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)
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
114 static 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,
117                         struct lm_lockstruct *lockstruct,
118                         struct kobject *fskobj)
119 {
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) {
137                 log_error("dlm_new_lockspace error %d", error);
138                 goto out_thread;
139         }
140
141         error = gdlm_kobject_setup(ls, fskobj);
142         if (error)
143                 goto out_dlm;
144
145         error = make_args(ls, host_data);
146         if (error)
147                 goto out_sysfs;
148
149         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
169 static 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
176         /* 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))
181                 goto out;
182
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)
188                 log_info("gdlm_unmount: %d stray locks freed", rv);
189  out:
190         kfree(ls);
191 }
192
193 static 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;
197         ls->recover_jid_done = jid;
198         kobject_uevent(&ls->kobj, KOBJ_CHANGE);
199 }
200
201 static 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);
206 }
207
208 /* 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
212 static void gdlm_withdraw(lm_lockspace_t *lockspace)
213 {
214         struct gdlm_ls *ls = (struct gdlm_ls *) lockspace;
215
216         kobject_uevent(&ls->kobj, KOBJ_OFFLINE);
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);
224         gdlm_kobject_release(ls);
225 }
226
227 struct lm_lockops gdlm_ops = {
228         .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,
246 };
247