mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-29 07:04:10 +08:00
gfs2: nfs lock support for gfs2
Add NFS lock support to GFS2. Signed-off-by: Marc Eshel <eshel@almaden.ibm.com> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Acked-by: Steven Whitehouse <swhiteho@redhat.com>
This commit is contained in:
parent
1a8322b2b0
commit
586759f03e
@ -25,6 +25,15 @@ struct plock_op {
|
|||||||
struct gdlm_plock_info info;
|
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)
|
static inline void set_version(struct gdlm_plock_info *info)
|
||||||
{
|
{
|
||||||
info->version[0] = GDLM_PLOCK_VERSION_MAJOR;
|
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 gdlm_ls *ls = lockspace;
|
||||||
struct plock_op *op;
|
struct plock_op *op;
|
||||||
|
struct plock_xop *xop;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
op = kzalloc(sizeof(*op), GFP_KERNEL);
|
xop = kzalloc(sizeof(*xop), GFP_KERNEL);
|
||||||
if (!op)
|
if (!xop)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
op = &xop->xop;
|
||||||
op->info.optype = GDLM_PLOCK_OP_LOCK;
|
op->info.optype = GDLM_PLOCK_OP_LOCK;
|
||||||
op->info.pid = fl->fl_pid;
|
op->info.pid = fl->fl_pid;
|
||||||
op->info.ex = (fl->fl_type == F_WRLCK);
|
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.start = fl->fl_start;
|
||||||
op->info.end = fl->fl_end;
|
op->info.end = fl->fl_end;
|
||||||
op->info.owner = (__u64)(long) fl->fl_owner;
|
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);
|
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);
|
spin_lock(&ops_lock);
|
||||||
if (!list_empty(&op->list)) {
|
if (!list_empty(&op->list)) {
|
||||||
@ -99,7 +122,63 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
|
|||||||
(unsigned long long)name->ln_number);
|
(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;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,6 +217,9 @@ int gdlm_punlock(void *lockspace, struct lm_lockname *name,
|
|||||||
|
|
||||||
rv = op->info.rv;
|
rv = op->info.rv;
|
||||||
|
|
||||||
|
if (rv == -ENOENT)
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
kfree(op);
|
kfree(op);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -161,6 +243,7 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
|
|||||||
op->info.start = fl->fl_start;
|
op->info.start = fl->fl_start;
|
||||||
op->info.end = fl->fl_end;
|
op->info.end = fl->fl_end;
|
||||||
|
|
||||||
|
|
||||||
send_op(op);
|
send_op(op);
|
||||||
wait_event(recv_wq, (op->done != 0));
|
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;
|
rv = op->info.rv;
|
||||||
|
|
||||||
if (rv == 0)
|
fl->fl_type = F_UNLCK;
|
||||||
fl->fl_type = F_UNLCK;
|
if (rv == -ENOENT)
|
||||||
else if (rv > 0) {
|
rv = 0;
|
||||||
|
else if (rv == 0 && op->info.pid != fl->fl_pid) {
|
||||||
fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK;
|
fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK;
|
||||||
fl->fl_pid = op->info.pid;
|
fl->fl_pid = op->info.pid;
|
||||||
fl->fl_start = op->info.start;
|
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);
|
spin_unlock(&ops_lock);
|
||||||
|
|
||||||
if (found)
|
if (found) {
|
||||||
wake_up(&recv_wq);
|
struct plock_xop *xop;
|
||||||
else
|
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,
|
printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid,
|
||||||
(unsigned long long)info.number);
|
(unsigned long long)info.number);
|
||||||
return count;
|
return count;
|
||||||
|
@ -520,6 +520,11 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cmd == F_CANCELLK) {
|
||||||
|
/* Hack: */
|
||||||
|
cmd = F_SETLK;
|
||||||
|
fl->fl_type = F_UNLCK;
|
||||||
|
}
|
||||||
if (IS_GETLK(cmd))
|
if (IS_GETLK(cmd))
|
||||||
return gfs2_lm_plock_get(sdp, &name, file, fl);
|
return gfs2_lm_plock_get(sdp, &name, file, fl);
|
||||||
else if (fl->fl_type == F_UNLCK)
|
else if (fl->fl_type == F_UNLCK)
|
||||||
|
Loading…
Reference in New Issue
Block a user