blob: 3caeafc02a1b6d354b3044ff4c96959aaa9fbb0b [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
David Teiglandd2f222e2006-05-19 08:24:02 -0400146 error = gdlm_kobject_setup(ls, fskobj);
147 if (error)
148 goto out_thread;
149
David Teigland29b79982006-01-16 16:52:38 +0000150 error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname),
David Teigland7aabffc2006-03-28 14:20:58 -0500151 &ls->dlm_lockspace,
152 nodir ? DLM_LSFL_NODIR : 0,
153 GDLM_LVB_SIZE);
David Teigland29b79982006-01-16 16:52:38 +0000154 if (error) {
David Teigland869d81d2006-01-17 08:47:12 +0000155 log_error("dlm_new_lockspace error %d", error);
David Teiglandd2f222e2006-05-19 08:24:02 -0400156 goto out_kobj;
David Teigland29b79982006-01-16 16:52:38 +0000157 }
158
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 Teiglandd2f222e2006-05-19 08:24:02 -0400167 out_kobj:
168 gdlm_kobject_release(ls);
David Teigland29b79982006-01-16 16:52:38 +0000169 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 Teigland6bd70ab2006-04-26 15:56:35 -0400206 ls->recover_jid_status = message;
David Teigland5ddec5b2006-01-18 09:34:14 +0000207 kobject_uevent(&ls->kobj, KOBJ_CHANGE);
David Teigland29b79982006-01-16 16:52:38 +0000208}
209
210static void gdlm_others_may_mount(lm_lockspace_t *lockspace)
211{
212 struct gdlm_ls *ls = (struct gdlm_ls *) lockspace;
213 ls->first_done = 1;
David Teigland5ddec5b2006-01-18 09:34:14 +0000214 kobject_uevent(&ls->kobj, KOBJ_CHANGE);
David Teigland29b79982006-01-16 16:52:38 +0000215}
216
David Teigland869d81d2006-01-17 08:47:12 +0000217/* Userspace gets the offline uevent, blocks new gfs locks on
218 other mounters, and lets us know (sets WITHDRAW flag). Then,
219 userspace leaves the mount group while we leave the lockspace. */
220
David Teigland29b79982006-01-16 16:52:38 +0000221static void gdlm_withdraw(lm_lockspace_t *lockspace)
222{
223 struct gdlm_ls *ls = (struct gdlm_ls *) lockspace;
224
David Teigland5ddec5b2006-01-18 09:34:14 +0000225 kobject_uevent(&ls->kobj, KOBJ_OFFLINE);
David Teigland29b79982006-01-16 16:52:38 +0000226
227 wait_event_interruptible(ls->wait_control,
228 test_bit(DFL_WITHDRAW, &ls->flags));
229
230 dlm_release_lockspace(ls->dlm_lockspace, 2);
231 gdlm_release_threads(ls);
232 gdlm_release_all_locks(ls);
David Teigland869d81d2006-01-17 08:47:12 +0000233 gdlm_kobject_release(ls);
David Teigland29b79982006-01-16 16:52:38 +0000234}
235
236struct lm_lockops gdlm_ops = {
David Teigland869d81d2006-01-17 08:47:12 +0000237 .lm_proto_name = "lock_dlm",
238 .lm_mount = gdlm_mount,
239 .lm_others_may_mount = gdlm_others_may_mount,
240 .lm_unmount = gdlm_unmount,
241 .lm_withdraw = gdlm_withdraw,
242 .lm_get_lock = gdlm_get_lock,
243 .lm_put_lock = gdlm_put_lock,
244 .lm_lock = gdlm_lock,
245 .lm_unlock = gdlm_unlock,
246 .lm_plock = gdlm_plock,
247 .lm_punlock = gdlm_punlock,
248 .lm_plock_get = gdlm_plock_get,
249 .lm_cancel = gdlm_cancel,
250 .lm_hold_lvb = gdlm_hold_lvb,
251 .lm_unhold_lvb = gdlm_unhold_lvb,
252 .lm_sync_lvb = gdlm_sync_lvb,
253 .lm_recovery_done = gdlm_recovery_done,
254 .lm_owner = THIS_MODULE,
David Teigland29b79982006-01-16 16:52:38 +0000255};
256