提交 150b3934 编写于 作者: M Marc Eshel 提交者: J. Bruce Fields

locks: allow {vfs,posix}_lock_file to return conflicting lock

The nfsv4 protocol's lock operation, in the case of a conflict, returns
information about the conflicting lock.

It's unclear how clients can use this, so for now we're not going so far as to
add a filesystem method that can return a conflicting lock, but we may as well
return something in the local case when it's easy to.
Signed-off-by: NMarc Eshel <eshel@almaden.ibm.com>
Signed-off-by: N"J. Bruce Fields" <bfields@citi.umich.edu>
上级 7723ec97
...@@ -363,7 +363,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, ...@@ -363,7 +363,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
} else } else
lock = &block->b_call->a_args.lock; lock = &block->b_call->a_args.lock;
error = posix_lock_file(file->f_file, &lock->fl); error = posix_lock_file(file->f_file, &lock->fl, NULL);
lock->fl.fl_flags &= ~FL_SLEEP; lock->fl.fl_flags &= ~FL_SLEEP;
dprintk("lockd: posix_lock_file returned %d\n", error); dprintk("lockd: posix_lock_file returned %d\n", error);
...@@ -467,7 +467,7 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock) ...@@ -467,7 +467,7 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
nlmsvc_cancel_blocked(file, lock); nlmsvc_cancel_blocked(file, lock);
lock->fl.fl_type = F_UNLCK; lock->fl.fl_type = F_UNLCK;
error = posix_lock_file(file->f_file, &lock->fl); error = posix_lock_file(file->f_file, &lock->fl, NULL);
return (error < 0)? nlm_lck_denied_nolocks : nlm_granted; return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;
} }
...@@ -569,7 +569,7 @@ nlmsvc_grant_blocked(struct nlm_block *block) ...@@ -569,7 +569,7 @@ nlmsvc_grant_blocked(struct nlm_block *block)
/* Try the lock operation again */ /* Try the lock operation again */
lock->fl.fl_flags |= FL_SLEEP; lock->fl.fl_flags |= FL_SLEEP;
error = posix_lock_file(file->f_file, &lock->fl); error = posix_lock_file(file->f_file, &lock->fl, NULL);
lock->fl.fl_flags &= ~FL_SLEEP; lock->fl.fl_flags &= ~FL_SLEEP;
switch (error) { switch (error) {
......
...@@ -182,7 +182,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, ...@@ -182,7 +182,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
lock.fl_type = F_UNLCK; lock.fl_type = F_UNLCK;
lock.fl_start = 0; lock.fl_start = 0;
lock.fl_end = OFFSET_MAX; lock.fl_end = OFFSET_MAX;
if (posix_lock_file(file->f_file, &lock) < 0) { if (posix_lock_file(file->f_file, &lock, NULL) < 0) {
printk("lockd: unlock failure in %s:%d\n", printk("lockd: unlock failure in %s:%d\n",
__FILE__, __LINE__); __FILE__, __LINE__);
return 1; return 1;
......
...@@ -801,7 +801,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) ...@@ -801,7 +801,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
return error; return error;
} }
static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request, struct file_lock *conflock) static int __posix_lock_file(struct inode *inode, struct file_lock *request, struct file_lock *conflock)
{ {
struct file_lock *fl; struct file_lock *fl;
struct file_lock *new_fl = NULL; struct file_lock *new_fl = NULL;
...@@ -1007,6 +1007,7 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request ...@@ -1007,6 +1007,7 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
* posix_lock_file - Apply a POSIX-style lock to a file * posix_lock_file - Apply a POSIX-style lock to a file
* @filp: The file to apply the lock to * @filp: The file to apply the lock to
* @fl: The lock to be applied * @fl: The lock to be applied
* @conflock: Place to return a copy of the conflicting lock, if found.
* *
* Add a POSIX style lock to a file. * Add a POSIX style lock to a file.
* We merge adjacent & overlapping locks whenever possible. * We merge adjacent & overlapping locks whenever possible.
...@@ -1016,26 +1017,12 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request ...@@ -1016,26 +1017,12 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
* whether or not a lock was successfully freed by testing the return * whether or not a lock was successfully freed by testing the return
* value for -ENOENT. * value for -ENOENT.
*/ */
int posix_lock_file(struct file *filp, struct file_lock *fl) int posix_lock_file(struct file *filp, struct file_lock *fl,
{
return __posix_lock_file_conf(filp->f_path.dentry->d_inode, fl, NULL);
}
EXPORT_SYMBOL(posix_lock_file);
/**
* posix_lock_file_conf - Apply a POSIX-style lock to a file
* @filp: The file to apply the lock to
* @fl: The lock to be applied
* @conflock: Place to return a copy of the conflicting lock, if found.
*
* Except for the conflock parameter, acts just like posix_lock_file.
*/
int posix_lock_file_conf(struct file *filp, struct file_lock *fl,
struct file_lock *conflock) struct file_lock *conflock)
{ {
return __posix_lock_file_conf(filp->f_path.dentry->d_inode, fl, conflock); return __posix_lock_file(filp->f_path.dentry->d_inode, fl, conflock);
} }
EXPORT_SYMBOL(posix_lock_file_conf); EXPORT_SYMBOL(posix_lock_file);
/** /**
* posix_lock_file_wait - Apply a POSIX-style lock to a file * posix_lock_file_wait - Apply a POSIX-style lock to a file
...@@ -1051,7 +1038,7 @@ int posix_lock_file_wait(struct file *filp, struct file_lock *fl) ...@@ -1051,7 +1038,7 @@ int posix_lock_file_wait(struct file *filp, struct file_lock *fl)
int error; int error;
might_sleep (); might_sleep ();
for (;;) { for (;;) {
error = posix_lock_file(filp, fl); error = posix_lock_file(filp, fl, NULL);
if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP)) if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP))
break; break;
error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
...@@ -1123,7 +1110,7 @@ int locks_mandatory_area(int read_write, struct inode *inode, ...@@ -1123,7 +1110,7 @@ int locks_mandatory_area(int read_write, struct inode *inode,
fl.fl_end = offset + count - 1; fl.fl_end = offset + count - 1;
for (;;) { for (;;) {
error = __posix_lock_file_conf(inode, &fl, NULL); error = __posix_lock_file(inode, &fl, NULL);
if (error != -EAGAIN) if (error != -EAGAIN)
break; break;
if (!(fl.fl_flags & FL_SLEEP)) if (!(fl.fl_flags & FL_SLEEP))
...@@ -1703,13 +1690,21 @@ int fcntl_getlk(struct file *filp, struct flock __user *l) ...@@ -1703,13 +1690,21 @@ int fcntl_getlk(struct file *filp, struct flock __user *l)
* @filp: The file to apply the lock to * @filp: The file to apply the lock to
* @cmd: type of locking operation (F_SETLK, F_GETLK, etc.) * @cmd: type of locking operation (F_SETLK, F_GETLK, etc.)
* @fl: The lock to be applied * @fl: The lock to be applied
* @conf: Place to return a copy of the conflicting lock, if found.
*
* A caller that doesn't care about the conflicting lock may pass NULL
* as the final argument.
*
* If the filesystem defines a private ->lock() method, then @conf will
* be left unchanged; so a caller that cares should initialize it to
* some acceptable default.
*/ */
int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl) int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf)
{ {
if (filp->f_op && filp->f_op->lock) if (filp->f_op && filp->f_op->lock)
return filp->f_op->lock(filp, cmd, fl); return filp->f_op->lock(filp, cmd, fl);
else else
return posix_lock_file(filp, fl); return posix_lock_file(filp, fl, conf);
} }
EXPORT_SYMBOL_GPL(vfs_lock_file); EXPORT_SYMBOL_GPL(vfs_lock_file);
...@@ -1776,7 +1771,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, ...@@ -1776,7 +1771,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
goto out; goto out;
for (;;) { for (;;) {
error = vfs_lock_file(filp, cmd, file_lock); error = vfs_lock_file(filp, cmd, file_lock, NULL);
if (error != -EAGAIN || cmd == F_SETLK) if (error != -EAGAIN || cmd == F_SETLK)
break; break;
error = wait_event_interruptible(file_lock->fl_wait, error = wait_event_interruptible(file_lock->fl_wait,
...@@ -1902,7 +1897,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, ...@@ -1902,7 +1897,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
goto out; goto out;
for (;;) { for (;;) {
error = vfs_lock_file(filp, cmd, file_lock); error = vfs_lock_file(filp, cmd, file_lock, NULL);
if (error != -EAGAIN || cmd == F_SETLK64) if (error != -EAGAIN || cmd == F_SETLK64)
break; break;
error = wait_event_interruptible(file_lock->fl_wait, error = wait_event_interruptible(file_lock->fl_wait,
...@@ -1956,7 +1951,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner) ...@@ -1956,7 +1951,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
lock.fl_ops = NULL; lock.fl_ops = NULL;
lock.fl_lmops = NULL; lock.fl_lmops = NULL;
vfs_lock_file(filp, F_SETLK, &lock); vfs_lock_file(filp, F_SETLK, &lock, NULL);
if (lock.fl_ops && lock.fl_ops->fl_release_private) if (lock.fl_ops && lock.fl_ops->fl_release_private)
lock.fl_ops->fl_release_private(&lock); lock.fl_ops->fl_release_private(&lock);
......
...@@ -2657,6 +2657,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -2657,6 +2657,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct file_lock conflock; struct file_lock conflock;
__be32 status = 0; __be32 status = 0;
unsigned int strhashval; unsigned int strhashval;
unsigned int cmd;
int err; int err;
dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
...@@ -2739,10 +2740,12 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -2739,10 +2740,12 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
case NFS4_READ_LT: case NFS4_READ_LT:
case NFS4_READW_LT: case NFS4_READW_LT:
file_lock.fl_type = F_RDLCK; file_lock.fl_type = F_RDLCK;
cmd = F_SETLK;
break; break;
case NFS4_WRITE_LT: case NFS4_WRITE_LT:
case NFS4_WRITEW_LT: case NFS4_WRITEW_LT:
file_lock.fl_type = F_WRLCK; file_lock.fl_type = F_WRLCK;
cmd = F_SETLK;
break; break;
default: default:
status = nfserr_inval; status = nfserr_inval;
...@@ -2769,9 +2772,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -2769,9 +2772,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
/* XXX?: Just to divert the locks_release_private at the start of /* XXX?: Just to divert the locks_release_private at the start of
* locks_copy_lock: */ * locks_copy_lock: */
conflock.fl_ops = NULL; locks_init_lock(&conflock);
conflock.fl_lmops = NULL; err = posix_lock_file(filp, &file_lock, &conflock);
err = posix_lock_file_conf(filp, &file_lock, &conflock);
switch (-err) { switch (-err) {
case 0: /* success! */ case 0: /* success! */
update_stateid(&lock_stp->st_stateid); update_stateid(&lock_stp->st_stateid);
...@@ -2933,7 +2935,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -2933,7 +2935,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
/* /*
* Try to unlock the file in the VFS. * Try to unlock the file in the VFS.
*/ */
err = posix_lock_file(filp, &file_lock); err = posix_lock_file(filp, &file_lock, NULL);
if (err) { if (err) {
dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n"); dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n");
goto out_nfserr; goto out_nfserr;
......
...@@ -852,12 +852,11 @@ extern void locks_copy_lock(struct file_lock *, struct file_lock *); ...@@ -852,12 +852,11 @@ extern void locks_copy_lock(struct file_lock *, struct file_lock *);
extern void locks_remove_posix(struct file *, fl_owner_t); extern void locks_remove_posix(struct file *, fl_owner_t);
extern void locks_remove_flock(struct file *); extern void locks_remove_flock(struct file *);
extern int posix_test_lock(struct file *, struct file_lock *); extern int posix_test_lock(struct file *, struct file_lock *);
extern int posix_lock_file_conf(struct file *, struct file_lock *, struct file_lock *); extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *);
extern int posix_lock_file(struct file *, struct file_lock *);
extern int posix_lock_file_wait(struct file *, struct file_lock *); extern int posix_lock_file_wait(struct file *, struct file_lock *);
extern int posix_unblock_lock(struct file *, struct file_lock *); extern int posix_unblock_lock(struct file *, struct file_lock *);
extern int vfs_test_lock(struct file *, struct file_lock *); extern int vfs_test_lock(struct file *, struct file_lock *);
extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *); extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *);
extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl); extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl);
extern int __break_lease(struct inode *inode, unsigned int flags); extern int __break_lease(struct inode *inode, unsigned int flags);
extern void lease_get_mtime(struct inode *, struct timespec *time); extern void lease_get_mtime(struct inode *, struct timespec *time);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册