diff options
Diffstat (limited to 'fs/dlm/lockspace.c')
-rw-r--r-- | fs/dlm/lockspace.c | 107 |
1 files changed, 70 insertions, 37 deletions
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 499e16759e96..56eae4e4a954 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c | |||
@@ -2,7 +2,7 @@ | |||
2 | ******************************************************************************* | 2 | ******************************************************************************* |
3 | ** | 3 | ** |
4 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | 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 | ** This copyrighted material is made available to anyone wishing to use, | 7 | ** This copyrighted material is made available to anyone wishing to use, |
8 | ** modify, copy, or redistribute it subject to the terms and conditions | 8 | ** modify, copy, or redistribute it subject to the terms and conditions |
@@ -23,6 +23,7 @@ | |||
23 | #include "lock.h" | 23 | #include "lock.h" |
24 | #include "recover.h" | 24 | #include "recover.h" |
25 | #include "requestqueue.h" | 25 | #include "requestqueue.h" |
26 | #include "user.h" | ||
26 | 27 | ||
27 | static int ls_count; | 28 | static int ls_count; |
28 | static struct mutex ls_lock; | 29 | static struct mutex ls_lock; |
@@ -246,23 +247,6 @@ static void dlm_scand_stop(void) | |||
246 | kthread_stop(scand_task); | 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 | struct dlm_ls *dlm_find_lockspace_global(uint32_t id) | 250 | struct dlm_ls *dlm_find_lockspace_global(uint32_t id) |
267 | { | 251 | { |
268 | struct dlm_ls *ls; | 252 | struct dlm_ls *ls; |
@@ -327,6 +311,7 @@ static void remove_lockspace(struct dlm_ls *ls) | |||
327 | for (;;) { | 311 | for (;;) { |
328 | spin_lock(&lslist_lock); | 312 | spin_lock(&lslist_lock); |
329 | if (ls->ls_count == 0) { | 313 | if (ls->ls_count == 0) { |
314 | WARN_ON(ls->ls_create_count != 0); | ||
330 | list_del(&ls->ls_list); | 315 | list_del(&ls->ls_list); |
331 | spin_unlock(&lslist_lock); | 316 | spin_unlock(&lslist_lock); |
332 | return; | 317 | return; |
@@ -381,7 +366,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, | |||
381 | uint32_t flags, int lvblen) | 366 | uint32_t flags, int lvblen) |
382 | { | 367 | { |
383 | struct dlm_ls *ls; | 368 | struct dlm_ls *ls; |
384 | int i, size, error = -ENOMEM; | 369 | int i, size, error; |
385 | int do_unreg = 0; | 370 | int do_unreg = 0; |
386 | 371 | ||
387 | if (namelen > DLM_LOCKSPACE_LEN) | 372 | if (namelen > DLM_LOCKSPACE_LEN) |
@@ -393,12 +378,32 @@ static int new_lockspace(char *name, int namelen, void **lockspace, | |||
393 | if (!try_module_get(THIS_MODULE)) | 378 | if (!try_module_get(THIS_MODULE)) |
394 | return -EINVAL; | 379 | return -EINVAL; |
395 | 380 | ||
396 | ls = dlm_find_lockspace_name(name, namelen); | 381 | error = 0; |
397 | if (ls) { | 382 | |
398 | *lockspace = ls; | 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 | module_put(THIS_MODULE); | 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); | ||
400 | |||
401 | if (error < 0) | ||
402 | goto out; | ||
403 | if (error) | ||
404 | goto ret_zero; | ||
405 | |||
406 | error = -ENOMEM; | ||
402 | 407 | ||
403 | ls = kzalloc(sizeof(struct dlm_ls) + namelen, GFP_KERNEL); | 408 | ls = kzalloc(sizeof(struct dlm_ls) + namelen, GFP_KERNEL); |
404 | if (!ls) | 409 | if (!ls) |
@@ -418,8 +423,9 @@ static int new_lockspace(char *name, int namelen, void **lockspace, | |||
418 | ls->ls_allocation = GFP_KERNEL; | 423 | ls->ls_allocation = GFP_KERNEL; |
419 | 424 | ||
420 | /* ls_exflags are forced to match among nodes, and we don't | 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 */ | 426 | need to require all nodes to have some flags set */ |
422 | ls->ls_exflags = (flags & ~(DLM_LSFL_TIMEWARN | DLM_LSFL_FS)); | 427 | ls->ls_exflags = (flags & ~(DLM_LSFL_TIMEWARN | DLM_LSFL_FS | |
428 | DLM_LSFL_NEWEXCL)); | ||
423 | 429 | ||
424 | size = dlm_config.ci_rsbtbl_size; | 430 | size = dlm_config.ci_rsbtbl_size; |
425 | ls->ls_rsbtbl_size = size; | 431 | ls->ls_rsbtbl_size = size; |
@@ -510,6 +516,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, | |||
510 | down_write(&ls->ls_in_recovery); | 516 | down_write(&ls->ls_in_recovery); |
511 | 517 | ||
512 | spin_lock(&lslist_lock); | 518 | spin_lock(&lslist_lock); |
519 | ls->ls_create_count = 1; | ||
513 | list_add(&ls->ls_list, &lslist); | 520 | list_add(&ls->ls_list, &lslist); |
514 | spin_unlock(&lslist_lock); | 521 | spin_unlock(&lslist_lock); |
515 | 522 | ||
@@ -548,7 +555,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, | |||
548 | dlm_create_debug_file(ls); | 555 | dlm_create_debug_file(ls); |
549 | 556 | ||
550 | log_debug(ls, "join complete"); | 557 | log_debug(ls, "join complete"); |
551 | 558 | ret_zero: | |
552 | *lockspace = ls; | 559 | *lockspace = ls; |
553 | return 0; | 560 | return 0; |
554 | 561 | ||
@@ -635,11 +642,32 @@ static int release_lockspace(struct dlm_ls *ls, int force) | |||
635 | struct dlm_lkb *lkb; | 642 | struct dlm_lkb *lkb; |
636 | struct dlm_rsb *rsb; | 643 | struct dlm_rsb *rsb; |
637 | struct list_head *head; | 644 | struct list_head *head; |
638 | int i; | 645 | int i, busy, rv; |
639 | int busy = lockspace_busy(ls); | 646 | |
647 | busy = lockspace_busy(ls); | ||
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 | } | ||
640 | 669 | ||
641 | if (busy > force) | 670 | dlm_device_deregister(ls); |
642 | return -EBUSY; | ||
643 | 671 | ||
644 | if (force < 3) | 672 | if (force < 3) |
645 | do_uevent(ls, 0); | 673 | do_uevent(ls, 0); |
@@ -720,15 +748,10 @@ static int release_lockspace(struct dlm_ls *ls, int force) | |||
720 | dlm_clear_members(ls); | 748 | dlm_clear_members(ls); |
721 | dlm_clear_members_gone(ls); | 749 | dlm_clear_members_gone(ls); |
722 | kfree(ls->ls_node_array); | 750 | kfree(ls->ls_node_array); |
751 | log_debug(ls, "release_lockspace final free"); | ||
723 | kobject_put(&ls->ls_kobj); | 752 | kobject_put(&ls->ls_kobj); |
724 | /* The ls structure will be freed when the kobject is done with */ | 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 | module_put(THIS_MODULE); | 755 | module_put(THIS_MODULE); |
733 | return 0; | 756 | return 0; |
734 | } | 757 | } |
@@ -750,11 +773,21 @@ static int release_lockspace(struct dlm_ls *ls, int force) | |||
750 | int dlm_release_lockspace(void *lockspace, int force) | 773 | int dlm_release_lockspace(void *lockspace, int force) |
751 | { | 774 | { |
752 | struct dlm_ls *ls; | 775 | struct dlm_ls *ls; |
776 | int error; | ||
753 | 777 | ||
754 | ls = dlm_find_lockspace_local(lockspace); | 778 | ls = dlm_find_lockspace_local(lockspace); |
755 | if (!ls) | 779 | if (!ls) |
756 | return -EINVAL; | 780 | return -EINVAL; |
757 | dlm_put_lockspace(ls); | 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 | } |
760 | 793 | ||