Commit a8dcf12f authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-linus' of git://linux-nfs.org/~bfields/linux

* 'for-linus' of git://linux-nfs.org/~bfields/linux:
  locks: fix vfs_test_lock() comment
  locks: make posix_test_lock() interface more consistent
  nfs: disable leases over NFS
  gfs2: stop giving out non-cluster-coherent leases
  locks: export setlease to filesystems
  locks: provide a file lease method enabling cluster-coherent leases
  locks: rename lease functions to reflect locks.c conventions
  locks: share more common lease code
  locks: clean up lease_alloc()
  locks: convert an -EINVAL return to a BUG
  leases: minor break_lease() comment clarification
parents d796e641 6924c554
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -488,6 +488,29 @@ static int gfs2_fsync(struct file *file, struct dentry *dentry, int datasync)
	return ret;
}

/**
 * gfs2_setlease - acquire/release a file lease
 * @file: the file pointer
 * @arg: lease type
 * @fl: file lock
 *
 * Returns: errno
 */

static int gfs2_setlease(struct file *file, long arg, struct file_lock **fl)
{
	struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host);

	/*
	 * We don't currently have a way to enforce a lease across the whole
	 * cluster; until we do, disable leases (by just returning -EINVAL),
	 * unless the administrator has requested purely local locking.
	 */
	if (!sdp->sd_args.ar_localflocks)
		return -EINVAL;
	return setlease(file, arg, fl);
}

/**
 * gfs2_lock - acquire/release a posix lock on a file
 * @file: the file pointer
@@ -638,6 +661,7 @@ const struct file_operations gfs2_file_fops = {
	.flock		= gfs2_flock,
	.splice_read	= generic_file_splice_read,
	.splice_write	= generic_file_splice_write,
	.setlease	= gfs2_setlease,
};

const struct file_operations gfs2_dir_fops = {
+57 −55
Original line number Diff line number Diff line
@@ -458,22 +458,20 @@ static int lease_init(struct file *filp, int type, struct file_lock *fl)
}

/* Allocate a file_lock initialised to this type of lease */
static int lease_alloc(struct file *filp, int type, struct file_lock **flp)
static struct file_lock *lease_alloc(struct file *filp, int type)
{
	struct file_lock *fl = locks_alloc_lock();
	int error = -ENOMEM;

	if (fl == NULL)
		goto out;
		return ERR_PTR(error);

	error = lease_init(filp, type, fl);
	if (error) {
		locks_free_lock(fl);
		fl = NULL;
		return ERR_PTR(error);
	}
out:
	*flp = fl;
	return error;
	return fl;
}

/* Check if two locks overlap each other.
@@ -661,7 +659,7 @@ static int locks_block_on_timeout(struct file_lock *blocker, struct file_lock *w
	return result;
}

int
void
posix_test_lock(struct file *filp, struct file_lock *fl)
{
	struct file_lock *cfl;
@@ -673,14 +671,12 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
		if (posix_locks_conflict(cfl, fl))
			break;
	}
	if (cfl) {
	if (cfl)
		__locks_copy_lock(fl, cfl);
		unlock_kernel();
		return 1;
	} else
	else
		fl->fl_type = F_UNLCK;
	unlock_kernel();
	return 0;
	return;
}

EXPORT_SYMBOL(posix_test_lock);
@@ -1169,9 +1165,9 @@ static void time_out_leases(struct inode *inode)
 *	@inode: the inode of the file to return
 *	@mode: the open mode (read or write)
 *
 *	break_lease (inlined for speed) has checked there already
 *	is a lease on this file.  Leases are broken on a call to open()
 *	or truncate().  This function can sleep unless you
 *	break_lease (inlined for speed) has checked there already is at least
 *	some kind of lock (maybe a lease) on this file.  Leases are broken on
 *	a call to open() or truncate().  This function can sleep unless you
 *	specified %O_NONBLOCK to your open().
 */
int __break_lease(struct inode *inode, unsigned int mode)
@@ -1179,12 +1175,10 @@ int __break_lease(struct inode *inode, unsigned int mode)
	int error = 0, future;
	struct file_lock *new_fl, *flock;
	struct file_lock *fl;
	int alloc_err;
	unsigned long break_time;
	int i_have_this_lease = 0;

	alloc_err = lease_alloc(NULL, mode & FMODE_WRITE ? F_WRLCK : F_RDLCK,
			&new_fl);
	new_fl = lease_alloc(NULL, mode & FMODE_WRITE ? F_WRLCK : F_RDLCK);

	lock_kernel();

