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

Commit e755d638 authored by Peng Tao's avatar Peng Tao Committed by Trond Myklebust
Browse files

NFS41: make sure sending LAYOUTRETURN before close if marked so



If layout is marked by NFS_LAYOUT_RETURN_BEFORE_CLOSE, we should always
send LAYOUTRETURN before close, and we don't need to do ROC drain if we
do send LAYOUTRETURN.

Signed-off-by: default avatarPeng Tao <tao.peng@primarydata.com>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
parent 36319608
Loading
Loading
Loading
Loading
+28 −23
Original line number Diff line number Diff line
@@ -1064,7 +1064,7 @@ bool pnfs_roc(struct inode *ino)
	struct pnfs_layout_segment *lseg, *tmp;
	nfs4_stateid stateid;
	LIST_HEAD(tmp_list);
	bool found = false, layoutreturn = false;
	bool found = false, layoutreturn = false, roc = false;

	spin_lock(&ino->i_lock);
	lo = nfsi->layout;
@@ -1072,7 +1072,7 @@ bool pnfs_roc(struct inode *ino)
	    test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags))
		goto out_noroc;

	/* Don't return layout if we hold a delegation */
	/* no roc if we hold a delegation */
	if (nfs4_check_delegation(ino, FMODE_READ))
		goto out_noroc;

@@ -1083,36 +1083,41 @@ bool pnfs_roc(struct inode *ino)
			goto out_noroc;
	}

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

	pnfs_clear_retry_layoutget(lo);
	list_for_each_entry_safe(lseg, tmp, &lo->plh_segs, pls_list)
		if (test_bit(NFS_LSEG_ROC, &lseg->pls_flags)) {
		/* If we are sending layoutreturn, invalidate all valid lsegs */
		if (layoutreturn || test_bit(NFS_LSEG_ROC, &lseg->pls_flags)) {
			mark_lseg_invalid(lseg, &tmp_list);
			found = true;
		}
	if (!found)
		goto out_noroc;
	if (test_and_set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
		goto out_noroc;
	lo->plh_return_iomode = IOMODE_ANY;
	pnfs_get_layout_hdr(lo); /* matched in pnfs_roc_release */
	spin_unlock(&ino->i_lock);
	pnfs_free_lseg_list(&tmp_list);
	pnfs_layoutcommit_inode(ino, true);
	return true;
	/* pnfs_prepare_layoutreturn() grabs lo ref and it will be put
	 * in pnfs_roc_release(). We don't really send a layoutreturn but
	 * still want others to view us like we are sending one!
	 *
	 * If pnfs_prepare_layoutreturn() fails, it means someone else is doing
	 * LAYOUTRETURN, so we proceed like there are no layouts to return.
	 *
	 * ROC in three conditions:
	 * 1. there are ROC lsegs
	 * 2. we don't send layoutreturn
	 * 3. no others are sending layoutreturn
	 */
	if (found && !layoutreturn && pnfs_prepare_layoutreturn(lo))
		roc = true;

out_noroc:
	if (lo) {
		stateid = lo->plh_stateid;
		if (test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
					   &lo->plh_flags))
			layoutreturn = pnfs_prepare_layoutreturn(lo);
	}
	spin_unlock(&ino->i_lock);
	if (layoutreturn) {
	pnfs_free_lseg_list(&tmp_list);
	pnfs_layoutcommit_inode(ino, true);
	if (layoutreturn)
		pnfs_send_layoutreturn(lo, stateid, IOMODE_ANY, true);
	}
	return false;
	return roc;
}

void pnfs_roc_release(struct inode *ino)