]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - fs/gfs2/locking/dlm/mount.c
Merge branches 'sched/clock', 'sched/cleanups' and 'linus' into sched/urgent
[linux-2.6-omap-h63xx.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 | DLM_LSFL_NEWEXCL |
148                                   (nodir ? DLM_LSFL_NODIR : 0),
149                                   GDLM_LVB_SIZE);
150         if (error) {
151                 log_error("dlm_new_lockspace error %d", error);
152                 goto out_kobj;
153         }
154
155         lockstruct->ls_jid = ls->jid;
156         lockstruct->ls_first = ls->first;
157         lockstruct->ls_lockspace = ls;
158         lockstruct->ls_ops = &gdlm_ops;
159         lockstruct->ls_flags = 0;
160         lockstruct->ls_lvb_size = GDLM_LVB_SIZE;
161         return 0;
162
163 out_kobj:
164         gdlm_kobject_release(ls);
165 out_thread:
166         gdlm_release_threads(ls);
167 out_free:
168         kfree(ls);
169 out:
170         return error;
171 }
172
173 static void gdlm_unmount(void *lockspace)
174 {
175         struct gdlm_ls *ls = lockspace;
176
177         log_debug("unmount flags %lx", ls->flags);
178
179         /* FIXME: serialize unmount and withdraw in case they
180            happen at once.  Also, if unmount follows withdraw,
181            wait for withdraw to finish. */
182
183         if (test_bit(DFL_WITHDRAW, &ls->flags))
184                 goto out;
185
186         gdlm_kobject_release(ls);
187         dlm_release_lockspace(ls->dlm_lockspace, 2);
188         gdlm_release_threads(ls);
189         BUG_ON(ls->all_locks_count);
190 out:
191         kfree(ls);
192 }
193
194 static void gdlm_recovery_done(void *lockspace, unsigned int jid,
195                                unsigned int message)
196 {
197         char env_jid[20];
198         char env_status[20];
199         char *envp[] = { env_jid, env_status, NULL };
200         struct gdlm_ls *ls = lockspace;
201         ls->recover_jid_done = jid;
202         ls->recover_jid_status = message;
203         sprintf(env_jid, "JID=%d", jid);
204         sprintf(env_status, "RECOVERY=%s",
205                 message == LM_RD_SUCCESS ? "Done" : "Failed");
206         kobject_uevent_env(&ls->kobj, KOBJ_CHANGE, envp);
207 }
208
209 static void gdlm_others_may_mount(void *lockspace)
210 {
211         char *message = "FIRSTMOUNT=Done";
212         char *envp[] = { message, NULL };
213         struct gdlm_ls *ls = lockspace;
214         ls->first_done = 1;
215         kobject_uevent_env(&ls->kobj, KOBJ_CHANGE, envp);
216 }
217
218 /* Userspace gets the offline uevent, blocks new gfs locks on
219    other mounters, and lets us know (sets WITHDRAW flag).  Then,
220    userspace leaves the mount group while we leave the lockspace. */
221
222 static void gdlm_withdraw(void *lockspace)
223 {
224         struct gdlm_ls *ls = lockspace;
225
226         kobject_uevent(&ls->kobj, KOBJ_OFFLINE);
227
228         wait_event_interruptible(ls->wait_control,
229                                  test_bit(DFL_WITHDRAW, &ls->flags));
230
231         dlm_release_lockspace(ls->dlm_lockspace, 2);
232         gdlm_release_threads(ls);
233         gdlm_kobject_release(ls);
234 }
235
236 static int gdlm_plock(void *lockspace, struct lm_lockname *name,
237                struct file *file, int cmd, struct file_lock *fl)
238 {
239         struct gdlm_ls *ls = lockspace;
240         return dlm_posix_lock(ls->dlm_lockspace, name->ln_number, file, cmd, fl);
241 }
242
243 static int gdlm_punlock(void *lockspace, struct lm_lockname *name,
244                  struct file *file, struct file_lock *fl)
245 {
246         struct gdlm_ls *ls = lockspace;
247         return dlm_posix_unlock(ls->dlm_lockspace, name->ln_number, file, fl);
248 }
249
250 static int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
251                    struct file *file, struct file_lock *fl)
252 {
253         struct gdlm_ls *ls = lockspace;
254         return dlm_posix_get(ls->dlm_lockspace, name->ln_number, file, fl);
255 }
256
257 const struct lm_lockops gdlm_ops = {
258         .lm_proto_name = "lock_dlm",
259         .lm_mount = gdlm_mount,
260         .lm_others_may_mount = gdlm_others_may_mount,
261         .lm_unmount = gdlm_unmount,
262         .lm_withdraw = gdlm_withdraw,
263         .lm_get_lock = gdlm_get_lock,
264         .lm_put_lock = gdlm_put_lock,
265         .lm_lock = gdlm_lock,
266         .lm_unlock = gdlm_unlock,
267         .lm_plock = gdlm_plock,
268         .lm_punlock = gdlm_punlock,
269         .lm_plock_get = gdlm_plock_get,
270         .lm_cancel = gdlm_cancel,
271         .lm_hold_lvb = gdlm_hold_lvb,
272         .lm_unhold_lvb = gdlm_unhold_lvb,
273         .lm_recovery_done = gdlm_recovery_done,
274         .lm_owner = THIS_MODULE,
275 };
276