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