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

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

Merge tag 'nfs-for-4.11-3' of git://git.linux-nfs.org/projects/anna/linux-nfs

Pull NFS client fixes from Anna Schumaker:
 "Here are a few more bugfixes that came in over the last couple of
  weeks. Most of these fix various hangs and loops that people found,
  but we also had a few error handling fixes.

  Stable Bugfixes:
   - fix infinite loop on BAD_STATEID error

  Other Bugfixes:
   - fix old dentry rehash after move
   - fix pnfs GETDEVINFO hangs
   - fix pnfs fallback to MDS on commit errors
   - fix flexfiles kernel oops"

* tag 'nfs-for-4.11-3' of git://git.linux-nfs.org/projects/anna/linux-nfs:
  nfs: flexfiles: fix kernel OOPS if MDS returns unsupported DS type
  NFSv4.1 fix infinite loop on IO BAD_STATEID error
  PNFS fix fallback to MDS if got error on commit to DS
  NFS filelayout:call GETDEVICEINFO after pnfs_layout_process completes
  NFS store nfs4_deviceid in struct nfs4_filelayout_segment
  NFS cleanup struct nfs4_filelayout_segment
  NFS: Fix old dentry rehash after move
parents e39bccf2 f17f8a14
Loading
Loading
Loading
Loading
+2 −7
Original line number Diff line number Diff line
@@ -2055,7 +2055,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
{
	struct inode *old_inode = d_inode(old_dentry);
	struct inode *new_inode = d_inode(new_dentry);
	struct dentry *dentry = NULL, *rehash = NULL;
	struct dentry *dentry = NULL;
	struct rpc_task *task;
	int error = -EBUSY;

@@ -2078,10 +2078,8 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
		 * To prevent any new references to the target during the
		 * rename, we unhash the dentry in advance.
		 */
		if (!d_unhashed(new_dentry)) {
		if (!d_unhashed(new_dentry))
			d_drop(new_dentry);
			rehash = new_dentry;
		}

		if (d_count(new_dentry) > 2) {
			int err;
@@ -2098,7 +2096,6 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
				goto out;

			new_dentry = dentry;
			rehash = NULL;
			new_inode = NULL;
		}
	}
@@ -2119,8 +2116,6 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
		error = task->tk_status;
	rpc_put_task(task);
out:
	if (rehash)
		d_rehash(rehash);
	trace_nfs_rename_exit(old_dir, old_dentry,
			new_dir, new_dentry, error);
	/* new dentry created? */
+96 −55
Original line number Diff line number Diff line
@@ -202,10 +202,10 @@ static int filelayout_async_handle_error(struct rpc_task *task,
			task->tk_status);
		nfs4_mark_deviceid_unavailable(devid);
		pnfs_error_mark_layout_for_return(inode, lseg);
		pnfs_set_lo_fail(lseg);
		rpc_wake_up(&tbl->slot_tbl_waitq);
		/* fall through */
	default:
		pnfs_set_lo_fail(lseg);
reset:
		dprintk("%s Retry through MDS. Error %d\n", __func__,
			task->tk_status);
@@ -560,6 +560,50 @@ filelayout_write_pagelist(struct nfs_pgio_header *hdr, int sync)
	return PNFS_ATTEMPTED;
}

static int
filelayout_check_deviceid(struct pnfs_layout_hdr *lo,
			  struct nfs4_filelayout_segment *fl,
			  gfp_t gfp_flags)
{
	struct nfs4_deviceid_node *d;
	struct nfs4_file_layout_dsaddr *dsaddr;
	int status = -EINVAL;

	/* find and reference the deviceid */
	d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode), &fl->deviceid,
			lo->plh_lc_cred, gfp_flags);
	if (d == NULL)
		goto out;

	dsaddr = container_of(d, struct nfs4_file_layout_dsaddr, id_node);
	/* Found deviceid is unavailable */
	if (filelayout_test_devid_unavailable(&dsaddr->id_node))
		goto out_put;

	fl->dsaddr = dsaddr;

	if (fl->first_stripe_index >= dsaddr->stripe_count) {
		dprintk("%s Bad first_stripe_index %u\n",
				__func__, fl->first_stripe_index);
		goto out_put;
	}

	if ((fl->stripe_type == STRIPE_SPARSE &&
	    fl->num_fh > 1 && fl->num_fh != dsaddr->ds_num) ||
	    (fl->stripe_type == STRIPE_DENSE &&
	    fl->num_fh != dsaddr->stripe_count)) {
		dprintk("%s num_fh %u not valid for given packing\n",
			__func__, fl->num_fh);
		goto out_put;
	}
	status = 0;
out:
	return status;
out_put:
	nfs4_fl_put_deviceid(dsaddr);
	goto out;
}

/*
 * filelayout_check_layout()
 *
@@ -572,11 +616,8 @@ static int
filelayout_check_layout(struct pnfs_layout_hdr *lo,
			struct nfs4_filelayout_segment *fl,
			struct nfs4_layoutget_res *lgr,
			struct nfs4_deviceid *id,
			gfp_t gfp_flags)
{
	struct nfs4_deviceid_node *d;
	struct nfs4_file_layout_dsaddr *dsaddr;
	int status = -EINVAL;

	dprintk("--> %s\n", __func__);
@@ -601,41 +642,10 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo,
		goto out;
	}

	/* find and reference the deviceid */
	d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode), id,
			lo->plh_lc_cred, gfp_flags);
	if (d == NULL)
		goto out;

	dsaddr = container_of(d, struct nfs4_file_layout_dsaddr, id_node);
	/* Found deviceid is unavailable */
	if (filelayout_test_devid_unavailable(&dsaddr->id_node))
		goto out_put;

	fl->dsaddr = dsaddr;

	if (fl->first_stripe_index >= dsaddr->stripe_count) {
		dprintk("%s Bad first_stripe_index %u\n",
				__func__, fl->first_stripe_index);
		goto out_put;
	}

	if ((fl->stripe_type == STRIPE_SPARSE &&
	    fl->num_fh > 1 && fl->num_fh != dsaddr->ds_num) ||
	    (fl->stripe_type == STRIPE_DENSE &&
	    fl->num_fh != dsaddr->stripe_count)) {
		dprintk("%s num_fh %u not valid for given packing\n",
			__func__, fl->num_fh);
		goto out_put;
	}

	status = 0;
out:
	dprintk("--> %s returns %d\n", __func__, status);
	return status;
out_put:
	nfs4_fl_put_deviceid(dsaddr);
	goto out;
}

static void _filelayout_free_lseg(struct nfs4_filelayout_segment *fl)
@@ -657,7 +667,6 @@ static int
filelayout_decode_layout(struct pnfs_layout_hdr *flo,
			 struct nfs4_filelayout_segment *fl,
			 struct nfs4_layoutget_res *lgr,
			 struct nfs4_deviceid *id,
			 gfp_t gfp_flags)
{
	struct xdr_stream stream;
@@ -682,9 +691,9 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo,
	if (unlikely(!p))
		goto out_err;

	memcpy(id, p, sizeof(*id));
	memcpy(&fl->deviceid, p, sizeof(fl->deviceid));
	p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
	nfs4_print_deviceid(id);
	nfs4_print_deviceid(&fl->deviceid);

	nfl_util = be32_to_cpup(p++);
	if (nfl_util & NFL4_UFLG_COMMIT_THRU_MDS)
@@ -831,15 +840,14 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
{
	struct nfs4_filelayout_segment *fl;
	int rc;
	struct nfs4_deviceid id;

	dprintk("--> %s\n", __func__);
	fl = kzalloc(sizeof(*fl), gfp_flags);
	if (!fl)
		return NULL;

	rc = filelayout_decode_layout(layoutid, fl, lgr, &id, gfp_flags);
	if (rc != 0 || filelayout_check_layout(layoutid, fl, lgr, &id, gfp_flags)) {
	rc = filelayout_decode_layout(layoutid, fl, lgr, gfp_flags);
	if (rc != 0 || filelayout_check_layout(layoutid, fl, lgr, gfp_flags)) {
		_filelayout_free_lseg(fl);
		return NULL;
	}
@@ -888,12 +896,45 @@ filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
	return min(stripe_unit - (unsigned int)stripe_offset, size);
}

static struct pnfs_layout_segment *
fl_pnfs_update_layout(struct inode *ino,
		      struct nfs_open_context *ctx,
		      loff_t pos,
		      u64 count,
		      enum pnfs_iomode iomode,
		      bool strict_iomode,
		      gfp_t gfp_flags)
{
	struct pnfs_layout_segment *lseg = NULL;
	struct pnfs_layout_hdr *lo;
	struct nfs4_filelayout_segment *fl;
	int status;

	lseg = pnfs_update_layout(ino, ctx, pos, count, iomode, strict_iomode,
				  gfp_flags);
	if (!lseg)
		lseg = ERR_PTR(-ENOMEM);
	if (IS_ERR(lseg))
		goto out;

	lo = NFS_I(ino)->layout;
	fl = FILELAYOUT_LSEG(lseg);

	status = filelayout_check_deviceid(lo, fl, gfp_flags);
	if (status)
		lseg = ERR_PTR(status);
out:
	if (IS_ERR(lseg))
		pnfs_put_lseg(lseg);
	return lseg;
}

static void
filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
			struct nfs_page *req)
{
	if (!pgio->pg_lseg) {
		pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
		pgio->pg_lseg = fl_pnfs_update_layout(pgio->pg_inode,
						      req->wb_context,
						      0,
						      NFS4_MAX_UINT64,
@@ -919,7 +960,7 @@ filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
	int status;

	if (!pgio->pg_lseg) {
		pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
		pgio->pg_lseg = fl_pnfs_update_layout(pgio->pg_inode,
						      req->wb_context,
						      0,
						      NFS4_MAX_UINT64,
+10 −9
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ struct nfs4_filelayout_segment {
	u32				stripe_unit;
	u32				first_stripe_index;
	u64				pattern_offset;
	struct nfs4_deviceid		deviceid;
	struct nfs4_file_layout_dsaddr	*dsaddr; /* Point to GETDEVINFO data */
	unsigned int			num_fh;
	struct nfs_fh			**fh_array;
+4 −0
Original line number Diff line number Diff line
@@ -208,6 +208,10 @@ static bool ff_layout_mirror_valid(struct pnfs_layout_segment *lseg,
		} else
			goto outerr;
	}

	if (IS_ERR(mirror->mirror_ds))
		goto outerr;

	if (mirror->mirror_ds->ds == NULL) {
		struct nfs4_deviceid_node *devid;
		devid = &mirror->mirror_ds->id_node;
+3 −6
Original line number Diff line number Diff line
@@ -2442,17 +2442,14 @@ static void nfs41_check_delegation_stateid(struct nfs4_state *state)
	}

	nfs4_stateid_copy(&stateid, &delegation->stateid);
	if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) {
	if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) ||
		!test_and_clear_bit(NFS_DELEGATION_TEST_EXPIRED,
			&delegation->flags)) {
		rcu_read_unlock();
		nfs_finish_clear_delegation_stateid(state, &stateid);
		return;
	}

	if (!test_and_clear_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags)) {
		rcu_read_unlock();
		return;
	}

	cred = get_rpccred(delegation->cred);
	rcu_read_unlock();
	status = nfs41_test_and_free_expired_stateid(server, &stateid, cred);