diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /fs/dlm/dir.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'fs/dlm/dir.c')
-rw-r--r-- | fs/dlm/dir.c | 295 |
1 files changed, 214 insertions, 81 deletions
diff --git a/fs/dlm/dir.c b/fs/dlm/dir.c index 278a75cda44..7b84c1dbc82 100644 --- a/fs/dlm/dir.c +++ b/fs/dlm/dir.c | |||
@@ -23,6 +23,50 @@ | |||
23 | #include "lock.h" | 23 | #include "lock.h" |
24 | #include "dir.h" | 24 | #include "dir.h" |
25 | 25 | ||
26 | |||
27 | static void put_free_de(struct dlm_ls *ls, struct dlm_direntry *de) | ||
28 | { | ||
29 | spin_lock(&ls->ls_recover_list_lock); | ||
30 | list_add(&de->list, &ls->ls_recover_list); | ||
31 | spin_unlock(&ls->ls_recover_list_lock); | ||
32 | } | ||
33 | |||
34 | static struct dlm_direntry *get_free_de(struct dlm_ls *ls, int len) | ||
35 | { | ||
36 | int found = 0; | ||
37 | struct dlm_direntry *de; | ||
38 | |||
39 | spin_lock(&ls->ls_recover_list_lock); | ||
40 | list_for_each_entry(de, &ls->ls_recover_list, list) { | ||
41 | if (de->length == len) { | ||
42 | list_del(&de->list); | ||
43 | de->master_nodeid = 0; | ||
44 | memset(de->name, 0, len); | ||
45 | found = 1; | ||
46 | break; | ||
47 | } | ||
48 | } | ||
49 | spin_unlock(&ls->ls_recover_list_lock); | ||
50 | |||
51 | if (!found) | ||
52 | de = kzalloc(sizeof(struct dlm_direntry) + len, GFP_NOFS); | ||
53 | return de; | ||
54 | } | ||
55 | |||
56 | void dlm_clear_free_entries(struct dlm_ls *ls) | ||
57 | { | ||
58 | struct dlm_direntry *de; | ||
59 | |||
60 | spin_lock(&ls->ls_recover_list_lock); | ||
61 | while (!list_empty(&ls->ls_recover_list)) { | ||
62 | de = list_entry(ls->ls_recover_list.next, struct dlm_direntry, | ||
63 | list); | ||
64 | list_del(&de->list); | ||
65 | kfree(de); | ||
66 | } | ||
67 | spin_unlock(&ls->ls_recover_list_lock); | ||
68 | } | ||
69 | |||
26 | /* | 70 | /* |
27 | * We use the upper 16 bits of the hash value to select the directory node. | 71 | * We use the upper 16 bits of the hash value to select the directory node. |
28 | * Low bits are used for distribution of rsb's among hash buckets on each node. | 72 | * Low bits are used for distribution of rsb's among hash buckets on each node. |
@@ -34,53 +78,144 @@ | |||
34 | 78 | ||
35 | int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash) | 79 | int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash) |
36 | { | 80 | { |
37 | uint32_t node; | 81 | struct list_head *tmp; |
82 | struct dlm_member *memb = NULL; | ||
83 | uint32_t node, n = 0; | ||
84 | int nodeid; | ||
85 | |||
86 | if (ls->ls_num_nodes == 1) { | ||
87 | nodeid = dlm_our_nodeid(); | ||
88 | goto out; | ||
89 | } | ||
38 | 90 | ||
39 | if (ls->ls_num_nodes == 1) | 91 | if (ls->ls_node_array) { |
40 | return dlm_our_nodeid(); | ||
41 | else { | ||
42 | node = (hash >> 16) % ls->ls_total_weight; | 92 | node = (hash >> 16) % ls->ls_total_weight; |
43 | return ls->ls_node_array[node]; | 93 | nodeid = ls->ls_node_array[node]; |
94 | goto out; | ||
95 | } | ||
96 | |||
97 | /* make_member_array() failed to kmalloc ls_node_array... */ | ||
98 | |||
99 | node = (hash >> 16) % ls->ls_num_nodes; | ||
100 | |||
101 | list_for_each(tmp, &ls->ls_nodes) { | ||
102 | if (n++ != node) | ||
103 | continue; | ||
104 | memb = list_entry(tmp, struct dlm_member, list); | ||
105 | break; | ||
44 | } | 106 | } |
107 | |||
108 | DLM_ASSERT(memb , printk("num_nodes=%u n=%u node=%u\n", | ||
109 | ls->ls_num_nodes, n, node);); | ||
110 | nodeid = memb->nodeid; | ||
111 | out: | ||
112 | return nodeid; | ||
45 | } | 113 | } |
46 | 114 | ||
47 | int dlm_dir_nodeid(struct dlm_rsb *r) | 115 | int dlm_dir_nodeid(struct dlm_rsb *r) |
48 | { | 116 | { |
49 | return r->res_dir_nodeid; | 117 | return dlm_hash2nodeid(r->res_ls, r->res_hash); |
50 | } | 118 | } |
51 | 119 | ||
52 | void dlm_recover_dir_nodeid(struct dlm_ls *ls) | 120 | static inline uint32_t dir_hash(struct dlm_ls *ls, char *name, int len) |
53 | { | 121 | { |
54 | struct dlm_rsb *r; | 122 | uint32_t val; |
55 | 123 | ||
56 | down_read(&ls->ls_root_sem); | 124 | val = jhash(name, len, 0); |
57 | list_for_each_entry(r, &ls->ls_root_list, res_root_list) { | 125 | val &= (ls->ls_dirtbl_size - 1); |
58 | r->res_dir_nodeid = dlm_hash2nodeid(ls, r->res_hash); | 126 | |
127 | return val; | ||
128 | } | ||
129 | |||
130 | static void add_entry_to_hash(struct dlm_ls *ls, struct dlm_direntry *de) | ||
131 | { | ||
132 | uint32_t bucket; | ||
133 | |||
134 | bucket = dir_hash(ls, de->name, de->length); | ||
135 | list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list); | ||
136 | } | ||
137 | |||
138 | static struct dlm_direntry *search_bucket(struct dlm_ls *ls, char *name, | ||
139 | int namelen, uint32_t bucket) | ||
140 | { | ||
141 | struct dlm_direntry *de; | ||
142 | |||
143 | list_for_each_entry(de, &ls->ls_dirtbl[bucket].list, list) { | ||
144 | if (de->length == namelen && !memcmp(name, de->name, namelen)) | ||
145 | goto out; | ||
146 | } | ||
147 | de = NULL; | ||
148 | out: | ||
149 | return de; | ||
150 | } | ||
151 | |||
152 | void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int namelen) | ||
153 | { | ||
154 | struct dlm_direntry *de; | ||
155 | uint32_t bucket; | ||
156 | |||
157 | bucket = dir_hash(ls, name, namelen); | ||
158 | |||
159 | spin_lock(&ls->ls_dirtbl[bucket].lock); | ||
160 | |||
161 | de = search_bucket(ls, name, namelen, bucket); | ||
162 | |||
163 | if (!de) { | ||
164 | log_error(ls, "remove fr %u none", nodeid); | ||
165 | goto out; | ||
166 | } | ||
167 | |||
168 | if (de->master_nodeid != nodeid) { | ||
169 | log_error(ls, "remove fr %u ID %u", nodeid, de->master_nodeid); | ||
170 | goto out; | ||
171 | } | ||
172 | |||
173 | list_del(&de->list); | ||
174 | kfree(de); | ||
175 | out: | ||
176 | spin_unlock(&ls->ls_dirtbl[bucket].lock); | ||
177 | } | ||
178 | |||
179 | void dlm_dir_clear(struct dlm_ls *ls) | ||
180 | { | ||
181 | struct list_head *head; | ||
182 | struct dlm_direntry *de; | ||
183 | int i; | ||
184 | |||
185 | DLM_ASSERT(list_empty(&ls->ls_recover_list), ); | ||
186 | |||
187 | for (i = 0; i < ls->ls_dirtbl_size; i++) { | ||
188 | spin_lock(&ls->ls_dirtbl[i].lock); | ||
189 | head = &ls->ls_dirtbl[i].list; | ||
190 | while (!list_empty(head)) { | ||
191 | de = list_entry(head->next, struct dlm_direntry, list); | ||
192 | list_del(&de->list); | ||
193 | put_free_de(ls, de); | ||
194 | } | ||
195 | spin_unlock(&ls->ls_dirtbl[i].lock); | ||
59 | } | 196 | } |
60 | up_read(&ls->ls_root_sem); | ||
61 | } | 197 | } |
62 | 198 | ||
63 | int dlm_recover_directory(struct dlm_ls *ls) | 199 | int dlm_recover_directory(struct dlm_ls *ls) |
64 | { | 200 | { |
65 | struct dlm_member *memb; | 201 | struct dlm_member *memb; |
202 | struct dlm_direntry *de; | ||
66 | char *b, *last_name = NULL; | 203 | char *b, *last_name = NULL; |
67 | int error = -ENOMEM, last_len, nodeid, result; | 204 | int error = -ENOMEM, last_len, count = 0; |
68 | uint16_t namelen; | 205 | uint16_t namelen; |
69 | unsigned int count = 0, count_match = 0, count_bad = 0, count_add = 0; | ||
70 | 206 | ||
71 | log_debug(ls, "dlm_recover_directory"); | 207 | log_debug(ls, "dlm_recover_directory"); |
72 | 208 | ||
73 | if (dlm_no_directory(ls)) | 209 | if (dlm_no_directory(ls)) |
74 | goto out_status; | 210 | goto out_status; |
75 | 211 | ||
212 | dlm_dir_clear(ls); | ||
213 | |||
76 | last_name = kmalloc(DLM_RESNAME_MAXLEN, GFP_NOFS); | 214 | last_name = kmalloc(DLM_RESNAME_MAXLEN, GFP_NOFS); |
77 | if (!last_name) | 215 | if (!last_name) |
78 | goto out; | 216 | goto out; |
79 | 217 | ||
80 | list_for_each_entry(memb, &ls->ls_nodes, list) { | 218 | list_for_each_entry(memb, &ls->ls_nodes, list) { |
81 | if (memb->nodeid == dlm_our_nodeid()) | ||
82 | continue; | ||
83 | |||
84 | memset(last_name, 0, DLM_RESNAME_MAXLEN); | 219 | memset(last_name, 0, DLM_RESNAME_MAXLEN); |
85 | last_len = 0; | 220 | last_len = 0; |
86 | 221 | ||
@@ -95,7 +230,7 @@ int dlm_recover_directory(struct dlm_ls *ls) | |||
95 | if (error) | 230 | if (error) |
96 | goto out_free; | 231 | goto out_free; |
97 | 232 | ||
98 | cond_resched(); | 233 | schedule(); |
99 | 234 | ||
100 | /* | 235 | /* |
101 | * pick namelen/name pairs out of received buffer | 236 | * pick namelen/name pairs out of received buffer |
@@ -132,96 +267,96 @@ int dlm_recover_directory(struct dlm_ls *ls) | |||
132 | if (namelen > DLM_RESNAME_MAXLEN) | 267 | if (namelen > DLM_RESNAME_MAXLEN) |
133 | goto out_free; | 268 | goto out_free; |
134 | 269 | ||
135 | error = dlm_master_lookup(ls, memb->nodeid, | 270 | error = -ENOMEM; |
136 | b, namelen, | 271 | de = get_free_de(ls, namelen); |
137 | DLM_LU_RECOVER_DIR, | 272 | if (!de) |
138 | &nodeid, &result); | ||
139 | if (error) { | ||
140 | log_error(ls, "recover_dir lookup %d", | ||
141 | error); | ||
142 | goto out_free; | 273 | goto out_free; |
143 | } | ||
144 | |||
145 | /* The name was found in rsbtbl, but the | ||
146 | * master nodeid is different from | ||
147 | * memb->nodeid which says it is the master. | ||
148 | * This should not happen. */ | ||
149 | |||
150 | if (result == DLM_LU_MATCH && | ||
151 | nodeid != memb->nodeid) { | ||
152 | count_bad++; | ||
153 | log_error(ls, "recover_dir lookup %d " | ||
154 | "nodeid %d memb %d bad %u", | ||
155 | result, nodeid, memb->nodeid, | ||
156 | count_bad); | ||
157 | print_hex_dump_bytes("dlm_recover_dir ", | ||
158 | DUMP_PREFIX_NONE, | ||
159 | b, namelen); | ||
160 | } | ||
161 | |||
162 | /* The name was found in rsbtbl, and the | ||
163 | * master nodeid matches memb->nodeid. */ | ||
164 | |||
165 | if (result == DLM_LU_MATCH && | ||
166 | nodeid == memb->nodeid) { | ||
167 | count_match++; | ||
168 | } | ||
169 | |||
170 | /* The name was not found in rsbtbl and was | ||
171 | * added with memb->nodeid as the master. */ | ||
172 | |||
173 | if (result == DLM_LU_ADD) { | ||
174 | count_add++; | ||
175 | } | ||
176 | 274 | ||
275 | de->master_nodeid = memb->nodeid; | ||
276 | de->length = namelen; | ||
177 | last_len = namelen; | 277 | last_len = namelen; |
278 | memcpy(de->name, b, namelen); | ||
178 | memcpy(last_name, b, namelen); | 279 | memcpy(last_name, b, namelen); |
179 | b += namelen; | 280 | b += namelen; |
180 | left -= namelen; | 281 | left -= namelen; |
282 | |||
283 | add_entry_to_hash(ls, de); | ||
181 | count++; | 284 | count++; |
182 | } | 285 | } |
183 | } | 286 | } |
184 | done: | 287 | done: |
185 | ; | 288 | ; |
186 | } | 289 | } |
187 | 290 | ||
188 | out_status: | 291 | out_status: |
189 | error = 0; | 292 | error = 0; |
190 | dlm_set_recover_status(ls, DLM_RS_DIR); | 293 | dlm_set_recover_status(ls, DLM_RS_DIR); |
191 | 294 | log_debug(ls, "dlm_recover_directory %d entries", count); | |
192 | log_debug(ls, "dlm_recover_directory %u in %u new", | ||
193 | count, count_add); | ||
194 | out_free: | 295 | out_free: |
195 | kfree(last_name); | 296 | kfree(last_name); |
196 | out: | 297 | out: |
298 | dlm_clear_free_entries(ls); | ||
197 | return error; | 299 | return error; |
198 | } | 300 | } |
199 | 301 | ||
200 | static struct dlm_rsb *find_rsb_root(struct dlm_ls *ls, char *name, int len) | 302 | static int get_entry(struct dlm_ls *ls, int nodeid, char *name, |
303 | int namelen, int *r_nodeid) | ||
201 | { | 304 | { |
202 | struct dlm_rsb *r; | 305 | struct dlm_direntry *de, *tmp; |
203 | uint32_t hash, bucket; | 306 | uint32_t bucket; |
204 | int rv; | 307 | |
308 | bucket = dir_hash(ls, name, namelen); | ||
309 | |||
310 | spin_lock(&ls->ls_dirtbl[bucket].lock); | ||
311 | de = search_bucket(ls, name, namelen, bucket); | ||
312 | if (de) { | ||
313 | *r_nodeid = de->master_nodeid; | ||
314 | spin_unlock(&ls->ls_dirtbl[bucket].lock); | ||
315 | if (*r_nodeid == nodeid) | ||
316 | return -EEXIST; | ||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | spin_unlock(&ls->ls_dirtbl[bucket].lock); | ||
321 | |||
322 | if (namelen > DLM_RESNAME_MAXLEN) | ||
323 | return -EINVAL; | ||
324 | |||
325 | de = kzalloc(sizeof(struct dlm_direntry) + namelen, GFP_NOFS); | ||
326 | if (!de) | ||
327 | return -ENOMEM; | ||
205 | 328 | ||
206 | hash = jhash(name, len, 0); | 329 | de->master_nodeid = nodeid; |
207 | bucket = hash & (ls->ls_rsbtbl_size - 1); | 330 | de->length = namelen; |
331 | memcpy(de->name, name, namelen); | ||
208 | 332 | ||
209 | spin_lock(&ls->ls_rsbtbl[bucket].lock); | 333 | spin_lock(&ls->ls_dirtbl[bucket].lock); |
210 | rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[bucket].keep, name, len, &r); | 334 | tmp = search_bucket(ls, name, namelen, bucket); |
211 | if (rv) | 335 | if (tmp) { |
212 | rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[bucket].toss, | 336 | kfree(de); |
213 | name, len, &r); | 337 | de = tmp; |
214 | spin_unlock(&ls->ls_rsbtbl[bucket].lock); | 338 | } else { |
339 | list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list); | ||
340 | } | ||
341 | *r_nodeid = de->master_nodeid; | ||
342 | spin_unlock(&ls->ls_dirtbl[bucket].lock); | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen, | ||
347 | int *r_nodeid) | ||
348 | { | ||
349 | return get_entry(ls, nodeid, name, namelen, r_nodeid); | ||
350 | } | ||
215 | 351 | ||
216 | if (!rv) | 352 | static struct dlm_rsb *find_rsb_root(struct dlm_ls *ls, char *name, int len) |
217 | return r; | 353 | { |
354 | struct dlm_rsb *r; | ||
218 | 355 | ||
219 | down_read(&ls->ls_root_sem); | 356 | down_read(&ls->ls_root_sem); |
220 | list_for_each_entry(r, &ls->ls_root_list, res_root_list) { | 357 | list_for_each_entry(r, &ls->ls_root_list, res_root_list) { |
221 | if (len == r->res_length && !memcmp(name, r->res_name, len)) { | 358 | if (len == r->res_length && !memcmp(name, r->res_name, len)) { |
222 | up_read(&ls->ls_root_sem); | 359 | up_read(&ls->ls_root_sem); |
223 | log_debug(ls, "find_rsb_root revert to root_list %s", | ||
224 | r->res_name); | ||
225 | return r; | 360 | return r; |
226 | } | 361 | } |
227 | } | 362 | } |
@@ -278,7 +413,6 @@ void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen, | |||
278 | be_namelen = cpu_to_be16(0); | 413 | be_namelen = cpu_to_be16(0); |
279 | memcpy(outbuf + offset, &be_namelen, sizeof(__be16)); | 414 | memcpy(outbuf + offset, &be_namelen, sizeof(__be16)); |
280 | offset += sizeof(__be16); | 415 | offset += sizeof(__be16); |
281 | ls->ls_recover_dir_sent_msg++; | ||
282 | goto out; | 416 | goto out; |
283 | } | 417 | } |
284 | 418 | ||
@@ -287,7 +421,6 @@ void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen, | |||
287 | offset += sizeof(__be16); | 421 | offset += sizeof(__be16); |
288 | memcpy(outbuf + offset, r->res_name, r->res_length); | 422 | memcpy(outbuf + offset, r->res_name, r->res_length); |
289 | offset += r->res_length; | 423 | offset += r->res_length; |
290 | ls->ls_recover_dir_sent_res++; | ||
291 | } | 424 | } |
292 | 425 | ||
293 | /* | 426 | /* |
@@ -300,8 +433,8 @@ void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen, | |||
300 | be_namelen = cpu_to_be16(0xFFFF); | 433 | be_namelen = cpu_to_be16(0xFFFF); |
301 | memcpy(outbuf + offset, &be_namelen, sizeof(__be16)); | 434 | memcpy(outbuf + offset, &be_namelen, sizeof(__be16)); |
302 | offset += sizeof(__be16); | 435 | offset += sizeof(__be16); |
303 | ls->ls_recover_dir_sent_msg++; | ||
304 | } | 436 | } |
437 | |||
305 | out: | 438 | out: |
306 | up_read(&ls->ls_root_sem); | 439 | up_read(&ls->ls_root_sem); |
307 | } | 440 | } |