Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-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         for (options = data; (x = strsep(&options, ":")); ) {
71                 if (!*x)
72                         continue;
73
74                 y = strchr(x, '=');
75                 if (y)
76                         *y++ = 0;
77
78                 if (!strcmp(x, "jid")) {
79                         if (!y) {
80                                 log_error("need argument to jid");
81                                 error = -EINVAL;
82                                 break;
83                         }
84                         sscanf(y, "%u", &ls->jid);
85
86                 } else if (!strcmp(x, "first")) {
87                         if (!y) {
88                                 log_error("need argument to first");
89                                 error = -EINVAL;
90                                 break;
91                         }
92                         sscanf(y, "%u", &ls->first);
93
94                 } else if (!strcmp(x, "id")) {
95                         if (!y) {
96                                 log_error("need argument to id");
97                                 error = -EINVAL;
98                                 break;
99                         }
100                         sscanf(y, "%u", &ls->id);
101
102                 } else if (!strcmp(x, "nodir")) {
103                         if (!y) {
104                                 log_error("need argument to nodir");
105                                 error = -EINVAL;
106                                 break;
107                         }
108                         sscanf(y, "%u", nodir);
109
110                 } else {
111                         log_error("unkonwn option: %s", x);
112                         error = -EINVAL;
113                         break;
114                 }
115         }
116
117         return error;
118 }
119
120 static int gdlm_mount(char *table_name, char *host_data,
121                         lm_callback_t cb, void *cb_data,
122                         unsigned int min_lvb_size, int flags,
123                         struct lm_lockstruct *lockstruct,
124                         struct kobject *fskobj)
125 {
126         struct gdlm_ls *ls;
127         int error = -ENOMEM, nodir = 0;
128
129         if (min_lvb_size > GDLM_LVB_SIZE)
130                 goto out;
131
132         ls = init_gdlm(cb, cb_data, flags, table_name);
133         if (!ls)
134                 goto out;
135
136         error = make_args(ls, host_data, &nodir);
137         if (error)
138                 goto out;
139
140         error = gdlm_init_threads(ls);
141         if (error)
142                 goto out_free;
143
144         error = gdlm_kobject_setup(ls, fskobj);
145         if (error)
146                 goto out_thread;
147
148         error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname),
149                                   &ls->dlm_lockspace,
150                                   DLM_LSFL_FS | (nodir ? DLM_LSFL_NODIR : 0),
151                                   GDLM_LVB_SIZE);
152         if (error) {
153                 log_error("dlm_new_lockspace error %d", error);
154                 goto out_kobj;
155         }
156
157         lockstruct->ls_jid = ls->jid;
158         lockstruct->ls_first = ls->first;
159         lockstruct->ls_lockspace = ls;
160         lockstruct->ls_ops = &gdlm_ops;
161         lockstruct->ls_flags = 0;
162         lockstruct->ls_lvb_size = GDLM_LVB_SIZE;
163         return 0;
164
165 out_kobj:
166         gdlm_kobject_release(ls);
167 out_thread:
168         gdlm_release_threads(ls);
169 out_free:
170         kfree(ls);
171 out:
172         return error;
173 }
174
175 static void gdlm_unmount(void *lockspace)
176 {
177         struct gdlm_ls *ls = lockspace;
178         int rv;
179
180         log_debug("unmount flags %lx", ls->flags);
181
182         /* FIXME: serialize unmount and withdraw in case they
183            happen at once.  Also, if unmount follows withdraw,
184            wait for withdraw to finish. */
185
186         if (test_bit(DFL_WITHDRAW, &ls->flags))
187                 goto out;
188
189         gdlm_kobject_release(ls);
190         dlm_release_lockspace(ls->dlm_lockspace, 2);
191         gdlm_release_threads(ls);
192         rv = gdlm_release_all_locks(ls);
193         if (rv)
194                 log_info("gdlm_unmount: %d stray locks freed", rv);
195 out:
196         kfree(ls);
197 }
198
199 static void gdlm_recovery_done(void *lockspace, unsigned int jid,
200                                unsigned int message)
201 {
202         struct gdlm_ls *ls = lockspace;
203         ls->recover_jid_done = jid;
204         ls->recover_jid_status = message;
205         kobject_uevent(&ls->kobj, KOBJ_CHANGE);
206 }
207
208 static void gdlm_others_may_mount(void *lockspace)
209 {
210         struct gdlm_ls *ls = lockspace;
211         ls->first_done = 1;
212         kobject_uevent(&ls->kobj, KOBJ_CHANGE);
213 }
214
215 /* Userspace gets the offline uevent, blocks new gfs locks on
216    other mounters, and lets us know (sets WITHDRAW flag).  Then,
217    userspace leaves the mount group while we leave the lockspace. */
218
219 static void gdlm_withdraw(void *lockspace)
220 {
221         struct gdlm_ls *ls = lockspace;
222
223         kobject_uevent(&ls->kobj, KOBJ_OFFLINE);
224
225         wait_event_interruptible(ls->wait_control,
226                                  test_bit(DFL_WITHDRAW, &ls->flags));
227
228         dlm_release_lockspace(ls->dlm_lockspace, 2);
229         gdlm_release_threads(ls);
230         gdlm_release_all_locks(ls);
231         gdlm_kobject_release(ls);
232 }
233
234 const struct lm_lockops gdlm_ops = {
235         .lm_proto_name = "lock_dlm",
236         .lm_mount = gdlm_mount,
237         .lm_others_may_mount = gdlm_others_may_mount,
238         .lm_unmount = gdlm_unmount,
239         .lm_withdraw = gdlm_withdraw,
240         .lm_get_lock = gdlm_get_lock,
241         .lm_put_lock = gdlm_put_lock,
242         .lm_lock = gdlm_lock,
243         .lm_unlock = gdlm_unlock,
244         .lm_plock = gdlm_plock,
245         .lm_punlock = gdlm_punlock,
246         .lm_plock_get = gdlm_plock_get,
247         .lm_cancel = gdlm_cancel,
248         .lm_hold_lvb = gdlm_hold_lvb,
249         .lm_unhold_lvb = gdlm_unhold_lvb,
250         .lm_recovery_done = gdlm_recovery_done,
251         .lm_owner = THIS_MODULE,
252 };
253