Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 150b3934 authored by Marc Eshel's avatar Marc Eshel Committed by J. Bruce Fields
Browse files

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: default avatarMarc Eshel <eshel@almaden.ibm.com>
Signed-off-by: default avatar"J. Bruce Fields" <bfields@citi.umich.edu>
parent 7723ec97
Loading
Loading
Loading
Loading
+3 −3
Original line number Original line Diff line number Diff line
@@ -363,7 +363,7 @@ again:
	} 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)
	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)


	/* 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) {
+1 −1
Original line number Original line Diff line number Diff line
@@ -182,7 +182,7 @@ again:
			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;
+20 −25
Original line number Original line Diff line number Diff line
@@ -801,7 +801,7 @@ out:
	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
 * 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
 * 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)
	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,
	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 @@ out:
 * @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 @@ again:
		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 @@ again:
		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)
	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);
+6 −4
Original line number Original line Diff line number Diff line
@@ -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,
		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,


	/* 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,
	/*
	/*
	*  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;
+2 −3
Original line number Original line Diff line number Diff line
@@ -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);