diff options
Diffstat (limited to 'fs/dlm/lockspace.c')
| -rw-r--r-- | fs/dlm/lockspace.c | 158 |
1 files changed, 118 insertions, 40 deletions
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 499e16759e96..d910501de6d2 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; |
| @@ -211,19 +212,41 @@ void dlm_lockspace_exit(void) | |||
| 211 | kset_unregister(dlm_kset); | 212 | kset_unregister(dlm_kset); |
| 212 | } | 213 | } |
| 213 | 214 | ||
| 215 | static struct dlm_ls *find_ls_to_scan(void) | ||
| 216 | { | ||
| 217 | struct dlm_ls *ls; | ||
| 218 | |||
| 219 | spin_lock(&lslist_lock); | ||
| 220 | list_for_each_entry(ls, &lslist, ls_list) { | ||
| 221 | if (time_after_eq(jiffies, ls->ls_scan_time + | ||
| 222 | dlm_config.ci_scan_secs * HZ)) { | ||
| 223 | spin_unlock(&lslist_lock); | ||
| 224 | return ls; | ||
| 225 | } | ||
| 226 | } | ||
| 227 | spin_unlock(&lslist_lock); | ||
| 228 | return NULL; | ||
| 229 | } | ||
| 230 | |||
| 214 | static int dlm_scand(void *data) | 231 | static int dlm_scand(void *data) |
| 215 | { | 232 | { |
| 216 | struct dlm_ls *ls; | 233 | struct dlm_ls *ls; |
| 234 | int timeout_jiffies = dlm_config.ci_scan_secs * HZ; | ||
| 217 | 235 | ||
| 218 | while (!kthread_should_stop()) { | 236 | while (!kthread_should_stop()) { |
| 219 | list_for_each_entry(ls, &lslist, ls_list) { | 237 | ls = find_ls_to_scan(); |
| 238 | if (ls) { | ||
| 220 | if (dlm_lock_recovery_try(ls)) { | 239 | if (dlm_lock_recovery_try(ls)) { |
| 240 | ls->ls_scan_time = jiffies; | ||
| 221 | dlm_scan_rsbs(ls); | 241 | dlm_scan_rsbs(ls); |
| 222 | dlm_scan_timeout(ls); | 242 | dlm_scan_timeout(ls); |
| 223 | dlm_unlock_recovery(ls); | 243 | dlm_unlock_recovery(ls); |
| 244 | } else { | ||
| 245 | ls->ls_scan_time += HZ; | ||
| 224 | } | 246 | } |
| 247 | } else { | ||
| 248 | schedule_timeout_interruptible(timeout_jiffies); | ||
| 225 | } | 249 | } |
| 226 | schedule_timeout_interruptible(dlm_config.ci_scan_secs * HZ); | ||
| 227 | } | 250 | } |
| 228 | return 0; | 251 | return 0; |
| 229 | } | 252 | } |
| @@ -246,23 +269,6 @@ static void dlm_scand_stop(void) | |||
| 246 | kthread_stop(scand_task); | 269 | kthread_stop(scand_task); |
| 247 | } | 270 | } |
| 248 | 271 | ||
| 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) | 272 | struct dlm_ls *dlm_find_lockspace_global(uint32_t id) |
| 267 | { | 273 | { |
| 268 | struct dlm_ls *ls; | 274 | struct dlm_ls *ls; |
| @@ -327,6 +333,7 @@ static void remove_lockspace(struct dlm_ls *ls) | |||
| 327 | for (;;) { | 333 | for (;;) { |
| 328 | spin_lock(&lslist_lock); | 334 | spin_lock(&lslist_lock); |
| 329 | if (ls->ls_count == 0) { | 335 | if (ls->ls_count == 0) { |
| 336 | WARN_ON(ls->ls_create_count != 0); | ||
| 330 | list_del(&ls->ls_list); | 337 | list_del(&ls->ls_list); |
| 331 | spin_unlock(&lslist_lock); | 338 | spin_unlock(&lslist_lock); |
| 332 | return; | 339 | return; |
| @@ -381,7 +388,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, | |||
| 381 | uint32_t flags, int lvblen) | 388 | uint32_t flags, int lvblen) |
| 382 | { | 389 | { |
| 383 | struct dlm_ls *ls; | 390 | struct dlm_ls *ls; |
| 384 | int i, size, error = -ENOMEM; | 391 | int i, size, error; |
| 385 | int do_unreg = 0; | 392 | int do_unreg = 0; |
| 386 | 393 | ||
| 387 | if (namelen > DLM_LOCKSPACE_LEN) | 394 | if (namelen > DLM_LOCKSPACE_LEN) |
| @@ -393,12 +400,37 @@ static int new_lockspace(char *name, int namelen, void **lockspace, | |||
| 393 | if (!try_module_get(THIS_MODULE)) | 400 | if (!try_module_get(THIS_MODULE)) |
| 394 | return -EINVAL; | 401 | return -EINVAL; |
| 395 | 402 | ||
| 396 | ls = dlm_find_lockspace_name(name, namelen); | 403 | if (!dlm_user_daemon_available()) { |
| 397 | if (ls) { | 404 | module_put(THIS_MODULE); |
| 398 | *lockspace = ls; | 405 | return -EUNATCH; |
| 406 | } | ||
| 407 | |||
| 408 | error = 0; | ||
| 409 | |||
| 410 | spin_lock(&lslist_lock); | ||
| 411 | list_for_each_entry(ls, &lslist, ls_list) { | ||
| 412 | WARN_ON(ls->ls_create_count <= 0); | ||
| 413 | if (ls->ls_namelen != namelen) | ||
| 414 | continue; | ||
| 415 | if (memcmp(ls->ls_name, name, namelen)) | ||
| 416 | continue; | ||
| 417 | if (flags & DLM_LSFL_NEWEXCL) { | ||
| 418 | error = -EEXIST; | ||
| 419 | break; | ||
| 420 | } | ||
| 421 | ls->ls_create_count++; | ||
| 399 | module_put(THIS_MODULE); | 422 | module_put(THIS_MODULE); |
| 400 | return -EEXIST; | 423 | error = 1; /* not an error, return 0 */ |
| 424 | break; | ||
| 401 | } | 425 | } |
| 426 | spin_unlock(&lslist_lock); | ||
| 427 | |||
| 428 | if (error < 0) | ||
| 429 | goto out; | ||
| 430 | if (error) | ||
| 431 | goto ret_zero; | ||
| 432 | |||
| 433 | error = -ENOMEM; | ||
| 402 | 434 | ||
| 403 | ls = kzalloc(sizeof(struct dlm_ls) + namelen, GFP_KERNEL); | 435 | ls = kzalloc(sizeof(struct dlm_ls) + namelen, GFP_KERNEL); |
| 404 | if (!ls) | 436 | if (!ls) |
| @@ -408,6 +440,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, | |||
| 408 | ls->ls_lvblen = lvblen; | 440 | ls->ls_lvblen = lvblen; |
| 409 | ls->ls_count = 0; | 441 | ls->ls_count = 0; |
| 410 | ls->ls_flags = 0; | 442 | ls->ls_flags = 0; |
| 443 | ls->ls_scan_time = jiffies; | ||
| 411 | 444 | ||
| 412 | if (flags & DLM_LSFL_TIMEWARN) | 445 | if (flags & DLM_LSFL_TIMEWARN) |
| 413 | set_bit(LSFL_TIMEWARN, &ls->ls_flags); | 446 | set_bit(LSFL_TIMEWARN, &ls->ls_flags); |
| @@ -418,8 +451,9 @@ static int new_lockspace(char *name, int namelen, void **lockspace, | |||
| 418 | ls->ls_allocation = GFP_KERNEL; | 451 | ls->ls_allocation = GFP_KERNEL; |
| 419 | 452 | ||
| 420 | /* ls_exflags are forced to match among nodes, and we don't | 453 | /* ls_exflags are forced to match among nodes, and we don't |
| 421 | need to require all nodes to have TIMEWARN or FS set */ | 454 | need to require all nodes to have some flags set */ |
| 422 | ls->ls_exflags = (flags & ~(DLM_LSFL_TIMEWARN | DLM_LSFL_FS)); | 455 | ls->ls_exflags = (flags & ~(DLM_LSFL_TIMEWARN | DLM_LSFL_FS | |
| 456 | DLM_LSFL_NEWEXCL)); | ||
| 423 | 457 | ||
| 424 | size = dlm_config.ci_rsbtbl_size; | 458 | size = dlm_config.ci_rsbtbl_size; |
| 425 | ls->ls_rsbtbl_size = size; | 459 | ls->ls_rsbtbl_size = size; |
| @@ -510,6 +544,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, | |||
| 510 | down_write(&ls->ls_in_recovery); | 544 | down_write(&ls->ls_in_recovery); |
| 511 | 545 | ||
| 512 | spin_lock(&lslist_lock); | 546 | spin_lock(&lslist_lock); |
| 547 | ls->ls_create_count = 1; | ||
| 513 | list_add(&ls->ls_list, &lslist); | 548 | list_add(&ls->ls_list, &lslist); |
| 514 | spin_unlock(&lslist_lock); | 549 | spin_unlock(&lslist_lock); |
| 515 | 550 | ||
| @@ -548,7 +583,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, | |||
| 548 | dlm_create_debug_file(ls); | 583 | dlm_create_debug_file(ls); |
| 549 | 584 | ||
| 550 | log_debug(ls, "join complete"); | 585 | log_debug(ls, "join complete"); |
| 551 | 586 | ret_zero: | |
| 552 | *lockspace = ls; | 587 | *lockspace = ls; |
| 553 | return 0; | 588 | return 0; |
| 554 | 589 | ||
| @@ -635,13 +670,34 @@ static int release_lockspace(struct dlm_ls *ls, int force) | |||
| 635 | struct dlm_lkb *lkb; | 670 | struct dlm_lkb *lkb; |
| 636 | struct dlm_rsb *rsb; | 671 | struct dlm_rsb *rsb; |
| 637 | struct list_head *head; | 672 | struct list_head *head; |
| 638 | int i; | 673 | int i, busy, rv; |
| 639 | int busy = lockspace_busy(ls); | 674 | |
| 675 | busy = lockspace_busy(ls); | ||
| 676 | |||
| 677 | spin_lock(&lslist_lock); | ||
| 678 | if (ls->ls_create_count == 1) { | ||
| 679 | if (busy > force) | ||
| 680 | rv = -EBUSY; | ||
| 681 | else { | ||
| 682 | /* remove_lockspace takes ls off lslist */ | ||
| 683 | ls->ls_create_count = 0; | ||
| 684 | rv = 0; | ||
| 685 | } | ||
| 686 | } else if (ls->ls_create_count > 1) { | ||
| 687 | rv = --ls->ls_create_count; | ||
| 688 | } else { | ||
| 689 | rv = -EINVAL; | ||
| 690 | } | ||
| 691 | spin_unlock(&lslist_lock); | ||
| 640 | 692 | ||
| 641 | if (busy > force) | 693 | if (rv) { |
| 642 | return -EBUSY; | 694 | log_debug(ls, "release_lockspace no remove %d", rv); |
| 695 | return rv; | ||
| 696 | } | ||
| 697 | |||
| 698 | dlm_device_deregister(ls); | ||
| 643 | 699 | ||
| 644 | if (force < 3) | 700 | if (force < 3 && dlm_user_daemon_available()) |
| 645 | do_uevent(ls, 0); | 701 | do_uevent(ls, 0); |
| 646 | 702 | ||
| 647 | dlm_recoverd_stop(ls); | 703 | dlm_recoverd_stop(ls); |
| @@ -720,15 +776,10 @@ static int release_lockspace(struct dlm_ls *ls, int force) | |||
| 720 | dlm_clear_members(ls); | 776 | dlm_clear_members(ls); |
| 721 | dlm_clear_members_gone(ls); | 777 | dlm_clear_members_gone(ls); |
| 722 | kfree(ls->ls_node_array); | 778 | kfree(ls->ls_node_array); |
| 779 | log_debug(ls, "release_lockspace final free"); | ||
| 723 | kobject_put(&ls->ls_kobj); | 780 | kobject_put(&ls->ls_kobj); |
| 724 | /* The ls structure will be freed when the kobject is done with */ | 781 | /* The ls structure will be freed when the kobject is done with */ |
| 725 | 782 | ||
| 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); | 783 | module_put(THIS_MODULE); |
| 733 | return 0; | 784 | return 0; |
| 734 | } | 785 | } |
| @@ -750,11 +801,38 @@ static int release_lockspace(struct dlm_ls *ls, int force) | |||
| 750 | int dlm_release_lockspace(void *lockspace, int force) | 801 | int dlm_release_lockspace(void *lockspace, int force) |
| 751 | { | 802 | { |
| 752 | struct dlm_ls *ls; | 803 | struct dlm_ls *ls; |
| 804 | int error; | ||
| 753 | 805 | ||
| 754 | ls = dlm_find_lockspace_local(lockspace); | 806 | ls = dlm_find_lockspace_local(lockspace); |
| 755 | if (!ls) | 807 | if (!ls) |
| 756 | return -EINVAL; | 808 | return -EINVAL; |
| 757 | dlm_put_lockspace(ls); | 809 | dlm_put_lockspace(ls); |
| 758 | return release_lockspace(ls, force); | 810 | |
| 811 | mutex_lock(&ls_lock); | ||
| 812 | error = release_lockspace(ls, force); | ||
| 813 | if (!error) | ||
| 814 | ls_count--; | ||
| 815 | else if (!ls_count) | ||
| 816 | threads_stop(); | ||
| 817 | mutex_unlock(&ls_lock); | ||
| 818 | |||
| 819 | return error; | ||
| 820 | } | ||
| 821 | |||
| 822 | void dlm_stop_lockspaces(void) | ||
| 823 | { | ||
| 824 | struct dlm_ls *ls; | ||
| 825 | |||
| 826 | restart: | ||
| 827 | spin_lock(&lslist_lock); | ||
| 828 | list_for_each_entry(ls, &lslist, ls_list) { | ||
| 829 | if (!test_bit(LSFL_RUNNING, &ls->ls_flags)) | ||
| 830 | continue; | ||
| 831 | spin_unlock(&lslist_lock); | ||
| 832 | log_error(ls, "no userland control daemon, stopping lockspace"); | ||
| 833 | dlm_ls_stop(ls); | ||
| 834 | goto restart; | ||
| 835 | } | ||
| 836 | spin_unlock(&lslist_lock); | ||
| 759 | } | 837 | } |
| 760 | 838 | ||
