Merge tag 'xfs-reflink-for-linus-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kerne...
[cascardo/linux.git] / fs / xfs / xfs_inode.c
index f072f48..4e560e6 100644 (file)
@@ -77,6 +77,29 @@ xfs_get_extsz_hint(
        return 0;
 }
 
+/*
+ * Helper function to extract CoW extent size hint from inode.
+ * Between the extent size hint and the CoW extent size hint, we
+ * return the greater of the two.  If the value is zero (automatic),
+ * use the default size.
+ */
+xfs_extlen_t
+xfs_get_cowextsz_hint(
+       struct xfs_inode        *ip)
+{
+       xfs_extlen_t            a, b;
+
+       a = 0;
+       if (ip->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE)
+               a = ip->i_d.di_cowextsize;
+       b = xfs_get_extsz_hint(ip);
+
+       a = max(a, b);
+       if (a == 0)
+               return XFS_DEFAULT_COWEXTSZ_HINT;
+       return a;
+}
+
 /*
  * These two are wrapper routines around the xfs_ilock() routine used to
  * centralize some grungy code.  They are used in places that wish to lock the
@@ -652,6 +675,8 @@ _xfs_dic2xflags(
        if (di_flags2 & XFS_DIFLAG2_ANY) {
                if (di_flags2 & XFS_DIFLAG2_DAX)
                        flags |= FS_XFLAG_DAX;
+               if (di_flags2 & XFS_DIFLAG2_COWEXTSIZE)
+                       flags |= FS_XFLAG_COWEXTSIZE;
        }
 
        if (has_attr)
@@ -822,7 +847,7 @@ xfs_ialloc(
        ip->i_d.di_nextents = 0;
        ASSERT(ip->i_d.di_nblocks == 0);
 
-       tv = current_fs_time(mp->m_super);
+       tv = current_time(inode);
        inode->i_mtime = tv;
        inode->i_atime = tv;
        inode->i_ctime = tv;
@@ -835,6 +860,7 @@ xfs_ialloc(
        if (ip->i_d.di_version == 3) {
                inode->i_version = 1;
                ip->i_d.di_flags2 = 0;
+               ip->i_d.di_cowextsize = 0;
                ip->i_d.di_crtime.t_sec = (__int32_t)tv.tv_sec;
                ip->i_d.di_crtime.t_nsec = (__int32_t)tv.tv_nsec;
        }
@@ -897,6 +923,15 @@ xfs_ialloc(
                        ip->i_d.di_flags |= di_flags;
                        ip->i_d.di_flags2 |= di_flags2;
                }
+               if (pip &&
+                   (pip->i_d.di_flags2 & XFS_DIFLAG2_ANY) &&
+                   pip->i_d.di_version == 3 &&
+                   ip->i_d.di_version == 3) {
+                       if (pip->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE) {
+                               ip->i_d.di_flags2 |= XFS_DIFLAG2_COWEXTSIZE;
+                               ip->i_d.di_cowextsize = pip->i_d.di_cowextsize;
+                       }
+               }
                /* FALLTHROUGH */
        case S_IFLNK:
                ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS;
@@ -1596,8 +1631,10 @@ xfs_itruncate_extents(
        /*
         * Clear the reflink flag if we truncated everything.
         */
-       if (ip->i_d.di_nblocks == 0 && xfs_is_reflink_inode(ip))
+       if (ip->i_d.di_nblocks == 0 && xfs_is_reflink_inode(ip)) {
                ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK;
+               xfs_inode_clear_cowblocks_tag(ip);
+       }
 
        /*
         * Always re-log the inode so that our permanent transaction can keep
@@ -1723,7 +1760,7 @@ xfs_inactive_truncate(
        /*
         * Log the inode size first to prevent stale data exposure in the event
         * of a system crash before the truncate completes. See the related
-        * comment in xfs_setattr_size() for details.
+        * comment in xfs_vn_setattr_size() for details.
         */
        ip->i_d.di_size = 0;
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);