Whamcloud - gitweb
db336397272ab1312b0a8045020804a39ed2c1ef
[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         res = NULL;
35         list_for_each(tmp, &obddev->u.ldlm.ldlm_namespaces) { 
36                 struct ldlm_namespace *chk;
37                 chk = list_entry(tmp, struct ldlm_namespace, ns_link);
38                 
39                 if ( chk->ns_id == id ) {
40                         res = chk;
41                         break;
42                 }
43         }
44
45         return res;
46 }
47
48 /* this must be called with ldlm_lock(obddev) held */
49 static void res_hash_init(struct ldlm_namespace *ns)
50 {
51         struct list_head *res_hash;
52         struct list_head *bucket;
53
54         if (ns->ns_hash != NULL)
55                 return;
56
57         OBD_ALLOC(res_hash, sizeof(struct list_head) * RES_HASH_SIZE);
58         if (!res_hash)
59                 LBUG();
60
61         for (bucket = res_hash + RES_HASH_SIZE - 1; bucket >= res_hash;
62              bucket--)
63                 INIT_LIST_HEAD(bucket);
64
65         ns->ns_hash = res_hash;
66 }
67
68 struct ldlm_namespace *ldlm_namespace_new(struct obd_device *obddev, __u32 id)
69 {
70         struct ldlm_namespace *ns;
71
72         if (ldlm_namespace_find(obddev, id))
73                 LBUG();
74
75         OBD_ALLOC(ns, sizeof(*ns));
76         if (!ns)
77                 LBUG();
78
79         ns->ns_id = id;
80         INIT_LIST_HEAD(&ns->ns_root_list);
81
82         list_add(&ns->ns_link, &obddev->u.ldlm.ldlm_namespaces);
83
84         res_hash_init(ns); 
85         atomic_set(&ns->ns_refcount, 0);
86
87         return ns;
88 }
89
90 int ldlm_namespace_free(struct ldlm_namespace *ns)
91 {
92         if (atomic_read(&ns->ns_refcount))
93                 return -EBUSY;
94
95         list_del(&ns->ns_link);
96         OBD_FREE(ns->ns_hash, sizeof(struct list_head) * RES_HASH_SIZE);
97         OBD_FREE(ns, sizeof(*ns));
98
99         return 0;
100 }
101
102 static __u32 ldlm_hash_fn(struct ldlm_resource *parent, __u64 *name)
103 {
104         __u32 hash = 0;
105         int i;
106
107         for (i = 0; i < RES_NAME_SIZE; i++)
108                 hash += name[i];
109
110         hash += (__u32)((unsigned long)parent >> 4);
111
112         return (hash & RES_HASH_MASK);
113 }
114
115 static struct ldlm_resource *ldlm_resource_new(void)
116 {
117         struct ldlm_resource *res;
118
119         res = kmem_cache_alloc(ldlm_resource_slab, SLAB_KERNEL);
120         if (res == NULL)
121                 LBUG();
122         memset(res, 0, sizeof(*res));
123
124         INIT_LIST_HEAD(&res->lr_children);
125         INIT_LIST_HEAD(&res->lr_childof);
126         INIT_LIST_HEAD(&res->lr_granted);
127         INIT_LIST_HEAD(&res->lr_converting);
128         INIT_LIST_HEAD(&res->lr_waiting);
129
130         res->lr_lock = SPIN_LOCK_UNLOCKED;
131
132         atomic_set(&res->lr_refcount, 1);
133
134         return res;
135 }
136
137 /* ldlm_lock(obddev) must be taken before calling resource_add */
138 static struct ldlm_resource *ldlm_resource_add(struct ldlm_namespace *ns,
139                                                struct ldlm_resource *parent,
140                                                __u64 *name, __u32 type)
141 {
142         struct list_head *bucket;
143         struct ldlm_resource *res;
144
145         bucket = ns->ns_hash + ldlm_hash_fn(parent, name);
146
147         res = ldlm_resource_new();
148         if (!res)
149                 LBUG();
150
151         memcpy(res->lr_name, name, RES_NAME_SIZE * sizeof(__u32));
152         res->lr_namespace = ns;
153         if (type < 0 || type > LDLM_MAX_TYPE) 
154                 LBUG();
155
156         res->lr_type = type; 
157         res->lr_most_restr = LCK_NL;
158         list_add(&res->lr_hash, bucket);
159         atomic_inc(&ns->ns_refcount);
160         if (parent == NULL) {
161                 res->lr_parent = res;
162                 list_add(&res->lr_rootlink, &ns->ns_root_list);
163         } else {
164                 res->lr_parent = parent;
165                 list_add(&res->lr_childof, &parent->lr_children);
166         }
167
168         return res;
169 }
170
171 struct ldlm_resource *ldlm_resource_get(struct ldlm_namespace *ns,
172                                         struct ldlm_resource *parent,
173                                         __u64 *name, __u32 type, int create)
174 {
175         struct list_head *bucket;
176         struct list_head *tmp = bucket;
177         struct ldlm_resource *res;
178
179         ENTRY;
180
181         if (ns->ns_hash == NULL)
182                 RETURN(NULL);
183         bucket = ns->ns_hash + ldlm_hash_fn(parent, name);
184
185         res = NULL;
186         list_for_each(tmp, bucket) {
187                 struct ldlm_resource *chk;
188                 chk = list_entry(tmp, struct ldlm_resource, lr_hash);
189
190                 if (memcmp(chk->lr_name, name,
191                            RES_NAME_SIZE * sizeof(__u32)) == 0) {
192                         res = chk;
193                         atomic_inc(&res->lr_refcount);
194                         break;
195                 }
196         }
197
198         if (res == NULL && create)
199                 res = ldlm_resource_add(ns, parent, name, type);
200
201         RETURN(res);
202 }
203
204 int ldlm_resource_put(struct ldlm_resource *res)
205 {
206         int rc = 0; 
207
208         if (atomic_read(&res->lr_refcount) <= 0)
209                 LBUG();
210
211         if (atomic_dec_and_test(&res->lr_refcount)) {
212                 if (!list_empty(&res->lr_granted))
213                         LBUG();
214
215                 if (!list_empty(&res->lr_converting))
216                         LBUG();
217
218                 if (!list_empty(&res->lr_waiting))
219                         LBUG();
220
221                 atomic_dec(&res->lr_namespace->ns_refcount);
222                 list_del(&res->lr_hash);
223                 list_del(&res->lr_rootlink);
224                 list_del(&res->lr_childof);
225
226                 kmem_cache_free(ldlm_resource_slab, res);
227                 rc = 1;
228         }
229
230         return rc; 
231 }
232
233 void ldlm_resource_add_lock(struct ldlm_resource *res, struct list_head *head,
234                             struct ldlm_lock *lock)
235 {
236         list_add(&lock->l_res_link, head);
237         atomic_inc(&res->lr_refcount);
238 }
239
240 void ldlm_resource_del_lock(struct ldlm_lock *lock)
241 {
242         list_del(&lock->l_res_link);
243         atomic_dec(&lock->l_resource->lr_refcount);
244 }
245
246 int ldlm_get_resource_handle(struct ldlm_resource *res, struct ldlm_handle *h)
247 {
248         LBUG();
249         return 0;
250 }
251
252 void ldlm_resource_dump(struct ldlm_resource *res)
253 {
254         struct list_head *tmp;
255         char name[256];
256
257         if (RES_NAME_SIZE != 3)
258                 LBUG();
259
260         snprintf(name, sizeof(name), "%Lx %Lx %Lx",
261                  res->lr_name[0], res->lr_name[1], res->lr_name[2]);
262
263         CDEBUG(D_OTHER, "--- Resource: %p (%s)\n", res, name);
264         CDEBUG(D_OTHER, "Namespace: %p (%u)\n", res->lr_namespace,
265                res->lr_namespace->ns_id);
266         CDEBUG(D_OTHER, "Parent: %p, root: %p\n", res->lr_parent, res->lr_root);
267
268         CDEBUG(D_OTHER, "Granted locks:\n");
269         list_for_each(tmp, &res->lr_granted) {
270                 struct ldlm_lock *lock;
271                 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
272                 ldlm_lock_dump(lock);
273         }
274
275         CDEBUG(D_OTHER, "Converting locks:\n");
276         list_for_each(tmp, &res->lr_converting) {
277                 struct ldlm_lock *lock;
278                 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
279                 ldlm_lock_dump(lock);
280         }
281
282         CDEBUG(D_OTHER, "Waiting locks:\n");
283         list_for_each(tmp, &res->lr_waiting) {
284                 struct ldlm_lock *lock;
285                 lock = list_entry(tmp, struct ldlm_lock, l_res_link);
286                 ldlm_lock_dump(lock);
287         }
288 }
289