]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: David Teigland <teigland@redhat.com> |
2 | commit 892c4467e335e9050c95e0d8409c136c4dadaca2 | |
3 | Author: David Teigland <teigland@redhat.com> | |
4 | Date: Wed Jan 7 16:48:52 2009 -0600 | |
5 | Subject: dlm: fix seq_file usage in debugfs lock dump | |
6 | ||
7 | The old code would leak iterators and leave reference counts on | |
8 | rsbs because it was ignoring the "stop" seq callback. The code | |
9 | followed an example that used the seq operations differently. | |
10 | This new code is based on actually understanding how the seq | |
11 | operations work. It also improves things by saving the hash bucket | |
12 | in the position to avoid cycling through completed buckets in start. | |
13 | ||
14 | Siged-off-by: Davd Teigland <teigland@redhat.com> | |
15 | Signed-off-by: Coly Li <coly.li@suse.de> | |
16 | ||
17 | diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c | |
18 | index 2f107d1..bc4af3e 100644 | |
19 | --- a/fs/dlm/debug_fs.c | |
20 | +++ b/fs/dlm/debug_fs.c | |
21 | @@ -1,7 +1,7 @@ | |
22 | /****************************************************************************** | |
23 | ******************************************************************************* | |
24 | ** | |
25 | -** Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved. | |
26 | +** Copyright (C) 2005-2009 Red Hat, Inc. All rights reserved. | |
27 | ** | |
28 | ** This copyrighted material is made available to anyone wishing to use, | |
29 | ** modify, copy, or redistribute it subject to the terms and conditions | |
30 | @@ -25,19 +25,6 @@ static struct mutex debug_buf_lock; | |
31 | ||
32 | static struct dentry *dlm_root; | |
33 | ||
34 | -struct rsb_iter { | |
35 | - int entry; | |
36 | - int format; | |
37 | - int header; | |
38 | - struct dlm_ls *ls; | |
39 | - struct list_head *next; | |
40 | - struct dlm_rsb *rsb; | |
41 | -}; | |
42 | - | |
43 | -/* | |
44 | - * dump all rsb's in the lockspace hash table | |
45 | - */ | |
46 | - | |
47 | static char *print_lockmode(int mode) | |
48 | { | |
49 | switch (mode) { | |
50 | @@ -60,13 +47,13 @@ static char *print_lockmode(int mode) | |
51 | } | |
52 | } | |
53 | ||
54 | -static void print_format1_lock(struct seq_file *s, struct dlm_lkb *lkb, | |
55 | - struct dlm_rsb *res) | |
56 | +static int print_format1_lock(struct seq_file *s, struct dlm_lkb *lkb, | |
57 | + struct dlm_rsb *res) | |
58 | { | |
59 | seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode)); | |
60 | ||
61 | - if (lkb->lkb_status == DLM_LKSTS_CONVERT | |
62 | - || lkb->lkb_status == DLM_LKSTS_WAITING) | |
63 | + if (lkb->lkb_status == DLM_LKSTS_CONVERT || | |
64 | + lkb->lkb_status == DLM_LKSTS_WAITING) | |
65 | seq_printf(s, " (%s)", print_lockmode(lkb->lkb_rqmode)); | |
66 | ||
67 | if (lkb->lkb_nodeid) { | |
68 | @@ -80,33 +67,42 @@ static void print_format1_lock(struct seq_file *s, struct dlm_lkb *lkb, | |
69 | if (lkb->lkb_wait_type) | |
70 | seq_printf(s, " wait_type: %d", lkb->lkb_wait_type); | |
71 | ||
72 | - seq_printf(s, "\n"); | |
73 | + return seq_printf(s, "\n"); | |
74 | } | |
75 | ||
76 | static int print_format1(struct dlm_rsb *res, struct seq_file *s) | |
77 | { | |
78 | struct dlm_lkb *lkb; | |
79 | int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list; | |
80 | + int rv; | |
81 | ||
82 | lock_rsb(res); | |
83 | ||
84 | - seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length); | |
85 | + rv = seq_printf(s, "\nResource %p Name (len=%d) \"", | |
86 | + res, res->res_length); | |
87 | + if (rv) | |
88 | + goto out; | |
89 | + | |
90 | for (i = 0; i < res->res_length; i++) { | |
91 | if (isprint(res->res_name[i])) | |
92 | seq_printf(s, "%c", res->res_name[i]); | |
93 | else | |
94 | seq_printf(s, "%c", '.'); | |
95 | } | |
96 | + | |
97 | if (res->res_nodeid > 0) | |
98 | - seq_printf(s, "\" \nLocal Copy, Master is node %d\n", | |
99 | - res->res_nodeid); | |
100 | + rv = seq_printf(s, "\" \nLocal Copy, Master is node %d\n", | |
101 | + res->res_nodeid); | |
102 | else if (res->res_nodeid == 0) | |
103 | - seq_printf(s, "\" \nMaster Copy\n"); | |
104 | + rv = seq_printf(s, "\" \nMaster Copy\n"); | |
105 | else if (res->res_nodeid == -1) | |
106 | - seq_printf(s, "\" \nLooking up master (lkid %x)\n", | |
107 | - res->res_first_lkid); | |
108 | + rv = seq_printf(s, "\" \nLooking up master (lkid %x)\n", | |
82094b55 | 109 | + res->res_first_lkid); |
2cb7cef9 BS |
110 | else |
111 | - seq_printf(s, "\" \nInvalid master %d\n", res->res_nodeid); | |
112 | + rv = seq_printf(s, "\" \nInvalid master %d\n", | |
113 | + res->res_nodeid); | |
114 | + if (rv) | |
115 | + goto out; | |
116 | ||
117 | /* Print the LVB: */ | |
118 | if (res->res_lvbptr) { | |
119 | @@ -119,52 +115,66 @@ static int print_format1(struct dlm_rsb *res, struct seq_file *s) | |
120 | } | |
121 | if (rsb_flag(res, RSB_VALNOTVALID)) | |
122 | seq_printf(s, " (INVALID)"); | |
123 | - seq_printf(s, "\n"); | |
124 | + rv = seq_printf(s, "\n"); | |
125 | + if (rv) | |
126 | + goto out; | |
127 | } | |
128 | ||
129 | root_list = !list_empty(&res->res_root_list); | |
130 | recover_list = !list_empty(&res->res_recover_list); | |
131 | ||
132 | if (root_list || recover_list) { | |
133 | - seq_printf(s, "Recovery: root %d recover %d flags %lx " | |
134 | - "count %d\n", root_list, recover_list, | |
135 | - res->res_flags, res->res_recover_locks_count); | |
136 | + rv = seq_printf(s, "Recovery: root %d recover %d flags %lx " | |
137 | + "count %d\n", root_list, recover_list, | |
82094b55 | 138 | + res->res_flags, res->res_recover_locks_count); |
2cb7cef9 BS |
139 | + if (rv) |
140 | + goto out; | |
141 | } | |
142 | ||
143 | /* Print the locks attached to this resource */ | |
144 | seq_printf(s, "Granted Queue\n"); | |
145 | - list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue) | |
146 | - print_format1_lock(s, lkb, res); | |
147 | + list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue) { | |
148 | + rv = print_format1_lock(s, lkb, res); | |
149 | + if (rv) | |
150 | + goto out; | |
151 | + } | |
152 | ||
153 | seq_printf(s, "Conversion Queue\n"); | |
154 | - list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue) | |
155 | - print_format1_lock(s, lkb, res); | |
156 | + list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue) { | |
157 | + rv = print_format1_lock(s, lkb, res); | |
158 | + if (rv) | |
159 | + goto out; | |
160 | + } | |
161 | ||
162 | seq_printf(s, "Waiting Queue\n"); | |
163 | - list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue) | |
164 | - print_format1_lock(s, lkb, res); | |
165 | + list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue) { | |
166 | + rv = print_format1_lock(s, lkb, res); | |
167 | + if (rv) | |
168 | + goto out; | |
169 | + } | |
170 | ||
171 | if (list_empty(&res->res_lookup)) | |
172 | goto out; | |
173 | ||
174 | seq_printf(s, "Lookup Queue\n"); | |
175 | list_for_each_entry(lkb, &res->res_lookup, lkb_rsb_lookup) { | |
176 | - seq_printf(s, "%08x %s", lkb->lkb_id, | |
177 | - print_lockmode(lkb->lkb_rqmode)); | |
178 | + rv = seq_printf(s, "%08x %s", lkb->lkb_id, | |
179 | + print_lockmode(lkb->lkb_rqmode)); | |
180 | if (lkb->lkb_wait_type) | |
181 | seq_printf(s, " wait_type: %d", lkb->lkb_wait_type); | |
182 | - seq_printf(s, "\n"); | |
183 | + rv = seq_printf(s, "\n"); | |
184 | } | |
185 | out: | |
186 | unlock_rsb(res); | |
187 | - return 0; | |
188 | + return rv; | |
189 | } | |
190 | ||
191 | -static void print_format2_lock(struct seq_file *s, struct dlm_lkb *lkb, | |
192 | - struct dlm_rsb *r) | |
193 | +static int print_format2_lock(struct seq_file *s, struct dlm_lkb *lkb, | |
194 | + struct dlm_rsb *r) | |
195 | { | |
196 | u64 xid = 0; | |
197 | u64 us; | |
198 | + int rv; | |
199 | ||
200 | if (lkb->lkb_flags & DLM_IFL_USER) { | |
201 | if (lkb->lkb_ua) | |
202 | @@ -177,69 +187,82 @@ static void print_format2_lock(struct seq_file *s, struct dlm_lkb *lkb, | |
203 | /* id nodeid remid pid xid exflags flags sts grmode rqmode time_us | |
204 | r_nodeid r_len r_name */ | |
205 | ||
206 | - seq_printf(s, "%x %d %x %u %llu %x %x %d %d %d %llu %u %d \"%s\"\n", | |
207 | - lkb->lkb_id, | |
208 | - lkb->lkb_nodeid, | |
209 | - lkb->lkb_remid, | |
210 | - lkb->lkb_ownpid, | |
211 | - (unsigned long long)xid, | |
212 | - lkb->lkb_exflags, | |
213 | - lkb->lkb_flags, | |
214 | - lkb->lkb_status, | |
215 | - lkb->lkb_grmode, | |
216 | - lkb->lkb_rqmode, | |
217 | - (unsigned long long)us, | |
218 | - r->res_nodeid, | |
219 | - r->res_length, | |
220 | - r->res_name); | |
221 | + rv = seq_printf(s, "%x %d %x %u %llu %x %x %d %d %d %llu %u %d \"%s\"\n", | |
222 | + lkb->lkb_id, | |
223 | + lkb->lkb_nodeid, | |
224 | + lkb->lkb_remid, | |
225 | + lkb->lkb_ownpid, | |
226 | + (unsigned long long)xid, | |
227 | + lkb->lkb_exflags, | |
228 | + lkb->lkb_flags, | |
229 | + lkb->lkb_status, | |
230 | + lkb->lkb_grmode, | |
231 | + lkb->lkb_rqmode, | |
232 | + (unsigned long long)us, | |
233 | + r->res_nodeid, | |
234 | + r->res_length, | |
235 | + r->res_name); | |
236 | + return rv; | |
237 | } | |
238 | ||
239 | static int print_format2(struct dlm_rsb *r, struct seq_file *s) | |
240 | { | |
241 | struct dlm_lkb *lkb; | |
242 | + int rv = 0; | |
243 | ||
244 | lock_rsb(r); | |
245 | ||
246 | - list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) | |
247 | - print_format2_lock(s, lkb, r); | |
248 | - | |
249 | - list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) | |
250 | - print_format2_lock(s, lkb, r); | |
251 | + list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) { | |
252 | + rv = print_format2_lock(s, lkb, r); | |
253 | + if (rv) | |
254 | + goto out; | |
255 | + } | |
256 | ||
257 | - list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) | |
258 | - print_format2_lock(s, lkb, r); | |
259 | + list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) { | |
260 | + rv = print_format2_lock(s, lkb, r); | |
261 | + if (rv) | |
262 | + goto out; | |
263 | + } | |
264 | ||
265 | + list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) { | |
266 | + rv = print_format2_lock(s, lkb, r); | |
267 | + if (rv) | |
268 | + goto out; | |
269 | + } | |
270 | + out: | |
271 | unlock_rsb(r); | |
272 | - return 0; | |
273 | + return rv; | |
274 | } | |
275 | ||
276 | -static void print_format3_lock(struct seq_file *s, struct dlm_lkb *lkb, | |
277 | - int rsb_lookup) | |
278 | +static int print_format3_lock(struct seq_file *s, struct dlm_lkb *lkb, | |
279 | + int rsb_lookup) | |
280 | { | |
281 | u64 xid = 0; | |
282 | + int rv; | |
283 | ||
284 | if (lkb->lkb_flags & DLM_IFL_USER) { | |
285 | if (lkb->lkb_ua) | |
286 | xid = lkb->lkb_ua->xid; | |
287 | } | |
288 | ||
289 | - seq_printf(s, "lkb %x %d %x %u %llu %x %x %d %d %d %d %d %d %u %llu %llu\n", | |
290 | - lkb->lkb_id, | |
291 | - lkb->lkb_nodeid, | |
292 | - lkb->lkb_remid, | |
293 | - lkb->lkb_ownpid, | |
294 | - (unsigned long long)xid, | |
295 | - lkb->lkb_exflags, | |
296 | - lkb->lkb_flags, | |
297 | - lkb->lkb_status, | |
298 | - lkb->lkb_grmode, | |
299 | - lkb->lkb_rqmode, | |
300 | - lkb->lkb_highbast, | |
301 | - rsb_lookup, | |
302 | - lkb->lkb_wait_type, | |
303 | - lkb->lkb_lvbseq, | |
304 | - (unsigned long long)ktime_to_ns(lkb->lkb_timestamp), | |
305 | - (unsigned long long)ktime_to_ns(lkb->lkb_time_bast)); | |
306 | + rv = seq_printf(s, "lkb %x %d %x %u %llu %x %x %d %d %d %d %d %d %u %llu %llu\n", | |
307 | + lkb->lkb_id, | |
308 | + lkb->lkb_nodeid, | |
309 | + lkb->lkb_remid, | |
310 | + lkb->lkb_ownpid, | |
311 | + (unsigned long long)xid, | |
312 | + lkb->lkb_exflags, | |
313 | + lkb->lkb_flags, | |
314 | + lkb->lkb_status, | |
315 | + lkb->lkb_grmode, | |
316 | + lkb->lkb_rqmode, | |
317 | + lkb->lkb_highbast, | |
318 | + rsb_lookup, | |
319 | + lkb->lkb_wait_type, | |
320 | + lkb->lkb_lvbseq, | |
321 | + (unsigned long long)ktime_to_ns(lkb->lkb_timestamp), | |
322 | + (unsigned long long)ktime_to_ns(lkb->lkb_time_bast)); | |
323 | + return rv; | |
324 | } | |
325 | ||
326 | static int print_format3(struct dlm_rsb *r, struct seq_file *s) | |
327 | @@ -247,18 +270,21 @@ static int print_format3(struct dlm_rsb *r, struct seq_file *s) | |
328 | struct dlm_lkb *lkb; | |
329 | int i, lvblen = r->res_ls->ls_lvblen; | |
330 | int print_name = 1; | |
331 | + int rv; | |
332 | ||
333 | lock_rsb(r); | |
334 | ||
335 | - seq_printf(s, "rsb %p %d %x %lx %d %d %u %d ", | |
336 | - r, | |
337 | - r->res_nodeid, | |
338 | - r->res_first_lkid, | |
339 | - r->res_flags, | |
340 | - !list_empty(&r->res_root_list), | |
341 | - !list_empty(&r->res_recover_list), | |
342 | - r->res_recover_locks_count, | |
343 | - r->res_length); | |
344 | + rv = seq_printf(s, "rsb %p %d %x %lx %d %d %u %d ", | |
345 | + r, | |
346 | + r->res_nodeid, | |
347 | + r->res_first_lkid, | |
348 | + r->res_flags, | |
349 | + !list_empty(&r->res_root_list), | |
350 | + !list_empty(&r->res_recover_list), | |
351 | + r->res_recover_locks_count, | |
352 | + r->res_length); | |
353 | + if (rv) | |
354 | + goto out; | |
355 | ||
356 | for (i = 0; i < r->res_length; i++) { | |
357 | if (!isascii(r->res_name[i]) || !isprint(r->res_name[i])) | |
358 | @@ -273,7 +299,9 @@ static int print_format3(struct dlm_rsb *r, struct seq_file *s) | |
359 | else | |
360 | seq_printf(s, " %02x", (unsigned char)r->res_name[i]); | |
361 | } | |
362 | - seq_printf(s, "\n"); | |
363 | + rv = seq_printf(s, "\n"); | |
364 | + if (rv) | |
365 | + goto out; | |
366 | ||
367 | if (!r->res_lvbptr) | |
368 | goto do_locks; | |
369 | @@ -282,344 +310,294 @@ static int print_format3(struct dlm_rsb *r, struct seq_file *s) | |
370 | ||
371 | for (i = 0; i < lvblen; i++) | |
372 | seq_printf(s, " %02x", (unsigned char)r->res_lvbptr[i]); | |
373 | - seq_printf(s, "\n"); | |
374 | + rv = seq_printf(s, "\n"); | |
375 | + if (rv) | |
376 | + goto out; | |
377 | ||
378 | do_locks: | |
379 | - list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) | |
380 | - print_format3_lock(s, lkb, 0); | |
381 | - | |
382 | - list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) | |
383 | - print_format3_lock(s, lkb, 0); | |
384 | - | |
385 | - list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) | |
386 | - print_format3_lock(s, lkb, 0); | |
387 | - | |
388 | - list_for_each_entry(lkb, &r->res_lookup, lkb_rsb_lookup) | |
389 | - print_format3_lock(s, lkb, 1); | |
390 | - | |
391 | - unlock_rsb(r); | |
392 | - return 0; | |
393 | -} | |
394 | - | |
395 | -static int rsb_iter_next(struct rsb_iter *ri) | |
396 | -{ | |
397 | - struct dlm_ls *ls = ri->ls; | |
398 | - int i; | |
399 | - | |
400 | - if (!ri->next) { | |
401 | - top: | |
402 | - /* Find the next non-empty hash bucket */ | |
403 | - for (i = ri->entry; i < ls->ls_rsbtbl_size; i++) { | |
404 | - read_lock(&ls->ls_rsbtbl[i].lock); | |
405 | - if (!list_empty(&ls->ls_rsbtbl[i].list)) { | |
406 | - ri->next = ls->ls_rsbtbl[i].list.next; | |
407 | - ri->rsb = list_entry(ri->next, struct dlm_rsb, | |
408 | - res_hashchain); | |
409 | - dlm_hold_rsb(ri->rsb); | |
410 | - read_unlock(&ls->ls_rsbtbl[i].lock); | |
411 | - break; | |
412 | - } | |
413 | - read_unlock(&ls->ls_rsbtbl[i].lock); | |
414 | - } | |
415 | - ri->entry = i; | |
416 | - | |
417 | - if (ri->entry >= ls->ls_rsbtbl_size) | |
418 | - return 1; | |
419 | - } else { | |
420 | - struct dlm_rsb *old = ri->rsb; | |
421 | - i = ri->entry; | |
422 | - read_lock(&ls->ls_rsbtbl[i].lock); | |
423 | - ri->next = ri->next->next; | |
424 | - if (ri->next->next == ls->ls_rsbtbl[i].list.next) { | |
425 | - /* End of list - move to next bucket */ | |
426 | - ri->next = NULL; | |
427 | - ri->entry++; | |
428 | - read_unlock(&ls->ls_rsbtbl[i].lock); | |
429 | - dlm_put_rsb(old); | |
430 | - goto top; | |
431 | - } | |
432 | - ri->rsb = list_entry(ri->next, struct dlm_rsb, res_hashchain); | |
433 | - dlm_hold_rsb(ri->rsb); | |
434 | - read_unlock(&ls->ls_rsbtbl[i].lock); | |
435 | - dlm_put_rsb(old); | |
436 | + list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) { | |
437 | + rv = print_format3_lock(s, lkb, 0); | |
438 | + if (rv) | |
439 | + goto out; | |
440 | } | |
441 | ||
442 | - return 0; | |
443 | -} | |
444 | - | |
445 | -static void rsb_iter_free(struct rsb_iter *ri) | |
446 | -{ | |
447 | - kfree(ri); | |
448 | -} | |
449 | - | |
450 | -static struct rsb_iter *rsb_iter_init(struct dlm_ls *ls) | |
451 | -{ | |
452 | - struct rsb_iter *ri; | |
453 | - | |
454 | - ri = kzalloc(sizeof *ri, GFP_KERNEL); | |
455 | - if (!ri) | |
456 | - return NULL; | |
457 | - | |
458 | - ri->ls = ls; | |
459 | - ri->entry = 0; | |
460 | - ri->next = NULL; | |
461 | - ri->format = 1; | |
462 | - | |
463 | - if (rsb_iter_next(ri)) { | |
464 | - rsb_iter_free(ri); | |
465 | - return NULL; | |
466 | + list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) { | |
467 | + rv = print_format3_lock(s, lkb, 0); | |
468 | + if (rv) | |
469 | + goto out; | |
470 | } | |
471 | ||
472 | - return ri; | |
473 | -} | |
474 | - | |
475 | -static void *rsb_seq_start(struct seq_file *file, loff_t *pos) | |
476 | -{ | |
477 | - struct rsb_iter *ri; | |
478 | - loff_t n = *pos; | |
479 | - | |
480 | - ri = rsb_iter_init(file->private); | |
481 | - if (!ri) | |
482 | - return NULL; | |
483 | - | |
484 | - while (n--) { | |
485 | - if (rsb_iter_next(ri)) { | |
486 | - rsb_iter_free(ri); | |
487 | - return NULL; | |
488 | - } | |
489 | + list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) { | |
490 | + rv = print_format3_lock(s, lkb, 0); | |
491 | + if (rv) | |
492 | + goto out; | |
493 | } | |
494 | ||
495 | - return ri; | |
496 | -} | |
497 | - | |
498 | -static void *rsb_seq_next(struct seq_file *file, void *iter_ptr, loff_t *pos) | |
499 | -{ | |
500 | - struct rsb_iter *ri = iter_ptr; | |
501 | - | |
502 | - (*pos)++; | |
503 | - | |
504 | - if (rsb_iter_next(ri)) { | |
505 | - rsb_iter_free(ri); | |
506 | - return NULL; | |
507 | + list_for_each_entry(lkb, &r->res_lookup, lkb_rsb_lookup) { | |
508 | + rv = print_format3_lock(s, lkb, 1); | |
509 | + if (rv) | |
510 | + goto out; | |
511 | } | |
512 | - | |
513 | - return ri; | |
514 | + out: | |
515 | + unlock_rsb(r); | |
516 | + return rv; | |
517 | } | |
518 | ||
519 | -static void rsb_seq_stop(struct seq_file *file, void *iter_ptr) | |
520 | -{ | |
521 | - /* nothing for now */ | |
522 | -} | |
523 | +struct rsbtbl_iter { | |
524 | + struct dlm_rsb *rsb; | |
525 | + unsigned bucket; | |
526 | + int format; | |
527 | + int header; | |
528 | +}; | |
529 | ||
530 | -static int rsb_seq_show(struct seq_file *file, void *iter_ptr) | |
531 | +/* seq_printf returns -1 if the buffer is full, and 0 otherwise. | |
532 | + If the buffer is full, seq_printf can be called again, but it | |
533 | + does nothing and just returns -1. So, the these printing routines | |
534 | + periodically check the return value to avoid wasting too much time | |
535 | + trying to print to a full buffer. */ | |
536 | + | |
537 | +static int table_seq_show(struct seq_file *seq, void *iter_ptr) | |
538 | { | |
539 | - struct rsb_iter *ri = iter_ptr; | |
540 | + struct rsbtbl_iter *ri = iter_ptr; | |
541 | + int rv = 0; | |
542 | ||
543 | switch (ri->format) { | |
544 | case 1: | |
545 | - print_format1(ri->rsb, file); | |
546 | + rv = print_format1(ri->rsb, seq); | |
547 | break; | |
548 | case 2: | |
549 | if (ri->header) { | |
550 | - seq_printf(file, "id nodeid remid pid xid exflags " | |
551 | - "flags sts grmode rqmode time_ms " | |
552 | - "r_nodeid r_len r_name\n"); | |
553 | + seq_printf(seq, "id nodeid remid pid xid exflags " | |
554 | + "flags sts grmode rqmode time_ms " | |
555 | + "r_nodeid r_len r_name\n"); | |
556 | ri->header = 0; | |
557 | } | |
558 | - print_format2(ri->rsb, file); | |
559 | + rv = print_format2(ri->rsb, seq); | |
560 | break; | |
561 | case 3: | |
562 | if (ri->header) { | |
563 | - seq_printf(file, "version rsb 1.1 lvb 1.1 lkb 1.1\n"); | |
564 | + seq_printf(seq, "version rsb 1.1 lvb 1.1 lkb 1.1\n"); | |
565 | ri->header = 0; | |
566 | } | |
567 | - print_format3(ri->rsb, file); | |
568 | + rv = print_format3(ri->rsb, seq); | |
569 | break; | |
570 | } | |
571 | ||
572 | - return 0; | |
573 | + return rv; | |
574 | } | |
575 | ||
576 | -static struct seq_operations rsb_seq_ops = { | |
577 | - .start = rsb_seq_start, | |
578 | - .next = rsb_seq_next, | |
579 | - .stop = rsb_seq_stop, | |
580 | - .show = rsb_seq_show, | |
581 | -}; | |
582 | +static struct seq_operations format1_seq_ops; | |
583 | +static struct seq_operations format2_seq_ops; | |
584 | +static struct seq_operations format3_seq_ops; | |
585 | ||
586 | -static int rsb_open(struct inode *inode, struct file *file) | |
587 | +static void *table_seq_start(struct seq_file *seq, loff_t *pos) | |
588 | { | |
589 | - struct seq_file *seq; | |
590 | - int ret; | |
591 | - | |
592 | - ret = seq_open(file, &rsb_seq_ops); | |
593 | - if (ret) | |
594 | - return ret; | |
595 | - | |
596 | - seq = file->private_data; | |
597 | - seq->private = inode->i_private; | |
598 | - | |
599 | - return 0; | |
600 | -} | |
601 | - | |
602 | -static const struct file_operations rsb_fops = { | |
603 | - .owner = THIS_MODULE, | |
604 | - .open = rsb_open, | |
605 | - .read = seq_read, | |
606 | - .llseek = seq_lseek, | |
607 | - .release = seq_release | |
608 | -}; | |
609 | + struct dlm_ls *ls = seq->private; | |
610 | + struct rsbtbl_iter *ri; | |
611 | + struct dlm_rsb *r; | |
612 | + loff_t n = *pos; | |
613 | + unsigned bucket, entry; | |
614 | ||
615 | -/* | |
616 | - * Dump state in compact per-lock listing | |
617 | - */ | |
618 | + bucket = n >> 32; | |
619 | + entry = n & ((1LL << 32) - 1); | |
620 | ||
621 | -static struct rsb_iter *locks_iter_init(struct dlm_ls *ls, loff_t *pos) | |
622 | -{ | |
623 | - struct rsb_iter *ri; | |
624 | + if (bucket >= ls->ls_rsbtbl_size) | |
625 | + return NULL; | |
626 | ||
627 | - ri = kzalloc(sizeof *ri, GFP_KERNEL); | |
628 | + ri = kzalloc(sizeof(struct rsbtbl_iter), GFP_KERNEL); | |
629 | if (!ri) | |
630 | return NULL; | |
631 | - | |
632 | - ri->ls = ls; | |
633 | - ri->entry = 0; | |
634 | - ri->next = NULL; | |
635 | - ri->format = 2; | |
636 | - | |
637 | - if (*pos == 0) | |
638 | + if (n == 0) | |
639 | ri->header = 1; | |
640 | - | |
641 | - if (rsb_iter_next(ri)) { | |
642 | - rsb_iter_free(ri); | |
643 | - return NULL; | |
644 | + if (seq->op == &format1_seq_ops) | |
645 | + ri->format = 1; | |
646 | + if (seq->op == &format2_seq_ops) | |
647 | + ri->format = 2; | |
648 | + if (seq->op == &format3_seq_ops) | |
649 | + ri->format = 3; | |
650 | + | |
651 | + read_lock(&ls->ls_rsbtbl[bucket].lock); | |
652 | + if (!list_empty(&ls->ls_rsbtbl[bucket].list)) { | |
653 | + list_for_each_entry(r, &ls->ls_rsbtbl[bucket].list, | |
654 | + res_hashchain) { | |
655 | + if (!entry--) { | |
656 | + dlm_hold_rsb(r); | |
657 | + ri->rsb = r; | |
658 | + ri->bucket = bucket; | |
659 | + read_unlock(&ls->ls_rsbtbl[bucket].lock); | |
660 | + return ri; | |
661 | + } | |
662 | + } | |
663 | } | |
664 | + read_unlock(&ls->ls_rsbtbl[bucket].lock); | |
665 | ||
666 | - return ri; | |
667 | -} | |
668 | + /* | |
669 | + * move to the first rsb in the next non-empty bucket | |
670 | + */ | |
671 | ||
672 | -static void *locks_seq_start(struct seq_file *file, loff_t *pos) | |
673 | -{ | |
674 | - struct rsb_iter *ri; | |
675 | - loff_t n = *pos; | |
676 | + /* zero the entry */ | |
677 | + n &= ~((1LL << 32) - 1); | |
678 | ||
679 | - ri = locks_iter_init(file->private, pos); | |
680 | - if (!ri) | |
681 | - return NULL; | |
682 | + while (1) { | |
683 | + bucket++; | |
684 | + n += 1LL << 32; | |
685 | ||
686 | - while (n--) { | |
687 | - if (rsb_iter_next(ri)) { | |
688 | - rsb_iter_free(ri); | |
689 | + if (bucket >= ls->ls_rsbtbl_size) { | |
690 | + kfree(ri); | |
691 | return NULL; | |
692 | } | |
693 | - } | |
694 | ||
695 | - return ri; | |
696 | + read_lock(&ls->ls_rsbtbl[bucket].lock); | |
697 | + if (!list_empty(&ls->ls_rsbtbl[bucket].list)) { | |
698 | + r = list_first_entry(&ls->ls_rsbtbl[bucket].list, | |
699 | + struct dlm_rsb, res_hashchain); | |
700 | + dlm_hold_rsb(r); | |
701 | + ri->rsb = r; | |
702 | + ri->bucket = bucket; | |
703 | + read_unlock(&ls->ls_rsbtbl[bucket].lock); | |
704 | + *pos = n; | |
705 | + return ri; | |
706 | + } | |
707 | + read_unlock(&ls->ls_rsbtbl[bucket].lock); | |
708 | + } | |
709 | } | |
710 | ||
711 | -static struct seq_operations locks_seq_ops = { | |
712 | - .start = locks_seq_start, | |
713 | - .next = rsb_seq_next, | |
714 | - .stop = rsb_seq_stop, | |
715 | - .show = rsb_seq_show, | |
716 | -}; | |
717 | - | |
718 | -static int locks_open(struct inode *inode, struct file *file) | |
719 | +static void *table_seq_next(struct seq_file *seq, void *iter_ptr, loff_t *pos) | |
720 | { | |
721 | - struct seq_file *seq; | |
722 | - int ret; | |
723 | - | |
724 | - ret = seq_open(file, &locks_seq_ops); | |
725 | - if (ret) | |
726 | - return ret; | |
727 | - | |
728 | - seq = file->private_data; | |
729 | - seq->private = inode->i_private; | |
730 | - | |
731 | - return 0; | |
732 | -} | |
733 | - | |
734 | -static const struct file_operations locks_fops = { | |
735 | - .owner = THIS_MODULE, | |
736 | - .open = locks_open, | |
737 | - .read = seq_read, | |
738 | - .llseek = seq_lseek, | |
739 | - .release = seq_release | |
740 | -}; | |
741 | - | |
742 | -/* | |
743 | - * Dump all rsb/lvb/lkb state in compact listing, more complete than _locks | |
744 | - * This can replace both formats 1 and 2 eventually. | |
745 | - */ | |
746 | + struct dlm_ls *ls = seq->private; | |
747 | + struct rsbtbl_iter *ri = iter_ptr; | |
748 | + struct list_head *next; | |
749 | + struct dlm_rsb *r, *rp; | |
750 | + loff_t n = *pos; | |
751 | + unsigned bucket; | |
752 | + | |
753 | + bucket = n >> 32; | |
754 | + | |
755 | + /* | |
756 | + * move to the next rsb in the same bucket | |
757 | + */ | |
758 | + | |
759 | + read_lock(&ls->ls_rsbtbl[bucket].lock); | |
760 | + rp = ri->rsb; | |
761 | + next = rp->res_hashchain.next; | |
762 | + | |
763 | + if (next != &ls->ls_rsbtbl[bucket].list) { | |
764 | + r = list_entry(next, struct dlm_rsb, res_hashchain); | |
765 | + dlm_hold_rsb(r); | |
766 | + ri->rsb = r; | |
767 | + read_unlock(&ls->ls_rsbtbl[bucket].lock); | |
768 | + dlm_put_rsb(rp); | |
769 | + ++*pos; | |
770 | + return ri; | |
771 | + } | |
772 | + read_unlock(&ls->ls_rsbtbl[bucket].lock); | |
773 | + dlm_put_rsb(rp); | |
774 | ||
775 | -static struct rsb_iter *all_iter_init(struct dlm_ls *ls, loff_t *pos) | |
776 | -{ | |
777 | - struct rsb_iter *ri; | |
778 | + /* | |
779 | + * move to the first rsb in the next non-empty bucket | |
780 | + */ | |
781 | ||
782 | - ri = kzalloc(sizeof *ri, GFP_KERNEL); | |
783 | - if (!ri) | |
784 | - return NULL; | |
785 | + /* zero the entry */ | |
786 | + n &= ~((1LL << 32) - 1); | |
787 | ||
788 | - ri->ls = ls; | |
789 | - ri->entry = 0; | |
790 | - ri->next = NULL; | |
791 | - ri->format = 3; | |
792 | + while (1) { | |
793 | + bucket++; | |
794 | + n += 1LL << 32; | |
795 | ||
796 | - if (*pos == 0) | |
797 | - ri->header = 1; | |
798 | + if (bucket >= ls->ls_rsbtbl_size) { | |
799 | + kfree(ri); | |
800 | + return NULL; | |
801 | + } | |
802 | ||
803 | - if (rsb_iter_next(ri)) { | |
804 | - rsb_iter_free(ri); | |
805 | - return NULL; | |
806 | + read_lock(&ls->ls_rsbtbl[bucket].lock); | |
807 | + if (!list_empty(&ls->ls_rsbtbl[bucket].list)) { | |
808 | + r = list_first_entry(&ls->ls_rsbtbl[bucket].list, | |
809 | + struct dlm_rsb, res_hashchain); | |
810 | + dlm_hold_rsb(r); | |
811 | + ri->rsb = r; | |
812 | + ri->bucket = bucket; | |
813 | + read_unlock(&ls->ls_rsbtbl[bucket].lock); | |
814 | + *pos = n; | |
815 | + return ri; | |
816 | + } | |
817 | + read_unlock(&ls->ls_rsbtbl[bucket].lock); | |
818 | } | |
819 | - | |
820 | - return ri; | |
821 | } | |
822 | ||
823 | -static void *all_seq_start(struct seq_file *file, loff_t *pos) | |
824 | +static void table_seq_stop(struct seq_file *seq, void *iter_ptr) | |
825 | { | |
826 | - struct rsb_iter *ri; | |
827 | - loff_t n = *pos; | |
828 | - | |
829 | - ri = all_iter_init(file->private, pos); | |
830 | - if (!ri) | |
831 | - return NULL; | |
832 | + struct rsbtbl_iter *ri = iter_ptr; | |
833 | ||
834 | - while (n--) { | |
835 | - if (rsb_iter_next(ri)) { | |
836 | - rsb_iter_free(ri); | |
837 | - return NULL; | |
838 | - } | |
839 | + if (ri) { | |
840 | + dlm_put_rsb(ri->rsb); | |
841 | + kfree(ri); | |
842 | } | |
843 | - | |
844 | - return ri; | |
845 | } | |
846 | ||
847 | -static struct seq_operations all_seq_ops = { | |
848 | - .start = all_seq_start, | |
849 | - .next = rsb_seq_next, | |
850 | - .stop = rsb_seq_stop, | |
851 | - .show = rsb_seq_show, | |
852 | +static struct seq_operations format1_seq_ops = { | |
853 | + .start = table_seq_start, | |
854 | + .next = table_seq_next, | |
855 | + .stop = table_seq_stop, | |
856 | + .show = table_seq_show, | |
857 | }; | |
858 | ||
859 | -static int all_open(struct inode *inode, struct file *file) | |
860 | +static struct seq_operations format2_seq_ops = { | |
861 | + .start = table_seq_start, | |
862 | + .next = table_seq_next, | |
863 | + .stop = table_seq_stop, | |
864 | + .show = table_seq_show, | |
865 | +}; | |
866 | + | |
867 | +static struct seq_operations format3_seq_ops = { | |
868 | + .start = table_seq_start, | |
869 | + .next = table_seq_next, | |
870 | + .stop = table_seq_stop, | |
871 | + .show = table_seq_show, | |
872 | +}; | |
873 | + | |
874 | +static const struct file_operations format1_fops; | |
875 | +static const struct file_operations format2_fops; | |
876 | +static const struct file_operations format3_fops; | |
877 | + | |
878 | +static int table_open(struct inode *inode, struct file *file) | |
879 | { | |
880 | struct seq_file *seq; | |
881 | - int ret; | |
882 | + int ret = -1; | |
883 | + | |
884 | + if (file->f_op == &format1_fops) | |
885 | + ret = seq_open(file, &format1_seq_ops); | |
886 | + else if (file->f_op == &format2_fops) | |
887 | + ret = seq_open(file, &format2_seq_ops); | |
888 | + else if (file->f_op == &format3_fops) | |
889 | + ret = seq_open(file, &format3_seq_ops); | |
890 | ||
891 | - ret = seq_open(file, &all_seq_ops); | |
892 | if (ret) | |
893 | return ret; | |
894 | ||
895 | seq = file->private_data; | |
896 | - seq->private = inode->i_private; | |
897 | - | |
898 | + seq->private = inode->i_private; /* the dlm_ls */ | |
899 | return 0; | |
900 | } | |
901 | ||
902 | -static const struct file_operations all_fops = { | |
903 | +static const struct file_operations format1_fops = { | |
904 | + .owner = THIS_MODULE, | |
905 | + .open = table_open, | |
906 | + .read = seq_read, | |
907 | + .llseek = seq_lseek, | |
908 | + .release = seq_release | |
909 | +}; | |
910 | + | |
911 | +static const struct file_operations format2_fops = { | |
912 | + .owner = THIS_MODULE, | |
913 | + .open = table_open, | |
914 | + .read = seq_read, | |
915 | + .llseek = seq_lseek, | |
916 | + .release = seq_release | |
917 | +}; | |
918 | + | |
919 | +static const struct file_operations format3_fops = { | |
920 | .owner = THIS_MODULE, | |
921 | - .open = all_open, | |
922 | + .open = table_open, | |
923 | .read = seq_read, | |
924 | .llseek = seq_lseek, | |
925 | .release = seq_release | |
926 | @@ -689,7 +667,7 @@ int dlm_create_debug_file(struct dlm_ls *ls) | |
927 | S_IFREG | S_IRUGO, | |
928 | dlm_root, | |
929 | ls, | |
930 | - &rsb_fops); | |
931 | + &format1_fops); | |
932 | if (!ls->ls_debug_rsb_dentry) | |
933 | goto fail; | |
934 | ||
935 | @@ -702,7 +680,7 @@ int dlm_create_debug_file(struct dlm_ls *ls) | |
936 | S_IFREG | S_IRUGO, | |
937 | dlm_root, | |
938 | ls, | |
939 | - &locks_fops); | |
940 | + &format2_fops); | |
941 | if (!ls->ls_debug_locks_dentry) | |
942 | goto fail; | |
943 | ||
944 | @@ -715,7 +693,7 @@ int dlm_create_debug_file(struct dlm_ls *ls) | |
945 | S_IFREG | S_IRUGO, | |
946 | dlm_root, | |
947 | ls, | |
948 | - &all_fops); | |
949 | + &format3_fops); | |
950 | if (!ls->ls_debug_all_dentry) | |
951 | goto fail; | |
952 |