Commit 547635c6 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'for-6.6-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux

Pull btrfs updates from David Sterba:
 "No new features, the bulk of the changes are fixes, refactoring and
  cleanups. The notable fix is the scrub performance restoration after
  rewrite in 6.4, though still only partial.

  Fixes:

   - scrub performance drop due to rewrite in 6.4 partially restored:
      - do IO grouping by blg_plug/blk_unplug again
      - avoid unnecessary tree searches when processing stripes, in
        extent and checksum trees
      - the drop is noticeable on fast PCIe devices, -66% and restored
        to -33% of the original
      - backports to 6.4 planned

   - handle more corner cases of transaction commit during orphan
     cleanup or delayed ref processing

   - use correct fsid/metadata_uuid when validating super block

   - copy directory permissions and time when creating a stub subvolume

  Core:

   - debugging feature integrity checker deprecated, to be removed in
     6.7

   - in zoned mode, zones are activated just before the write, making
     error handling easier, now the overcommit mechanism can be enabled
     again which improves performance by avoiding more frequent flushing

   - v0 extent handling completely removed, deprecated long time ago

   - error handling improvements

   - tests:
      - extent buffer bitmap tests
      - pinned extent splitting tests

   - cleanups and refactoring:
      - compression writeback
      - extent buffer bitmap
      - space flushing, ENOSPC handling"

* tag 'for-6.6-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: (110 commits)
  btrfs: zoned: skip splitting and logical rewriting on pre-alloc write
  btrfs: tests: test invalid splitting when skipping pinned drop extent_map
  btrfs: tests: add a test for btrfs_add_extent_mapping
  btrfs: tests: add extent_map tests for dropping with odd layouts
  btrfs: scrub: move write back of repaired sectors to scrub_stripe_read_repair_worker()
  btrfs: scrub: don't go ordered workqueue for dev-replace
  btrfs: scrub: fix grouping of read IO
  btrfs: scrub: avoid unnecessary csum tree search preparing stripes
  btrfs: scrub: avoid unnecessary extent tree search preparing stripes
  btrfs: copy dir permission and time when creating a stub subvolume
  btrfs: remove pointless empty list check when reading delayed dir indexes
  btrfs: drop redundant check to use fs_devices::metadata_uuid
  btrfs: compare the correct fsid/metadata_uuid in btrfs_validate_super
  btrfs: use the correct superblock to compare fsid in btrfs_validate_super
  btrfs: simplify memcpy either of metadata_uuid or fsid
  btrfs: add a helper to read the superblock metadata_uuid
  btrfs: remove v0 extent handling
  btrfs: output extra debug info if we failed to find an inline backref
  btrfs: move the !zoned assert into run_delalloc_cow
  btrfs: consolidate the error handling in run_delalloc_nocow
  ...
