summaryrefslogtreecommitdiff
path: root/fs/gfs2/locking/dlm
diff options
context:
space:
mode:
Diffstat (limited to 'fs/gfs2/locking/dlm')
-rw-r--r--fs/gfs2/locking/dlm/lock.c14
-rw-r--r--fs/gfs2/locking/dlm/lock_dlm.h3
-rw-r--r--fs/gfs2/locking/dlm/plock.c109
-rw-r--r--fs/gfs2/locking/dlm/sysfs.c2
4 files changed, 108 insertions, 20 deletions
diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c
index b167addf9fd1..c305255bfe8a 100644
--- a/fs/gfs2/locking/dlm/lock.c
+++ b/fs/gfs2/locking/dlm/lock.c
@@ -151,7 +151,7 @@ static inline unsigned int make_flags(struct gdlm_lock *lp,
/* make_strname - convert GFS lock numbers to a string */
-static inline void make_strname(struct lm_lockname *lockname,
+static inline void make_strname(const struct lm_lockname *lockname,
struct gdlm_strname *str)
{
sprintf(str->name, "%8x%16llx", lockname->ln_type,
@@ -169,6 +169,7 @@ static int gdlm_create_lp(struct gdlm_ls *ls, struct lm_lockname *name,
return -ENOMEM;
lp->lockname = *name;
+ make_strname(name, &lp->strname);
lp->ls = ls;
lp->cur = DLM_LOCK_IV;
lp->lvb = NULL;
@@ -227,7 +228,6 @@ void gdlm_put_lock(void *lock)
unsigned int gdlm_do_lock(struct gdlm_lock *lp)
{
struct gdlm_ls *ls = lp->ls;
- struct gdlm_strname str;
int error, bast = 1;
/*
@@ -249,8 +249,6 @@ unsigned int gdlm_do_lock(struct gdlm_lock *lp)
if (test_bit(LFL_NOBAST, &lp->flags))
bast = 0;
- make_strname(&lp->lockname, &str);
-
set_bit(LFL_ACTIVE, &lp->flags);
log_debug("lk %x,%llx id %x %d,%d %x", lp->lockname.ln_type,
@@ -258,8 +256,8 @@ unsigned int gdlm_do_lock(struct gdlm_lock *lp)
lp->cur, lp->req, lp->lkf);
error = dlm_lock(ls->dlm_lockspace, lp->req, &lp->lksb, lp->lkf,
- str.name, str.namelen, 0, gdlm_ast, lp,
- bast ? gdlm_bast : NULL);
+ lp->strname.name, lp->strname.namelen, 0, gdlm_ast,
+ lp, bast ? gdlm_bast : NULL);
if ((error == -EAGAIN) && (lp->lkf & DLM_LKF_NOQUEUE)) {
lp->lksb.sb_status = -EAGAIN;
@@ -268,7 +266,7 @@ unsigned int gdlm_do_lock(struct gdlm_lock *lp)
}
if (error) {
- log_debug("%s: gdlm_lock %x,%llx err=%d cur=%d req=%d lkf=%x "
+ log_error("%s: gdlm_lock %x,%llx err=%d cur=%d req=%d lkf=%x "
"flags=%lx", ls->fsname, lp->lockname.ln_type,
(unsigned long long)lp->lockname.ln_number, error,
lp->cur, lp->req, lp->lkf, lp->flags);
@@ -296,7 +294,7 @@ static unsigned int gdlm_do_unlock(struct gdlm_lock *lp)
error = dlm_unlock(ls->dlm_lockspace, lp->lksb.sb_lkid, lkf, NULL, lp);
if (error) {
- log_debug("%s: gdlm_unlock %x,%llx err=%d cur=%d req=%d lkf=%x "
+ log_error("%s: gdlm_unlock %x,%llx err=%d cur=%d req=%d lkf=%x "
"flags=%lx", ls->fsname, lp->lockname.ln_type,
(unsigned long long)lp->lockname.ln_number, error,
lp->cur, lp->req, lp->lkf, lp->flags);
diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h
index a87c7bf3c568..d074c6e6f9bf 100644
--- a/fs/gfs2/locking/dlm/lock_dlm.h
+++ b/fs/gfs2/locking/dlm/lock_dlm.h
@@ -36,7 +36,7 @@
#define GDLM_STRNAME_BYTES 24
#define GDLM_LVB_SIZE 32
-#define GDLM_DROP_COUNT 200000
+#define GDLM_DROP_COUNT 0
#define GDLM_DROP_PERIOD 60
#define GDLM_NAME_LEN 128
@@ -106,6 +106,7 @@ enum {
struct gdlm_lock {
struct gdlm_ls *ls;
struct lm_lockname lockname;
+ struct gdlm_strname strname;
char *lvb;
struct dlm_lksb lksb;
diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c
index 1dd4215b83d0..f82495e18c2d 100644
--- a/fs/gfs2/locking/dlm/plock.c
+++ b/fs/gfs2/locking/dlm/plock.c
@@ -25,6 +25,15 @@ struct plock_op {
struct gdlm_plock_info info;
};
+struct plock_xop {
+ struct plock_op xop;
+ void *callback;
+ void *fl;
+ void *file;
+ struct file_lock flc;
+};
+
+
static inline void set_version(struct gdlm_plock_info *info)
{
info->version[0] = GDLM_PLOCK_VERSION_MAJOR;
@@ -64,12 +73,14 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
{
struct gdlm_ls *ls = lockspace;
struct plock_op *op;
+ struct plock_xop *xop;
int rv;
- op = kzalloc(sizeof(*op), GFP_KERNEL);
- if (!op)
+ xop = kzalloc(sizeof(*xop), GFP_KERNEL);
+ if (!xop)
return -ENOMEM;
+ op = &xop->xop;
op->info.optype = GDLM_PLOCK_OP_LOCK;
op->info.pid = fl->fl_pid;
op->info.ex = (fl->fl_type == F_WRLCK);
@@ -79,9 +90,21 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
op->info.start = fl->fl_start;
op->info.end = fl->fl_end;
op->info.owner = (__u64)(long) fl->fl_owner;
+ if (fl->fl_lmops && fl->fl_lmops->fl_grant) {
+ xop->callback = fl->fl_lmops->fl_grant;
+ locks_init_lock(&xop->flc);
+ locks_copy_lock(&xop->flc, fl);
+ xop->fl = fl;
+ xop->file = file;
+ } else
+ xop->callback = NULL;
send_op(op);
- wait_event(recv_wq, (op->done != 0));
+
+ if (xop->callback == NULL)
+ wait_event(recv_wq, (op->done != 0));
+ else
+ return -EINPROGRESS;
spin_lock(&ops_lock);
if (!list_empty(&op->list)) {
@@ -99,7 +122,63 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
(unsigned long long)name->ln_number);
}
- kfree(op);
+ kfree(xop);
+ return rv;
+}
+
+/* Returns failure iff a succesful lock operation should be canceled */
+static int gdlm_plock_callback(struct plock_op *op)
+{
+ struct file *file;
+ struct file_lock *fl;
+ struct file_lock *flc;
+ int (*notify)(void *, void *, int) = NULL;
+ struct plock_xop *xop = (struct plock_xop *)op;
+ int rv = 0;
+
+ spin_lock(&ops_lock);
+ if (!list_empty(&op->list)) {
+ printk(KERN_INFO "plock op on list\n");
+ list_del(&op->list);
+ }
+ spin_unlock(&ops_lock);
+
+ /* check if the following 2 are still valid or make a copy */
+ file = xop->file;
+ flc = &xop->flc;
+ fl = xop->fl;
+ notify = xop->callback;
+
+ if (op->info.rv) {
+ notify(flc, NULL, op->info.rv);
+ goto out;
+ }
+
+ /* got fs lock; bookkeep locally as well: */
+ flc->fl_flags &= ~FL_SLEEP;
+ if (posix_lock_file(file, flc, NULL)) {
+ /*
+ * This can only happen in the case of kmalloc() failure.
+ * The filesystem's own lock is the authoritative lock,
+ * so a failure to get the lock locally is not a disaster.
+ * As long as GFS cannot reliably cancel locks (especially
+ * in a low-memory situation), we're better off ignoring
+ * this failure than trying to recover.
+ */
+ log_error("gdlm_plock: vfs lock error file %p fl %p",
+ file, fl);
+ }
+
+ rv = notify(flc, NULL, 0);
+ if (rv) {
+ /* XXX: We need to cancel the fs lock here: */
+ printk("gfs2 lock granted after lock request failed;"
+ " dangling lock!\n");
+ goto out;
+ }
+
+out:
+ kfree(xop);
return rv;
}
@@ -138,6 +217,9 @@ int gdlm_punlock(void *lockspace, struct lm_lockname *name,
rv = op->info.rv;
+ if (rv == -ENOENT)
+ rv = 0;
+
kfree(op);
return rv;
}
@@ -161,6 +243,7 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
op->info.start = fl->fl_start;
op->info.end = fl->fl_end;
+
send_op(op);
wait_event(recv_wq, (op->done != 0));
@@ -173,9 +256,10 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
rv = op->info.rv;
- if (rv == 0)
- fl->fl_type = F_UNLCK;
- else if (rv > 0) {
+ fl->fl_type = F_UNLCK;
+ if (rv == -ENOENT)
+ rv = 0;
+ else if (rv == 0 && op->info.pid != fl->fl_pid) {
fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK;
fl->fl_pid = op->info.pid;
fl->fl_start = op->info.start;
@@ -243,9 +327,14 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
}
spin_unlock(&ops_lock);
- if (found)
- wake_up(&recv_wq);
- else
+ if (found) {
+ struct plock_xop *xop;
+ xop = (struct plock_xop *)op;
+ if (xop->callback)
+ count = gdlm_plock_callback(op);
+ else
+ wake_up(&recv_wq);
+ } else
printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid,
(unsigned long long)info.number);
return count;
diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c
index 4746b884662d..d9fe3ca40e18 100644
--- a/fs/gfs2/locking/dlm/sysfs.c
+++ b/fs/gfs2/locking/dlm/sysfs.c
@@ -190,7 +190,6 @@ static struct kobj_type gdlm_ktype = {
};
static struct kset gdlm_kset = {
- .subsys = &kernel_subsys,
.kobj = {.name = "lock_dlm",},
.ktype = &gdlm_ktype,
};
@@ -225,6 +224,7 @@ int gdlm_sysfs_init(void)
{
int error;
+ kobj_set_kset_s(&gdlm_kset, kernel_subsys);
error = kset_register(&gdlm_kset);
if (error)
printk("lock_dlm: cannot register kset %d\n", error);