diff options
Diffstat (limited to 'fs/dlm/user.c')
| -rw-r--r-- | fs/dlm/user.c | 124 |
1 files changed, 94 insertions, 30 deletions
diff --git a/fs/dlm/user.c b/fs/dlm/user.c index 34f14a14fb4e..b3832c67194a 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 |
| @@ -15,7 +15,6 @@ | |||
| 15 | #include <linux/poll.h> | 15 | #include <linux/poll.h> |
| 16 | #include <linux/signal.h> | 16 | #include <linux/signal.h> |
| 17 | #include <linux/spinlock.h> | 17 | #include <linux/spinlock.h> |
| 18 | #include <linux/smp_lock.h> | ||
| 19 | #include <linux/dlm.h> | 18 | #include <linux/dlm.h> |
| 20 | #include <linux/dlm_device.h> | 19 | #include <linux/dlm_device.h> |
| 21 | 20 | ||
| @@ -27,6 +26,8 @@ | |||
| 27 | 26 | ||
| 28 | static const char name_prefix[] = "dlm"; | 27 | static const char name_prefix[] = "dlm"; |
| 29 | static const struct file_operations device_fops; | 28 | static const struct file_operations device_fops; |
| 29 | static atomic_t dlm_monitor_opened; | ||
| 30 | static int dlm_monitor_unused = 1; | ||
| 30 | 31 | ||
| 31 | #ifdef CONFIG_COMPAT | 32 | #ifdef CONFIG_COMPAT |
| 32 | 33 | ||
| @@ -340,10 +341,15 @@ static int device_user_deadlock(struct dlm_user_proc *proc, | |||
| 340 | return error; | 341 | return error; |
| 341 | } | 342 | } |
| 342 | 343 | ||
| 343 | static int create_misc_device(struct dlm_ls *ls, char *name) | 344 | static int dlm_device_register(struct dlm_ls *ls, char *name) |
| 344 | { | 345 | { |
| 345 | int error, len; | 346 | int error, len; |
| 346 | 347 | ||
| 348 | /* The device is already registered. This happens when the | ||
| 349 | lockspace is created multiple times from userspace. */ | ||
| 350 | if (ls->ls_device.name) | ||
| 351 | return 0; | ||
| 352 | |||
| 347 | error = -ENOMEM; | 353 | error = -ENOMEM; |
| 348 | len = strlen(name) + strlen(name_prefix) + 2; | 354 | len = strlen(name) + strlen(name_prefix) + 2; |
| 349 | ls->ls_device.name = kzalloc(len, GFP_KERNEL); | 355 | ls->ls_device.name = kzalloc(len, GFP_KERNEL); |
| @@ -363,6 +369,22 @@ fail: | |||
| 363 | return error; | 369 | return error; |
| 364 | } | 370 | } |
| 365 | 371 | ||
| 372 | int dlm_device_deregister(struct dlm_ls *ls) | ||
| 373 | { | ||
| 374 | int error; | ||
| 375 | |||
| 376 | /* The device is not registered. This happens when the lockspace | ||
| 377 | was never used from userspace, or when device_create_lockspace() | ||
| 378 | calls dlm_release_lockspace() after the register fails. */ | ||
| 379 | if (!ls->ls_device.name) | ||
| 380 | return 0; | ||
| 381 | |||
| 382 | error = misc_deregister(&ls->ls_device); | ||
| 383 | if (!error) | ||
| 384 | kfree(ls->ls_device.name); | ||
| 385 | return error; | ||
| 386 | } | ||
| 387 | |||
| 366 | static int device_user_purge(struct dlm_user_proc *proc, | 388 | static int device_user_purge(struct dlm_user_proc *proc, |
| 367 | struct dlm_purge_params *params) | 389 | struct dlm_purge_params *params) |
| 368 | { | 390 | { |
| @@ -397,7 +419,7 @@ static int device_create_lockspace(struct dlm_lspace_params *params) | |||
| 397 | if (!ls) | 419 | if (!ls) |
| 398 | return -ENOENT; | 420 | return -ENOENT; |
| 399 | 421 | ||
| 400 | error = create_misc_device(ls, params->name); | 422 | error = dlm_device_register(ls, params->name); |
| 401 | dlm_put_lockspace(ls); | 423 | dlm_put_lockspace(ls); |
| 402 | 424 | ||
| 403 | if (error) | 425 | if (error) |
| @@ -421,31 +443,22 @@ static int device_remove_lockspace(struct dlm_lspace_params *params) | |||
| 421 | if (!ls) | 443 | if (!ls) |
| 422 | return -ENOENT; | 444 | return -ENOENT; |
| 423 | 445 | ||
| 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) | 446 | if (params->flags & DLM_USER_LSFLG_FORCEFREE) |
| 436 | force = 2; | 447 | force = 2; |
| 437 | 448 | ||
| 438 | lockspace = ls->ls_local_handle; | 449 | lockspace = ls->ls_local_handle; |
| 450 | dlm_put_lockspace(ls); | ||
| 439 | 451 | ||
| 440 | /* dlm_release_lockspace waits for references to go to zero, | 452 | /* The final dlm_release_lockspace waits for references to go to |
| 441 | so all processes will need to close their device for the ls | 453 | zero, so all processes will need to close their device for the |
| 442 | before the release will procede */ | 454 | ls before the release will proceed. release also calls the |
| 455 | device_deregister above. Converting a positive return value | ||
| 456 | from release to zero means that userspace won't know when its | ||
| 457 | release was the final one, but it shouldn't need to know. */ | ||
| 443 | 458 | ||
| 444 | dlm_put_lockspace(ls); | ||
| 445 | error = dlm_release_lockspace(lockspace, force); | 459 | error = dlm_release_lockspace(lockspace, force); |
| 446 | if (error) | 460 | if (error > 0) |
| 447 | create_misc_device(ls, ls->ls_name); | 461 | error = 0; |
| 448 | out: | ||
| 449 | return error; | 462 | return error; |
| 450 | } | 463 | } |
| 451 | 464 | ||
| @@ -623,17 +636,13 @@ static int device_open(struct inode *inode, struct file *file) | |||
| 623 | struct dlm_user_proc *proc; | 636 | struct dlm_user_proc *proc; |
| 624 | struct dlm_ls *ls; | 637 | struct dlm_ls *ls; |
| 625 | 638 | ||
| 626 | lock_kernel(); | ||
| 627 | ls = dlm_find_lockspace_device(iminor(inode)); | 639 | ls = dlm_find_lockspace_device(iminor(inode)); |
| 628 | if (!ls) { | 640 | if (!ls) |
| 629 | unlock_kernel(); | ||
| 630 | return -ENOENT; | 641 | return -ENOENT; |
| 631 | } | ||
| 632 | 642 | ||
| 633 | proc = kzalloc(sizeof(struct dlm_user_proc), GFP_KERNEL); | 643 | proc = kzalloc(sizeof(struct dlm_user_proc), GFP_KERNEL); |
| 634 | if (!proc) { | 644 | if (!proc) { |
| 635 | dlm_put_lockspace(ls); | 645 | dlm_put_lockspace(ls); |
| 636 | unlock_kernel(); | ||
| 637 | return -ENOMEM; | 646 | return -ENOMEM; |
| 638 | } | 647 | } |
| 639 | 648 | ||
| @@ -645,7 +654,6 @@ static int device_open(struct inode *inode, struct file *file) | |||
| 645 | spin_lock_init(&proc->locks_spin); | 654 | spin_lock_init(&proc->locks_spin); |
| 646 | init_waitqueue_head(&proc->wait); | 655 | init_waitqueue_head(&proc->wait); |
| 647 | file->private_data = proc; | 656 | file->private_data = proc; |
| 648 | unlock_kernel(); | ||
| 649 | 657 | ||
| 650 | return 0; | 658 | return 0; |
| 651 | } | 659 | } |
| @@ -878,9 +886,28 @@ static unsigned int device_poll(struct file *file, poll_table *wait) | |||
| 878 | return 0; | 886 | return 0; |
| 879 | } | 887 | } |
| 880 | 888 | ||
| 889 | int dlm_user_daemon_available(void) | ||
| 890 | { | ||
| 891 | /* dlm_controld hasn't started (or, has started, but not | ||
| 892 | properly populated configfs) */ | ||
| 893 | |||
| 894 | if (!dlm_our_nodeid()) | ||
| 895 | return 0; | ||
| 896 | |||
| 897 | /* This is to deal with versions of dlm_controld that don't | ||
| 898 | know about the monitor device. We assume that if the | ||
| 899 | dlm_controld was started (above), but the monitor device | ||
| 900 | was never opened, that it's an old version. dlm_controld | ||
| 901 | should open the monitor device before populating configfs. */ | ||
| 902 | |||
| 903 | if (dlm_monitor_unused) | ||
| 904 | return 1; | ||
| 905 | |||
| 906 | return atomic_read(&dlm_monitor_opened) ? 1 : 0; | ||
| 907 | } | ||
| 908 | |||
| 881 | static int ctl_device_open(struct inode *inode, struct file *file) | 909 | static int ctl_device_open(struct inode *inode, struct file *file) |
| 882 | { | 910 | { |
| 883 | cycle_kernel_lock(); | ||
| 884 | file->private_data = NULL; | 911 | file->private_data = NULL; |
| 885 | return 0; | 912 | return 0; |
| 886 | } | 913 | } |
| @@ -890,6 +917,20 @@ static int ctl_device_close(struct inode *inode, struct file *file) | |||
| 890 | return 0; | 917 | return 0; |
| 891 | } | 918 | } |
| 892 | 919 | ||
| 920 | static int monitor_device_open(struct inode *inode, struct file *file) | ||
| 921 | { | ||
| 922 | atomic_inc(&dlm_monitor_opened); | ||
| 923 | dlm_monitor_unused = 0; | ||
| 924 | return 0; | ||
| 925 | } | ||
| 926 | |||
| 927 | static int monitor_device_close(struct inode *inode, struct file *file) | ||
| 928 | { | ||
| 929 | if (atomic_dec_and_test(&dlm_monitor_opened)) | ||
| 930 | dlm_stop_lockspaces(); | ||
| 931 | return 0; | ||
| 932 | } | ||
| 933 | |||
| 893 | static const struct file_operations device_fops = { | 934 | static const struct file_operations device_fops = { |
| 894 | .open = device_open, | 935 | .open = device_open, |
| 895 | .release = device_close, | 936 | .release = device_close, |
| @@ -913,19 +954,42 @@ static struct miscdevice ctl_device = { | |||
| 913 | .minor = MISC_DYNAMIC_MINOR, | 954 | .minor = MISC_DYNAMIC_MINOR, |
| 914 | }; | 955 | }; |
| 915 | 956 | ||
| 957 | static const struct file_operations monitor_device_fops = { | ||
| 958 | .open = monitor_device_open, | ||
| 959 | .release = monitor_device_close, | ||
| 960 | .owner = THIS_MODULE, | ||
| 961 | }; | ||
| 962 | |||
| 963 | static struct miscdevice monitor_device = { | ||
| 964 | .name = "dlm-monitor", | ||
| 965 | .fops = &monitor_device_fops, | ||
| 966 | .minor = MISC_DYNAMIC_MINOR, | ||
| 967 | }; | ||
| 968 | |||
| 916 | int __init dlm_user_init(void) | 969 | int __init dlm_user_init(void) |
| 917 | { | 970 | { |
| 918 | int error; | 971 | int error; |
| 919 | 972 | ||
| 973 | atomic_set(&dlm_monitor_opened, 0); | ||
| 974 | |||
| 920 | error = misc_register(&ctl_device); | 975 | error = misc_register(&ctl_device); |
| 921 | if (error) | 976 | if (error) { |
| 922 | log_print("misc_register failed for control device"); | 977 | log_print("misc_register failed for control device"); |
| 978 | goto out; | ||
| 979 | } | ||
| 923 | 980 | ||
| 981 | error = misc_register(&monitor_device); | ||
| 982 | if (error) { | ||
| 983 | log_print("misc_register failed for monitor device"); | ||
| 984 | misc_deregister(&ctl_device); | ||
| 985 | } | ||
| 986 | out: | ||
| 924 | return error; | 987 | return error; |
| 925 | } | 988 | } |
| 926 | 989 | ||
| 927 | void dlm_user_exit(void) | 990 | void dlm_user_exit(void) |
| 928 | { | 991 | { |
| 929 | misc_deregister(&ctl_device); | 992 | misc_deregister(&ctl_device); |
| 993 | misc_deregister(&monitor_device); | ||
| 930 | } | 994 | } |
| 931 | 995 | ||
