Skip to content

Commit 4f2e9dc

Browse files
jtlaytontrondmypd
authored andcommitted
nfs4: resend LAYOUTGET when there is a race that changes the seqid
pnfs_layout_process will check the returned layout stateid against what the kernel has in-core. If it turns out that the stateid we received is older, then we should resend the LAYOUTGET instead of falling back to MDS I/O. Signed-off-by: Jeff Layton <jeff.layton@primarydata.com> Cc: stable@vger.kernel.org # 3.18+ Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
1 parent c812012 commit 4f2e9dc

1 file changed

Lines changed: 31 additions & 25 deletions

File tree

fs/nfs/pnfs.c

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -872,33 +872,38 @@ send_layoutget(struct pnfs_layout_hdr *lo,
872872

873873
dprintk("--> %s\n", __func__);
874874

875-
lgp = kzalloc(sizeof(*lgp), gfp_flags);
876-
if (lgp == NULL)
877-
return NULL;
875+
/*
876+
* Synchronously retrieve layout information from server and
877+
* store in lseg. If we race with a concurrent seqid morphing
878+
* op, then re-send the LAYOUTGET.
879+
*/
880+
do {
881+
lgp = kzalloc(sizeof(*lgp), gfp_flags);
882+
if (lgp == NULL)
883+
return NULL;
884+
885+
i_size = i_size_read(ino);
886+
887+
lgp->args.minlength = PAGE_CACHE_SIZE;
888+
if (lgp->args.minlength > range->length)
889+
lgp->args.minlength = range->length;
890+
if (range->iomode == IOMODE_READ) {
891+
if (range->offset >= i_size)
892+
lgp->args.minlength = 0;
893+
else if (i_size - range->offset < lgp->args.minlength)
894+
lgp->args.minlength = i_size - range->offset;
895+
}
896+
lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE;
897+
lgp->args.range = *range;
898+
lgp->args.type = server->pnfs_curr_ld->id;
899+
lgp->args.inode = ino;
900+
lgp->args.ctx = get_nfs_open_context(ctx);
901+
lgp->gfp_flags = gfp_flags;
902+
lgp->cred = lo->plh_lc_cred;
878903

879-
i_size = i_size_read(ino);
904+
lseg = nfs4_proc_layoutget(lgp, gfp_flags);
905+
} while (lseg == ERR_PTR(-EAGAIN));
880906

881-
lgp->args.minlength = PAGE_CACHE_SIZE;
882-
if (lgp->args.minlength > range->length)
883-
lgp->args.minlength = range->length;
884-
if (range->iomode == IOMODE_READ) {
885-
if (range->offset >= i_size)
886-
lgp->args.minlength = 0;
887-
else if (i_size - range->offset < lgp->args.minlength)
888-
lgp->args.minlength = i_size - range->offset;
889-
}
890-
lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE;
891-
lgp->args.range = *range;
892-
lgp->args.type = server->pnfs_curr_ld->id;
893-
lgp->args.inode = ino;
894-
lgp->args.ctx = get_nfs_open_context(ctx);
895-
lgp->gfp_flags = gfp_flags;
896-
lgp->cred = lo->plh_lc_cred;
897-
898-
/* Synchronously retrieve layout information from server and
899-
* store in lseg.
900-
*/
901-
lseg = nfs4_proc_layoutget(lgp, gfp_flags);
902907
if (IS_ERR(lseg)) {
903908
switch (PTR_ERR(lseg)) {
904909
case -ENOMEM:
@@ -1687,6 +1692,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
16871692
/* existing state ID, make sure the sequence number matches. */
16881693
if (pnfs_layout_stateid_blocked(lo, &res->stateid)) {
16891694
dprintk("%s forget reply due to sequence\n", __func__);
1695+
status = -EAGAIN;
16901696
goto out_forget_reply;
16911697
}
16921698
pnfs_set_layout_stateid(lo, &res->stateid, false);

0 commit comments

Comments
 (0)