Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ee3441b4 authored by Jeff Mahoney's avatar Jeff Mahoney Committed by Chris Mason
Browse files

btrfs: fall back to global reservation when removing subvolumes



I recently did some ENOSPC testing that involved filling the disk
while create and removing snapshots in a loop. During the test cycle,
I ran into an ENOSPC when trying to remove a snapshot, leaving the fs
stuck in ENOSPC even after a umount/mount cycle.

This patch allow subvolume removal to fall back onto the global
block reservation in order to succeed when it would have failed
otherwise.

Signed-off-by: default avatarJeff Mahoney <jeffm@suse.com>
Signed-off-by: default avatarJosef Bacik <jbacik@fusionio.com>
Signed-off-by: default avatarChris Mason <chris.mason@fusionio.com>
parent 74be9510
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -3175,7 +3175,7 @@ void btrfs_orphan_release_metadata(struct inode *inode);
int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
				     struct btrfs_block_rsv *rsv,
				     int nitems,
				     u64 *qgroup_reserved);
				     u64 *qgroup_reserved, bool use_global_rsv);
void btrfs_subvolume_release_metadata(struct btrfs_root *root,
				      struct btrfs_block_rsv *rsv,
				      u64 qgroup_reserved);
+7 −1
Original line number Diff line number Diff line
@@ -4742,10 +4742,12 @@ void btrfs_orphan_release_metadata(struct inode *inode)
int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
				     struct btrfs_block_rsv *rsv,
				     int items,
				     u64 *qgroup_reserved)
				     u64 *qgroup_reserved,
				     bool use_global_rsv)
{
	u64 num_bytes;
	int ret;
	struct btrfs_block_rsv *global_rsv = &root->fs_info->global_block_rsv;

	if (root->fs_info->quota_enabled) {
		/* One for parent inode, two for dir entries */
@@ -4764,6 +4766,10 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
					    BTRFS_BLOCK_GROUP_METADATA);
	ret = btrfs_block_rsv_add(root, rsv, num_bytes,
				  BTRFS_RESERVE_FLUSH_ALL);

	if (ret == -ENOSPC && use_global_rsv)
		ret = btrfs_block_rsv_migrate(global_rsv, rsv, num_bytes);

	if (ret) {
		if (*qgroup_reserved)
			btrfs_qgroup_free(root, *qgroup_reserved);
+4 −3
Original line number Diff line number Diff line
@@ -396,7 +396,7 @@ static noinline int create_subvol(struct inode *dir,
	 * of create_snapshot().
	 */
	ret = btrfs_subvolume_reserve_metadata(root, &block_rsv,
					       7, &qgroup_reserved);
					       7, &qgroup_reserved, false);
	if (ret)
		return ret;

@@ -576,7 +576,8 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
	 */
	ret = btrfs_subvolume_reserve_metadata(BTRFS_I(dir)->root,
					&pending_snapshot->block_rsv, 7,
					&pending_snapshot->qgroup_reserved);
					&pending_snapshot->qgroup_reserved,
					false);
	if (ret)
		goto out;

@@ -2174,7 +2175,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
	 * ref/backref.
	 */
	err = btrfs_subvolume_reserve_metadata(root, &block_rsv,
					       5, &qgroup_reserved);
					       5, &qgroup_reserved, true);
	if (err)
		goto out_up_write;