@@ -1212,8 +1206,9 @@ int __break_lease(struct inode *inode, unsigned int mode)
		goto out;
	}

	if (alloc_err && !i_have_this_lease && ((mode & O_NONBLOCK) == 0)) {
		error = alloc_err;
	if (IS_ERR(new_fl) && !i_have_this_lease
			&& ((mode & O_NONBLOCK) == 0)) {
		error = PTR_ERR(new_fl);
		goto out;
	}

@@ -1260,7 +1255,7 @@ restart:

out:
	unlock_kernel();
	if (!alloc_err)
	if (!IS_ERR(new_fl))
		locks_free_lock(new_fl);
	return error;
}
@@ -1329,7 +1324,7 @@ int fcntl_getlease(struct file *filp)
}

/**
 *	__setlease	-	sets a lease on an open file
 *	setlease	-	sets a lease on an open file
 *	@filp: file pointer
 *	@arg: type of lease to obtain
 *	@flp: input - file_lock to use, output - file_lock inserted
@@ -1339,18 +1334,24 @@ int fcntl_getlease(struct file *filp)
 *
 *	Called with kernel lock held.
 */
static int __setlease(struct file *filp, long arg, struct file_lock **flp)
int setlease(struct file *filp, long arg, struct file_lock **flp)
{
	struct file_lock *fl, **before, **my_before = NULL, *lease;
	struct dentry *dentry = filp->f_path.dentry;
	struct inode *inode = dentry->d_inode;
	int error, rdlease_count = 0, wrlease_count = 0;

	if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE))
		return -EACCES;
	if (!S_ISREG(inode->i_mode))
		return -EINVAL;
	error = security_file_lock(filp, arg);
	if (error)
		return error;

	time_out_leases(inode);

	error = -EINVAL;
	if (!flp || !(*flp) || !(*flp)->fl_lmops || !(*flp)->fl_lmops->fl_break)
		goto out;
	BUG_ON(!(*flp)->fl_lmops->fl_break);

	lease = *flp;

@@ -1418,39 +1419,49 @@ static int __setlease(struct file *filp, long arg, struct file_lock **flp)
out:
	return error;
}
EXPORT_SYMBOL(setlease);

 /**
 *	setlease        -       sets a lease on an open file
 *	vfs_setlease        -       sets a lease on an open file
 *	@filp: file pointer
 *	@arg: type of lease to obtain
 *	@lease: file_lock to use
 *
 *	Call this to establish a lease on the file.
 *	The fl_lmops fl_break function is required by break_lease
 *	The (*lease)->fl_lmops->fl_break operation must be set; if not,
 *	break_lease will oops!
 *
 *	This will call the filesystem's setlease file method, if
 *	defined.  Note that there is no getlease method; instead, the
 *	filesystem setlease method should call back to setlease() to
 *	add a lease to the inode's lease list, where fcntl_getlease() can
 *	find it.  Since fcntl_getlease() only reports whether the current
 *	task holds a lease, a cluster filesystem need only do this for
 *	leases held by processes on this node.
 *
 *	There is also no break_lease method; filesystems that
 *	handle their own leases shoud break leases themselves from the
 *	filesystem's open, create, and (on truncate) setattr methods.
 *
 *	Warning: the only current setlease methods exist only to disable
 *	leases in certain cases.  More vfs changes may be required to
 *	allow a full filesystem lease implementation.
 */

int setlease(struct file *filp, long arg, struct file_lock **lease)
int vfs_setlease(struct file *filp, long arg, struct file_lock **lease)
{
	struct dentry *dentry = filp->f_path.dentry;
	struct inode *inode = dentry->d_inode;
	int error;

	if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE))
		return -EACCES;
	if (!S_ISREG(inode->i_mode))
		return -EINVAL;
	error = security_file_lock(filp, arg);
	if (error)
		return error;

	lock_kernel();
	error = __setlease(filp, arg, lease);
	if (filp->f_op && filp->f_op->setlease)
		error = filp->f_op->setlease(filp, arg, lease);
	else
		error = setlease(filp, arg, lease);
	unlock_kernel();

	return error;
}

EXPORT_SYMBOL(setlease);
EXPORT_SYMBOL_GPL(vfs_setlease);

/**
 *	fcntl_setlease	-	sets a lease on an open file
@@ -1469,14 +1480,6 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
	struct inode *inode = dentry->d_inode;
	int error;

	if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE))
		return -EACCES;
	if (!S_ISREG(inode->i_mode))
		return -EINVAL;
	error = security_file_lock(filp, arg);
	if (error)
		return error;

	locks_init_lock(&fl);
	error = lease_init(filp, arg, &fl);
	if (error)
@@ -1484,13 +1487,13 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)

	lock_kernel();

	error = __setlease(filp, arg, &flp);
	error = vfs_setlease(filp, arg, &flp);
	if (error || arg == F_UNLCK)
		goto out_unlock;

	error = fasync_helper(fd, filp, 1, &flp->fl_fasync);
	if (error < 0) {
		/* remove lease just inserted by __setlease */
		/* remove lease just inserted by setlease */
		flp->fl_type = F_UNLCK | F_INPROGRESS;
		flp->fl_break_time = jiffies - 10;
		time_out_leases(inode);
