Commit 13dd7f87 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/dlm

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/dlm:
  dlm: choose better identifiers
  dlm: remove bkl
  dlm: fix address compare
  dlm: fix locking of lockspace list in dlm_scand
  dlm: detect available userspace daemon
  dlm: allow multiple lockspace creates
parents b0af205a 27eccf46
...@@ -14,6 +14,9 @@ ...@@ -14,6 +14,9 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/configfs.h> #include <linux/configfs.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <net/ipv6.h>
#include <net/sock.h> #include <net/sock.h>
#include "config.h" #include "config.h"
...@@ -377,24 +380,24 @@ static struct config_item_type node_type = { ...@@ -377,24 +380,24 @@ static struct config_item_type node_type = {
.ct_owner = THIS_MODULE, .ct_owner = THIS_MODULE,
}; };
static struct dlm_cluster *to_cluster(struct config_item *i) static struct dlm_cluster *config_item_to_cluster(struct config_item *i)
{ {
return i ? container_of(to_config_group(i), struct dlm_cluster, group) : return i ? container_of(to_config_group(i), struct dlm_cluster, group) :
NULL; NULL;
} }
static struct dlm_space *to_space(struct config_item *i) static struct dlm_space *config_item_to_space(struct config_item *i)
{ {
return i ? container_of(to_config_group(i), struct dlm_space, group) : return i ? container_of(to_config_group(i), struct dlm_space, group) :
NULL; NULL;
} }
static struct dlm_comm *to_comm(struct config_item *i) static struct dlm_comm *config_item_to_comm(struct config_item *i)
{ {
return i ? container_of(i, struct dlm_comm, item) : NULL; return i ? container_of(i, struct dlm_comm, item) : NULL;
} }
static struct dlm_node *to_node(struct config_item *i) static struct dlm_node *config_item_to_node(struct config_item *i)
{ {
return i ? container_of(i, struct dlm_node, item) : NULL; return i ? container_of(i, struct dlm_node, item) : NULL;
} }
...@@ -450,7 +453,7 @@ static struct config_group *make_cluster(struct config_group *g, ...@@ -450,7 +453,7 @@ static struct config_group *make_cluster(struct config_group *g,
static void drop_cluster(struct config_group *g, struct config_item *i) static void drop_cluster(struct config_group *g, struct config_item *i)
{ {
struct dlm_cluster *cl = to_cluster(i); struct dlm_cluster *cl = config_item_to_cluster(i);
struct config_item *tmp; struct config_item *tmp;
int j; int j;
...@@ -468,7 +471,7 @@ static void drop_cluster(struct config_group *g, struct config_item *i) ...@@ -468,7 +471,7 @@ static void drop_cluster(struct config_group *g, struct config_item *i)
static void release_cluster(struct config_item *i) static void release_cluster(struct config_item *i)
{ {
struct dlm_cluster *cl = to_cluster(i); struct dlm_cluster *cl = config_item_to_cluster(i);
kfree(cl->group.default_groups); kfree(cl->group.default_groups);
kfree(cl); kfree(cl);
} }
...@@ -507,7 +510,7 @@ static struct config_group *make_space(struct config_group *g, const char *name) ...@@ -507,7 +510,7 @@ static struct config_group *make_space(struct config_group *g, const char *name)
static void drop_space(struct config_group *g, struct config_item *i) static void drop_space(struct config_group *g, struct config_item *i)
{ {
struct dlm_space *sp = to_space(i); struct dlm_space *sp = config_item_to_space(i);
struct config_item *tmp; struct config_item *tmp;
int j; int j;
...@@ -524,7 +527,7 @@ static void drop_space(struct config_group *g, struct config_item *i) ...@@ -524,7 +527,7 @@ static void drop_space(struct config_group *g, struct config_item *i)
static void release_space(struct config_item *i) static void release_space(struct config_item *i)
{ {
struct dlm_space *sp = to_space(i); struct dlm_space *sp = config_item_to_space(i);
kfree(sp->group.default_groups); kfree(sp->group.default_groups);
kfree(sp); kfree(sp);
} }
...@@ -546,7 +549,7 @@ static struct config_item *make_comm(struct config_group *g, const char *name) ...@@ -546,7 +549,7 @@ static struct config_item *make_comm(struct config_group *g, const char *name)
static void drop_comm(struct config_group *g, struct config_item *i) static void drop_comm(struct config_group *g, struct config_item *i)
{ {
struct dlm_comm *cm = to_comm(i); struct dlm_comm *cm = config_item_to_comm(i);
if (local_comm == cm) if (local_comm == cm)
local_comm = NULL; local_comm = NULL;
dlm_lowcomms_close(cm->nodeid); dlm_lowcomms_close(cm->nodeid);
...@@ -557,13 +560,13 @@ static void drop_comm(struct config_group *g, struct config_item *i) ...@@ -557,13 +560,13 @@ static void drop_comm(struct config_group *g, struct config_item *i)
static void release_comm(struct config_item *i) static void release_comm(struct config_item *i)
{ {
struct dlm_comm *cm = to_comm(i); struct dlm_comm *cm = config_item_to_comm(i);
kfree(cm); kfree(cm);
} }
static struct config_item *make_node(struct config_group *g, const char *name) static struct config_item *make_node(struct config_group *g, const char *name)
{ {
struct dlm_space *sp = to_space(g->cg_item.ci_parent); struct dlm_space *sp = config_item_to_space(g->cg_item.ci_parent);
struct dlm_node *nd; struct dlm_node *nd;
nd = kzalloc(sizeof(struct dlm_node), GFP_KERNEL); nd = kzalloc(sizeof(struct dlm_node), GFP_KERNEL);
...@@ -585,8 +588,8 @@ static struct config_item *make_node(struct config_group *g, const char *name) ...@@ -585,8 +588,8 @@ static struct config_item *make_node(struct config_group *g, const char *name)
static void drop_node(struct config_group *g, struct config_item *i) static void drop_node(struct config_group *g, struct config_item *i)
{ {
struct dlm_space *sp = to_space(g->cg_item.ci_parent); struct dlm_space *sp = config_item_to_space(g->cg_item.ci_parent);
struct dlm_node *nd = to_node(i); struct dlm_node *nd = config_item_to_node(i);
mutex_lock(&sp->members_lock); mutex_lock(&sp->members_lock);
list_del(&nd->list); list_del(&nd->list);
...@@ -598,7 +601,7 @@ static void drop_node(struct config_group *g, struct config_item *i) ...@@ -598,7 +601,7 @@ static void drop_node(struct config_group *g, struct config_item *i)
static void release_node(struct config_item *i) static void release_node(struct config_item *i)
{ {
struct dlm_node *nd = to_node(i); struct dlm_node *nd = config_item_to_node(i);
kfree(nd); kfree(nd);
} }
...@@ -632,7 +635,7 @@ void dlm_config_exit(void) ...@@ -632,7 +635,7 @@ void dlm_config_exit(void)
static ssize_t show_cluster(struct config_item *i, struct configfs_attribute *a, static ssize_t show_cluster(struct config_item *i, struct configfs_attribute *a,
char *buf) char *buf)
{ {
struct dlm_cluster *cl = to_cluster(i); struct dlm_cluster *cl = config_item_to_cluster(i);
struct cluster_attribute *cla = struct cluster_attribute *cla =
container_of(a, struct cluster_attribute, attr); container_of(a, struct cluster_attribute, attr);
return cla->show ? cla->show(cl, buf) : 0; return cla->show ? cla->show(cl, buf) : 0;
...@@ -642,7 +645,7 @@ static ssize_t store_cluster(struct config_item *i, ...@@ -642,7 +645,7 @@ static ssize_t store_cluster(struct config_item *i,
struct configfs_attribute *a, struct configfs_attribute *a,
const char *buf, size_t len) const char *buf, size_t len)
{ {
struct dlm_cluster *cl = to_cluster(i); struct dlm_cluster *cl = config_item_to_cluster(i);
struct cluster_attribute *cla = struct cluster_attribute *cla =
container_of(a, struct cluster_attribute, attr); container_of(a, struct cluster_attribute, attr);
return cla->store ? cla->store(cl, buf, len) : -EINVAL; return cla->store ? cla->store(cl, buf, len) : -EINVAL;
...@@ -651,7 +654,7 @@ static ssize_t store_cluster(struct config_item *i, ...@@ -651,7 +654,7 @@ static ssize_t store_cluster(struct config_item *i,
static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a, static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a,
char *buf) char *buf)
{ {
struct dlm_comm *cm = to_comm(i); struct dlm_comm *cm = config_item_to_comm(i);
struct comm_attribute *cma = struct comm_attribute *cma =
container_of(a, struct comm_attribute, attr); container_of(a, struct comm_attribute, attr);
return cma->show ? cma->show(cm, buf) : 0; return cma->show ? cma->show(cm, buf) : 0;
...@@ -660,7 +663,7 @@ static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a, ...@@ -660,7 +663,7 @@ static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a,
static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a, static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a,
const char *buf, size_t len) const char *buf, size_t len)
{ {
struct dlm_comm *cm = to_comm(i); struct dlm_comm *cm = config_item_to_comm(i);
struct comm_attribute *cma = struct comm_attribute *cma =
container_of(a, struct comm_attribute, attr); container_of(a, struct comm_attribute, attr);
return cma->store ? cma->store(cm, buf, len) : -EINVAL; return cma->store ? cma->store(cm, buf, len) : -EINVAL;
...@@ -714,7 +717,7 @@ static ssize_t comm_addr_write(struct dlm_comm *cm, const char *buf, size_t len) ...@@ -714,7 +717,7 @@ static ssize_t comm_addr_write(struct dlm_comm *cm, const char *buf, size_t len)
static ssize_t show_node(struct config_item *i, struct configfs_attribute *a, static ssize_t show_node(struct config_item *i, struct configfs_attribute *a,
char *buf) char *buf)
{ {
struct dlm_node *nd = to_node(i); struct dlm_node *nd = config_item_to_node(i);
struct node_attribute *nda = struct node_attribute *nda =
container_of(a, struct node_attribute, attr); container_of(a, struct node_attribute, attr);
return nda->show ? nda->show(nd, buf) : 0; return nda->show ? nda->show(nd, buf) : 0;
...@@ -723,7 +726,7 @@ static ssize_t show_node(struct config_item *i, struct configfs_attribute *a, ...@@ -723,7 +726,7 @@ static ssize_t show_node(struct config_item *i, struct configfs_attribute *a,
static ssize_t store_node(struct config_item *i, struct configfs_attribute *a, static ssize_t store_node(struct config_item *i, struct configfs_attribute *a,
const char *buf, size_t len) const char *buf, size_t len)
{ {
struct dlm_node *nd = to_node(i); struct dlm_node *nd = config_item_to_node(i);
struct node_attribute *nda = struct node_attribute *nda =
container_of(a, struct node_attribute, attr); container_of(a, struct node_attribute, attr);
return nda->store ? nda->store(nd, buf, len) : -EINVAL; return nda->store ? nda->store(nd, buf, len) : -EINVAL;
...@@ -768,7 +771,7 @@ static struct dlm_space *get_space(char *name) ...@@ -768,7 +771,7 @@ static struct dlm_space *get_space(char *name)
i = config_group_find_item(space_list, name); i = config_group_find_item(space_list, name);
mutex_unlock(&space_list->cg_subsys->su_mutex); mutex_unlock(&space_list->cg_subsys->su_mutex);
return to_space(i); return config_item_to_space(i);
} }
static void put_space(struct dlm_space *sp) static void put_space(struct dlm_space *sp)
...@@ -776,6 +779,33 @@ static void put_space(struct dlm_space *sp) ...@@ -776,6 +779,33 @@ static void put_space(struct dlm_space *sp)
config_item_put(&sp->group.cg_item); config_item_put(&sp->group.cg_item);
} }
static int addr_compare(struct sockaddr_storage *x, struct sockaddr_storage *y)
{
switch (x->ss_family) {
case AF_INET: {
struct sockaddr_in *sinx = (struct sockaddr_in *)x;
struct sockaddr_in *siny = (struct sockaddr_in *)y;
if (sinx->sin_addr.s_addr != siny->sin_addr.s_addr)
return 0;
if (sinx->sin_port != siny->sin_port)
return 0;
break;
}
case AF_INET6: {
struct sockaddr_in6 *sinx = (struct sockaddr_in6 *)x;
struct sockaddr_in6 *siny = (struct sockaddr_in6 *)y;
if (!ipv6_addr_equal(&sinx->sin6_addr, &siny->sin6_addr))
return 0;
if (sinx->sin6_port != siny->sin6_port)
return 0;
break;
}
default:
return 0;
}
return 1;
}
static struct dlm_comm *get_comm(int nodeid, struct sockaddr_storage *addr) static struct dlm_comm *get_comm(int nodeid, struct sockaddr_storage *addr)
{ {
struct config_item *i; struct config_item *i;
...@@ -788,7 +818,7 @@ static struct dlm_comm *get_comm(int nodeid, struct sockaddr_storage *addr) ...@@ -788,7 +818,7 @@ static struct dlm_comm *get_comm(int nodeid, struct sockaddr_storage *addr)
mutex_lock(&clusters_root.subsys.su_mutex); mutex_lock(&clusters_root.subsys.su_mutex);
list_for_each_entry(i, &comm_list->cg_children, ci_entry) { list_for_each_entry(i, &comm_list->cg_children, ci_entry) {
cm = to_comm(i); cm = config_item_to_comm(i);
if (nodeid) { if (nodeid) {
if (cm->nodeid != nodeid) if (cm->nodeid != nodeid)
...@@ -797,8 +827,7 @@ static struct dlm_comm *get_comm(int nodeid, struct sockaddr_storage *addr) ...@@ -797,8 +827,7 @@ static struct dlm_comm *get_comm(int nodeid, struct sockaddr_storage *addr)
config_item_get(i); config_item_get(i);
break; break;
} else { } else {
if (!cm->addr_count || if (!cm->addr_count || !addr_compare(cm->addr[0], addr))
memcmp(cm->addr[0], addr, sizeof(*addr)))
continue; continue;
found = 1; found = 1;
config_item_get(i); config_item_get(i);
......
...@@ -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,8 +441,11 @@ struct dlm_ls { ...@@ -441,8 +441,11 @@ 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_ */
unsigned long ls_scan_time;
struct kobject ls_kobj; struct kobject ls_kobj;
struct dlm_rsbtable *ls_rsbtbl; struct dlm_rsbtable *ls_rsbtbl;
......
...@@ -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;
...@@ -211,19 +212,41 @@ void dlm_lockspace_exit(void) ...@@ -211,19 +212,41 @@ void dlm_lockspace_exit(void)
kset_unregister(dlm_kset); kset_unregister(dlm_kset);
} }
static struct dlm_ls *find_ls_to_scan(void)
{
struct dlm_ls *ls;
spin_lock(&lslist_lock);
list_for_each_entry(ls, &lslist, ls_list) {
if (time_after_eq(jiffies, ls->ls_scan_time +
dlm_config.ci_scan_secs * HZ)) {
spin_unlock(&lslist_lock);
return ls;
}
}
spin_unlock(&lslist_lock);
return NULL;
}
static int dlm_scand(void *data) static int dlm_scand(void *data)
{ {
struct dlm_ls *ls; struct dlm_ls *ls;
int timeout_jiffies = dlm_config.ci_scan_secs * HZ;
while (!kthread_should_stop()) { while (!kthread_should_stop()) {
list_for_each_entry(ls, &lslist, ls_list) { ls = find_ls_to_scan();
if (ls) {
if (dlm_lock_recovery_try(ls)) { if (dlm_lock_recovery_try(ls)) {
ls->ls_scan_time = jiffies;
dlm_scan_rsbs(ls); dlm_scan_rsbs(ls);
dlm_scan_timeout(ls); dlm_scan_timeout(ls);
dlm_unlock_recovery(ls); dlm_unlock_recovery(ls);
} else {
ls->ls_scan_time += HZ;
} }
} else {
schedule_timeout_interruptible(timeout_jiffies);
} }
schedule_timeout_interruptible(dlm_config.ci_scan_secs * HZ);
} }
return 0; return 0;
} }
...@@ -246,23 +269,6 @@ static void dlm_scand_stop(void) ...@@ -246,23 +269,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 +333,7 @@ static void remove_lockspace(struct dlm_ls *ls) ...@@ -327,6 +333,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 +388,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, ...@@ -381,7 +388,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 +400,37 @@ static int new_lockspace(char *name, int namelen, void **lockspace, ...@@ -393,12 +400,37 @@ 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); if (!dlm_user_daemon_available()) {
if (ls) { module_put(THIS_MODULE);
*lockspace = ls; return -EUNATCH;
}
error = 0;
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)
...@@ -408,6 +440,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, ...@@ -408,6 +440,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
ls->ls_lvblen = lvblen; ls->ls_lvblen = lvblen;
ls->ls_count = 0; ls->ls_count = 0;
ls->ls_flags = 0; ls->ls_flags = 0;
ls->ls_scan_time = jiffies;
if (flags & DLM_LSFL_TIMEWARN) if (flags & DLM_LSFL_TIMEWARN)
set_bit(LSFL_TIMEWARN, &ls->ls_flags); set_bit(LSFL_TIMEWARN, &ls->ls_flags);
...@@ -418,8 +451,9 @@ static int new_lockspace(char *name, int namelen, void **lockspace, ...@@ -418,8 +451,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 +544,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, ...@@ -510,6 +544,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 +583,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, ...@@ -548,7 +583,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,13 +670,34 @@ static int release_lockspace(struct dlm_ls *ls, int force) ...@@ -635,13 +670,34 @@ 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)
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 (busy > force) if (rv) {
return -EBUSY; log_debug(ls, "release_lockspace no remove %d", rv);
return rv;
}
dlm_device_deregister(ls);
if (force < 3) if (force < 3 && dlm_user_daemon_available())
do_uevent(ls, 0); do_uevent(ls, 0);
dlm_recoverd_stop(ls); dlm_recoverd_stop(ls);
...@@ -720,15 +776,10 @@ static int release_lockspace(struct dlm_ls *ls, int force) ...@@ -720,15 +776,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 +801,38 @@ static int release_lockspace(struct dlm_ls *ls, int force) ...@@ -750,11 +801,38 @@ 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;
}
void dlm_stop_lockspaces(void)
{
struct dlm_ls *ls;
restart:
spin_lock(&lslist_lock);
list_for_each_entry(ls, &lslist, ls_list) {
if (!test_bit(LSFL_RUNNING, &ls->ls_flags))
continue;
spin_unlock(&lslist_lock);
log_error(ls, "no userland control daemon, stopping lockspace");
dlm_ls_stop(ls);
goto restart;
}
spin_unlock(&lslist_lock);
} }
...@@ -20,6 +20,7 @@ struct dlm_ls *dlm_find_lockspace_global(uint32_t id); ...@@ -20,6 +20,7 @@ struct dlm_ls *dlm_find_lockspace_global(uint32_t id);
struct dlm_ls *dlm_find_lockspace_local(void *id); struct dlm_ls *dlm_find_lockspace_local(void *id);
struct dlm_ls *dlm_find_lockspace_device(int minor); struct dlm_ls *dlm_find_lockspace_device(int minor);
void dlm_put_lockspace(struct dlm_ls *ls); void dlm_put_lockspace(struct dlm_ls *ls);
void dlm_stop_lockspaces(void);
#endif /* __LOCKSPACE_DOT_H__ */ #endif /* __LOCKSPACE_DOT_H__ */
/* /*
* 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
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/smp_lock.h>
#include <linux/dlm.h> #include <linux/dlm.h>
#include <linux/dlm_device.h> #include <linux/dlm_device.h>
...@@ -27,6 +26,8 @@ ...@@ -27,6 +26,8 @@
static const char name_prefix[] = "dlm"; static const char name_prefix[] = "dlm";
static const struct file_operations device_fops; static const struct file_operations device_fops;
static atomic_t dlm_monitor_opened;
static int dlm_monitor_unused = 1;
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
...@@ -340,10 +341,15 @@ static int device_user_deadlock(struct dlm_user_proc *proc, ...@@ -340,10 +341,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 +369,22 @@ fail: ...@@ -363,6 +369,22 @@ fail:
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 +419,7 @@ static int device_create_lockspace(struct dlm_lspace_params *params) ...@@ -397,7 +419,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 +443,22 @@ static int device_remove_lockspace(struct dlm_lspace_params *params) ...@@ -421,31 +443,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;
} }
...@@ -623,17 +636,13 @@ static int device_open(struct inode *inode, struct file *file) ...@@ -623,17 +636,13 @@ static int device_open(struct inode *inode, struct file *file)
struct dlm_user_proc *proc; struct dlm_user_proc *proc;
struct dlm_ls *ls; struct dlm_ls *ls;
lock_kernel();
ls = dlm_find_lockspace_device(iminor(inode)); ls = dlm_find_lockspace_device(iminor(inode));
if (!ls) { if (!ls)
unlock_kernel();
return -ENOENT; return -ENOENT;
}
proc = kzalloc(sizeof(struct dlm_user_proc), GFP_KERNEL); proc = kzalloc(sizeof(struct dlm_user_proc), GFP_KERNEL);
if (!proc) { if (!proc) {
dlm_put_lockspace(ls); dlm_put_lockspace(ls);
unlock_kernel();
return -ENOMEM; return -ENOMEM;
} }
...@@ -645,7 +654,6 @@ static int device_open(struct inode *inode, struct file *file) ...@@ -645,7 +654,6 @@ static int device_open(struct inode *inode, struct file *file)
spin_lock_init(&proc->locks_spin); spin_lock_init(&proc->locks_spin);
init_waitqueue_head(&proc->wait); init_waitqueue_head(&proc->wait);
file->private_data = proc; file->private_data = proc;
unlock_kernel();
return 0; return 0;
} }
...@@ -878,9 +886,28 @@ static unsigned int device_poll(struct file *file, poll_table *wait) ...@@ -878,9 +886,28 @@ static unsigned int device_poll(struct file *file, poll_table *wait)
return 0; return 0;
} }
int dlm_user_daemon_available(void)
{
/* dlm_controld hasn't started (or, has started, but not
properly populated configfs) */
if (!dlm_our_nodeid())
return 0;
/* This is to deal with versions of dlm_controld that don't
know about the monitor device. We assume that if the
dlm_controld was started (above), but the monitor device
was never opened, that it's an old version. dlm_controld
should open the monitor device before populating configfs. */
if (dlm_monitor_unused)
return 1;
return atomic_read(&dlm_monitor_opened) ? 1 : 0;
}
static int ctl_device_open(struct inode *inode, struct file *file) static int ctl_device_open(struct inode *inode, struct file *file)
{ {
cycle_kernel_lock();
file->private_data = NULL; file->private_data = NULL;
return 0; return 0;
} }
...@@ -890,6 +917,20 @@ static int ctl_device_close(struct inode *inode, struct file *file) ...@@ -890,6 +917,20 @@ static int ctl_device_close(struct inode *inode, struct file *file)
return 0; return 0;
} }
static int monitor_device_open(struct inode *inode, struct file *file)
{
atomic_inc(&dlm_monitor_opened);
dlm_monitor_unused = 0;
return 0;
}
static int monitor_device_close(struct inode *inode, struct file *file)
{
if (atomic_dec_and_test(&dlm_monitor_opened))
dlm_stop_lockspaces();
return 0;
}
static const struct file_operations device_fops = { static const struct file_operations device_fops = {
.open = device_open, .open = device_open,
.release = device_close, .release = device_close,
...@@ -913,19 +954,42 @@ static struct miscdevice ctl_device = { ...@@ -913,19 +954,42 @@ static struct miscdevice ctl_device = {
.minor = MISC_DYNAMIC_MINOR, .minor = MISC_DYNAMIC_MINOR,
}; };
static const struct file_operations monitor_device_fops = {
.open = monitor_device_open,
.release = monitor_device_close,
.owner = THIS_MODULE,
};
static struct miscdevice monitor_device = {
.name = "dlm-monitor",
.fops = &monitor_device_fops,
.minor = MISC_DYNAMIC_MINOR,
};
int __init dlm_user_init(void) int __init dlm_user_init(void)
{ {
int error; int error;
atomic_set(&dlm_monitor_opened, 0);
error = misc_register(&ctl_device); error = misc_register(&ctl_device);
if (error) if (error) {
log_print("misc_register failed for control device"); log_print("misc_register failed for control device");
goto out;
}
error = misc_register(&monitor_device);
if (error) {
log_print("misc_register failed for monitor device");
misc_deregister(&ctl_device);
}
out:
return error; return error;
} }
void dlm_user_exit(void) void dlm_user_exit(void)
{ {
misc_deregister(&ctl_device); misc_deregister(&ctl_device);
misc_deregister(&monitor_device);
} }
/* /*
* 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,7 @@ ...@@ -12,5 +12,7 @@
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);
int dlm_user_daemon_available(void);
#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