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

Commit 1442d167 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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

* 'for-3.2' of git://linux-nfs.org/~bfields/linux: (103 commits)
  nfs41: implement DESTROY_CLIENTID operation
  nfsd4: typo logical vs bitwise negate for want_mask
  nfsd4: allow NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL | NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED
  nfsd4: seq->status_flags may be used unitialized
  nfsd41: use SEQ4_STATUS_BACKCHANNEL_FAULT when cb_sequence is invalid
  nfsd4: implement new 4.1 open reclaim types
  nfsd4: remove unneeded CLAIM_DELEGATE_CUR workaround
  nfsd4: warn on open failure after create
  nfsd4: preallocate open stateid in process_open1()
  nfsd4: do idr preallocation with stateid allocation
  nfsd4: preallocate nfs4_file in process_open1()
  nfsd4: clean up open owners on OPEN failure
  nfsd4: simplify process_open1 logic
  nfsd4: make is_open_owner boolean
  nfsd4: centralize renew_client() calls
  nfsd4: typo logical vs bitwise negate
  nfs: fix bug about IPv6 address scope checking
  nfsd4: more robust ignoring of WANT bits in OPEN
  nfsd4: move name-length checks to xdr
  nfsd4: move access/deny validity checks to xdr code
  ...
parents 7e0bb71e 345c2842
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -51,8 +51,6 @@
#define F_EXLCK		16	/* or 3 */
#define F_SHLCK		32	/* or 4 */

#define F_INPROGRESS	64

#include <asm-generic/fcntl.h>

