Whamcloud - gitweb
94af2511a8702326965f23509c597576c1764b23
[fs/lustre-release.git] / lustre / ldlm / resource.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2002 Cluster File Systems, Inc.
5  *
6  * This code is issued under the GNU General Public License.
7  * See the file COPYING in this distribution
8  *
9  * by Cluster File Systems, Inc.
10  */
11
12 #define EXPORT_SYMTAB
13
14 #include <linux/version.h>
15 #include <linux/module.h>
16 #include <linux/slab.h>
17 #include <asm/unistd.h>
18
19 #define DEBUG_SUBSYSTEM S_LDLM
20
21 #include <linux/obd_support.h>
22 #include <linux/obd_class.h>
23
24 #include <linux/lustre_dlm.h>
25
26 static kmem_cache_t *ldlm_resource_slab;
27 kmem_cache_t *ldlm_lock_slab;
28
29 struct ldlm_namespace *ldlm_namespace_find(struct obd_device *obddev, __u32 id)
30 {
31         struct list_head *tmp;
32         struct ldlm_namespace *res;
33
34         ldlm_lock(obddev);
35
36         res = NULL;
37         list_for_each(tmp, &obddev->u.ldlm.ldlm_namespaces) { 
38                 struct ldlm_namespace *chk;
39                 chk = list_entry(tmp, struct ldlm_namespace, ns_link);
40                 
41                 if ( chk->ns_id == id ) {
42                         res = chk;
43                         break;
44                 }
45         }
46
47         ldlm_unlock(obddev);
48
49         return res;
50 }
51
52 /* this must be called with ldlm_lock(obddev) held */
53 static void res_hash_init(struct ldlm_namespace *ns)
54 {
55         struct list_head *res_hash;
56         struct list_head *bucket;
57
58         if (ns->ns_hash != NULL)
59                 return;
60
61         OBD_ALLOC(res_hash, sizeof(struct list_head) * RES_HASH_SIZE);
62         if (!res_hash)
63                 BUG();
64
65         for (bucket = res_hash + RES_HASH_SIZE-1 ; bucket >= res_hash ;
66              bucket--) {
67                 INIT_LIST_HEAD(bucket);
68         }
69
70         ns->ns_hash = res_hash;
71 }
72
73 struct ldlm_namespace *ldlm_namespace_new(struct obd_device *obddev, __u32 id)
74 {
75         struct ldlm_namespace *ns;
76
77         ldlm_lock(obddev);
78
79         if (ldlm_namespace_find(obddev, id))
80                 BUG();
81
82         OBD_ALLOC(ns, sizeof(*ns));
83         if (!ns)
84                 BUG();
85
86         ns->ns_id = id;
87         INIT_LIST_HEAD(&ns->ns_root_list);
88
89         list_add(&ns->ns_link, &obddev->u.ldlm.ldlm_namespaces);
90
91         res_hash_init(ns); 
92
93         ldlm_unlock(obddev);
94
95         return ns;
96 }
97
98 static __u32 ldlm_hash_fn(struct ldlm_resource *parent, __u32 *name)
99 {
100         __u32 hash = 0;
101         int i;
102
103         for (i = 0; i < RES_NAME_SIZE; i++) {
104                 hash += name[i];
105         }
106
107         hash += (__u32)((unsigned long)parent >> 4);
108
109         return (hash & RES_HASH_MASK);
110 }
111
112 static struct ldlm_resource *ldlm_resource_new(void)
113 {
114         struct ldlm_resource *res;
115
116         res = kmem_cache_alloc(ldlm_resource_slab, SLAB_KERNEL);
117         if (res == NULL)
118                 BUG();
119         memset(res, 0, sizeof(*res));
120
121         INIT_LIST_HEAD(&res->lr_children);
122         INIT_LIST_HEAD(&res->lr_granted);
123         INIT_LIST_HEAD(&res->lr_converting);
124         INIT_LIST_HEAD(&res->lr_waiting);
125
126         res->lr_lock = SPIN_LOCK_UNLOCKED;
127
128         atomic_set(&res->lr_refcount, 1);
129
130         return res;
131 }
132
133 /* ldlm_lock(obddev) must be taken before calling resource_add */
134 static struct ldlm_resource *ldlm_resource_add(struct ldlm_namespace *ns,
135                                                struct ldlm_resource *parent,
136                                                __u32 *name)
137 {
138         struct list_head *bucket;
139         struct ldlm_resource *res;
140
141         bucket = ns->ns_hash + ldlm_hash_fn(parent, name);
142
143         res = ldlm_resource_new();
144         if (!res)
145                 BUG();
146
147         memcpy(res->lr_name, name, RES_NAME_SIZE * sizeof(__u32));
148         res->lr_namespace = ns;
149         list_add(&res->lr_hash, bucket);
150         if (parent == NULL) {
151                 res->lr_parent = res;
152                 list_add(&res->lr_rootlink, &ns->ns_root_list);
153         } else {
154                 res->lr_parent = parent;
155                 list_add(&res->lr_childof, &parent->lr_children);
156         }
157
158         return res;
159 }
160
161 struct ldlm_resource *ldlm_resource_get(struct ldlm_namespace *ns,
162                                         struct ldlm_resource *parent,
163                                         __u32 *name, int create)
164 {
165         struct list_head *bucket;
166         struct list_head *tmp = bucket;
167         struct ldlm_resource *res;
168
169         if (ns->ns_hash == NULL)
170                 BUG();
171         bucket = ns->ns_hash + ldlm_hash_fn(parent, name);
172
173         ldlm_lock(ns->ns_obddev);
174
175         res = NULL;
176         list_for_each(tmp, bucket) {
177                 struct ldlm_resource *chk;
178                 chk = list_entry(tmp, struct ldlm_resource, lr_hash);
179
180                 if (memcmp(chk->lr_name, name,
181                            RES_NAME_SIZE * sizeof(__u32)) == 0) {
182                         res = chk;
183                         atomic_inc(&res->lr_refcount);
184                         break;
185                 }
186         }
187
188         if (res == NULL && create)
189                 res = ldlm_resource_add(ns, parent, name);
190
191         ldlm_unlock(ns->ns_obddev);
192
193         return res;
194 }
195
196 void ldlm_resource_put(struct ldlm_resource *res)
197 {
198         ldlm_lock(res->lr_namespace->ns_obddev);
199
200         if (atomic_dec_and_test(&res->lr_refcount)) {
201                 if (!list_empty(&res->lr_granted))
202                         BUG();
203
204                 if (!list_empty(&res->lr_converting))
205                         BUG();
206
207                 if (!list_empty(&res->lr_waiting))
208                         BUG();
209
210                 list_del(&res->lr_hash);
211                 list_del(&res->lr_rootlink);
212                 list_del(&res->lr_childof);
213
214                 kmem_cache_free(ldlm_resource_slab, res);
215         }
216
217         ldlm_unlock(res->lr_namespace->ns_obddev);
218 }
219
220 int ldlm_get_resource_handle(struct ldlm_resource *res, struct ldlm_handle *h)
221 {
222         BUG();
223         return 0;
224 }
225
226 void ldlm_resource_dump(struct ldlm_resource *res)
227 {
228         struct list_head *tmp;
229         char name[256];
230
231         if (RES_NAME_SIZE != 6)
232                 BUG();
233
234         snprintf(name, sizeof(name), "%x %x %x %x %x %x",
235                  res->lr_name[0], res->lr_name[1], res->lr_name[2],
236                  res->lr_name[3], res->lr_name[4], res->lr_name[5]);
237
238         CDEBUG(D_OTHER, "--- Resource: %p (%s)\n", res, name);
239         CDEBUG(D_OTHER, "Namespace: %p (%u)\n", res->lr_namespace,
240                res->lr_namespace->ns_id);
241         CDEBUG(D_OTHER, "Parent: %p, root: %p\n", res->lr_parent, res->lr_root);
242
243         CDEBUG(D_OTHER, "Granted locks:\n");
244         list_for_each(tmp, &res->lr_granted) {
245                 struct ldlm_lock *lock;
246                 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
247                 ldlm_lock_dump(lock);
248         }
249
250         CDEBUG(D_OTHER, "Converting locks:\n");
251         list_for_each(tmp, &res->lr_converting) {
252                 struct ldlm_lock *lock;
253                 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
254                 ldlm_lock_dump(lock);
255         }
256
257         CDEBUG(D_OTHER, "Waiting locks:\n");
258         list_for_each(tmp, &res->lr_waiting) {
259                 struct ldlm_lock *lock;
260                 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
261                 ldlm_lock_dump(lock);
262         }
263 }
264
265 static int ldlm_obd_setup(struct obd_device *obddev, obd_count len, void *data)
266 {
267         INIT_LIST_HEAD(&obddev->u.ldlm.ldlm_namespaces);
268         obddev->u.ldlm.ldlm_lock = SPIN_LOCK_UNLOCKED;
269
270         return 0;
271 }
272
273 static int ldlm_iocontrol(int cmd, struct obd_conn *conn, int len, void *karg,
274                           void *uarg)
275 {
276         struct obd_device *obddev = conn->oc_dev;
277         int err;
278
279         ENTRY;
280
281         if ( _IOC_TYPE(cmd) != IOC_LDLM_TYPE ||
282              _IOC_NR(cmd) < IOC_LDLM_MIN_NR  ||
283              _IOC_NR(cmd) > IOC_LDLM_MAX_NR ) {
284                 CDEBUG(D_IOCTL, "invalid ioctl ( type %d, nr %d, size %d )\n",
285                                 _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd));
286                 EXIT;
287                 return -EINVAL;
288         }
289
290         switch (cmd) {
291         case IOC_LDLM_TEST: {
292                 err = ldlm_test(obddev);
293                 CERROR("-- done err %d\n", err);
294                 EXIT;
295                 break;
296         }
297         default:
298                 err = -EINVAL;
299                 EXIT;
300                 break;
301         }
302
303         return err;
304 }
305
306 struct obd_ops ldlm_obd_ops = {
307         o_iocontrol:   ldlm_iocontrol,
308         o_setup:       ldlm_obd_setup,
309         o_connect:     gen_connect,
310         o_disconnect:  gen_disconnect
311 };
312
313 static int __init ldlm_init(void)
314 {
315         int rc = obd_register_type(&ldlm_obd_ops, OBD_LDLM_DEVICENAME);
316         if (rc != 0)
317                 return rc;
318
319         ldlm_resource_slab = kmem_cache_create("ldlm_resources",
320                                                sizeof(struct ldlm_resource), 0,
321                                                SLAB_HWCACHE_ALIGN, NULL, NULL);
322         if (ldlm_resource_slab == NULL)
323                 return -ENOMEM;
324
325         ldlm_lock_slab = kmem_cache_create("ldlm_locks",
326                                            sizeof(struct ldlm_lock), 0,
327                                            SLAB_HWCACHE_ALIGN, NULL, NULL);
328         if (ldlm_lock_slab == NULL) {
329                 kmem_cache_destroy(ldlm_resource_slab);
330                 return -ENOMEM;
331         }
332
333         return 0;
334 }
335
336 static void __exit ldlm_exit(void)
337 {
338         obd_unregister_type(OBD_LDLM_DEVICENAME);
339         kmem_cache_destroy(ldlm_resource_slab);
340         kmem_cache_destroy(ldlm_lock_slab);
341 }
342
343 MODULE_AUTHOR("Cluster File Systems, Inc. <braam@clusterfs.com>");
344 MODULE_DESCRIPTION("Lustre Lock Management Module v0.1");
345 MODULE_LICENSE("GPL"); 
346
347 module_init(ldlm_init);
348 module_exit(ldlm_exit);