Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
[linux-2.6] / fs / gfs2 / locking / dlm / mount.c
1 /*
2  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
3  * Copyright (C) 2004-2005 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 "lock_dlm.h"
11
12 const struct lm_lockops gdlm_ops;
13
14
15 static struct gdlm_ls *init_gdlm(lm_callback_t cb, struct gfs2_sbd *sdp,
16                                  int flags, char *table_name)
17 {
18         struct gdlm_ls *ls;
19         char buf[256], *p;
20
21         ls = kzalloc(sizeof(struct gdlm_ls), GFP_KERNEL);
22         if (!ls)
23                 return NULL;
24
25         ls->drop_locks_count = GDLM_DROP_COUNT;
26         ls->drop_locks_period = GDLM_DROP_PERIOD;
27         ls->fscb = cb;
28         ls->sdp = sdp;
29         ls->fsflags = flags;
30         spin_lock_init(&ls->async_lock);
31         INIT_LIST_HEAD(&ls->complete);
32         INIT_LIST_HEAD(&ls->blocking);
33         INIT_LIST_HEAD(&ls->delayed);
34         INIT_LIST_HEAD(&ls->submit);
35         INIT_LIST_HEAD(&ls->all_locks);
36         init_waitqueue_head(&ls->thread_wait);
37         init_waitqueue_head(&ls->wait_control);
38         ls->thread1 = NULL;
39         ls->thread2 = NULL;
40         ls->drop_time = jiffies;
41         ls->jid = -1;
42
43         strncpy(buf, table_name, 256);
44         buf[255] = '\0';
45
46         p = strchr(buf, ':');
47         if (!p) {
48                 log_info("invalid table_name \"%s\"", table_name);
49                 kfree(ls);
50                 return NULL;
51         }
52         *p = '\0';
53         p++;
54
55         strncpy(ls->clustername, buf, GDLM_NAME_LEN);
56         strncpy(ls->fsname, p, GDLM_NAME_LEN);
57
58         return ls;
59 }
60
61 static int make_args(struct gdlm_ls *ls, char *data_arg, int *nodir)
62 {
63         char data[256];
64         char *options, *x, *y;
65         int error = 0;
66
67         memset(data, 0, 256);
68         strncpy(data, data_arg, 255);
69
70         if (!strlen(data)) {
71                 log_error("no mount options, (u)mount helpers not installed");
72                 return -EINVAL;
73         }
74
75         for (options = data; (x = strsep(&options, ":")); ) {
76                 if (!*x)
77                         continue;
78
79                 y = strchr(x, '=');
80                 if (y)
81                         *y++ = 0;
82
83                 if (!strcmp(x, "jid")) {
84                         if (!y) {
85                                 log_error("need argument to jid");
86                                 error = -EINVAL;
87                                 break;
88                         }
89                         sscanf(y, "%u", &ls->jid);
90
91                 } else if (!strcmp(x, "first")) {
92                         if (!y) {
93                                 log_error("need argument to first");
94                                 error = -EINVAL;
95                                 break;
96                         }
97                         sscanf(y, "%u", &ls->first);
98
99                 } else if (!strcmp(x, "id")) {
100                         if (!y) {
101                                 log_error("need argument to id");
102                                 error = -EINVAL;
103                                 break;
104                         }
105                         sscanf(y, "%u", &ls->id);
106
107                 } else if (!strcmp(x, "nodir")) {
108                         if (!y) {
109                                 log_error("need argument to nodir");
110                                 error = -EINVAL;
111                                 break;
112                         }
113                         sscanf(y, "%u", nodir);
114
115                 } else {
116                         log_error("unkonwn option: %s", x);
117                         error = -EINVAL;
118                         break;
119                 }
120         }
121
122         return error;
123 }
124
125 static int gdlm_mount(char *table_name, char *host_data,
126                         lm_callback_t cb, void *cb_data,
127                         unsigned int min_lvb_size, int flags,
128                         struct lm_lockstruct *lockstruct,
129                         struct kobject *fskobj)
130 {
131         struct gdlm_ls *ls;
132         int error = -ENOMEM, nodir = 0;
133
134         if (min_lvb_size > GDLM_LVB_SIZE)
135                 goto out;
136
137         ls = init_gdlm(cb, cb_data, flags, table_name);
138         if (!ls)
139                 goto out;
140
141         error = make_args(ls, host_data, &nodir);
142         if (error)
143                 goto out;
144
145         error = gdlm_init_threads(ls);
146         if (error)
147                 goto out_free;
148
149         error = gdlm_kobject_setup(ls, fskobj);
150         if (error)
151                 goto out_thread;
152
153         error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname),
154                                   &ls->dlm_lockspace,
155                                   DLM_LSFL_FS | (nodir ? DLM_LSFL_NODIR : 0),
156                                   GDLM_LVB_SIZE);
157         if (error) {
158                 log_error("dlm_new_lockspace error %d", error);
159                 goto out_kobj;
160         }
161
162         lockstruct->ls_jid = ls->jid;
163         lockstruct->ls_first = ls->first;
164         lockstruct->ls_lockspace = ls;
165         lockstruct->ls_ops = &gdlm_ops;
166         lockstruct->ls_flags = 0;
167         lockstruct->ls_lvb_size = GDLM_LVB_SIZE;
168         return 0;
169
170 out_kobj:
171         gdlm_kobject_release(ls);
172 out_thread:
173         gdlm_release_threads(ls);
174 out_free:
175         kfree(ls);
176 out:
177         return error;
178 }
179
180 static void gdlm_unmount(void *lockspace)
181 {
182         struct gdlm_ls *ls = lockspace;
183         int rv;
184
185         log_debug("unmount flags %lx", ls->flags);
186
187         /* FIXME: serialize unmount and withdraw in case they
188            happen at once.  Also, if unmount follows withdraw,
189            wait for withdraw to finish. */
190
191         if (test_bit(DFL_WITHDRAW, &ls->flags))
192                 goto out;
193
194         gdlm_kobject_release(ls);
195         dlm_release_lockspace(ls->dlm_lockspace, 2);
196         gdlm_release_threads(ls);
197         rv = gdlm_release_all_locks(ls);
198         if (rv)
199                 log_info("gdlm_unmount: %d stray locks freed", rv);
200 out:
201         kfree(ls);
202 }
203
204 static void gdlm_recovery_done(void *lockspace, unsigned int jid,
205                                unsigned int message)
206 {
207         struct gdlm_ls *ls = lockspace;
208         ls->recover_jid_done = jid;
209         ls->recover_jid_status = message;
210         kobject_uevent(&ls->kobj, KOBJ_CHANGE);
211 }
212
213 static void gdlm_others_may_mount(void *lockspace)
214 {
215         struct gdlm_ls *ls = lockspace;
216         ls->first_done = 1;
217         kobject_uevent(&ls->kobj, KOBJ_CHANGE);
218 }
219
220 /* Userspace gets the offline uevent, blocks new gfs locks on
221    other mounters, and lets us know (sets WITHDRAW flag).  Then,
222    userspace leaves the mount group while we leave the lockspace. */
223
224 static void gdlm_withdraw(void *lockspace)
225 {
226         struct gdlm_ls *ls = lockspace;
227
228         kobject_uevent(&ls->kobj, KOBJ_OFFLINE);
229
230         wait_event_interruptible(ls->wait_control,
231                                  test_bit(DFL_WITHDRAW, &ls->flags));
232
233         dlm_release_lockspace(ls->dlm_lockspace, 2);
234         gdlm_release_threads(ls);
235         gdlm_release_all_locks(ls);
236         gdlm_kobject_release(ls);
237 }
238
239 static int gdlm_plock(void *lockspace, struct lm_lockname *name,
240                struct file *file, int cmd, struct file_lock *fl)
241 {
242         struct gdlm_ls *ls = lockspace;
243         return dlm_posix_lock(ls->dlm_lockspace, name->ln_number, file, cmd, fl);
244 }
245
246 static int gdlm_punlock(void *lockspace, struct lm_lockname *name,
247                  struct file *file, struct file_lock *fl)
248 {
249         struct gdlm_ls *ls = lockspace;
250         return dlm_posix_unlock(ls->dlm_lockspace, name->ln_number, file, fl);
251 }
252
253 static int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
254                    struct file *file, struct file_lock *fl)
255 {
256         struct gdlm_ls *ls = lockspace;
257         return dlm_posix_get(ls->dlm_lockspace, name->ln_number, file, fl);
258 }
259
260 const struct lm_lockops gdlm_ops = {
261         .lm_proto_name = "lock_dlm",
262         .lm_mount = gdlm_mount,
263         .lm_others_may_mount = gdlm_others_may_mount,
264         .lm_unmount = gdlm_unmount,
265         .lm_withdraw = gdlm_withdraw,
266         .lm_get_lock = gdlm_get_lock,
267         .lm_put_lock = gdlm_put_lock,
268         .lm_lock = gdlm_lock,
269         .lm_unlock = gdlm_unlock,
270         .lm_plock = gdlm_plock,
271         .lm_punlock = gdlm_punlock,
272         .lm_plock_get = gdlm_plock_get,
273         .lm_cancel = gdlm_cancel,
274         .lm_hold_lvb = gdlm_hold_lvb,
275         .lm_unhold_lvb = gdlm_unhold_lvb,
276         .lm_recovery_done = gdlm_recovery_done,
277         .lm_owner = THIS_MODULE,
278 };
279