Merge branch 'master'
[linux-2.6] / fs / gfs2 / locking / dlm / mount.c
1 /*
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  */
9
10 #include "lock_dlm.h"
11
12 int gdlm_drop_count;
13 int gdlm_drop_period;
14 struct lm_lockops gdlm_ops;
15
16
17 static 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
23         ls = kzalloc(sizeof(struct gdlm_ls), GFP_KERNEL);
24         if (!ls)
25                 return NULL;
26
27         ls->drop_locks_count = gdlm_drop_count;
28         ls->drop_locks_period = gdlm_drop_period;
29         ls->fscb = cb;
30         ls->fsdata = fsdata;
31         ls->fsflags = flags;
32         spin_lock_init(&ls->async_lock);
33         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);
38         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) {
50                 log_info("invalid table_name \"%s\"", table_name);
51                 kfree(ls);
52                 return NULL;
53         }
54         *p = '\0';
55         p++;
56
57         strncpy(ls->clustername, buf, GDLM_NAME_LEN);
58         strncpy(ls->fsname, p, GDLM_NAME_LEN);
59
60         return ls;
61 }
62
63 static int make_args(struct gdlm_ls *ls, char *data_arg, int *nodir)
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 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
112                 } else {
113                         log_error("unkonwn option: %s", x);
114                         error = -EINVAL;
115                         break;
116                 }
117         }
118
119         return error;
120 }
121
122 static 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,
125                         struct lm_lockstruct *lockstruct,
126                         struct kobject *fskobj)
127 {
128         struct gdlm_ls *ls;
129         int error = -ENOMEM, nodir = 0;
130
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
138         error = make_args(ls, host_data, &nodir);
139         if (error)
140                 goto out;
141
142         error = gdlm_init_threads(ls);
143         if (error)
144                 goto out_free;
145
146         error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname),
147                                   &ls->dlm_lockspace,
148                                   nodir ? DLM_LSFL_NODIR : 0,
149                                   GDLM_LVB_SIZE);
150         if (error) {
151                 log_error("dlm_new_lockspace error %d", error);
152                 goto out_thread;
153         }
154
155         error = gdlm_kobject_setup(ls, fskobj);
156         if (error)
157                 goto out_dlm;
158
159         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
167  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
177 static 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
184         /* 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))
189                 goto out;
190
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)
196                 log_info("gdlm_unmount: %d stray locks freed", rv);
197  out:
198         kfree(ls);
199 }
200
201 static 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;
205         ls->recover_jid_done = jid;
206         kobject_uevent(&ls->kobj, KOBJ_CHANGE);
207 }
208
209 static void gdlm_others_may_mount(lm_lockspace_t *lockspace)
210 {
211         struct gdlm_ls *ls = (struct gdlm_ls *) lockspace;
212         ls->first_done = 1;
213         kobject_uevent(&ls->kobj, KOBJ_CHANGE);
214 }
215
216 /* 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
220 static void gdlm_withdraw(lm_lockspace_t *lockspace)
221 {
222         struct gdlm_ls *ls = (struct gdlm_ls *) lockspace;
223
224         kobject_uevent(&ls->kobj, KOBJ_OFFLINE);
225
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);
232         gdlm_kobject_release(ls);
233 }
234
235 struct lm_lockops gdlm_ops = {
236         .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,
254 };
255