]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - fs/gfs2/locking/dlm/mount.c
Merge branch 'sbp2-spindown' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee139...
[mirror_ubuntu-artful-kernel.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