Commit 0e39a731 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull btrfs fixes from David Sterba:

 - fix bug in qgroups reporting incorrect usage for higher level qgroups

 - in zoned mode, do not select metadata group as finish target

 - convert xarray lock to RCU when trying to release extent buffer to
   avoid a deadlock

 - do not allow relocation on partially dropped subvolumes, which is
   normally not possible but has been reported on old filesystems

 - in tree-log, report errors on missing block group when unaccounting
   log tree extent buffers

 - with large folios, fix range length when processing ordered extents

* tag 'for-6.17-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: fix iteration bug in __qgroup_excl_accounting()
  btrfs: zoned: do not select metadata BG as finish target
  btrfs: do not allow relocation of partially dropped subvolumes
  btrfs: error on missing block group when unaccounting log tree extent buffers
  btrfs: fix wrong length parameter for btrfs_cleanup_ordered_extents()
  btrfs: make btrfs_cleanup_ordered_extents() support large folios
  btrfs: fix subpage deadlock in try_release_subpage_extent_buffer()
parents 20e0d857 7b632596
Loading
Loading
Loading
Loading
+6 −5
Original line number Diff line number Diff line
@@ -4331,15 +4331,18 @@ static int try_release_subpage_extent_buffer(struct folio *folio)
	unsigned long end = index + (PAGE_SIZE >> fs_info->nodesize_bits) - 1;
	int ret;

	xa_lock_irq(&fs_info->buffer_tree);
	rcu_read_lock();
	xa_for_each_range(&fs_info->buffer_tree, index, eb, start, end) {
		/*
		 * The same as try_release_extent_buffer(), to ensure the eb
		 * won't disappear out from under us.
		 */
		spin_lock(&eb->refs_lock);
		rcu_read_unlock();

		if (refcount_read(&eb->refs) != 1 || extent_buffer_under_io(eb)) {
			spin_unlock(&eb->refs_lock);
			rcu_read_lock();
			continue;
		}

@@ -4358,11 +4361,10 @@ static int try_release_subpage_extent_buffer(struct folio *folio)
		 * check the folio private at the end.  And
		 * release_extent_buffer() will release the refs_lock.
		 */
		xa_unlock_irq(&fs_info->buffer_tree);
		release_extent_buffer(eb);
		xa_lock_irq(&fs_info->buffer_tree);
		rcu_read_lock();
	}
	xa_unlock_irq(&fs_info->buffer_tree);
	rcu_read_unlock();

	/*
	 * Finally to check if we have cleared folio private, as if we have
@@ -4375,7 +4377,6 @@ static int try_release_subpage_extent_buffer(struct folio *folio)
		ret = 0;
	spin_unlock(&folio->mapping->i_private_lock);
	return ret;

}

int try_release_extent_buffer(struct folio *folio)
+5 −3
Original line number Diff line number Diff line
@@ -401,10 +401,12 @@ static inline void btrfs_cleanup_ordered_extents(struct btrfs_inode *inode,

	while (index <= end_index) {
		folio = filemap_get_folio(inode->vfs_inode.i_mapping, index);
		if (IS_ERR(folio)) {
			index++;
		if (IS_ERR(folio))
			continue;
		}

		index = folio_end(folio) >> PAGE_SHIFT;
		/*
		 * Here we just clear all Ordered bits for every page in the
		 * range, then btrfs_mark_ordered_io_finished() will handle
@@ -2013,7 +2015,7 @@ static int nocow_one_range(struct btrfs_inode *inode, struct folio *locked_folio
	 * cleaered by the caller.
	 */
	if (ret < 0)
		btrfs_cleanup_ordered_extents(inode, file_pos, end);
		btrfs_cleanup_ordered_extents(inode, file_pos, len);
	return ret;
}

+1 −2
Original line number Diff line number Diff line
@@ -1453,7 +1453,6 @@ static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info, u64 ref_root,
				    struct btrfs_qgroup *src, int sign)
{
	struct btrfs_qgroup *qgroup;
	struct btrfs_qgroup *cur;
	LIST_HEAD(qgroup_list);
	u64 num_bytes = src->excl;
	int ret = 0;
@@ -1463,7 +1462,7 @@ static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info, u64 ref_root,
		goto out;

	qgroup_iterator_add(&qgroup_list, qgroup);
	list_for_each_entry(cur, &qgroup_list, iterator) {
	list_for_each_entry(qgroup, &qgroup_list, iterator) {
		struct btrfs_qgroup_list *glist;

		qgroup->rfer += sign * num_bytes;
+19 −0
Original line number Diff line number Diff line
@@ -602,6 +602,25 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans,
	if (btrfs_root_id(root) == objectid) {
		u64 commit_root_gen;

		/*
		 * Relocation will wait for cleaner thread, and any half-dropped
		 * subvolume will be fully cleaned up at mount time.
		 * So here we shouldn't hit a subvolume with non-zero drop_progress.
		 *
		 * If this isn't the case, error out since it can make us attempt to
		 * drop references for extents that were already dropped before.
		 */
		if (unlikely(btrfs_disk_key_objectid(&root->root_item.drop_progress))) {
			struct btrfs_key cpu_key;

			btrfs_disk_key_to_cpu(&cpu_key, &root->root_item.drop_progress);
			btrfs_err(fs_info,
	"cannot relocate partially dropped subvolume %llu, drop progress key (%llu %u %llu)",
				  objectid, cpu_key.objectid, cpu_key.type, cpu_key.offset);
			ret = -EUCLEAN;
			goto fail;
		}

		/* called by btrfs_init_reloc_root */
		ret = btrfs_copy_root(trans, root, root->commit_root, &eb,
				      BTRFS_TREE_RELOC_OBJECTID);
+7 −12
Original line number Diff line number Diff line
@@ -2605,14 +2605,14 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
/*
 * Correctly adjust the reserved bytes occupied by a log tree extent buffer
 */
static void unaccount_log_buffer(struct btrfs_fs_info *fs_info, u64 start)
static int unaccount_log_buffer(struct btrfs_fs_info *fs_info, u64 start)
{
	struct btrfs_block_group *cache;

	cache = btrfs_lookup_block_group(fs_info, start);
	if (!cache) {
		btrfs_err(fs_info, "unable to find block group for %llu", start);
		return;
		return -ENOENT;
	}

	spin_lock(&cache->space_info->lock);
@@ -2623,27 +2623,22 @@ static void unaccount_log_buffer(struct btrfs_fs_info *fs_info, u64 start)
	spin_unlock(&cache->space_info->lock);

	btrfs_put_block_group(cache);

	return 0;
}

static int clean_log_buffer(struct btrfs_trans_handle *trans,
			    struct extent_buffer *eb)
{
	int ret;

	btrfs_tree_lock(eb);
	btrfs_clear_buffer_dirty(trans, eb);
	wait_on_extent_buffer_writeback(eb);
	btrfs_tree_unlock(eb);

	if (trans) {
		ret = btrfs_pin_reserved_extent(trans, eb);
		if (ret)
			return ret;
	} else {
		unaccount_log_buffer(eb->fs_info, eb->start);
	}
	if (trans)
		return btrfs_pin_reserved_extent(trans, eb);

	return 0;
	return unaccount_log_buffer(eb->fs_info, eb->start);
}

static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
Loading