blob: 41c5b04caaba4194712fe955a76750462066d4b2 [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 Teiglandee32e4f2007-01-25 14:24:04 -060025 ls->drop_locks_count = GDLM_DROP_COUNT;
26 ls->drop_locks_period = GDLM_DROP_PERIOD;
David Teigland29b79982006-01-16 16:52:38 +000027 ls->fscb = cb;
Steven Whitehouse1c089c32006-09-07 15:50:20 -040028 ls->sdp = sdp;
David Teigland29b79982006-01-16 16:52:38 +000029 ls->fsflags = flags;
David Teigland29b79982006-01-16 16:52:38 +000030 spin_lock_init(&ls->async_lock);
David Teigland29b79982006-01-16 16:52:38 +000031 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);
David Teigland29b79982006-01-16 16:52:38 +000036 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
Al Viro4b4fcaa2006-10-11 17:25:45 +010046 p = strchr(buf, ':');
David Teigland29b79982006-01-16 16:52:38 +000047 if (!p) {
David Teigland869d81d2006-01-17 08:47:12 +000048 log_info("invalid table_name \"%s\"", table_name);
David Teigland29b79982006-01-16 16:52:38 +000049 kfree(ls);
50 return NULL;
51 }
52 *p = '\0';
53 p++;
54
David Teigland869d81d2006-01-17 08:47:12 +000055 strncpy(ls->clustername, buf, GDLM_NAME_LEN);
56 strncpy(ls->fsname, p, GDLM_NAME_LEN);
David Teigland29b79982006-01-16 16:52:38 +000057
58 return ls;
59}
60
David Teigland7aabffc2006-03-28 14:20:58 -050061static int make_args(struct gdlm_ls *ls, char *data_arg, int *nodir)
David Teigland869d81d2006-01-17 08:47:12 +000062{
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
David Teigland7aabffc2006-03-28 14:20:58 -0500102 } 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
David Teigland869d81d2006-01-17 08:47:12 +0000110 } else {
111 log_error("unkonwn option: %s", x);
112 error = -EINVAL;
113 break;
114 }
115 }
116
117 return error;
118}
119
David Teigland29b79982006-01-16 16:52:38 +0000120static int gdlm_mount(char *table_name, char *host_data,
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400121 lm_callback_t cb, void *cb_data,
David Teigland29b79982006-01-16 16:52:38 +0000122 unsigned int min_lvb_size, int flags,
David Teigland869d81d2006-01-17 08:47:12 +0000123 struct lm_lockstruct *lockstruct,
124 struct kobject *fskobj)
David Teigland29b79982006-01-16 16:52:38 +0000125{
126 struct gdlm_ls *ls;
David Teigland7aabffc2006-03-28 14:20:58 -0500127 int error = -ENOMEM, nodir = 0;
David Teigland29b79982006-01-16 16:52:38 +0000128
129 if (min_lvb_size > GDLM_LVB_SIZE)
130 goto out;
131
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400132 ls = init_gdlm(cb, cb_data, flags, table_name);
David Teigland29b79982006-01-16 16:52:38 +0000133 if (!ls)
134 goto out;
135
David Teigland7aabffc2006-03-28 14:20:58 -0500136 error = make_args(ls, host_data, &nodir);
137 if (error)
138 goto out;
139
David Teigland29b79982006-01-16 16:52:38 +0000140 error = gdlm_init_threads(ls);
141 if (error)
142 goto out_free;
143
David Teiglandd2f222e2006-05-19 08:24:02 -0400144 error = gdlm_kobject_setup(ls, fskobj);
145 if (error)
146 goto out_thread;
147
David Teigland29b79982006-01-16 16:52:38 +0000148 error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname),
David Teigland7aabffc2006-03-28 14:20:58 -0500149 &ls->dlm_lockspace,
Patrick Caulfield44f487a2007-06-06 09:21:22 -0500150 DLM_LSFL_FS | (nodir ? DLM_LSFL_NODIR : 0),
David Teigland7aabffc2006-03-28 14:20:58 -0500151 GDLM_LVB_SIZE);
David Teigland29b79982006-01-16 16:52:38 +0000152 if (error) {
David Teigland869d81d2006-01-17 08:47:12 +0000153 log_error("dlm_new_lockspace error %d", error);
David Teiglandd2f222e2006-05-19 08:24:02 -0400154 goto out_kobj;
David Teigland29b79982006-01-16 16:52:38 +0000155 }
156
David Teigland29b79982006-01-16 16:52:38 +0000157 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
Steven Whitehousea91ea692006-09-04 12:04:26 -0400165out_kobj:
David Teiglandd2f222e2006-05-19 08:24:02 -0400166 gdlm_kobject_release(ls);
Steven Whitehousea91ea692006-09-04 12:04:26 -0400167out_thread:
David Teigland29b79982006-01-16 16:52:38 +0000168 gdlm_release_threads(ls);
Steven Whitehousea91ea692006-09-04 12:04:26 -0400169out_free:
David Teigland29b79982006-01-16 16:52:38 +0000170 kfree(ls);
Steven Whitehousea91ea692006-09-04 12:04:26 -0400171out:
David Teigland29b79982006-01-16 16:52:38 +0000172 return error;
173}
174
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400175static void gdlm_unmount(void *lockspace)
David Teigland29b79982006-01-16 16:52:38 +0000176{
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400177 struct gdlm_ls *ls = lockspace;
David Teigland29b79982006-01-16 16:52:38 +0000178 int rv;
179
180 log_debug("unmount flags %lx", ls->flags);
181
David Teigland869d81d2006-01-17 08:47:12 +0000182 /* 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))
David Teigland29b79982006-01-16 16:52:38 +0000187 goto out;
David Teigland29b79982006-01-16 16:52:38 +0000188
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)
David Teigland869d81d2006-01-17 08:47:12 +0000194 log_info("gdlm_unmount: %d stray locks freed", rv);
Steven Whitehousea91ea692006-09-04 12:04:26 -0400195out:
David Teigland29b79982006-01-16 16:52:38 +0000196 kfree(ls);
197}
198
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400199static void gdlm_recovery_done(void *lockspace, unsigned int jid,
David Teigland29b79982006-01-16 16:52:38 +0000200 unsigned int message)
201{
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400202 struct gdlm_ls *ls = lockspace;
David Teigland869d81d2006-01-17 08:47:12 +0000203 ls->recover_jid_done = jid;
David Teigland6bd70ab2006-04-26 15:56:35 -0400204 ls->recover_jid_status = message;
David Teigland5ddec5b2006-01-18 09:34:14 +0000205 kobject_uevent(&ls->kobj, KOBJ_CHANGE);
David Teigland29b79982006-01-16 16:52:38 +0000206}
207
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400208static void gdlm_others_may_mount(void *lockspace)
David Teigland29b79982006-01-16 16:52:38 +0000209{
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400210 struct gdlm_ls *ls = lockspace;
David Teigland29b79982006-01-16 16:52:38 +0000211 ls->first_done = 1;
David Teigland5ddec5b2006-01-18 09:34:14 +0000212 kobject_uevent(&ls->kobj, KOBJ_CHANGE);
David Teigland29b79982006-01-16 16:52:38 +0000213}
214
David Teigland869d81d2006-01-17 08:47:12 +0000215/* 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
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400219static void gdlm_withdraw(void *lockspace)
David Teigland29b79982006-01-16 16:52:38 +0000220{
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400221 struct gdlm_ls *ls = lockspace;
David Teigland29b79982006-01-16 16:52:38 +0000222
David Teigland5ddec5b2006-01-18 09:34:14 +0000223 kobject_uevent(&ls->kobj, KOBJ_OFFLINE);
David Teigland29b79982006-01-16 16:52:38 +0000224
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);
David Teigland869d81d2006-01-17 08:47:12 +0000231 gdlm_kobject_release(ls);
David Teigland29b79982006-01-16 16:52:38 +0000232}
233
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400234const struct lm_lockops gdlm_ops = {
David Teigland869d81d2006-01-17 08:47:12 +0000235 .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,
David Teigland869d81d2006-01-17 08:47:12 +0000250 .lm_recovery_done = gdlm_recovery_done,
251 .lm_owner = THIS_MODULE,
David Teigland29b79982006-01-16 16:52:38 +0000252};
253