Merge tag 'mmc-v4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
[cascardo/linux.git] / fs / xfs / xfs_super.c
index 2d092f9..ade4691 100644 (file)
@@ -47,6 +47,9 @@
 #include "xfs_sysfs.h"
 #include "xfs_ondisk.h"
 #include "xfs_rmap_item.h"
+#include "xfs_refcount_item.h"
+#include "xfs_bmap_item.h"
+#include "xfs_reflink.h"
 
 #include <linux/namei.h>
 #include <linux/init.h>
@@ -936,6 +939,7 @@ xfs_fs_destroy_inode(
        struct inode            *inode)
 {
        struct xfs_inode        *ip = XFS_I(inode);
+       int                     error;
 
        trace_xfs_destroy_inode(ip);
 
@@ -943,6 +947,14 @@ xfs_fs_destroy_inode(
        XFS_STATS_INC(ip->i_mount, vn_rele);
        XFS_STATS_INC(ip->i_mount, vn_remove);
 
+       if (xfs_is_reflink_inode(ip)) {
+               error = xfs_reflink_cancel_cow_range(ip, 0, NULLFILEOFF);
+               if (error && !XFS_FORCED_SHUTDOWN(ip->i_mount))
+                       xfs_warn(ip->i_mount,
+"Error %d while evicting CoW blocks for inode %llu.",
+                                       error, ip->i_ino);
+       }
+
        xfs_inactive(ip);
 
        ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || ip->i_delayed_blks == 0);
@@ -1006,6 +1018,16 @@ xfs_fs_drop_inode(
 {
        struct xfs_inode        *ip = XFS_I(inode);
 
+       /*
+        * If this unlinked inode is in the middle of recovery, don't
+        * drop the inode just yet; log recovery will take care of
+        * that.  See the comment for this inode flag.
+        */
+       if (ip->i_flags & XFS_IRECOVERY) {
+               ASSERT(ip->i_mount->m_log->l_flags & XLOG_RECOVERY_NEEDED);
+               return 0;
+       }
+
        return generic_drop_inode(inode) || (ip->i_flags & XFS_IDONTCACHE);
 }
 
@@ -1296,10 +1318,31 @@ xfs_fs_remount(
                xfs_restore_resvblks(mp);
                xfs_log_work_queue(mp);
                xfs_queue_eofblocks(mp);
+
+               /* Recover any CoW blocks that never got remapped. */
+               error = xfs_reflink_recover_cow(mp);
+               if (error) {
+                       xfs_err(mp,
+       "Error %d recovering leftover CoW allocations.", error);
+                       xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
+                       return error;
+               }
+
+               /* Create the per-AG metadata reservation pool .*/
+               error = xfs_fs_reserve_ag_blocks(mp);
+               if (error && error != -ENOSPC)
+                       return error;
        }
 
        /* rw -> ro */
        if (!(mp->m_flags & XFS_MOUNT_RDONLY) && (*flags & MS_RDONLY)) {
+               /* Free the per-AG metadata reservation pool. */
+               error = xfs_fs_unreserve_ag_blocks(mp);
+               if (error) {
+                       xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
+                       return error;
+               }
+
                /*
                 * Before we sync the metadata, we need to free up the reserve
                 * block pool so that the used block count in the superblock on
@@ -1490,6 +1533,7 @@ xfs_fs_fill_super(
        atomic_set(&mp->m_active_trans, 0);
        INIT_DELAYED_WORK(&mp->m_reclaim_work, xfs_reclaim_worker);
        INIT_DELAYED_WORK(&mp->m_eofblocks_work, xfs_eofblocks_worker);
+       INIT_DELAYED_WORK(&mp->m_cowblocks_work, xfs_cowblocks_worker);
        mp->m_kobj.kobject.kset = xfs_kset;
 
        mp->m_super = sb;
@@ -1572,6 +1616,9 @@ xfs_fs_fill_super(
                        "DAX unsupported by block device. Turning off DAX.");
                        mp->m_flags &= ~XFS_MOUNT_DAX;
                }
+               if (xfs_sb_version_hasreflink(&mp->m_sb))
+                       xfs_alert(mp,
+               "DAX and reflink have not been tested together!");
        }
 
        if (xfs_sb_version_hasrmapbt(&mp->m_sb)) {
@@ -1585,6 +1632,10 @@ xfs_fs_fill_super(
        "EXPERIMENTAL reverse mapping btree feature enabled. Use at your own risk!");
        }
 
+       if (xfs_sb_version_hasreflink(&mp->m_sb))
+               xfs_alert(mp,
+       "EXPERIMENTAL reflink feature enabled. Use at your own risk!");
+
        error = xfs_mountfs(mp);
        if (error)
                goto out_filestream_unmount;
@@ -1788,8 +1839,38 @@ xfs_init_zones(void)
        if (!xfs_rui_zone)
                goto out_destroy_rud_zone;
 
+       xfs_cud_zone = kmem_zone_init(sizeof(struct xfs_cud_log_item),
+                       "xfs_cud_item");
+       if (!xfs_cud_zone)
+               goto out_destroy_rui_zone;
+
+       xfs_cui_zone = kmem_zone_init(
+                       xfs_cui_log_item_sizeof(XFS_CUI_MAX_FAST_EXTENTS),
+                       "xfs_cui_item");
+       if (!xfs_cui_zone)
+               goto out_destroy_cud_zone;
+
+       xfs_bud_zone = kmem_zone_init(sizeof(struct xfs_bud_log_item),
+                       "xfs_bud_item");
+       if (!xfs_bud_zone)
+               goto out_destroy_cui_zone;
+
+       xfs_bui_zone = kmem_zone_init(
+                       xfs_bui_log_item_sizeof(XFS_BUI_MAX_FAST_EXTENTS),
+                       "xfs_bui_item");
+       if (!xfs_bui_zone)
+               goto out_destroy_bud_zone;
+
        return 0;
 
+ out_destroy_bud_zone:
+       kmem_zone_destroy(xfs_bud_zone);
+ out_destroy_cui_zone:
+       kmem_zone_destroy(xfs_cui_zone);
+ out_destroy_cud_zone:
+       kmem_zone_destroy(xfs_cud_zone);
+ out_destroy_rui_zone:
+       kmem_zone_destroy(xfs_rui_zone);
  out_destroy_rud_zone:
        kmem_zone_destroy(xfs_rud_zone);
  out_destroy_icreate_zone:
@@ -1832,6 +1913,10 @@ xfs_destroy_zones(void)
         * destroy caches.
         */
        rcu_barrier();
+       kmem_zone_destroy(xfs_bui_zone);
+       kmem_zone_destroy(xfs_bud_zone);
+       kmem_zone_destroy(xfs_cui_zone);
+       kmem_zone_destroy(xfs_cud_zone);
        kmem_zone_destroy(xfs_rui_zone);
        kmem_zone_destroy(xfs_rud_zone);
        kmem_zone_destroy(xfs_icreate_zone);
@@ -1885,6 +1970,8 @@ init_xfs_fs(void)
 
        xfs_extent_free_init_defer_op();
        xfs_rmap_update_init_defer_op();
+       xfs_refcount_update_init_defer_op();
+       xfs_bmap_update_init_defer_op();
 
        xfs_dir_startup();