blob: e4ef99b001f61d284037558b17f9cc350a09b0ed [file] [log] [blame]
From ceea4b1f2711f14c730f68423b4d974c8d48d39d Mon Sep 17 00:00:00 2001
From: Qu Wenruo <>
Date: Tue, 16 Jun 2020 10:17:37 +0800
Subject: [PATCH] btrfs: free anon block device right after subvolume deletion
commit 082b6c970f02fefd278c7833880cda29691a5f34 upstream.
When a lot of subvolumes are created, there is a user report about
transaction aborted caused by slow anonymous block device reclaim:
BTRFS: Transaction aborted (error -24)
WARNING: CPU: 17 PID: 17041 at fs/btrfs/transaction.c:1576 create_pending_snapshot+0xbc4/0xd10 [btrfs]
RIP: 0010:create_pending_snapshot+0xbc4/0xd10 [btrfs]
Call Trace:
create_pending_snapshots+0x82/0xa0 [btrfs]
btrfs_commit_transaction+0x275/0x8c0 [btrfs]
btrfs_mksubvol+0x4b9/0x500 [btrfs]
btrfs_ioctl_snap_create_transid+0x174/0x180 [btrfs]
btrfs_ioctl_snap_create_v2+0x11c/0x180 [btrfs]
btrfs_ioctl+0x11a4/0x2da0 [btrfs]
---[ end trace 33f2f83f3d5250e9 ]---
BTRFS: error (device sda1) in create_pending_snapshot:1576: errno=-24 unknown
BTRFS info (device sda1): forced readonly
BTRFS warning (device sda1): Skipping commit of aborted transaction.
BTRFS: error (device sda1) in cleanup_transaction:1831: errno=-24 unknown
The anonymous device pool is shared and its size is 1M. It's possible to
hit that limit if the subvolume deletion is not fast enough and the
subvolumes to be cleaned keep the ids allocated.
We can't avoid the anon device pool exhaustion but we can shorten the
time the id is attached to the subvolume root once the subvolume becomes
invisible to the user.
Reported-by: Greed Rong <>
CC: # 4.4+
Reviewed-by: Josef Bacik <>
Signed-off-by: Qu Wenruo <>
Reviewed-by: David Sterba <>
Signed-off-by: David Sterba <>
Signed-off-by: Paul Gortmaker <>
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 6a57bf38e761..fe10da44a4d2 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -4547,6 +4547,8 @@ int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry)
+ free_anon_bdev(dest->anon_dev);
+ dest->anon_dev = 0;
trans->block_rsv = NULL;
trans->bytes_reserved = 0;