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

Commit e7bdea77 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull NFS client bugfixes from Anna Schumaker:
 "Stable bugfixes:
   - Fix _cancel_empty_pagelist
   - Fix a double page unlock
   - Make nfs_atomic_open() call d_drop() on all ->open_context() errors.
   - Fix another OPEN_DOWNGRADE bug

  Other bugfixes:
   - Ensure we handle delegation errors in nfs4_proc_layoutget()
   - Layout stateids start out as being invalid
   - Add sparse lock annotations for pnfs_find_alloc_layout
   - Handle bad delegation stateids in nfs4_layoutget_handle_exception
   - Fix up O_DIRECT results
   - Fix potential use after free of state in nfs4_do_reclaim.
   - Mark the layout stateid invalid when all segments are removed
   - Don't let readdirplus revalidate an inode that was marked as stale
   - Fix potential race in nfs_fhget()
   - Fix an unused variable warning"

* tag 'nfs-for-4.7-2' of git://git.linux-nfs.org/projects/anna/linux-nfs:
  NFS: Fix another OPEN_DOWNGRADE bug
  make nfs_atomic_open() call d_drop() on all ->open_context() errors.
  NFS: Fix an unused variable warning
  NFS: Fix potential race in nfs_fhget()
  NFS: Don't let readdirplus revalidate an inode that was marked as stale
  NFSv4.1/pnfs: Mark the layout stateid invalid when all segments are removed
  NFS: Fix a double page unlock
  pnfs_nfs: fix _cancel_empty_pagelist
  nfs4: Fix potential use after free of state in nfs4_do_reclaim.
  NFS: Fix up O_DIRECT results
  NFS/pnfs: handle bad delegation stateids in nfs4_layoutget_handle_exception
  NFSv4.1/pnfs: Add sparse lock annotations for pnfs_find_alloc_layout
  NFSv4.1/pnfs: Layout stateids start out as being invalid
  NFSv4.1/pnfs: Ensure we handle delegation errors in nfs4_proc_layoutget()
parents 89a82a92 e547f262
Loading
Loading
Loading
Loading
+7 −4
Original line number Original line Diff line number Diff line
@@ -424,12 +424,17 @@ static int xdr_decode(nfs_readdir_descriptor_t *desc,
static
static
int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry)
int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry)
{
{
	struct inode *inode;
	struct nfs_inode *nfsi;
	struct nfs_inode *nfsi;


	if (d_really_is_negative(dentry))
	if (d_really_is_negative(dentry))
		return 0;
		return 0;


	nfsi = NFS_I(d_inode(dentry));
	inode = d_inode(dentry);
	if (is_bad_inode(inode) || NFS_STALE(inode))
		return 0;

	nfsi = NFS_I(inode);
	if (entry->fattr->fileid == nfsi->fileid)
	if (entry->fattr->fileid == nfsi->fileid)
		return 1;
		return 1;
	if (nfs_compare_fh(entry->fh, &nfsi->fh) == 0)
	if (nfs_compare_fh(entry->fh, &nfsi->fh) == 0)
@@ -1363,7 +1368,6 @@ EXPORT_SYMBOL_GPL(nfs_dentry_operations);
struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
{
{
	struct dentry *res;
	struct dentry *res;
	struct dentry *parent;
	struct inode *inode = NULL;
	struct inode *inode = NULL;
	struct nfs_fh *fhandle = NULL;
	struct nfs_fh *fhandle = NULL;
	struct nfs_fattr *fattr = NULL;
	struct nfs_fattr *fattr = NULL;
@@ -1393,7 +1397,6 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
	if (IS_ERR(label))
	if (IS_ERR(label))
		goto out;
		goto out;


	parent = dentry->d_parent;
	/* Protect against concurrent sillydeletes */
	/* Protect against concurrent sillydeletes */
	trace_nfs_lookup_enter(dir, dentry, flags);
	trace_nfs_lookup_enter(dir, dentry, flags);
	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
@@ -1536,9 +1539,9 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
		err = PTR_ERR(inode);
		err = PTR_ERR(inode);
		trace_nfs_atomic_open_exit(dir, ctx, open_flags, err);
		trace_nfs_atomic_open_exit(dir, ctx, open_flags, err);
		put_nfs_open_context(ctx);
		put_nfs_open_context(ctx);
		d_drop(dentry);
		switch (err) {
		switch (err) {
		case -ENOENT:
		case -ENOENT:
			d_drop(dentry);
			d_add(dentry, NULL);
			d_add(dentry, NULL);
			nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
			nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
			break;
			break;
+7 −3
Original line number Original line Diff line number Diff line
@@ -353,10 +353,12 @@ static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq)


	result = wait_for_completion_killable(&dreq->completion);
	result = wait_for_completion_killable(&dreq->completion);


	if (!result) {
		result = dreq->count;
		WARN_ON_ONCE(dreq->count < 0);
	}
	if (!result)
	if (!result)
		result = dreq->error;
		result = dreq->error;
	if (!result)
		result = dreq->count;


out:
out:
	return (ssize_t) result;
	return (ssize_t) result;
@@ -386,8 +388,10 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq, bool write)


	if (dreq->iocb) {
	if (dreq->iocb) {
		long res = (long) dreq->error;
		long res = (long) dreq->error;
		if (!res)
		if (dreq->count != 0) {
			res = (long) dreq->count;
			res = (long) dreq->count;
			WARN_ON_ONCE(dreq->count < 0);
		}
		dreq->iocb->ki_complete(dreq->iocb, res, 0);
		dreq->iocb->ki_complete(dreq->iocb, res, 0);
	}
	}


+1 −0
Original line number Original line Diff line number Diff line
@@ -282,6 +282,7 @@ nfs_init_locked(struct inode *inode, void *opaque)
	struct nfs_fattr	*fattr = desc->fattr;
	struct nfs_fattr	*fattr = desc->fattr;


	set_nfs_fileid(inode, fattr->fileid);
	set_nfs_fileid(inode, fattr->fileid);
	inode->i_mode = fattr->mode;
	nfs_copy_fh(NFS_FH(inode), desc->fh);
	nfs_copy_fh(NFS_FH(inode), desc->fh);
	return 0;
	return 0;
}
}
+10 −8
Original line number Original line Diff line number Diff line
@@ -2882,12 +2882,11 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
			call_close |= is_wronly;
			call_close |= is_wronly;
		else if (is_wronly)
		else if (is_wronly)
			calldata->arg.fmode |= FMODE_WRITE;
			calldata->arg.fmode |= FMODE_WRITE;
		if (calldata->arg.fmode != (FMODE_READ|FMODE_WRITE))
			call_close |= is_rdwr;
	} else if (is_rdwr)
	} else if (is_rdwr)
		calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;
		calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;


	if (calldata->arg.fmode == 0)
		call_close |= is_rdwr;

	if (!nfs4_valid_open_stateid(state))
	if (!nfs4_valid_open_stateid(state))
		call_close = 0;
		call_close = 0;
	spin_unlock(&state->owner->so_lock);
	spin_unlock(&state->owner->so_lock);
