[GFS2] Check for installation of mount helpers for DLM mounts
[firefly-linux-kernel-4.4.55.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 const struct lm_lockops gdlm_ops;
13
14
15 static struct gdlm_ls *init_gdlm(lm_callback_t cb, struct gfs2_sbd *sdp,
16                                  int flags, char *table_name)
17 {
18         struct gdlm_ls *ls;
19         char buf[256], *p;
20
21         ls = kzalloc(sizeof(struct gdlm_ls), GFP_KERNEL);
22         if (!ls)
23                 return NULL;
24
25         ls->drop_locks_count = GDLM_DROP_COUNT;
26         ls->drop_locks_period = GDLM_DROP_PERIOD;
27         ls->fscb = cb;
28         ls->sdp = sdp;
29         ls->fsflags = flags;
30         spin_lock_init(&ls->async_lock);
31         INIT_LIST_HEAD(&ls->complete);
32         INIT_LIST_HEAD(&ls->blocking);
33         INIT_LIST_HEAD(&ls->delayed);
34         INIT_LIST_HEAD(&ls->submit);
35         INIT_LIST_HEAD(&ls->all_locks);
36         init_waitqueue_head(&ls->thread_wait);
37         init_waitqueue_head(&ls->wait_control);
38         ls->thread1 = NULL;
39         ls->thread2 = NULL;
40         ls->drop_time = jiffies;
41         ls->jid = -1;
42
43         strncpy(buf, table_name, 256);
44         buf[255] = '\0';
45
46         p = strchr(buf, ':');
47         if (!p) {
48                 log_info("invalid table_name \"%s\"", table_name);
49                 kfree(ls);
50                 return NULL;
51         }
52         *p = '\0';
53         p++;
54
55         strncpy(ls->clustername, buf, GDLM_NAME_LEN);
56         strncpy(ls->fsname, p, GDLM_NAME_LEN);
57
58         return ls;
59 }
60
61 static int make_args(struct gdlm_ls *ls, char *data_arg, int *nodir)
62 {
63         char data[256];
64         char *options, *x, *y;
65         int error = 0;
66
67         memset(data, 0, 256);
68         strncpy(data, data_arg, 255);
69
70         if (!strlen(data)) {
71                 printk(KERN_ERR
72                        "DLM/GFS2/GFS ERROR: (u)mount helpers are not installed!\n");
73                 return -EINVAL;
74         }
75
76         for (options = data; (x = strsep(&options, ":")); ) {
77                 if (!*x)
78                         continue;
79
80                 y = strchr(x, '=');
81                 if (y)
82                         *y++ = 0;
83
84                 if (!strcmp(x, "jid")) {
85                         if (!y) {
86                                 log_error("need argument to jid");
87                                 error = -EINVAL;
88                                 break;
89                         }
90                         sscanf(y, "%u", &ls->jid);
91
92                 } else if (!strcmp(x, "first")) {
93                         if (!y) {
94                                 log_error("need argument to first");
95                                 error = -EINVAL;
96                                 break;
97                         }
98                         sscanf(y, "%u", &ls->first);
99
100                 } else if (!strcmp(x, "id")) {
101                         if (!y) {
102                                 log_error("need argument to id");
103                                 error = -EINVAL;
104                                 break;
105                         }
106                         sscanf(y, "%u", &ls->id);
107
108                 } else if (!strcmp(x, "nodir")) {
109                         if (!y) {
110                                 log_error("need argument to nodir");
111                                 error = -EINVAL;
112                                 break;
113                         }
114                         sscanf(y, "%u", nodir);
115
116                 } else {
117                         log_error("unkonwn option: %s", x);
118                         error = -EINVAL;
119                         break;
120                 }
121         }
122
123         return error;
124 }
125
126 static int gdlm_mount(char *table_name, char *host_data,
127                         lm_callback_t cb, void *cb_data,
128                         unsigned int min_lvb_size, int flags,
129                         struct lm_lockstruct *lockstruct,
130                         struct kobject *fskobj)
131 {
132         struct gdlm_ls *ls;
133         int error = -ENOMEM, nodir = 0;
134
135         if (min_lvb_size > GDLM_LVB_SIZE)
136                 goto out;
137
138         ls = init_gdlm(cb, cb_data, flags, table_name);
139         if (!ls)
140                 goto out;
141
142         error = make_args(ls, host_data, &nodir);
143         if (error)
144                 goto out;
145
146         error = gdlm_init_threads(ls);
147         if (error)
148                 goto out_free;
149
150         error = gdlm_kobject_setup(ls, fskobj);
151         if (error)
152                 goto out_thread;
153
154         error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname),
155                                   &ls->dlm_lockspace,
156                                   DLM_LSFL_FS | (nodir ? DLM_LSFL_NODIR : 0),
157                                   GDLM_LVB_SIZE);
158         if (error) {
159                 log_error("dlm_new_lockspace error %d", error);
160                 goto out_kobj;
161         }
162
163         lockstruct->ls_jid = ls->jid;
164         lockstruct->ls_first = ls->first;
165         lockstruct->ls_lockspace = ls;
166         lockstruct->ls_ops = &gdlm_ops;
167         lockstruct->ls_flags = 0;
168         lockstruct->ls_lvb_size = GDLM_LVB_SIZE;
169         return 0;
170
171 out_kobj:
172         gdlm_kobject_release(ls);
173 out_thread:
174         gdlm_release_threads(ls);
175 out_free:
176         kfree(ls);
177 out:
178         return error;
179 }
180
181 static void gdlm_unmount(void *lockspace)
182 {
183         struct gdlm_ls *ls = lockspace;
184         int rv;
185
186         log_debug("unmount flags %lx", ls->flags);
187
188         /* FIXME: serialize unmount and withdraw in case they
189            happen at once.  Also, if unmount follows withdraw,
190            wait for withdraw to finish. */
191
192         if (test_bit(DFL_WITHDRAW, &ls->flags))
193                 goto out;
194
195         gdlm_kobject_release(ls);
196         dlm_release_lockspace(ls->dlm_lockspace, 2);
197         gdlm_release_threads(ls);
198         rv = gdlm_release_all_locks(ls);
199         if (rv)
200                 log_info("gdlm_unmount: %d stray locks freed", rv);
201 out:
202         kfree(ls);
203 }
204
205 static void gdlm_recovery_done(void *lockspace, unsigned int jid,
206                                unsigned int message)
207 {
208         struct gdlm_ls *ls = lockspace;
209         ls->recover_jid_done = jid;
210         ls->recover_jid_status = message;
211         kobject_uevent(&ls->kobj, KOBJ_CHANGE);
212 }
213
214 static void gdlm_others_may_mount(void *lockspace)
215 {
216         struct gdlm_ls *ls = lockspace;
217         ls->first_done = 1;
218         kobject_uevent(&ls->kobj, KOBJ_CHANGE);
219 }
220
221 /* Userspace gets the offline uevent, blocks new gfs locks on
222    other mounters, and lets us know (sets WITHDRAW flag).  Then,
223    userspace leaves the mount group while we leave the lockspace. */
224
225 static void gdlm_withdraw(void *lockspace)
226 {
227         struct gdlm_ls *ls = lockspace;
228
229         kobject_uevent(&ls->kobj, KOBJ_OFFLINE);
230
231         wait_event_interruptible(ls->wait_control,
232                                  test_bit(DFL_WITHDRAW, &ls->flags));
233
234         dlm_release_lockspace(ls->dlm_lockspace, 2);
235         gdlm_release_threads(ls);
236         gdlm_release_all_locks(ls);
237         gdlm_kobject_release(ls);
238 }
239
240 const struct lm_lockops gdlm_ops = {
241         .lm_proto_name = "lock_dlm",
242         .lm_mount = gdlm_mount,
243         .lm_others_may_mount = gdlm_others_may_mount,
244         .lm_unmount = gdlm_unmount,
245         .lm_withdraw = gdlm_withdraw,
246         .lm_get_lock = gdlm_get_lock,
247         .lm_put_lock = gdlm_put_lock,
248         .lm_lock = gdlm_lock,
249         .lm_unlock = gdlm_unlock,
250         .lm_plock = gdlm_plock,
251         .lm_punlock = gdlm_punlock,
252         .lm_plock_get = gdlm_plock_get,
253         .lm_cancel = gdlm_cancel,
254         .lm_hold_lvb = gdlm_hold_lvb,
255         .lm_unhold_lvb = gdlm_unhold_lvb,
256         .lm_recovery_done = gdlm_recovery_done,
257         .lm_owner = THIS_MODULE,
258 };
259