Whamcloud - gitweb
285e16b5488f74514c7276c46b06493d4599e152
[fs/lustre-release.git] / lustre / ldlm / ldlm_lock.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 extern kmem_cache_t *ldlm_lock_slab;
27
28 static struct ldlm_lock *ldlm_lock_new(struct ldlm_lock *parent,
29                                        struct ldlm_resource *resource,
30                                        ldlm_mode_t mode)
31 {
32         struct ldlm_lock *lock;
33
34         lock = kmem_cache_alloc(ldlm_lock_slab, SLAB_KERNEL);
35         if (lock == NULL)
36                 BUG();
37
38         memset(lock, 0, sizeof(*lock));
39         lock->l_resource = resource;
40         lock->l_req_mode = mode;
41         INIT_LIST_HEAD(&lock->l_children);
42
43         if (parent != NULL) {
44                 lock->l_parent = parent;
45                 list_add(&lock->l_childof, &parent->l_children);
46         }
47
48         return lock;
49 }
50
51 static int ldlm_notify_incompatible(struct list_head *list,
52                                     struct ldlm_lock *new)
53 {
54         struct list_head *tmp;
55         int rc = 0;
56
57         list_for_each(tmp, list) {
58                 struct ldlm_lock *lock = list_entry(tmp, struct ldlm_lock,
59                                                     l_res_link);
60                 if (lockmode_compat(lock->l_req_mode, new->l_req_mode))
61                         continue;
62
63                 rc = 1;
64
65                 if (lock->l_resource->lr_blocking != NULL)
66                         lock->l_resource->lr_blocking(lock, new);
67         }
68
69         return rc;
70 }
71
72 ldlm_error_t ldlm_local_lock_enqueue(struct obd_device *obddev, __u32 ns_id,
73                                      struct ldlm_resource *parent_res,
74                                      struct ldlm_lock *parent_lock,
75                                      __u32 *res_id, ldlm_mode_t mode)
76 {
77         struct ldlm_namespace *ns;
78         struct ldlm_resource *res;
79         struct ldlm_lock *lock;
80         int incompat, rc;
81
82         ENTRY;
83
84         ns = ldlm_namespace_find(obddev, ns_id);
85         if (ns == NULL || ns->ns_hash == NULL)
86                 BUG();
87
88         res = ldlm_resource_get(ns, parent_res, res_id, 1);
89         if (res == NULL)
90                 BUG();
91
92         lock = ldlm_lock_new(parent_lock, res, mode);
93         if (lock == NULL)
94                 BUG();
95
96         spin_lock(&res->lr_lock);
97
98         /* FIXME: We may want to optimize by checking lr_most_restr */
99
100         if (!list_empty(&res->lr_converting)) {
101                 list_add(&lock->l_res_link, res->lr_waiting.prev);
102                 rc = ELDLM_BLOCK_CONV;
103                 GOTO(out, rc);
104         }
105         if (!list_empty(&res->lr_waiting)) {
106                 list_add(&lock->l_res_link, res->lr_waiting.prev);
107                 rc = ELDLM_BLOCK_WAIT;
108                 GOTO(out, rc);
109         }
110         incompat = ldlm_notify_incompatible(&res->lr_granted, lock);
111         if (incompat) {
112                 list_add(&lock->l_res_link, res->lr_waiting.prev);
113                 rc = ELDLM_BLOCK_GRANTED;
114                 GOTO(out, rc);
115         }
116
117         list_add(&lock->l_res_link, &res->lr_granted);
118         lock->l_granted_mode = mode;
119         if (mode < res->lr_most_restr)
120                 res->lr_most_restr = mode;
121
122         rc = ELDLM_OK;
123         GOTO(out, rc);
124
125  out:
126         spin_unlock(&res->lr_lock);
127         return rc;
128 }
129
130 void ldlm_lock_dump(struct ldlm_lock *lock)
131 {
132         char ver[128];
133
134         if (RES_VERSION_SIZE != 4)
135                 BUG();
136
137         snprintf(ver, sizeof(ver), "%x %x %x %x",
138                  lock->l_version[0], lock->l_version[1],
139                  lock->l_version[2], lock->l_version[3]);
140
141         CDEBUG(D_OTHER, "  -- Lock dump: %p (%s)\n", lock, ver);
142         CDEBUG(D_OTHER, "  Parent: %p\n", lock->l_parent);
143         CDEBUG(D_OTHER, "  Requested mode: %d, granted mode: %d\n",
144                (int)lock->l_req_mode, (int)lock->l_granted_mode);
145 }