aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dlm/dir.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-17 16:15:55 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-17 16:15:55 -0500
commit8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch)
treea8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /fs/dlm/dir.c
parent406089d01562f1e2bf9f089fd7637009ebaad589 (diff)
Patched in Tegra support.
Diffstat (limited to 'fs/dlm/dir.c')
-rw-r--r--fs/dlm/dir.c295
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
27static 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
34static 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
56void 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
35int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash) 79int 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
47int dlm_dir_nodeid(struct dlm_rsb *r) 115int 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
52void dlm_recover_dir_nodeid(struct dlm_ls *ls) 120static 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
130static 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
138static 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
152void 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
179void 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
63int dlm_recover_directory(struct dlm_ls *ls) 199int 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
200static struct dlm_rsb *find_rsb_root(struct dlm_ls *ls, char *name, int len) 302static 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
346int 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) 352static 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}