|
|
@@ -1655,28 +1655,15 @@ xfs_inode_clear_eofblocks_tag(
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * Automatic CoW Reservation Freeing
|
|
|
- *
|
|
|
- * These functions automatically garbage collect leftover CoW reservations
|
|
|
- * that were made on behalf of a cowextsize hint when we start to run out
|
|
|
- * of quota or when the reservations sit around for too long. If the file
|
|
|
- * has dirty pages or is undergoing writeback, its CoW reservations will
|
|
|
- * be retained.
|
|
|
- *
|
|
|
- * The actual garbage collection piggybacks off the same code that runs
|
|
|
- * the speculative EOF preallocation garbage collector.
|
|
|
+ * Set ourselves up to free CoW blocks from this file. If it's already clean
|
|
|
+ * then we can bail out quickly, but otherwise we must back off if the file
|
|
|
+ * is undergoing some kind of write.
|
|
|
*/
|
|
|
-STATIC int
|
|
|
-xfs_inode_free_cowblocks(
|
|
|
+static bool
|
|
|
+xfs_prep_free_cowblocks(
|
|
|
struct xfs_inode *ip,
|
|
|
- int flags,
|
|
|
- void *args)
|
|
|
+ struct xfs_ifork *ifp)
|
|
|
{
|
|
|
- int ret;
|
|
|
- struct xfs_eofblocks *eofb = args;
|
|
|
- int match;
|
|
|
- struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
|
|
|
-
|
|
|
/*
|
|
|
* Just clear the tag if we have an empty cow fork or none at all. It's
|
|
|
* possible the inode was fully unshared since it was originally tagged.
|
|
|
@@ -1684,7 +1671,7 @@ xfs_inode_free_cowblocks(
|
|
|
if (!xfs_is_reflink_inode(ip) || !ifp->if_bytes) {
|
|
|
trace_xfs_inode_free_cowblocks_invalid(ip);
|
|
|
xfs_inode_clear_cowblocks_tag(ip);
|
|
|
- return 0;
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
@@ -1695,6 +1682,35 @@ xfs_inode_free_cowblocks(
|
|
|
mapping_tagged(VFS_I(ip)->i_mapping, PAGECACHE_TAG_DIRTY) ||
|
|
|
mapping_tagged(VFS_I(ip)->i_mapping, PAGECACHE_TAG_WRITEBACK) ||
|
|
|
atomic_read(&VFS_I(ip)->i_dio_count))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Automatic CoW Reservation Freeing
|
|
|
+ *
|
|
|
+ * These functions automatically garbage collect leftover CoW reservations
|
|
|
+ * that were made on behalf of a cowextsize hint when we start to run out
|
|
|
+ * of quota or when the reservations sit around for too long. If the file
|
|
|
+ * has dirty pages or is undergoing writeback, its CoW reservations will
|
|
|
+ * be retained.
|
|
|
+ *
|
|
|
+ * The actual garbage collection piggybacks off the same code that runs
|
|
|
+ * the speculative EOF preallocation garbage collector.
|
|
|
+ */
|
|
|
+STATIC int
|
|
|
+xfs_inode_free_cowblocks(
|
|
|
+ struct xfs_inode *ip,
|
|
|
+ int flags,
|
|
|
+ void *args)
|
|
|
+{
|
|
|
+ struct xfs_eofblocks *eofb = args;
|
|
|
+ struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
|
|
|
+ int match;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ if (!xfs_prep_free_cowblocks(ip, ifp))
|
|
|
return 0;
|
|
|
|
|
|
if (eofb) {
|
|
|
@@ -1715,7 +1731,12 @@ xfs_inode_free_cowblocks(
|
|
|
xfs_ilock(ip, XFS_IOLOCK_EXCL);
|
|
|
xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
|
|
|
|
|
|
- ret = xfs_reflink_cancel_cow_range(ip, 0, NULLFILEOFF, false);
|
|
|
+ /*
|
|
|
+ * Check again, nobody else should be able to dirty blocks or change
|
|
|
+ * the reflink iflag now that we have the first two locks held.
|
|
|
+ */
|
|
|
+ if (xfs_prep_free_cowblocks(ip, ifp))
|
|
|
+ ret = xfs_reflink_cancel_cow_range(ip, 0, NULLFILEOFF, false);
|
|
|
|
|
|
xfs_iunlock(ip, XFS_MMAPLOCK_EXCL);
|
|
|
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
|