Merge branch 'drm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[linux-2.6] / fs / gfs2 / locking.c
1 /*
2  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
3  * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
4  *
5  * This copyrighted material is made available to anyone wishing to use,
6  * modify, copy, or redistribute it subject to the terms and conditions
7  * of the GNU General Public License version 2.
8  */
9
10 #include <linux/module.h>
11 #include <linux/init.h>
12 #include <linux/string.h>
13 #include <linux/slab.h>
14 #include <linux/wait.h>
15 #include <linux/sched.h>
16 #include <linux/kmod.h>
17 #include <linux/fs.h>
18 #include <linux/delay.h>
19 #include <linux/lm_interface.h>
20
21 struct lmh_wrapper {
22         struct list_head lw_list;
23         const struct lm_lockops *lw_ops;
24 };
25
26 static int nolock_mount(char *table_name, char *host_data,
27                         lm_callback_t cb, void *cb_data,
28                         unsigned int min_lvb_size, int flags,
29                         struct lm_lockstruct *lockstruct,
30                         struct kobject *fskobj);
31
32 /* List of registered low-level locking protocols.  A file system selects one
33    of them by name at mount time, e.g. lock_nolock, lock_dlm. */
34
35 static const struct lm_lockops nolock_ops = {
36         .lm_proto_name = "lock_nolock",
37         .lm_mount = nolock_mount,
38 };
39
40 static struct lmh_wrapper nolock_proto  = {
41         .lw_list = LIST_HEAD_INIT(nolock_proto.lw_list),
42         .lw_ops = &nolock_ops,
43 };
44
45 static LIST_HEAD(lmh_list);
46 static DEFINE_MUTEX(lmh_lock);
47
48 static int nolock_mount(char *table_name, char *host_data,
49                         lm_callback_t cb, void *cb_data,
50                         unsigned int min_lvb_size, int flags,
51                         struct lm_lockstruct *lockstruct,
52                         struct kobject *fskobj)
53 {
54         char *c;
55         unsigned int jid;
56
57         c = strstr(host_data, "jid=");
58         if (!c)
59                 jid = 0;
60         else {
61                 c += 4;
62                 sscanf(c, "%u", &jid);
63         }
64
65         lockstruct->ls_jid = jid;
66         lockstruct->ls_first = 1;
67         lockstruct->ls_lvb_size = min_lvb_size;
68         lockstruct->ls_ops = &nolock_ops;
69         lockstruct->ls_flags = LM_LSFLAG_LOCAL;
70
71         return 0;
72 }
73
74 /**
75  * gfs2_register_lockproto - Register a low-level locking protocol
76  * @proto: the protocol definition
77  *
78  * Returns: 0 on success, -EXXX on failure
79  */
80
81 int gfs2_register_lockproto(const struct lm_lockops *proto)
82 {
83         struct lmh_wrapper *lw;
84
85         mutex_lock(&lmh_lock);
86
87         list_for_each_entry(lw, &lmh_list, lw_list) {
88                 if (!strcmp(lw->lw_ops->lm_proto_name, proto->lm_proto_name)) {
89                         mutex_unlock(&lmh_lock);
90                         printk(KERN_INFO "GFS2: protocol %s already exists\n",
91                                proto->lm_proto_name);
92                         return -EEXIST;
93                 }
94         }
95
96         lw = kzalloc(sizeof(struct lmh_wrapper), GFP_KERNEL);
97         if (!lw) {
98                 mutex_unlock(&lmh_lock);
99                 return -ENOMEM;
100         }
101
102         lw->lw_ops = proto;
103         list_add(&lw->lw_list, &lmh_list);
104
105         mutex_unlock(&lmh_lock);
106
107         return 0;
108 }
109
110 /**
111  * gfs2_unregister_lockproto - Unregister a low-level locking protocol
112  * @proto: the protocol definition
113  *
114  */
115
116 void gfs2_unregister_lockproto(const struct lm_lockops *proto)
117 {
118         struct lmh_wrapper *lw;
119
120         mutex_lock(&lmh_lock);
121
122         list_for_each_entry(lw, &lmh_list, lw_list) {
123                 if (!strcmp(lw->lw_ops->lm_proto_name, proto->lm_proto_name)) {
124                         list_del(&lw->lw_list);
125                         mutex_unlock(&lmh_lock);
126                         kfree(lw);
127                         return;
128                 }
129         }
130
131         mutex_unlock(&lmh_lock);
132
133         printk(KERN_WARNING "GFS2: can't unregister lock protocol %s\n",
134                proto->lm_proto_name);
135 }
136
137 /**
138  * gfs2_mount_lockproto - Mount a lock protocol
139  * @proto_name - the name of the protocol
140  * @table_name - the name of the lock space
141  * @host_data - data specific to this host
142  * @cb - the callback to the code using the lock module
143  * @sdp - The GFS2 superblock
144  * @min_lvb_size - the mininum LVB size that the caller can deal with
145  * @flags - LM_MFLAG_*
146  * @lockstruct - a structure returned describing the mount
147  *
148  * Returns: 0 on success, -EXXX on failure
149  */
150
151 int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data,
152                          lm_callback_t cb, void *cb_data,
153                          unsigned int min_lvb_size, int flags,
154                          struct lm_lockstruct *lockstruct,
155                          struct kobject *fskobj)
156 {
157         struct lmh_wrapper *lw = NULL;
158         int try = 0;
159         int error, found;
160
161
162 retry:
163         mutex_lock(&lmh_lock);
164
165         if (list_empty(&nolock_proto.lw_list))
166                 list_add(&nolock_proto.lw_list, &lmh_list);
167
168         found = 0;
169         list_for_each_entry(lw, &lmh_list, lw_list) {
170                 if (!strcmp(lw->lw_ops->lm_proto_name, proto_name)) {
171                         found = 1;
172                         break;
173                 }
174         }
175
176         if (!found) {
177                 if (!try && capable(CAP_SYS_MODULE)) {
178                         try = 1;
179                         mutex_unlock(&lmh_lock);
180                         request_module(proto_name);
181                         goto retry;
182                 }
183                 printk(KERN_INFO "GFS2: can't find protocol %s\n", proto_name);
184                 error = -ENOENT;
185                 goto out;
186         }
187
188         if (lw->lw_ops->lm_owner &&
189             !try_module_get(lw->lw_ops->lm_owner)) {
190                 try = 0;
191                 mutex_unlock(&lmh_lock);
192                 msleep(1000);
193                 goto retry;
194         }
195
196         error = lw->lw_ops->lm_mount(table_name, host_data, cb, cb_data,
197                                      min_lvb_size, flags, lockstruct, fskobj);
198         if (error)
199                 module_put(lw->lw_ops->lm_owner);
200 out:
201         mutex_unlock(&lmh_lock);
202         return error;
203 }
204
205 void gfs2_unmount_lockproto(struct lm_lockstruct *lockstruct)
206 {
207         mutex_lock(&lmh_lock);
208         if (lockstruct->ls_ops->lm_unmount)
209                 lockstruct->ls_ops->lm_unmount(lockstruct->ls_lockspace);
210         if (lockstruct->ls_ops->lm_owner)
211                 module_put(lockstruct->ls_ops->lm_owner);
212         mutex_unlock(&lmh_lock);
213 }
214
215 /**
216  * gfs2_withdraw_lockproto - abnormally unmount a lock module
217  * @lockstruct: the lockstruct passed into mount
218  *
219  */
220
221 void gfs2_withdraw_lockproto(struct lm_lockstruct *lockstruct)
222 {
223         mutex_lock(&lmh_lock);
224         lockstruct->ls_ops->lm_withdraw(lockstruct->ls_lockspace);
225         if (lockstruct->ls_ops->lm_owner)
226                 module_put(lockstruct->ls_ops->lm_owner);
227         mutex_unlock(&lmh_lock);
228 }
229
230 EXPORT_SYMBOL_GPL(gfs2_register_lockproto);
231 EXPORT_SYMBOL_GPL(gfs2_unregister_lockproto);
232