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