Commit 5e9ccc372dc855900c4a75b21286038938e288c7
Committed by
David Teigland
1 parent
2cf12c0bf2
Exists in
master
and in
7 other branches
dlm: replace idr with hash table for connections
Integer nodeids can be too large for the idr code; use a hash table instead. Signed-off-by: Christine Caulfield <ccaulfie@redhat.com> Signed-off-by: David Teigland <teigland@redhat.com>
Showing 1 changed file with 92 additions and 79 deletions Side-by-side Diff
fs/dlm/lowcomms.c
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | ******************************************************************************* |
3 | 3 | ** |
4 | 4 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. |
5 | -** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | |
5 | +** Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. | |
6 | 6 | ** |
7 | 7 | ** This copyrighted material is made available to anyone wishing to use, |
8 | 8 | ** modify, copy, or redistribute it subject to the terms and conditions |
... | ... | @@ -48,7 +48,6 @@ |
48 | 48 | #include <net/sock.h> |
49 | 49 | #include <net/tcp.h> |
50 | 50 | #include <linux/pagemap.h> |
51 | -#include <linux/idr.h> | |
52 | 51 | #include <linux/file.h> |
53 | 52 | #include <linux/mutex.h> |
54 | 53 | #include <linux/sctp.h> |
... | ... | @@ -61,6 +60,7 @@ |
61 | 60 | #include "config.h" |
62 | 61 | |
63 | 62 | #define NEEDED_RMEM (4*1024*1024) |
63 | +#define CONN_HASH_SIZE 32 | |
64 | 64 | |
65 | 65 | struct cbuf { |
66 | 66 | unsigned int base; |
... | ... | @@ -115,6 +115,7 @@ |
115 | 115 | int retries; |
116 | 116 | #define MAX_CONNECT_RETRIES 3 |
117 | 117 | int sctp_assoc; |
118 | + struct hlist_node list; | |
118 | 119 | struct connection *othercon; |
119 | 120 | struct work_struct rwork; /* Receive workqueue */ |
120 | 121 | struct work_struct swork; /* Send workqueue */ |
121 | 122 | |
122 | 123 | |
... | ... | @@ -139,14 +140,37 @@ |
139 | 140 | static struct workqueue_struct *recv_workqueue; |
140 | 141 | static struct workqueue_struct *send_workqueue; |
141 | 142 | |
142 | -static DEFINE_IDR(connections_idr); | |
143 | +static struct hlist_head connection_hash[CONN_HASH_SIZE]; | |
143 | 144 | static DEFINE_MUTEX(connections_lock); |
144 | -static int max_nodeid; | |
145 | 145 | static struct kmem_cache *con_cache; |
146 | 146 | |
147 | 147 | static void process_recv_sockets(struct work_struct *work); |
148 | 148 | static void process_send_sockets(struct work_struct *work); |
149 | 149 | |
150 | + | |
151 | +/* This is deliberately very simple because most clusters have simple | |
152 | + sequential nodeids, so we should be able to go straight to a connection | |
153 | + struct in the array */ | |
154 | +static inline int nodeid_hash(int nodeid) | |
155 | +{ | |
156 | + return nodeid & (CONN_HASH_SIZE-1); | |
157 | +} | |
158 | + | |
159 | +static struct connection *__find_con(int nodeid) | |
160 | +{ | |
161 | + int r; | |
162 | + struct hlist_node *h; | |
163 | + struct connection *con; | |
164 | + | |
165 | + r = nodeid_hash(nodeid); | |
166 | + | |
167 | + hlist_for_each_entry(con, h, &connection_hash[r], list) { | |
168 | + if (con->nodeid == nodeid) | |
169 | + return con; | |
170 | + } | |
171 | + return NULL; | |
172 | +} | |
173 | + | |
150 | 174 | /* |
151 | 175 | * If 'allocation' is zero then we don't attempt to create a new |
152 | 176 | * connection structure for this node. |
153 | 177 | |
154 | 178 | |
155 | 179 | |
156 | 180 | |
... | ... | @@ -155,32 +179,18 @@ |
155 | 179 | { |
156 | 180 | struct connection *con = NULL; |
157 | 181 | int r; |
158 | - int n; | |
159 | 182 | |
160 | - con = idr_find(&connections_idr, nodeid); | |
183 | + con = __find_con(nodeid); | |
161 | 184 | if (con || !alloc) |
162 | 185 | return con; |
163 | 186 | |
164 | - r = idr_pre_get(&connections_idr, alloc); | |
165 | - if (!r) | |
166 | - return NULL; | |
167 | - | |
168 | 187 | con = kmem_cache_zalloc(con_cache, alloc); |
169 | 188 | if (!con) |
170 | 189 | return NULL; |
171 | 190 | |
172 | - r = idr_get_new_above(&connections_idr, con, nodeid, &n); | |
173 | - if (r) { | |
174 | - kmem_cache_free(con_cache, con); | |
175 | - return NULL; | |
176 | - } | |
191 | + r = nodeid_hash(nodeid); | |
192 | + hlist_add_head(&con->list, &connection_hash[r]); | |
177 | 193 | |
178 | - if (n != nodeid) { | |
179 | - idr_remove(&connections_idr, n); | |
180 | - kmem_cache_free(con_cache, con); | |
181 | - return NULL; | |
182 | - } | |
183 | - | |
184 | 194 | con->nodeid = nodeid; |
185 | 195 | mutex_init(&con->sock_mutex); |
186 | 196 | INIT_LIST_HEAD(&con->writequeue); |
187 | 197 | |
188 | 198 | |
... | ... | @@ -190,19 +200,30 @@ |
190 | 200 | |
191 | 201 | /* Setup action pointers for child sockets */ |
192 | 202 | if (con->nodeid) { |
193 | - struct connection *zerocon = idr_find(&connections_idr, 0); | |
203 | + struct connection *zerocon = __find_con(0); | |
194 | 204 | |
195 | 205 | con->connect_action = zerocon->connect_action; |
196 | 206 | if (!con->rx_action) |
197 | 207 | con->rx_action = zerocon->rx_action; |
198 | 208 | } |
199 | 209 | |
200 | - if (nodeid > max_nodeid) | |
201 | - max_nodeid = nodeid; | |
202 | - | |
203 | 210 | return con; |
204 | 211 | } |
205 | 212 | |
213 | +/* Loop round all connections */ | |
214 | +static void foreach_conn(void (*conn_func)(struct connection *c)) | |
215 | +{ | |
216 | + int i; | |
217 | + struct hlist_node *h, *n; | |
218 | + struct connection *con; | |
219 | + | |
220 | + for (i = 0; i < CONN_HASH_SIZE; i++) { | |
221 | + hlist_for_each_entry_safe(con, h, n, &connection_hash[i], list){ | |
222 | + conn_func(con); | |
223 | + } | |
224 | + } | |
225 | +} | |
226 | + | |
206 | 227 | static struct connection *nodeid2con(int nodeid, gfp_t allocation) |
207 | 228 | { |
208 | 229 | struct connection *con; |
209 | 230 | |
... | ... | @@ -218,14 +239,17 @@ |
218 | 239 | static struct connection *assoc2con(int assoc_id) |
219 | 240 | { |
220 | 241 | int i; |
242 | + struct hlist_node *h; | |
221 | 243 | struct connection *con; |
222 | 244 | |
223 | 245 | mutex_lock(&connections_lock); |
224 | - for (i=0; i<=max_nodeid; i++) { | |
225 | - con = __nodeid2con(i, 0); | |
226 | - if (con && con->sctp_assoc == assoc_id) { | |
227 | - mutex_unlock(&connections_lock); | |
228 | - return con; | |
246 | + | |
247 | + for (i = 0 ; i < CONN_HASH_SIZE; i++) { | |
248 | + hlist_for_each_entry(con, h, &connection_hash[i], list) { | |
249 | + if (con && con->sctp_assoc == assoc_id) { | |
250 | + mutex_unlock(&connections_lock); | |
251 | + return con; | |
252 | + } | |
229 | 253 | } |
230 | 254 | } |
231 | 255 | mutex_unlock(&connections_lock); |
232 | 256 | |
233 | 257 | |
... | ... | @@ -376,25 +400,23 @@ |
376 | 400 | log_print("send EOF to node failed: %d", ret); |
377 | 401 | } |
378 | 402 | |
403 | +static void sctp_init_failed_foreach(struct connection *con) | |
404 | +{ | |
405 | + con->sctp_assoc = 0; | |
406 | + if (test_and_clear_bit(CF_CONNECT_PENDING, &con->flags)) { | |
407 | + if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags)) | |
408 | + queue_work(send_workqueue, &con->swork); | |
409 | + } | |
410 | +} | |
411 | + | |
379 | 412 | /* INIT failed but we don't know which node... |
380 | 413 | restart INIT on all pending nodes */ |
381 | 414 | static void sctp_init_failed(void) |
382 | 415 | { |
383 | - int i; | |
384 | - struct connection *con; | |
385 | - | |
386 | 416 | mutex_lock(&connections_lock); |
387 | - for (i=1; i<=max_nodeid; i++) { | |
388 | - con = __nodeid2con(i, 0); | |
389 | - if (!con) | |
390 | - continue; | |
391 | - con->sctp_assoc = 0; | |
392 | - if (test_and_clear_bit(CF_CONNECT_PENDING, &con->flags)) { | |
393 | - if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags)) { | |
394 | - queue_work(send_workqueue, &con->swork); | |
395 | - } | |
396 | - } | |
397 | - } | |
417 | + | |
418 | + foreach_conn(sctp_init_failed_foreach); | |
419 | + | |
398 | 420 | mutex_unlock(&connections_lock); |
399 | 421 | } |
400 | 422 | |
401 | 423 | |
... | ... | @@ -1313,13 +1335,10 @@ |
1313 | 1335 | |
1314 | 1336 | static void clean_one_writequeue(struct connection *con) |
1315 | 1337 | { |
1316 | - struct list_head *list; | |
1317 | - struct list_head *temp; | |
1338 | + struct writequeue_entry *e, *safe; | |
1318 | 1339 | |
1319 | 1340 | spin_lock(&con->writequeue_lock); |
1320 | - list_for_each_safe(list, temp, &con->writequeue) { | |
1321 | - struct writequeue_entry *e = | |
1322 | - list_entry(list, struct writequeue_entry, list); | |
1341 | + list_for_each_entry_safe(e, safe, &con->writequeue, list) { | |
1323 | 1342 | list_del(&e->list); |
1324 | 1343 | free_entry(e); |
1325 | 1344 | } |
... | ... | @@ -1369,14 +1388,7 @@ |
1369 | 1388 | /* Discard all entries on the write queues */ |
1370 | 1389 | static void clean_writequeues(void) |
1371 | 1390 | { |
1372 | - int nodeid; | |
1373 | - | |
1374 | - for (nodeid = 1; nodeid <= max_nodeid; nodeid++) { | |
1375 | - struct connection *con = __nodeid2con(nodeid, 0); | |
1376 | - | |
1377 | - if (con) | |
1378 | - clean_one_writequeue(con); | |
1379 | - } | |
1391 | + foreach_conn(clean_one_writequeue); | |
1380 | 1392 | } |
1381 | 1393 | |
1382 | 1394 | static void work_stop(void) |
1383 | 1395 | |
1384 | 1396 | |
1385 | 1397 | |
... | ... | @@ -1406,23 +1418,29 @@ |
1406 | 1418 | return 0; |
1407 | 1419 | } |
1408 | 1420 | |
1409 | -void dlm_lowcomms_stop(void) | |
1421 | +static void stop_conn(struct connection *con) | |
1410 | 1422 | { |
1411 | - int i; | |
1412 | - struct connection *con; | |
1423 | + con->flags |= 0x0F; | |
1424 | + if (con->sock) | |
1425 | + con->sock->sk->sk_user_data = NULL; | |
1426 | +} | |
1413 | 1427 | |
1428 | +static void free_conn(struct connection *con) | |
1429 | +{ | |
1430 | + close_connection(con, true); | |
1431 | + if (con->othercon) | |
1432 | + kmem_cache_free(con_cache, con->othercon); | |
1433 | + hlist_del(&con->list); | |
1434 | + kmem_cache_free(con_cache, con); | |
1435 | +} | |
1436 | + | |
1437 | +void dlm_lowcomms_stop(void) | |
1438 | +{ | |
1414 | 1439 | /* Set all the flags to prevent any |
1415 | 1440 | socket activity. |
1416 | 1441 | */ |
1417 | 1442 | mutex_lock(&connections_lock); |
1418 | - for (i = 0; i <= max_nodeid; i++) { | |
1419 | - con = __nodeid2con(i, 0); | |
1420 | - if (con) { | |
1421 | - con->flags |= 0x0F; | |
1422 | - if (con->sock) | |
1423 | - con->sock->sk->sk_user_data = NULL; | |
1424 | - } | |
1425 | - } | |
1443 | + foreach_conn(stop_conn); | |
1426 | 1444 | mutex_unlock(&connections_lock); |
1427 | 1445 | |
1428 | 1446 | work_stop(); |
1429 | 1447 | |
1430 | 1448 | |
... | ... | @@ -1430,25 +1448,20 @@ |
1430 | 1448 | mutex_lock(&connections_lock); |
1431 | 1449 | clean_writequeues(); |
1432 | 1450 | |
1433 | - for (i = 0; i <= max_nodeid; i++) { | |
1434 | - con = __nodeid2con(i, 0); | |
1435 | - if (con) { | |
1436 | - close_connection(con, true); | |
1437 | - if (con->othercon) | |
1438 | - kmem_cache_free(con_cache, con->othercon); | |
1439 | - kmem_cache_free(con_cache, con); | |
1440 | - } | |
1441 | - } | |
1442 | - max_nodeid = 0; | |
1451 | + foreach_conn(free_conn); | |
1452 | + | |
1443 | 1453 | mutex_unlock(&connections_lock); |
1444 | 1454 | kmem_cache_destroy(con_cache); |
1445 | - idr_init(&connections_idr); | |
1446 | 1455 | } |
1447 | 1456 | |
1448 | 1457 | int dlm_lowcomms_start(void) |
1449 | 1458 | { |
1450 | 1459 | int error = -EINVAL; |
1451 | 1460 | struct connection *con; |
1461 | + int i; | |
1462 | + | |
1463 | + for (i = 0; i < CONN_HASH_SIZE; i++) | |
1464 | + INIT_HLIST_HEAD(&connection_hash[i]); | |
1452 | 1465 | |
1453 | 1466 | init_local(); |
1454 | 1467 | if (!dlm_local_count) { |