xfs: swap leaf buffer into path struct atomically during path shift
[firefly-linux-kernel-4.4.55.git] / fs / xfs / libxfs / xfs_da_btree.c
index e9f6709a3846e093f95eb23c70b21e4dd97ac9c5..f6a8631dc771b485e58b39f8432fa1c97c7368bb 100644 (file)
@@ -1822,6 +1822,7 @@ xfs_da3_path_shift(
        struct xfs_da_args      *args;
        struct xfs_da_node_entry *btree;
        struct xfs_da3_icnode_hdr nodehdr;
+       struct xfs_buf          *bp;
        xfs_dablk_t             blkno = 0;
        int                     level;
        int                     error;
@@ -1866,20 +1867,24 @@ xfs_da3_path_shift(
         */
        for (blk++, level++; level < path->active; blk++, level++) {
                /*
-                * Release the old block.
-                * (if it's dirty, trans won't actually let go)
+                * Read the next child block into a local buffer.
                 */
-               if (release)
-                       xfs_trans_brelse(args->trans, blk->bp);
+               error = xfs_da3_node_read(args->trans, dp, blkno, -1, &bp,
+                                         args->whichfork);
+               if (error)
+                       return error;
 
                /*
-                * Read the next child block.
+                * Release the old block (if it's dirty, the trans doesn't
+                * actually let go) and swap the local buffer into the path
+                * structure. This ensures failure of the above read doesn't set
+                * a NULL buffer in an active slot in the path.
                 */
+               if (release)
+                       xfs_trans_brelse(args->trans, blk->bp);
                blk->blkno = blkno;
-               error = xfs_da3_node_read(args->trans, dp, blkno, -1,
-                                       &blk->bp, args->whichfork);
-               if (error)
-                       return error;
+               blk->bp = bp;
+
                info = blk->bp->b_addr;
                ASSERT(info->magic == cpu_to_be16(XFS_DA_NODE_MAGIC) ||
                       info->magic == cpu_to_be16(XFS_DA3_NODE_MAGIC) ||