pNFS: Ensure layoutreturn acts as a completion for layout callbacks
[deliverable/linux.git] / fs / nfs / pnfs.c
index 0c7e0d45a4de6ee1fba11c40417d3fb01678049b..878dc4b7085a4fcadac423b2280fa097495150fd 100644 (file)
@@ -361,8 +361,10 @@ pnfs_layout_remove_lseg(struct pnfs_layout_hdr *lo,
        list_del_init(&lseg->pls_list);
        /* Matched by pnfs_get_layout_hdr in pnfs_layout_insert_lseg */
        atomic_dec(&lo->plh_refcount);
-       if (list_empty(&lo->plh_segs))
+       if (list_empty(&lo->plh_segs)) {
+               set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
                clear_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags);
+       }
        rpc_wake_up(&NFS_SERVER(inode)->roc_rpcwaitq);
 }
 
@@ -759,24 +761,25 @@ void
 pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, const nfs4_stateid *new,
                        bool update_barrier)
 {
-       u32 oldseq, newseq, new_barrier;
-       int empty = list_empty(&lo->plh_segs);
+       u32 oldseq, newseq, new_barrier = 0;
+       bool invalid = !pnfs_layout_is_valid(lo);
 
        oldseq = be32_to_cpu(lo->plh_stateid.seqid);
        newseq = be32_to_cpu(new->seqid);
-       if (empty || pnfs_seqid_is_newer(newseq, oldseq)) {
+       if (invalid || pnfs_seqid_is_newer(newseq, oldseq)) {
                nfs4_stateid_copy(&lo->plh_stateid, new);
-               if (update_barrier) {
-                       new_barrier = be32_to_cpu(new->seqid);
-               } else {
-                       /* Because of wraparound, we want to keep the barrier
-                        * "close" to the current seqids.
-                        */
-                       new_barrier = newseq - atomic_read(&lo->plh_outstanding);
-               }
-               if (empty || pnfs_seqid_is_newer(new_barrier, lo->plh_barrier))
-                       lo->plh_barrier = new_barrier;
+               /*
+                * Because of wraparound, we want to keep the barrier
+                * "close" to the current seqids.
+                */
+               new_barrier = newseq - atomic_read(&lo->plh_outstanding);
        }
+       if (update_barrier)
+               new_barrier = be32_to_cpu(new->seqid);
+       else if (new_barrier == 0)
+               return;
+       if (invalid || pnfs_seqid_is_newer(new_barrier, lo->plh_barrier))
+               lo->plh_barrier = new_barrier;
 }
 
 static bool
@@ -871,15 +874,37 @@ void pnfs_clear_layoutreturn_waitbit(struct pnfs_layout_hdr *lo)
        rpc_wake_up(&NFS_SERVER(lo->plh_inode)->roc_rpcwaitq);
 }
 
+static void
+pnfs_clear_layoutreturn_info(struct pnfs_layout_hdr *lo)
+{
+       lo->plh_return_iomode = 0;
+       lo->plh_return_seq = 0;
+       clear_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags);
+}
+
 static bool
-pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo)
+pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo,
+               nfs4_stateid *stateid,
+               enum pnfs_iomode *iomode)
 {
        if (test_and_set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
                return false;
-       lo->plh_return_iomode = 0;
-       lo->plh_return_seq = 0;
        pnfs_get_layout_hdr(lo);
-       clear_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags);
+       if (test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags)) {
+               if (stateid != NULL) {
+                       nfs4_stateid_copy(stateid, &lo->plh_stateid);
+                       if (lo->plh_return_seq != 0)
+                               stateid->seqid = cpu_to_be32(lo->plh_return_seq);
+               }
+               if (iomode != NULL)
+                       *iomode = lo->plh_return_iomode;
+               pnfs_clear_layoutreturn_info(lo);
+               return true;
+       }
+       if (stateid != NULL)
+               nfs4_stateid_copy(stateid, &lo->plh_stateid);
+       if (iomode != NULL)
+               *iomode = IOMODE_ANY;
        return true;
 }
 
@@ -947,10 +972,7 @@ static void pnfs_layoutreturn_before_put_layout_hdr(struct pnfs_layout_hdr *lo)
                enum pnfs_iomode iomode;
                bool send;
 
