Commit c8ebd433 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull nfsd fixes from Chuck Lever:
 "A set of NFSD fixes that arrived just a bit late for the 6.19 merge
  window.

  Regression fix:
   - Avoid unnecessarily breaking a timestamp delegation

  Stable fixes:
   - Fix a crasher in nlm4svc_proc_test()
   - Fix nfsd_file reference leak during write delegation
   - Fix error flow in client_states_open()"

* tag 'nfsd-6.19-2' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux:
  nfsd: Drop the client reference in client_states_open()
  nfsd: use ATTR_DELEG in nfsd4_finalize_deleg_timestamps()
  nfsd: fix nfsd_file reference leak in nfsd4_add_rdaccess_to_wrdeleg()
  lockd: fix vfs_test_lock() calls
parents dbf8fe85 1f941b2c
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -97,7 +97,6 @@ __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
	struct nlm_args *argp = rqstp->rq_argp;
	struct nlm_host	*host;
	struct nlm_file	*file;
	struct nlm_lockowner *test_owner;
	__be32 rc = rpc_success;

	dprintk("lockd: TEST4        called\n");
@@ -107,7 +106,6 @@ __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
		return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;

	test_owner = argp->lock.fl.c.flc_owner;
	/* Now check for conflicting locks */
	resp->status = nlmsvc_testlock(rqstp, file, host, &argp->lock,
				       &resp->lock);
@@ -116,7 +114,7 @@ __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
	else
		dprintk("lockd: TEST4        status %d\n", ntohl(resp->status));

	nlmsvc_put_lockowner(test_owner);
	nlmsvc_release_lockowner(&argp->lock);
	nlmsvc_release_host(host);
	nlm_release_file(file);
	return rc;
+12 −9
Original line number Diff line number Diff line
@@ -633,7 +633,13 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
	}

	mode = lock_to_openmode(&lock->fl);
	error = vfs_test_lock(file->f_file[mode], &lock->fl);
	locks_init_lock(&conflock->fl);
	/* vfs_test_lock only uses start, end, and owner, but tests flc_file */
	conflock->fl.c.flc_file = lock->fl.c.flc_file;
	conflock->fl.fl_start = lock->fl.fl_start;
	conflock->fl.fl_end = lock->fl.fl_end;
	conflock->fl.c.flc_owner = lock->fl.c.flc_owner;
	error = vfs_test_lock(file->f_file[mode], &conflock->fl);
	if (error) {
		/* We can't currently deal with deferred test requests */
		if (error == FILE_LOCK_DEFERRED)
@@ -643,22 +649,19 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
		goto out;
	}

	if (lock->fl.c.flc_type == F_UNLCK) {
	if (conflock->fl.c.flc_type == F_UNLCK) {
		ret = nlm_granted;
		goto out;
	}

	dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
		lock->fl.c.flc_type, (long long)lock->fl.fl_start,
		(long long)lock->fl.fl_end);
		conflock->fl.c.flc_type, (long long)conflock->fl.fl_start,
		(long long)conflock->fl.fl_end);
	conflock->caller = "somehost";	/* FIXME */
	conflock->len = strlen(conflock->caller);
	conflock->oh.len = 0;		/* don't return OH info */
	conflock->svid = lock->fl.c.flc_pid;
	conflock->fl.c.flc_type = lock->fl.c.flc_type;
	conflock->fl.fl_start = lock->fl.fl_start;
	conflock->fl.fl_end = lock->fl.fl_end;
	locks_release_private(&lock->fl);
	conflock->svid = conflock->fl.c.flc_pid;
	locks_release_private(&conflock->fl);

	ret = nlm_lck_denied;
out:
+1 −4
Original line number Diff line number Diff line
@@ -117,7 +117,6 @@ __nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
	struct nlm_args *argp = rqstp->rq_argp;
	struct nlm_host	*host;
	struct nlm_file	*file;
	struct nlm_lockowner *test_owner;
	__be32 rc = rpc_success;

	dprintk("lockd: TEST          called\n");
