blob: ab301023094f9b8f999705618bfa4e37c3889549 [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
Fabio Massimo Di Nitto0b7580c2007-11-15 13:48:52 +000070 if (!strlen(data)) {
71 printk(KERN_ERR
72 "DLM/GFS2/GFS ERROR: (u)mount helpers are not installed!\n");
73 return -EINVAL;
74 }
75
David Teigland869d81d2006-01-17 08:47:12 +000076 for (options = data; (x = strsep(&options, ":")); ) {
77 if (!*x)
78 continue;
79
80 y = strchr(x, '=');
81 if (y)
82 *y++ = 0;
83
84 if (!strcmp(x, "jid")) {
85 if (!y) {
86 log_error("need argument to jid");
87 error = -EINVAL;
88 break;
89 }
90 sscanf(y, "%u", &ls->jid);
91
92 } else if (!strcmp(x, "first")) {
93 if (!y) {
94 log_error("need argument to first");
95 error = -EINVAL;
96 break;
97 }
98 sscanf(y, "%u", &ls->first);
99
100 } else if (!strcmp(x, "id")) {
101 if (!y) {
102 log_error("need argument to id");
103 error = -EINVAL;
104 break;
105 }
106 sscanf(y, "%u", &ls->id);
107
David Teigland7aabffc2006-03-28 14:20:58 -0500108 } else if (!strcmp(x, "nodir")) {
109 if (!y) {
110 log_error("need argument to nodir");
111 error = -EINVAL;
112 break;
113 }
114 sscanf(y, "%u", nodir);
115
David Teigland869d81d2006-01-17 08:47:12 +0000116 } else {
117 log_error("unkonwn option: %s", x);
118 error = -EINVAL;
119 break;
120 }
121 }
122
123 return error;
124}
125
David Teigland29b79982006-01-16 16:52:38 +0000126static int gdlm_mount(char *table_name, char *host_data,
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400127 lm_callback_t cb, void *cb_data,
David Teigland29b79982006-01-16 16:52:38 +0000128 unsigned int min_lvb_size, int flags,
David Teigland869d81d2006-01-17 08:47:12 +0000129 struct lm_lockstruct *lockstruct,
130 struct kobject *fskobj)
David Teigland29b79982006-01-16 16:52:38 +0000131{
132 struct gdlm_ls *ls;
David Teigland7aabffc2006-03-28 14:20:58 -0500133 int error = -ENOMEM, nodir = 0;
David Teigland29b79982006-01-16 16:52:38 +0000134
135 if (min_lvb_size > GDLM_LVB_SIZE)
136 goto out;
137
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400138 ls = init_gdlm(cb, cb_data, flags, table_name);
David Teigland29b79982006-01-16 16:52:38 +0000139 if (!ls)
140 goto out;
141
David Teigland7aabffc2006-03-28 14:20:58 -0500142 error = make_args(ls, host_data, &nodir);
143 if (error)
144 goto out;
145
David Teigland29b79982006-01-16 16:52:38 +0000146 error = gdlm_init_threads(ls);
147 if (error)
148 goto out_free;
149
David Teiglandd2f222e2006-05-19 08:24:02 -0400150 error = gdlm_kobject_setup(ls, fskobj);
151 if (error)
152 goto out_thread;
153
David Teigland29b79982006-01-16 16:52:38 +0000154 error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname),
David Teigland7aabffc2006-03-28 14:20:58 -0500155 &ls->dlm_lockspace,
Patrick Caulfield44f487a2007-06-06 09:21:22 -0500156 DLM_LSFL_FS | (nodir ? DLM_LSFL_NODIR : 0),
David Teigland7aabffc2006-03-28 14:20:58 -0500157 GDLM_LVB_SIZE);
David Teigland29b79982006-01-16 16:52:38 +0000158 if (error) {
David Teigland869d81d2006-01-17 08:47:12 +0000159 log_error("dlm_new_lockspace error %d", error);
David Teiglandd2f222e2006-05-19 08:24:02 -0400160 goto out_kobj;
David Teigland29b79982006-01-16 16:52:38 +0000161 }
162
David Teigland29b79982006-01-16 16:52:38 +0000163 lockstruct->ls_jid = ls->jid;
164 lockstruct->ls_first = ls->first;
165 lockstruct->ls_lockspace = ls;
166 lockstruct->ls_ops = &gdlm_ops;
167 lockstruct->ls_flags = 0;
168 lockstruct->ls_lvb_size = GDLM_LVB_SIZE;
169 return 0;
170
Steven Whitehousea91ea692006-09-04 12:04:26 -0400171out_kobj:
David Teiglandd2f222e2006-05-19 08:24:02 -0400172 gdlm_kobject_release(ls);
Steven Whitehousea91ea692006-09-04 12:04:26 -0400173out_thread:
David Teigland29b79982006-01-16 16:52:38 +0000174 gdlm_release_threads(ls);
Steven Whitehousea91ea692006-09-04 12:04:26 -0400175out_free:
David Teigland29b79982006-01-16 16:52:38 +0000176 kfree(ls);
Steven Whitehousea91ea692006-09-04 12:04:26 -0400177out:
David Teigland29b79982006-01-16 16:52:38 +0000178 return error;
179}
180
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400181static void gdlm_unmount(void *lockspace)
David Teigland29b79982006-01-16 16:52:38 +0000182{
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400183 struct gdlm_ls *ls = lockspace;
David Teigland29b79982006-01-16 16:52:38 +0000184 int rv;
185
186 log_debug("unmount flags %lx", ls->flags);
187
David Teigland869d81d2006-01-17 08:47:12 +0000188 /* FIXME: serialize unmount and withdraw in case they
189 happen at once. Also, if unmount follows withdraw,
190 wait for withdraw to finish. */
191
192 if (test_bit(DFL_WITHDRAW, &ls->flags))
David Teigland29b79982006-01-16 16:52:38 +0000193 goto out;
David Teigland29b79982006-01-16 16:52:38 +0000194
195 gdlm_kobject_release(ls);
196 dlm_release_lockspace(ls->dlm_lockspace, 2);
197 gdlm_release_threads(ls);
198 rv = gdlm_release_all_locks(ls);
199 if (rv)
David Teigland869d81d2006-01-17 08:47:12 +0000200 log_info("gdlm_unmount: %d stray locks freed", rv);
Steven Whitehousea91ea692006-09-04 12:04:26 -0400201out:
David Teigland29b79982006-01-16 16:52:38 +0000202 kfree(ls);
203}
204
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400205static void gdlm_recovery_done(void *lockspace, unsigned int jid,
David Teigland29b79982006-01-16 16:52:38 +0000206 unsigned int message)
207{
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400208 struct gdlm_ls *ls = lockspace;
David Teigland869d81d2006-01-17 08:47:12 +0000209 ls->recover_jid_done = jid;
David Teigland6bd70ab2006-04-26 15:56:35 -0400210 ls->recover_jid_status = message;
David Teigland5ddec5b2006-01-18 09:34:14 +0000211 kobject_uevent(&ls->kobj, KOBJ_CHANGE);
David Teigland29b79982006-01-16 16:52:38 +0000212}
213
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400214static void gdlm_others_may_mount(void *lockspace)
David Teigland29b79982006-01-16 16:52:38 +0000215{
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400216 struct gdlm_ls *ls = lockspace;
David Teigland29b79982006-01-16 16:52:38 +0000217 ls->first_done = 1;
David Teigland5ddec5b2006-01-18 09:34:14 +0000218 kobject_uevent(&ls->kobj, KOBJ_CHANGE);
David Teigland29b79982006-01-16 16:52:38 +0000219}
220
David Teigland869d81d2006-01-17 08:47:12 +0000221/* Userspace gets the offline uevent, blocks new gfs locks on
222 other mounters, and lets us know (sets WITHDRAW flag). Then,
223 userspace leaves the mount group while we leave the lockspace. */
224
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400225static void gdlm_withdraw(void *lockspace)
David Teigland29b79982006-01-16 16:52:38 +0000226{
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400227 struct gdlm_ls *ls = lockspace;
David Teigland29b79982006-01-16 16:52:38 +0000228
David Teigland5ddec5b2006-01-18 09:34:14 +0000229 kobject_uevent(&ls->kobj, KOBJ_OFFLINE);
David Teigland29b79982006-01-16 16:52:38 +0000230
231 wait_event_interruptible(ls->wait_control,
232 test_bit(DFL_WITHDRAW, &ls->flags));
233
234 dlm_release_lockspace(ls->dlm_lockspace, 2);
235 gdlm_release_threads(ls);
236 gdlm_release_all_locks(ls);
David Teigland869d81d2006-01-17 08:47:12 +0000237 gdlm_kobject_release(ls);
David Teigland29b79982006-01-16 16:52:38 +0000238}
239
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400240const struct lm_lockops gdlm_ops = {
David Teigland869d81d2006-01-17 08:47:12 +0000241 .lm_proto_name = "lock_dlm",
242 .lm_mount = gdlm_mount,
243 .lm_others_may_mount = gdlm_others_may_mount,
244 .lm_unmount = gdlm_unmount,
245 .lm_withdraw = gdlm_withdraw,
246 .lm_get_lock = gdlm_get_lock,
247 .lm_put_lock = gdlm_put_lock,
248 .lm_lock = gdlm_lock,
249 .lm_unlock = gdlm_unlock,
250 .lm_plock = gdlm_plock,
251 .lm_punlock = gdlm_punlock,
252 .lm_plock_get = gdlm_plock_get,
253 .lm_cancel = gdlm_cancel,
254 .lm_hold_lvb = gdlm_hold_lvb,
255 .lm_unhold_lvb = gdlm_unhold_lvb,
David Teigland869d81d2006-01-17 08:47:12 +0000256 .lm_recovery_done = gdlm_recovery_done,
257 .lm_owner = THIS_MODULE,
David Teigland29b79982006-01-16 16:52:38 +0000258};
259