blob: 026f05ce168d6687d091c24f80401e0f36ce8605 [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
7 * of the GNU General Public License v.2.
8 */
David Teigland29b79982006-01-16 16:52:38 +00009
10#include "lock_dlm.h"
11
12int gdlm_drop_count;
13int gdlm_drop_period;
14struct lm_lockops gdlm_ops;
15
16
17static struct gdlm_ls *init_gdlm(lm_callback_t cb, lm_fsdata_t *fsdata,
18 int flags, char *table_name)
19{
20 struct gdlm_ls *ls;
21 char buf[256], *p;
22
David Teigland869d81d2006-01-17 08:47:12 +000023 ls = kzalloc(sizeof(struct gdlm_ls), GFP_KERNEL);
David Teigland29b79982006-01-16 16:52:38 +000024 if (!ls)
25 return NULL;
26
David Teigland29b79982006-01-16 16:52:38 +000027 ls->drop_locks_count = gdlm_drop_count;
28 ls->drop_locks_period = gdlm_drop_period;
David Teigland29b79982006-01-16 16:52:38 +000029 ls->fscb = cb;
30 ls->fsdata = fsdata;
31 ls->fsflags = flags;
David Teigland29b79982006-01-16 16:52:38 +000032 spin_lock_init(&ls->async_lock);
David Teigland29b79982006-01-16 16:52:38 +000033 INIT_LIST_HEAD(&ls->complete);
34 INIT_LIST_HEAD(&ls->blocking);
35 INIT_LIST_HEAD(&ls->delayed);
36 INIT_LIST_HEAD(&ls->submit);
37 INIT_LIST_HEAD(&ls->all_locks);
David Teigland29b79982006-01-16 16:52:38 +000038 init_waitqueue_head(&ls->thread_wait);
39 init_waitqueue_head(&ls->wait_control);
40 ls->thread1 = NULL;
41 ls->thread2 = NULL;
42 ls->drop_time = jiffies;
43 ls->jid = -1;
44
45 strncpy(buf, table_name, 256);
46 buf[255] = '\0';
47
48 p = strstr(buf, ":");
49 if (!p) {
David Teigland869d81d2006-01-17 08:47:12 +000050 log_info("invalid table_name \"%s\"", table_name);
David Teigland29b79982006-01-16 16:52:38 +000051 kfree(ls);
52 return NULL;
53 }
54 *p = '\0';
55 p++;
56
David Teigland869d81d2006-01-17 08:47:12 +000057 strncpy(ls->clustername, buf, GDLM_NAME_LEN);
58 strncpy(ls->fsname, p, GDLM_NAME_LEN);
David Teigland29b79982006-01-16 16:52:38 +000059
60 return ls;
61}
62
David Teigland7aabffc2006-03-28 14:20:58 -050063static int make_args(struct gdlm_ls *ls, char *data_arg, int *nodir)
David Teigland869d81d2006-01-17 08:47:12 +000064{
65 char data[256];
66 char *options, *x, *y;
67 int error = 0;
68
69 memset(data, 0, 256);
70 strncpy(data, data_arg, 255);
71
72 for (options = data; (x = strsep(&options, ":")); ) {
73 if (!*x)
74 continue;
75
76 y = strchr(x, '=');
77 if (y)
78 *y++ = 0;
79
80 if (!strcmp(x, "jid")) {
81 if (!y) {
82 log_error("need argument to jid");
83 error = -EINVAL;
84 break;
85 }
86 sscanf(y, "%u", &ls->jid);
87
88 } else if (!strcmp(x, "first")) {
89 if (!y) {
90 log_error("need argument to first");
91 error = -EINVAL;
92 break;
93 }
94 sscanf(y, "%u", &ls->first);
95
96 } else if (!strcmp(x, "id")) {
97 if (!y) {
98 log_error("need argument to id");
99 error = -EINVAL;
100 break;
101 }
102 sscanf(y, "%u", &ls->id);
103
David Teigland7aabffc2006-03-28 14:20:58 -0500104 } else if (!strcmp(x, "nodir")) {
105 if (!y) {
106 log_error("need argument to nodir");
107 error = -EINVAL;
108 break;
109 }
110 sscanf(y, "%u", nodir);
111
David Teigland869d81d2006-01-17 08:47:12 +0000112 } else {
113 log_error("unkonwn option: %s", x);
114 error = -EINVAL;
115 break;
116 }
117 }
118
119 return error;
120}
121
David Teigland29b79982006-01-16 16:52:38 +0000122static int gdlm_mount(char *table_name, char *host_data,
123 lm_callback_t cb, lm_fsdata_t *fsdata,
124 unsigned int min_lvb_size, int flags,
David Teigland869d81d2006-01-17 08:47:12 +0000125 struct lm_lockstruct *lockstruct,
126 struct kobject *fskobj)
David Teigland29b79982006-01-16 16:52:38 +0000127{
128 struct gdlm_ls *ls;
David Teigland7aabffc2006-03-28 14:20:58 -0500129 int error = -ENOMEM, nodir = 0;
David Teigland29b79982006-01-16 16:52:38 +0000130
131 if (min_lvb_size > GDLM_LVB_SIZE)
132 goto out;
133
134 ls = init_gdlm(cb, fsdata, flags, table_name);
135 if (!ls)
136 goto out;
137
David Teigland7aabffc2006-03-28 14:20:58 -0500138 error = make_args(ls, host_data, &nodir);
139 if (error)
140 goto out;
141
David Teigland29b79982006-01-16 16:52:38 +0000142 error = gdlm_init_threads(ls);
143 if (error)
144 goto out_free;
145
146 error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname),
David Teigland7aabffc2006-03-28 14:20:58 -0500147 &ls->dlm_lockspace,
148 nodir ? DLM_LSFL_NODIR : 0,
149 GDLM_LVB_SIZE);
David Teigland29b79982006-01-16 16:52:38 +0000150 if (error) {
David Teigland869d81d2006-01-17 08:47:12 +0000151 log_error("dlm_new_lockspace error %d", error);
David Teigland29b79982006-01-16 16:52:38 +0000152 goto out_thread;
153 }
154
David Teigland869d81d2006-01-17 08:47:12 +0000155 error = gdlm_kobject_setup(ls, fskobj);
David Teigland29b79982006-01-16 16:52:38 +0000156 if (error)
157 goto out_dlm;
David Teigland29b79982006-01-16 16:52:38 +0000158
David Teigland29b79982006-01-16 16:52:38 +0000159 lockstruct->ls_jid = ls->jid;
160 lockstruct->ls_first = ls->first;
161 lockstruct->ls_lockspace = ls;
162 lockstruct->ls_ops = &gdlm_ops;
163 lockstruct->ls_flags = 0;
164 lockstruct->ls_lvb_size = GDLM_LVB_SIZE;
165 return 0;
166
David Teigland29b79982006-01-16 16:52:38 +0000167 out_dlm:
168 dlm_release_lockspace(ls->dlm_lockspace, 2);
169 out_thread:
170 gdlm_release_threads(ls);
171 out_free:
172 kfree(ls);
173 out:
174 return error;
175}
176
177static void gdlm_unmount(lm_lockspace_t *lockspace)
178{
179 struct gdlm_ls *ls = (struct gdlm_ls *) lockspace;
180 int rv;
181
182 log_debug("unmount flags %lx", ls->flags);
183
David Teigland869d81d2006-01-17 08:47:12 +0000184 /* FIXME: serialize unmount and withdraw in case they
185 happen at once. Also, if unmount follows withdraw,
186 wait for withdraw to finish. */
187
188 if (test_bit(DFL_WITHDRAW, &ls->flags))
David Teigland29b79982006-01-16 16:52:38 +0000189 goto out;
David Teigland29b79982006-01-16 16:52:38 +0000190
191 gdlm_kobject_release(ls);
192 dlm_release_lockspace(ls->dlm_lockspace, 2);
193 gdlm_release_threads(ls);
194 rv = gdlm_release_all_locks(ls);
195 if (rv)
David Teigland869d81d2006-01-17 08:47:12 +0000196 log_info("gdlm_unmount: %d stray locks freed", rv);
David Teigland29b79982006-01-16 16:52:38 +0000197 out:
198 kfree(ls);
199}
200
201static void gdlm_recovery_done(lm_lockspace_t *lockspace, unsigned int jid,
202 unsigned int message)
203{
204 struct gdlm_ls *ls = (struct gdlm_ls *) lockspace;
David Teigland869d81d2006-01-17 08:47:12 +0000205 ls->recover_jid_done = jid;
David Teigland5ddec5b2006-01-18 09:34:14 +0000206 kobject_uevent(&ls->kobj, KOBJ_CHANGE);
David Teigland29b79982006-01-16 16:52:38 +0000207}
208
209static void gdlm_others_may_mount(lm_lockspace_t *lockspace)
210{
211 struct gdlm_ls *ls = (struct gdlm_ls *) lockspace;
212 ls->first_done = 1;
David Teigland5ddec5b2006-01-18 09:34:14 +0000213 kobject_uevent(&ls->kobj, KOBJ_CHANGE);
David Teigland29b79982006-01-16 16:52:38 +0000214}
215
David Teigland869d81d2006-01-17 08:47:12 +0000216/* Userspace gets the offline uevent, blocks new gfs locks on
217 other mounters, and lets us know (sets WITHDRAW flag). Then,
218 userspace leaves the mount group while we leave the lockspace. */
219
David Teigland29b79982006-01-16 16:52:38 +0000220static void gdlm_withdraw(lm_lockspace_t *lockspace)
221{
222 struct gdlm_ls *ls = (struct gdlm_ls *) lockspace;
223
David Teigland5ddec5b2006-01-18 09:34:14 +0000224 kobject_uevent(&ls->kobj, KOBJ_OFFLINE);
David Teigland29b79982006-01-16 16:52:38 +0000225
226 wait_event_interruptible(ls->wait_control,
227 test_bit(DFL_WITHDRAW, &ls->flags));
228
229 dlm_release_lockspace(ls->dlm_lockspace, 2);
230 gdlm_release_threads(ls);
231 gdlm_release_all_locks(ls);
David Teigland869d81d2006-01-17 08:47:12 +0000232 gdlm_kobject_release(ls);
David Teigland29b79982006-01-16 16:52:38 +0000233}
234
235struct lm_lockops gdlm_ops = {
David Teigland869d81d2006-01-17 08:47:12 +0000236 .lm_proto_name = "lock_dlm",
237 .lm_mount = gdlm_mount,
238 .lm_others_may_mount = gdlm_others_may_mount,
239 .lm_unmount = gdlm_unmount,
240 .lm_withdraw = gdlm_withdraw,
241 .lm_get_lock = gdlm_get_lock,
242 .lm_put_lock = gdlm_put_lock,
243 .lm_lock = gdlm_lock,
244 .lm_unlock = gdlm_unlock,
245 .lm_plock = gdlm_plock,
246 .lm_punlock = gdlm_punlock,
247 .lm_plock_get = gdlm_plock_get,
248 .lm_cancel = gdlm_cancel,
249 .lm_hold_lvb = gdlm_hold_lvb,
250 .lm_unhold_lvb = gdlm_unhold_lvb,
251 .lm_sync_lvb = gdlm_sync_lvb,
252 .lm_recovery_done = gdlm_recovery_done,
253 .lm_owner = THIS_MODULE,
David Teigland29b79982006-01-16 16:52:38 +0000254};
255