blob: f2efff424224dd3e0052284076e679d067e48ad8 [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)) {
David Teigland00c13472007-11-15 09:01:13 -060071 log_error("no mount options, (u)mount helpers not installed");
Fabio Massimo Di Nitto0b7580c2007-11-15 13:48:52 +000072 return -EINVAL;
73 }
74
David Teigland869d81d2006-01-17 08:47:12 +000075 for (options = data; (x = strsep(&options, ":")); ) {
76 if (!*x)
77 continue;
78
79 y = strchr(x, '=');
80 if (y)
81 *y++ = 0;
82
83 if (!strcmp(x, "jid")) {
84 if (!y) {
85 log_error("need argument to jid");
86 error = -EINVAL;
87 break;
88 }
89 sscanf(y, "%u", &ls->jid);
90
91 } else if (!strcmp(x, "first")) {
92 if (!y) {
93 log_error("need argument to first");
94 error = -EINVAL;
95 break;
96 }
97 sscanf(y, "%u", &ls->first);
98
99 } else if (!strcmp(x, "id")) {
100 if (!y) {
101 log_error("need argument to id");
102 error = -EINVAL;
103 break;
104 }
105 sscanf(y, "%u", &ls->id);
106
David Teigland7aabffc2006-03-28 14:20:58 -0500107 } else if (!strcmp(x, "nodir")) {
108 if (!y) {
109 log_error("need argument to nodir");
110 error = -EINVAL;
111 break;
112 }
113 sscanf(y, "%u", nodir);
114
David Teigland869d81d2006-01-17 08:47:12 +0000115 } else {
116 log_error("unkonwn option: %s", x);
117 error = -EINVAL;
118 break;
119 }
120 }
121
122 return error;
123}
124
David Teigland29b79982006-01-16 16:52:38 +0000125static int gdlm_mount(char *table_name, char *host_data,
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400126 lm_callback_t cb, void *cb_data,
David Teigland29b79982006-01-16 16:52:38 +0000127 unsigned int min_lvb_size, int flags,
David Teigland869d81d2006-01-17 08:47:12 +0000128 struct lm_lockstruct *lockstruct,
129 struct kobject *fskobj)
David Teigland29b79982006-01-16 16:52:38 +0000130{
131 struct gdlm_ls *ls;
David Teigland7aabffc2006-03-28 14:20:58 -0500132 int error = -ENOMEM, nodir = 0;
David Teigland29b79982006-01-16 16:52:38 +0000133
134 if (min_lvb_size > GDLM_LVB_SIZE)
135 goto out;
136
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400137 ls = init_gdlm(cb, cb_data, flags, table_name);
David Teigland29b79982006-01-16 16:52:38 +0000138 if (!ls)
139 goto out;
140
David Teigland7aabffc2006-03-28 14:20:58 -0500141 error = make_args(ls, host_data, &nodir);
142 if (error)
143 goto out;
144
David Teigland29b79982006-01-16 16:52:38 +0000145 error = gdlm_init_threads(ls);
146 if (error)
147 goto out_free;
148
David Teiglandd2f222e2006-05-19 08:24:02 -0400149 error = gdlm_kobject_setup(ls, fskobj);
150 if (error)
151 goto out_thread;
152
David Teigland29b79982006-01-16 16:52:38 +0000153 error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname),
David Teigland7aabffc2006-03-28 14:20:58 -0500154 &ls->dlm_lockspace,
Patrick Caulfield44f487a2007-06-06 09:21:22 -0500155 DLM_LSFL_FS | (nodir ? DLM_LSFL_NODIR : 0),
David Teigland7aabffc2006-03-28 14:20:58 -0500156 GDLM_LVB_SIZE);
David Teigland29b79982006-01-16 16:52:38 +0000157 if (error) {
David Teigland869d81d2006-01-17 08:47:12 +0000158 log_error("dlm_new_lockspace error %d", error);
David Teiglandd2f222e2006-05-19 08:24:02 -0400159 goto out_kobj;
David Teigland29b79982006-01-16 16:52:38 +0000160 }
161
David Teigland29b79982006-01-16 16:52:38 +0000162 lockstruct->ls_jid = ls->jid;
163 lockstruct->ls_first = ls->first;
164 lockstruct->ls_lockspace = ls;
165 lockstruct->ls_ops = &gdlm_ops;
166 lockstruct->ls_flags = 0;
167 lockstruct->ls_lvb_size = GDLM_LVB_SIZE;
168 return 0;
169
Steven Whitehousea91ea692006-09-04 12:04:26 -0400170out_kobj:
David Teiglandd2f222e2006-05-19 08:24:02 -0400171 gdlm_kobject_release(ls);
Steven Whitehousea91ea692006-09-04 12:04:26 -0400172out_thread:
David Teigland29b79982006-01-16 16:52:38 +0000173 gdlm_release_threads(ls);
Steven Whitehousea91ea692006-09-04 12:04:26 -0400174out_free:
David Teigland29b79982006-01-16 16:52:38 +0000175 kfree(ls);
Steven Whitehousea91ea692006-09-04 12:04:26 -0400176out:
David Teigland29b79982006-01-16 16:52:38 +0000177 return error;
178}
179
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400180static void gdlm_unmount(void *lockspace)
David Teigland29b79982006-01-16 16:52:38 +0000181{
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400182 struct gdlm_ls *ls = lockspace;
David Teigland29b79982006-01-16 16:52:38 +0000183 int rv;
184
185 log_debug("unmount flags %lx", ls->flags);
186
David Teigland869d81d2006-01-17 08:47:12 +0000187 /* FIXME: serialize unmount and withdraw in case they
188 happen at once. Also, if unmount follows withdraw,
189 wait for withdraw to finish. */
190
191 if (test_bit(DFL_WITHDRAW, &ls->flags))
David Teigland29b79982006-01-16 16:52:38 +0000192 goto out;
David Teigland29b79982006-01-16 16:52:38 +0000193
194 gdlm_kobject_release(ls);
195 dlm_release_lockspace(ls->dlm_lockspace, 2);
196 gdlm_release_threads(ls);
197 rv = gdlm_release_all_locks(ls);
198 if (rv)
David Teigland869d81d2006-01-17 08:47:12 +0000199 log_info("gdlm_unmount: %d stray locks freed", rv);
Steven Whitehousea91ea692006-09-04 12:04:26 -0400200out:
David Teigland29b79982006-01-16 16:52:38 +0000201 kfree(ls);
202}
203
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400204static void gdlm_recovery_done(void *lockspace, unsigned int jid,
David Teigland29b79982006-01-16 16:52:38 +0000205 unsigned int message)
206{
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400207 struct gdlm_ls *ls = lockspace;
David Teigland869d81d2006-01-17 08:47:12 +0000208 ls->recover_jid_done = jid;
David Teigland6bd70ab2006-04-26 15:56:35 -0400209 ls->recover_jid_status = message;
David Teigland5ddec5b2006-01-18 09:34:14 +0000210 kobject_uevent(&ls->kobj, KOBJ_CHANGE);
David Teigland29b79982006-01-16 16:52:38 +0000211}
212
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400213static void gdlm_others_may_mount(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 ls->first_done = 1;
David Teigland5ddec5b2006-01-18 09:34:14 +0000217 kobject_uevent(&ls->kobj, KOBJ_CHANGE);
David Teigland29b79982006-01-16 16:52:38 +0000218}
219
David Teigland869d81d2006-01-17 08:47:12 +0000220/* Userspace gets the offline uevent, blocks new gfs locks on
221 other mounters, and lets us know (sets WITHDRAW flag). Then,
222 userspace leaves the mount group while we leave the lockspace. */
223
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400224static void gdlm_withdraw(void *lockspace)
David Teigland29b79982006-01-16 16:52:38 +0000225{
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400226 struct gdlm_ls *ls = lockspace;
David Teigland29b79982006-01-16 16:52:38 +0000227
David Teigland5ddec5b2006-01-18 09:34:14 +0000228 kobject_uevent(&ls->kobj, KOBJ_OFFLINE);
David Teigland29b79982006-01-16 16:52:38 +0000229
230 wait_event_interruptible(ls->wait_control,
231 test_bit(DFL_WITHDRAW, &ls->flags));
232
233 dlm_release_lockspace(ls->dlm_lockspace, 2);
234 gdlm_release_threads(ls);
235 gdlm_release_all_locks(ls);
David Teigland869d81d2006-01-17 08:47:12 +0000236 gdlm_kobject_release(ls);
David Teigland29b79982006-01-16 16:52:38 +0000237}
238
Steven Whitehouse9b47c112006-09-08 10:17:58 -0400239const struct lm_lockops gdlm_ops = {
David Teigland869d81d2006-01-17 08:47:12 +0000240 .lm_proto_name = "lock_dlm",
241 .lm_mount = gdlm_mount,
242 .lm_others_may_mount = gdlm_others_may_mount,
243 .lm_unmount = gdlm_unmount,
244 .lm_withdraw = gdlm_withdraw,
245 .lm_get_lock = gdlm_get_lock,
246 .lm_put_lock = gdlm_put_lock,
247 .lm_lock = gdlm_lock,
248 .lm_unlock = gdlm_unlock,
249 .lm_plock = gdlm_plock,
250 .lm_punlock = gdlm_punlock,
251 .lm_plock_get = gdlm_plock_get,
252 .lm_cancel = gdlm_cancel,
253 .lm_hold_lvb = gdlm_hold_lvb,
254 .lm_unhold_lvb = gdlm_unhold_lvb,
David Teigland869d81d2006-01-17 08:47:12 +0000255 .lm_recovery_done = gdlm_recovery_done,
256 .lm_owner = THIS_MODULE,
David Teigland29b79982006-01-16 16:52:38 +0000257};
258