Whamcloud - gitweb
- ll_file_open was not passing the correct file->f_flags to mdc_open. Fixed.
[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 int ldlm_resource_put(struct ldlm_resource *res)
197 {
198         int rc = 0; 
199         ldlm_lock(res->lr_namespace->ns_obddev);
200
201         if (atomic_dec_and_test(&res->lr_refcount)) {
202                 if (!list_empty(&res->lr_granted))
203                         BUG();
204
205                 if (!list_empty(&res->lr_converting))
206                         BUG();
207
208                 if (!list_empty(&res->lr_waiting))
209                         BUG();
210
211                 list_del(&res->lr_hash);
212                 list_del(&res->lr_rootlink);
213                 list_del(&res->lr_childof);
214
215                 kmem_cache_free(ldlm_resource_slab, res);
216                 rc = 1;
217         }
218         ldlm_unlock(res->lr_namespace->ns_obddev);
219         return rc; 
220 }
221
222 int ldlm_get_resource_handle(struct ldlm_resource *res, struct ldlm_handle *h)
223 {
224         BUG();
225         return 0;
226 }
227
228 void ldlm_resource_dump(struct ldlm_resource *res)
229 {
230         struct list_head *tmp;
231         char name[256];
232
233         if (RES_NAME_SIZE != 6)
234                 BUG();
235
236         snprintf(name, sizeof(name), "%x %x %x %x %x %x",
237                  res->lr_name[0], res->lr_name[1], res->lr_name[2],
238                  res->lr_name[3], res->lr_name[4], res->lr_name[5]);
239
240         CDEBUG(D_OTHER, "--- Resource: %p (%s)\n", res, name);
241         CDEBUG(D_OTHER, "Namespace: %p (%u)\n", res->lr_namespace,
242                res->lr_namespace->ns_id);
243         CDEBUG(D_OTHER, "Parent: %p, root: %p\n", res->lr_parent, res->lr_root);
244
245         CDEBUG(D_OTHER, "Granted locks:\n");
246         list_for_each(tmp, &res->lr_granted) {
247                 struct ldlm_lock *lock;
248                 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
249                 ldlm_lock_dump(lock);
250         }
251
252         CDEBUG(D_OTHER, "Converting locks:\n");
253         list_for_each(tmp, &res->lr_converting) {
254                 struct ldlm_lock *lock;
255                 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
256                 ldlm_lock_dump(lock);
257         }
258
259         CDEBUG(D_OTHER, "Waiting locks:\n");
260         list_for_each(tmp, &res->lr_waiting) {
261                 struct ldlm_lock *lock;
262                 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
263                 ldlm_lock_dump(lock);
264         }
265 }
266
267 static int ldlm_obd_setup(struct obd_device *obddev, obd_count len, void *data)
268 {
269         INIT_LIST_HEAD(&obddev->u.ldlm.ldlm_namespaces);
270         obddev->u.ldlm.ldlm_lock = SPIN_LOCK_UNLOCKED;
271
272         return 0;
273 }
274
275 static int ldlm_iocontrol(int cmd, struct obd_conn *conn, int len, void *karg,
276                           void *uarg)
277 {
278         struct obd_device *obddev = conn->oc_dev;
279         int err;
280
281         ENTRY;
282
283         if ( _IOC_TYPE(cmd) != IOC_LDLM_TYPE ||
284              _IOC_NR(cmd) < IOC_LDLM_MIN_NR  ||
285              _IOC_NR(cmd) > IOC_LDLM_MAX_NR ) {
286                 CDEBUG(D_IOCTL, "invalid ioctl ( type %d, nr %d, size %d )\n",
287                                 _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd));
288                 EXIT;
289                 return -EINVAL;
290         }
291
292         switch (cmd) {
293         case IOC_LDLM_TEST: {
294                 err = ldlm_test(obddev);
295                 CERROR("-- done err %d\n", err);
296                 EXIT;
297                 break;
298         }
299         default:
300                 err = -EINVAL;
301                 EXIT;
302                 break;
303         }
304
305         return err;
306 }
307
308 struct obd_ops ldlm_obd_ops = {
309         o_iocontrol:   ldlm_iocontrol,
310         o_setup:       ldlm_obd_setup,
311         o_connect:     gen_connect,
312         o_disconnect:  gen_disconnect
313 };
314
315 static int __init ldlm_init(void)
316 {
317         int rc = obd_register_type(&ldlm_obd_ops, OBD_LDLM_DEVICENAME);
318         if (rc != 0)
319                 return rc;
320
321         ldlm_resource_slab = kmem_cache_create("ldlm_resources",
322                                                sizeof(struct ldlm_resource), 0,
323                                                SLAB_HWCACHE_ALIGN, NULL, NULL);
324         if (ldlm_resource_slab == NULL)
325                 return -ENOMEM;
326
327         ldlm_lock_slab = kmem_cache_create("ldlm_locks",
328                                            sizeof(struct ldlm_lock), 0,
329                                            SLAB_HWCACHE_ALIGN, NULL, NULL);
330         if (ldlm_lock_slab == NULL) {
331                 kmem_cache_destroy(ldlm_resource_slab);
332                 return -ENOMEM;
333         }
334
335         return 0;
336 }
337
338 static void __exit ldlm_exit(void)
339 {
340         obd_unregister_type(OBD_LDLM_DEVICENAME);
341         kmem_cache_destroy(ldlm_resource_slab);
342         kmem_cache_destroy(ldlm_lock_slab);
343 }
344
345 MODULE_AUTHOR("Cluster File Systems, Inc. <braam@clusterfs.com>");
346 MODULE_DESCRIPTION("Lustre Lock Management Module v0.1");
347 MODULE_LICENSE("GPL"); 
348
349 module_init(ldlm_init);
350 module_exit(ldlm_exit);