blob: 09d78c216f4828792a27a0651a1cd98d6abf5d74 [file] [log] [blame]
David Teigland869d81d2006-01-17 08:47:12 +00001/*
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
Steven Whitehousee9fc2aa2006-09-01 11:05:15 -04007 * of the GNU General Public License version 2.
David Teigland869d81d2006-01-17 08:47:12 +00008 */
David Teigland29b79982006-01-16 16:52:38 +00009
10#include "lock_dlm.h"
11
Steven Whitehouse9b47c112006-09-08 10:17:58 -040012const struct lm_lockops gdlm_ops;
David Teigland29b79982006-01-16 16:52:38 +000013
14
Steven Whitehouse1c089c32006-09-07 15:50:20 -040015static struct gdlm_ls *init_gdlm(lm_callback_t cb, struct gfs2_sbd *sdp,
David Teigland29b79982006-01-16 16:52:38 +000016 int flags, char *table_name)
17{
18 struct gdlm_ls *ls;
19 char buf[256], *p;
20
David Teigland869d81d2006-01-17 08:47:12 +000021 ls = kzalloc(sizeof(struct gdlm_ls), GFP_KERNEL);
David Teigland29b79982006-01-16 16:52:38 +000022 if (!ls)
23 return NULL;
24
David Teigland29b79982006-01-16 16:52:38 +000025 ls->fscb = cb;
Steven Whitehouse1c089c32006-09-07 15:50:20 -040026 ls->sdp = sdp;
David Teigland29b79982006-01-16 16:52:38 +000027 ls->fsflags = flags;
David Teigland29b79982006-01-16 16:52:38 +000028 spin_lock_init(&ls->async_lock);
David Teigland29b79982006-01-16 16:52:38 +000029 INIT_LIST_HEAD(&ls->delayed);
30 INIT_LIST_HEAD(&ls->submit);
David Teigland29b79982006-01-16 16:52:38 +000031 init_waitqueue_head(&ls->thread_wait);
32 init_waitqueue_head(&ls->wait_control);
David Teigland29b79982006-01-16 16:52:38 +000033 ls->jid = -1;
34
35 strncpy(buf, table_name, 256);
36 buf[255] = '\0';
37
Al Viro4b4fcaa2006-10-11 17:25:45 +010038 p = strchr(buf, ':');
David Teigland29b79982006-01-16 16:52:38 +000039 if (!p) {
David Teigland869d81d2006-01-17 08:47:12 +000040 log_info("invalid table_name \"%s\"", table_name);
David Teigland29b79982006-01-16 16:52:38 +000041 kfree(ls);
42 return NULL;
43 }
44 *p = '\0';
45 p++;
46
David Teigland869d81d2006-01-17 08:47:12 +000047 strncpy(ls->clustername, buf, GDLM_NAME_LEN);
48 strncpy(ls->fsname, p, GDLM_NAME_LEN);
David Teigland29b79982006-01-16 16:52:38 +000049
50 return ls;
51}
52
David Teigland7aabffc2006-03-28 14:20:58 -050053static int make_args(struct gdlm_ls *ls, char *data_arg, int *nodir)
David Teigland869d81d2006-01-17 08:47:12 +000054{
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
Fabio Massimo Di Nitto0b7580c2007-11-15 13:48:52 +000062 if (!strlen(data)) {
David Teigland00c13472007-11-15 09:01:13 -060063 log_error("no mount options, (u)mount helpers not installed");
Fabio Massimo Di Nitto0b7580c2007-11-15 13:48:52 +000064 return -EINVAL;
65 }
66
David Teigland869d81d2006-01-17 08:47:12 +000067 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
David Teigland7aabffc2006-03-28 14:20:58 -050099 } 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
David Teigland869d81d2006-01-17 08:47:12 +0000107 } else {
108 log_error("unkonwn option: %s", x);
109 error = -EINVAL;
110 break;
111 }
112 }
113
114 return error;
115}
116
David Teigland29b79982006-01-16 16:52:38 +0000117static int gdlm_mount(char *table_name, char *host_data,
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400118 lm_callback_t cb, void *cb_data,
David Teigland29b79982006-01-16 16:52:38 +0000119 unsigned int min_lvb_size, int flags,
David Teigland869d81d2006-01-17 08:47:12 +0000120 struct lm_lockstruct *lockstruct,
121 struct kobject *fskobj)
David Teigland29b79982006-01-16 16:52:38 +0000122{
123 struct gdlm_ls *ls;
David Teigland7aabffc2006-03-28 14:20:58 -0500124 int error = -ENOMEM, nodir = 0;
David Teigland29b79982006-01-16 16:52:38 +0000125
126 if (min_lvb_size > GDLM_LVB_SIZE)
127 goto out;
128
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400129 ls = init_gdlm(cb, cb_data, flags, table_name);
David Teigland29b79982006-01-16 16:52:38 +0000130 if (!ls)
131 goto out;
132
David Teigland7aabffc2006-03-28 14:20:58 -0500133 error = make_args(ls, host_data, &nodir);
134 if (error)
135 goto out;
136
David Teigland29b79982006-01-16 16:52:38 +0000137 error = gdlm_init_threads(ls);
138 if (error)
139 goto out_free;
140
David Teiglandd2f222e2006-05-19 08:24:02 -0400141 error = gdlm_kobject_setup(ls, fskobj);
142 if (error)
143 goto out_thread;
144
David Teigland29b79982006-01-16 16:52:38 +0000145 error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname),
David Teigland7aabffc2006-03-28 14:20:58 -0500146 &ls->dlm_lockspace,
Patrick Caulfield44f487a2007-06-06 09:21:22 -0500147 DLM_LSFL_FS | (nodir ? DLM_LSFL_NODIR : 0),
David Teigland7aabffc2006-03-28 14:20:58 -0500148 GDLM_LVB_SIZE);
David Teigland29b79982006-01-16 16:52:38 +0000149 if (error) {
David Teigland869d81d2006-01-17 08:47:12 +0000150 log_error("dlm_new_lockspace error %d", error);
David Teiglandd2f222e2006-05-19 08:24:02 -0400151 goto out_kobj;
David Teigland29b79982006-01-16 16:52:38 +0000152 }
153
David Teigland29b79982006-01-16 16:52:38 +0000154 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
Steven Whitehousea91ea692006-09-04 12:04:26 -0400162out_kobj:
David Teiglandd2f222e2006-05-19 08:24:02 -0400163 gdlm_kobject_release(ls);
Steven Whitehousea91ea692006-09-04 12:04:26 -0400164out_thread:
David Teigland29b79982006-01-16 16:52:38 +0000165 gdlm_release_threads(ls);
Steven Whitehousea91ea692006-09-04 12:04:26 -0400166out_free:
David Teigland29b79982006-01-16 16:52:38 +0000167 kfree(ls);
Steven Whitehousea91ea692006-09-04 12:04:26 -0400168out:
David Teigland29b79982006-01-16 16:52:38 +0000169 return error;
170}
171
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400172static void gdlm_unmount(void *lockspace)
David Teigland29b79982006-01-16 16:52:38 +0000173{
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400174 struct gdlm_ls *ls = lockspace;
David Teigland29b79982006-01-16 16:52:38 +0000175
176 log_debug("unmount flags %lx", ls->flags);
177
David Teigland869d81d2006-01-17 08:47:12 +0000178 /* 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))
David Teigland29b79982006-01-16 16:52:38 +0000183 goto out;
David Teigland29b79982006-01-16 16:52:38 +0000184
185 gdlm_kobject_release(ls);
186 dlm_release_lockspace(ls->dlm_lockspace, 2);
187 gdlm_release_threads(ls);
Steven Whitehouse31fcba02008-06-04 15:06:21 +0100188 BUG_ON(ls->all_locks_count);
Steven Whitehousea91ea692006-09-04 12:04:26 -0400189out:
David Teigland29b79982006-01-16 16:52:38 +0000190 kfree(ls);
191}
192
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400193static void gdlm_recovery_done(void *lockspace, unsigned int jid,
David Teigland29b79982006-01-16 16:52:38 +0000194 unsigned int message)
195{
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400196 struct gdlm_ls *ls = lockspace;
David Teigland869d81d2006-01-17 08:47:12 +0000197 ls->recover_jid_done = jid;
David Teigland6bd70ab2006-04-26 15:56:35 -0400198 ls->recover_jid_status = message;
David Teigland5ddec5b2006-01-18 09:34:14 +0000199 kobject_uevent(&ls->kobj, KOBJ_CHANGE);
David Teigland29b79982006-01-16 16:52:38 +0000200}
201
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400202static void gdlm_others_may_mount(void *lockspace)
David Teigland29b79982006-01-16 16:52:38 +0000203{
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400204 struct gdlm_ls *ls = lockspace;
David Teigland29b79982006-01-16 16:52:38 +0000205 ls->first_done = 1;
David Teigland5ddec5b2006-01-18 09:34:14 +0000206 kobject_uevent(&ls->kobj, KOBJ_CHANGE);
David Teigland29b79982006-01-16 16:52:38 +0000207}
208
David Teigland869d81d2006-01-17 08:47:12 +0000209/* 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
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400213static void gdlm_withdraw(void *lockspace)
David Teigland29b79982006-01-16 16:52:38 +0000214{
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400215 struct gdlm_ls *ls = lockspace;
David Teigland29b79982006-01-16 16:52:38 +0000216
David Teigland5ddec5b2006-01-18 09:34:14 +0000217 kobject_uevent(&ls->kobj, KOBJ_OFFLINE);
David Teigland29b79982006-01-16 16:52:38 +0000218
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);
David Teigland869d81d2006-01-17 08:47:12 +0000224 gdlm_kobject_release(ls);
David Teigland29b79982006-01-16 16:52:38 +0000225}
226
David Teigland24022112008-03-14 15:09:15 -0500227static 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
234static 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
241static 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
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400248const struct lm_lockops gdlm_ops = {
David Teigland869d81d2006-01-17 08:47:12 +0000249 .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,
David Teigland869d81d2006-01-17 08:47:12 +0000264 .lm_recovery_done = gdlm_recovery_done,
265 .lm_owner = THIS_MODULE,
David Teigland29b79982006-01-16 16:52:38 +0000266};
267