-               nfs4_stateid_copy(&stateid, &lo->plh_stateid);
-               stateid.seqid = cpu_to_be32(lo->plh_return_seq);
-               iomode = lo->plh_return_iomode;
-               send = pnfs_prepare_layoutreturn(lo);
+               send = pnfs_prepare_layoutreturn(lo, &stateid, &iomode);
                spin_unlock(&inode->i_lock);
                if (send) {
                        /* Send an async layoutreturn so we dont deadlock */
@@ -987,7 +1009,6 @@ _pnfs_return_layout(struct inode *ino)
                dprintk("NFS: %s no layout to return\n", __func__);
                goto out;
        }
-       nfs4_stateid_copy(&stateid, &nfsi->layout->plh_stateid);
        /* Reference matched in nfs4_layoutreturn_release */
        pnfs_get_layout_hdr(lo);
        empty = list_empty(&lo->plh_segs);
@@ -1011,7 +1032,7 @@ _pnfs_return_layout(struct inode *ino)
        }
 
        set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
-       send = pnfs_prepare_layoutreturn(lo);
+       send = pnfs_prepare_layoutreturn(lo, &stateid, NULL);
        spin_unlock(&ino->i_lock);
        pnfs_free_lseg_list(&tmp_list);
        if (send)
@@ -1078,11 +1099,10 @@ bool pnfs_roc(struct inode *ino)
                        goto out_noroc;
        }
 
-       nfs4_stateid_copy(&stateid, &lo->plh_stateid);
        /* always send layoutreturn if being marked so */
-       if (test_and_clear_bit(NFS_LAYOUT_RETURN_REQUESTED,
-                                  &lo->plh_flags))
-               layoutreturn = pnfs_prepare_layoutreturn(lo);
+       if (test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags))
+               layoutreturn = pnfs_prepare_layoutreturn(lo,
+                               &stateid, NULL);
 
        list_for_each_entry_safe(lseg, tmp, &lo->plh_segs, pls_list)
                /* If we are sending layoutreturn, invalidate all valid lsegs */
@@ -1290,6 +1310,7 @@ alloc_init_layout_hdr(struct inode *ino,
        INIT_LIST_HEAD(&lo->plh_bulk_destroy);
        lo->plh_inode = ino;
        lo->plh_lc_cred = get_rpccred(ctx->cred);
+       lo->plh_flags |= 1 << NFS_LAYOUT_INVALID_STID;
        return lo;
 }
 
@@ -1297,6 +1318,8 @@ static struct pnfs_layout_hdr *
 pnfs_find_alloc_layout(struct inode *ino,
                       struct nfs_open_context *ctx,
                       gfp_t gfp_flags)
+       __releases(&ino->i_lock)
+       __acquires(&ino->i_lock)
 {
        struct nfs_inode *nfsi = NFS_I(ino);
        struct pnfs_layout_hdr *new = NULL;
@@ -1565,8 +1588,7 @@ lookup_again:
         * 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)) {
+       if (test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags)) {
 
                /*
                 * The first layoutget for the file. Need to serialize per
@@ -1760,10 +1782,13 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
                lo->plh_barrier = be32_to_cpu(res->stateid.seqid);
        }
 
-       clear_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
-
        pnfs_get_lseg(lseg);
        pnfs_layout_insert_lseg(lo, lseg, &free_me);
+       if (!pnfs_layout_is_valid(lo)) {
+               pnfs_clear_layoutreturn_info(lo);
+               clear_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
+       }
+
 
        if (res->return_on_close)
                set_bit(NFS_LSEG_ROC, &lseg->pls_flags);
@@ -1860,10 +1885,9 @@ void pnfs_error_mark_layout_for_return(struct inode *inode,
        if (!pnfs_mark_matching_lsegs_return(lo, &free_me,
                                                &range, lseg->pls_seq)) {
                nfs4_stateid stateid;
-               enum pnfs_iomode iomode = lo->plh_return_iomode;
+               enum pnfs_iomode iomode;
 
-               nfs4_stateid_copy(&stateid, &lo->plh_stateid);
-               return_now = pnfs_prepare_layoutreturn(lo);
+               return_now = pnfs_prepare_layoutreturn(lo, &stateid, &iomode);
                spin_unlock(&inode->i_lock);
                if (return_now)
                        pnfs_send_layoutreturn(lo, &stateid, iomode, false);
This page took 0.030623 seconds and 5 git commands to generate.