]>
Commit | Line | Data |
---|---|---|
d7e09d03 PT |
1 | /* |
2 | * GPL HEADER START | |
3 | * | |
4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 only, | |
8 | * as published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * General Public License version 2 for more details (a copy is included | |
14 | * in the LICENSE file that accompanied this code). | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * version 2 along with this program; If not, see | |
6a5b99a4 | 18 | * http://www.gnu.org/licenses/gpl-2.0.html |
d7e09d03 | 19 | * |
d7e09d03 PT |
20 | * GPL HEADER END |
21 | */ | |
22 | /* | |
23 | * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. | |
24 | * Use is subject to license terms. | |
25 | * | |
1dc563a6 | 26 | * Copyright (c) 2010, 2015, Intel Corporation. |
d7e09d03 PT |
27 | */ |
28 | /* | |
29 | * This file is part of Lustre, http://www.lustre.org/ | |
30 | * Lustre is a trademark of Sun Microsystems, Inc. | |
31 | * | |
32 | * lustre/ldlm/ldlm_resource.c | |
33 | * | |
34 | * Author: Phil Schwan <phil@clusterfs.com> | |
35 | * Author: Peter Braam <braam@clusterfs.com> | |
36 | */ | |
37 | ||
38 | #define DEBUG_SUBSYSTEM S_LDLM | |
e27db149 GKH |
39 | #include "../include/lustre_dlm.h" |
40 | #include "../include/lustre_fid.h" | |
41 | #include "../include/obd_class.h" | |
d7e09d03 PT |
42 | #include "ldlm_internal.h" |
43 | ||
44 | struct kmem_cache *ldlm_resource_slab, *ldlm_lock_slab; | |
45 | ||
ea28d21a MR |
46 | int ldlm_srv_namespace_nr; |
47 | int ldlm_cli_namespace_nr; | |
d7e09d03 PT |
48 | |
49 | struct mutex ldlm_srv_namespace_lock; | |
50 | LIST_HEAD(ldlm_srv_namespace_list); | |
51 | ||
52 | struct mutex ldlm_cli_namespace_lock; | |
91a50030 OD |
53 | /* Client Namespaces that have active resources in them. |
54 | * Once all resources go away, ldlm_poold moves such namespaces to the | |
6f789a6a OD |
55 | * inactive list |
56 | */ | |
91a50030 OD |
57 | LIST_HEAD(ldlm_cli_active_namespace_list); |
58 | /* Client namespaces that don't have any locks in them */ | |
58ba1c31 | 59 | static LIST_HEAD(ldlm_cli_inactive_namespace_list); |
d7e09d03 | 60 | |
700815d4 DE |
61 | static struct dentry *ldlm_debugfs_dir; |
62 | static struct dentry *ldlm_ns_debugfs_dir; | |
63 | struct dentry *ldlm_svc_debugfs_dir; | |
d7e09d03 | 64 | |
d7e09d03 | 65 | /* during debug dump certain amount of granted locks for one resource to avoid |
6f789a6a OD |
66 | * DDOS. |
67 | */ | |
58c6d133 | 68 | static unsigned int ldlm_dump_granted_max = 256; |
d7e09d03 | 69 | |
700815d4 DE |
70 | static ssize_t |
71 | lprocfs_wr_dump_ns(struct file *file, const char __user *buffer, | |
72 | size_t count, loff_t *off) | |
d7e09d03 PT |
73 | { |
74 | ldlm_dump_all_namespaces(LDLM_NAMESPACE_SERVER, D_DLMTRACE); | |
75 | ldlm_dump_all_namespaces(LDLM_NAMESPACE_CLIENT, D_DLMTRACE); | |
0a3bdb00 | 76 | return count; |
d7e09d03 | 77 | } |
c9f6bb96 | 78 | |
73bb1da6 PT |
79 | LPROC_SEQ_FOPS_WR_ONLY(ldlm, dump_ns); |
80 | ||
8b230932 MR |
81 | static int ldlm_rw_uint_seq_show(struct seq_file *m, void *v) |
82 | { | |
83 | seq_printf(m, "%u\n", *(unsigned int *)m->private); | |
84 | return 0; | |
85 | } | |
86 | ||
87 | static ssize_t | |
88 | ldlm_rw_uint_seq_write(struct file *file, const char __user *buffer, | |
89 | size_t count, loff_t *off) | |
90 | { | |
91 | struct seq_file *seq = file->private_data; | |
92 | ||
93 | if (count == 0) | |
94 | return 0; | |
95 | return kstrtouint_from_user(buffer, count, 0, | |
96 | (unsigned int *)seq->private); | |
97 | } | |
98 | ||
99 | LPROC_SEQ_FOPS(ldlm_rw_uint); | |
d7e09d03 | 100 | |
700815d4 DE |
101 | static struct lprocfs_vars ldlm_debugfs_list[] = { |
102 | { "dump_namespaces", &ldlm_dump_ns_fops, NULL, 0222 }, | |
103 | { "dump_granted_max", &ldlm_rw_uint_fops, &ldlm_dump_granted_max }, | |
104 | { NULL } | |
105 | }; | |
106 | ||
107 | int ldlm_debugfs_setup(void) | |
d7e09d03 PT |
108 | { |
109 | int rc; | |
700815d4 DE |
110 | |
111 | ldlm_debugfs_dir = ldebugfs_register(OBD_LDLM_DEVICENAME, | |
112 | debugfs_lustre_root, | |
113 | NULL, NULL); | |
114 | if (IS_ERR_OR_NULL(ldlm_debugfs_dir)) { | |
d7e09d03 | 115 | CERROR("LProcFS failed in ldlm-init\n"); |
700815d4 | 116 | rc = ldlm_debugfs_dir ? PTR_ERR(ldlm_debugfs_dir) : -ENOMEM; |
d1c0d446 | 117 | goto err; |
d7e09d03 PT |
118 | } |
119 | ||
700815d4 DE |
120 | ldlm_ns_debugfs_dir = ldebugfs_register("namespaces", |
121 | ldlm_debugfs_dir, | |
122 | NULL, NULL); | |
123 | if (IS_ERR_OR_NULL(ldlm_ns_debugfs_dir)) { | |
d7e09d03 | 124 | CERROR("LProcFS failed in ldlm-init\n"); |
700815d4 DE |
125 | rc = ldlm_ns_debugfs_dir ? PTR_ERR(ldlm_ns_debugfs_dir) |
126 | : -ENOMEM; | |
d1c0d446 | 127 | goto err_type; |
d7e09d03 PT |
128 | } |
129 | ||
700815d4 DE |
130 | ldlm_svc_debugfs_dir = ldebugfs_register("services", |
131 | ldlm_debugfs_dir, | |
132 | NULL, NULL); | |
133 | if (IS_ERR_OR_NULL(ldlm_svc_debugfs_dir)) { | |
d7e09d03 | 134 | CERROR("LProcFS failed in ldlm-init\n"); |
700815d4 DE |
135 | rc = ldlm_svc_debugfs_dir ? PTR_ERR(ldlm_svc_debugfs_dir) |
136 | : -ENOMEM; | |
d1c0d446 | 137 | goto err_ns; |
d7e09d03 PT |
138 | } |
139 | ||
700815d4 | 140 | rc = ldebugfs_add_vars(ldlm_debugfs_dir, ldlm_debugfs_list, NULL); |
69565839 DE |
141 | if (rc) { |
142 | CERROR("LProcFS failed in ldlm-init\n"); | |
143 | goto err_svc; | |
144 | } | |
d7e09d03 | 145 | |
0a3bdb00 | 146 | return 0; |
d7e09d03 | 147 | |
69565839 DE |
148 | err_svc: |
149 | ldebugfs_remove(&ldlm_svc_debugfs_dir); | |
d7e09d03 | 150 | err_ns: |
700815d4 | 151 | ldebugfs_remove(&ldlm_ns_debugfs_dir); |
d7e09d03 | 152 | err_type: |
700815d4 | 153 | ldebugfs_remove(&ldlm_debugfs_dir); |
d7e09d03 | 154 | err: |
700815d4 DE |
155 | ldlm_svc_debugfs_dir = NULL; |
156 | ldlm_ns_debugfs_dir = NULL; | |
157 | ldlm_debugfs_dir = NULL; | |
0a3bdb00 | 158 | return rc; |
d7e09d03 PT |
159 | } |
160 | ||
700815d4 | 161 | void ldlm_debugfs_cleanup(void) |
d7e09d03 | 162 | { |
700815d4 DE |
163 | if (!IS_ERR_OR_NULL(ldlm_svc_debugfs_dir)) |
164 | ldebugfs_remove(&ldlm_svc_debugfs_dir); | |
d7e09d03 | 165 | |
700815d4 DE |
166 | if (!IS_ERR_OR_NULL(ldlm_ns_debugfs_dir)) |
167 | ldebugfs_remove(&ldlm_ns_debugfs_dir); | |
d7e09d03 | 168 | |
700815d4 DE |
169 | if (!IS_ERR_OR_NULL(ldlm_debugfs_dir)) |
170 | ldebugfs_remove(&ldlm_debugfs_dir); | |
1e4db2b3 | 171 | |
700815d4 DE |
172 | ldlm_svc_debugfs_dir = NULL; |
173 | ldlm_ns_debugfs_dir = NULL; | |
174 | ldlm_debugfs_dir = NULL; | |
d7e09d03 PT |
175 | } |
176 | ||
61d4a2e4 OD |
177 | static ssize_t resource_count_show(struct kobject *kobj, struct attribute *attr, |
178 | char *buf) | |
d7e09d03 | 179 | { |
61d4a2e4 OD |
180 | struct ldlm_namespace *ns = container_of(kobj, struct ldlm_namespace, |
181 | ns_kobj); | |
d7e09d03 | 182 | __u64 res = 0; |
6ea510c1 | 183 | struct cfs_hash_bd bd; |
d7e09d03 PT |
184 | int i; |
185 | ||
6e3dd654 | 186 | /* result is not strictly consistent */ |
d7e09d03 PT |
187 | cfs_hash_for_each_bucket(ns->ns_rs_hash, &bd, i) |
188 | res += cfs_hash_bd_count_get(&bd); | |
61d4a2e4 | 189 | return sprintf(buf, "%lld\n", res); |
d7e09d03 | 190 | } |
61d4a2e4 | 191 | LUSTRE_RO_ATTR(resource_count); |
d7e09d03 | 192 | |
63af1f57 OD |
193 | static ssize_t lock_count_show(struct kobject *kobj, struct attribute *attr, |
194 | char *buf) | |
d7e09d03 | 195 | { |
63af1f57 OD |
196 | struct ldlm_namespace *ns = container_of(kobj, struct ldlm_namespace, |
197 | ns_kobj); | |
d7e09d03 PT |
198 | __u64 locks; |
199 | ||
200 | locks = lprocfs_stats_collector(ns->ns_stats, LDLM_NSS_LOCKS, | |
201 | LPROCFS_FIELDS_FLAGS_SUM); | |
63af1f57 | 202 | return sprintf(buf, "%lld\n", locks); |
d7e09d03 | 203 | } |
63af1f57 | 204 | LUSTRE_RO_ATTR(lock_count); |
d7e09d03 | 205 | |
3dd45982 OD |
206 | static ssize_t lock_unused_count_show(struct kobject *kobj, |
207 | struct attribute *attr, | |
208 | char *buf) | |
209 | { | |
210 | struct ldlm_namespace *ns = container_of(kobj, struct ldlm_namespace, | |
211 | ns_kobj); | |
212 | ||
213 | return sprintf(buf, "%d\n", ns->ns_nr_unused); | |
214 | } | |
215 | LUSTRE_RO_ATTR(lock_unused_count); | |
216 | ||
6784096b OD |
217 | static ssize_t lru_size_show(struct kobject *kobj, struct attribute *attr, |
218 | char *buf) | |
d7e09d03 | 219 | { |
6784096b OD |
220 | struct ldlm_namespace *ns = container_of(kobj, struct ldlm_namespace, |
221 | ns_kobj); | |
d7e09d03 PT |
222 | __u32 *nr = &ns->ns_max_unused; |
223 | ||
224 | if (ns_connect_lru_resize(ns)) | |
225 | nr = &ns->ns_nr_unused; | |
6784096b | 226 | return sprintf(buf, "%u", *nr); |
d7e09d03 PT |
227 | } |
228 | ||
6784096b OD |
229 | static ssize_t lru_size_store(struct kobject *kobj, struct attribute *attr, |
230 | const char *buffer, size_t count) | |
d7e09d03 | 231 | { |
6784096b OD |
232 | struct ldlm_namespace *ns = container_of(kobj, struct ldlm_namespace, |
233 | ns_kobj); | |
d7e09d03 PT |
234 | unsigned long tmp; |
235 | int lru_resize; | |
ae59720b | 236 | int err; |
d7e09d03 | 237 | |
6784096b | 238 | if (strncmp(buffer, "clear", 5) == 0) { |
d7e09d03 PT |
239 | CDEBUG(D_DLMTRACE, |
240 | "dropping all unused locks from namespace %s\n", | |
241 | ldlm_ns_name(ns)); | |
242 | if (ns_connect_lru_resize(ns)) { | |
243 | int canceled, unused = ns->ns_nr_unused; | |
244 | ||
245 | /* Try to cancel all @ns_nr_unused locks. */ | |
246 | canceled = ldlm_cancel_lru(ns, unused, 0, | |
581b75c2 | 247 | LDLM_LRU_FLAG_PASSED); |
d7e09d03 PT |
248 | if (canceled < unused) { |
249 | CDEBUG(D_DLMTRACE, | |
2d00bd17 JP |
250 | "not all requested locks are canceled, requested: %d, canceled: %d\n", |
251 | unused, | |
d7e09d03 PT |
252 | canceled); |
253 | return -EINVAL; | |
254 | } | |
255 | } else { | |
256 | tmp = ns->ns_max_unused; | |
257 | ns->ns_max_unused = 0; | |
581b75c2 | 258 | ldlm_cancel_lru(ns, 0, 0, LDLM_LRU_FLAG_PASSED); |
d7e09d03 PT |
259 | ns->ns_max_unused = tmp; |
260 | } | |
261 | return count; | |
262 | } | |
263 | ||
6784096b | 264 | err = kstrtoul(buffer, 10, &tmp); |
ae59720b | 265 | if (err != 0) { |
6784096b | 266 | CERROR("lru_size: invalid value written\n"); |
d7e09d03 PT |
267 | return -EINVAL; |
268 | } | |
269 | lru_resize = (tmp == 0); | |
270 | ||
271 | if (ns_connect_lru_resize(ns)) { | |
272 | if (!lru_resize) | |
273 | ns->ns_max_unused = (unsigned int)tmp; | |
274 | ||
275 | if (tmp > ns->ns_nr_unused) | |
276 | tmp = ns->ns_nr_unused; | |
277 | tmp = ns->ns_nr_unused - tmp; | |
278 | ||
279 | CDEBUG(D_DLMTRACE, | |
280 | "changing namespace %s unused locks from %u to %u\n", | |
281 | ldlm_ns_name(ns), ns->ns_nr_unused, | |
282 | (unsigned int)tmp); | |
581b75c2 | 283 | ldlm_cancel_lru(ns, tmp, LCF_ASYNC, LDLM_LRU_FLAG_PASSED); |
d7e09d03 PT |
284 | |
285 | if (!lru_resize) { | |
286 | CDEBUG(D_DLMTRACE, | |
287 | "disable lru_resize for namespace %s\n", | |
288 | ldlm_ns_name(ns)); | |
289 | ns->ns_connect_flags &= ~OBD_CONNECT_LRU_RESIZE; | |
290 | } | |
291 | } else { | |
292 | CDEBUG(D_DLMTRACE, | |
293 | "changing namespace %s max_unused from %u to %u\n", | |
294 | ldlm_ns_name(ns), ns->ns_max_unused, | |
295 | (unsigned int)tmp); | |
296 | ns->ns_max_unused = (unsigned int)tmp; | |
581b75c2 | 297 | ldlm_cancel_lru(ns, 0, LCF_ASYNC, LDLM_LRU_FLAG_PASSED); |
d7e09d03 PT |
298 | |
299 | /* Make sure that LRU resize was originally supported before | |
6f789a6a OD |
300 | * turning it on here. |
301 | */ | |
d7e09d03 PT |
302 | if (lru_resize && |
303 | (ns->ns_orig_connect_flags & OBD_CONNECT_LRU_RESIZE)) { | |
304 | CDEBUG(D_DLMTRACE, | |
305 | "enable lru_resize for namespace %s\n", | |
306 | ldlm_ns_name(ns)); | |
307 | ns->ns_connect_flags |= OBD_CONNECT_LRU_RESIZE; | |
308 | } | |
309 | } | |
310 | ||
311 | return count; | |
312 | } | |
6784096b | 313 | LUSTRE_RW_ATTR(lru_size); |
d7e09d03 | 314 | |
c841236d OD |
315 | static ssize_t lru_max_age_show(struct kobject *kobj, struct attribute *attr, |
316 | char *buf) | |
317 | { | |
318 | struct ldlm_namespace *ns = container_of(kobj, struct ldlm_namespace, | |
319 | ns_kobj); | |
320 | ||
321 | return sprintf(buf, "%u", ns->ns_max_age); | |
322 | } | |
323 | ||
324 | static ssize_t lru_max_age_store(struct kobject *kobj, struct attribute *attr, | |
325 | const char *buffer, size_t count) | |
326 | { | |
327 | struct ldlm_namespace *ns = container_of(kobj, struct ldlm_namespace, | |
328 | ns_kobj); | |
329 | unsigned long tmp; | |
330 | int err; | |
331 | ||
332 | err = kstrtoul(buffer, 10, &tmp); | |
333 | if (err != 0) | |
334 | return -EINVAL; | |
335 | ||
336 | ns->ns_max_age = tmp; | |
337 | ||
338 | return count; | |
339 | } | |
340 | LUSTRE_RW_ATTR(lru_max_age); | |
341 | ||
87d32094 OD |
342 | static ssize_t early_lock_cancel_show(struct kobject *kobj, |
343 | struct attribute *attr, | |
344 | char *buf) | |
d7e09d03 | 345 | { |
87d32094 OD |
346 | struct ldlm_namespace *ns = container_of(kobj, struct ldlm_namespace, |
347 | ns_kobj); | |
d7e09d03 | 348 | |
87d32094 | 349 | return sprintf(buf, "%d\n", ns_connect_cancelset(ns)); |
d7e09d03 PT |
350 | } |
351 | ||
87d32094 OD |
352 | static ssize_t early_lock_cancel_store(struct kobject *kobj, |
353 | struct attribute *attr, | |
354 | const char *buffer, | |
355 | size_t count) | |
d7e09d03 | 356 | { |
87d32094 OD |
357 | struct ldlm_namespace *ns = container_of(kobj, struct ldlm_namespace, |
358 | ns_kobj); | |
359 | unsigned long supp = -1; | |
d7e09d03 PT |
360 | int rc; |
361 | ||
87d32094 | 362 | rc = kstrtoul(buffer, 10, &supp); |
d7e09d03 PT |
363 | if (rc < 0) |
364 | return rc; | |
365 | ||
366 | if (supp == 0) | |
367 | ns->ns_connect_flags &= ~OBD_CONNECT_CANCELSET; | |
368 | else if (ns->ns_orig_connect_flags & OBD_CONNECT_CANCELSET) | |
369 | ns->ns_connect_flags |= OBD_CONNECT_CANCELSET; | |
370 | return count; | |
371 | } | |
87d32094 | 372 | LUSTRE_RW_ATTR(early_lock_cancel); |
d7e09d03 | 373 | |
18fd8850 OD |
374 | /* These are for namespaces in /sys/fs/lustre/ldlm/namespaces/ */ |
375 | static struct attribute *ldlm_ns_attrs[] = { | |
61d4a2e4 | 376 | &lustre_attr_resource_count.attr, |
63af1f57 | 377 | &lustre_attr_lock_count.attr, |
3dd45982 | 378 | &lustre_attr_lock_unused_count.attr, |
6784096b | 379 | &lustre_attr_lru_size.attr, |
c841236d | 380 | &lustre_attr_lru_max_age.attr, |
87d32094 | 381 | &lustre_attr_early_lock_cancel.attr, |
18fd8850 OD |
382 | NULL, |
383 | }; | |
384 | ||
385 | static void ldlm_ns_release(struct kobject *kobj) | |
386 | { | |
387 | struct ldlm_namespace *ns = container_of(kobj, struct ldlm_namespace, | |
388 | ns_kobj); | |
389 | complete(&ns->ns_kobj_unregister); | |
390 | } | |
391 | ||
392 | static struct kobj_type ldlm_ns_ktype = { | |
393 | .default_attrs = ldlm_ns_attrs, | |
394 | .sysfs_ops = &lustre_sysfs_ops, | |
395 | .release = ldlm_ns_release, | |
396 | }; | |
397 | ||
700815d4 | 398 | static void ldlm_namespace_debugfs_unregister(struct ldlm_namespace *ns) |
d7e09d03 | 399 | { |
700815d4 | 400 | if (IS_ERR_OR_NULL(ns->ns_debugfs_entry)) |
d7e09d03 PT |
401 | CERROR("dlm namespace %s has no procfs dir?\n", |
402 | ldlm_ns_name(ns)); | |
73bb1da6 | 403 | else |
700815d4 | 404 | ldebugfs_remove(&ns->ns_debugfs_entry); |
d7e09d03 | 405 | |
44b53f18 | 406 | if (ns->ns_stats) |
d7e09d03 PT |
407 | lprocfs_free_stats(&ns->ns_stats); |
408 | } | |
409 | ||
58c6d133 | 410 | static void ldlm_namespace_sysfs_unregister(struct ldlm_namespace *ns) |
18fd8850 OD |
411 | { |
412 | kobject_put(&ns->ns_kobj); | |
413 | wait_for_completion(&ns->ns_kobj_unregister); | |
414 | } | |
415 | ||
58c6d133 | 416 | static int ldlm_namespace_sysfs_register(struct ldlm_namespace *ns) |
18fd8850 OD |
417 | { |
418 | int err; | |
419 | ||
420 | ns->ns_kobj.kset = ldlm_ns_kset; | |
421 | init_completion(&ns->ns_kobj_unregister); | |
422 | err = kobject_init_and_add(&ns->ns_kobj, &ldlm_ns_ktype, NULL, | |
423 | "%s", ldlm_ns_name(ns)); | |
424 | ||
63af1f57 | 425 | ns->ns_stats = lprocfs_alloc_stats(LDLM_NSS_LAST, 0); |
44b53f18 | 426 | if (!ns->ns_stats) { |
63af1f57 OD |
427 | kobject_put(&ns->ns_kobj); |
428 | return -ENOMEM; | |
429 | } | |
430 | ||
431 | lprocfs_counter_init(ns->ns_stats, LDLM_NSS_LOCKS, | |
432 | LPROCFS_CNTR_AVGMINMAX, "locks", "locks"); | |
433 | ||
18fd8850 OD |
434 | return err; |
435 | } | |
436 | ||
700815d4 | 437 | static int ldlm_namespace_debugfs_register(struct ldlm_namespace *ns) |
d7e09d03 | 438 | { |
700815d4 | 439 | struct dentry *ns_entry; |
d7e09d03 | 440 | |
700815d4 DE |
441 | if (!IS_ERR_OR_NULL(ns->ns_debugfs_entry)) { |
442 | ns_entry = ns->ns_debugfs_entry; | |
73bb1da6 | 443 | } else { |
700815d4 DE |
444 | ns_entry = debugfs_create_dir(ldlm_ns_name(ns), |
445 | ldlm_ns_debugfs_dir); | |
44b53f18 | 446 | if (!ns_entry) |
73bb1da6 | 447 | return -ENOMEM; |
700815d4 | 448 | ns->ns_debugfs_entry = ns_entry; |
73bb1da6 PT |
449 | } |
450 | ||
d7e09d03 PT |
451 | return 0; |
452 | } | |
c9f6bb96 | 453 | |
d7e09d03 | 454 | #undef MAX_STRING_SIZE |
d7e09d03 | 455 | |
58c6d133 OD |
456 | static struct ldlm_resource *ldlm_resource_getref(struct ldlm_resource *res) |
457 | { | |
458 | LASSERT(res); | |
459 | LASSERT(res != LP_POISON); | |
460 | atomic_inc(&res->lr_refcount); | |
461 | CDEBUG(D_INFO, "getref res: %p count: %d\n", res, | |
462 | atomic_read(&res->lr_refcount)); | |
463 | return res; | |
464 | } | |
465 | ||
8dde0685 OD |
466 | static unsigned int ldlm_res_hop_hash(struct cfs_hash *hs, |
467 | const void *key, unsigned int mask) | |
d7e09d03 PT |
468 | { |
469 | const struct ldlm_res_id *id = key; | |
483ace06 RS |
470 | unsigned int val = 0; |
471 | unsigned int i; | |
d7e09d03 PT |
472 | |
473 | for (i = 0; i < RES_NAME_SIZE; i++) | |
474 | val += id->name[i]; | |
475 | return val & mask; | |
476 | } | |
477 | ||
8dde0685 OD |
478 | static unsigned int ldlm_res_hop_fid_hash(struct cfs_hash *hs, |
479 | const void *key, unsigned int mask) | |
d7e09d03 PT |
480 | { |
481 | const struct ldlm_res_id *id = key; | |
482 | struct lu_fid fid; | |
483 | __u32 hash; | |
484 | __u32 val; | |
485 | ||
486 | fid.f_seq = id->name[LUSTRE_RES_ID_SEQ_OFF]; | |
487 | fid.f_oid = (__u32)id->name[LUSTRE_RES_ID_VER_OID_OFF]; | |
488 | fid.f_ver = (__u32)(id->name[LUSTRE_RES_ID_VER_OID_OFF] >> 32); | |
489 | ||
490 | hash = fid_flatten32(&fid); | |
491 | hash += (hash >> 4) + (hash << 12); /* mixing oid and seq */ | |
492 | if (id->name[LUSTRE_RES_ID_HSH_OFF] != 0) { | |
493 | val = id->name[LUSTRE_RES_ID_HSH_OFF]; | |
494 | hash += (val >> 5) + (val << 11); | |
495 | } else { | |
496 | val = fid_oid(&fid); | |
497 | } | |
72c0824a | 498 | hash = hash_long(hash, hs->hs_bkt_bits); |
d7e09d03 | 499 | /* give me another random factor */ |
72c0824a | 500 | hash -= hash_long((unsigned long)hs, val % 11 + 3); |
d7e09d03 PT |
501 | |
502 | hash <<= hs->hs_cur_bits - hs->hs_bkt_bits; | |
503 | hash |= ldlm_res_hop_hash(hs, key, CFS_HASH_NBKT(hs) - 1); | |
504 | ||
505 | return hash & mask; | |
506 | } | |
507 | ||
508 | static void *ldlm_res_hop_key(struct hlist_node *hnode) | |
509 | { | |
510 | struct ldlm_resource *res; | |
511 | ||
512 | res = hlist_entry(hnode, struct ldlm_resource, lr_hash); | |
513 | return &res->lr_name; | |
514 | } | |
515 | ||
516 | static int ldlm_res_hop_keycmp(const void *key, struct hlist_node *hnode) | |
517 | { | |
518 | struct ldlm_resource *res; | |
519 | ||
520 | res = hlist_entry(hnode, struct ldlm_resource, lr_hash); | |
521 | return ldlm_res_eq((const struct ldlm_res_id *)key, | |
522 | (const struct ldlm_res_id *)&res->lr_name); | |
523 | } | |
524 | ||
525 | static void *ldlm_res_hop_object(struct hlist_node *hnode) | |
526 | { | |
527 | return hlist_entry(hnode, struct ldlm_resource, lr_hash); | |
528 | } | |
529 | ||
e7ddc48c AR |
530 | static void ldlm_res_hop_get_locked(struct cfs_hash *hs, |
531 | struct hlist_node *hnode) | |
d7e09d03 PT |
532 | { |
533 | struct ldlm_resource *res; | |
534 | ||
535 | res = hlist_entry(hnode, struct ldlm_resource, lr_hash); | |
536 | ldlm_resource_getref(res); | |
537 | } | |
538 | ||
e7ddc48c AR |
539 | static void ldlm_res_hop_put_locked(struct cfs_hash *hs, |
540 | struct hlist_node *hnode) | |
d7e09d03 PT |
541 | { |
542 | struct ldlm_resource *res; | |
543 | ||
544 | res = hlist_entry(hnode, struct ldlm_resource, lr_hash); | |
545 | /* cfs_hash_for_each_nolock is the only chance we call it */ | |
546 | ldlm_resource_putref_locked(res); | |
547 | } | |
548 | ||
6da6eabe | 549 | static void ldlm_res_hop_put(struct cfs_hash *hs, struct hlist_node *hnode) |
d7e09d03 PT |
550 | { |
551 | struct ldlm_resource *res; | |
552 | ||
553 | res = hlist_entry(hnode, struct ldlm_resource, lr_hash); | |
554 | ldlm_resource_putref(res); | |
555 | } | |
556 | ||
db9fc06b | 557 | static struct cfs_hash_ops ldlm_ns_hash_ops = { |
d7e09d03 | 558 | .hs_hash = ldlm_res_hop_hash, |
db9fc06b | 559 | .hs_key = ldlm_res_hop_key, |
d7e09d03 PT |
560 | .hs_keycmp = ldlm_res_hop_keycmp, |
561 | .hs_keycpy = NULL, | |
562 | .hs_object = ldlm_res_hop_object, | |
db9fc06b | 563 | .hs_get = ldlm_res_hop_get_locked, |
d7e09d03 | 564 | .hs_put_locked = ldlm_res_hop_put_locked, |
db9fc06b | 565 | .hs_put = ldlm_res_hop_put |
d7e09d03 PT |
566 | }; |
567 | ||
db9fc06b | 568 | static struct cfs_hash_ops ldlm_ns_fid_hash_ops = { |
d7e09d03 | 569 | .hs_hash = ldlm_res_hop_fid_hash, |
db9fc06b | 570 | .hs_key = ldlm_res_hop_key, |
d7e09d03 PT |
571 | .hs_keycmp = ldlm_res_hop_keycmp, |
572 | .hs_keycpy = NULL, | |
573 | .hs_object = ldlm_res_hop_object, | |
db9fc06b | 574 | .hs_get = ldlm_res_hop_get_locked, |
d7e09d03 | 575 | .hs_put_locked = ldlm_res_hop_put_locked, |
db9fc06b | 576 | .hs_put = ldlm_res_hop_put |
d7e09d03 PT |
577 | }; |
578 | ||
38d676da | 579 | struct ldlm_ns_hash_def { |
87ba6ebf | 580 | enum ldlm_ns_type nsd_type; |
d7e09d03 | 581 | /** hash bucket bits */ |
483ace06 | 582 | unsigned int nsd_bkt_bits; |
d7e09d03 | 583 | /** hash bits */ |
483ace06 | 584 | unsigned int nsd_all_bits; |
d7e09d03 | 585 | /** hash operations */ |
db9fc06b | 586 | struct cfs_hash_ops *nsd_hops; |
38d676da | 587 | }; |
d7e09d03 | 588 | |
58c6d133 | 589 | static struct ldlm_ns_hash_def ldlm_ns_hash_defs[] = { |
d7e09d03 PT |
590 | { |
591 | .nsd_type = LDLM_NS_TYPE_MDC, | |
592 | .nsd_bkt_bits = 11, | |
593 | .nsd_all_bits = 16, | |
594 | .nsd_hops = &ldlm_ns_fid_hash_ops, | |
595 | }, | |
596 | { | |
597 | .nsd_type = LDLM_NS_TYPE_MDT, | |
598 | .nsd_bkt_bits = 14, | |
599 | .nsd_all_bits = 21, | |
600 | .nsd_hops = &ldlm_ns_fid_hash_ops, | |
601 | }, | |
602 | { | |
603 | .nsd_type = LDLM_NS_TYPE_OSC, | |
604 | .nsd_bkt_bits = 8, | |
605 | .nsd_all_bits = 12, | |
606 | .nsd_hops = &ldlm_ns_hash_ops, | |
607 | }, | |
608 | { | |
609 | .nsd_type = LDLM_NS_TYPE_OST, | |
610 | .nsd_bkt_bits = 11, | |
611 | .nsd_all_bits = 17, | |
612 | .nsd_hops = &ldlm_ns_hash_ops, | |
613 | }, | |
614 | { | |
615 | .nsd_type = LDLM_NS_TYPE_MGC, | |
616 | .nsd_bkt_bits = 4, | |
617 | .nsd_all_bits = 4, | |
618 | .nsd_hops = &ldlm_ns_hash_ops, | |
619 | }, | |
620 | { | |
621 | .nsd_type = LDLM_NS_TYPE_MGT, | |
622 | .nsd_bkt_bits = 4, | |
623 | .nsd_all_bits = 4, | |
624 | .nsd_hops = &ldlm_ns_hash_ops, | |
625 | }, | |
626 | { | |
627 | .nsd_type = LDLM_NS_TYPE_UNKNOWN, | |
628 | }, | |
629 | }; | |
630 | ||
58c6d133 OD |
631 | /** Register \a ns in the list of namespaces */ |
632 | static void ldlm_namespace_register(struct ldlm_namespace *ns, | |
2885bdea | 633 | enum ldlm_side client) |
58c6d133 OD |
634 | { |
635 | mutex_lock(ldlm_namespace_lock(client)); | |
636 | LASSERT(list_empty(&ns->ns_list_chain)); | |
58ba1c31 | 637 | list_add(&ns->ns_list_chain, &ldlm_cli_inactive_namespace_list); |
58c6d133 OD |
638 | ldlm_namespace_nr_inc(client); |
639 | mutex_unlock(ldlm_namespace_lock(client)); | |
640 | } | |
641 | ||
d7e09d03 PT |
642 | /** |
643 | * Create and initialize new empty namespace. | |
644 | */ | |
645 | struct ldlm_namespace *ldlm_namespace_new(struct obd_device *obd, char *name, | |
2885bdea | 646 | enum ldlm_side client, |
4d0d6b0e | 647 | enum ldlm_appetite apt, |
87ba6ebf | 648 | enum ldlm_ns_type ns_type) |
d7e09d03 PT |
649 | { |
650 | struct ldlm_namespace *ns = NULL; | |
651 | struct ldlm_ns_bucket *nsb; | |
38d676da | 652 | struct ldlm_ns_hash_def *nsd; |
6ea510c1 | 653 | struct cfs_hash_bd bd; |
d7e09d03 PT |
654 | int idx; |
655 | int rc; | |
d7e09d03 | 656 | |
44b53f18 | 657 | LASSERT(obd); |
d7e09d03 PT |
658 | |
659 | rc = ldlm_get_ref(); | |
660 | if (rc) { | |
661 | CERROR("ldlm_get_ref failed: %d\n", rc); | |
0a3bdb00 | 662 | return NULL; |
d7e09d03 PT |
663 | } |
664 | ||
43ee4160 | 665 | for (idx = 0;; idx++) { |
d7e09d03 PT |
666 | nsd = &ldlm_ns_hash_defs[idx]; |
667 | if (nsd->nsd_type == LDLM_NS_TYPE_UNKNOWN) { | |
668 | CERROR("Unknown type %d for ns %s\n", ns_type, name); | |
d1c0d446 | 669 | goto out_ref; |
d7e09d03 PT |
670 | } |
671 | ||
672 | if (nsd->nsd_type == ns_type) | |
673 | break; | |
674 | } | |
675 | ||
352f7891 | 676 | ns = kzalloc(sizeof(*ns), GFP_NOFS); |
d7e09d03 | 677 | if (!ns) |
d1c0d446 | 678 | goto out_ref; |
d7e09d03 PT |
679 | |
680 | ns->ns_rs_hash = cfs_hash_create(name, | |
681 | nsd->nsd_all_bits, nsd->nsd_all_bits, | |
682 | nsd->nsd_bkt_bits, sizeof(*nsb), | |
683 | CFS_HASH_MIN_THETA, | |
684 | CFS_HASH_MAX_THETA, | |
685 | nsd->nsd_hops, | |
686 | CFS_HASH_DEPTH | | |
687 | CFS_HASH_BIGNAME | | |
688 | CFS_HASH_SPIN_BKTLOCK | | |
689 | CFS_HASH_NO_ITEMREF); | |
44b53f18 | 690 | if (!ns->ns_rs_hash) |
d1c0d446 | 691 | goto out_ns; |
d7e09d03 PT |
692 | |
693 | cfs_hash_for_each_bucket(ns->ns_rs_hash, &bd, idx) { | |
694 | nsb = cfs_hash_bd_extra_get(ns->ns_rs_hash, &bd); | |
695 | at_init(&nsb->nsb_at_estimate, ldlm_enqueue_min, 0); | |
696 | nsb->nsb_namespace = ns; | |
697 | } | |
698 | ||
699 | ns->ns_obd = obd; | |
700 | ns->ns_appetite = apt; | |
701 | ns->ns_client = client; | |
702 | ||
703 | INIT_LIST_HEAD(&ns->ns_list_chain); | |
704 | INIT_LIST_HEAD(&ns->ns_unused_list); | |
705 | spin_lock_init(&ns->ns_lock); | |
706 | atomic_set(&ns->ns_bref, 0); | |
707 | init_waitqueue_head(&ns->ns_waitq); | |
708 | ||
d7e09d03 PT |
709 | ns->ns_max_parallel_ast = LDLM_DEFAULT_PARALLEL_AST_LIMIT; |
710 | ns->ns_nr_unused = 0; | |
711 | ns->ns_max_unused = LDLM_DEFAULT_LRU_SIZE; | |
712 | ns->ns_max_age = LDLM_DEFAULT_MAX_ALIVE; | |
d7e09d03 PT |
713 | ns->ns_orig_connect_flags = 0; |
714 | ns->ns_connect_flags = 0; | |
715 | ns->ns_stopping = 0; | |
18fd8850 OD |
716 | |
717 | rc = ldlm_namespace_sysfs_register(ns); | |
718 | if (rc != 0) { | |
719 | CERROR("Can't initialize ns sysfs, rc %d\n", rc); | |
720 | goto out_hash; | |
721 | } | |
722 | ||
700815d4 | 723 | rc = ldlm_namespace_debugfs_register(ns); |
d7e09d03 PT |
724 | if (rc != 0) { |
725 | CERROR("Can't initialize ns proc, rc %d\n", rc); | |
18fd8850 | 726 | goto out_sysfs; |
d7e09d03 PT |
727 | } |
728 | ||
91a50030 | 729 | idx = ldlm_namespace_nr_read(client); |
d7e09d03 PT |
730 | rc = ldlm_pool_init(&ns->ns_pool, ns, idx, client); |
731 | if (rc) { | |
732 | CERROR("Can't initialize lock pool, rc %d\n", rc); | |
d1c0d446 | 733 | goto out_proc; |
d7e09d03 PT |
734 | } |
735 | ||
736 | ldlm_namespace_register(ns, client); | |
0a3bdb00 | 737 | return ns; |
d7e09d03 | 738 | out_proc: |
700815d4 | 739 | ldlm_namespace_debugfs_unregister(ns); |
18fd8850 OD |
740 | out_sysfs: |
741 | ldlm_namespace_sysfs_unregister(ns); | |
d7e09d03 PT |
742 | ldlm_namespace_cleanup(ns, 0); |
743 | out_hash: | |
744 | cfs_hash_putref(ns->ns_rs_hash); | |
745 | out_ns: | |
352f7891 | 746 | kfree(ns); |
d7e09d03 PT |
747 | out_ref: |
748 | ldlm_put_ref(); | |
0a3bdb00 | 749 | return NULL; |
d7e09d03 PT |
750 | } |
751 | EXPORT_SYMBOL(ldlm_namespace_new); | |
752 | ||
753 | extern struct ldlm_lock *ldlm_lock_get(struct ldlm_lock *lock); | |
754 | ||
755 | /** | |
756 | * Cancel and destroy all locks on a resource. | |
757 | * | |
758 | * If flags contains FL_LOCAL_ONLY, don't try to tell the server, just | |
759 | * clean up. This is currently only used for recovery, and we make | |
760 | * certain assumptions as a result--notably, that we shouldn't cancel | |
761 | * locks with refs. | |
762 | */ | |
763 | static void cleanup_resource(struct ldlm_resource *res, struct list_head *q, | |
764 | __u64 flags) | |
765 | { | |
766 | struct list_head *tmp; | |
cf739f84 | 767 | int rc = 0; |
d7e09d03 PT |
768 | bool local_only = !!(flags & LDLM_FL_LOCAL_ONLY); |
769 | ||
770 | do { | |
771 | struct ldlm_lock *lock = NULL; | |
cf739f84 | 772 | struct lustre_handle lockh; |
d7e09d03 PT |
773 | |
774 | /* First, we look for non-cleaned-yet lock | |
6f789a6a OD |
775 | * all cleaned locks are marked by CLEANED flag. |
776 | */ | |
d7e09d03 PT |
777 | lock_res(res); |
778 | list_for_each(tmp, q) { | |
24c198e9 | 779 | lock = list_entry(tmp, struct ldlm_lock, l_res_link); |
5a9a80ba | 780 | if (ldlm_is_cleaned(lock)) { |
d7e09d03 PT |
781 | lock = NULL; |
782 | continue; | |
783 | } | |
784 | LDLM_LOCK_GET(lock); | |
5a9a80ba | 785 | ldlm_set_cleaned(lock); |
d7e09d03 PT |
786 | break; |
787 | } | |
788 | ||
44b53f18 | 789 | if (!lock) { |
d7e09d03 PT |
790 | unlock_res(res); |
791 | break; | |
792 | } | |
793 | ||
794 | /* Set CBPENDING so nothing in the cancellation path | |
6f789a6a OD |
795 | * can match this lock. |
796 | */ | |
5a9a80ba BK |
797 | ldlm_set_cbpending(lock); |
798 | ldlm_set_failed(lock); | |
d7e09d03 PT |
799 | lock->l_flags |= flags; |
800 | ||
801 | /* ... without sending a CANCEL message for local_only. */ | |
802 | if (local_only) | |
5a9a80ba | 803 | ldlm_set_local_only(lock); |
d7e09d03 PT |
804 | |
805 | if (local_only && (lock->l_readers || lock->l_writers)) { | |
806 | /* This is a little bit gross, but much better than the | |
807 | * alternative: pretend that we got a blocking AST from | |
808 | * the server, so that when the lock is decref'd, it | |
6f789a6a OD |
809 | * will go away ... |
810 | */ | |
d7e09d03 PT |
811 | unlock_res(res); |
812 | LDLM_DEBUG(lock, "setting FL_LOCAL_ONLY"); | |
c68c3fa4 VF |
813 | if (lock->l_flags & LDLM_FL_FAIL_LOC) { |
814 | set_current_state(TASK_UNINTERRUPTIBLE); | |
815 | schedule_timeout(cfs_time_seconds(4)); | |
816 | set_current_state(TASK_RUNNING); | |
817 | } | |
d7e09d03 | 818 | if (lock->l_completion_ast) |
c68c3fa4 VF |
819 | lock->l_completion_ast(lock, LDLM_FL_FAILED, |
820 | NULL); | |
d7e09d03 PT |
821 | LDLM_LOCK_RELEASE(lock); |
822 | continue; | |
823 | } | |
824 | ||
cf739f84 OD |
825 | unlock_res(res); |
826 | ldlm_lock2handle(lock, &lockh); | |
46ff82f9 | 827 | rc = ldlm_cli_cancel(&lockh, LCF_LOCAL); |
cf739f84 OD |
828 | if (rc) |
829 | CERROR("ldlm_cli_cancel: %d\n", rc); | |
d7e09d03 PT |
830 | LDLM_LOCK_RELEASE(lock); |
831 | } while (1); | |
832 | } | |
833 | ||
6da6eabe | 834 | static int ldlm_resource_clean(struct cfs_hash *hs, struct cfs_hash_bd *bd, |
d7e09d03 PT |
835 | struct hlist_node *hnode, void *arg) |
836 | { | |
837 | struct ldlm_resource *res = cfs_hash_object(hs, hnode); | |
838 | __u64 flags = *(__u64 *)arg; | |
839 | ||
840 | cleanup_resource(res, &res->lr_granted, flags); | |
d7e09d03 PT |
841 | cleanup_resource(res, &res->lr_waiting, flags); |
842 | ||
843 | return 0; | |
844 | } | |
845 | ||
6da6eabe | 846 | static int ldlm_resource_complain(struct cfs_hash *hs, struct cfs_hash_bd *bd, |
d7e09d03 PT |
847 | struct hlist_node *hnode, void *arg) |
848 | { | |
849 | struct ldlm_resource *res = cfs_hash_object(hs, hnode); | |
850 | ||
851 | lock_res(res); | |
1ada25dc | 852 | CERROR("%s: namespace resource " DLDLMRES |
6d95e048 AD |
853 | " (%p) refcount nonzero (%d) after lock cleanup; forcing cleanup.\n", |
854 | ldlm_ns_name(ldlm_res_to_ns(res)), PLDLMRES(res), res, | |
d7e09d03 PT |
855 | atomic_read(&res->lr_refcount) - 1); |
856 | ||
857 | ldlm_resource_dump(D_ERROR, res); | |
858 | unlock_res(res); | |
859 | return 0; | |
860 | } | |
861 | ||
862 | /** | |
863 | * Cancel and destroy all locks in the namespace. | |
864 | * | |
865 | * Typically used during evictions when server notified client that it was | |
866 | * evicted and all of its state needs to be destroyed. | |
867 | * Also used during shutdown. | |
868 | */ | |
869 | int ldlm_namespace_cleanup(struct ldlm_namespace *ns, __u64 flags) | |
870 | { | |
44b53f18 | 871 | if (!ns) { |
d7e09d03 PT |
872 | CDEBUG(D_INFO, "NULL ns, skipping cleanup\n"); |
873 | return ELDLM_OK; | |
874 | } | |
875 | ||
c2242d14 NY |
876 | cfs_hash_for_each_nolock(ns->ns_rs_hash, ldlm_resource_clean, |
877 | &flags, 0); | |
878 | cfs_hash_for_each_nolock(ns->ns_rs_hash, ldlm_resource_complain, | |
879 | NULL, 0); | |
d7e09d03 PT |
880 | return ELDLM_OK; |
881 | } | |
882 | EXPORT_SYMBOL(ldlm_namespace_cleanup); | |
883 | ||
884 | /** | |
885 | * Attempts to free namespace. | |
886 | * | |
887 | * Only used when namespace goes away, like during an unmount. | |
888 | */ | |
889 | static int __ldlm_namespace_free(struct ldlm_namespace *ns, int force) | |
890 | { | |
d7e09d03 PT |
891 | /* At shutdown time, don't call the cancellation callback */ |
892 | ldlm_namespace_cleanup(ns, force ? LDLM_FL_LOCAL_ONLY : 0); | |
893 | ||
894 | if (atomic_read(&ns->ns_bref) > 0) { | |
895 | struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL); | |
896 | int rc; | |
902f3bb1 | 897 | |
d7e09d03 PT |
898 | CDEBUG(D_DLMTRACE, |
899 | "dlm namespace %s free waiting on refcount %d\n", | |
900 | ldlm_ns_name(ns), atomic_read(&ns->ns_bref)); | |
901 | force_wait: | |
902 | if (force) | |
df3c30f6 JY |
903 | lwi = LWI_TIMEOUT(msecs_to_jiffies(obd_timeout * |
904 | MSEC_PER_SEC) / 4, NULL, NULL); | |
d7e09d03 PT |
905 | |
906 | rc = l_wait_event(ns->ns_waitq, | |
907 | atomic_read(&ns->ns_bref) == 0, &lwi); | |
908 | ||
909 | /* Forced cleanups should be able to reclaim all references, | |
6f789a6a OD |
910 | * so it's safe to wait forever... we can't leak locks... |
911 | */ | |
d7e09d03 | 912 | if (force && rc == -ETIMEDOUT) { |
2d00bd17 JP |
913 | LCONSOLE_ERROR("Forced cleanup waiting for %s namespace with %d resources in use, (rc=%d)\n", |
914 | ldlm_ns_name(ns), | |
d7e09d03 | 915 | atomic_read(&ns->ns_bref), rc); |
d1c0d446 | 916 | goto force_wait; |
d7e09d03 PT |
917 | } |
918 | ||
919 | if (atomic_read(&ns->ns_bref)) { | |
2d00bd17 | 920 | LCONSOLE_ERROR("Cleanup waiting for %s namespace with %d resources in use, (rc=%d)\n", |
d7e09d03 PT |
921 | ldlm_ns_name(ns), |
922 | atomic_read(&ns->ns_bref), rc); | |
0a3bdb00 | 923 | return ELDLM_NAMESPACE_EXISTS; |
d7e09d03 PT |
924 | } |
925 | CDEBUG(D_DLMTRACE, "dlm namespace %s free done waiting\n", | |
926 | ldlm_ns_name(ns)); | |
927 | } | |
928 | ||
0a3bdb00 | 929 | return ELDLM_OK; |
d7e09d03 PT |
930 | } |
931 | ||
932 | /** | |
933 | * Performs various cleanups for passed \a ns to make it drop refc and be | |
934 | * ready for freeing. Waits for refc == 0. | |
935 | * | |
936 | * The following is done: | |
937 | * (0) Unregister \a ns from its list to make inaccessible for potential | |
938 | * users like pools thread and others; | |
939 | * (1) Clear all locks in \a ns. | |
940 | */ | |
941 | void ldlm_namespace_free_prior(struct ldlm_namespace *ns, | |
942 | struct obd_import *imp, | |
943 | int force) | |
944 | { | |
945 | int rc; | |
29aaf496 | 946 | |
bf050e55 | 947 | if (!ns) |
d7e09d03 | 948 | return; |
d7e09d03 PT |
949 | |
950 | spin_lock(&ns->ns_lock); | |
951 | ns->ns_stopping = 1; | |
952 | spin_unlock(&ns->ns_lock); | |
953 | ||
954 | /* | |
955 | * Can fail with -EINTR when force == 0 in which case try harder. | |
956 | */ | |
957 | rc = __ldlm_namespace_free(ns, force); | |
958 | if (rc != ELDLM_OK) { | |
959 | if (imp) { | |
960 | ptlrpc_disconnect_import(imp, 0); | |
961 | ptlrpc_invalidate_import(imp); | |
962 | } | |
963 | ||
964 | /* | |
965 | * With all requests dropped and the import inactive | |
6e3dd654 | 966 | * we are guaranteed all reference will be dropped. |
d7e09d03 PT |
967 | */ |
968 | rc = __ldlm_namespace_free(ns, 1); | |
969 | LASSERT(rc == 0); | |
970 | } | |
d7e09d03 PT |
971 | } |
972 | ||
58c6d133 OD |
973 | /** Unregister \a ns from the list of namespaces. */ |
974 | static void ldlm_namespace_unregister(struct ldlm_namespace *ns, | |
2885bdea | 975 | enum ldlm_side client) |
58c6d133 OD |
976 | { |
977 | mutex_lock(ldlm_namespace_lock(client)); | |
978 | LASSERT(!list_empty(&ns->ns_list_chain)); | |
979 | /* Some asserts and possibly other parts of the code are still | |
980 | * using list_empty(&ns->ns_list_chain). This is why it is | |
6f789a6a OD |
981 | * important to use list_del_init() here. |
982 | */ | |
58c6d133 OD |
983 | list_del_init(&ns->ns_list_chain); |
984 | ldlm_namespace_nr_dec(client); | |
985 | mutex_unlock(ldlm_namespace_lock(client)); | |
986 | } | |
987 | ||
d7e09d03 PT |
988 | /** |
989 | * Performs freeing memory structures related to \a ns. This is only done | |
990 | * when ldlm_namespce_free_prior() successfully removed all resources | |
991 | * referencing \a ns and its refc == 0. | |
992 | */ | |
993 | void ldlm_namespace_free_post(struct ldlm_namespace *ns) | |
994 | { | |
bf050e55 | 995 | if (!ns) |
d7e09d03 | 996 | return; |
d7e09d03 PT |
997 | |
998 | /* Make sure that nobody can find this ns in its list. */ | |
999 | ldlm_namespace_unregister(ns, ns->ns_client); | |
1000 | /* Fini pool _before_ parent proc dir is removed. This is important as | |
1001 | * ldlm_pool_fini() removes own proc dir which is child to @dir. | |
6f789a6a OD |
1002 | * Removing it after @dir may cause oops. |
1003 | */ | |
d7e09d03 PT |
1004 | ldlm_pool_fini(&ns->ns_pool); |
1005 | ||
700815d4 | 1006 | ldlm_namespace_debugfs_unregister(ns); |
9c7e397c | 1007 | ldlm_namespace_sysfs_unregister(ns); |
d7e09d03 PT |
1008 | cfs_hash_putref(ns->ns_rs_hash); |
1009 | /* Namespace \a ns should be not on list at this time, otherwise | |
1010 | * this will cause issues related to using freed \a ns in poold | |
6f789a6a OD |
1011 | * thread. |
1012 | */ | |
d7e09d03 | 1013 | LASSERT(list_empty(&ns->ns_list_chain)); |
352f7891 | 1014 | kfree(ns); |
d7e09d03 | 1015 | ldlm_put_ref(); |
d7e09d03 PT |
1016 | } |
1017 | ||
d7e09d03 PT |
1018 | void ldlm_namespace_get(struct ldlm_namespace *ns) |
1019 | { | |
1020 | atomic_inc(&ns->ns_bref); | |
1021 | } | |
d7e09d03 | 1022 | |
91a50030 | 1023 | /* This is only for callers that care about refcount */ |
58c6d133 | 1024 | static int ldlm_namespace_get_return(struct ldlm_namespace *ns) |
91a50030 OD |
1025 | { |
1026 | return atomic_inc_return(&ns->ns_bref); | |
1027 | } | |
1028 | ||
d7e09d03 PT |
1029 | void ldlm_namespace_put(struct ldlm_namespace *ns) |
1030 | { | |
1031 | if (atomic_dec_and_lock(&ns->ns_bref, &ns->ns_lock)) { | |
1032 | wake_up(&ns->ns_waitq); | |
1033 | spin_unlock(&ns->ns_lock); | |
1034 | } | |
1035 | } | |
d7e09d03 | 1036 | |
d7e09d03 | 1037 | /** Should be called with ldlm_namespace_lock(client) taken. */ |
91a50030 | 1038 | void ldlm_namespace_move_to_active_locked(struct ldlm_namespace *ns, |
2885bdea | 1039 | enum ldlm_side client) |
d7e09d03 PT |
1040 | { |
1041 | LASSERT(!list_empty(&ns->ns_list_chain)); | |
1042 | LASSERT(mutex_is_locked(ldlm_namespace_lock(client))); | |
1043 | list_move_tail(&ns->ns_list_chain, ldlm_namespace_list(client)); | |
1044 | } | |
1045 | ||
91a50030 OD |
1046 | /** Should be called with ldlm_namespace_lock(client) taken. */ |
1047 | void ldlm_namespace_move_to_inactive_locked(struct ldlm_namespace *ns, | |
2885bdea | 1048 | enum ldlm_side client) |
91a50030 OD |
1049 | { |
1050 | LASSERT(!list_empty(&ns->ns_list_chain)); | |
1051 | LASSERT(mutex_is_locked(ldlm_namespace_lock(client))); | |
58ba1c31 | 1052 | list_move_tail(&ns->ns_list_chain, &ldlm_cli_inactive_namespace_list); |
91a50030 OD |
1053 | } |
1054 | ||
d7e09d03 | 1055 | /** Should be called with ldlm_namespace_lock(client) taken. */ |
2885bdea | 1056 | struct ldlm_namespace *ldlm_namespace_first_locked(enum ldlm_side client) |
d7e09d03 PT |
1057 | { |
1058 | LASSERT(mutex_is_locked(ldlm_namespace_lock(client))); | |
1059 | LASSERT(!list_empty(ldlm_namespace_list(client))); | |
1060 | return container_of(ldlm_namespace_list(client)->next, | |
1061 | struct ldlm_namespace, ns_list_chain); | |
1062 | } | |
1063 | ||
1064 | /** Create and initialize new resource. */ | |
1065 | static struct ldlm_resource *ldlm_resource_new(void) | |
1066 | { | |
1067 | struct ldlm_resource *res; | |
1068 | int idx; | |
1069 | ||
3eed2d00 | 1070 | res = kmem_cache_zalloc(ldlm_resource_slab, GFP_NOFS); |
44b53f18 | 1071 | if (!res) |
d7e09d03 PT |
1072 | return NULL; |
1073 | ||
1074 | INIT_LIST_HEAD(&res->lr_granted); | |
d7e09d03 PT |
1075 | INIT_LIST_HEAD(&res->lr_waiting); |
1076 | ||
1077 | /* Initialize interval trees for each lock mode. */ | |
1078 | for (idx = 0; idx < LCK_MODE_NUM; idx++) { | |
1079 | res->lr_itree[idx].lit_size = 0; | |
1080 | res->lr_itree[idx].lit_mode = 1 << idx; | |
1081 | res->lr_itree[idx].lit_root = NULL; | |
1082 | } | |
1083 | ||
1084 | atomic_set(&res->lr_refcount, 1); | |
1085 | spin_lock_init(&res->lr_lock); | |
1086 | lu_ref_init(&res->lr_reference); | |
1087 | ||
1088 | /* The creator of the resource must unlock the mutex after LVB | |
6f789a6a OD |
1089 | * initialization. |
1090 | */ | |
d7e09d03 PT |
1091 | mutex_init(&res->lr_lvb_mutex); |
1092 | mutex_lock(&res->lr_lvb_mutex); | |
1093 | ||
1094 | return res; | |
1095 | } | |
1096 | ||
1097 | /** | |
1098 | * Return a reference to resource with given name, creating it if necessary. | |
1099 | * Args: namespace with ns_lock unlocked | |
1100 | * Locks: takes and releases NS hash-lock and res->lr_lock | |
1101 | * Returns: referenced, unlocked ldlm_resource or NULL | |
1102 | */ | |
1103 | struct ldlm_resource * | |
1104 | ldlm_resource_get(struct ldlm_namespace *ns, struct ldlm_resource *parent, | |
52ee0d20 OD |
1105 | const struct ldlm_res_id *name, enum ldlm_type type, |
1106 | int create) | |
d7e09d03 PT |
1107 | { |
1108 | struct hlist_node *hnode; | |
099d5adf | 1109 | struct ldlm_resource *res = NULL; |
6ea510c1 | 1110 | struct cfs_hash_bd bd; |
d7e09d03 | 1111 | __u64 version; |
91a50030 | 1112 | int ns_refcount = 0; |
cde5f109 | 1113 | int rc; |
d7e09d03 | 1114 | |
44b53f18 OD |
1115 | LASSERT(!parent); |
1116 | LASSERT(ns->ns_rs_hash); | |
d7e09d03 PT |
1117 | LASSERT(name->name[0] != 0); |
1118 | ||
1119 | cfs_hash_bd_get_and_lock(ns->ns_rs_hash, (void *)name, &bd, 0); | |
1120 | hnode = cfs_hash_bd_lookup_locked(ns->ns_rs_hash, &bd, (void *)name); | |
44b53f18 | 1121 | if (hnode) { |
d7e09d03 | 1122 | cfs_hash_bd_unlock(ns->ns_rs_hash, &bd, 0); |
099d5adf | 1123 | goto lvbo_init; |
d7e09d03 PT |
1124 | } |
1125 | ||
1126 | version = cfs_hash_bd_version_get(&bd); | |
1127 | cfs_hash_bd_unlock(ns->ns_rs_hash, &bd, 0); | |
1128 | ||
1129 | if (create == 0) | |
099d5adf | 1130 | return ERR_PTR(-ENOENT); |
d7e09d03 PT |
1131 | |
1132 | LASSERTF(type >= LDLM_MIN_TYPE && type < LDLM_MAX_TYPE, | |
1133 | "type: %d\n", type); | |
1134 | res = ldlm_resource_new(); | |
1135 | if (!res) | |
099d5adf | 1136 | return ERR_PTR(-ENOMEM); |
d7e09d03 PT |
1137 | |
1138 | res->lr_ns_bucket = cfs_hash_bd_extra_get(ns->ns_rs_hash, &bd); | |
1139 | res->lr_name = *name; | |
1140 | res->lr_type = type; | |
d7e09d03 PT |
1141 | |
1142 | cfs_hash_bd_lock(ns->ns_rs_hash, &bd, 1); | |
1143 | hnode = (version == cfs_hash_bd_version_get(&bd)) ? NULL : | |
1144 | cfs_hash_bd_lookup_locked(ns->ns_rs_hash, &bd, (void *)name); | |
1145 | ||
44b53f18 | 1146 | if (hnode) { |
d7e09d03 PT |
1147 | /* Someone won the race and already added the resource. */ |
1148 | cfs_hash_bd_unlock(ns->ns_rs_hash, &bd, 1); | |
1149 | /* Clean lu_ref for failed resource. */ | |
1150 | lu_ref_fini(&res->lr_reference); | |
1151 | /* We have taken lr_lvb_mutex. Drop it. */ | |
1152 | mutex_unlock(&res->lr_lvb_mutex); | |
5c4d8ed8 | 1153 | kmem_cache_free(ldlm_resource_slab, res); |
099d5adf | 1154 | lvbo_init: |
d7e09d03 PT |
1155 | res = hlist_entry(hnode, struct ldlm_resource, lr_hash); |
1156 | /* Synchronize with regard to resource creation. */ | |
1157 | if (ns->ns_lvbo && ns->ns_lvbo->lvbo_init) { | |
1158 | mutex_lock(&res->lr_lvb_mutex); | |
1159 | mutex_unlock(&res->lr_lvb_mutex); | |
1160 | } | |
1161 | ||
1162 | if (unlikely(res->lr_lvb_len < 0)) { | |
cde5f109 | 1163 | rc = res->lr_lvb_len; |
d7e09d03 | 1164 | ldlm_resource_putref(res); |
cde5f109 | 1165 | res = ERR_PTR(rc); |
d7e09d03 PT |
1166 | } |
1167 | return res; | |
1168 | } | |
1169 | /* We won! Let's add the resource. */ | |
1170 | cfs_hash_bd_add_locked(ns->ns_rs_hash, &bd, &res->lr_hash); | |
1171 | if (cfs_hash_bd_count_get(&bd) == 1) | |
91a50030 | 1172 | ns_refcount = ldlm_namespace_get_return(ns); |
d7e09d03 PT |
1173 | |
1174 | cfs_hash_bd_unlock(ns->ns_rs_hash, &bd, 1); | |
1175 | if (ns->ns_lvbo && ns->ns_lvbo->lvbo_init) { | |
d7e09d03 PT |
1176 | OBD_FAIL_TIMEOUT(OBD_FAIL_LDLM_CREATE_RESOURCE, 2); |
1177 | rc = ns->ns_lvbo->lvbo_init(res); | |
1178 | if (rc < 0) { | |
55f5a824 GKH |
1179 | CERROR("%s: lvbo_init failed for resource %#llx:%#llx: rc = %d\n", |
1180 | ns->ns_obd->obd_name, name->name[0], | |
1181 | name->name[1], rc); | |
d7e09d03 PT |
1182 | res->lr_lvb_len = rc; |
1183 | mutex_unlock(&res->lr_lvb_mutex); | |
1184 | ldlm_resource_putref(res); | |
099d5adf | 1185 | return ERR_PTR(rc); |
d7e09d03 PT |
1186 | } |
1187 | } | |
1188 | ||
1189 | /* We create resource with locked lr_lvb_mutex. */ | |
1190 | mutex_unlock(&res->lr_lvb_mutex); | |
1191 | ||
91a50030 OD |
1192 | /* Let's see if we happened to be the very first resource in this |
1193 | * namespace. If so, and this is a client namespace, we need to move | |
1194 | * the namespace into the active namespaces list to be patrolled by | |
6f789a6a OD |
1195 | * the ldlm_poold. |
1196 | */ | |
cf739f84 | 1197 | if (ns_refcount == 1) { |
91a50030 OD |
1198 | mutex_lock(ldlm_namespace_lock(LDLM_NAMESPACE_CLIENT)); |
1199 | ldlm_namespace_move_to_active_locked(ns, LDLM_NAMESPACE_CLIENT); | |
1200 | mutex_unlock(ldlm_namespace_lock(LDLM_NAMESPACE_CLIENT)); | |
1201 | } | |
1202 | ||
d7e09d03 PT |
1203 | return res; |
1204 | } | |
1205 | EXPORT_SYMBOL(ldlm_resource_get); | |
1206 | ||
6ea510c1 | 1207 | static void __ldlm_resource_putref_final(struct cfs_hash_bd *bd, |
d7e09d03 PT |
1208 | struct ldlm_resource *res) |
1209 | { | |
1210 | struct ldlm_ns_bucket *nsb = res->lr_ns_bucket; | |
1211 | ||
1212 | if (!list_empty(&res->lr_granted)) { | |
1213 | ldlm_resource_dump(D_ERROR, res); | |
1214 | LBUG(); | |
1215 | } | |
1216 | ||
d7e09d03 PT |
1217 | if (!list_empty(&res->lr_waiting)) { |
1218 | ldlm_resource_dump(D_ERROR, res); | |
1219 | LBUG(); | |
1220 | } | |
1221 | ||
1222 | cfs_hash_bd_del_locked(nsb->nsb_namespace->ns_rs_hash, | |
1223 | bd, &res->lr_hash); | |
1224 | lu_ref_fini(&res->lr_reference); | |
1225 | if (cfs_hash_bd_count_get(bd) == 0) | |
1226 | ldlm_namespace_put(nsb->nsb_namespace); | |
1227 | } | |
1228 | ||
1229 | /* Returns 1 if the resource was freed, 0 if it remains. */ | |
1230 | int ldlm_resource_putref(struct ldlm_resource *res) | |
1231 | { | |
1232 | struct ldlm_namespace *ns = ldlm_res_to_ns(res); | |
6ea510c1 | 1233 | struct cfs_hash_bd bd; |
d7e09d03 PT |
1234 | |
1235 | LASSERT_ATOMIC_GT_LT(&res->lr_refcount, 0, LI_POISON); | |
1236 | CDEBUG(D_INFO, "putref res: %p count: %d\n", | |
1237 | res, atomic_read(&res->lr_refcount) - 1); | |
1238 | ||
1239 | cfs_hash_bd_get(ns->ns_rs_hash, &res->lr_name, &bd); | |
1240 | if (cfs_hash_bd_dec_and_lock(ns->ns_rs_hash, &bd, &res->lr_refcount)) { | |
1241 | __ldlm_resource_putref_final(&bd, res); | |
1242 | cfs_hash_bd_unlock(ns->ns_rs_hash, &bd, 1); | |
1243 | if (ns->ns_lvbo && ns->ns_lvbo->lvbo_free) | |
1244 | ns->ns_lvbo->lvbo_free(res); | |
5c4d8ed8 | 1245 | kmem_cache_free(ldlm_resource_slab, res); |
d7e09d03 PT |
1246 | return 1; |
1247 | } | |
1248 | return 0; | |
1249 | } | |
1250 | EXPORT_SYMBOL(ldlm_resource_putref); | |
1251 | ||
1252 | /* Returns 1 if the resource was freed, 0 if it remains. */ | |
1253 | int ldlm_resource_putref_locked(struct ldlm_resource *res) | |
1254 | { | |
1255 | struct ldlm_namespace *ns = ldlm_res_to_ns(res); | |
1256 | ||
1257 | LASSERT_ATOMIC_GT_LT(&res->lr_refcount, 0, LI_POISON); | |
1258 | CDEBUG(D_INFO, "putref res: %p count: %d\n", | |
1259 | res, atomic_read(&res->lr_refcount) - 1); | |
1260 | ||
1261 | if (atomic_dec_and_test(&res->lr_refcount)) { | |
6ea510c1 | 1262 | struct cfs_hash_bd bd; |
d7e09d03 PT |
1263 | |
1264 | cfs_hash_bd_get(ldlm_res_to_ns(res)->ns_rs_hash, | |
1265 | &res->lr_name, &bd); | |
1266 | __ldlm_resource_putref_final(&bd, res); | |
1267 | cfs_hash_bd_unlock(ns->ns_rs_hash, &bd, 1); | |
1268 | /* NB: ns_rs_hash is created with CFS_HASH_NO_ITEMREF, | |
1269 | * so we should never be here while calling cfs_hash_del, | |
1270 | * cfs_hash_for_each_nolock is the only case we can get | |
1271 | * here, which is safe to release cfs_hash_bd_lock. | |
1272 | */ | |
1273 | if (ns->ns_lvbo && ns->ns_lvbo->lvbo_free) | |
1274 | ns->ns_lvbo->lvbo_free(res); | |
5c4d8ed8 | 1275 | kmem_cache_free(ldlm_resource_slab, res); |
d7e09d03 PT |
1276 | |
1277 | cfs_hash_bd_lock(ns->ns_rs_hash, &bd, 1); | |
1278 | return 1; | |
1279 | } | |
1280 | return 0; | |
1281 | } | |
1282 | ||
1283 | /** | |
1284 | * Add a lock into a given resource into specified lock list. | |
1285 | */ | |
1286 | void ldlm_resource_add_lock(struct ldlm_resource *res, struct list_head *head, | |
1287 | struct ldlm_lock *lock) | |
1288 | { | |
1289 | check_res_locked(res); | |
1290 | ||
e93876dd | 1291 | LDLM_DEBUG(lock, "About to add this lock:"); |
d7e09d03 | 1292 | |
5a9a80ba | 1293 | if (ldlm_is_destroyed(lock)) { |
d7e09d03 PT |
1294 | CDEBUG(D_OTHER, "Lock destroyed, not adding to resource\n"); |
1295 | return; | |
1296 | } | |
1297 | ||
1298 | LASSERT(list_empty(&lock->l_res_link)); | |
1299 | ||
1300 | list_add_tail(&lock->l_res_link, head); | |
1301 | } | |
1302 | ||
d7e09d03 PT |
1303 | void ldlm_resource_unlink_lock(struct ldlm_lock *lock) |
1304 | { | |
1305 | int type = lock->l_resource->lr_type; | |
1306 | ||
1307 | check_res_locked(lock->l_resource); | |
1308 | if (type == LDLM_IBITS || type == LDLM_PLAIN) | |
1309 | ldlm_unlink_lock_skiplist(lock); | |
1310 | else if (type == LDLM_EXTENT) | |
1311 | ldlm_extent_unlink_lock(lock); | |
1312 | list_del_init(&lock->l_res_link); | |
1313 | } | |
1314 | EXPORT_SYMBOL(ldlm_resource_unlink_lock); | |
1315 | ||
1316 | void ldlm_res2desc(struct ldlm_resource *res, struct ldlm_resource_desc *desc) | |
1317 | { | |
1318 | desc->lr_type = res->lr_type; | |
1319 | desc->lr_name = res->lr_name; | |
1320 | } | |
1321 | ||
1322 | /** | |
1323 | * Print information about all locks in all namespaces on this node to debug | |
1324 | * log. | |
1325 | */ | |
2885bdea | 1326 | void ldlm_dump_all_namespaces(enum ldlm_side client, int level) |
d7e09d03 PT |
1327 | { |
1328 | struct list_head *tmp; | |
1329 | ||
1330 | if (!((libcfs_debug | D_ERROR) & level)) | |
1331 | return; | |
1332 | ||
1333 | mutex_lock(ldlm_namespace_lock(client)); | |
1334 | ||
1335 | list_for_each(tmp, ldlm_namespace_list(client)) { | |
1336 | struct ldlm_namespace *ns; | |
902f3bb1 | 1337 | |
d7e09d03 PT |
1338 | ns = list_entry(tmp, struct ldlm_namespace, ns_list_chain); |
1339 | ldlm_namespace_dump(level, ns); | |
1340 | } | |
1341 | ||
1342 | mutex_unlock(ldlm_namespace_lock(client)); | |
1343 | } | |
d7e09d03 | 1344 | |
6da6eabe | 1345 | static int ldlm_res_hash_dump(struct cfs_hash *hs, struct cfs_hash_bd *bd, |
d7e09d03 PT |
1346 | struct hlist_node *hnode, void *arg) |
1347 | { | |
1348 | struct ldlm_resource *res = cfs_hash_object(hs, hnode); | |
1349 | int level = (int)(unsigned long)arg; | |
1350 | ||
1351 | lock_res(res); | |
1352 | ldlm_resource_dump(level, res); | |
1353 | unlock_res(res); | |
1354 | ||
1355 | return 0; | |
1356 | } | |
1357 | ||
1358 | /** | |
1359 | * Print information about all locks in this namespace on this node to debug | |
1360 | * log. | |
1361 | */ | |
1362 | void ldlm_namespace_dump(int level, struct ldlm_namespace *ns) | |
1363 | { | |
1364 | if (!((libcfs_debug | D_ERROR) & level)) | |
1365 | return; | |
1366 | ||
cf739f84 OD |
1367 | CDEBUG(level, "--- Namespace: %s (rc: %d, side: client)\n", |
1368 | ldlm_ns_name(ns), atomic_read(&ns->ns_bref)); | |
d7e09d03 | 1369 | |
699503bc | 1370 | if (time_before(cfs_time_current(), ns->ns_next_dump)) |
d7e09d03 PT |
1371 | return; |
1372 | ||
1373 | cfs_hash_for_each_nolock(ns->ns_rs_hash, | |
1374 | ldlm_res_hash_dump, | |
c2242d14 | 1375 | (void *)(unsigned long)level, 0); |
d7e09d03 PT |
1376 | spin_lock(&ns->ns_lock); |
1377 | ns->ns_next_dump = cfs_time_shift(10); | |
1378 | spin_unlock(&ns->ns_lock); | |
1379 | } | |
d7e09d03 PT |
1380 | |
1381 | /** | |
1382 | * Print information about all locks in this resource to debug log. | |
1383 | */ | |
1384 | void ldlm_resource_dump(int level, struct ldlm_resource *res) | |
1385 | { | |
1386 | struct ldlm_lock *lock; | |
1387 | unsigned int granted = 0; | |
1388 | ||
f440d909 | 1389 | BUILD_BUG_ON(RES_NAME_SIZE != 4); |
d7e09d03 PT |
1390 | |
1391 | if (!((libcfs_debug | D_ERROR) & level)) | |
1392 | return; | |
1393 | ||
1ada25dc | 1394 | CDEBUG(level, "--- Resource: " DLDLMRES " (%p) refcount = %d\n", |
6d95e048 | 1395 | PLDLMRES(res), res, atomic_read(&res->lr_refcount)); |
d7e09d03 PT |
1396 | |
1397 | if (!list_empty(&res->lr_granted)) { | |
1398 | CDEBUG(level, "Granted locks (in reverse order):\n"); | |
1399 | list_for_each_entry_reverse(lock, &res->lr_granted, | |
24c198e9 | 1400 | l_res_link) { |
d7e09d03 PT |
1401 | LDLM_DEBUG_LIMIT(level, lock, "###"); |
1402 | if (!(level & D_CANTMASK) && | |
1403 | ++granted > ldlm_dump_granted_max) { | |
2d00bd17 JP |
1404 | CDEBUG(level, "only dump %d granted locks to avoid DDOS.\n", |
1405 | granted); | |
d7e09d03 PT |
1406 | break; |
1407 | } | |
1408 | } | |
1409 | } | |
d7e09d03 PT |
1410 | if (!list_empty(&res->lr_waiting)) { |
1411 | CDEBUG(level, "Waiting locks:\n"); | |
1412 | list_for_each_entry(lock, &res->lr_waiting, l_res_link) | |
1413 | LDLM_DEBUG_LIMIT(level, lock, "###"); | |
1414 | } | |
1415 | } | |
06563b56 | 1416 | EXPORT_SYMBOL(ldlm_resource_dump); |