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