Commit 0f8e0d9a317406612700426fad3efab0b7bbc467
1 parent
4c246edd25
Exists in
master
and in
39 other branches
dlm: allow multiple lockspace creates
Add a count for lockspace create and release so that create can be called multiple times to use the lockspace from different places. Also add the new flag DLM_LSFL_NEWEXCL to create a lockspace with the previous behavior of returning -EEXIST if the lockspace already exists. Signed-off-by: David Teigland <teigland@redhat.com>
Showing 7 changed files with 116 additions and 64 deletions Side-by-side Diff
fs/dlm/dlm_internal.h
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | ******************************************************************************* |
3 | 3 | ** |
4 | 4 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. |
5 | -** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | |
5 | +** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. | |
6 | 6 | ** |
7 | 7 | ** This copyrighted material is made available to anyone wishing to use, |
8 | 8 | ** modify, copy, or redistribute it subject to the terms and conditions |
... | ... | @@ -441,7 +441,9 @@ |
441 | 441 | uint32_t ls_global_id; /* global unique lockspace ID */ |
442 | 442 | uint32_t ls_exflags; |
443 | 443 | int ls_lvblen; |
444 | - int ls_count; /* reference count */ | |
444 | + int ls_count; /* refcount of processes in | |
445 | + the dlm using this ls */ | |
446 | + int ls_create_count; /* create/release refcount */ | |
445 | 447 | unsigned long ls_flags; /* LSFL_ */ |
446 | 448 | struct kobject ls_kobj; |
447 | 449 |
fs/dlm/lockspace.c
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | ******************************************************************************* |
3 | 3 | ** |
4 | 4 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. |
5 | -** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | |
5 | +** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. | |
6 | 6 | ** |
7 | 7 | ** This copyrighted material is made available to anyone wishing to use, |
8 | 8 | ** modify, copy, or redistribute it subject to the terms and conditions |
... | ... | @@ -23,6 +23,7 @@ |
23 | 23 | #include "lock.h" |
24 | 24 | #include "recover.h" |
25 | 25 | #include "requestqueue.h" |
26 | +#include "user.h" | |
26 | 27 | |
27 | 28 | static int ls_count; |
28 | 29 | static struct mutex ls_lock; |
... | ... | @@ -246,23 +247,6 @@ |
246 | 247 | kthread_stop(scand_task); |
247 | 248 | } |
248 | 249 | |
249 | -static struct dlm_ls *dlm_find_lockspace_name(char *name, int namelen) | |
250 | -{ | |
251 | - struct dlm_ls *ls; | |
252 | - | |
253 | - spin_lock(&lslist_lock); | |
254 | - | |
255 | - list_for_each_entry(ls, &lslist, ls_list) { | |
256 | - if (ls->ls_namelen == namelen && | |
257 | - memcmp(ls->ls_name, name, namelen) == 0) | |
258 | - goto out; | |
259 | - } | |
260 | - ls = NULL; | |
261 | - out: | |
262 | - spin_unlock(&lslist_lock); | |
263 | - return ls; | |
264 | -} | |
265 | - | |
266 | 250 | struct dlm_ls *dlm_find_lockspace_global(uint32_t id) |
267 | 251 | { |
268 | 252 | struct dlm_ls *ls; |
... | ... | @@ -327,6 +311,7 @@ |
327 | 311 | for (;;) { |
328 | 312 | spin_lock(&lslist_lock); |
329 | 313 | if (ls->ls_count == 0) { |
314 | + WARN_ON(ls->ls_create_count != 0); | |
330 | 315 | list_del(&ls->ls_list); |
331 | 316 | spin_unlock(&lslist_lock); |
332 | 317 | return; |
... | ... | @@ -381,7 +366,7 @@ |
381 | 366 | uint32_t flags, int lvblen) |
382 | 367 | { |
383 | 368 | struct dlm_ls *ls; |
384 | - int i, size, error = -ENOMEM; | |
369 | + int i, size, error; | |
385 | 370 | int do_unreg = 0; |
386 | 371 | |
387 | 372 | if (namelen > DLM_LOCKSPACE_LEN) |
388 | 373 | |
389 | 374 | |
390 | 375 | |
... | ... | @@ -393,13 +378,33 @@ |
393 | 378 | if (!try_module_get(THIS_MODULE)) |
394 | 379 | return -EINVAL; |
395 | 380 | |
396 | - ls = dlm_find_lockspace_name(name, namelen); | |
397 | - if (ls) { | |
398 | - *lockspace = ls; | |
381 | + error = 0; | |
382 | + | |
383 | + spin_lock(&lslist_lock); | |
384 | + list_for_each_entry(ls, &lslist, ls_list) { | |
385 | + WARN_ON(ls->ls_create_count <= 0); | |
386 | + if (ls->ls_namelen != namelen) | |
387 | + continue; | |
388 | + if (memcmp(ls->ls_name, name, namelen)) | |
389 | + continue; | |
390 | + if (flags & DLM_LSFL_NEWEXCL) { | |
391 | + error = -EEXIST; | |
392 | + break; | |
393 | + } | |
394 | + ls->ls_create_count++; | |
399 | 395 | module_put(THIS_MODULE); |
400 | - return -EEXIST; | |
396 | + error = 1; /* not an error, return 0 */ | |
397 | + break; | |
401 | 398 | } |
399 | + spin_unlock(&lslist_lock); | |
402 | 400 | |
401 | + if (error < 0) | |
402 | + goto out; | |
403 | + if (error) | |
404 | + goto ret_zero; | |
405 | + | |
406 | + error = -ENOMEM; | |
407 | + | |
403 | 408 | ls = kzalloc(sizeof(struct dlm_ls) + namelen, GFP_KERNEL); |
404 | 409 | if (!ls) |
405 | 410 | goto out; |
... | ... | @@ -418,8 +423,9 @@ |
418 | 423 | ls->ls_allocation = GFP_KERNEL; |
419 | 424 | |
420 | 425 | /* ls_exflags are forced to match among nodes, and we don't |
421 | - need to require all nodes to have TIMEWARN or FS set */ | |
422 | - ls->ls_exflags = (flags & ~(DLM_LSFL_TIMEWARN | DLM_LSFL_FS)); | |
426 | + need to require all nodes to have some flags set */ | |
427 | + ls->ls_exflags = (flags & ~(DLM_LSFL_TIMEWARN | DLM_LSFL_FS | | |
428 | + DLM_LSFL_NEWEXCL)); | |
423 | 429 | |
424 | 430 | size = dlm_config.ci_rsbtbl_size; |
425 | 431 | ls->ls_rsbtbl_size = size; |
... | ... | @@ -510,6 +516,7 @@ |
510 | 516 | down_write(&ls->ls_in_recovery); |
511 | 517 | |
512 | 518 | spin_lock(&lslist_lock); |
519 | + ls->ls_create_count = 1; | |
513 | 520 | list_add(&ls->ls_list, &lslist); |
514 | 521 | spin_unlock(&lslist_lock); |
515 | 522 | |
... | ... | @@ -548,7 +555,7 @@ |
548 | 555 | dlm_create_debug_file(ls); |
549 | 556 | |
550 | 557 | log_debug(ls, "join complete"); |
551 | - | |
558 | + ret_zero: | |
552 | 559 | *lockspace = ls; |
553 | 560 | return 0; |
554 | 561 | |
555 | 562 | |
556 | 563 | |
... | ... | @@ -635,12 +642,33 @@ |
635 | 642 | struct dlm_lkb *lkb; |
636 | 643 | struct dlm_rsb *rsb; |
637 | 644 | struct list_head *head; |
638 | - int i; | |
639 | - int busy = lockspace_busy(ls); | |
645 | + int i, busy, rv; | |
640 | 646 | |
641 | - if (busy > force) | |
642 | - return -EBUSY; | |
647 | + busy = lockspace_busy(ls); | |
643 | 648 | |
649 | + spin_lock(&lslist_lock); | |
650 | + if (ls->ls_create_count == 1) { | |
651 | + if (busy > force) | |
652 | + rv = -EBUSY; | |
653 | + else { | |
654 | + /* remove_lockspace takes ls off lslist */ | |
655 | + ls->ls_create_count = 0; | |
656 | + rv = 0; | |
657 | + } | |
658 | + } else if (ls->ls_create_count > 1) { | |
659 | + rv = --ls->ls_create_count; | |
660 | + } else { | |
661 | + rv = -EINVAL; | |
662 | + } | |
663 | + spin_unlock(&lslist_lock); | |
664 | + | |
665 | + if (rv) { | |
666 | + log_debug(ls, "release_lockspace no remove %d", rv); | |
667 | + return rv; | |
668 | + } | |
669 | + | |
670 | + dlm_device_deregister(ls); | |
671 | + | |
644 | 672 | if (force < 3) |
645 | 673 | do_uevent(ls, 0); |
646 | 674 | |
647 | 675 | |
... | ... | @@ -720,15 +748,10 @@ |
720 | 748 | dlm_clear_members(ls); |
721 | 749 | dlm_clear_members_gone(ls); |
722 | 750 | kfree(ls->ls_node_array); |
751 | + log_debug(ls, "release_lockspace final free"); | |
723 | 752 | kobject_put(&ls->ls_kobj); |
724 | 753 | /* The ls structure will be freed when the kobject is done with */ |
725 | 754 | |
726 | - mutex_lock(&ls_lock); | |
727 | - ls_count--; | |
728 | - if (!ls_count) | |
729 | - threads_stop(); | |
730 | - mutex_unlock(&ls_lock); | |
731 | - | |
732 | 755 | module_put(THIS_MODULE); |
733 | 756 | return 0; |
734 | 757 | } |
735 | 758 | |
... | ... | @@ -750,11 +773,21 @@ |
750 | 773 | int dlm_release_lockspace(void *lockspace, int force) |
751 | 774 | { |
752 | 775 | struct dlm_ls *ls; |
776 | + int error; | |
753 | 777 | |
754 | 778 | ls = dlm_find_lockspace_local(lockspace); |
755 | 779 | if (!ls) |
756 | 780 | return -EINVAL; |
757 | 781 | dlm_put_lockspace(ls); |
758 | - return release_lockspace(ls, force); | |
782 | + | |
783 | + mutex_lock(&ls_lock); | |
784 | + error = release_lockspace(ls, force); | |
785 | + if (!error) | |
786 | + ls_count--; | |
787 | + else if (!ls_count) | |
788 | + threads_stop(); | |
789 | + mutex_unlock(&ls_lock); | |
790 | + | |
791 | + return error; | |
759 | 792 | } |
fs/dlm/user.c
1 | 1 | /* |
2 | - * Copyright (C) 2006-2007 Red Hat, Inc. All rights reserved. | |
2 | + * Copyright (C) 2006-2008 Red Hat, Inc. All rights reserved. | |
3 | 3 | * |
4 | 4 | * This copyrighted material is made available to anyone wishing to use, |
5 | 5 | * modify, copy, or redistribute it subject to the terms and conditions |
6 | 6 | |
... | ... | @@ -340,10 +340,15 @@ |
340 | 340 | return error; |
341 | 341 | } |
342 | 342 | |
343 | -static int create_misc_device(struct dlm_ls *ls, char *name) | |
343 | +static int dlm_device_register(struct dlm_ls *ls, char *name) | |
344 | 344 | { |
345 | 345 | int error, len; |
346 | 346 | |
347 | + /* The device is already registered. This happens when the | |
348 | + lockspace is created multiple times from userspace. */ | |
349 | + if (ls->ls_device.name) | |
350 | + return 0; | |
351 | + | |
347 | 352 | error = -ENOMEM; |
348 | 353 | len = strlen(name) + strlen(name_prefix) + 2; |
349 | 354 | ls->ls_device.name = kzalloc(len, GFP_KERNEL); |
... | ... | @@ -363,6 +368,22 @@ |
363 | 368 | return error; |
364 | 369 | } |
365 | 370 | |
371 | +int dlm_device_deregister(struct dlm_ls *ls) | |
372 | +{ | |
373 | + int error; | |
374 | + | |
375 | + /* The device is not registered. This happens when the lockspace | |
376 | + was never used from userspace, or when device_create_lockspace() | |
377 | + calls dlm_release_lockspace() after the register fails. */ | |
378 | + if (!ls->ls_device.name) | |
379 | + return 0; | |
380 | + | |
381 | + error = misc_deregister(&ls->ls_device); | |
382 | + if (!error) | |
383 | + kfree(ls->ls_device.name); | |
384 | + return error; | |
385 | +} | |
386 | + | |
366 | 387 | static int device_user_purge(struct dlm_user_proc *proc, |
367 | 388 | struct dlm_purge_params *params) |
368 | 389 | { |
... | ... | @@ -397,7 +418,7 @@ |
397 | 418 | if (!ls) |
398 | 419 | return -ENOENT; |
399 | 420 | |
400 | - error = create_misc_device(ls, params->name); | |
421 | + error = dlm_device_register(ls, params->name); | |
401 | 422 | dlm_put_lockspace(ls); |
402 | 423 | |
403 | 424 | if (error) |
404 | 425 | |
405 | 426 | |
406 | 427 | |
407 | 428 | |
... | ... | @@ -421,31 +442,22 @@ |
421 | 442 | if (!ls) |
422 | 443 | return -ENOENT; |
423 | 444 | |
424 | - /* Deregister the misc device first, so we don't have | |
425 | - * a device that's not attached to a lockspace. If | |
426 | - * dlm_release_lockspace fails then we can recreate it | |
427 | - */ | |
428 | - error = misc_deregister(&ls->ls_device); | |
429 | - if (error) { | |
430 | - dlm_put_lockspace(ls); | |
431 | - goto out; | |
432 | - } | |
433 | - kfree(ls->ls_device.name); | |
434 | - | |
435 | 445 | if (params->flags & DLM_USER_LSFLG_FORCEFREE) |
436 | 446 | force = 2; |
437 | 447 | |
438 | 448 | lockspace = ls->ls_local_handle; |
449 | + dlm_put_lockspace(ls); | |
439 | 450 | |
440 | - /* dlm_release_lockspace waits for references to go to zero, | |
441 | - so all processes will need to close their device for the ls | |
442 | - before the release will procede */ | |
451 | + /* The final dlm_release_lockspace waits for references to go to | |
452 | + zero, so all processes will need to close their device for the | |
453 | + ls before the release will proceed. release also calls the | |
454 | + device_deregister above. Converting a positive return value | |
455 | + from release to zero means that userspace won't know when its | |
456 | + release was the final one, but it shouldn't need to know. */ | |
443 | 457 | |
444 | - dlm_put_lockspace(ls); | |
445 | 458 | error = dlm_release_lockspace(lockspace, force); |
446 | - if (error) | |
447 | - create_misc_device(ls, ls->ls_name); | |
448 | - out: | |
459 | + if (error > 0) | |
460 | + error = 0; | |
449 | 461 | return error; |
450 | 462 | } |
451 | 463 |
fs/dlm/user.h
1 | 1 | /* |
2 | - * Copyright (C) 2006 Red Hat, Inc. All rights reserved. | |
2 | + * Copyright (C) 2006-2008 Red Hat, Inc. All rights reserved. | |
3 | 3 | * |
4 | 4 | * This copyrighted material is made available to anyone wishing to use, |
5 | 5 | * modify, copy, or redistribute it subject to the terms and conditions |
... | ... | @@ -12,6 +12,7 @@ |
12 | 12 | void dlm_user_add_ast(struct dlm_lkb *lkb, int type); |
13 | 13 | int dlm_user_init(void); |
14 | 14 | void dlm_user_exit(void); |
15 | +int dlm_device_deregister(struct dlm_ls *ls); | |
15 | 16 | |
16 | 17 | #endif |
fs/gfs2/locking/dlm/mount.c
... | ... | @@ -144,7 +144,8 @@ |
144 | 144 | |
145 | 145 | error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname), |
146 | 146 | &ls->dlm_lockspace, |
147 | - DLM_LSFL_FS | (nodir ? DLM_LSFL_NODIR : 0), | |
147 | + DLM_LSFL_FS | DLM_LSFL_NEWEXCL | | |
148 | + (nodir ? DLM_LSFL_NODIR : 0), | |
148 | 149 | GDLM_LVB_SIZE); |
149 | 150 | if (error) { |
150 | 151 | log_error("dlm_new_lockspace error %d", error); |
include/linux/dlm.h
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | ******************************************************************************* |
3 | 3 | ** |
4 | 4 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. |
5 | -** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | |
5 | +** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. | |
6 | 6 | ** |
7 | 7 | ** This copyrighted material is made available to anyone wishing to use, |
8 | 8 | ** modify, copy, or redistribute it subject to the terms and conditions |
9 | 9 | |
... | ... | @@ -65,9 +65,12 @@ |
65 | 65 | char * sb_lvbptr; |
66 | 66 | }; |
67 | 67 | |
68 | +/* dlm_new_lockspace() flags */ | |
69 | + | |
68 | 70 | #define DLM_LSFL_NODIR 0x00000001 |
69 | 71 | #define DLM_LSFL_TIMEWARN 0x00000002 |
70 | 72 | #define DLM_LSFL_FS 0x00000004 |
73 | +#define DLM_LSFL_NEWEXCL 0x00000008 | |
71 | 74 | |
72 | 75 | #ifdef __KERNEL__ |
73 | 76 |
include/linux/dlm_device.h
... | ... | @@ -26,7 +26,7 @@ |
26 | 26 | /* Version of the device interface */ |
27 | 27 | #define DLM_DEVICE_VERSION_MAJOR 6 |
28 | 28 | #define DLM_DEVICE_VERSION_MINOR 0 |
29 | -#define DLM_DEVICE_VERSION_PATCH 0 | |
29 | +#define DLM_DEVICE_VERSION_PATCH 1 | |
30 | 30 | |
31 | 31 | /* struct passed to the lock write */ |
32 | 32 | struct dlm_lock_params { |