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