@@ -7924,8 +7923,8 @@ nfs4_layoutget_handle_exception(struct rpc_task *task,
			break;
			break;
		}
		}
		lo = NFS_I(inode)->layout;
		lo = NFS_I(inode)->layout;
		if (lo && nfs4_stateid_match(&lgp->args.stateid,
		if (lo && !test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags) &&
					&lo->plh_stateid)) {
		    nfs4_stateid_match_other(&lgp->args.stateid, &lo->plh_stateid)) {
			LIST_HEAD(head);
			LIST_HEAD(head);


			/*
			/*
@@ -7936,10 +7935,10 @@ nfs4_layoutget_handle_exception(struct rpc_task *task,
			pnfs_mark_matching_lsegs_invalid(lo, &head, NULL, 0);
			pnfs_mark_matching_lsegs_invalid(lo, &head, NULL, 0);
			spin_unlock(&inode->i_lock);
			spin_unlock(&inode->i_lock);
			pnfs_free_lseg_list(&head);
			pnfs_free_lseg_list(&head);
		} else
			spin_unlock(&inode->i_lock);
			status = -EAGAIN;
			status = -EAGAIN;
			goto out;
			goto out;
		} else
			spin_unlock(&inode->i_lock);
	}
	}


	status = nfs4_handle_exception(server, status, exception);
	status = nfs4_handle_exception(server, status, exception);
@@ -8036,7 +8035,10 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout, gfp_t gfp_flags)
		.flags = RPC_TASK_ASYNC,
		.flags = RPC_TASK_ASYNC,
	};
	};
	struct pnfs_layout_segment *lseg = NULL;
	struct pnfs_layout_segment *lseg = NULL;
	struct nfs4_exception exception = { .timeout = *timeout };
	struct nfs4_exception exception = {
		.inode = inode,
		.timeout = *timeout,
	};
	int status = 0;
	int status = 0;


	dprintk("--> %s\n", __func__);
	dprintk("--> %s\n", __func__);
+1 −1
Original line number Original line Diff line number Diff line
@@ -1488,9 +1488,9 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
					}
					}
					spin_unlock(&state->state_lock);
					spin_unlock(&state->state_lock);
				}
				}
				nfs4_put_open_state(state);
				clear_bit(NFS_STATE_RECLAIM_NOGRACE,
				clear_bit(NFS_STATE_RECLAIM_NOGRACE,
					&state->flags);
					&state->flags);
				nfs4_put_open_state(state);
				spin_lock(&sp->so_lock);
				spin_lock(&sp->so_lock);
				goto restart;
				goto restart;
			}
			}
Loading