parents f678c890 c02d35d8
......@@ -49,9 +49,11 @@ config BTRFS_FS_POSIX_ACL
If you don't know what Access Control Lists are, say N
config BTRFS_FS_CHECK_INTEGRITY
bool "Btrfs with integrity check tool compiled in (DANGEROUS)"
bool "Btrfs with integrity check tool compiled in (DEPRECATED)"
depends on BTRFS_FS
help
This feature has been deprecated and will be removed in 6.7.
Adds code that examines all block write requests (including
writes of the super block). The goal is to verify that the
state of the filesystem on disk is always consistent, i.e.,
......
......@@ -3,6 +3,8 @@
#ifndef BTRFS_ACCESSORS_H
#define BTRFS_ACCESSORS_H
#include <linux/stddef.h>
struct btrfs_map_token {
struct extent_buffer *eb;
char *kaddr;
......@@ -34,13 +36,13 @@ static inline void put_unaligned_le8(u8 val, void *p)
read_extent_buffer(eb, (char *)(result), \
((unsigned long)(ptr)) + \
offsetof(type, member), \
sizeof(((type *)0)->member)))
sizeof_field(type, member)))
#define write_eb_member(eb, ptr, type, member, result) (\
write_extent_buffer(eb, (char *)(result), \
((unsigned long)(ptr)) + \
offsetof(type, member), \
sizeof(((type *)0)->member)))
sizeof_field(type, member)))
#define DECLARE_BTRFS_SETGET_BITS(bits) \
u##bits btrfs_get_token_##bits(struct btrfs_map_token *token, \
......@@ -62,25 +64,25 @@ DECLARE_BTRFS_SETGET_BITS(64)
static inline u##bits btrfs_##name(const struct extent_buffer *eb, \
const type *s) \
{ \
static_assert(sizeof(u##bits) == sizeof(((type *)0))->member); \
static_assert(sizeof(u##bits) == sizeof_field(type, member)); \
return btrfs_get_##bits(eb, s, offsetof(type, member)); \
} \
static inline void btrfs_set_##name(const struct extent_buffer *eb, type *s, \
u##bits val) \
{ \
static_assert(sizeof(u##bits) == sizeof(((type *)0))->member); \
static_assert(sizeof(u##bits) == sizeof_field(type, member)); \
btrfs_set_##bits(eb, s, offsetof(type, member), val); \
} \
static inline u##bits btrfs_token_##name(struct btrfs_map_token *token, \
const type *s) \
{ \
static_assert(sizeof(u##bits) == sizeof(((type *)0))->member); \
static_assert(sizeof(u##bits) == sizeof_field(type, member)); \
return btrfs_get_token_##bits(token, s, offsetof(type, member));\
} \
static inline void btrfs_set_token_##name(struct btrfs_map_token *token,\
type *s, u##bits val) \
{ \
static_assert(sizeof(u##bits) == sizeof(((type *)0))->member); \
static_assert(sizeof(u##bits) == sizeof_field(type, member)); \
btrfs_set_token_##bits(token, s, offsetof(type, member), val); \
}
......@@ -111,17 +113,14 @@ static inline void btrfs_set_##name(type *s, u##bits val) \
static inline u64 btrfs_device_total_bytes(const struct extent_buffer *eb,
struct btrfs_dev_item *s)
{
static_assert(sizeof(u64) ==
sizeof(((struct btrfs_dev_item *)0))->total_bytes);
return btrfs_get_64(eb, s, offsetof(struct btrfs_dev_item,
total_bytes));
static_assert(sizeof(u64) == sizeof_field(struct btrfs_dev_item, total_bytes));
return btrfs_get_64(eb, s, offsetof(struct btrfs_dev_item, total_bytes));
}
static inline void btrfs_set_device_total_bytes(const struct extent_buffer *eb,
struct btrfs_dev_item *s,
u64 val)
{
static_assert(sizeof(u64) ==
sizeof(((struct btrfs_dev_item *)0))->total_bytes);
static_assert(sizeof(u64) == sizeof_field(struct btrfs_dev_item, total_bytes));
WARN_ON(!IS_ALIGNED(val, eb->fs_info->sectorsize));
btrfs_set_64(eb, s, offsetof(struct btrfs_dev_item, total_bytes), val);
}
......
......@@ -3373,7 +3373,6 @@ int btrfs_backref_add_tree_node(struct btrfs_backref_cache *cache,
struct btrfs_key *node_key,
struct btrfs_backref_node *cur)
{
struct btrfs_fs_info *fs_info = cache->fs_info;
struct btrfs_backref_edge *edge;
struct btrfs_backref_node *exist;
int ret;
......@@ -3462,25 +3461,21 @@ int btrfs_backref_add_tree_node(struct btrfs_backref_cache *cache,
ret = handle_direct_tree_backref(cache, &key, cur);
if (ret < 0)
goto out;
continue;
} else if (unlikely(key.type == BTRFS_EXTENT_REF_V0_KEY)) {
ret = -EINVAL;
btrfs_print_v0_err(fs_info);
btrfs_handle_fs_error(fs_info, ret, NULL);
goto out;
} else if (key.type != BTRFS_TREE_BLOCK_REF_KEY) {
continue;
} else if (key.type == BTRFS_TREE_BLOCK_REF_KEY) {
/*
* key.type == BTRFS_TREE_BLOCK_REF_KEY, inline ref
* offset means the root objectid. We need to search
* the tree to get its parent bytenr.
*/
ret = handle_indirect_tree_backref(cache, path, &key, node_key,
cur);
if (ret < 0)
goto out;
}
/*
* key.type == BTRFS_TREE_BLOCK_REF_KEY, inline ref offset
* means the root objectid. We need to search the tree to get
* its parent bytenr.
* Unrecognized tree backref items (if it can pass tree-checker)
* would be ignored.
*/
ret = handle_indirect_tree_backref(cache, path, &key, node_key,
cur);
if (ret < 0)
goto out;
}
ret = 0;
cur->checked = 1;
......
......@@ -504,13 +504,20 @@ static void fragment_free_space(struct btrfs_block_group *block_group)
#endif
/*
* This is only called by btrfs_cache_block_group, since we could have freed
* extents we need to check the pinned_extents for any extents that can't be
* used yet since their free space will be released as soon as the transaction
* commits.
* Add a free space range to the in memory free space cache of a block group.
* This checks if the range contains super block locations and any such
* locations are not added to the free space cache.
*
* @block_group: The target block group.
* @start: Start offset of the range.
* @end: End offset of the range (exclusive).
* @total_added_ret: Optional pointer to return the total amount of space
* added to the block group's free space cache.
*
* Returns 0 on success or < 0 on error.
*/
int add_new_free_space(struct btrfs_block_group *block_group, u64 start, u64 end,
u64 *total_added_ret)
int btrfs_add_new_free_space(struct btrfs_block_group *block_group, u64 start,
u64 end, u64 *total_added_ret)
{
struct btrfs_fs_info *info = block_group->fs_info;
u64 extent_start, extent_end, size;
......@@ -520,11 +527,10 @@ int add_new_free_space(struct btrfs_block_group *block_group, u64 start, u64 end
*total_added_ret = 0;
while (start < end) {
ret = find_first_extent_bit(&info->excluded_extents, start,
&extent_start, &extent_end,
EXTENT_DIRTY | EXTENT_UPTODATE,
NULL);
if (ret)
if (!find_first_extent_bit(&info->excluded_extents, start,
&extent_start, &extent_end,
EXTENT_DIRTY | EXTENT_UPTODATE,
NULL))
break;
if (extent_start <= start) {
......@@ -799,8 +805,8 @@ static int load_extent_tree_free(struct btrfs_caching_control *caching_ctl)
key.type == BTRFS_METADATA_ITEM_KEY) {
u64 space_added;
ret = add_new_free_space(block_group, last, key.objectid,
&space_added);
ret = btrfs_add_new_free_space(block_group, last,
key.objectid, &space_added);
if (ret)
goto out;
total_found += space_added;
......@@ -821,14 +827,20 @@ static int load_extent_tree_free(struct btrfs_caching_control *caching_ctl)
path->slots[0]++;
}
ret = add_new_free_space(block_group, last,
block_group->start + block_group->length,
NULL);
ret = btrfs_add_new_free_space(block_group, last,
block_group->start + block_group->length,
NULL);
out:
btrfs_free_path(path);
return ret;
}
static inline void btrfs_free_excluded_extents(const struct btrfs_block_group *bg)
{
clear_extent_bits(&bg->fs_info->excluded_extents, bg->start,
bg->start + bg->length - 1, EXTENT_UPTODATE);
}
static noinline void caching_thread(struct btrfs_work *work)
{
struct btrfs_block_group *block_group;
......@@ -2098,8 +2110,9 @@ static int exclude_super_stripes(struct btrfs_block_group *cache)
if (cache->start < BTRFS_SUPER_INFO_OFFSET) {
stripe_len = BTRFS_SUPER_INFO_OFFSET - cache->start;
cache->bytes_super += stripe_len;
ret = btrfs_add_excluded_extent(fs_info, cache->start,
stripe_len);
ret = set_extent_bit(&fs_info->excluded_extents, cache->start,
cache->start + stripe_len - 1,
EXTENT_UPTODATE, NULL);
if (ret)
return ret;
}
......@@ -2125,8 +2138,9 @@ static int exclude_super_stripes(struct btrfs_block_group *cache)
cache->start + cache->length - logical[nr]);
cache->bytes_super += len;
ret = btrfs_add_excluded_extent(fs_info, logical[nr],
len);
ret = set_extent_bit(&fs_info->excluded_extents, logical[nr],
logical[nr] + len - 1,
EXTENT_UPTODATE, NULL);
if (ret) {
kfree(logical);
return ret;
......@@ -2319,8 +2333,8 @@ static int read_one_block_group(struct btrfs_fs_info *info,
btrfs_free_excluded_extents(cache);
} else if (cache->used == 0) {
cache->cached = BTRFS_CACHE_FINISHED;
ret = add_new_free_space(cache, cache->start,
cache->start + cache->length, NULL);
ret = btrfs_add_new_free_space(cache, cache->start,
cache->start + cache->length, NULL);
btrfs_free_excluded_extents(cache);
if (ret)
goto error;
......@@ -2767,7 +2781,7 @@ struct btrfs_block_group *btrfs_make_block_group(struct btrfs_trans_handle *tran
return ERR_PTR(ret);
}
ret = add_new_free_space(cache, chunk_offset, chunk_offset + size, NULL);
ret = btrfs_add_new_free_space(cache, chunk_offset, chunk_offset + size, NULL);
btrfs_free_excluded_extents(cache);
if (ret) {
btrfs_put_block_group(cache);
......@@ -4075,7 +4089,7 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags,
if (IS_ERR(ret_bg)) {
ret = PTR_ERR(ret_bg);
} else if (from_extent_allocation) {
} else if (from_extent_allocation && (flags & BTRFS_BLOCK_GROUP_DATA)) {
/*
* New block group is likely to be used soon. Try to activate
* it now. Failure is OK for now.
......@@ -4273,6 +4287,17 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
struct btrfs_caching_control *caching_ctl;
struct rb_node *n;
if (btrfs_is_zoned(info)) {
if (info->active_meta_bg) {
btrfs_put_block_group(info->active_meta_bg);
info->active_meta_bg = NULL;
}
if (info->active_system_bg) {
btrfs_put_block_group(info->active_system_bg);
info->active_system_bg = NULL;
}
}
write_lock(&info->block_group_cache_lock);
while (!list_empty(&info->caching_block_groups)) {
caching_ctl = list_entry(info->caching_block_groups.next,
......
......@@ -291,8 +291,8 @@ int btrfs_cache_block_group(struct btrfs_block_group *cache, bool wait);
void btrfs_put_caching_control(struct btrfs_caching_control *ctl);
struct btrfs_caching_control *btrfs_get_caching_control(
struct btrfs_block_group *cache);
int add_new_free_space(struct btrfs_block_group *block_group,
u64 start, u64 end, u64 *total_added_ret);
int btrfs_add_new_free_space(struct btrfs_block_group *block_group,
u64 start, u64 end, u64 *total_added_ret);
struct btrfs_trans_handle *btrfs_start_trans_remove_block_group(
struct btrfs_fs_info *fs_info,
const u64 chunk_offset);
......
......@@ -498,12 +498,8 @@ int btrfs_prealloc_file_range_trans(struct inode *inode,
u64 start, u64 num_bytes, u64 min_size,
loff_t actual_len, u64 *alloc_hint);
int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct page *locked_page,
u64 start, u64 end, int *page_started,
unsigned long *nr_written, struct writeback_control *wbc);
u64 start, u64 end, struct writeback_control *wbc);
int btrfs_writepage_cow_fixup(struct page *page);
void btrfs_writepage_endio_finish_ordered(struct btrfs_inode *inode,
struct page *page, u64 start,
u64 end, bool uptodate);
int btrfs_encoded_io_compression_from_extent(struct btrfs_fs_info *fs_info,
int compress_type);
int btrfs_encoded_read_regular_fill_pages(struct btrfs_inode *inode,
......
......@@ -1736,9 +1736,6 @@ int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
int over = 0;
unsigned char d_type;
if (list_empty(ins_list))
return 0;
/*
* Changing the data of the delayed item is impossible. So
* we needn't lock them. And we have held i_mutex of the
......
......@@ -792,9 +792,9 @@ static int btrfs_set_target_alloc_state(struct btrfs_device *srcdev,
lockdep_assert_held(&srcdev->fs_info->chunk_mutex);
while (!find_first_extent_bit(&srcdev->alloc_state, start,
&found_start, &found_end,
CHUNK_ALLOCATED, &cached_state)) {
while (find_first_extent_bit(&srcdev->alloc_state, start,
&found_start, &found_end,
CHUNK_ALLOCATED, &cached_state)) {
ret = set_extent_bit(&tgtdev->alloc_state, found_start,
found_end, CHUNK_ALLOCATED, NULL);
if (ret)
......
......@@ -313,21 +313,16 @@ static bool check_tree_block_fsid(struct extent_buffer *eb)
struct btrfs_fs_info *fs_info = eb->fs_info;
struct btrfs_fs_devices *fs_devices = fs_info->fs_devices, *seed_devs;
u8 fsid[BTRFS_FSID_SIZE];
u8 *metadata_uuid;
read_extent_buffer(eb, fsid, offsetof(struct btrfs_header, fsid),
BTRFS_FSID_SIZE);
/*
* Checking the incompat flag is only valid for the current fs. For
* seed devices it's forbidden to have their uuid changed so reading
* ->fsid in this case is fine
* alloc_fs_devices() copies the fsid into metadata_uuid if the
* metadata_uuid is unset in the superblock, including for a seed device.
* So, we can use fs_devices->metadata_uuid.
*/
if (btrfs_fs_incompat(fs_info, METADATA_UUID))
metadata_uuid = fs_devices->metadata_uuid;
else
metadata_uuid = fs_devices->fsid;
if (!memcmp(fsid, metadata_uuid, BTRFS_FSID_SIZE))
if (memcmp(fsid, fs_info->fs_devices->metadata_uuid, BTRFS_FSID_SIZE) == 0)
return false;
list_for_each_entry(seed_devs, &fs_devices->seed_list, seed_list)
......@@ -2384,21 +2379,18 @@ int btrfs_validate_super(struct btrfs_fs_info *fs_info,
ret = -EINVAL;
}
if (memcmp(fs_info->fs_devices->fsid, fs_info->super_copy->fsid,
BTRFS_FSID_SIZE)) {
if (memcmp(fs_info->fs_devices->fsid, sb->fsid, BTRFS_FSID_SIZE) != 0) {
btrfs_err(fs_info,
"superblock fsid doesn't match fsid of fs_devices: %pU != %pU",
fs_info->super_copy->fsid, fs_info->fs_devices->fsid);
sb->fsid, fs_info->fs_devices->fsid);
ret = -EINVAL;
}
if (btrfs_fs_incompat(fs_info, METADATA_UUID) &&
memcmp(fs_info->fs_devices->metadata_uuid,
fs_info->super_copy->metadata_uuid, BTRFS_FSID_SIZE)) {
if (memcmp(fs_info->fs_devices->metadata_uuid, btrfs_sb_fsid_ptr(sb),
BTRFS_FSID_SIZE) != 0) {
btrfs_err(fs_info,
"superblock metadata_uuid doesn't match metadata uuid of fs_devices: %pU != %pU",
fs_info->super_copy->metadata_uuid,
fs_info->fs_devices->metadata_uuid);
btrfs_sb_fsid_ptr(sb), fs_info->fs_devices->metadata_uuid);
ret = -EINVAL;
}
......@@ -2869,6 +2861,56 @@ static int btrfs_check_uuid_tree(struct btrfs_fs_info *fs_info)
return 0;
}
static int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info)
{
u64 root_objectid = 0;
struct btrfs_root *gang[8];
int i = 0;
int err = 0;
unsigned int ret = 0;
while (1) {
spin_lock(&fs_info->fs_roots_radix_lock);
ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix,
(void **)gang, root_objectid,
ARRAY_SIZE(gang));
if (!ret) {
spin_unlock(&fs_info->fs_roots_radix_lock);
break;
}
root_objectid = gang[ret - 1]->root_key.objectid + 1;
for (i = 0; i < ret; i++) {
/* Avoid to grab roots in dead_roots. */
if (btrfs_root_refs(&gang[i]->root_item) == 0) {
gang[i] = NULL;
continue;
}
/* Grab all the search result for later use. */
gang[i] = btrfs_grab_root(gang[i]);
}
spin_unlock(&fs_info->fs_roots_radix_lock);
for (i = 0; i < ret; i++) {
if (!gang[i])
continue;
root_objectid = gang[i]->root_key.objectid;
err = btrfs_orphan_cleanup(gang[i]);
if (err)
goto out;
btrfs_put_root(gang[i]);
}
root_objectid++;
}
out:
/* Release the uncleaned roots due to error. */
for (; i < ret; i++) {
if (gang[i])
btrfs_put_root(gang[i]);
}
return err;
}
/*
* Some options only have meaning at mount time and shouldn't persist across
* remounts, or be displayed. Clear these at the end of mount and remount
......@@ -3222,7 +3264,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
/* check FS state, whether FS is broken. */
if (btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_ERROR)
set_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state);
WRITE_ONCE(fs_info->fs_error, -EUCLEAN);
/*
* In the long term, we'll store the compression type in the super
......@@ -3417,6 +3459,8 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
btrfs_free_zone_cache(fs_info);
btrfs_check_active_zone_reservation(fs_info);
if (!sb_rdonly(sb) && fs_info->fs_devices->missing_devices &&
!btrfs_check_rw_degradable(fs_info, NULL)) {
btrfs_warn(fs_info,
......@@ -4136,56 +4180,6 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
btrfs_put_root(root);
}
int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info)
{
u64 root_objectid = 0;
struct btrfs_root *gang[8];
int i = 0;
int err = 0;
unsigned int ret = 0;
while (1) {
spin_lock(&fs_info->fs_roots_radix_lock);
ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix,
(void **)gang, root_objectid,
ARRAY_SIZE(gang));
if (!ret) {
spin_unlock(&fs_info->fs_roots_radix_lock);
break;
}
root_objectid = gang[ret - 1]->root_key.objectid + 1;
for (i = 0; i < ret; i++) {
/* Avoid to grab roots in dead_roots */
if (btrfs_root_refs(&gang[i]->root_item) == 0) {
gang[i] = NULL;
continue;
}
/* grab all the search result for later use */
gang[i] = btrfs_grab_root(gang[i]);
}
spin_unlock(&fs_info->fs_roots_radix_lock);
for (i = 0; i < ret; i++) {
if (!gang[i])
continue;
root_objectid = gang[i]->root_key.objectid;
err = btrfs_orphan_cleanup(gang[i]);
if (err)
goto out;
btrfs_put_root(gang[i]);
}
root_objectid++;
}
out:
/* release the uncleaned roots due to error */
for (; i < ret; i++) {
if (gang[i])
btrfs_put_root(gang[i]);
}
return err;
}
int btrfs_commit_super(struct btrfs_fs_info *fs_info)
{
struct btrfs_root *root = fs_info->tree_root;
......@@ -4228,7 +4222,7 @@ static void warn_about_uncommitted_trans(struct btrfs_fs_info *fs_info)
u64 found_end;
found = true;
while (!find_first_extent_bit(&trans->dirty_pages, cur,
while (find_first_extent_bit(&trans->dirty_pages, cur,
&found_start, &found_end, EXTENT_DIRTY, &cached)) {
dirty_bytes += found_end + 1 - found_start;
cur = found_end + 1;
......@@ -4552,9 +4546,7 @@ static void btrfs_destroy_ordered_extents(struct btrfs_root *root)
static void btrfs_destroy_all_ordered_extents(struct btrfs_fs_info *fs_info)
{
struct btrfs_root *root;
struct list_head splice;
INIT_LIST_HEAD(&splice);
LIST_HEAD(splice);
spin_lock(&fs_info->ordered_root_lock);
list_splice_init(&fs_info->ordered_roots, &splice);
......@@ -4660,9 +4652,7 @@ static void btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root)
{
struct btrfs_inode *btrfs_inode;
struct list_head splice;
INIT_LIST_HEAD(&splice);
LIST_HEAD(splice);
spin_lock(&root->delalloc_lock);
list_splice_init(&root->delalloc_inodes, &splice);
......@@ -4695,9 +4685,7 @@ static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root)
static void btrfs_destroy_all_delalloc_inodes(struct btrfs_fs_info *fs_info)
{
struct btrfs_root *root;
struct list_head splice;
INIT_LIST_HEAD(&splice);
LIST_HEAD(splice);
spin_lock(&fs_info->delalloc_root_lock);
list_splice_init(&fs_info->delalloc_roots, &splice);
......@@ -4716,21 +4704,16 @@ static void btrfs_destroy_all_delalloc_inodes(struct btrfs_fs_info *fs_info)
spin_unlock(&fs_info->delalloc_root_lock);
}
static int btrfs_destroy_marked_extents(struct btrfs_fs_info *fs_info,
struct extent_io_tree *dirty_pages,
int mark)
static void btrfs_destroy_marked_extents(struct btrfs_fs_info *fs_info,
struct extent_io_tree *dirty_pages,
int mark)
{
int ret;
struct extent_buffer *eb;
u64 start = 0;
u64 end;
while (1) {
ret = find_first_extent_bit(dirty_pages, start, &start, &end,
mark, NULL);
if (ret)
break;
while (find_first_extent_bit(dirty_pages, start, &start, &end,
mark, NULL)) {
clear_extent_bits(dirty_pages, start, end, mark);
while (start <= end) {
eb = find_extent_buffer(fs_info, start);
......@@ -4746,16 +4729,13 @@ static int btrfs_destroy_marked_extents(struct btrfs_fs_info *fs_info,
free_extent_buffer_stale(eb);
}
}
return ret;
}
static int btrfs_destroy_pinned_extent(struct btrfs_fs_info *fs_info,
struct extent_io_tree *unpin)
static void btrfs_destroy_pinned_extent(struct btrfs_fs_info *fs_info,
struct extent_io_tree *unpin)
{
u64 start;
u64 end;
int ret;
while (1) {
struct extent_state *cached_state = NULL;
......@@ -4767,9 +4747,8 @@ static int btrfs_destroy_pinned_extent(struct btrfs_fs_info *fs_info,
* the same extent range.
*/
mutex_lock(&fs_info->unused_bg_unpin_mutex);
ret = find_first_extent_bit(unpin, 0, &start, &end,
EXTENT_DIRTY, &cached_state);
if (ret) {
if (!find_first_extent_bit(unpin, 0, &start, &end,
EXTENT_DIRTY, &cached_state)) {
mutex_unlock(&fs_info->unused_bg_unpin_mutex);
break;
}
......@@ -4780,8 +4759,6 @@ static int btrfs_destroy_pinned_extent(struct btrfs_fs_info *fs_info,
mutex_unlock(&fs_info->unused_bg_unpin_mutex);
cond_resched();
}
return 0;
}
static void btrfs_cleanup_bg_io(struct btrfs_block_group *cache)
......
......@@ -77,7 +77,6 @@ struct btrfs_root *btrfs_extent_root(struct btrfs_fs_info *fs_info, u64 bytenr);
struct btrfs_root *btrfs_block_group_root(struct btrfs_fs_info *fs_info);
void btrfs_free_fs_info(struct btrfs_fs_info *fs_info);
int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info);
void btrfs_btree_balance_dirty(struct btrfs_fs_info *fs_info);
void btrfs_btree_balance_dirty_nodelay(struct btrfs_fs_info *fs_info);
void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
......
......@@ -831,15 +831,15 @@ static struct extent_state *find_first_extent_bit_state(struct extent_io_tree *t
*
* Note: If there are multiple bits set in @bits, any of them will match.
*
* Return 0 if we find something, and update @start_ret and @end_ret.
* Return 1 if we found nothing.
* Return true if we find something, and update @start_ret and @end_ret.
* Return false if we found nothing.
*/
int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
u64 *start_ret, u64 *end_ret, u32 bits,
struct extent_state **cached_state)
bool find_first_extent_bit(struct extent_io_tree *tree, u64 start,
u64 *start_ret, u64 *end_ret, u32 bits,
struct extent_state **cached_state)
{
struct extent_state *state;
int ret = 1;
bool ret = false;
spin_lock(&tree->lock);
if (cached_state && *cached_state) {
......@@ -863,7 +863,7 @@ int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
cache_state_if_flags(state, cached_state, 0);
*start_ret = state->start;
*end_ret = state->end;
ret = 0;
ret = true;
}
out:
spin_unlock(&tree->lock);
......
......@@ -182,9 +182,9 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
u32 bits, u32 clear_bits,
struct extent_state **cached_state);
int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
u64 *start_ret, u64 *end_ret, u32 bits,
struct extent_state **cached_state);
bool find_first_extent_bit(struct extent_io_tree *tree, u64 start,
u64 *start_ret, u64 *end_ret, u32 bits,
struct extent_state **cached_state);
void find_first_clear_extent_bit(struct extent_io_tree *tree, u64 start,
u64 *start_ret, u64 *end_ret, u32 bits);
int find_contiguous_extent_bit(struct extent_io_tree *tree, u64 start,
......
......@@ -69,27 +69,6 @@ static int block_group_bits(struct btrfs_block_group *cache, u64 bits)
return (cache->flags & bits) == bits;
}
int btrfs_add_excluded_extent(struct btrfs_fs_info *fs_info,
u64 start, u64 num_bytes)
{
u64 end = start + num_bytes - 1;
set_extent_bit(&fs_info->excluded_extents, start, end,
EXTENT_UPTODATE, NULL);
return 0;
}
void btrfs_free_excluded_extents(struct btrfs_block_group *cache)
{
struct btrfs_fs_info *fs_info = cache->fs_info;
u64 start, end;
start = cache->start;
end = start + cache->length - 1;
clear_extent_bits(&fs_info->excluded_extents, start, end,
EXTENT_UPTODATE);
}
/* simple helper to search for an existing data extent at a given offset */
int btrfs_lookup_data_extent(struct btrfs_fs_info *fs_info, u64 start, u64 len)
{
......@@ -187,8 +166,10 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
num_refs = btrfs_extent_refs(leaf, ei);
extent_flags = btrfs_extent_flags(leaf, ei);
} else {
ret = -EINVAL;
btrfs_print_v0_err(fs_info);
ret = -EUCLEAN;
btrfs_err(fs_info,
"unexpected extent item size, has %u expect >= %zu",
item_size, sizeof(*ei));
if (trans)
btrfs_abort_transaction(trans, ret);
else
......@@ -402,11 +383,11 @@ int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb,
}
}
WARN_ON(1);
btrfs_print_leaf(eb);
btrfs_err(eb->fs_info,
"eb %llu iref 0x%lx invalid extent inline ref type %d",
eb->start, (unsigned long)iref, type);
WARN_ON(1);
return BTRFS_REF_TYPE_INVALID;
}
......@@ -624,12 +605,12 @@ static noinline int remove_extent_data_ref(struct btrfs_trans_handle *trans,
ref2 = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_shared_data_ref);
num_refs = btrfs_shared_data_ref_count(leaf, ref2);
} else if (unlikely(key.type == BTRFS_EXTENT_REF_V0_KEY)) {
btrfs_print_v0_err(trans->fs_info);
btrfs_abort_transaction(trans, -EINVAL);
return -EINVAL;
} else {
BUG();
btrfs_err(trans->fs_info,
"unrecognized backref key (%llu %u %llu)",
key.objectid, key.type, key.offset);
btrfs_abort_transaction(trans, -EUCLEAN);
return -EUCLEAN;
}
BUG_ON(num_refs < refs_to_drop);
......@@ -660,7 +641,6 @@ static noinline u32 extent_data_ref_count(struct btrfs_path *path,
leaf = path->nodes[0];
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
BUG_ON(key.type == BTRFS_EXTENT_REF_V0_KEY);
if (iref) {
/*
* If type is invalid, we should have bailed out earlier than
......@@ -869,6 +849,11 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
err = -ENOENT;
goto out;
} else if (WARN_ON(ret)) {
btrfs_print_leaf(path->nodes[0]);
btrfs_err(fs_info,
"extent item not found for insert, bytenr %llu num_bytes %llu parent %llu root_objectid %llu owner %llu offset %llu",
bytenr, num_bytes, parent, root_objectid, owner,
offset);
err = -EIO;
goto out;
}
......@@ -876,8 +861,10 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
leaf = path->nodes[0];
item_size = btrfs_item_size(leaf, path->slots[0]);
if (unlikely(item_size < sizeof(*ei))) {
err = -EINVAL;
btrfs_print_v0_err(fs_info);
err = -EUCLEAN;
btrfs_err(fs_info,
"unexpected extent item size, has %llu expect >= %zu",
item_size, sizeof(*ei));
btrfs_abort_transaction(trans, err);
goto out;
}
......@@ -1079,13 +1066,13 @@ static int lookup_extent_backref(struct btrfs_trans_handle *trans,
/*
* helper to update/remove inline back ref
*/
static noinline_for_stack
void update_inline_extent_backref(struct btrfs_path *path,
static noinline_for_stack int update_inline_extent_backref(struct btrfs_path *path,
struct btrfs_extent_inline_ref *iref,
int refs_to_mod,
struct btrfs_delayed_extent_op *extent_op)
{
struct extent_buffer *leaf = path->nodes[0];
struct btrfs_fs_info *fs_info = leaf->fs_info;
struct btrfs_extent_item *ei;
struct btrfs_extent_data_ref *dref = NULL;
struct btrfs_shared_data_ref *sref = NULL;
......@@ -1098,18 +1085,33 @@ void update_inline_extent_backref(struct btrfs_path *path,
ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);
refs = btrfs_extent_refs(leaf, ei);
WARN_ON(refs_to_mod < 0 && refs + refs_to_mod <= 0);
if (unlikely(refs_to_mod < 0 && refs + refs_to_mod <= 0)) {
struct btrfs_key key;
u32 extent_size;
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
if (key.type == BTRFS_METADATA_ITEM_KEY)
extent_size = fs_info->nodesize;
else
extent_size = key.offset;
btrfs_print_leaf(leaf);
btrfs_err(fs_info,
"invalid refs_to_mod for extent %llu num_bytes %u, has %d expect >= -%llu",
key.objectid, extent_size, refs_to_mod, refs);
return -EUCLEAN;
}
refs += refs_to_mod;
btrfs_set_extent_refs(leaf, ei, refs);
if (extent_op)
__run_delayed_extent_op(extent_op, leaf, ei);
type = btrfs_get_extent_inline_ref_type(leaf, iref, BTRFS_REF_TYPE_ANY);
/*
* If type is invalid, we should have bailed out after
* lookup_inline_extent_backref().
* Function btrfs_get_extent_inline_ref_type() has already printed
* error messages.
*/
type = btrfs_get_extent_inline_ref_type(leaf, iref, BTRFS_REF_TYPE_ANY);
ASSERT(type != BTRFS_REF_TYPE_INVALID);
if (unlikely(type == BTRFS_REF_TYPE_INVALID))
return -EUCLEAN;
if (type == BTRFS_EXTENT_DATA_REF_KEY) {
dref = (struct btrfs_extent_data_ref *)(&iref->offset);
......@@ -1119,10 +1121,43 @@ void update_inline_extent_backref(struct btrfs_path *path,
refs = btrfs_shared_data_ref_count(leaf, sref);
} else {
refs = 1;
BUG_ON(refs_to_mod != -1);
/*
* For tree blocks we can only drop one ref for it, and tree
* blocks should not have refs > 1.
*
* Furthermore if we're inserting a new inline backref, we
* won't reach this path either. That would be
* setup_inline_extent_backref().
*/
if (unlikely(refs_to_mod != -1)) {
struct btrfs_key key;
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
btrfs_print_leaf(leaf);
btrfs_err(fs_info,
"invalid refs_to_mod for tree block %llu, has %d expect -1",
key.objectid, refs_to_mod);
return -EUCLEAN;
}
}
BUG_ON(refs_to_mod < 0 && refs < -refs_to_mod);
if (unlikely(refs_to_mod < 0 && refs < -refs_to_mod)) {
struct btrfs_key key;
u32 extent_size;
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
if (key.type == BTRFS_METADATA_ITEM_KEY)
extent_size = fs_info->nodesize;
else
extent_size = key.offset;
btrfs_print_leaf(leaf);
btrfs_err(fs_info,
"invalid refs_to_mod for backref entry, iref %lu extent %llu num_bytes %u, has %d expect >= -%llu",
(unsigned long)iref, key.objectid, extent_size,
refs_to_mod, refs);
return -EUCLEAN;
}
refs += refs_to_mod;
if (refs > 0) {
......@@ -1142,6 +1177,7 @@ void update_inline_extent_backref(struct btrfs_path *path,
btrfs_truncate_item(path, item_size, 1);
}
btrfs_mark_buffer_dirty(leaf);
return 0;
}
static noinline_for_stack
......@@ -1170,7 +1206,7 @@ int insert_inline_extent_backref(struct btrfs_trans_handle *trans,
bytenr, num_bytes, root_objectid, path->slots[0]);
return -EUCLEAN;
}
update_inline_extent_backref(path, iref, refs_to_add, extent_op);
ret = update_inline_extent_backref(path, iref, refs_to_add, extent_op);
} else if (ret == -ENOENT) {
setup_inline_extent_backref(trans->fs_info, path, iref, parent,
root_objectid, owner, offset,
......@@ -1190,7 +1226,7 @@ static int remove_extent_backref(struct btrfs_trans_handle *trans,
BUG_ON(!is_data && refs_to_drop != 1);
if (iref)
update_inline_extent_backref(path, iref, -refs_to_drop, NULL);
ret = update_inline_extent_backref(path, iref, -refs_to_drop, NULL);
else if (is_data)
ret = remove_extent_data_ref(trans, root, path, refs_to_drop);
else
......@@ -1629,8 +1665,10 @@ static int run_delayed_extent_op(struct btrfs_trans_handle *trans,
item_size = btrfs_item_size(leaf, path->slots[0]);
if (unlikely(item_size < sizeof(*ei))) {
err = -EINVAL;
btrfs_print_v0_err(fs_info);
err = -EUCLEAN;
btrfs_err(fs_info,
"unexpected extent item size, has %u expect >= %zu",
item_size, sizeof(*ei));
btrfs_abort_transaction(trans, err);
goto out;
}
......@@ -2751,9 +2789,8 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans)
struct extent_state *cached_state = NULL;
mutex_lock(&fs_info->unused_bg_unpin_mutex);
ret = find_first_extent_bit(unpin, 0, &start, &end,
EXTENT_DIRTY, &cached_state);
if (ret) {
if (!find_first_extent_bit(unpin, 0, &start, &end,
EXTENT_DIRTY, &cached_state)) {
mutex_unlock(&fs_info->unused_bg_unpin_mutex);
break;
}
......@@ -3059,8 +3096,10 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
leaf = path->nodes[0];
item_size = btrfs_item_size(leaf, extent_slot);
if (unlikely(item_size < sizeof(*ei))) {
ret = -EINVAL;
btrfs_print_v0_err(info);
ret = -EUCLEAN;
btrfs_err(trans->fs_info,
"unexpected extent item size, has %u expect >= %zu",
item_size, sizeof(*ei));
btrfs_abort_transaction(trans, ret);
goto out;
}
......@@ -3351,11 +3390,38 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_ref *ref)
}
enum btrfs_loop_type {
/*
* Start caching block groups but do not wait for progress or for them
* to be done.
*/
LOOP_CACHING_NOWAIT,
/*
* Wait for the block group free_space >= the space we're waiting for if
* the block group isn't cached.
*/
LOOP_CACHING_WAIT,
/*
* Allow allocations to happen from block groups that do not yet have a
* size classification.
*/
LOOP_UNSET_SIZE_CLASS,
/*
* Allocate a chunk and then retry the allocation.
*/
LOOP_ALLOC_CHUNK,
/*
* Ignore the size class restrictions for this allocation.
*/
LOOP_WRONG_SIZE_CLASS,
/*
* Ignore the empty size, only try to allocate the number of bytes
* needed for this allocation.
*/
LOOP_NO_EMPTY_SIZE,
};
......@@ -3427,7 +3493,6 @@ btrfs_release_block_group(struct btrfs_block_group *cache,
* Helper function for find_free_extent().
*
* Return -ENOENT to inform caller that we need fallback to unclustered mode.
* Return -EAGAIN to inform caller that we need to re-search this block group
* Return >0 to inform caller that we find nothing
* Return 0 means we have found a location and set ffe_ctl->found_offset.
*/
......@@ -3508,14 +3573,6 @@ static int find_free_extent_clustered(struct btrfs_block_group *bg,
trace_btrfs_reserve_extent_cluster(bg, ffe_ctl);
return 0;
}
} else if (!ffe_ctl->cached && ffe_ctl->loop > LOOP_CACHING_NOWAIT &&
!ffe_ctl->retry_clustered) {
spin_unlock(&last_ptr->refill_lock);
ffe_ctl->retry_clustered = true;
btrfs_wait_block_group_cache_progress(bg, ffe_ctl->num_bytes +
ffe_ctl->empty_cluster + ffe_ctl->empty_size);
return -EAGAIN;
}
/*
* At this point we either didn't find a cluster or we weren't able to
......@@ -3530,7 +3587,6 @@ static int find_free_extent_clustered(struct btrfs_block_group *bg,
/*
* Return >0 to inform caller that we find nothing
* Return 0 when we found an free extent and set ffe_ctrl->found_offset
* Return -EAGAIN to inform caller that we need to re-search this block group
*/
static int find_free_extent_unclustered(struct btrfs_block_group *bg,
struct find_free_extent_ctl *ffe_ctl)
......@@ -3568,25 +3624,8 @@ static int find_free_extent_unclustered(struct btrfs_block_group *bg,
offset = btrfs_find_space_for_alloc(bg, ffe_ctl->search_start,
ffe_ctl->num_bytes, ffe_ctl->empty_size,
&ffe_ctl->max_extent_size);
/*
* If we didn't find a chunk, and we haven't failed on this block group
* before, and this block group is in the middle of caching and we are
* ok with waiting, then go ahead and wait for progress to be made, and
* set @retry_unclustered to true.
*
* If @retry_unclustered is true then we've already waited on this
* block group once and should move on to the next block group.
*/
if (!offset && !ffe_ctl->retry_unclustered && !ffe_ctl->cached &&
ffe_ctl->loop > LOOP_CACHING_NOWAIT) {
btrfs_wait_block_group_cache_progress(bg, ffe_ctl->num_bytes +
ffe_ctl->empty_size);
ffe_ctl->retry_unclustered = true;
return -EAGAIN;
} else if (!offset) {
if (!offset)
return 1;
}
ffe_ctl->found_offset = offset;
return 0;
}
......@@ -3600,7 +3639,7 @@ static int do_allocation_clustered(struct btrfs_block_group *block_group,
/* We want to try and use the cluster allocator, so lets look there */
if (ffe_ctl->last_ptr && ffe_ctl->use_cluster) {
ret = find_free_extent_clustered(block_group, ffe_ctl, bg_ret);
if (ret >= 0 || ret == -EAGAIN)
if (ret >= 0)
return ret;
/* ret == -ENOENT case falls through */
}
......@@ -3685,7 +3724,9 @@ static int do_allocation_zoned(struct btrfs_block_group *block_group,
}
spin_unlock(&block_group->lock);
if (!ret && !btrfs_zone_activate(block_group)) {
/* Metadata block group is activated at write time. */
if (!ret && (block_group->flags & BTRFS_BLOCK_GROUP_DATA) &&
!btrfs_zone_activate(block_group)) {
ret = 1;
/*
* May need to clear fs_info->{treelog,data_reloc}_bg.
......@@ -3709,7 +3750,8 @@ static int do_allocation_zoned(struct btrfs_block_group *block_group,
fs_info->data_reloc_bg == 0);
if (block_group->ro ||
test_bit(BLOCK_GROUP_FLAG_ZONED_DATA_RELOC, &block_group->runtime_flags)) {
(!ffe_ctl->for_data_reloc &&
test_bit(BLOCK_GROUP_FLAG_ZONED_DATA_RELOC, &block_group->runtime_flags))) {
ret = 1;
goto out;
}
......@@ -3752,8 +3794,26 @@ static int do_allocation_zoned(struct btrfs_block_group *block_group,
if (ffe_ctl->for_treelog && !fs_info->treelog_bg)
fs_info->treelog_bg = block_group->start;
if (ffe_ctl->for_data_reloc && !fs_info->data_reloc_bg)
fs_info->data_reloc_bg = block_group->start;
if (ffe_ctl->for_data_reloc) {
if (!fs_info->data_reloc_bg)
fs_info->data_reloc_bg = block_group->start;
/*
* Do not allow allocations from this block group, unless it is
* for data relocation. Compared to increasing the ->ro, setting
* the ->zoned_data_reloc_ongoing flag still allows nocow
* writers to come in. See btrfs_inc_nocow_writers().
*
* We need to disable an allocation to avoid an allocation of
* regular (non-relocation data) extent. With mix of relocation
* extents and regular extents, we can dispatch WRITE commands
* (for relocation extents) and ZONE APPEND commands (for
* regular extents) at the same time to the same zone, which
* easily break the write pointer.
*
* Also, this flag avoids this block group to be zone finished.
*/
set_bit(BLOCK_GROUP_FLAG_ZONED_DATA_RELOC, &block_group->runtime_flags);
}
ffe_ctl->found_offset = start + block_group->alloc_offset;
block_group->alloc_offset += num_bytes;
......@@ -3771,24 +3831,8 @@ static int do_allocation_zoned(struct btrfs_block_group *block_group,
out:
if (ret && ffe_ctl->for_treelog)
fs_info->treelog_bg = 0;
if (ret && ffe_ctl->for_data_reloc &&
fs_info->data_reloc_bg == block_group->start) {
/*
* Do not allow further allocations from this block group.
* Compared to increasing the ->ro, setting the
* ->zoned_data_reloc_ongoing flag still allows nocow
* writers to come in. See btrfs_inc_nocow_writers().
*
* We need to disable an allocation to avoid an allocation of
* regular (non-relocation data) extent. With mix of relocation
* extents and regular extents, we can dispatch WRITE commands
* (for relocation extents) and ZONE APPEND commands (for
* regular extents) at the same time to the same zone, which
* easily break the write pointer.
*/
set_bit(BLOCK_GROUP_FLAG_ZONED_DATA_RELOC, &block_group->runtime_flags);
if (ret && ffe_ctl->for_data_reloc)
fs_info->data_reloc_bg = 0;
}
spin_unlock(&fs_info->relocation_bg_lock);
spin_unlock(&fs_info->treelog_bg_lock);
spin_unlock(&block_group->lock);
......@@ -3816,8 +3860,7 @@ static void release_block_group(struct btrfs_block_group *block_group,
{
switch (ffe_ctl->policy) {
case BTRFS_EXTENT_ALLOC_CLUSTERED:
ffe_ctl->retry_clustered = false;
ffe_ctl->retry_unclustered = false;
ffe_ctl->retry_uncached = false;
break;
case BTRFS_EXTENT_ALLOC_ZONED:
/* Nothing to do */
......@@ -3861,6 +3904,10 @@ static void found_extent(struct find_free_extent_ctl *ffe_ctl,
static int can_allocate_chunk_zoned(struct btrfs_fs_info *fs_info,
struct find_free_extent_ctl *ffe_ctl)
{
/* Block group's activeness is not a requirement for METADATA block groups. */
if (!(ffe_ctl->flags & BTRFS_BLOCK_GROUP_DATA))
return 0;
/* If we can activate new zone, just allocate a chunk and use it */
if (btrfs_can_activate_zone(fs_info->fs_devices, ffe_ctl->flags))
return 0;
......@@ -3949,15 +3996,7 @@ static int find_free_extent_update_loop(struct btrfs_fs_info *fs_info,
if (ffe_ctl->index < BTRFS_NR_RAID_TYPES)
return 1;
/*
* LOOP_CACHING_NOWAIT, search partially cached block groups, kicking
* caching kthreads as we move along
* LOOP_CACHING_WAIT, search everything, and wait if our bg is caching
* LOOP_UNSET_SIZE_CLASS, allow unset size class
* LOOP_ALLOC_CHUNK, force a chunk allocation and try again
* LOOP_NO_EMPTY_SIZE, set empty_size and empty_cluster to 0 and try
* again
*/
/* See the comments for btrfs_loop_type for an explanation of the phases. */
if (ffe_ctl->loop < LOOP_NO_EMPTY_SIZE) {
ffe_ctl->index = 0;
/*
......@@ -4168,9 +4207,7 @@ static noinline int find_free_extent(struct btrfs_root *root,
ffe_ctl->orig_have_caching_bg = false;
ffe_ctl->index = btrfs_bg_flags_to_raid_index(ffe_ctl->flags);
ffe_ctl->loop = 0;
/* For clustered allocation */
ffe_ctl->retry_clustered = false;
ffe_ctl->retry_unclustered = false;
ffe_ctl->retry_uncached = false;
ffe_ctl->cached = 0;
ffe_ctl->max_extent_size = 0;
ffe_ctl->total_free_space = 0;
......@@ -4321,16 +4358,12 @@ static noinline int find_free_extent(struct btrfs_root *root,
bg_ret = NULL;
ret = do_allocation(block_group, ffe_ctl, &bg_ret);
if (ret == 0) {
if (bg_ret && bg_ret != block_group) {
btrfs_release_block_group(block_group,
ffe_ctl->delalloc);
block_group = bg_ret;
}
} else if (ret == -EAGAIN) {
goto have_block_group;
} else if (ret > 0) {
if (ret > 0)
goto loop;
if (bg_ret && bg_ret != block_group) {
btrfs_release_block_group(block_group, ffe_ctl->delalloc);
block_group = bg_ret;
}
/* Checks */
......@@ -4371,6 +4404,15 @@ static noinline int find_free_extent(struct btrfs_root *root,
btrfs_release_block_group(block_group, ffe_ctl->delalloc);
break;
loop:
if (!ffe_ctl->cached && ffe_ctl->loop > LOOP_CACHING_NOWAIT &&
!ffe_ctl->retry_uncached) {
ffe_ctl->retry_uncached = true;
btrfs_wait_block_group_cache_progress(block_group,
ffe_ctl->num_bytes +
ffe_ctl->empty_cluster +
ffe_ctl->empty_size);
goto have_block_group;
}
release_block_group(block_group, ffe_ctl, ffe_ctl->delalloc);
cond_resched();
}
......
......@@ -48,16 +48,11 @@ struct find_free_extent_ctl {
int loop;
/*
* Whether we're refilling a cluster, if true we need to re-search
* current block group but don't try to refill the cluster again.
* Set to true if we're retrying the allocation on this block group
* after waiting for caching progress, this is so that we retry only
* once before moving on to another block group.
*/
bool retry_clustered;
/*
* Whether we're updating free space cache, if true we need to re-search
* current block group but don't try updating free space cache again.
*/
bool retry_unclustered;
bool retry_uncached;
/* If current block group is cached */
int cached;
......@@ -96,9 +91,6 @@ int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb,
enum btrfs_inline_ref_type is_data);
u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset);
int btrfs_add_excluded_extent(struct btrfs_fs_info *fs_info,
u64 start, u64 num_bytes);
void btrfs_free_excluded_extents(struct btrfs_block_group *cache);
int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, unsigned long count);
void btrfs_cleanup_ref_head_accounting(struct btrfs_fs_info *fs_info,
struct btrfs_delayed_ref_root *delayed_refs,
......
This diff is collapsed.
......@@ -40,7 +40,6 @@ enum {
ENUM_BIT(PAGE_START_WRITEBACK),
ENUM_BIT(PAGE_END_WRITEBACK),
ENUM_BIT(PAGE_SET_ORDERED),
ENUM_BIT(PAGE_LOCK),
};
/*
......@@ -94,6 +93,13 @@ struct extent_buffer {
#endif
};
struct btrfs_eb_write_context {
struct writeback_control *wbc;
struct extent_buffer *eb;
/* Block group @eb resides in. Only used for zoned mode. */
struct btrfs_block_group *zoned_bg;
};
/*
* Get the correct offset inside the page of extent buffer.
*
......@@ -178,8 +184,9 @@ int try_release_extent_mapping(struct page *page, gfp_t mask);
int try_release_extent_buffer(struct page *page);
int btrfs_read_folio(struct file *file, struct folio *folio);
int extent_write_locked_range(struct inode *inode, u64 start, u64 end,
struct writeback_control *wbc);
void extent_write_locked_range(struct inode *inode, struct page *locked_page,
u64 start, u64 end, struct writeback_control *wbc,
bool pages_dirty);
int extent_writepages(struct address_space *mapping,
struct writeback_control *wbc);
int btree_write_cache_pages(struct address_space *mapping,
......@@ -236,11 +243,24 @@ void read_extent_buffer(const struct extent_buffer *eb, void *dst,
int read_extent_buffer_to_user_nofault(const struct extent_buffer *eb,
void __user *dst, unsigned long start,
unsigned long len);
void write_extent_buffer_fsid(const struct extent_buffer *eb, const void *src);
void write_extent_buffer_chunk_tree_uuid(const struct extent_buffer *eb,
const void *src);
void write_extent_buffer(const struct extent_buffer *eb, const void *src,
unsigned long start, unsigned long len);
static inline void write_extent_buffer_chunk_tree_uuid(
const struct extent_buffer *eb, const void *chunk_tree_uuid)
{
write_extent_buffer(eb, chunk_tree_uuid,
offsetof(struct btrfs_header, chunk_tree_uuid),
BTRFS_FSID_SIZE);
}
static inline void write_extent_buffer_fsid(const struct extent_buffer *eb,
const void *fsid)
{
write_extent_buffer(eb, fsid, offsetof(struct btrfs_header, fsid),
BTRFS_FSID_SIZE);
}
void copy_extent_buffer_full(const struct extent_buffer *dst,
const struct extent_buffer *src);
void copy_extent_buffer(const struct extent_buffer *dst,
......@@ -266,7 +286,6 @@ void set_extent_buffer_dirty(struct extent_buffer *eb);
void set_extent_buffer_uptodate(struct extent_buffer *eb);
void clear_extent_buffer_uptodate(struct extent_buffer *eb);
void extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end);
void extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end);
void extent_clear_unlock_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
struct page *locked_page,
u32 bits_to_clear, unsigned long page_ops);
......@@ -277,8 +296,6 @@ void btrfs_clear_buffer_dirty(struct btrfs_trans_handle *trans,
int btrfs_alloc_page_array(unsigned int nr_pages, struct page **page_array);
void end_extent_writepage(struct page *page, int err, u64 start, u64 end);
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
bool find_lock_delalloc_range(struct inode *inode,
struct page *locked_page, u64 *start,
......
......@@ -597,29 +597,37 @@ int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end,
* Each bit represents a sector. Thus caller should ensure @csum_buf passed
* in is large enough to contain all csums.
*/
int btrfs_lookup_csums_bitmap(struct btrfs_root *root, u64 start, u64 end,
u8 *csum_buf, unsigned long *csum_bitmap,
bool search_commit)
int btrfs_lookup_csums_bitmap(struct btrfs_root *root, struct btrfs_path *path,
u64 start, u64 end, u8 *csum_buf,
unsigned long *csum_bitmap)
{
struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_key key;
struct btrfs_path *path;
struct extent_buffer *leaf;
struct btrfs_csum_item *item;
const u64 orig_start = start;
bool free_path = false;
int ret;
ASSERT(IS_ALIGNED(start, fs_info->sectorsize) &&
IS_ALIGNED(end + 1, fs_info->sectorsize));
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
if (!path) {
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
free_path = true;
}
if (search_commit) {
path->skip_locking = 1;
path->reada = READA_FORWARD;
path->search_commit_root = 1;
/* Check if we can reuse the previous path. */
if (path->nodes[0]) {
btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
if (key.objectid == BTRFS_EXTENT_CSUM_OBJECTID &&
key.type == BTRFS_EXTENT_CSUM_KEY &&
key.offset <= start)
goto search_forward;
btrfs_release_path(path);
}
key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
......@@ -656,6 +664,7 @@ int btrfs_lookup_csums_bitmap(struct btrfs_root *root, u64 start, u64 end,
}
}
search_forward:
while (start <= end) {
u64 csum_end;
......@@ -712,7 +721,8 @@ int btrfs_lookup_csums_bitmap(struct btrfs_root *root, u64 start, u64 end,
}
ret = 0;
fail:
btrfs_free_path(path);
if (free_path)
btrfs_free_path(path);
return ret;
}
......
......@@ -57,9 +57,9 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end,
struct list_head *list, int search_commit,
bool nowait);
int btrfs_lookup_csums_bitmap(struct btrfs_root *root, u64 start, u64 end,
u8 *csum_buf, unsigned long *csum_bitmap,
bool search_commit);
int btrfs_lookup_csums_bitmap(struct btrfs_root *root, struct btrfs_path *path,
u64 start, u64 end, u8 *csum_buf,
unsigned long *csum_bitmap);
void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode,
const struct btrfs_path *path,
struct btrfs_file_extent_item *fi,
......
......@@ -2999,7 +2999,7 @@ static long btrfs_fallocate(struct file *file, int mode,
struct extent_changeset *data_reserved = NULL;
struct falloc_range *range;
struct falloc_range *tmp;
struct list_head reserve_list;
LIST_HEAD(reserve_list);
u64 cur_offset;
u64 last_byte;
u64 alloc_start;
......@@ -3091,7 +3091,6 @@ static long btrfs_fallocate(struct file *file, int mode,
btrfs_assert_inode_range_clean(BTRFS_I(inode), alloc_start, locked_end);
/* First, check if we exceed the qgroup limit */
INIT_LIST_HEAD(&reserve_list);
while (cur_offset < alloc_end) {
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, cur_offset,
alloc_end - cur_offset);
......
......@@ -1219,10 +1219,9 @@ static noinline_for_stack int write_pinned_extent_entries(
start = block_group->start;
while (start < block_group->start + block_group->length) {
ret = find_first_extent_bit(unpin, start,
&extent_start, &extent_end,
EXTENT_DIRTY, NULL);
if (ret)
if (!find_first_extent_bit(unpin, start,
&extent_start, &extent_end,
EXTENT_DIRTY, NULL))
return 0;
/* This pinned extent is out of our range */
......@@ -2705,13 +2704,8 @@ static int __btrfs_add_free_space_zoned(struct btrfs_block_group *block_group,
bg_reclaim_threshold = READ_ONCE(sinfo->bg_reclaim_threshold);
spin_lock(&ctl->tree_lock);
/* Count initial region as zone_unusable until it gets activated. */
if (!used)
to_free = size;
else if (initial &&
test_bit(BTRFS_FS_ACTIVE_ZONE_TRACKING, &block_group->fs_info->flags) &&
(block_group->flags & (BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_SYSTEM)))
to_free = 0;
else if (initial)
to_free = block_group->zone_capacity;
else if (offset >= block_group->alloc_offset)
......@@ -2739,8 +2733,7 @@ static int __btrfs_add_free_space_zoned(struct btrfs_block_group *block_group,
reclaimable_unusable = block_group->zone_unusable -
(block_group->length - block_group->zone_capacity);
/* All the region is now unusable. Mark it as unused and reclaim */
if (block_group->zone_unusable == block_group->length &&
block_group->alloc_offset) {
if (block_group->zone_unusable == block_group->length) {
btrfs_mark_bg_unused(block_group);
} else if (bg_reclaim_threshold &&
reclaimable_unusable >=
......@@ -2944,7 +2937,8 @@ void btrfs_dump_free_space(struct btrfs_block_group *block_group,
btrfs_info(fs_info, "block group has cluster?: %s",
list_empty(&block_group->cluster_list) ? "no" : "yes");
btrfs_info(fs_info,
"%d blocks of free space at or bigger than bytes is", count);
"%d free space entries at or bigger than %llu bytes",
count, bytes);
}
void btrfs_init_free_space_ctl(struct btrfs_block_group *block_group,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment