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

Commit 81b676bd authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull NFS client bugfix and cleanup from Trond Myklebust:
 "Bugfix:
   - pNFS: Fix for missing layoutreturn calls

  Cleanup:
   - pNFS: rename NFS_LAYOUT_RETURN_BEFORE_CLOSE for code clarity"

* tag 'nfs-for-4.5-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  NFS: Cleanup - rename NFS_LAYOUT_RETURN_BEFORE_CLOSE
  pNFS: Fix missing layoutreturn calls
parents ef582d09 2370abda
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1215,7 +1215,7 @@ static int ff_layout_read_done_cb(struct rpc_task *task,
					hdr->pgio_mirror_idx + 1,
					&hdr->pgio_mirror_idx))
			goto out_eagain;
		set_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
		set_bit(NFS_LAYOUT_RETURN_REQUESTED,
			&hdr->lseg->pls_layout->plh_flags);
		pnfs_read_resend_pnfs(hdr);
		return task->tk_status;
+1 −1
Original line number Diff line number Diff line
@@ -412,7 +412,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
					 OP_ILLEGAL, GFP_NOIO);
		if (!fail_return) {
			if (ff_layout_has_available_ds(lseg))
				set_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
				set_bit(NFS_LAYOUT_RETURN_REQUESTED,
					&lseg->pls_layout->plh_flags);
			else
				pnfs_error_mark_layout_for_return(ino, lseg);
+58 −64
Original line number Diff line number Diff line
@@ -52,9 +52,7 @@ static DEFINE_SPINLOCK(pnfs_spinlock);
 */
static LIST_HEAD(pnfs_modules_tbl);

static int
pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, const nfs4_stateid *stateid,
		       enum pnfs_iomode iomode, bool sync);
static void pnfs_layoutreturn_before_put_layout_hdr(struct pnfs_layout_hdr *lo);

/* Return the registered pnfs layout driver module matching given id */
static struct pnfs_layoutdriver_type *
@@ -243,6 +241,8 @@ pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo)
{
	struct inode *inode = lo->plh_inode;

	pnfs_layoutreturn_before_put_layout_hdr(lo);

	if (atomic_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) {
		if (!list_empty(&lo->plh_segs))
			WARN_ONCE(1, "NFS: BUG unfreed layout segments.\n");
@@ -345,58 +345,6 @@ pnfs_layout_remove_lseg(struct pnfs_layout_hdr *lo,
	rpc_wake_up(&NFS_SERVER(inode)->roc_rpcwaitq);
}

/* Return true if layoutreturn is needed */
static bool
pnfs_layout_need_return(struct pnfs_layout_hdr *lo,
			struct pnfs_layout_segment *lseg)
{
	struct pnfs_layout_segment *s;

	if (!test_and_clear_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags))
		return false;

	list_for_each_entry(s, &lo->plh_segs, pls_list)
		if (s != lseg && test_bit(NFS_LSEG_LAYOUTRETURN, &s->pls_flags))
			return false;

	return true;
}

static bool
pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo)
{
	if (test_and_set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
		return false;
	lo->plh_return_iomode = 0;
	pnfs_get_layout_hdr(lo);
	clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, &lo->plh_flags);
	return true;
}

static void pnfs_layoutreturn_before_put_lseg(struct pnfs_layout_segment *lseg,
		struct pnfs_layout_hdr *lo, struct inode *inode)
{
	lo = lseg->pls_layout;
	inode = lo->plh_inode;

	spin_lock(&inode->i_lock);
	if (pnfs_layout_need_return(lo, lseg)) {
		nfs4_stateid stateid;
		enum pnfs_iomode iomode;
		bool send;

		nfs4_stateid_copy(&stateid, &lo->plh_stateid);
		iomode = lo->plh_return_iomode;
		send = pnfs_prepare_layoutreturn(lo);
		spin_unlock(&inode->i_lock);
		if (send) {
			/* Send an async layoutreturn so we dont deadlock */
			pnfs_send_layoutreturn(lo, &stateid, iomode, false);
		}
	} else
		spin_unlock(&inode->i_lock);
}

void
pnfs_put_lseg(struct pnfs_layout_segment *lseg)
{
@@ -410,15 +358,8 @@ pnfs_put_lseg(struct pnfs_layout_segment *lseg)
		atomic_read(&lseg->pls_refcount),
		test_bit(NFS_LSEG_VALID, &lseg->pls_flags));

	/* Handle the case where refcount != 1 */
	if (atomic_add_unless(&lseg->pls_refcount, -1, 1))
		return;

	lo = lseg->pls_layout;
	inode = lo->plh_inode;
	/* Do we need a layoutreturn? */
	if (test_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags))
		pnfs_layoutreturn_before_put_lseg(lseg, lo, inode);

	if (atomic_dec_and_lock(&lseg->pls_refcount, &inode->i_lock)) {
		if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags)) {
@@ -937,6 +878,17 @@ void pnfs_clear_layoutreturn_waitbit(struct pnfs_layout_hdr *lo)
	rpc_wake_up(&NFS_SERVER(lo->plh_inode)->roc_rpcwaitq);
}

static bool
pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo)
{
	if (test_and_set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
		return false;
	lo->plh_return_iomode = 0;
	pnfs_get_layout_hdr(lo);
	clear_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags);
	return true;
}

static int
pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, const nfs4_stateid *stateid,
		       enum pnfs_iomode iomode, bool sync)
@@ -971,6 +923,48 @@ pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, const nfs4_stateid *stateid,
	return status;
}

/* Return true if layoutreturn is needed */
static bool
pnfs_layout_need_return(struct pnfs_layout_hdr *lo)
{
	struct pnfs_layout_segment *s;

	if (!test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags))
		return false;

	/* Defer layoutreturn until all lsegs are done */
	list_for_each_entry(s, &lo->plh_segs, pls_list) {
		if (test_bit(NFS_LSEG_LAYOUTRETURN, &s->pls_flags))
			return false;
	}

	return true;
}

static void pnfs_layoutreturn_before_put_layout_hdr(struct pnfs_layout_hdr *lo)
{
	struct inode *inode= lo->plh_inode;

	if (!test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags))
		return;
	spin_lock(&inode->i_lock);
	if (pnfs_layout_need_return(lo)) {
		nfs4_stateid stateid;
		enum pnfs_iomode iomode;
		bool send;

		nfs4_stateid_copy(&stateid, &lo->plh_stateid);
		iomode = lo->plh_return_iomode;
		send = pnfs_prepare_layoutreturn(lo);
		spin_unlock(&inode->i_lock);
		if (send) {
			/* Send an async layoutreturn so we dont deadlock */
			pnfs_send_layoutreturn(lo, &stateid, iomode, false);
		}
	} else
		spin_unlock(&inode->i_lock);
}

/*
 * Initiates a LAYOUTRETURN(FILE), and removes the pnfs_layout_hdr
 * when the layout segment list is empty.
@@ -1091,7 +1085,7 @@ bool pnfs_roc(struct inode *ino)

	nfs4_stateid_copy(&stateid, &lo->plh_stateid);
	/* always send layoutreturn if being marked so */
	if (test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
	if (test_and_clear_bit(NFS_LAYOUT_RETURN_REQUESTED,
				   &lo->plh_flags))
		layoutreturn = pnfs_prepare_layoutreturn(lo);

@@ -1772,7 +1766,7 @@ pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
			pnfs_set_plh_return_iomode(lo, return_range->iomode);
			if (!mark_lseg_invalid(lseg, tmp_list))
				remaining++;
			set_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
			set_bit(NFS_LAYOUT_RETURN_REQUESTED,
					&lo->plh_flags);
		}
	return remaining;
+2 −2
Original line number Diff line number Diff line
@@ -94,8 +94,8 @@ enum {
	NFS_LAYOUT_RO_FAILED = 0,	/* get ro layout failed stop trying */
	NFS_LAYOUT_RW_FAILED,		/* get rw layout failed stop trying */
	NFS_LAYOUT_BULK_RECALL,		/* bulk recall affecting layout */
	NFS_LAYOUT_RETURN,		/* Return this layout ASAP */
	NFS_LAYOUT_RETURN_BEFORE_CLOSE,	/* Return this layout before close */
	NFS_LAYOUT_RETURN,		/* layoutreturn in progress */
	NFS_LAYOUT_RETURN_REQUESTED,	/* Return this layout ASAP */
	NFS_LAYOUT_INVALID_STID,	/* layout stateid id is invalid */
	NFS_LAYOUT_FIRST_LAYOUTGET,	/* Serialize first layoutget */
};