]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - fs/xfs/xfs_bmap_util.c
Merge branch 'xfs-dax-updates' into for-next
[karo-tx-linux.git] / fs / xfs / xfs_bmap_util.c
index 0f34886cf7269b1cd67eadbc372655372253981b..dbae6490a79a5f41e5407b57f82477e5ed7582b8 100644 (file)
@@ -56,6 +56,35 @@ xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb)
                 XFS_FSB_TO_DADDR((ip)->i_mount, (fsb)));
 }
 
+/*
+ * Routine to zero an extent on disk allocated to the specific inode.
+ *
+ * The VFS functions take a linearised filesystem block offset, so we have to
+ * convert the sparse xfs fsb to the right format first.
+ * VFS types are real funky, too.
+ */
+int
+xfs_zero_extent(
+       struct xfs_inode *ip,
+       xfs_fsblock_t   start_fsb,
+       xfs_off_t       count_fsb)
+{
+       struct xfs_mount *mp = ip->i_mount;
+       xfs_daddr_t     sector = xfs_fsb_to_db(ip, start_fsb);
+       sector_t        block = XFS_BB_TO_FSBT(mp, sector);
+       ssize_t         size = XFS_FSB_TO_B(mp, count_fsb);
+
+       if (IS_DAX(VFS_I(ip)))
+               return dax_clear_blocks(VFS_I(ip), block, size);
+
+       /*
+        * let the block layer decide on the fastest method of
+        * implementing the zeroing.
+        */
+       return sb_issue_zeroout(mp->m_super, block, count_fsb, GFP_NOFS);
+
+}
+
 /*
  * Routine to be called at transaction's end by xfs_bmapi, xfs_bunmapi
  * caller.  Frees all the extents that need freeing, which must be done
@@ -67,16 +96,15 @@ xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb)
  */
 int                                            /* error */
 xfs_bmap_finish(
-       xfs_trans_t             **tp,           /* transaction pointer addr */
-       xfs_bmap_free_t         *flist,         /* i/o: list extents to free */
-       int                     *committed)     /* xact committed or not */
+       struct xfs_trans                **tp,   /* transaction pointer addr */
+       struct xfs_bmap_free            *flist, /* i/o: list extents to free */
+       int                             *committed)/* xact committed or not */
 {
-       xfs_efd_log_item_t      *efd;           /* extent free data */
-       xfs_efi_log_item_t      *efi;           /* extent free intention */
-       int                     error;          /* error return value */
-       xfs_bmap_free_item_t    *free;          /* free extent item */
-       xfs_mount_t             *mp;            /* filesystem mount structure */
-       xfs_bmap_free_item_t    *next;          /* next item on free list */
+       struct xfs_efd_log_item         *efd;   /* extent free data */
+       struct xfs_efi_log_item         *efi;   /* extent free intention */
+       int                             error;  /* error return value */
+       struct xfs_bmap_free_item       *free;  /* free extent item */
+       struct xfs_bmap_free_item       *next;  /* next item on free list */
 
        ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES);
        if (flist->xbf_count == 0) {
@@ -88,40 +116,48 @@ xfs_bmap_finish(
                xfs_trans_log_efi_extent(*tp, efi, free->xbfi_startblock,
                        free->xbfi_blockcount);
 
-       error = xfs_trans_roll(tp, NULL);
-       *committed = 1;
-       /*
-        * We have a new transaction, so we should return committed=1,
-        * even though we're returning an error.
-        */
-       if (error)
+       error = __xfs_trans_roll(tp, NULL, committed);
+       if (error) {
+               /*
+                * If the transaction was committed, drop the EFD reference
+                * since we're bailing out of here. The other reference is
+                * dropped when the EFI hits the AIL.
+                *
+                * If the transaction was not committed, the EFI is freed by the
+                * EFI item unlock handler on abort. Also, we have a new
+                * transaction so we should return committed=1 even though we're
+                * returning an error.
+                */
+               if (*committed) {
+                       xfs_efi_release(efi);
+                       xfs_force_shutdown((*tp)->t_mountp,
+                               (error == -EFSCORRUPTED) ?
+                                       SHUTDOWN_CORRUPT_INCORE :
+                                       SHUTDOWN_META_IO_ERROR);
+               } else {
+                       *committed = 1;
+               }
+
                return error;
+       }
 
+       /*
+        * Get an EFD and free each extent in the list, logging to the EFD in
+        * the process. The remaining bmap free list is cleaned up by the caller
+        * on error.
+        */
        efd = xfs_trans_get_efd(*tp, efi, flist->xbf_count);
        for (free = flist->xbf_first; free != NULL; free = next) {
                next = free->xbfi_next;
-               if ((error = xfs_free_extent(*tp, free->xbfi_startblock,
-                               free->xbfi_blockcount))) {
-                       /*
-                        * The bmap free list will be cleaned up at a
-                        * higher level.  The EFI will be canceled when
-                        * this transaction is aborted.
-                        * Need to force shutdown here to make sure it
-                        * happens, since this transaction may not be
-                        * dirty yet.
-                        */
-                       mp = (*tp)->t_mountp;
-                       if (!XFS_FORCED_SHUTDOWN(mp))
-                               xfs_force_shutdown(mp,
-                                                  (error == -EFSCORRUPTED) ?
-                                                  SHUTDOWN_CORRUPT_INCORE :
-                                                  SHUTDOWN_META_IO_ERROR);
+
+               error = xfs_trans_free_extent(*tp, efd, free->xbfi_startblock,
+                                             free->xbfi_blockcount);
+               if (error)
                        return error;
-               }
-               xfs_trans_log_efd_extent(*tp, efd, free->xbfi_startblock,
-                       free->xbfi_blockcount);
+
                xfs_bmap_del_free(flist, NULL, free);
        }
+
        return 0;
 }
 
@@ -222,6 +258,13 @@ xfs_bmap_rtalloc(
                xfs_trans_mod_dquot_byino(ap->tp, ap->ip,
                        ap->wasdel ? XFS_TRANS_DQ_DELRTBCOUNT :
                                        XFS_TRANS_DQ_RTBCOUNT, (long) ralen);
+
+               /* Zero the extent if we were asked to do so */
+               if (ap->userdata & XFS_ALLOC_USERDATA_ZERO) {
+                       error = xfs_zero_extent(ap->ip, ap->blkno, ap->length);
+                       if (error)
+                               return error;
+               }
        } else {
                ap->length = 0;
        }
@@ -1020,7 +1063,7 @@ xfs_alloc_file_space(
                xfs_bmap_init(&free_list, &firstfsb);
                error = xfs_bmapi_write(tp, ip, startoffset_fsb,
                                        allocatesize_fsb, alloc_type, &firstfsb,
-                                       0, imapp, &nimaps, &free_list);
+                                       resblks, imapp, &nimaps, &free_list);
                if (error) {
                        goto error0;
                }
@@ -1467,7 +1510,7 @@ xfs_shift_file_space(
                                XFS_DIOSTRAT_SPACE_RES(mp, 0), 0,
                                XFS_QMOPT_RES_REGBLKS);
                if (error)
-                       goto out;
+                       goto out_trans_cancel;
 
                xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
 
@@ -1481,18 +1524,20 @@ xfs_shift_file_space(
                                &done, stop_fsb, &first_block, &free_list,
                                direction, XFS_BMAP_MAX_SHIFT_EXTENTS);
                if (error)
-                       goto out;
+                       goto out_bmap_cancel;
 
                error = xfs_bmap_finish(&tp, &free_list, &committed);
                if (error)
-                       goto out;
+                       goto out_bmap_cancel;
 
                error = xfs_trans_commit(tp);
        }
 
        return error;
 
-out:
+out_bmap_cancel:
+       xfs_bmap_cancel(&free_list);
+out_trans_cancel:
        xfs_trans_cancel(tp);
        return error;
 }