[GFS2] Update copyright, tidy up incore.h
[pandora-kernel.git] / 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 version 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 = gdlm_kobject_setup(ls, fskobj);
147         if (error)
148                 goto out_thread;
149
150         error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname),
151                                   &ls->dlm_lockspace,
152                                   nodir ? DLM_LSFL_NODIR : 0,
153                                   GDLM_LVB_SIZE);
154         if (error) {
155                 log_error("dlm_new_lockspace error %d", error);
156                 goto out_kobj;
157         }
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_kobj:
168         gdlm_kobject_release(ls);
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         ls->recover_jid_status = message;
207         kobject_uevent(&ls->kobj, KOBJ_CHANGE);
208 }
209
210 static void gdlm_others_may_mount(lm_lockspace_t *lockspace)
211 {
212         struct gdlm_ls *ls = (struct gdlm_ls *) lockspace;
213         ls->first_done = 1;
214         kobject_uevent(&ls->kobj, KOBJ_CHANGE);
215 }
216
217 /* 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
221 static void gdlm_withdraw(lm_lockspace_t *lockspace)
222 {
223         struct gdlm_ls *ls = (struct gdlm_ls *) lockspace;
224
225         kobject_uevent(&ls->kobj, KOBJ_OFFLINE);
226
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);
233         gdlm_kobject_release(ls);
234 }
235
236 struct lm_lockops gdlm_ops = {
237         .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,
255 };
256