aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dlm
diff options
context:
space:
mode:
Diffstat (limited to 'fs/dlm')
-rw-r--r--fs/dlm/dlm_internal.h6
-rw-r--r--fs/dlm/lockspace.c107
-rw-r--r--fs/dlm/user.c54
-rw-r--r--fs/dlm/user.h3
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
27static int ls_count; 28static int ls_count;
28static struct mutex ls_lock; 29static 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
249static 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
266struct dlm_ls *dlm_find_lockspace_global(uint32_t id) 250struct 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)
750int dlm_release_lockspace(void *lockspace, int force) 773int 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
343static int create_misc_device(struct dlm_ls *ls, char *name) 343static 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
371int 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
366static int device_user_purge(struct dlm_user_proc *proc, 387static 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 @@
12void dlm_user_add_ast(struct dlm_lkb *lkb, int type); 12void dlm_user_add_ast(struct dlm_lkb *lkb, int type);
13int dlm_user_init(void); 13int dlm_user_init(void);
14void dlm_user_exit(void); 14void dlm_user_exit(void);
15int dlm_device_deregister(struct dlm_ls *ls);
15 16
16#endif 17#endif