#endif
+0 −1
Original line number Diff line number Diff line
@@ -37,7 +37,6 @@
#include <linux/dirent.h>
#include <linux/fsnotify.h>
#include <linux/highuid.h>
#include <linux/nfsd/syscall.h>
#include <linux/personality.h>
#include <linux/rwsem.h>
#include <linux/tsacct_kern.h>
+2 −23
Original line number Diff line number Diff line
@@ -316,14 +316,8 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
	struct hlist_node *pos;
	struct nlm_host	*host = NULL;
	struct nsm_handle *nsm = NULL;
	struct sockaddr_in sin = {
		.sin_family	= AF_INET,
	};
	struct sockaddr_in6 sin6 = {
		.sin6_family	= AF_INET6,
	};
	struct sockaddr *src_sap;
	size_t src_len = rqstp->rq_addrlen;
	struct sockaddr *src_sap = svc_daddr(rqstp);
	size_t src_len = rqstp->rq_daddrlen;
	struct nlm_lookup_host_info ni = {
		.server		= 1,
		.sap		= svc_addr(rqstp),
@@ -340,21 +334,6 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,

	mutex_lock(&nlm_host_mutex);

	switch (ni.sap->sa_family) {
	case AF_INET:
		sin.sin_addr.s_addr = rqstp->rq_daddr.addr.s_addr;
		src_sap = (struct sockaddr *)&sin;
		break;
	case AF_INET6:
		ipv6_addr_copy(&sin6.sin6_addr, &rqstp->rq_daddr.addr6);
		src_sap = (struct sockaddr *)&sin6;
		break;
	default:
		dprintk("lockd: %s failed; unrecognized address family\n",
			__func__);
		goto out;
	}

	if (time_after_eq(jiffies, next_gc))
		nlm_gc_hosts();

+1 −1
Original line number Diff line number Diff line
@@ -282,7 +282,7 @@ int lockd_up(void)
	/*
	 * Create the kernel thread and wait for it to start.
	 */
	nlmsvc_rqst = svc_prepare_thread(serv, &serv->sv_pools[0]);
	nlmsvc_rqst = svc_prepare_thread(serv, &serv->sv_pools[0], NUMA_NO_NODE);
	if (IS_ERR(nlmsvc_rqst)) {
		error = PTR_ERR(nlmsvc_rqst);
		nlmsvc_rqst = NULL;
+140 −83
Original line number Diff line number Diff line
@@ -133,6 +133,20 @@
#define IS_FLOCK(fl)	(fl->fl_flags & FL_FLOCK)
#define IS_LEASE(fl)	(fl->fl_flags & FL_LEASE)

static bool lease_breaking(struct file_lock *fl)
{
	return fl->fl_flags & (FL_UNLOCK_PENDING | FL_DOWNGRADE_PENDING);
}

static int target_leasetype(struct file_lock *fl)
{
	if (fl->fl_flags & FL_UNLOCK_PENDING)
		return F_UNLCK;
	if (fl->fl_flags & FL_DOWNGRADE_PENDING)
		return F_RDLCK;
	return fl->fl_type;
}

int leases_enable = 1;
int lease_break_time = 45;

@@ -1119,6 +1133,17 @@ int locks_mandatory_area(int read_write, struct inode *inode,

EXPORT_SYMBOL(locks_mandatory_area);

static void lease_clear_pending(struct file_lock *fl, int arg)
{
	switch (arg) {
	case F_UNLCK:
		fl->fl_flags &= ~FL_UNLOCK_PENDING;
		/* fall through: */
	case F_RDLCK:
		fl->fl_flags &= ~FL_DOWNGRADE_PENDING;
	}
}

/* We already had a lease on this file; just change its type */
int lease_modify(struct file_lock **before, int arg)
{
@@ -1127,6 +1152,7 @@ int lease_modify(struct file_lock **before, int arg)

	if (error)
		return error;
	lease_clear_pending(fl, arg);
	locks_wake_up_blocks(fl);
	if (arg == F_UNLCK)
		locks_delete_lock(before);
@@ -1135,19 +1161,25 @@ int lease_modify(struct file_lock **before, int arg)

EXPORT_SYMBOL(lease_modify);

static bool past_time(unsigned long then)
{
	if (!then)
		/* 0 is a special value meaning "this never expires": */
		return false;
	return time_after(jiffies, then);
}

static void time_out_leases(struct inode *inode)
{
	struct file_lock **before;
	struct file_lock *fl;

	before = &inode->i_flock;
	while ((fl = *before) && IS_LEASE(fl) && (fl->fl_type & F_INPROGRESS)) {
		if ((fl->fl_break_time == 0)
				|| time_before(jiffies, fl->fl_break_time)) {
			before = &fl->fl_next;
			continue;
		}
		lease_modify(before, fl->fl_type & ~F_INPROGRESS);
	while ((fl = *before) && IS_LEASE(fl) && lease_breaking(fl)) {
		if (past_time(fl->fl_downgrade_time))
			lease_modify(before, F_RDLCK);
		if (past_time(fl->fl_break_time))
			lease_modify(before, F_UNLCK);
		if (fl == *before)	/* lease_modify may have freed fl */
			before = &fl->fl_next;
	}
@@ -1165,7 +1197,7 @@ static void time_out_leases(struct inode *inode)
 */
int __break_lease(struct inode *inode, unsigned int mode)
{
	int error = 0, future;
	int error = 0;
	struct file_lock *new_fl, *flock;
	struct file_lock *fl;
	unsigned long break_time;
@@ -1182,24 +1214,13 @@ int __break_lease(struct inode *inode, unsigned int mode)
	if ((flock == NULL) || !IS_LEASE(flock))
		goto out;

	if (!locks_conflict(flock, new_fl))
		goto out;

	for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next)
		if (fl->fl_owner == current->files)
			i_have_this_lease = 1;

	if (want_write) {
		/* If we want write access, we have to revoke any lease. */
		future = F_UNLCK | F_INPROGRESS;
	} else if (flock->fl_type & F_INPROGRESS) {
		/* If the lease is already being broken, we just leave it */
		future = flock->fl_type;
	} else if (flock->fl_type & F_WRLCK) {
		/* Downgrade the exclusive lease to a read-only lease. */
		future = F_RDLCK | F_INPROGRESS;
	} else {
		/* the existing lease was read-only, so we can read too. */
		goto out;
	}

	if (IS_ERR(new_fl) && !i_have_this_lease
			&& ((mode & O_NONBLOCK) == 0)) {
		error = PTR_ERR(new_fl);
@@ -1214,12 +1235,18 @@ int __break_lease(struct inode *inode, unsigned int mode)
	}

	for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) {
		if (fl->fl_type != future) {
			fl->fl_type = future;
		if (want_write) {
			if (fl->fl_flags & FL_UNLOCK_PENDING)
				continue;
			fl->fl_flags |= FL_UNLOCK_PENDING;
			fl->fl_break_time = break_time;
			/* lease must have lmops break callback */
			fl->fl_lmops->lm_break(fl);
		} else {
			if (lease_breaking(flock))
				continue;
			fl->fl_flags |= FL_DOWNGRADE_PENDING;
			fl->fl_downgrade_time = break_time;
		}
		fl->fl_lmops->lm_break(fl);
	}

	if (i_have_this_lease || (mode & O_NONBLOCK)) {
@@ -1243,10 +1270,13 @@ int __break_lease(struct inode *inode, unsigned int mode)
	if (error >= 0) {
		if (error == 0)
			time_out_leases(inode);
		/* Wait for the next lease that has not been broken yet */
		/*
		 * Wait for the next conflicting lease that has not been
		 * broken yet
		 */
		for (flock = inode->i_flock; flock && IS_LEASE(flock);
				flock = flock->fl_next) {
			if (flock->fl_type & F_INPROGRESS)
			if (locks_conflict(new_fl, flock))
				goto restart;
		}
		error = 0;
@@ -1314,7 +1344,7 @@ int fcntl_getlease(struct file *filp)
	for (fl = filp->f_path.dentry->d_inode->i_flock; fl && IS_LEASE(fl);
			fl = fl->fl_next) {
		if (fl->fl_file == filp) {
			type = fl->fl_type & ~F_INPROGRESS;
			type = target_leasetype(fl);
			break;
		}
	}
@@ -1322,41 +1352,15 @@ int fcntl_getlease(struct file *filp)
	return type;
}

/**
 *	generic_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
 *
 *	The (input) flp->fl_lmops->lm_break function is required
 *	by break_lease().
 *
 *	Called with file_lock_lock held.
 */
int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
int generic_add_lease(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;
	int error;

	lease = *flp;

	error = -EACCES;
	if ((current_fsuid() != inode->i_uid) && !capable(CAP_LEASE))
		goto out;
	error = -EINVAL;
	if (!S_ISREG(inode->i_mode))
		goto out;
	error = security_file_lock(filp, arg);
	if (error)
		goto out;

	time_out_leases(inode);

	BUG_ON(!(*flp)->fl_lmops->lm_break);

	if (arg != F_UNLCK) {
	error = -EAGAIN;
	if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
		goto out;
@@ -1364,7 +1368,6 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
	    && ((dentry->d_count > 1)
		|| (atomic_read(&inode->i_count) > 1)))
		goto out;
	}

	/*
	 * At this point, we know that if there is an exclusive
@@ -1374,26 +1377,27 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
	 * then the file is not open by anyone (including us)
	 * except for this filp.
	 */
	error = -EAGAIN;
	for (before = &inode->i_flock;
			((fl = *before) != NULL) && IS_LEASE(fl);
			before = &fl->fl_next) {
		if (fl->fl_file == filp)
		if (fl->fl_file == filp) {
			my_before = before;
		else if (fl->fl_type == (F_INPROGRESS | F_UNLCK))
			continue;
		}
		/*
			 * Someone is in the process of opening this
			 * file for writing so we may not take an
			 * exclusive lease on it.
		 * No exclusive leases if someone else has a lease on
		 * this file:
		 */
			wrlease_count++;
		else
			rdlease_count++;
	}

	error = -EAGAIN;
	if ((arg == F_RDLCK && (wrlease_count > 0)) ||
	    (arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0)))
		if (arg == F_WRLCK)
			goto out;
		/*
		 * Modifying our existing lease is OK, but no getting a
		 * new lease if someone else is opening for write:
		 */
		if (fl->fl_flags & FL_UNLOCK_PENDING)
			goto out;
	}

	if (my_before != NULL) {
		error = lease->fl_lmops->lm_change(my_before, arg);
@@ -1402,9 +1406,6 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
		goto out;
	}

	if (arg == F_UNLCK)
		goto out;

	error = -EINVAL;
	if (!leases_enable)
		goto out;
@@ -1415,6 +1416,62 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
out:
	return error;
}

int generic_delete_lease(struct file *filp, struct file_lock **flp)
{
	struct file_lock *fl, **before;
	struct dentry *dentry = filp->f_path.dentry;
	struct inode *inode = dentry->d_inode;

	for (before = &inode->i_flock;
			((fl = *before) != NULL) && IS_LEASE(fl);
			before = &fl->fl_next) {
		if (fl->fl_file != filp)
			continue;
		return (*flp)->fl_lmops->lm_change(before, F_UNLCK);
	}
	return -EAGAIN;
}

/**
 *	generic_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
 *
 *	The (input) flp->fl_lmops->lm_break function is required
 *	by break_lease().
 *
 *	Called with file_lock_lock held.
 */
int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
{
	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;

	time_out_leases(inode);

	BUG_ON(!(*flp)->fl_lmops->lm_break);

	switch (arg) {
	case F_UNLCK:
		return generic_delete_lease(filp, flp);
	case F_RDLCK:
	case F_WRLCK:
		return generic_add_lease(filp, arg, flp);
	default:
		BUG();
	}
}
EXPORT_SYMBOL(generic_setlease);

static int __vfs_setlease(struct file *filp, long arg, struct file_lock **lease)
@@ -2126,7 +2183,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
		}
	} else if (IS_LEASE(fl)) {
		seq_printf(f, "LEASE  ");
		if (fl->fl_type & F_INPROGRESS)
		if (lease_breaking(fl))
			seq_printf(f, "BREAKING  ");
		else if (fl->fl_file)
			seq_printf(f, "ACTIVE    ");
@@ -2142,7 +2199,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
			       : (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE ");
	} else {
		seq_printf(f, "%s ",
			       (fl->fl_type & F_INPROGRESS)
			       (lease_breaking(fl))
			       ? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ "
			       : (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");
	}
Loading