diff options
| author | David Teigland <teigland@redhat.com> | 2008-08-06 14:30:24 -0400 |
|---|---|---|
| committer | David Teigland <teigland@redhat.com> | 2008-08-28 12:49:15 -0400 |
| commit | 0f8e0d9a317406612700426fad3efab0b7bbc467 (patch) | |
| tree | b4ed35afeab36615e50d5c7928a6199780fd2fca /fs/dlm | |
| parent | 4c246edd2550304df5b766cc841584b2bb058843 (diff) | |
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>
Diffstat (limited to 'fs/dlm')
| -rw-r--r-- | fs/dlm/dlm_internal.h | 6 | ||||
| -rw-r--r-- | fs/dlm/lockspace.c | 107 | ||||
| -rw-r--r-- | fs/dlm/user.c | 54 | ||||
| -rw-r--r-- | fs/dlm/user.h | 3 |
4 files changed, 109 insertions, 61 deletions
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index 5a7ac33b629c..9e0622aff496 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h | |||
| @@ -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 |
| @@ -441,7 +441,9 @@ struct dlm_ls { | |||
| 441 | uint32_t ls_global_id; /* global unique lockspace ID */ | 441 | uint32_t ls_global_id; /* global unique lockspace ID */ |
| 442 | uint32_t ls_exflags; | 442 | uint32_t ls_exflags; |
| 443 | int ls_lvblen; | 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 | unsigned long ls_flags; /* LSFL_ */ | 447 | unsigned long ls_flags; /* LSFL_ */ |
| 446 | struct kobject ls_kobj; | 448 | struct kobject ls_kobj; |
| 447 | 449 | ||
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 | ||
diff --git a/fs/dlm/user.c b/fs/dlm/user.c index 34f14a14fb4e..6542110c0da4 100644 --- a/fs/dlm/user.c +++ b/fs/dlm/user.c | |||
| @@ -1,5 +1,5 @@ | |||
| 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 | * This copyrighted material is made available to anyone wishing to use, | 4 | * This copyrighted material is made available to anyone wishing to use, |
| 5 | * modify, copy, or redistribute it subject to the terms and conditions | 5 | * modify, copy, or redistribute it subject to the terms and conditions |
| @@ -340,10 +340,15 @@ static int device_user_deadlock(struct dlm_user_proc *proc, | |||
| 340 | return error; | 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 | int error, len; | 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 | error = -ENOMEM; | 352 | error = -ENOMEM; |
| 348 | len = strlen(name) + strlen(name_prefix) + 2; | 353 | len = strlen(name) + strlen(name_prefix) + 2; |
| 349 | ls->ls_device.name = kzalloc(len, GFP_KERNEL); | 354 | ls->ls_device.name = kzalloc(len, GFP_KERNEL); |
| @@ -363,6 +368,22 @@ fail: | |||
| 363 | return error; | 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 | static int device_user_purge(struct dlm_user_proc *proc, | 387 | static int device_user_purge(struct dlm_user_proc *proc, |
| 367 | struct dlm_purge_params *params) | 388 | struct dlm_purge_params *params) |
| 368 | { | 389 | { |
| @@ -397,7 +418,7 @@ static int device_create_lockspace(struct dlm_lspace_params *params) | |||
| 397 | if (!ls) | 418 | if (!ls) |
| 398 | return -ENOENT; | 419 | return -ENOENT; |
| 399 | 420 | ||
| 400 | error = create_misc_device(ls, params->name); | 421 | error = dlm_device_register(ls, params->name); |
| 401 | dlm_put_lockspace(ls); | 422 | dlm_put_lockspace(ls); |
| 402 | 423 | ||
| 403 | if (error) | 424 | if (error) |
| @@ -421,31 +442,22 @@ static int device_remove_lockspace(struct dlm_lspace_params *params) | |||
| 421 | if (!ls) | 442 | if (!ls) |
| 422 | return -ENOENT; | 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 | if (params->flags & DLM_USER_LSFLG_FORCEFREE) | 445 | if (params->flags & DLM_USER_LSFLG_FORCEFREE) |
| 436 | force = 2; | 446 | force = 2; |
| 437 | 447 | ||
| 438 | lockspace = ls->ls_local_handle; | 448 | lockspace = ls->ls_local_handle; |
| 449 | dlm_put_lockspace(ls); | ||
| 439 | 450 | ||
| 440 | /* dlm_release_lockspace waits for references to go to zero, | 451 | /* The final dlm_release_lockspace waits for references to go to |
| 441 | so all processes will need to close their device for the ls | 452 | zero, so all processes will need to close their device for the |
| 442 | before the release will procede */ | 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 | error = dlm_release_lockspace(lockspace, force); | 458 | error = dlm_release_lockspace(lockspace, force); |
| 446 | if (error) | 459 | if (error > 0) |
| 447 | create_misc_device(ls, ls->ls_name); | 460 | error = 0; |
| 448 | out: | ||
| 449 | return error; | 461 | return error; |
| 450 | } | 462 | } |
| 451 | 463 | ||
diff --git a/fs/dlm/user.h b/fs/dlm/user.h index d38e9f3e4151..c528b6b2991b 100644 --- a/fs/dlm/user.h +++ b/fs/dlm/user.h | |||
| @@ -1,5 +1,5 @@ | |||
| 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 | * This copyrighted material is made available to anyone wishing to use, | 4 | * This copyrighted material is made available to anyone wishing to use, |
| 5 | * modify, copy, or redistribute it subject to the terms and conditions | 5 | * modify, copy, or redistribute it subject to the terms and conditions |
| @@ -12,5 +12,6 @@ | |||
| 12 | void dlm_user_add_ast(struct dlm_lkb *lkb, int type); | 12 | void dlm_user_add_ast(struct dlm_lkb *lkb, int type); |
| 13 | int dlm_user_init(void); | 13 | int dlm_user_init(void); |
| 14 | void dlm_user_exit(void); | 14 | void dlm_user_exit(void); |
| 15 | int dlm_device_deregister(struct dlm_ls *ls); | ||
| 15 | 16 | ||
| 16 | #endif | 17 | #endif |
