blob: bfb224638f2dd1cd7a132615afe1955a5a8ca209 [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 Teigland869d81d2006-01-17 08:47:12 +000063static int make_args(struct gdlm_ls *ls, char *data_arg)
64{
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
104 } else {
105 log_error("unkonwn option: %s", x);
106 error = -EINVAL;
107 break;
108 }
109 }
110
111 return error;
112}
113
David Teigland29b79982006-01-16 16:52:38 +0000114static int gdlm_mount(char *table_name, char *host_data,
115 lm_callback_t cb, lm_fsdata_t *fsdata,
116 unsigned int min_lvb_size, int flags,
David Teigland869d81d2006-01-17 08:47:12 +0000117 struct lm_lockstruct *lockstruct,
118 struct kobject *fskobj)
David Teigland29b79982006-01-16 16:52:38 +0000119{
120 struct gdlm_ls *ls;
121 int error = -ENOMEM;
122
123 if (min_lvb_size > GDLM_LVB_SIZE)
124 goto out;
125
126 ls = init_gdlm(cb, fsdata, flags, table_name);
127 if (!ls)
128 goto out;
129
130 error = gdlm_init_threads(ls);
131 if (error)
132 goto out_free;
133
134 error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname),
135 &ls->dlm_lockspace, 0, GDLM_LVB_SIZE);
136 if (error) {
David Teigland869d81d2006-01-17 08:47:12 +0000137 log_error("dlm_new_lockspace error %d", error);
David Teigland29b79982006-01-16 16:52:38 +0000138 goto out_thread;
139 }
140
David Teigland869d81d2006-01-17 08:47:12 +0000141 error = gdlm_kobject_setup(ls, fskobj);
David Teigland29b79982006-01-16 16:52:38 +0000142 if (error)
143 goto out_dlm;
David Teigland29b79982006-01-16 16:52:38 +0000144
David Teigland869d81d2006-01-17 08:47:12 +0000145 error = make_args(ls, host_data);
David Teigland29b79982006-01-16 16:52:38 +0000146 if (error)
147 goto out_sysfs;
148
David Teigland29b79982006-01-16 16:52:38 +0000149 lockstruct->ls_jid = ls->jid;
150 lockstruct->ls_first = ls->first;
151 lockstruct->ls_lockspace = ls;
152 lockstruct->ls_ops = &gdlm_ops;
153 lockstruct->ls_flags = 0;
154 lockstruct->ls_lvb_size = GDLM_LVB_SIZE;
155 return 0;
156
157 out_sysfs:
158 gdlm_kobject_release(ls);
159 out_dlm:
160 dlm_release_lockspace(ls->dlm_lockspace, 2);
161 out_thread:
162 gdlm_release_threads(ls);
163 out_free:
164 kfree(ls);
165 out:
166 return error;
167}
168
169static void gdlm_unmount(lm_lockspace_t *lockspace)
170{
171 struct gdlm_ls *ls = (struct gdlm_ls *) lockspace;
172 int rv;
173
174 log_debug("unmount flags %lx", ls->flags);
175
David Teigland869d81d2006-01-17 08:47:12 +0000176 /* FIXME: serialize unmount and withdraw in case they
177 happen at once. Also, if unmount follows withdraw,
178 wait for withdraw to finish. */
179
180 if (test_bit(DFL_WITHDRAW, &ls->flags))
David Teigland29b79982006-01-16 16:52:38 +0000181 goto out;
David Teigland29b79982006-01-16 16:52:38 +0000182
183 gdlm_kobject_release(ls);
184 dlm_release_lockspace(ls->dlm_lockspace, 2);
185 gdlm_release_threads(ls);
186 rv = gdlm_release_all_locks(ls);
187 if (rv)
David Teigland869d81d2006-01-17 08:47:12 +0000188 log_info("gdlm_unmount: %d stray locks freed", rv);
David Teigland29b79982006-01-16 16:52:38 +0000189 out:
190 kfree(ls);
191}
192
193static void gdlm_recovery_done(lm_lockspace_t *lockspace, unsigned int jid,
194 unsigned int message)
195{
196 struct gdlm_ls *ls = (struct gdlm_ls *) lockspace;
David Teigland869d81d2006-01-17 08:47:12 +0000197 ls->recover_jid_done = jid;
David Teigland29b79982006-01-16 16:52:38 +0000198 kobject_uevent(&ls->kobj, KOBJ_CHANGE, NULL);
199}
200
201static void gdlm_others_may_mount(lm_lockspace_t *lockspace)
202{
203 struct gdlm_ls *ls = (struct gdlm_ls *) lockspace;
204 ls->first_done = 1;
205 kobject_uevent(&ls->kobj, KOBJ_CHANGE, NULL);
206}
207
David Teigland869d81d2006-01-17 08:47:12 +0000208/* Userspace gets the offline uevent, blocks new gfs locks on
209 other mounters, and lets us know (sets WITHDRAW flag). Then,
210 userspace leaves the mount group while we leave the lockspace. */
211
David Teigland29b79982006-01-16 16:52:38 +0000212static void gdlm_withdraw(lm_lockspace_t *lockspace)
213{
214 struct gdlm_ls *ls = (struct gdlm_ls *) lockspace;
215
David Teigland29b79982006-01-16 16:52:38 +0000216 kobject_uevent(&ls->kobj, KOBJ_OFFLINE, NULL);
217
218 wait_event_interruptible(ls->wait_control,
219 test_bit(DFL_WITHDRAW, &ls->flags));
220
221 dlm_release_lockspace(ls->dlm_lockspace, 2);
222 gdlm_release_threads(ls);
223 gdlm_release_all_locks(ls);
David Teigland869d81d2006-01-17 08:47:12 +0000224 gdlm_kobject_release(ls);
David Teigland29b79982006-01-16 16:52:38 +0000225}
226
227struct lm_lockops gdlm_ops = {
David Teigland869d81d2006-01-17 08:47:12 +0000228 .lm_proto_name = "lock_dlm",
229 .lm_mount = gdlm_mount,
230 .lm_others_may_mount = gdlm_others_may_mount,
231 .lm_unmount = gdlm_unmount,
232 .lm_withdraw = gdlm_withdraw,
233 .lm_get_lock = gdlm_get_lock,
234 .lm_put_lock = gdlm_put_lock,
235 .lm_lock = gdlm_lock,
236 .lm_unlock = gdlm_unlock,
237 .lm_plock = gdlm_plock,
238 .lm_punlock = gdlm_punlock,
239 .lm_plock_get = gdlm_plock_get,
240 .lm_cancel = gdlm_cancel,
241 .lm_hold_lvb = gdlm_hold_lvb,
242 .lm_unhold_lvb = gdlm_unhold_lvb,
243 .lm_sync_lvb = gdlm_sync_lvb,
244 .lm_recovery_done = gdlm_recovery_done,
245 .lm_owner = THIS_MODULE,
David Teigland29b79982006-01-16 16:52:38 +0000246};
247