These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / fs / xfs / libxfs / xfs_bmap.c
index f1026e8..119c242 100644 (file)
@@ -948,14 +948,16 @@ xfs_bmap_local_to_extents(
        bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0);
 
        /*
-        * Initialise the block and copy the data
+        * Initialize the block, copy the data and log the remote buffer.
         *
-        * Note: init_fn must set the buffer log item type correctly!
+        * The callout is responsible for logging because the remote format
+        * might differ from the local format and thus we don't know how much to
+        * log here. Note that init_fn must also set the buffer log item type
+        * correctly.
         */
        init_fn(tp, bp, ip, ifp);
 
-       /* account for the change in fork size and log everything */
-       xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
+       /* account for the change in fork size */
        xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
        xfs_bmap_local_to_extents_empty(ip, whichfork);
        flags |= XFS_ILOG_CORE;
@@ -1112,7 +1114,6 @@ xfs_bmap_add_attrfork(
        int                     committed;      /* xaction was committed */
        int                     logflags;       /* logging flags */
        int                     error;          /* error return value */
-       int                     cancel_flags = 0;
 
        ASSERT(XFS_IFORK_Q(ip) == 0);
 
@@ -1124,17 +1125,15 @@ xfs_bmap_add_attrfork(
                tp->t_flags |= XFS_TRANS_RESERVE;
        error = xfs_trans_reserve(tp, &M_RES(mp)->tr_addafork, blks, 0);
        if (error) {
-               xfs_trans_cancel(tp, 0);
+               xfs_trans_cancel(tp);
                return error;
        }
-       cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
        xfs_ilock(ip, XFS_ILOCK_EXCL);
        error = xfs_trans_reserve_quota_nblks(tp, ip, blks, 0, rsvd ?
                        XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
                        XFS_QMOPT_RES_REGBLKS);
        if (error)
                goto trans_cancel;
-       cancel_flags |= XFS_TRANS_ABORT;
        if (XFS_IFORK_Q(ip))
                goto trans_cancel;
        if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS) {
@@ -1218,14 +1217,14 @@ xfs_bmap_add_attrfork(
        error = xfs_bmap_finish(&tp, &flist, &committed);
        if (error)
                goto bmap_cancel;
-       error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
+       error = xfs_trans_commit(tp);
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
        return error;
 
 bmap_cancel:
        xfs_bmap_cancel(&flist);
 trans_cancel:
-       xfs_trans_cancel(tp, cancel_flags);
+       xfs_trans_cancel(tp);
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
        return error;
 }
@@ -1438,7 +1437,7 @@ xfs_bmap_search_extents(
        xfs_ifork_t     *ifp;           /* inode fork pointer */
        xfs_bmbt_rec_host_t  *ep;            /* extent record pointer */
 
-       XFS_STATS_INC(xs_look_exlist);
+       XFS_STATS_INC(ip->i_mount, xs_look_exlist);
        ifp = XFS_IFORK_PTR(ip, fork);
 
        ep = xfs_bmap_search_multi_extents(ifp, bno, eofp, lastxp, gotp, prevp);
@@ -1735,7 +1734,7 @@ xfs_bmap_add_extent_delay_real(
        ASSERT(!bma->cur ||
               (bma->cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL));
 
-       XFS_STATS_INC(xs_add_exlist);
+       XFS_STATS_INC(mp, xs_add_exlist);
 
 #define        LEFT            r[0]
 #define        RIGHT           r[1]
@@ -2289,7 +2288,7 @@ xfs_bmap_add_extent_unwritten_real(
        ASSERT(*idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec));
        ASSERT(!isnullstartblock(new->br_startblock));
 
-       XFS_STATS_INC(xs_add_exlist);
+       XFS_STATS_INC(mp, xs_add_exlist);
 
 #define        LEFT            r[0]
 #define        RIGHT           r[1]
@@ -2949,7 +2948,7 @@ xfs_bmap_add_extent_hole_real(
        ASSERT(!bma->cur ||
               !(bma->cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL));
 
-       XFS_STATS_INC(xs_add_exlist);
+       XFS_STATS_INC(mp, xs_add_exlist);
 
        state = 0;
        if (whichfork == XFS_ATTR_FORK)
@@ -3521,7 +3520,8 @@ xfs_bmap_longest_free_extent(
                }
        }
 
-       longest = xfs_alloc_longest_free_extent(mp, pag);
+       longest = xfs_alloc_longest_free_extent(mp, pag,
+                                       xfs_alloc_min_freelist(mp, pag));
        if (*blen < longest)
                *blen = longest;
 
@@ -3802,8 +3802,13 @@ xfs_bmap_btalloc(
        args.wasdel = ap->wasdel;
        args.isfl = 0;
        args.userdata = ap->userdata;
-       if ((error = xfs_alloc_vextent(&args)))
+       if (ap->userdata & XFS_ALLOC_USERDATA_ZERO)
+               args.ip = ap->ip;
+
+       error = xfs_alloc_vextent(&args);
+       if (error)
                return error;
+
        if (tryagain && args.fsbno == NULLFSBLOCK) {
                /*
                 * Exact allocation failed. Now try with alignment
@@ -4038,7 +4043,7 @@ xfs_bmapi_read(
        if (XFS_FORCED_SHUTDOWN(mp))
                return -EIO;
 
-       XFS_STATS_INC(xs_blk_mapr);
+       XFS_STATS_INC(mp, xs_blk_mapr);
 
        ifp = XFS_IFORK_PTR(ip, whichfork);
 
@@ -4223,7 +4228,7 @@ xfs_bmapi_delay(
        if (XFS_FORCED_SHUTDOWN(mp))
                return -EIO;
 
-       XFS_STATS_INC(xs_blk_mapw);
+       XFS_STATS_INC(mp, xs_blk_mapw);
 
        if (!(ifp->if_flags & XFS_IFEXTENTS)) {
                error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK);
@@ -4302,11 +4307,14 @@ xfs_bmapi_allocate(
 
        /*
         * Indicate if this is the first user data in the file, or just any
-        * user data.
+        * user data. And if it is userdata, indicate whether it needs to
+        * be initialised to zero during allocation.
         */
        if (!(bma->flags & XFS_BMAPI_METADATA)) {
                bma->userdata = (bma->offset == 0) ?
                        XFS_ALLOC_INITIAL_USER_DATA : XFS_ALLOC_USERDATA;
+               if (bma->flags & XFS_BMAPI_ZERO)
+                       bma->userdata |= XFS_ALLOC_USERDATA_ZERO;
        }
 
        bma->minlen = (bma->flags & XFS_BMAPI_CONTIG) ? bma->length : 1;
@@ -4421,10 +4429,29 @@ xfs_bmapi_convert_unwritten(
        mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN)
                                ? XFS_EXT_NORM : XFS_EXT_UNWRITTEN;
 
+       /*
+        * Before insertion into the bmbt, zero the range being converted
+        * if required.
+        */
+       if (flags & XFS_BMAPI_ZERO) {
+               error = xfs_zero_extent(bma->ip, mval->br_startblock,
+                                       mval->br_blockcount);
+               if (error)
+                       return error;
+       }
+
        error = xfs_bmap_add_extent_unwritten_real(bma->tp, bma->ip, &bma->idx,
                        &bma->cur, mval, bma->firstblock, bma->flist,
                        &tmp_logflags);
-       bma->logflags |= tmp_logflags;
+       /*
+        * Log the inode core unconditionally in the unwritten extent conversion
+        * path because the conversion might not have done so (e.g., if the
+        * extent count hasn't changed). We need to make sure the inode is dirty
+        * in the transaction for the sake of fsync(), even if nothing has
+        * changed, because fsync() will not force the log for this transaction
+        * unless it sees the inode pinned.
+        */
+       bma->logflags |= tmp_logflags | XFS_ILOG_CORE;
        if (error)
                return error;
 
@@ -4506,6 +4533,18 @@ xfs_bmapi_write(
        ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL);
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 
+       /* zeroing is for currently only for data extents, not metadata */
+       ASSERT((flags & (XFS_BMAPI_METADATA | XFS_BMAPI_ZERO)) !=
+                       (XFS_BMAPI_METADATA | XFS_BMAPI_ZERO));
+       /*
+        * we can allocate unwritten extents or pre-zero allocated blocks,
+        * but it makes no sense to do both at once. This would result in
+        * zeroing the unwritten extent twice, but it still being an
+        * unwritten extent....
+        */
+       ASSERT((flags & (XFS_BMAPI_PREALLOC | XFS_BMAPI_ZERO)) !=
+                       (XFS_BMAPI_PREALLOC | XFS_BMAPI_ZERO));
+
        if (unlikely(XFS_TEST_ERROR(
            (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
             XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
@@ -4519,7 +4558,7 @@ xfs_bmapi_write(
 
        ifp = XFS_IFORK_PTR(ip, whichfork);
 
-       XFS_STATS_INC(xs_blk_mapw);
+       XFS_STATS_INC(mp, xs_blk_mapw);
 
        if (*firstblock == NULLFSBLOCK) {
                if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE)
@@ -4712,12 +4751,12 @@ xfs_bmap_del_extent(
        xfs_filblks_t           temp2;  /* for indirect length calculations */
        int                     state = 0;
 
-       XFS_STATS_INC(xs_del_exlist);
+       mp = ip->i_mount;
+       XFS_STATS_INC(mp, xs_del_exlist);
 
        if (whichfork == XFS_ATTR_FORK)
                state |= BMAP_ATTRFORK;
 
-       mp = ip->i_mount;
        ifp = XFS_IFORK_PTR(ip, whichfork);
        ASSERT((*idx >= 0) && (*idx < ifp->if_bytes /
                (uint)sizeof(xfs_bmbt_rec_t)));
@@ -5064,7 +5103,7 @@ xfs_bunmapi(
                *done = 1;
                return 0;
        }
-       XFS_STATS_INC(xs_blk_unmap);
+       XFS_STATS_INC(mp, xs_blk_unmap);
        isrt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip);
        start = bno;
        bno = start + len - 1;
@@ -5918,7 +5957,7 @@ xfs_bmap_split_extent(
        error = xfs_trans_reserve(tp, &M_RES(mp)->tr_write,
                        XFS_DIOSTRAT_SPACE_RES(mp, 0), 0);
        if (error) {
-               xfs_trans_cancel(tp, 0);
+               xfs_trans_cancel(tp);
                return error;
        }
 
@@ -5936,10 +5975,10 @@ xfs_bmap_split_extent(
        if (error)
                goto out;
 
-       return xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-
+       return xfs_trans_commit(tp);
 
 out:
-       xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
+       xfs_bmap_cancel(&free_list);
+       xfs_trans_cancel(tp);
        return error;
 }