Merge branch 'locking-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[cascardo/linux.git] / fs / xfs / xfs_bmap_util.c
index cd4a850..4ece4f2 100644 (file)
@@ -25,6 +25,7 @@
 #include "xfs_bit.h"
 #include "xfs_mount.h"
 #include "xfs_da_format.h"
+#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
 #include "xfs_trans.h"
@@ -40,6 +41,7 @@
 #include "xfs_trace.h"
 #include "xfs_icache.h"
 #include "xfs_log.h"
+#include "xfs_rmap_btree.h"
 
 /* Kernel only BMAP related definitions and functions */
 
@@ -79,95 +81,6 @@ xfs_zero_extent(
                GFP_NOFS, true);
 }
 
-/* Sort bmap items by AG. */
-static int
-xfs_bmap_free_list_cmp(
-       void                    *priv,
-       struct list_head        *a,
-       struct list_head        *b)
-{
-       struct xfs_mount        *mp = priv;
-       struct xfs_bmap_free_item       *ra;
-       struct xfs_bmap_free_item       *rb;
-
-       ra = container_of(a, struct xfs_bmap_free_item, xbfi_list);
-       rb = container_of(b, struct xfs_bmap_free_item, xbfi_list);
-       return  XFS_FSB_TO_AGNO(mp, ra->xbfi_startblock) -
-               XFS_FSB_TO_AGNO(mp, rb->xbfi_startblock);
-}
-
-/*
- * 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
- * last due to locking considerations.  We never free any extents in
- * the first transaction.
- *
- * If an inode *ip is provided, rejoin it to the transaction if
- * the transaction was committed.
- */
-int                                            /* error */
-xfs_bmap_finish(
-       struct xfs_trans                **tp,   /* transaction pointer addr */
-       struct xfs_bmap_free            *flist, /* i/o: list extents to free */
-       struct xfs_inode                *ip)
-{
-       struct xfs_efd_log_item         *efd;   /* extent free data */
-       struct xfs_efi_log_item         *efi;   /* extent free intention */
-       int                             error;  /* error return value */
-       int                             committed;/* xact committed or not */
-       struct xfs_bmap_free_item       *free;  /* free extent item */
-
-       ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES);
-       if (flist->xbf_count == 0)
-               return 0;
-
-       list_sort((*tp)->t_mountp, &flist->xbf_flist, xfs_bmap_free_list_cmp);
-
-       efi = xfs_trans_get_efi(*tp, flist->xbf_count);
-       list_for_each_entry(free, &flist->xbf_flist, xbfi_list)
-               xfs_trans_log_efi_extent(*tp, efi, free->xbfi_startblock,
-                       free->xbfi_blockcount);
-
-       error = __xfs_trans_roll(tp, ip, &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,
-                                          SHUTDOWN_META_IO_ERROR);
-               }
-               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);
-       while (!list_empty(&flist->xbf_flist)) {
-               free = list_first_entry(&flist->xbf_flist,
-                               struct xfs_bmap_free_item, xbfi_list);
-               error = xfs_trans_free_extent(*tp, efd, free->xbfi_startblock,
-                                             free->xbfi_blockcount);
-               if (error)
-                       return error;
-
-               xfs_bmap_del_free(flist, free);
-       }
-
-       return 0;
-}
-
 int
 xfs_bmap_rtalloc(
        struct xfs_bmalloca     *ap)    /* bmap alloc argument struct */
@@ -214,9 +127,9 @@ xfs_bmap_rtalloc(
        /*
         * Lock out modifications to both the RT bitmap and summary inodes
         */
-       xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL);
+       xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL|XFS_ILOCK_RTBITMAP);
        xfs_trans_ijoin(ap->tp, mp->m_rbmip, XFS_ILOCK_EXCL);
-       xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL);
+       xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL|XFS_ILOCK_RTSUM);
        xfs_trans_ijoin(ap->tp, mp->m_rsumip, XFS_ILOCK_EXCL);
 
        /*
@@ -773,7 +686,7 @@ xfs_bmap_punch_delalloc_range(
                xfs_bmbt_irec_t imap;
                int             nimaps = 1;
                xfs_fsblock_t   firstblock;
-               xfs_bmap_free_t flist;
+               struct xfs_defer_ops dfops;
 
                /*
                 * Map the range first and check that it is a delalloc extent
@@ -804,18 +717,18 @@ xfs_bmap_punch_delalloc_range(
                WARN_ON(imap.br_blockcount == 0);
 
                /*
-                * Note: while we initialise the firstblock/flist pair, they
+                * Note: while we initialise the firstblock/dfops pair, they
                 * should never be used because blocks should never be
                 * allocated or freed for a delalloc extent and hence we need
                 * don't cancel or finish them after the xfs_bunmapi() call.
                 */
-               xfs_bmap_init(&flist, &firstblock);
+               xfs_defer_init(&dfops, &firstblock);
                error = xfs_bunmapi(NULL, ip, start_fsb, 1, 0, 1, &firstblock,
-                                       &flist, &done);
+                                       &dfops, &done);
                if (error)
                        break;
 