@@ -127,8 +126,6 @@ __nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
	if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
		return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;

	test_owner = argp->lock.fl.c.flc_owner;

	/* Now check for conflicting locks */
	resp->status = cast_status(nlmsvc_testlock(rqstp, file, host,
						   &argp->lock, &resp->lock));
@@ -138,7 +135,7 @@ __nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
		dprintk("lockd: TEST          status %d vers %d\n",
			ntohl(resp->status), rqstp->rq_vers);

	nlmsvc_put_lockowner(test_owner);
	nlmsvc_release_lockowner(&argp->lock);
	nlmsvc_release_host(host);
	nlm_release_file(file);
	return rc;
+10 −2
Original line number Diff line number Diff line
@@ -2236,13 +2236,21 @@ SYSCALL_DEFINE2(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; also used to hold result
 * @fl: The byte-range in the file to test; also used to hold result
 *
 * On entry, @fl does not contain a lock, but identifies a range (fl_start, fl_end)
 * in the file (c.flc_file), and an owner (c.flc_owner) for whom existing locks
 * should be ignored.  c.flc_type and c.flc_flags are ignored.
 * Both fl_lmops and fl_ops in @fl must be NULL.
 * Returns -ERRNO on failure.  Indicates presence of conflicting lock by
 * setting conf->fl_type to something other than F_UNLCK.
 * setting fl->fl_type to something other than F_UNLCK.
 *
 * If vfs_test_lock() does find a lock and return it, the caller must
 * use locks_free_lock() or locks_release_private() on the returned lock.
 */
int vfs_test_lock(struct file *filp, struct file_lock *fl)
{
	WARN_ON_ONCE(fl->fl_ops || fl->fl_lmops);
	WARN_ON_ONCE(filp != fl->c.flc_file);
	if (filp->f_op->lock)
		return filp->f_op->lock(filp, F_GETLK, fl);
+14 −6
Original line number Diff line number Diff line
@@ -1218,13 +1218,15 @@ static void put_deleg_file(struct nfs4_file *fp)

	if (nf)
		nfsd_file_put(nf);
	if (rnf)
	if (rnf) {
		nfsd_file_put(rnf);
		nfs4_file_put_access(fp, NFS4_SHARE_ACCESS_READ);
	}
}

static void nfsd4_finalize_deleg_timestamps(struct nfs4_delegation *dp, struct file *f)
{
	struct iattr ia = { .ia_valid = ATTR_ATIME | ATTR_CTIME | ATTR_MTIME };
	struct iattr ia = { .ia_valid = ATTR_ATIME | ATTR_CTIME | ATTR_MTIME | ATTR_DELEG };
	struct inode *inode = file_inode(f);
	int ret;

@@ -3097,8 +3099,10 @@ static int client_states_open(struct inode *inode, struct file *file)
		return -ENXIO;

	ret = seq_open(file, &states_seq_ops);
	if (ret)
	if (ret) {
		drop_client(clp);
		return ret;
	}
	s = file->private_data;
	s->private = clp;
	return 0;
@@ -6231,10 +6235,14 @@ nfsd4_add_rdaccess_to_wrdeleg(struct svc_rqst *rqstp, struct nfsd4_open *open,
		fp = stp->st_stid.sc_file;
		spin_lock(&fp->fi_lock);
		__nfs4_file_get_access(fp, NFS4_SHARE_ACCESS_READ);
		fp = stp->st_stid.sc_file;
		if (!fp->fi_fds[O_RDONLY]) {
			fp->fi_fds[O_RDONLY] = nf;
		fp->fi_rdeleg_file = nf;
			nf = NULL;
		}
		fp->fi_rdeleg_file = nfsd_file_get(fp->fi_fds[O_RDONLY]);
		spin_unlock(&fp->fi_lock);
		if (nf)
			nfsd_file_put(nf);
	}
	return true;
}