]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: David Teigland <teigland@redhat.com> |
2 | Subject: [PATCH] dlm: allow multiple lockspace creates | |
3 | Patch-mainline: 2.6.28? | |
4 | References: FATE110294 | |
5 | ||
6 | Add a count for lockspace create and release so that create can | |
7 | be called multiple times to use the lockspace from different places. | |
8 | Also add the new flag DLM_LSFL_NEWEXCL to create a lockspace with | |
9 | the previous behavior of returning -EEXIST if the lockspace already | |
10 | exists. | |
11 | ||
12 | Signed-off-by: David Teigland <teigland@redhat.com> | |
13 | Acked-by: Mark Fasheh <mfasheh@suse.com> | |
14 | --- | |
15 | fs/dlm/dlm_internal.h | 6 ++- | |
16 | fs/dlm/lockspace.c | 107 ++++++++++++++++++++++++++++--------------- | |
17 | fs/dlm/user.c | 54 +++++++++++++-------- | |
18 | fs/dlm/user.h | 3 +- | |
19 | fs/gfs2/locking/dlm/mount.c | 3 +- | |
20 | include/linux/dlm.h | 5 ++- | |
21 | include/linux/dlm_device.h | 2 +- | |
22 | 7 files changed, 116 insertions(+), 64 deletions(-) | |
23 | ||
24 | diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h | |
25 | index 5a7ac33..9e0622a 100644 | |
26 | --- a/fs/dlm/dlm_internal.h | |
27 | +++ b/fs/dlm/dlm_internal.h | |
28 | @@ -2,7 +2,7 @@ | |
29 | ******************************************************************************* | |
30 | ** | |
31 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | |
32 | -** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | |
33 | +** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. | |
34 | ** | |
35 | ** This copyrighted material is made available to anyone wishing to use, | |
36 | ** modify, copy, or redistribute it subject to the terms and conditions | |
37 | @@ -441,7 +441,9 @@ struct dlm_ls { | |
38 | uint32_t ls_global_id; /* global unique lockspace ID */ | |
39 | uint32_t ls_exflags; | |
40 | int ls_lvblen; | |
41 | - int ls_count; /* reference count */ | |
42 | + int ls_count; /* refcount of processes in | |
43 | + the dlm using this ls */ | |
44 | + int ls_create_count; /* create/release refcount */ | |
45 | unsigned long ls_flags; /* LSFL_ */ | |
46 | struct kobject ls_kobj; | |
47 | ||
48 | diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c | |
49 | index 499e167..56eae4e 100644 | |
50 | --- a/fs/dlm/lockspace.c | |
51 | +++ b/fs/dlm/lockspace.c | |
52 | @@ -2,7 +2,7 @@ | |
53 | ******************************************************************************* | |
54 | ** | |
55 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | |
56 | -** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | |
57 | +** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. | |
58 | ** | |
59 | ** This copyrighted material is made available to anyone wishing to use, | |
60 | ** modify, copy, or redistribute it subject to the terms and conditions | |
61 | @@ -23,6 +23,7 @@ | |
62 | #include "lock.h" | |
63 | #include "recover.h" | |
64 | #include "requestqueue.h" | |
65 | +#include "user.h" | |
66 | ||
67 | static int ls_count; | |
68 | static struct mutex ls_lock; | |
69 | @@ -246,23 +247,6 @@ static void dlm_scand_stop(void) | |
70 | kthread_stop(scand_task); | |
71 | } | |
72 | ||
73 | -static struct dlm_ls *dlm_find_lockspace_name(char *name, int namelen) | |
74 | -{ | |
75 | - struct dlm_ls *ls; | |
76 | - | |
77 | - spin_lock(&lslist_lock); | |
78 | - | |
79 | - list_for_each_entry(ls, &lslist, ls_list) { | |
80 | - if (ls->ls_namelen == namelen && | |
81 | - memcmp(ls->ls_name, name, namelen) == 0) | |
82 | - goto out; | |
83 | - } | |
84 | - ls = NULL; | |
85 | - out: | |
86 | - spin_unlock(&lslist_lock); | |
87 | - return ls; | |
88 | -} | |
89 | - | |
90 | struct dlm_ls *dlm_find_lockspace_global(uint32_t id) | |
91 | { | |
92 | struct dlm_ls *ls; | |
93 | @@ -327,6 +311,7 @@ static void remove_lockspace(struct dlm_ls *ls) | |
94 | for (;;) { | |
95 | spin_lock(&lslist_lock); | |
96 | if (ls->ls_count == 0) { | |
97 | + WARN_ON(ls->ls_create_count != 0); | |
98 | list_del(&ls->ls_list); | |
99 | spin_unlock(&lslist_lock); | |
100 | return; | |
101 | @@ -381,7 +366,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, | |
102 | uint32_t flags, int lvblen) | |
103 | { | |
104 | struct dlm_ls *ls; | |
105 | - int i, size, error = -ENOMEM; | |
106 | + int i, size, error; | |
107 | int do_unreg = 0; | |
108 | ||
109 | if (namelen > DLM_LOCKSPACE_LEN) | |
110 | @@ -393,12 +378,32 @@ static int new_lockspace(char *name, int namelen, void **lockspace, | |
111 | if (!try_module_get(THIS_MODULE)) | |
112 | return -EINVAL; | |
113 | ||
114 | - ls = dlm_find_lockspace_name(name, namelen); | |
115 | - if (ls) { | |
116 | - *lockspace = ls; | |
117 | + error = 0; | |
118 | + | |
119 | + spin_lock(&lslist_lock); | |
120 | + list_for_each_entry(ls, &lslist, ls_list) { | |
121 | + WARN_ON(ls->ls_create_count <= 0); | |
122 | + if (ls->ls_namelen != namelen) | |
123 | + continue; | |
124 | + if (memcmp(ls->ls_name, name, namelen)) | |
125 | + continue; | |
126 | + if (flags & DLM_LSFL_NEWEXCL) { | |
127 | + error = -EEXIST; | |
128 | + break; | |
129 | + } | |
130 | + ls->ls_create_count++; | |
131 | module_put(THIS_MODULE); | |
132 | - return -EEXIST; | |
133 | + error = 1; /* not an error, return 0 */ | |
134 | + break; | |
135 | } | |
136 | + spin_unlock(&lslist_lock); | |
137 | + | |
138 | + if (error < 0) | |
139 | + goto out; | |
140 | + if (error) | |
141 | + goto ret_zero; | |
142 | + | |
143 | + error = -ENOMEM; | |
144 | ||
145 | ls = kzalloc(sizeof(struct dlm_ls) + namelen, GFP_KERNEL); | |
146 | if (!ls) | |
147 | @@ -418,8 +423,9 @@ static int new_lockspace(char *name, int namelen, void **lockspace, | |
148 | ls->ls_allocation = GFP_KERNEL; | |
149 | ||
150 | /* ls_exflags are forced to match among nodes, and we don't | |
151 | - need to require all nodes to have TIMEWARN or FS set */ | |
152 | - ls->ls_exflags = (flags & ~(DLM_LSFL_TIMEWARN | DLM_LSFL_FS)); | |
153 | + need to require all nodes to have some flags set */ | |
154 | + ls->ls_exflags = (flags & ~(DLM_LSFL_TIMEWARN | DLM_LSFL_FS | | |
155 | + DLM_LSFL_NEWEXCL)); | |
156 | ||
157 | size = dlm_config.ci_rsbtbl_size; | |
158 | ls->ls_rsbtbl_size = size; | |
159 | @@ -510,6 +516,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, | |
160 | down_write(&ls->ls_in_recovery); | |
161 | ||
162 | spin_lock(&lslist_lock); | |
163 | + ls->ls_create_count = 1; | |
164 | list_add(&ls->ls_list, &lslist); | |
165 | spin_unlock(&lslist_lock); | |
166 | ||
167 | @@ -548,7 +555,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, | |
168 | dlm_create_debug_file(ls); | |
169 | ||
170 | log_debug(ls, "join complete"); | |
171 | - | |
172 | + ret_zero: | |
173 | *lockspace = ls; | |
174 | return 0; | |
175 | ||
176 | @@ -635,11 +642,32 @@ static int release_lockspace(struct dlm_ls *ls, int force) | |
177 | struct dlm_lkb *lkb; | |
178 | struct dlm_rsb *rsb; | |
179 | struct list_head *head; | |
180 | - int i; | |
181 | - int busy = lockspace_busy(ls); | |
182 | + int i, busy, rv; | |
183 | + | |
184 | + busy = lockspace_busy(ls); | |
185 | + | |
186 | + spin_lock(&lslist_lock); | |
187 | + if (ls->ls_create_count == 1) { | |
188 | + if (busy > force) | |
189 | + rv = -EBUSY; | |
190 | + else { | |
191 | + /* remove_lockspace takes ls off lslist */ | |
192 | + ls->ls_create_count = 0; | |
193 | + rv = 0; | |
194 | + } | |
195 | + } else if (ls->ls_create_count > 1) { | |
196 | + rv = --ls->ls_create_count; | |
197 | + } else { | |
198 | + rv = -EINVAL; | |
199 | + } | |
200 | + spin_unlock(&lslist_lock); | |
201 | + | |
202 | + if (rv) { | |
203 | + log_debug(ls, "release_lockspace no remove %d", rv); | |
204 | + return rv; | |
205 | + } | |
206 | ||
207 | - if (busy > force) | |
208 | - return -EBUSY; | |
209 | + dlm_device_deregister(ls); | |
210 | ||
211 | if (force < 3) | |
212 | do_uevent(ls, 0); | |
213 | @@ -720,15 +748,10 @@ static int release_lockspace(struct dlm_ls *ls, int force) | |
214 | dlm_clear_members(ls); | |
215 | dlm_clear_members_gone(ls); | |
216 | kfree(ls->ls_node_array); | |
217 | + log_debug(ls, "release_lockspace final free"); | |
218 | kobject_put(&ls->ls_kobj); | |
219 | /* The ls structure will be freed when the kobject is done with */ | |
220 | ||
221 | - mutex_lock(&ls_lock); | |
222 | - ls_count--; | |
223 | - if (!ls_count) | |
224 | - threads_stop(); | |
225 | - mutex_unlock(&ls_lock); | |
226 | - | |
227 | module_put(THIS_MODULE); | |
228 | return 0; | |
229 | } | |
230 | @@ -750,11 +773,21 @@ static int release_lockspace(struct dlm_ls *ls, int force) | |
231 | int dlm_release_lockspace(void *lockspace, int force) | |
232 | { | |
233 | struct dlm_ls *ls; | |
234 | + int error; | |
235 | ||
236 | ls = dlm_find_lockspace_local(lockspace); | |
237 | if (!ls) | |
238 | return -EINVAL; | |
239 | dlm_put_lockspace(ls); | |
240 | - return release_lockspace(ls, force); | |
241 | + | |
242 | + mutex_lock(&ls_lock); | |
243 | + error = release_lockspace(ls, force); | |
244 | + if (!error) | |
245 | + ls_count--; | |
246 | + else if (!ls_count) | |
247 | + threads_stop(); | |
248 | + mutex_unlock(&ls_lock); | |
249 | + | |
250 | + return error; | |
251 | } | |
252 | ||
253 | diff --git a/fs/dlm/user.c b/fs/dlm/user.c | |
254 | index 34f14a1..6542110 100644 | |
255 | --- a/fs/dlm/user.c | |
256 | +++ b/fs/dlm/user.c | |
257 | @@ -1,5 +1,5 @@ | |
258 | /* | |
259 | - * Copyright (C) 2006-2007 Red Hat, Inc. All rights reserved. | |
260 | + * Copyright (C) 2006-2008 Red Hat, Inc. All rights reserved. | |
261 | * | |
262 | * This copyrighted material is made available to anyone wishing to use, | |
263 | * modify, copy, or redistribute it subject to the terms and conditions | |
264 | @@ -340,10 +340,15 @@ static int device_user_deadlock(struct dlm_user_proc *proc, | |
265 | return error; | |
266 | } | |
267 | ||
268 | -static int create_misc_device(struct dlm_ls *ls, char *name) | |
269 | +static int dlm_device_register(struct dlm_ls *ls, char *name) | |
270 | { | |
271 | int error, len; | |
272 | ||
273 | + /* The device is already registered. This happens when the | |
274 | + lockspace is created multiple times from userspace. */ | |
275 | + if (ls->ls_device.name) | |
276 | + return 0; | |
277 | + | |
278 | error = -ENOMEM; | |
279 | len = strlen(name) + strlen(name_prefix) + 2; | |
280 | ls->ls_device.name = kzalloc(len, GFP_KERNEL); | |
281 | @@ -363,6 +368,22 @@ fail: | |
282 | return error; | |
283 | } | |
284 | ||
285 | +int dlm_device_deregister(struct dlm_ls *ls) | |
286 | +{ | |
287 | + int error; | |
288 | + | |
289 | + /* The device is not registered. This happens when the lockspace | |
290 | + was never used from userspace, or when device_create_lockspace() | |
291 | + calls dlm_release_lockspace() after the register fails. */ | |
292 | + if (!ls->ls_device.name) | |
293 | + return 0; | |
294 | + | |
295 | + error = misc_deregister(&ls->ls_device); | |
296 | + if (!error) | |
297 | + kfree(ls->ls_device.name); | |
298 | + return error; | |
299 | +} | |
300 | + | |
301 | static int device_user_purge(struct dlm_user_proc *proc, | |
302 | struct dlm_purge_params *params) | |
303 | { | |
304 | @@ -397,7 +418,7 @@ static int device_create_lockspace(struct dlm_lspace_params *params) | |
305 | if (!ls) | |
306 | return -ENOENT; | |
307 | ||
308 | - error = create_misc_device(ls, params->name); | |
309 | + error = dlm_device_register(ls, params->name); | |
310 | dlm_put_lockspace(ls); | |
311 | ||
312 | if (error) | |
313 | @@ -421,31 +442,22 @@ static int device_remove_lockspace(struct dlm_lspace_params *params) | |
314 | if (!ls) | |
315 | return -ENOENT; | |
316 | ||
317 | - /* Deregister the misc device first, so we don't have | |
318 | - * a device that's not attached to a lockspace. If | |
319 | - * dlm_release_lockspace fails then we can recreate it | |
320 | - */ | |
321 | - error = misc_deregister(&ls->ls_device); | |
322 | - if (error) { | |
323 | - dlm_put_lockspace(ls); | |
324 | - goto out; | |
325 | - } | |
326 | - kfree(ls->ls_device.name); | |
327 | - | |
328 | if (params->flags & DLM_USER_LSFLG_FORCEFREE) | |
329 | force = 2; | |
330 | ||
331 | lockspace = ls->ls_local_handle; | |
332 | + dlm_put_lockspace(ls); | |
333 | ||
334 | - /* dlm_release_lockspace waits for references to go to zero, | |
335 | - so all processes will need to close their device for the ls | |
336 | - before the release will procede */ | |
337 | + /* The final dlm_release_lockspace waits for references to go to | |
338 | + zero, so all processes will need to close their device for the | |
339 | + ls before the release will proceed. release also calls the | |
340 | + device_deregister above. Converting a positive return value | |
341 | + from release to zero means that userspace won't know when its | |
342 | + release was the final one, but it shouldn't need to know. */ | |
343 | ||
344 | - dlm_put_lockspace(ls); | |
345 | error = dlm_release_lockspace(lockspace, force); | |
346 | - if (error) | |
347 | - create_misc_device(ls, ls->ls_name); | |
348 | - out: | |
349 | + if (error > 0) | |
350 | + error = 0; | |
351 | return error; | |
352 | } | |
353 | ||
354 | diff --git a/fs/dlm/user.h b/fs/dlm/user.h | |
355 | index d38e9f3..c528b6b 100644 | |
356 | --- a/fs/dlm/user.h | |
357 | +++ b/fs/dlm/user.h | |
358 | @@ -1,5 +1,5 @@ | |
359 | /* | |
360 | - * Copyright (C) 2006 Red Hat, Inc. All rights reserved. | |
361 | + * Copyright (C) 2006-2008 Red Hat, Inc. All rights reserved. | |
362 | * | |
363 | * This copyrighted material is made available to anyone wishing to use, | |
364 | * modify, copy, or redistribute it subject to the terms and conditions | |
365 | @@ -12,5 +12,6 @@ | |
366 | void dlm_user_add_ast(struct dlm_lkb *lkb, int type); | |
367 | int dlm_user_init(void); | |
368 | void dlm_user_exit(void); | |
369 | +int dlm_device_deregister(struct dlm_ls *ls); | |
370 | ||
371 | #endif | |
372 | diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c | |
373 | index 09d78c2..0c4cbe6 100644 | |
374 | --- a/fs/gfs2/locking/dlm/mount.c | |
375 | +++ b/fs/gfs2/locking/dlm/mount.c | |
376 | @@ -144,7 +144,8 @@ static int gdlm_mount(char *table_name, char *host_data, | |
377 | ||
378 | error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname), | |
379 | &ls->dlm_lockspace, | |
380 | - DLM_LSFL_FS | (nodir ? DLM_LSFL_NODIR : 0), | |
381 | + DLM_LSFL_FS | DLM_LSFL_NEWEXCL | | |
382 | + (nodir ? DLM_LSFL_NODIR : 0), | |
383 | GDLM_LVB_SIZE); | |
384 | if (error) { | |
385 | log_error("dlm_new_lockspace error %d", error); | |
386 | diff --git a/include/linux/dlm.h b/include/linux/dlm.h | |
387 | index 203a025..b9cd386 100644 | |
388 | --- a/include/linux/dlm.h | |
389 | +++ b/include/linux/dlm.h | |
390 | @@ -2,7 +2,7 @@ | |
391 | ******************************************************************************* | |
392 | ** | |
393 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | |
394 | -** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | |
395 | +** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. | |
396 | ** | |
397 | ** This copyrighted material is made available to anyone wishing to use, | |
398 | ** modify, copy, or redistribute it subject to the terms and conditions | |
399 | @@ -65,9 +65,12 @@ struct dlm_lksb { | |
400 | char * sb_lvbptr; | |
401 | }; | |
402 | ||
403 | +/* dlm_new_lockspace() flags */ | |
404 | + | |
405 | #define DLM_LSFL_NODIR 0x00000001 | |
406 | #define DLM_LSFL_TIMEWARN 0x00000002 | |
407 | #define DLM_LSFL_FS 0x00000004 | |
408 | +#define DLM_LSFL_NEWEXCL 0x00000008 | |
409 | ||
410 | #ifdef __KERNEL__ | |
411 | ||
412 | diff --git a/include/linux/dlm_device.h b/include/linux/dlm_device.h | |
413 | index c603450..3060783 100644 | |
414 | --- a/include/linux/dlm_device.h | |
415 | +++ b/include/linux/dlm_device.h | |
416 | @@ -26,7 +26,7 @@ | |
417 | /* Version of the device interface */ | |
418 | #define DLM_DEVICE_VERSION_MAJOR 6 | |
419 | #define DLM_DEVICE_VERSION_MINOR 0 | |
420 | -#define DLM_DEVICE_VERSION_PATCH 0 | |
421 | +#define DLM_DEVICE_VERSION_PATCH 1 | |
422 | ||
423 | /* struct passed to the lock write */ | |
424 | struct dlm_lock_params { | |
425 | -- | |
426 | 1.5.4.5 | |
427 |