Skip to content

Commit

Permalink
Merge branch 'server-cluster-locking-api' of git://linux-nfs.org/~bfi…
Browse files Browse the repository at this point in the history
…elds/linux

* 'server-cluster-locking-api' of git://linux-nfs.org/~bfields/linux:
  gfs2: nfs lock support for gfs2
  lockd: add code to handle deferred lock requests
  lockd: always preallocate block in nlmsvc_lock()
  lockd: handle test_lock deferrals
  lockd: pass cookie in nlmsvc_testlock
  lockd: handle fl_grant callbacks
  lockd: save lock state on deferral
  locks: add fl_grant callback for asynchronous lock return
  nfsd4: Convert NFSv4 to new lock interface
  locks: add lock cancel command
  locks: allow {vfs,posix}_lock_file to return conflicting lock
  locks: factor out generic/filesystem switch from setlock code
  locks: factor out generic/filesystem switch from test_lock
  locks: give posix_test_lock same interface as ->lock
  locks: make ->lock release private data before returning in GETLK case
  locks: create posix-to-flock helper functions
  locks: trivial removal of unnecessary parentheses
  • Loading branch information
Linus Torvalds committed May 7, 2007
2 parents 0f9008e + 586759f commit 2d56d3c
Show file tree
Hide file tree
Showing 15 changed files with 546 additions and 205 deletions.
3 changes: 1 addition & 2 deletions fs/fuse/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -738,8 +738,7 @@ static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl)

if (cmd == F_GETLK) {
if (fc->no_lock) {
if (!posix_test_lock(file, fl, fl))
fl->fl_type = F_UNLCK;
posix_test_lock(file, fl);
err = 0;
} else
err = fuse_getlk(file, fl);
Expand Down
109 changes: 99 additions & 10 deletions fs/gfs2/locking/dlm/plock.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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)) {
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
}
Expand All @@ -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));

Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
8 changes: 1 addition & 7 deletions fs/gfs2/locking/nolock/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,7 @@ static void nolock_unhold_lvb(void *lock, char *lvb)
static int nolock_plock_get(void *lockspace, struct lm_lockname *name,
struct file *file, struct file_lock *fl)
{
struct file_lock tmp;
int ret;

ret = posix_test_lock(file, fl, &tmp);
fl->fl_type = F_UNLCK;
if (ret)
memcpy(fl, &tmp, sizeof(struct file_lock));
posix_test_lock(file, fl);

return 0;
}
Expand Down
12 changes: 6 additions & 6 deletions fs/gfs2/ops_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -513,18 +513,18 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)

if (sdp->sd_args.ar_localflocks) {
if (IS_GETLK(cmd)) {
struct file_lock tmp;
int ret;
ret = posix_test_lock(file, fl, &tmp);
fl->fl_type = F_UNLCK;
if (ret)
memcpy(fl, &tmp, sizeof(struct file_lock));
posix_test_lock(file, fl);
return 0;
} else {
return posix_lock_file_wait(file, fl);
}
}

if (cmd == F_CANCELLK) {
/* Hack: */
cmd = F_SETLK;
fl->fl_type = F_UNLCK;
}
if (IS_GETLK(cmd))
return gfs2_lm_plock_get(sdp, &name, file, fl);
else if (fl->fl_type == F_UNLCK)
Expand Down
6 changes: 5 additions & 1 deletion fs/lockd/svc4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,9 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;

/* Now check for conflicting locks */
resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock);
resp->status = nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie);
if (resp->status == nlm_drop_reply)
return rpc_drop_reply;

dprintk("lockd: TEST4 status %d\n", ntohl(resp->status));
nlm_release_host(host);
Expand Down Expand Up @@ -143,6 +145,8 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Now try to lock the file */
resp->status = nlmsvc_lock(rqstp, file, &argp->lock,
argp->block, &argp->cookie);
if (resp->status == nlm_drop_reply)
return rpc_drop_reply;

dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
nlm_release_host(host);
Expand Down
Loading

0 comments on commit 2d56d3c

Please sign in to comment.