-               ASSERT(!flist.xbf_count && list_empty(&flist.xbf_flist));
+               ASSERT(!xfs_defer_has_unfinished_work(&dfops));
 next_block:
                start_fsb++;
                remaining--;
@@ -972,7 +885,7 @@ xfs_alloc_file_space(
        int                     rt;
        xfs_trans_t             *tp;
        xfs_bmbt_irec_t         imaps[1], *imapp;
-       xfs_bmap_free_t         free_list;
+       struct xfs_defer_ops    dfops;
        uint                    qblocks, resblks, resrtextents;
        int                     error;
 
@@ -1063,17 +976,17 @@ xfs_alloc_file_space(
 
                xfs_trans_ijoin(tp, ip, 0);
 
-               xfs_bmap_init(&free_list, &firstfsb);
+               xfs_defer_init(&dfops, &firstfsb);
                error = xfs_bmapi_write(tp, ip, startoffset_fsb,
                                        allocatesize_fsb, alloc_type, &firstfsb,
-                                       resblks, imapp, &nimaps, &free_list);
+                                       resblks, imapp, &nimaps, &dfops);
                if (error)
                        goto error0;
 
                /*
                 * Complete the transaction
                 */
-               error = xfs_bmap_finish(&tp, &free_list, NULL);
+               error = xfs_defer_finish(&tp, &dfops, NULL);
                if (error)
                        goto error0;
 
@@ -1096,7 +1009,7 @@ xfs_alloc_file_space(
        return error;
 
 error0:        /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
-       xfs_bmap_cancel(&free_list);
+       xfs_defer_cancel(&dfops);
        xfs_trans_unreserve_quota_nblks(tp, ip, (long)qblocks, 0, quota_flag);
 
 error1:        /* Just cancel transaction */
@@ -1114,7 +1027,7 @@ xfs_unmap_extent(
 {
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_trans        *tp;
-       struct xfs_bmap_free    free_list;
+       struct xfs_defer_ops    dfops;
        xfs_fsblock_t           firstfsb;
        uint                    resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
        int                     error;
@@ -1133,13 +1046,13 @@ xfs_unmap_extent(
 
        xfs_trans_ijoin(tp, ip, 0);
 
-       xfs_bmap_init(&free_list, &firstfsb);
+       xfs_defer_init(&dfops, &firstfsb);
        error = xfs_bunmapi(tp, ip, startoffset_fsb, len_fsb, 0, 2, &firstfsb,
-                       &free_list, done);
+                       &dfops, done);
        if (error)
                goto out_bmap_cancel;
 
-       error = xfs_bmap_finish(&tp, &free_list, NULL);
+       error = xfs_defer_finish(&tp, &dfops, ip);
        if (error)
                goto out_bmap_cancel;
 
@@ -1149,7 +1062,7 @@ out_unlock:
        return error;
 
 out_bmap_cancel:
-       xfs_bmap_cancel(&free_list);
+       xfs_defer_cancel(&dfops);
 out_trans_cancel:
        xfs_trans_cancel(tp);
        goto out_unlock;
@@ -1338,7 +1251,7 @@ xfs_shift_file_space(
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_trans        *tp;
        int                     error;
-       struct xfs_bmap_free    free_list;
+       struct xfs_defer_ops    dfops;
        xfs_fsblock_t           first_block;
        xfs_fileoff_t           stop_fsb;
        xfs_fileoff_t           next_fsb;
@@ -1416,19 +1329,19 @@ xfs_shift_file_space(
 
                xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
 
-               xfs_bmap_init(&free_list, &first_block);
+               xfs_defer_init(&dfops, &first_block);
 
                /*
                 * We are using the write transaction in which max 2 bmbt
                 * updates are allowed
                 */
                error = xfs_bmap_shift_extents(tp, ip, &next_fsb, shift_fsb,
-                               &done, stop_fsb, &first_block, &free_list,
+                               &done, stop_fsb, &first_block, &dfops,
                                direction, XFS_BMAP_MAX_SHIFT_EXTENTS);
                if (error)
                        goto out_bmap_cancel;
 
-               error = xfs_bmap_finish(&tp, &free_list, NULL);
+               error = xfs_defer_finish(&tp, &dfops, NULL);
                if (error)
                        goto out_bmap_cancel;
 
@@ -1438,7 +1351,7 @@ xfs_shift_file_space(
        return error;
 
 out_bmap_cancel:
-       xfs_bmap_cancel(&free_list);
+       xfs_defer_cancel(&dfops);
 out_trans_cancel:
        xfs_trans_cancel(tp);
        return error;
@@ -1622,6 +1535,10 @@ xfs_swap_extents(
        __uint64_t      tmp;
        int             lock_flags;
 
+       /* XXX: we can't do this with rmap, will fix later */
+       if (xfs_sb_version_hasrmapbt(&mp->m_sb))
+               return -EOPNOTSUPP;
+
        tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL);
        if (!tempifp) {
                error = -ENOMEM;