Commit 0f8e0d9a authored by David Teigland's avatar David Teigland

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: default avatarDavid Teigland <teigland@redhat.com>
parent 4c246edd
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
******************************************************************************* *******************************************************************************
** **
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. ** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
** **
** This copyrighted material is made available to anyone wishing to use, ** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions ** modify, copy, or redistribute it subject to the terms and conditions
...@@ -441,7 +441,9 @@ struct dlm_ls { ...@@ -441,7 +441,9 @@ struct dlm_ls {
uint32_t ls_global_id; /* global unique lockspace ID */ uint32_t ls_global_id; /* global unique lockspace ID */
uint32_t ls_exflags; uint32_t ls_exflags;
int ls_lvblen; int ls_lvblen;
int ls_count; /* reference count */ int ls_count; /* refcount of processes in
the dlm using this ls */
int ls_create_count; /* create/release refcount */
unsigned long ls_flags; /* LSFL_ */ unsigned long ls_flags; /* LSFL_ */
struct kobject ls_kobj; struct kobject ls_kobj;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
******************************************************************************* *******************************************************************************
** **
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. ** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
** **
** This copyrighted material is made available to anyone wishing to use, ** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions ** modify, copy, or redistribute it subject to the terms and conditions
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "lock.h" #include "lock.h"
#include "recover.h" #include "recover.h"
#include "requestqueue.h" #include "requestqueue.h"
#include "user.h"
static int ls_count; static int ls_count;
static struct mutex ls_lock; static struct mutex ls_lock;
...@@ -246,23 +247,6 @@ static void dlm_scand_stop(void) ...@@ -246,23 +247,6 @@ static void dlm_scand_stop(void)
kthread_stop(scand_task); kthread_stop(scand_task);
} }
static struct dlm_ls *dlm_find_lockspace_name(char *name, int namelen)
{
struct dlm_ls *ls;
spin_lock(&lslist_lock);
list_for_each_entry(ls, &lslist, ls_list) {
if (ls->ls_namelen == namelen &&
memcmp(ls->ls_name, name, namelen) == 0)
goto out;
}
ls = NULL;
out:
spin_unlock(&lslist_lock);
return ls;
}
struct dlm_ls *dlm_find_lockspace_global(uint32_t id) struct dlm_ls *dlm_find_lockspace_global(uint32_t id)
{ {
struct dlm_ls *ls; struct dlm_ls *ls;
...@@ -327,6 +311,7 @@ static void remove_lockspace(struct dlm_ls *ls) ...@@ -327,6 +311,7 @@ static void remove_lockspace(struct dlm_ls *ls)
for (;;) { for (;;) {
spin_lock(&lslist_lock); spin_lock(&lslist_lock);
if (ls->ls_count == 0) { if (ls->ls_count == 0) {
WARN_ON(ls->ls_create_count != 0);
list_del(&ls->ls_list); list_del(&ls->ls_list);
spin_unlock(&lslist_lock); spin_unlock(&lslist_lock);
return; return;
...@@ -381,7 +366,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, ...@@ -381,7 +366,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
uint32_t flags, int lvblen) uint32_t flags, int lvblen)
{ {
struct dlm_ls *ls; struct dlm_ls *ls;
int i, size, error = -ENOMEM; int i, size, error;
int do_unreg = 0; int do_unreg = 0;
if (namelen > DLM_LOCKSPACE_LEN) if (namelen > DLM_LOCKSPACE_LEN)
...@@ -393,12 +378,32 @@ static int new_lockspace(char *name, int namelen, void **lockspace, ...@@ -393,12 +378,32 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
if (!try_module_get(THIS_MODULE)) if (!try_module_get(THIS_MODULE))
return -EINVAL; return -EINVAL;
ls = dlm_find_lockspace_name(name, namelen); error = 0;
if (ls) {
*lockspace = ls; spin_lock(&lslist_lock);
list_for_each_entry(ls, &lslist, ls_list) {
WARN_ON(ls->ls_create_count <= 0);
if (ls->ls_namelen != namelen)
continue;
if (memcmp(ls->ls_name, name, namelen))
continue;
if (flags & DLM_LSFL_NEWEXCL) {
error = -EEXIST;
break;
}
ls->ls_create_count++;
module_put(THIS_MODULE); module_put(THIS_MODULE);
return -EEXIST; error = 1; /* not an error, return 0 */
break;
} }
spin_unlock(&lslist_lock);
if (error < 0)
goto out;
if (error)
goto ret_zero;
error = -ENOMEM;
ls = kzalloc(sizeof(struct dlm_ls) + namelen, GFP_KERNEL); ls = kzalloc(sizeof(struct dlm_ls) + namelen, GFP_KERNEL);
if (!ls) if (!ls)
...@@ -418,8 +423,9 @@ static int new_lockspace(char *name, int namelen, void **lockspace, ...@@ -418,8 +423,9 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
ls->ls_allocation = GFP_KERNEL; ls->ls_allocation = GFP_KERNEL;
/* ls_exflags are forced to match among nodes, and we don't /* ls_exflags are forced to match among nodes, and we don't
need to require all nodes to have TIMEWARN or FS set */ need to require all nodes to have some flags set */
ls->ls_exflags = (flags & ~(DLM_LSFL_TIMEWARN | DLM_LSFL_FS)); ls->ls_exflags = (flags & ~(DLM_LSFL_TIMEWARN | DLM_LSFL_FS |
DLM_LSFL_NEWEXCL));
size = dlm_config.ci_rsbtbl_size; size = dlm_config.ci_rsbtbl_size;
ls->ls_rsbtbl_size = size; ls->ls_rsbtbl_size = size;
...@@ -510,6 +516,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, ...@@ -510,6 +516,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
down_write(&ls->ls_in_recovery); down_write(&ls->ls_in_recovery);
spin_lock(&lslist_lock); spin_lock(&lslist_lock);
ls->ls_create_count = 1;
list_add(&ls->ls_list, &lslist); list_add(&ls->ls_list, &lslist);
spin_unlock(&lslist_lock); spin_unlock(&lslist_lock);
...@@ -548,7 +555,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, ...@@ -548,7 +555,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
dlm_create_debug_file(ls); dlm_create_debug_file(ls);
log_debug(ls, "join complete"); log_debug(ls, "join complete");
ret_zero:
*lockspace = ls; *lockspace = ls;
return 0; return 0;
...@@ -635,11 +642,32 @@ static int release_lockspace(struct dlm_ls *ls, int force) ...@@ -635,11 +642,32 @@ static int release_lockspace(struct dlm_ls *ls, int force)
struct dlm_lkb *lkb; struct dlm_lkb *lkb;
struct dlm_rsb *rsb; struct dlm_rsb *rsb;
struct list_head *head; struct list_head *head;
int i; int i, busy, rv;
int busy = lockspace_busy(ls);
busy = lockspace_busy(ls);
spin_lock(&lslist_lock);
if (ls->ls_create_count == 1) {
if (busy > force) if (busy > force)
return -EBUSY; rv = -EBUSY;
else {
/* remove_lockspace takes ls off lslist */
ls->ls_create_count = 0;
rv = 0;
}
} else if (ls->ls_create_count > 1) {
rv = --ls->ls_create_count;
} else {
rv = -EINVAL;
}
spin_unlock(&lslist_lock);
if (rv) {
log_debug(ls, "release_lockspace no remove %d", rv);
return rv;
}
dlm_device_deregister(ls);
if (force < 3) if (force < 3)
do_uevent(ls, 0); do_uevent(ls, 0);
...@@ -720,15 +748,10 @@ static int release_lockspace(struct dlm_ls *ls, int force) ...@@ -720,15 +748,10 @@ static int release_lockspace(struct dlm_ls *ls, int force)
dlm_clear_members(ls); dlm_clear_members(ls);
dlm_clear_members_gone(ls); dlm_clear_members_gone(ls);
kfree(ls->ls_node_array); kfree(ls->ls_node_array);
log_debug(ls, "release_lockspace final free");
kobject_put(&ls->ls_kobj); kobject_put(&ls->ls_kobj);
/* The ls structure will be freed when the kobject is done with */ /* The ls structure will be freed when the kobject is done with */
mutex_lock(&ls_lock);
ls_count--;
if (!ls_count)
threads_stop();
mutex_unlock(&ls_lock);
module_put(THIS_MODULE); module_put(THIS_MODULE);
return 0; return 0;
} }
...@@ -750,11 +773,21 @@ static int release_lockspace(struct dlm_ls *ls, int force) ...@@ -750,11 +773,21 @@ static int release_lockspace(struct dlm_ls *ls, int force)
int dlm_release_lockspace(void *lockspace, int force) int dlm_release_lockspace(void *lockspace, int force)
{ {
struct dlm_ls *ls; struct dlm_ls *ls;
int error;
ls = dlm_find_lockspace_local(lockspace); ls = dlm_find_lockspace_local(lockspace);
if (!ls) if (!ls)
return -EINVAL; return -EINVAL;
dlm_put_lockspace(ls); dlm_put_lockspace(ls);
return release_lockspace(ls, force);
mutex_lock(&ls_lock);
error = release_lockspace(ls, force);
if (!error)
ls_count--;
else if (!ls_count)
threads_stop();
mutex_unlock(&ls_lock);
return error;
} }
/* /*
* Copyright (C) 2006-2007 Red Hat, Inc. All rights reserved. * Copyright (C) 2006-2008 Red Hat, Inc. All rights reserved.
* *
* This copyrighted material is made available to anyone wishing to use, * This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions * 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,10 +340,15 @@ static int device_user_deadlock(struct dlm_user_proc *proc,
return error; return error;
} }
static int create_misc_device(struct dlm_ls *ls, char *name) static int dlm_device_register(struct dlm_ls *ls, char *name)
{ {
int error, len; int error, len;
/* The device is already registered. This happens when the
lockspace is created multiple times from userspace. */
if (ls->ls_device.name)
return 0;
error = -ENOMEM; error = -ENOMEM;
len = strlen(name) + strlen(name_prefix) + 2; len = strlen(name) + strlen(name_prefix) + 2;
ls->ls_device.name = kzalloc(len, GFP_KERNEL); ls->ls_device.name = kzalloc(len, GFP_KERNEL);
...@@ -363,6 +368,22 @@ static int create_misc_device(struct dlm_ls *ls, char *name) ...@@ -363,6 +368,22 @@ static int create_misc_device(struct dlm_ls *ls, char *name)
return error; return error;
} }
int dlm_device_deregister(struct dlm_ls *ls)
{
int error;
/* The device is not registered. This happens when the lockspace
was never used from userspace, or when device_create_lockspace()
calls dlm_release_lockspace() after the register fails. */
if (!ls->ls_device.name)
return 0;
error = misc_deregister(&ls->ls_device);
if (!error)
kfree(ls->ls_device.name);
return error;
}
static int device_user_purge(struct dlm_user_proc *proc, static int device_user_purge(struct dlm_user_proc *proc,
struct dlm_purge_params *params) struct dlm_purge_params *params)
{ {
...@@ -397,7 +418,7 @@ static int device_create_lockspace(struct dlm_lspace_params *params) ...@@ -397,7 +418,7 @@ static int device_create_lockspace(struct dlm_lspace_params *params)
if (!ls) if (!ls)
return -ENOENT; return -ENOENT;
error = create_misc_device(ls, params->name); error = dlm_device_register(ls, params->name);
dlm_put_lockspace(ls); dlm_put_lockspace(ls);
if (error) if (error)
...@@ -421,31 +442,22 @@ static int device_remove_lockspace(struct dlm_lspace_params *params) ...@@ -421,31 +442,22 @@ static int device_remove_lockspace(struct dlm_lspace_params *params)
if (!ls) if (!ls)
return -ENOENT; return -ENOENT;
/* Deregister the misc device first, so we don't have
* a device that's not attached to a lockspace. If
* dlm_release_lockspace fails then we can recreate it
*/
error = misc_deregister(&ls->ls_device);
if (error) {
dlm_put_lockspace(ls);
goto out;
}
kfree(ls->ls_device.name);
if (params->flags & DLM_USER_LSFLG_FORCEFREE) if (params->flags & DLM_USER_LSFLG_FORCEFREE)
force = 2; force = 2;
lockspace = ls->ls_local_handle; lockspace = ls->ls_local_handle;
dlm_put_lockspace(ls);
/* dlm_release_lockspace waits for references to go to zero, /* The final dlm_release_lockspace waits for references to go to
so all processes will need to close their device for the ls zero, so all processes will need to close their device for the
before the release will procede */ ls before the release will proceed. release also calls the
device_deregister above. Converting a positive return value
from release to zero means that userspace won't know when its
release was the final one, but it shouldn't need to know. */
dlm_put_lockspace(ls);
error = dlm_release_lockspace(lockspace, force); error = dlm_release_lockspace(lockspace, force);
if (error) if (error > 0)
create_misc_device(ls, ls->ls_name); error = 0;
out:
return error; return error;
} }
......
/* /*
* Copyright (C) 2006 Red Hat, Inc. All rights reserved. * Copyright (C) 2006-2008 Red Hat, Inc. All rights reserved.
* *
* This copyrighted material is made available to anyone wishing to use, * This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions * modify, copy, or redistribute it subject to the terms and conditions
...@@ -12,5 +12,6 @@ ...@@ -12,5 +12,6 @@
void dlm_user_add_ast(struct dlm_lkb *lkb, int type); void dlm_user_add_ast(struct dlm_lkb *lkb, int type);
int dlm_user_init(void); int dlm_user_init(void);
void dlm_user_exit(void); void dlm_user_exit(void);
int dlm_device_deregister(struct dlm_ls *ls);
#endif #endif
...@@ -144,7 +144,8 @@ static int gdlm_mount(char *table_name, char *host_data, ...@@ -144,7 +144,8 @@ static int gdlm_mount(char *table_name, char *host_data,
error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname), error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname),
&ls->dlm_lockspace, &ls->dlm_lockspace,
DLM_LSFL_FS | (nodir ? DLM_LSFL_NODIR : 0), DLM_LSFL_FS | DLM_LSFL_NEWEXCL |
(nodir ? DLM_LSFL_NODIR : 0),
GDLM_LVB_SIZE); GDLM_LVB_SIZE);
if (error) { if (error) {
log_error("dlm_new_lockspace error %d", error); log_error("dlm_new_lockspace error %d", error);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
******************************************************************************* *******************************************************************************
** **
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. ** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
** **
** This copyrighted material is made available to anyone wishing to use, ** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions ** modify, copy, or redistribute it subject to the terms and conditions
...@@ -65,9 +65,12 @@ struct dlm_lksb { ...@@ -65,9 +65,12 @@ struct dlm_lksb {
char * sb_lvbptr; char * sb_lvbptr;
}; };
/* dlm_new_lockspace() flags */
#define DLM_LSFL_NODIR 0x00000001 #define DLM_LSFL_NODIR 0x00000001
#define DLM_LSFL_TIMEWARN 0x00000002 #define DLM_LSFL_TIMEWARN 0x00000002
#define DLM_LSFL_FS 0x00000004 #define DLM_LSFL_FS 0x00000004
#define DLM_LSFL_NEWEXCL 0x00000008
#ifdef __KERNEL__ #ifdef __KERNEL__
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
/* Version of the device interface */ /* Version of the device interface */
#define DLM_DEVICE_VERSION_MAJOR 6 #define DLM_DEVICE_VERSION_MAJOR 6
#define DLM_DEVICE_VERSION_MINOR 0 #define DLM_DEVICE_VERSION_MINOR 0
#define DLM_DEVICE_VERSION_PATCH 0 #define DLM_DEVICE_VERSION_PATCH 1
/* struct passed to the lock write */ /* struct passed to the lock write */
struct dlm_lock_params { struct dlm_lock_params {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment