summaryrefslogtreecommitdiff
path: root/fs/btrfs/reflink.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2021-01-25 14:35:44 +1000
committerDave Airlie <airlied@redhat.com>2021-01-25 14:35:44 +1000
commitbc96ad6722f86a377ed2872c9a4854c90caf78ca (patch)
treeece8859165a1faa10e4e2203d231fc7e87925139 /fs/btrfs/reflink.c
parentd82afcf9caaac26ce2642511115bca9dacf30f41 (diff)
parent6ee1d745b7c9fd573fba142a2efdad76a9f1cb04 (diff)
Merge tag 'v5.11-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux into drm-next
Backmerge v5.11-rc5 into drm-next to clean up a bunch of conflicts we are dragging around. Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'fs/btrfs/reflink.c')
-rw-r--r--fs/btrfs/reflink.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c
index ab80896315be..b03e7891394e 100644
--- a/fs/btrfs/reflink.c
+++ b/fs/btrfs/reflink.c
@@ -89,6 +89,19 @@ static int copy_inline_to_page(struct btrfs_inode *inode,
if (ret)
goto out_unlock;
+ /*
+ * After dirtying the page our caller will need to start a transaction,
+ * and if we are low on metadata free space, that can cause flushing of
+ * delalloc for all inodes in order to get metadata space released.
+ * However we are holding the range locked for the whole duration of
+ * the clone/dedupe operation, so we may deadlock if that happens and no
+ * other task releases enough space. So mark this inode as not being
+ * possible to flush to avoid such deadlock. We will clear that flag
+ * when we finish cloning all extents, since a transaction is started
+ * after finding each extent to clone.
+ */
+ set_bit(BTRFS_INODE_NO_DELALLOC_FLUSH, &inode->runtime_flags);
+
if (comp_type == BTRFS_COMPRESS_NONE) {
char *map;
@@ -549,6 +562,8 @@ process_slot:
out:
btrfs_free_path(path);
kvfree(buf);
+ clear_bit(BTRFS_INODE_NO_DELALLOC_FLUSH, &BTRFS_I(inode)->runtime_flags);
+
return ret;
}