@@ -1597,8 +1600,7 @@ asmlinkage long sys_flock(unsigned int fd, unsigned int cmd)
/**
 * vfs_test_lock - test file byte range lock
 * @filp: The file to test lock for
 * @fl: The lock to test
 * @conf: Place to return a copy of the conflicting lock, if found
 * @fl: The lock to test; also used to hold result
 *
 * Returns -ERRNO on failure.  Indicates presence of conflicting lock by
 * setting conf->fl_type to something other than F_UNLCK.
+15 −1
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ static int nfs_fsync(struct file *, struct dentry *dentry, int datasync);
static int nfs_check_flags(int flags);
static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl);
static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl);
static int nfs_setlease(struct file *file, long arg, struct file_lock **fl);

const struct file_operations nfs_file_operations = {
	.llseek		= nfs_file_llseek,
@@ -69,6 +70,7 @@ const struct file_operations nfs_file_operations = {
	.flock		= nfs_flock,
	.splice_read	= nfs_file_splice_read,
	.check_flags	= nfs_check_flags,
	.setlease	= nfs_setlease,
};

const struct inode_operations nfs_file_inode_operations = {
@@ -400,7 +402,9 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)

	lock_kernel();
	/* Try local locking first */
	if (posix_test_lock(filp, fl)) {
	posix_test_lock(filp, fl);
	if (fl->fl_type != F_UNLCK) {
		/* found a conflict */
		goto out;
	}

@@ -558,3 +562,13 @@ static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
		return do_unlk(filp, cmd, fl);
	return do_setlk(filp, cmd, fl);
}

static int nfs_setlease(struct file *file, long arg, struct file_lock **fl)
{
	/*
	 * There is no protocol support for leases, so we have no way
	 * to implement them correctly in the face of opens by other
	 * clients.
	 */
	return -EINVAL;
}
+5 −5
Original line number Diff line number Diff line
@@ -256,7 +256,7 @@ nfs4_close_delegation(struct nfs4_delegation *dp)
	/* The following nfsd_close may not actually close the file,
	 * but we want to remove the lease in any case. */
	if (dp->dl_flock)
		setlease(filp, F_UNLCK, &dp->dl_flock);
		vfs_setlease(filp, F_UNLCK, &dp->dl_flock);
	nfsd_close(filp);
}

@@ -1402,7 +1402,7 @@ void nfsd_release_deleg_cb(struct file_lock *fl)
/*
 * Set the delegation file_lock back pointer.
 *
 * Called from __setlease() with lock_kernel() held.
 * Called from setlease() with lock_kernel() held.
 */
static
void nfsd_copy_lock_deleg_cb(struct file_lock *new, struct file_lock *fl)
@@ -1416,7 +1416,7 @@ void nfsd_copy_lock_deleg_cb(struct file_lock *new, struct file_lock *fl)
}

/*
 * Called from __setlease() with lock_kernel() held
 * Called from setlease() with lock_kernel() held
 */
static
int nfsd_same_client_deleg_cb(struct file_lock *onlist, struct file_lock *try)
@@ -1716,10 +1716,10 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
	fl.fl_file = stp->st_vfs_file;
	fl.fl_pid = current->tgid;

	/* setlease checks to see if delegation should be handed out.
	/* vfs_setlease checks to see if delegation should be handed out.
	 * the lock_manager callbacks fl_mylease and fl_change are used
	 */
	if ((status = setlease(stp->st_vfs_file,
	if ((status = vfs_setlease(stp->st_vfs_file,
		flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK, &flp))) {
		dprintk("NFSD: setlease failed [%d], no delegation\n", status);
		unhash_delegation(dp);
+3 −1
Original line number Diff line number Diff line
@@ -862,7 +862,7 @@ extern void locks_init_lock(struct file_lock *);
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_flock(struct file *);
extern int posix_test_lock(struct file *, struct file_lock *);
extern void posix_test_lock(struct file *, struct file_lock *);
extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *);
extern int posix_lock_file_wait(struct file *, struct file_lock *);
extern int posix_unblock_lock(struct file *, struct file_lock *);
@@ -873,6 +873,7 @@ extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl);
extern int __break_lease(struct inode *inode, unsigned int flags);
extern void lease_get_mtime(struct inode *, struct timespec *time);
extern int setlease(struct file *, long, struct file_lock **);
extern int vfs_setlease(struct file *, long, struct file_lock **);
extern int lease_modify(struct file_lock **, int);
extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
@@ -1122,6 +1123,7 @@ struct file_operations {
	int (*flock) (struct file *, int, struct file_lock *);
	ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
	ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
	int (*setlease)(struct file *, long, struct file_lock **);
};

struct inode_operations {