pnfs: rework LAYOUTGET retry handling
[deliverable/linux.git] / fs / nfs / pnfs.c
index 2a609af845fe75ef9e904b1dbc2cd669ae930ce5..46339a7fb1919521089689120574e3e775b27b21 100644 (file)
@@ -796,45 +796,18 @@ pnfs_layoutgets_blocked(const struct pnfs_layout_hdr *lo)
                test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags);
 }
 
-int
-pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo,
-                             const struct pnfs_layout_range *range,
-                             struct nfs4_state *open_state)
-{
-       int status = 0;
-
-       dprintk("--> %s\n", __func__);
-       spin_lock(&lo->plh_inode->i_lock);
-       if (pnfs_layoutgets_blocked(lo)) {
-               status = -EAGAIN;
-       } else if (!nfs4_valid_open_stateid(open_state)) {
-               status = -EBADF;
-       } else if (list_empty(&lo->plh_segs) ||
-                  test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags)) {
-               int seq;
-
-               do {
-                       seq = read_seqbegin(&open_state->seqlock);
-                       nfs4_stateid_copy(dst, &open_state->stateid);
-               } while (read_seqretry(&open_state->seqlock, seq));
-       } else
-               nfs4_stateid_copy(dst, &lo->plh_stateid);
-       spin_unlock(&lo->plh_inode->i_lock);
-       dprintk("<-- %s\n", __func__);
-       return status;
-}
-
 /*
-* Get layout from server.
-*    for now, assume that whole file layouts are requested.
-*    arg->offset: 0
-*    arg->length: all ones
-*/
+ * Get layout from server.
+ *    for now, assume that whole file layouts are requested.
+ *    arg->offset: 0
+ *    arg->length: all ones
+ */
 static struct pnfs_layout_segment *
 send_layoutget(struct pnfs_layout_hdr *lo,
           struct nfs_open_context *ctx,
+          nfs4_stateid *stateid,
           const struct pnfs_layout_range *range,
-          gfp_t gfp_flags)
+          long *timeout, gfp_t gfp_flags)
 {
        struct inode *ino = lo->plh_inode;
        struct nfs_server *server = NFS_SERVER(ino);
@@ -868,10 +841,11 @@ send_layoutget(struct pnfs_layout_hdr *lo,
        lgp->args.type = server->pnfs_curr_ld->id;
        lgp->args.inode = ino;
        lgp->args.ctx = get_nfs_open_context(ctx);
+       nfs4_stateid_copy(&lgp->args.stateid, stateid);
        lgp->gfp_flags = gfp_flags;
        lgp->cred = lo->plh_lc_cred;
 
-       return nfs4_proc_layoutget(lgp, gfp_flags);
+       return nfs4_proc_layoutget(lgp, timeout, gfp_flags);
 }
 
 static void pnfs_clear_layoutcommit(struct inode *inode,
@@ -1511,27 +1485,30 @@ pnfs_update_layout(struct inode *ino,
                .offset = pos,
                .length = count,
        };
-       unsigned pg_offset;
+       unsigned pg_offset, seq;
        struct nfs_server *server = NFS_SERVER(ino);
        struct nfs_client *clp = server->nfs_client;
-       struct pnfs_layout_hdr *lo;
+       struct pnfs_layout_hdr *lo = NULL;
        struct pnfs_layout_segment *lseg = NULL;
+       nfs4_stateid stateid;
+       long timeout = 0;
+       unsigned long giveup = jiffies + rpc_get_timeout(server->client);
        bool first;
 
        if (!pnfs_enabled_sb(NFS_SERVER(ino))) {
-               trace_pnfs_update_layout(ino, pos, count, iomode, NULL,
+               trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
                                 PNFS_UPDATE_LAYOUT_NO_PNFS);
                goto out;
        }
 
        if (iomode == IOMODE_READ && i_size_read(ino) == 0) {
-               trace_pnfs_update_layout(ino, pos, count, iomode, NULL,
+               trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
                                 PNFS_UPDATE_LAYOUT_RD_ZEROLEN);
                goto out;
        }
 
        if (pnfs_within_mdsthreshold(ctx, ino, iomode)) {
-               trace_pnfs_update_layout(ino, pos, count, iomode, NULL,
+               trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
                                 PNFS_UPDATE_LAYOUT_MDSTHRESH);
                goto out;
        }
@@ -1542,14 +1519,14 @@ lookup_again:
        lo = pnfs_find_alloc_layout(ino, ctx, gfp_flags);
        if (lo == NULL) {
                spin_unlock(&ino->i_lock);
-               trace_pnfs_update_layout(ino, pos, count, iomode, NULL,
+               trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
                                 PNFS_UPDATE_LAYOUT_NOMEM);
                goto out;
        }
 
        /* Do we even need to bother with this? */
        if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
-               trace_pnfs_update_layout(ino, pos, count, iomode, lo,
+               trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
                                 PNFS_UPDATE_LAYOUT_BULK_RECALL);
                dprintk("%s matches recall, use MDS\n", __func__);
                goto out_unlock;
@@ -1557,14 +1534,34 @@ lookup_again:
 
        /* if LAYOUTGET already failed once we don't try again */
        if (pnfs_layout_io_test_failed(lo, iomode)) {
-               trace_pnfs_update_layout(ino, pos, count, iomode, lo,
+               trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
                                 PNFS_UPDATE_LAYOUT_IO_TEST_FAIL);
                goto out_unlock;
        }
 
-       first = list_empty(&lo->plh_segs);
-       if (first) {
-               /* The first layoutget for the file. Need to serialize per
+       lseg = pnfs_find_lseg(lo, &arg);
+       if (lseg) {
+               trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
+                               PNFS_UPDATE_LAYOUT_FOUND_CACHED);
+               goto out_unlock;
+       }
+
+       if (!nfs4_valid_open_stateid(ctx->state)) {
+               trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
+                               PNFS_UPDATE_LAYOUT_INVALID_OPEN);
+               goto out_unlock;
+       }
+
+       /*
+        * Choose a stateid for the LAYOUTGET. If we don't have a layout
+        * stateid, or it has been invalidated, then we must use the open
+        * stateid.
+        */
+       if (lo->plh_stateid.seqid == 0 ||
+           test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags)) {
+
+               /*
+                * The first layoutget for the file. Need to serialize per
                 * RFC 5661 Errata 3208.
                 */
                if (test_and_set_bit(NFS_LAYOUT_FIRST_LAYOUTGET,
@@ -1573,18 +1570,17 @@ lookup_again:
                        wait_on_bit(&lo->plh_flags, NFS_LAYOUT_FIRST_LAYOUTGET,
                                    TASK_UNINTERRUPTIBLE);
                        pnfs_put_layout_hdr(lo);
+                       dprintk("%s retrying\n", __func__);
                        goto lookup_again;
                }
+
+               first = true;
+               do {
+                       seq = read_seqbegin(&ctx->state->seqlock);
+                       nfs4_stateid_copy(&stateid, &ctx->state->stateid);
+               } while (read_seqretry(&ctx->state->seqlock, seq));
        } else {
-               /* Check to see if the layout for the given range
-                * already exists
-                */
-               lseg = pnfs_find_lseg(lo, &arg);
-               if (lseg) {
-                       trace_pnfs_update_layout(ino, pos, count, iomode, lo,
-                                       PNFS_UPDATE_LAYOUT_FOUND_CACHED);
-                       goto out_unlock;
-               }
+               nfs4_stateid_copy(&stateid, &lo->plh_stateid);
        }
 
        /*
@@ -1599,15 +1595,17 @@ lookup_again:
                                pnfs_clear_first_layoutget(lo);
                        pnfs_put_layout_hdr(lo);
                        dprintk("%s retrying\n", __func__);
+                       trace_pnfs_update_layout(ino, pos, count, iomode, lo,
+                                       lseg, PNFS_UPDATE_LAYOUT_RETRY);
                        goto lookup_again;
                }
-               trace_pnfs_update_layout(ino, pos, count, iomode, lo,
+               trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
                                PNFS_UPDATE_LAYOUT_RETURN);
                goto out_put_layout_hdr;
        }
 
        if (pnfs_layoutgets_blocked(lo)) {
-               trace_pnfs_update_layout(ino, pos, count, iomode, lo,
+               trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
                                PNFS_UPDATE_LAYOUT_BLOCKED);
                goto out_unlock;
        }
@@ -1632,26 +1630,36 @@ lookup_again:
        if (arg.length != NFS4_MAX_UINT64)
                arg.length = PAGE_ALIGN(arg.length);
 
-       lseg = send_layoutget(lo, ctx, &arg, gfp_flags);
+       lseg = send_layoutget(lo, ctx, &stateid, &arg, &timeout, gfp_flags);
+       trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
+                                PNFS_UPDATE_LAYOUT_SEND_LAYOUTGET);
        if (IS_ERR(lseg)) {
-               if (lseg == ERR_PTR(-EAGAIN)) {
+               switch(PTR_ERR(lseg)) {
+               case -ERECALLCONFLICT:
+                       if (time_after(jiffies, giveup))
+                               lseg = NULL;
+                       /* Fallthrough */
+               case -EAGAIN:
+                       pnfs_put_layout_hdr(lo);
                        if (first)
                                pnfs_clear_first_layoutget(lo);
-                       pnfs_put_layout_hdr(lo);
-                       goto lookup_again;
-               }
-
-               if (!nfs_error_is_fatal(PTR_ERR(lseg))) {
-                       pnfs_layout_clear_fail_bit(lo, pnfs_iomode_to_fail_bit(iomode));
-                       lseg = NULL;
+                       if (lseg) {
+                               trace_pnfs_update_layout(ino, pos, count,
+                                       iomode, lo, lseg, PNFS_UPDATE_LAYOUT_RETRY);
+                               goto lookup_again;
+                       }
+                       /* Fallthrough */
+               default:
+                       if (!nfs_error_is_fatal(PTR_ERR(lseg))) {
+                               pnfs_layout_clear_fail_bit(lo, pnfs_iomode_to_fail_bit(iomode));
+                               lseg = NULL;
+                       }
                }
        } else {
                pnfs_layout_clear_fail_bit(lo, pnfs_iomode_to_fail_bit(iomode));
        }
 
        atomic_dec(&lo->plh_outstanding);
-       trace_pnfs_update_layout(ino, pos, count, iomode, lo,
-                                PNFS_UPDATE_LAYOUT_SEND_LAYOUTGET);
 out_put_layout_hdr:
        if (first)
                pnfs_clear_first_layoutget(lo);
This page took 0.028835 seconds and 5 git commands to generate.