Whamcloud - gitweb
e00baa9b06fc20a2266c3c823985b230e8e50e41
[fs/lustre-release.git] / lustre / ldlm / 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 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                 LBUG();
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                 LBUG();
81
82         OBD_ALLOC(ns, sizeof(*ns));
83         if (!ns)
84                 LBUG();
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, __u64 *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                 LBUG();
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                                                __u64 *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                 LBUG();
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                                         __u64 *name, int create)
164 {
165         struct list_head *bucket;
166         struct list_head *tmp = bucket;
167         struct ldlm_resource *res;
168
169         ENTRY;
170
171         if (ns->ns_hash == NULL)
172                 RETURN(NULL);
173         bucket = ns->ns_hash + ldlm_hash_fn(parent, name);
174
175         ldlm_lock(ns->ns_obddev);
176
177         res = NULL;
178         list_for_each(tmp, bucket) {
179                 struct ldlm_resource *chk;
180                 chk = list_entry(tmp, struct ldlm_resource, lr_hash);
181
182                 if (memcmp(chk->lr_name, name,
183                            RES_NAME_SIZE * sizeof(__u32)) == 0) {
184                         res = chk;
185                         atomic_inc(&res->lr_refcount);
186                         break;
187                 }
188         }
189
190         if (res == NULL && create)
191                 res = ldlm_resource_add(ns, parent, name);
192
193         ldlm_unlock(ns->ns_obddev);
194
195         RETURN(res);
196 }
197
198 int ldlm_resource_put(struct ldlm_resource *res)
199 {
200         int rc = 0; 
201         ldlm_lock(res->lr_namespace->ns_obddev);
202
203         if (atomic_dec_and_test(&res->lr_refcount)) {
204                 if (!list_empty(&res->lr_granted))
205                         LBUG();
206
207                 if (!list_empty(&res->lr_converting))
208                         LBUG();
209
210                 if (!list_empty(&res->lr_waiting))
211                         LBUG();
212
213                 list_del(&res->lr_hash);
214                 list_del(&res->lr_rootlink);
215                 list_del(&res->lr_childof);
216
217                 kmem_cache_free(ldlm_resource_slab, res);
218                 rc = 1;
219         }
220         ldlm_unlock(res->lr_namespace->ns_obddev);
221         return rc; 
222 }
223
224 int ldlm_get_resource_handle(struct ldlm_resource *res, struct ldlm_handle *h)
225 {
226         LBUG();
227         return 0;
228 }
229
230 void ldlm_resource_dump(struct ldlm_resource *res)
231 {
232         struct list_head *tmp;
233         char name[256];
234
235         if (RES_NAME_SIZE != 3)
236                 LBUG();
237
238         snprintf(name, sizeof(name), "%Lx %Lx %Lx",
239                  res->lr_name[0], res->lr_name[1], res->lr_name[2]);
240
241         CDEBUG(D_OTHER, "--- Resource: %p (%s)\n", res, name);
242         CDEBUG(D_OTHER, "Namespace: %p (%u)\n", res->lr_namespace,
243                res->lr_namespace->ns_id);
244         CDEBUG(D_OTHER, "Parent: %p, root: %p\n", res->lr_parent, res->lr_root);
245
246         CDEBUG(D_OTHER, "Granted locks:\n");
247         list_for_each(tmp, &res->lr_granted) {
248                 struct ldlm_lock *lock;
249                 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
250                 ldlm_lock_dump(lock);
251         }
252
253         CDEBUG(D_OTHER, "Converting locks:\n");
254         list_for_each(tmp, &res->lr_converting) {
255                 struct ldlm_lock *lock;
256                 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
257                 ldlm_lock_dump(lock);
258         }
259
260         CDEBUG(D_OTHER, "Waiting locks:\n");
261         list_for_each(tmp, &res->lr_waiting) {
262                 struct ldlm_lock *lock;
263                 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
264                 ldlm_lock_dump(lock);
265         }
266 }
267