提交 d601e58c 编写于 作者: L Linus Torvalds

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

Pull btrfs updates from David Sterba:
 "This end of the year branch is intentionally not that exciting. Most
  of the changes are under the hood, but there are some minor user
  visible improvements and several performance improvements too.

  Features:

   - make send work with concurrent block group relocation.

     We're not allowed to prevent send failing or silently producing
     some bad stream but with more fine grained locking and checks it's
     possible. The send vs deduplication exclusion could reuse the same
     logic in the future.

   - new exclusive operation 'balance paused' to allow adding a device
     to filesystem with paused balance

   - new sysfs file for fsid stored in the per-device directory to help
     distinguish devices when seeding is enabled, the fsid may differ
     from the one reported by the filesystem

  Performance improvements:

   - less metadata needed for directory logging, directory deletion is
     20-40% faster

   - in zoned mode, cache zone information during mount to speed up
     repeated queries (about 50% speedup)

   - free space tree entries get indexed and searched by size (latency
     -30%, search run time -30%)

   - less contention in tree node locking when inserting a key and no
     splits are needed (files/sec in fsmark improves by 1-20%)

  Fixes:

   - fix ENOSPC failure when attempting direct IO write into NOCOW range

   - fix deadlock between quota enable and other quota operations

   - global reserve minimum calculations fixed to account for free space
     tree

   - in zoned mode, fix condition for chunk allocation that may not find
     the right zone for reuse and could lead to early ENOSPC

  Core:

   - global reserve stealing got simplified and cleaned up in evict

   - remove async transaction commit based on manual transaction refs,
     reuse existing kthread and mechanisms to let it commit transaction
     before timeout

   - preparatory work for extent tree v2, add wrappers for global tree
     roots, truncation path cleanups

   - remove readahead framework, it's a bit overengineered and used only
     for scrub, and yet it does not cover all its needs, there is
     another readahead built in the b-tree search that is now used,
     performance drop on HDD is about 5% which is acceptable and scrub
     is often throttled anyway, on SSDs there's no reported drop but
     slight improvement

   - self tests report extent tree state when error occurs

   - replace assert with debugging information when an uncommitted
     transaction is found at unmount time

  Other:

   - error handling improvements

   - other cleanups and refactoring"

* tag 'for-5.17-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: (115 commits)
  btrfs: output more debug messages for uncommitted transaction
  btrfs: respect the max size in the header when activating swap file
  btrfs: fix argument list that the kdoc format and script verified
  btrfs: remove unnecessary parameter type from compression_decompress_bio
  btrfs: selftests: dump extent io tree if extent-io-tree test failed
  btrfs: scrub: cleanup the argument list of scrub_stripe()
  btrfs: scrub: cleanup the argument list of scrub_chunk()
  btrfs: remove reada infrastructure
  btrfs: scrub: use btrfs_path::reada for extent tree readahead
  btrfs: scrub: remove the unnecessary path parameter for scrub_raid56_parity()
  btrfs: refactor unlock_up
  btrfs: skip transaction commit after failure to create subvolume
  btrfs: zoned: fix chunk allocation condition for zoned allocator
  btrfs: add extent allocator hook to decide to allocate chunk or not
  btrfs: zoned: unset dedicated block group on allocation failure
  btrfs: zoned: drop redundant check for REQ_OP_ZONE_APPEND and btrfs_is_zoned
  btrfs: zoned: sink zone check into btrfs_repair_one_zone
  btrfs: zoned: simplify btrfs_check_meta_write_pointer
  btrfs: zoned: encapsulate inode locking for zoned relocation
  btrfs: sysfs: add devinfo/fsid to retrieve actual fsid from the device
  ...
...@@ -27,7 +27,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ ...@@ -27,7 +27,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \ extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
export.o tree-log.o free-space-cache.o zlib.o lzo.o zstd.o \ export.o tree-log.o free-space-cache.o zlib.o lzo.o zstd.o \
compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \ compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \ backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \
uuid-tree.o props.o free-space-tree.o tree-checker.o space-info.o \ uuid-tree.o props.o free-space-tree.o tree-checker.o space-info.o \
block-rsv.o delalloc-space.o block-group.o discard.o reflink.o \ block-rsv.o delalloc-space.o block-group.o discard.o reflink.o \
subpage.o tree-mod-log.o subpage.o tree-mod-log.o
......
...@@ -950,7 +950,7 @@ static int add_inline_refs(const struct btrfs_fs_info *fs_info, ...@@ -950,7 +950,7 @@ static int add_inline_refs(const struct btrfs_fs_info *fs_info,
leaf = path->nodes[0]; leaf = path->nodes[0];
slot = path->slots[0]; slot = path->slots[0];
item_size = btrfs_item_size_nr(leaf, slot); item_size = btrfs_item_size(leaf, slot);
BUG_ON(item_size < sizeof(*ei)); BUG_ON(item_size < sizeof(*ei));
ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item); ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item);
...@@ -1049,12 +1049,12 @@ static int add_inline_refs(const struct btrfs_fs_info *fs_info, ...@@ -1049,12 +1049,12 @@ static int add_inline_refs(const struct btrfs_fs_info *fs_info,
* *
* Returns 0 on success, <0 on error, or BACKREF_FOUND_SHARED. * Returns 0 on success, <0 on error, or BACKREF_FOUND_SHARED.
*/ */
static int add_keyed_refs(struct btrfs_fs_info *fs_info, static int add_keyed_refs(struct btrfs_root *extent_root,
struct btrfs_path *path, u64 bytenr, struct btrfs_path *path, u64 bytenr,
int info_level, struct preftrees *preftrees, int info_level, struct preftrees *preftrees,
struct share_check *sc) struct share_check *sc)
{ {
struct btrfs_root *extent_root = fs_info->extent_root; struct btrfs_fs_info *fs_info = extent_root->fs_info;
int ret; int ret;
int slot; int slot;
struct extent_buffer *leaf; struct extent_buffer *leaf;
...@@ -1170,6 +1170,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, ...@@ -1170,6 +1170,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
struct ulist *roots, const u64 *extent_item_pos, struct ulist *roots, const u64 *extent_item_pos,
struct share_check *sc, bool ignore_offset) struct share_check *sc, bool ignore_offset)
{ {
struct btrfs_root *root = btrfs_extent_root(fs_info, bytenr);
struct btrfs_key key; struct btrfs_key key;
struct btrfs_path *path; struct btrfs_path *path;
struct btrfs_delayed_ref_root *delayed_refs = NULL; struct btrfs_delayed_ref_root *delayed_refs = NULL;
...@@ -1203,28 +1204,26 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, ...@@ -1203,28 +1204,26 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
if (time_seq == BTRFS_SEQ_LAST) if (time_seq == BTRFS_SEQ_LAST)
path->skip_locking = 1; path->skip_locking = 1;
/*
* grab both a lock on the path and a lock on the delayed ref head.
* We need both to get a consistent picture of how the refs look
* at a specified point in time
*/
again: again:
head = NULL; head = NULL;
ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0); ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
if (ret < 0) if (ret < 0)
goto out; goto out;
BUG_ON(ret == 0); if (ret == 0) {
/* This shouldn't happen, indicates a bug or fs corruption. */
ASSERT(ret != 0);
ret = -EUCLEAN;
goto out;
}
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
if (trans && likely(trans->type != __TRANS_DUMMY) && if (trans && likely(trans->type != __TRANS_DUMMY) &&
time_seq != BTRFS_SEQ_LAST) { time_seq != BTRFS_SEQ_LAST) {
#else
if (trans && time_seq != BTRFS_SEQ_LAST) {
#endif
/* /*
* look if there are updates for this ref queued and lock the * We have a specific time_seq we care about and trans which
* head * means we have the path lock, we need to grab the ref head and
* lock it so we have a consistent view of the refs at the given
* time.
*/ */
delayed_refs = &trans->transaction->delayed_refs; delayed_refs = &trans->transaction->delayed_refs;
spin_lock(&delayed_refs->lock); spin_lock(&delayed_refs->lock);
...@@ -1271,7 +1270,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, ...@@ -1271,7 +1270,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
&info_level, &preftrees, sc); &info_level, &preftrees, sc);
if (ret) if (ret)
goto out; goto out;
ret = add_keyed_refs(fs_info, path, bytenr, info_level, ret = add_keyed_refs(root, path, bytenr, info_level,
&preftrees, sc); &preftrees, sc);
if (ret) if (ret)
goto out; goto out;
...@@ -1360,10 +1359,18 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, ...@@ -1360,10 +1359,18 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
goto out; goto out;
if (!ret && extent_item_pos) { if (!ret && extent_item_pos) {
/* /*
* we've recorded that parent, so we must extend * We've recorded that parent, so we must extend
* its inode list here * its inode list here.
*
* However if there was corruption we may not
* have found an eie, return an error in this
* case.
*/ */
BUG_ON(!eie); ASSERT(eie);
if (!eie) {
ret = -EUCLEAN;
goto out;
}
while (eie->next) while (eie->next)
eie = eie->next; eie = eie->next;
eie->next = ref->inode_list; eie->next = ref->inode_list;
...@@ -1740,6 +1747,7 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical, ...@@ -1740,6 +1747,7 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
struct btrfs_path *path, struct btrfs_key *found_key, struct btrfs_path *path, struct btrfs_key *found_key,
u64 *flags_ret) u64 *flags_ret)
{ {
struct btrfs_root *extent_root = btrfs_extent_root(fs_info, logical);
int ret; int ret;
u64 flags; u64 flags;
u64 size = 0; u64 size = 0;
...@@ -1755,11 +1763,11 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical, ...@@ -1755,11 +1763,11 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
key.objectid = logical; key.objectid = logical;
key.offset = (u64)-1; key.offset = (u64)-1;
ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0); ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = btrfs_previous_extent_item(fs_info->extent_root, path, 0); ret = btrfs_previous_extent_item(extent_root, path, 0);
if (ret) { if (ret) {
if (ret > 0) if (ret > 0)
ret = -ENOENT; ret = -ENOENT;
...@@ -1779,7 +1787,7 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical, ...@@ -1779,7 +1787,7 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
} }
eb = path->nodes[0]; eb = path->nodes[0];
item_size = btrfs_item_size_nr(eb, path->slots[0]); item_size = btrfs_item_size(eb, path->slots[0]);
BUG_ON(item_size < sizeof(*ei)); BUG_ON(item_size < sizeof(*ei));
ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item); ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item);
...@@ -1962,7 +1970,7 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, ...@@ -1962,7 +1970,7 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
extent_item_objectid); extent_item_objectid);
if (!search_commit_root) { if (!search_commit_root) {
trans = btrfs_attach_transaction(fs_info->extent_root); trans = btrfs_attach_transaction(fs_info->tree_root);
if (IS_ERR(trans)) { if (IS_ERR(trans)) {
if (PTR_ERR(trans) != -ENOENT && if (PTR_ERR(trans) != -ENOENT &&
PTR_ERR(trans) != -EROFS) PTR_ERR(trans) != -EROFS)
...@@ -2058,7 +2066,6 @@ static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root, ...@@ -2058,7 +2066,6 @@ static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root,
u64 parent = 0; u64 parent = 0;
int found = 0; int found = 0;
struct extent_buffer *eb; struct extent_buffer *eb;
struct btrfs_item *item;
struct btrfs_inode_ref *iref; struct btrfs_inode_ref *iref;
struct btrfs_key found_key; struct btrfs_key found_key;
...@@ -2084,10 +2091,9 @@ static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root, ...@@ -2084,10 +2091,9 @@ static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root,
} }
btrfs_release_path(path); btrfs_release_path(path);
item = btrfs_item_nr(slot);
iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref); iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref);
for (cur = 0; cur < btrfs_item_size(eb, item); cur += len) { for (cur = 0; cur < btrfs_item_size(eb, slot); cur += len) {
name_len = btrfs_inode_ref_name_len(eb, iref); name_len = btrfs_inode_ref_name_len(eb, iref);
/* path must be released before calling iterate()! */ /* path must be released before calling iterate()! */
btrfs_debug(fs_root->fs_info, btrfs_debug(fs_root->fs_info,
...@@ -2143,7 +2149,7 @@ static int iterate_inode_extrefs(u64 inum, struct btrfs_root *fs_root, ...@@ -2143,7 +2149,7 @@ static int iterate_inode_extrefs(u64 inum, struct btrfs_root *fs_root,
} }
btrfs_release_path(path); btrfs_release_path(path);
item_size = btrfs_item_size_nr(eb, slot); item_size = btrfs_item_size(eb, slot);
ptr = btrfs_item_ptr_offset(eb, slot); ptr = btrfs_item_ptr_offset(eb, slot);
cur_offset = 0; cur_offset = 0;
...@@ -2330,6 +2336,7 @@ struct btrfs_backref_iter *btrfs_backref_iter_alloc( ...@@ -2330,6 +2336,7 @@ struct btrfs_backref_iter *btrfs_backref_iter_alloc(
int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr) int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr)
{ {
struct btrfs_fs_info *fs_info = iter->fs_info; struct btrfs_fs_info *fs_info = iter->fs_info;
struct btrfs_root *extent_root = btrfs_extent_root(fs_info, bytenr);
struct btrfs_path *path = iter->path; struct btrfs_path *path = iter->path;
struct btrfs_extent_item *ei; struct btrfs_extent_item *ei;
struct btrfs_key key; struct btrfs_key key;
...@@ -2340,7 +2347,7 @@ int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr) ...@@ -2340,7 +2347,7 @@ int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr)
key.offset = (u64)-1; key.offset = (u64)-1;
iter->bytenr = bytenr; iter->bytenr = bytenr;
ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0); ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (ret == 0) { if (ret == 0) {
...@@ -2364,7 +2371,7 @@ int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr) ...@@ -2364,7 +2371,7 @@ int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr)
iter->item_ptr = (u32)btrfs_item_ptr_offset(path->nodes[0], iter->item_ptr = (u32)btrfs_item_ptr_offset(path->nodes[0],
path->slots[0]); path->slots[0]);
iter->end_ptr = (u32)(iter->item_ptr + iter->end_ptr = (u32)(iter->item_ptr +
btrfs_item_size_nr(path->nodes[0], path->slots[0])); btrfs_item_size(path->nodes[0], path->slots[0]));
ei = btrfs_item_ptr(path->nodes[0], path->slots[0], ei = btrfs_item_ptr(path->nodes[0], path->slots[0],
struct btrfs_extent_item); struct btrfs_extent_item);
...@@ -2383,7 +2390,7 @@ int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr) ...@@ -2383,7 +2390,7 @@ int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr)
/* If there is no inline backref, go search for keyed backref */ /* If there is no inline backref, go search for keyed backref */
if (iter->cur_ptr >= iter->end_ptr) { if (iter->cur_ptr >= iter->end_ptr) {
ret = btrfs_next_item(fs_info->extent_root, path); ret = btrfs_next_item(extent_root, path);
/* No inline nor keyed ref */ /* No inline nor keyed ref */
if (ret > 0) { if (ret > 0) {
...@@ -2404,7 +2411,7 @@ int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr) ...@@ -2404,7 +2411,7 @@ int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr)
iter->cur_ptr = (u32)btrfs_item_ptr_offset(path->nodes[0], iter->cur_ptr = (u32)btrfs_item_ptr_offset(path->nodes[0],
path->slots[0]); path->slots[0]);
iter->item_ptr = iter->cur_ptr; iter->item_ptr = iter->cur_ptr;
iter->end_ptr = (u32)(iter->item_ptr + btrfs_item_size_nr( iter->end_ptr = (u32)(iter->item_ptr + btrfs_item_size(
path->nodes[0], path->slots[0])); path->nodes[0], path->slots[0]));
} }
...@@ -2427,6 +2434,7 @@ int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr) ...@@ -2427,6 +2434,7 @@ int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr)
int btrfs_backref_iter_next(struct btrfs_backref_iter *iter) int btrfs_backref_iter_next(struct btrfs_backref_iter *iter)
{ {
struct extent_buffer *eb = btrfs_backref_get_eb(iter); struct extent_buffer *eb = btrfs_backref_get_eb(iter);
struct btrfs_root *extent_root;
struct btrfs_path *path = iter->path; struct btrfs_path *path = iter->path;
struct btrfs_extent_inline_ref *iref; struct btrfs_extent_inline_ref *iref;
int ret; int ret;
...@@ -2457,7 +2465,8 @@ int btrfs_backref_iter_next(struct btrfs_backref_iter *iter) ...@@ -2457,7 +2465,8 @@ int btrfs_backref_iter_next(struct btrfs_backref_iter *iter)
} }
/* We're at keyed items, there is no inline item, go to the next one */ /* We're at keyed items, there is no inline item, go to the next one */
ret = btrfs_next_item(iter->fs_info->extent_root, iter->path); extent_root = btrfs_extent_root(iter->fs_info, iter->bytenr);
ret = btrfs_next_item(extent_root, iter->path);
if (ret) if (ret)
return ret; return ret;
...@@ -2469,7 +2478,7 @@ int btrfs_backref_iter_next(struct btrfs_backref_iter *iter) ...@@ -2469,7 +2478,7 @@ int btrfs_backref_iter_next(struct btrfs_backref_iter *iter)
iter->item_ptr = (u32)btrfs_item_ptr_offset(path->nodes[0], iter->item_ptr = (u32)btrfs_item_ptr_offset(path->nodes[0],
path->slots[0]); path->slots[0]);
iter->cur_ptr = iter->item_ptr; iter->cur_ptr = iter->item_ptr;
iter->end_ptr = iter->item_ptr + (u32)btrfs_item_size_nr(path->nodes[0], iter->end_ptr = iter->item_ptr + (u32)btrfs_item_size(path->nodes[0],
path->slots[0]); path->slots[0]);
return 0; return 0;
} }
......
...@@ -514,7 +514,7 @@ static int load_extent_tree_free(struct btrfs_caching_control *caching_ctl) ...@@ -514,7 +514,7 @@ static int load_extent_tree_free(struct btrfs_caching_control *caching_ctl)
{ {
struct btrfs_block_group *block_group = caching_ctl->block_group; struct btrfs_block_group *block_group = caching_ctl->block_group;
struct btrfs_fs_info *fs_info = block_group->fs_info; struct btrfs_fs_info *fs_info = block_group->fs_info;
struct btrfs_root *extent_root = fs_info->extent_root; struct btrfs_root *extent_root;
struct btrfs_path *path; struct btrfs_path *path;
struct extent_buffer *leaf; struct extent_buffer *leaf;
struct btrfs_key key; struct btrfs_key key;
...@@ -529,6 +529,7 @@ static int load_extent_tree_free(struct btrfs_caching_control *caching_ctl) ...@@ -529,6 +529,7 @@ static int load_extent_tree_free(struct btrfs_caching_control *caching_ctl)
return -ENOMEM; return -ENOMEM;
last = max_t(u64, block_group->start, BTRFS_SUPER_INFO_OFFSET); last = max_t(u64, block_group->start, BTRFS_SUPER_INFO_OFFSET);
extent_root = btrfs_extent_root(fs_info, last);
#ifdef CONFIG_BTRFS_DEBUG #ifdef CONFIG_BTRFS_DEBUG
/* /*
...@@ -841,7 +842,7 @@ static int remove_block_group_item(struct btrfs_trans_handle *trans, ...@@ -841,7 +842,7 @@ static int remove_block_group_item(struct btrfs_trans_handle *trans,
struct btrfs_key key; struct btrfs_key key;
int ret; int ret;
root = fs_info->extent_root; root = btrfs_block_group_root(fs_info);
key.objectid = block_group->start; key.objectid = block_group->start;
key.type = BTRFS_BLOCK_GROUP_ITEM_KEY; key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
key.offset = block_group->length; key.offset = block_group->length;
...@@ -1106,6 +1107,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, ...@@ -1106,6 +1107,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
struct btrfs_trans_handle *btrfs_start_trans_remove_block_group( struct btrfs_trans_handle *btrfs_start_trans_remove_block_group(
struct btrfs_fs_info *fs_info, const u64 chunk_offset) struct btrfs_fs_info *fs_info, const u64 chunk_offset)
{ {
struct btrfs_root *root = btrfs_block_group_root(fs_info);
struct extent_map_tree *em_tree = &fs_info->mapping_tree; struct extent_map_tree *em_tree = &fs_info->mapping_tree;
struct extent_map *em; struct extent_map *em;
struct map_lookup *map; struct map_lookup *map;
...@@ -1139,8 +1141,7 @@ struct btrfs_trans_handle *btrfs_start_trans_remove_block_group( ...@@ -1139,8 +1141,7 @@ struct btrfs_trans_handle *btrfs_start_trans_remove_block_group(
num_items = 3 + map->num_stripes; num_items = 3 + map->num_stripes;
free_extent_map(em); free_extent_map(em);
return btrfs_start_transaction_fallback_global_rsv(fs_info->extent_root, return btrfs_start_transaction_fallback_global_rsv(root, num_items);
num_items);
} }
/* /*
...@@ -1508,7 +1509,6 @@ void btrfs_reclaim_bgs_work(struct work_struct *work) ...@@ -1508,7 +1509,6 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
container_of(work, struct btrfs_fs_info, reclaim_bgs_work); container_of(work, struct btrfs_fs_info, reclaim_bgs_work);
struct btrfs_block_group *bg; struct btrfs_block_group *bg;
struct btrfs_space_info *space_info; struct btrfs_space_info *space_info;
LIST_HEAD(again_list);
if (!test_bit(BTRFS_FS_OPEN, &fs_info->flags)) if (!test_bit(BTRFS_FS_OPEN, &fs_info->flags))
return; return;
...@@ -1585,18 +1585,14 @@ void btrfs_reclaim_bgs_work(struct work_struct *work) ...@@ -1585,18 +1585,14 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
div64_u64(zone_unusable * 100, bg->length)); div64_u64(zone_unusable * 100, bg->length));
trace_btrfs_reclaim_block_group(bg); trace_btrfs_reclaim_block_group(bg);
ret = btrfs_relocate_chunk(fs_info, bg->start); ret = btrfs_relocate_chunk(fs_info, bg->start);
if (ret && ret != -EAGAIN) if (ret)
btrfs_err(fs_info, "error relocating chunk %llu", btrfs_err(fs_info, "error relocating chunk %llu",
bg->start); bg->start);
next: next:
btrfs_put_block_group(bg);
spin_lock(&fs_info->unused_bgs_lock); spin_lock(&fs_info->unused_bgs_lock);
if (ret == -EAGAIN && list_empty(&bg->bg_list))
list_add_tail(&bg->bg_list, &again_list);
else
btrfs_put_block_group(bg);
} }
list_splice_tail(&again_list, &fs_info->reclaim_bgs);
spin_unlock(&fs_info->unused_bgs_lock); spin_unlock(&fs_info->unused_bgs_lock);
mutex_unlock(&fs_info->reclaim_bgs_lock); mutex_unlock(&fs_info->reclaim_bgs_lock);
btrfs_exclop_finish(fs_info); btrfs_exclop_finish(fs_info);
...@@ -1678,7 +1674,7 @@ static int find_first_block_group(struct btrfs_fs_info *fs_info, ...@@ -1678,7 +1674,7 @@ static int find_first_block_group(struct btrfs_fs_info *fs_info,
struct btrfs_path *path, struct btrfs_path *path,
struct btrfs_key *key) struct btrfs_key *key)
{ {
struct btrfs_root *root = fs_info->extent_root; struct btrfs_root *root = btrfs_block_group_root(fs_info);
int ret; int ret;
struct btrfs_key found_key; struct btrfs_key found_key;
struct extent_buffer *leaf; struct extent_buffer *leaf;
...@@ -2165,6 +2161,7 @@ static int fill_dummy_bgs(struct btrfs_fs_info *fs_info) ...@@ -2165,6 +2161,7 @@ static int fill_dummy_bgs(struct btrfs_fs_info *fs_info)
int btrfs_read_block_groups(struct btrfs_fs_info *info) int btrfs_read_block_groups(struct btrfs_fs_info *info)
{ {
struct btrfs_root *root = btrfs_block_group_root(info);
struct btrfs_path *path; struct btrfs_path *path;
int ret; int ret;
struct btrfs_block_group *cache; struct btrfs_block_group *cache;
...@@ -2173,7 +2170,7 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info) ...@@ -2173,7 +2170,7 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info)
int need_clear = 0; int need_clear = 0;
u64 cache_gen; u64 cache_gen;
if (!info->extent_root) if (!root)
return fill_dummy_bgs(info); return fill_dummy_bgs(info);
key.objectid = 0; key.objectid = 0;
...@@ -2276,7 +2273,7 @@ static int insert_block_group_item(struct btrfs_trans_handle *trans, ...@@ -2276,7 +2273,7 @@ static int insert_block_group_item(struct btrfs_trans_handle *trans,
{ {
struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_block_group_item bgi; struct btrfs_block_group_item bgi;
struct btrfs_root *root; struct btrfs_root *root = btrfs_block_group_root(fs_info);
struct btrfs_key key; struct btrfs_key key;
spin_lock(&block_group->lock); spin_lock(&block_group->lock);
...@@ -2289,7 +2286,6 @@ static int insert_block_group_item(struct btrfs_trans_handle *trans, ...@@ -2289,7 +2286,6 @@ static int insert_block_group_item(struct btrfs_trans_handle *trans,
key.offset = block_group->length; key.offset = block_group->length;
spin_unlock(&block_group->lock); spin_unlock(&block_group->lock);
root = fs_info->extent_root;
return btrfs_insert_item(trans, root, &key, &bgi, sizeof(bgi)); return btrfs_insert_item(trans, root, &key, &bgi, sizeof(bgi));
} }
...@@ -2543,12 +2539,13 @@ int btrfs_inc_block_group_ro(struct btrfs_block_group *cache, ...@@ -2543,12 +2539,13 @@ int btrfs_inc_block_group_ro(struct btrfs_block_group *cache,
{ {
struct btrfs_fs_info *fs_info = cache->fs_info; struct btrfs_fs_info *fs_info = cache->fs_info;
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
struct btrfs_root *root = btrfs_block_group_root(fs_info);
u64 alloc_flags; u64 alloc_flags;
int ret; int ret;
bool dirty_bg_running; bool dirty_bg_running;
do { do {
trans = btrfs_join_transaction(fs_info->extent_root); trans = btrfs_join_transaction(root);
if (IS_ERR(trans)) if (IS_ERR(trans))
return PTR_ERR(trans); return PTR_ERR(trans);
...@@ -2653,7 +2650,7 @@ static int update_block_group_item(struct btrfs_trans_handle *trans, ...@@ -2653,7 +2650,7 @@ static int update_block_group_item(struct btrfs_trans_handle *trans,
{ {
struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_fs_info *fs_info = trans->fs_info;
int ret; int ret;
struct btrfs_root *root = fs_info->extent_root; struct btrfs_root *root = btrfs_block_group_root(fs_info);
unsigned long bi; unsigned long bi;
struct extent_buffer *leaf; struct extent_buffer *leaf;
struct btrfs_block_group_item bgi; struct btrfs_block_group_item bgi;
...@@ -3790,7 +3787,7 @@ static void reserve_chunk_space(struct btrfs_trans_handle *trans, ...@@ -3790,7 +3787,7 @@ static void reserve_chunk_space(struct btrfs_trans_handle *trans,
} }
if (!ret) { if (!ret) {
ret = btrfs_block_rsv_add(fs_info->chunk_root, ret = btrfs_block_rsv_add(fs_info,
&fs_info->chunk_block_rsv, &fs_info->chunk_block_rsv,
bytes, BTRFS_RESERVE_NO_FLUSH); bytes, BTRFS_RESERVE_NO_FLUSH);
if (!ret) if (!ret)
...@@ -3911,9 +3908,7 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info) ...@@ -3911,9 +3908,7 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
list_del_init(&block_group->bg_list); list_del_init(&block_group->bg_list);
btrfs_put_block_group(block_group); btrfs_put_block_group(block_group);
} }
spin_unlock(&info->unused_bgs_lock);
spin_lock(&info->unused_bgs_lock);
while (!list_empty(&info->reclaim_bgs)) { while (!list_empty(&info->reclaim_bgs)) {
block_group = list_first_entry(&info->reclaim_bgs, block_group = list_first_entry(&info->reclaim_bgs,
struct btrfs_block_group, struct btrfs_block_group,
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "space-info.h" #include "space-info.h"
#include "transaction.h" #include "transaction.h"
#include "block-group.h" #include "block-group.h"
#include "disk-io.h"
/* /*
* HOW DO BLOCK RESERVES WORK * HOW DO BLOCK RESERVES WORK
...@@ -208,7 +209,7 @@ void btrfs_free_block_rsv(struct btrfs_fs_info *fs_info, ...@@ -208,7 +209,7 @@ void btrfs_free_block_rsv(struct btrfs_fs_info *fs_info,
kfree(rsv); kfree(rsv);
} }
int btrfs_block_rsv_add(struct btrfs_root *root, int btrfs_block_rsv_add(struct btrfs_fs_info *fs_info,
struct btrfs_block_rsv *block_rsv, u64 num_bytes, struct btrfs_block_rsv *block_rsv, u64 num_bytes,
enum btrfs_reserve_flush_enum flush) enum btrfs_reserve_flush_enum flush)
{ {
...@@ -217,7 +218,7 @@ int btrfs_block_rsv_add(struct btrfs_root *root, ...@@ -217,7 +218,7 @@ int btrfs_block_rsv_add(struct btrfs_root *root,
if (num_bytes == 0) if (num_bytes == 0)
return 0; return 0;
ret = btrfs_reserve_metadata_bytes(root, block_rsv, num_bytes, flush); ret = btrfs_reserve_metadata_bytes(fs_info, block_rsv, num_bytes, flush);
if (!ret) if (!ret)
btrfs_block_rsv_add_bytes(block_rsv, num_bytes, true); btrfs_block_rsv_add_bytes(block_rsv, num_bytes, true);
...@@ -241,7 +242,7 @@ int btrfs_block_rsv_check(struct btrfs_block_rsv *block_rsv, int min_factor) ...@@ -241,7 +242,7 @@ int btrfs_block_rsv_check(struct btrfs_block_rsv *block_rsv, int min_factor)
return ret; return ret;
} }
int btrfs_block_rsv_refill(struct btrfs_root *root, int btrfs_block_rsv_refill(struct btrfs_fs_info *fs_info,
struct btrfs_block_rsv *block_rsv, u64 min_reserved, struct btrfs_block_rsv *block_rsv, u64 min_reserved,
enum btrfs_reserve_flush_enum flush) enum btrfs_reserve_flush_enum flush)
{ {
...@@ -262,7 +263,7 @@ int btrfs_block_rsv_refill(struct btrfs_root *root, ...@@ -262,7 +263,7 @@ int btrfs_block_rsv_refill(struct btrfs_root *root,
if (!ret) if (!ret)
return 0; return 0;
ret = btrfs_reserve_metadata_bytes(root, block_rsv, num_bytes, flush); ret = btrfs_reserve_metadata_bytes(fs_info, block_rsv, num_bytes, flush);
if (!ret) { if (!ret) {
btrfs_block_rsv_add_bytes(block_rsv, num_bytes, false); btrfs_block_rsv_add_bytes(block_rsv, num_bytes, false);
return 0; return 0;
...@@ -351,23 +352,29 @@ void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info) ...@@ -351,23 +352,29 @@ void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info)
{ {
struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv; struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
struct btrfs_space_info *sinfo = block_rsv->space_info; struct btrfs_space_info *sinfo = block_rsv->space_info;
u64 num_bytes; struct btrfs_root *root, *tmp;
unsigned min_items; u64 num_bytes = btrfs_root_used(&fs_info->tree_root->root_item);
unsigned int min_items = 1;
/* /*
* The global block rsv is based on the size of the extent tree, the * The global block rsv is based on the size of the extent tree, the
* checksum tree and the root tree. If the fs is empty we want to set * checksum tree and the root tree. If the fs is empty we want to set
* it to a minimal amount for safety. * it to a minimal amount for safety.
*
* We also are going to need to modify the minimum of the tree root and
* any global roots we could touch.
*/ */
num_bytes = btrfs_root_used(&fs_info->extent_root->root_item) + read_lock(&fs_info->global_root_lock);
btrfs_root_used(&fs_info->csum_root->root_item) + rbtree_postorder_for_each_entry_safe(root, tmp, &fs_info->global_root_tree,
btrfs_root_used(&fs_info->tree_root->root_item); rb_node) {
if (root->root_key.objectid == BTRFS_EXTENT_TREE_OBJECTID ||
/* root->root_key.objectid == BTRFS_CSUM_TREE_OBJECTID ||
* We at a minimum are going to modify the csum root, the tree root, and root->root_key.objectid == BTRFS_FREE_SPACE_TREE_OBJECTID) {
* the extent root. num_bytes += btrfs_root_used(&root->root_item);
*/ min_items++;
min_items = 3; }
}
read_unlock(&fs_info->global_root_lock);
/* /*
* But we also want to reserve enough space so we can do the fallback * But we also want to reserve enough space so we can do the fallback
...@@ -412,6 +419,30 @@ void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info) ...@@ -412,6 +419,30 @@ void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info)
spin_unlock(&sinfo->lock); spin_unlock(&sinfo->lock);
} }
void btrfs_init_root_block_rsv(struct btrfs_root *root)
{
struct btrfs_fs_info *fs_info = root->fs_info;
switch (root->root_key.objectid) {
case BTRFS_CSUM_TREE_OBJECTID:
case BTRFS_EXTENT_TREE_OBJECTID:
case BTRFS_FREE_SPACE_TREE_OBJECTID:
root->block_rsv = &fs_info->delayed_refs_rsv;
break;
case BTRFS_ROOT_TREE_OBJECTID:
case BTRFS_DEV_TREE_OBJECTID:
case BTRFS_QUOTA_TREE_OBJECTID:
root->block_rsv = &fs_info->global_block_rsv;
break;
case BTRFS_CHUNK_TREE_OBJECTID:
root->block_rsv = &fs_info->chunk_block_rsv;
break;
default:
root->block_rsv = NULL;
break;
}
}
void btrfs_init_global_block_rsv(struct btrfs_fs_info *fs_info) void btrfs_init_global_block_rsv(struct btrfs_fs_info *fs_info)
{ {
struct btrfs_space_info *space_info; struct btrfs_space_info *space_info;
...@@ -426,22 +457,6 @@ void btrfs_init_global_block_rsv(struct btrfs_fs_info *fs_info) ...@@ -426,22 +457,6 @@ void btrfs_init_global_block_rsv(struct btrfs_fs_info *fs_info)
fs_info->delayed_block_rsv.space_info = space_info; fs_info->delayed_block_rsv.space_info = space_info;
fs_info->delayed_refs_rsv.space_info = space_info; fs_info->delayed_refs_rsv.space_info = space_info;
/*
* Our various recovery options can leave us with NULL roots, so check
* here and just bail before we go dereferencing NULLs everywhere.
*/
if (!fs_info->extent_root || !fs_info->csum_root ||
!fs_info->dev_root || !fs_info->chunk_root || !fs_info->tree_root)
return;
fs_info->extent_root->block_rsv = &fs_info->delayed_refs_rsv;
fs_info->csum_root->block_rsv = &fs_info->delayed_refs_rsv;
fs_info->dev_root->block_rsv = &fs_info->global_block_rsv;
fs_info->tree_root->block_rsv = &fs_info->global_block_rsv;
if (fs_info->quota_root)
fs_info->quota_root->block_rsv = &fs_info->global_block_rsv;
fs_info->chunk_root->block_rsv = &fs_info->chunk_block_rsv;
btrfs_update_global_block_rsv(fs_info); btrfs_update_global_block_rsv(fs_info);
} }
...@@ -467,8 +482,9 @@ static struct btrfs_block_rsv *get_block_rsv( ...@@ -467,8 +482,9 @@ static struct btrfs_block_rsv *get_block_rsv(
struct btrfs_block_rsv *block_rsv = NULL; struct btrfs_block_rsv *block_rsv = NULL;
if (test_bit(BTRFS_ROOT_SHAREABLE, &root->state) || if (test_bit(BTRFS_ROOT_SHAREABLE, &root->state) ||
(root == fs_info->csum_root && trans->adding_csums) || (root == fs_info->uuid_root) ||
(root == fs_info->uuid_root)) (trans->adding_csums &&
root->root_key.objectid == BTRFS_CSUM_TREE_OBJECTID))
block_rsv = trans->block_rsv; block_rsv = trans->block_rsv;
if (!block_rsv) if (!block_rsv)
...@@ -523,7 +539,7 @@ struct btrfs_block_rsv *btrfs_use_block_rsv(struct btrfs_trans_handle *trans, ...@@ -523,7 +539,7 @@ struct btrfs_block_rsv *btrfs_use_block_rsv(struct btrfs_trans_handle *trans,
block_rsv->type, ret); block_rsv->type, ret);
} }
try_reserve: try_reserve:
ret = btrfs_reserve_metadata_bytes(root, block_rsv, blocksize, ret = btrfs_reserve_metadata_bytes(fs_info, block_rsv, blocksize,
BTRFS_RESERVE_NO_FLUSH); BTRFS_RESERVE_NO_FLUSH);
if (!ret) if (!ret)
return block_rsv; return block_rsv;
......
...@@ -50,6 +50,7 @@ struct btrfs_block_rsv { ...@@ -50,6 +50,7 @@ struct btrfs_block_rsv {
}; };
void btrfs_init_block_rsv(struct btrfs_block_rsv *rsv, unsigned short type); void btrfs_init_block_rsv(struct btrfs_block_rsv *rsv, unsigned short type);
void btrfs_init_root_block_rsv(struct btrfs_root *root);
struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_fs_info *fs_info, struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_fs_info *fs_info,
unsigned short type); unsigned short type);
void btrfs_init_metadata_block_rsv(struct btrfs_fs_info *fs_info, void btrfs_init_metadata_block_rsv(struct btrfs_fs_info *fs_info,
...@@ -57,11 +58,11 @@ void btrfs_init_metadata_block_rsv(struct btrfs_fs_info *fs_info, ...@@ -57,11 +58,11 @@ void btrfs_init_metadata_block_rsv(struct btrfs_fs_info *fs_info,
unsigned short type); unsigned short type);
void btrfs_free_block_rsv(struct btrfs_fs_info *fs_info, void btrfs_free_block_rsv(struct btrfs_fs_info *fs_info,
struct btrfs_block_rsv *rsv); struct btrfs_block_rsv *rsv);
int btrfs_block_rsv_add(struct btrfs_root *root, int btrfs_block_rsv_add(struct btrfs_fs_info *fs_info,
struct btrfs_block_rsv *block_rsv, u64 num_bytes, struct btrfs_block_rsv *block_rsv, u64 num_bytes,
enum btrfs_reserve_flush_enum flush); enum btrfs_reserve_flush_enum flush);
int btrfs_block_rsv_check(struct btrfs_block_rsv *block_rsv, int min_factor); int btrfs_block_rsv_check(struct btrfs_block_rsv *block_rsv, int min_factor);
int btrfs_block_rsv_refill(struct btrfs_root *root, int btrfs_block_rsv_refill(struct btrfs_fs_info *fs_info,
struct btrfs_block_rsv *block_rsv, u64 min_reserved, struct btrfs_block_rsv *block_rsv, u64 min_reserved,
enum btrfs_reserve_flush_enum flush); enum btrfs_reserve_flush_enum flush);
int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv, int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv,
......
...@@ -138,19 +138,11 @@ struct btrfs_inode { ...@@ -138,19 +138,11 @@ struct btrfs_inode {
/* a local copy of root's last_log_commit */ /* a local copy of root's last_log_commit */
int last_log_commit; int last_log_commit;
union { /*
/* * Total number of bytes pending delalloc, used by stat to calculate the
* Total number of bytes pending delalloc, used by stat to * real block usage of the file. This is used only for files.
* calculate the real block usage of the file. This is used */
* only for files. u64 delalloc_bytes;
*/
u64 delalloc_bytes;
/*
* The offset of the last dir item key that was logged.
* This is used only for directories.
*/
u64 last_dir_item_offset;
};
union { union {
/* /*
......
...@@ -96,10 +96,10 @@ static int compression_compress_pages(int type, struct list_head *ws, ...@@ -96,10 +96,10 @@ static int compression_compress_pages(int type, struct list_head *ws,
} }
} }
static int compression_decompress_bio(int type, struct list_head *ws, static int compression_decompress_bio(struct list_head *ws,
struct compressed_bio *cb) struct compressed_bio *cb)
{ {
switch (type) { switch (cb->compress_type) {
case BTRFS_COMPRESS_ZLIB: return zlib_decompress_bio(ws, cb); case BTRFS_COMPRESS_ZLIB: return zlib_decompress_bio(ws, cb);
case BTRFS_COMPRESS_LZO: return lzo_decompress_bio(ws, cb); case BTRFS_COMPRESS_LZO: return lzo_decompress_bio(ws, cb);
case BTRFS_COMPRESS_ZSTD: return zstd_decompress_bio(ws, cb); case BTRFS_COMPRESS_ZSTD: return zstd_decompress_bio(ws, cb);
...@@ -157,7 +157,8 @@ static int check_compressed_csum(struct btrfs_inode *inode, struct bio *bio, ...@@ -157,7 +157,8 @@ static int check_compressed_csum(struct btrfs_inode *inode, struct bio *bio,
struct compressed_bio *cb = bio->bi_private; struct compressed_bio *cb = bio->bi_private;
u8 *cb_sum = cb->sums; u8 *cb_sum = cb->sums;
if (!fs_info->csum_root || (inode->flags & BTRFS_INODE_NODATASUM)) if ((inode->flags & BTRFS_INODE_NODATASUM) ||
test_bit(BTRFS_FS_STATE_NO_CSUMS, &fs_info->fs_state))
return 0; return 0;
shash->tfm = fs_info->csum_shash; shash->tfm = fs_info->csum_shash;
...@@ -1359,7 +1360,7 @@ static int btrfs_decompress_bio(struct compressed_bio *cb) ...@@ -1359,7 +1360,7 @@ static int btrfs_decompress_bio(struct compressed_bio *cb)
int type = cb->compress_type; int type = cb->compress_type;
workspace = get_workspace(type, 0); workspace = get_workspace(type, 0);
ret = compression_decompress_bio(type, workspace, cb); ret = compression_decompress_bio(workspace, cb);
put_workspace(type, workspace); put_workspace(type, workspace);
return ret; return ret;
......
此差异已折叠。
...@@ -143,6 +143,8 @@ enum { ...@@ -143,6 +143,8 @@ enum {
BTRFS_FS_STATE_DEV_REPLACING, BTRFS_FS_STATE_DEV_REPLACING,
/* The btrfs_fs_info created for self-tests */ /* The btrfs_fs_info created for self-tests */
BTRFS_FS_STATE_DUMMY_FS_INFO, BTRFS_FS_STATE_DUMMY_FS_INFO,
BTRFS_FS_STATE_NO_CSUMS,
}; };
#define BTRFS_BACKREF_REV_MAX 256 #define BTRFS_BACKREF_REV_MAX 256
...@@ -511,11 +513,6 @@ struct btrfs_discard_ctl { ...@@ -511,11 +513,6 @@ struct btrfs_discard_ctl {
atomic64_t discard_bytes_saved; atomic64_t discard_bytes_saved;
}; };
enum btrfs_orphan_cleanup_state {
ORPHAN_CLEANUP_STARTED = 1,
ORPHAN_CLEANUP_DONE = 2,
};
void btrfs_init_async_reclaim_work(struct btrfs_fs_info *fs_info); void btrfs_init_async_reclaim_work(struct btrfs_fs_info *fs_info);
/* fs_info */ /* fs_info */
...@@ -553,7 +550,6 @@ struct btrfs_swapfile_pin { ...@@ -553,7 +550,6 @@ struct btrfs_swapfile_pin {
bool btrfs_pinned_by_swapfile(struct btrfs_fs_info *fs_info, void *ptr); bool btrfs_pinned_by_swapfile(struct btrfs_fs_info *fs_info, void *ptr);
enum { enum {
BTRFS_FS_BARRIER,
BTRFS_FS_CLOSING_START, BTRFS_FS_CLOSING_START,
BTRFS_FS_CLOSING_DONE, BTRFS_FS_CLOSING_DONE,
BTRFS_FS_LOG_RECOVERING, BTRFS_FS_LOG_RECOVERING,
...@@ -576,7 +572,6 @@ enum { ...@@ -576,7 +572,6 @@ enum {
/* /*
* Indicate that relocation of a chunk has started, it's set per chunk * Indicate that relocation of a chunk has started, it's set per chunk
* and is toggled between chunks. * and is toggled between chunks.
* Set, tested and cleared while holding fs_info::send_reloc_lock.
*/ */
BTRFS_FS_RELOC_RUNNING, BTRFS_FS_RELOC_RUNNING,
...@@ -601,6 +596,9 @@ enum { ...@@ -601,6 +596,9 @@ enum {
/* Indicate whether there are any tree modification log users */ /* Indicate whether there are any tree modification log users */
BTRFS_FS_TREE_MOD_LOG_USERS, BTRFS_FS_TREE_MOD_LOG_USERS,
/* Indicate that we want the transaction kthread to commit right now. */
BTRFS_FS_COMMIT_TRANS,
#if BITS_PER_LONG == 32 #if BITS_PER_LONG == 32
/* Indicate if we have error/warn message printed on 32bit systems */ /* Indicate if we have error/warn message printed on 32bit systems */
BTRFS_FS_32BIT_ERROR, BTRFS_FS_32BIT_ERROR,
...@@ -613,6 +611,7 @@ enum { ...@@ -613,6 +611,7 @@ enum {
*/ */
enum btrfs_exclusive_operation { enum btrfs_exclusive_operation {
BTRFS_EXCLOP_NONE, BTRFS_EXCLOP_NONE,
BTRFS_EXCLOP_BALANCE_PAUSED,
BTRFS_EXCLOP_BALANCE, BTRFS_EXCLOP_BALANCE,
BTRFS_EXCLOP_DEV_ADD, BTRFS_EXCLOP_DEV_ADD,
BTRFS_EXCLOP_DEV_REMOVE, BTRFS_EXCLOP_DEV_REMOVE,
...@@ -624,20 +623,21 @@ enum btrfs_exclusive_operation { ...@@ -624,20 +623,21 @@ enum btrfs_exclusive_operation {
struct btrfs_fs_info { struct btrfs_fs_info {
u8 chunk_tree_uuid[BTRFS_UUID_SIZE]; u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
unsigned long flags; unsigned long flags;
struct btrfs_root *extent_root;
struct btrfs_root *tree_root; struct btrfs_root *tree_root;
struct btrfs_root *chunk_root; struct btrfs_root *chunk_root;
struct btrfs_root *dev_root; struct btrfs_root *dev_root;
struct btrfs_root *fs_root; struct btrfs_root *fs_root;
struct btrfs_root *csum_root;
struct btrfs_root *quota_root; struct btrfs_root *quota_root;
struct btrfs_root *uuid_root; struct btrfs_root *uuid_root;
struct btrfs_root *free_space_root;
struct btrfs_root *data_reloc_root; struct btrfs_root *data_reloc_root;
/* the log root tree is a directory of all the other log roots */ /* the log root tree is a directory of all the other log roots */
struct btrfs_root *log_root_tree; struct btrfs_root *log_root_tree;
/* The tree that holds the global roots (csum, extent, etc) */
rwlock_t global_root_lock;
struct rb_root global_root_tree;
spinlock_t fs_roots_radix_lock; spinlock_t fs_roots_radix_lock;
struct radix_tree_root fs_roots_radix; struct radix_tree_root fs_roots_radix;
...@@ -673,6 +673,12 @@ struct btrfs_fs_info { ...@@ -673,6 +673,12 @@ struct btrfs_fs_info {
u64 generation; u64 generation;
u64 last_trans_committed; u64 last_trans_committed;
/*
* Generation of the last transaction used for block group relocation
* since the filesystem was last mounted (or 0 if none happened yet).
* Must be written and read while holding btrfs_fs_info::commit_root_sem.
*/
u64 last_reloc_trans;
u64 avg_delayed_ref_runtime; u64 avg_delayed_ref_runtime;
/* /*
...@@ -815,7 +821,6 @@ struct btrfs_fs_info { ...@@ -815,7 +821,6 @@ struct btrfs_fs_info {
struct btrfs_workqueue *endio_write_workers; struct btrfs_workqueue *endio_write_workers;
struct btrfs_workqueue *endio_freespace_worker; struct btrfs_workqueue *endio_freespace_worker;
struct btrfs_workqueue *caching_workers; struct btrfs_workqueue *caching_workers;
struct btrfs_workqueue *readahead_workers;
/* /*
* fixup workers take dirty pages that didn't properly go through * fixup workers take dirty pages that didn't properly go through
...@@ -952,13 +957,6 @@ struct btrfs_fs_info { ...@@ -952,13 +957,6 @@ struct btrfs_fs_info {
struct btrfs_delayed_root *delayed_root; struct btrfs_delayed_root *delayed_root;
/* readahead tree */
spinlock_t reada_lock;
struct radix_tree_root reada_tree;
/* readahead works cnt */
atomic_t reada_works_cnt;
/* Extent buffer radix tree */ /* Extent buffer radix tree */
spinlock_t buffer_lock; spinlock_t buffer_lock;
/* Entries are eb->start / sectorsize */ /* Entries are eb->start / sectorsize */
...@@ -1003,13 +1001,6 @@ struct btrfs_fs_info { ...@@ -1003,13 +1001,6 @@ struct btrfs_fs_info {
struct crypto_shash *csum_shash; struct crypto_shash *csum_shash;
spinlock_t send_reloc_lock;
/*
* Number of send operations in progress.
* Updated while holding fs_info::send_reloc_lock.
*/
int send_in_progress;
/* Type of exclusive operation running, protected by super_lock */ /* Type of exclusive operation running, protected by super_lock */
enum btrfs_exclusive_operation exclusive_operation; enum btrfs_exclusive_operation exclusive_operation;
...@@ -1110,6 +1101,8 @@ enum { ...@@ -1110,6 +1101,8 @@ enum {
BTRFS_ROOT_HAS_LOG_TREE, BTRFS_ROOT_HAS_LOG_TREE,
/* Qgroup flushing is in progress */ /* Qgroup flushing is in progress */
BTRFS_ROOT_QGROUP_FLUSHING, BTRFS_ROOT_QGROUP_FLUSHING,
/* We started the orphan cleanup for this root. */
BTRFS_ROOT_ORPHAN_CLEANUP,
}; };
/* /*
...@@ -1128,6 +1121,8 @@ struct btrfs_qgroup_swapped_blocks { ...@@ -1128,6 +1121,8 @@ struct btrfs_qgroup_swapped_blocks {
* and for the extent tree extent_root root. * and for the extent tree extent_root root.
*/ */
struct btrfs_root { struct btrfs_root {
struct rb_node rb_node;
struct extent_buffer *node; struct extent_buffer *node;
struct extent_buffer *commit_root; struct extent_buffer *commit_root;
...@@ -1178,8 +1173,6 @@ struct btrfs_root { ...@@ -1178,8 +1173,6 @@ struct btrfs_root {
spinlock_t log_extents_lock[2]; spinlock_t log_extents_lock[2];
struct list_head logged_list[2]; struct list_head logged_list[2];
int orphan_cleanup_state;
spinlock_t inode_lock; spinlock_t inode_lock;
/* red-black tree that keeps track of in-memory inodes */ /* red-black tree that keeps track of in-memory inodes */
struct rb_root inode_tree; struct rb_root inode_tree;
...@@ -1960,8 +1953,8 @@ static inline void btrfs_set_node_key(const struct extent_buffer *eb, ...@@ -1960,8 +1953,8 @@ static inline void btrfs_set_node_key(const struct extent_buffer *eb,
} }
/* struct btrfs_item */ /* struct btrfs_item */
BTRFS_SETGET_FUNCS(item_offset, struct btrfs_item, offset, 32); BTRFS_SETGET_FUNCS(raw_item_offset, struct btrfs_item, offset, 32);
BTRFS_SETGET_FUNCS(item_size, struct btrfs_item, size, 32); BTRFS_SETGET_FUNCS(raw_item_size, struct btrfs_item, size, 32);
BTRFS_SETGET_STACK_FUNCS(stack_item_offset, struct btrfs_item, offset, 32); BTRFS_SETGET_STACK_FUNCS(stack_item_offset, struct btrfs_item, offset, 32);
BTRFS_SETGET_STACK_FUNCS(stack_item_size, struct btrfs_item, size, 32); BTRFS_SETGET_STACK_FUNCS(stack_item_size, struct btrfs_item, size, 32);
...@@ -1976,25 +1969,36 @@ static inline struct btrfs_item *btrfs_item_nr(int nr) ...@@ -1976,25 +1969,36 @@ static inline struct btrfs_item *btrfs_item_nr(int nr)
return (struct btrfs_item *)btrfs_item_nr_offset(nr); return (struct btrfs_item *)btrfs_item_nr_offset(nr);
} }
static inline u32 btrfs_item_end(const struct extent_buffer *eb, #define BTRFS_ITEM_SETGET_FUNCS(member) \
struct btrfs_item *item) static inline u32 btrfs_item_##member(const struct extent_buffer *eb, \
{ int slot) \
return btrfs_item_offset(eb, item) + btrfs_item_size(eb, item); { \
return btrfs_raw_item_##member(eb, btrfs_item_nr(slot)); \
} \
static inline void btrfs_set_item_##member(const struct extent_buffer *eb, \
int slot, u32 val) \
{ \
btrfs_set_raw_item_##member(eb, btrfs_item_nr(slot), val); \
} \
static inline u32 btrfs_token_item_##member(struct btrfs_map_token *token, \
int slot) \
{ \
struct btrfs_item *item = btrfs_item_nr(slot); \
return btrfs_token_raw_item_##member(token, item); \
} \
static inline void btrfs_set_token_item_##member(struct btrfs_map_token *token, \
int slot, u32 val) \
{ \
struct btrfs_item *item = btrfs_item_nr(slot); \
btrfs_set_token_raw_item_##member(token, item, val); \
} }
static inline u32 btrfs_item_end_nr(const struct extent_buffer *eb, int nr) BTRFS_ITEM_SETGET_FUNCS(offset)
{ BTRFS_ITEM_SETGET_FUNCS(size);
return btrfs_item_end(eb, btrfs_item_nr(nr));
}
static inline u32 btrfs_item_offset_nr(const struct extent_buffer *eb, int nr)
{
return btrfs_item_offset(eb, btrfs_item_nr(nr));
}
static inline u32 btrfs_item_size_nr(const struct extent_buffer *eb, int nr) static inline u32 btrfs_item_data_end(const struct extent_buffer *eb, int nr)
{ {
return btrfs_item_size(eb, btrfs_item_nr(nr)); return btrfs_item_offset(eb, nr) + btrfs_item_size(eb, nr);
} }
static inline void btrfs_item_key(const struct extent_buffer *eb, static inline void btrfs_item_key(const struct extent_buffer *eb,
...@@ -2463,7 +2467,7 @@ static inline unsigned int leaf_data_end(const struct extent_buffer *leaf) ...@@ -2463,7 +2467,7 @@ static inline unsigned int leaf_data_end(const struct extent_buffer *leaf)
if (nr == 0) if (nr == 0)
return BTRFS_LEAF_DATA_SIZE(leaf->fs_info); return BTRFS_LEAF_DATA_SIZE(leaf->fs_info);
return btrfs_item_offset_nr(leaf, nr - 1); return btrfs_item_offset(leaf, nr - 1);
} }
/* struct btrfs_file_extent_item */ /* struct btrfs_file_extent_item */
...@@ -2522,9 +2526,9 @@ BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item, ...@@ -2522,9 +2526,9 @@ BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
*/ */
static inline u32 btrfs_file_extent_inline_item_len( static inline u32 btrfs_file_extent_inline_item_len(
const struct extent_buffer *eb, const struct extent_buffer *eb,
struct btrfs_item *e) int nr)
{ {
return btrfs_item_size(eb, e) - BTRFS_FILE_EXTENT_INLINE_DATA_START; return btrfs_item_size(eb, nr) - BTRFS_FILE_EXTENT_INLINE_DATA_START;
} }
/* btrfs_qgroup_status_item */ /* btrfs_qgroup_status_item */
...@@ -2616,11 +2620,11 @@ BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cursor_right, ...@@ -2616,11 +2620,11 @@ BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cursor_right,
/* helper function to cast into the data area of the leaf. */ /* helper function to cast into the data area of the leaf. */
#define btrfs_item_ptr(leaf, slot, type) \ #define btrfs_item_ptr(leaf, slot, type) \
((type *)(BTRFS_LEAF_DATA_OFFSET + \ ((type *)(BTRFS_LEAF_DATA_OFFSET + \
btrfs_item_offset_nr(leaf, slot))) btrfs_item_offset(leaf, slot)))
#define btrfs_item_ptr_offset(leaf, slot) \ #define btrfs_item_ptr_offset(leaf, slot) \
((unsigned long)(BTRFS_LEAF_DATA_OFFSET + \ ((unsigned long)(BTRFS_LEAF_DATA_OFFSET + \
btrfs_item_offset_nr(leaf, slot))) btrfs_item_offset(leaf, slot)))
static inline u32 btrfs_crc32c(u32 crc, const void *address, unsigned length) static inline u32 btrfs_crc32c(u32 crc, const void *address, unsigned length)
{ {
...@@ -3119,36 +3123,6 @@ int btrfs_del_orphan_item(struct btrfs_trans_handle *trans, ...@@ -3119,36 +3123,6 @@ int btrfs_del_orphan_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 offset); struct btrfs_root *root, u64 offset);
int btrfs_find_orphan_item(struct btrfs_root *root, u64 offset); int btrfs_find_orphan_item(struct btrfs_root *root, u64 offset);
/* inode-item.c */
int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
const char *name, int name_len,
u64 inode_objectid, u64 ref_objectid, u64 index);
int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
const char *name, int name_len,
u64 inode_objectid, u64 ref_objectid, u64 *index);
int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path, u64 objectid);
int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_path *path,
struct btrfs_key *location, int mod);
struct btrfs_inode_extref *
btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
const char *name, int name_len,
u64 inode_objectid, u64 ref_objectid, int ins_len,
int cow);
struct btrfs_inode_ref *btrfs_find_name_in_backref(struct extent_buffer *leaf,
int slot, const char *name,
int name_len);
struct btrfs_inode_extref *btrfs_find_name_in_ext_backref(
struct extent_buffer *leaf, int slot, u64 ref_objectid,
const char *name, int name_len);
/* file-item.c */ /* file-item.c */
struct btrfs_dio_private; struct btrfs_dio_private;
int btrfs_del_csums(struct btrfs_trans_handle *trans, int btrfs_del_csums(struct btrfs_trans_handle *trans,
...@@ -3208,10 +3182,6 @@ int btrfs_add_link(struct btrfs_trans_handle *trans, ...@@ -3208,10 +3182,6 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry); int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry);
int btrfs_truncate_block(struct btrfs_inode *inode, loff_t from, loff_t len, int btrfs_truncate_block(struct btrfs_inode *inode, loff_t from, loff_t len,
int front); int front);
int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_inode *inode, u64 new_size,
u32 min_type, u64 *extents_found);
int btrfs_start_delalloc_snapshot(struct btrfs_root *root, bool in_reclaim_context); int btrfs_start_delalloc_snapshot(struct btrfs_root *root, bool in_reclaim_context);
int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, long nr, int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, long nr,
...@@ -3310,6 +3280,9 @@ bool btrfs_exclop_start_try_lock(struct btrfs_fs_info *fs_info, ...@@ -3310,6 +3280,9 @@ bool btrfs_exclop_start_try_lock(struct btrfs_fs_info *fs_info,
enum btrfs_exclusive_operation type); enum btrfs_exclusive_operation type);
void btrfs_exclop_start_unlock(struct btrfs_fs_info *fs_info); void btrfs_exclop_start_unlock(struct btrfs_fs_info *fs_info);
void btrfs_exclop_finish(struct btrfs_fs_info *fs_info); void btrfs_exclop_finish(struct btrfs_fs_info *fs_info);
void btrfs_exclop_balance(struct btrfs_fs_info *fs_info,
enum btrfs_exclusive_operation op);
/* file.c */ /* file.c */
int __init btrfs_auto_defrag_init(void); int __init btrfs_auto_defrag_init(void);
...@@ -3826,23 +3799,6 @@ static inline void btrfs_bio_counter_dec(struct btrfs_fs_info *fs_info) ...@@ -3826,23 +3799,6 @@ static inline void btrfs_bio_counter_dec(struct btrfs_fs_info *fs_info)
btrfs_bio_counter_sub(fs_info, 1); btrfs_bio_counter_sub(fs_info, 1);
} }
/* reada.c */
struct reada_control {
struct btrfs_fs_info *fs_info; /* tree to prefetch */
struct btrfs_key key_start;
struct btrfs_key key_end; /* exclusive */
atomic_t elems;
struct kref refcnt;
wait_queue_head_t wait;
};
struct reada_control *btrfs_reada_add(struct btrfs_root *root,
struct btrfs_key *start, struct btrfs_key *end);
int btrfs_reada_wait(void *handle);
void btrfs_reada_detach(void *handle);
int btree_readahead_hook(struct extent_buffer *eb, int err);
void btrfs_reada_remove_dev(struct btrfs_device *dev);
void btrfs_reada_undo_remove_dev(struct btrfs_device *dev);
static inline int is_fstree(u64 rootid) static inline int is_fstree(u64 rootid)
{ {
if (rootid == BTRFS_FS_TREE_OBJECTID || if (rootid == BTRFS_FS_TREE_OBJECTID ||
......
...@@ -334,7 +334,7 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes) ...@@ -334,7 +334,7 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes)
ret = btrfs_qgroup_reserve_meta_prealloc(root, qgroup_reserve, true); ret = btrfs_qgroup_reserve_meta_prealloc(root, qgroup_reserve, true);
if (ret) if (ret)
return ret; return ret;
ret = btrfs_reserve_metadata_bytes(root, block_rsv, meta_reserve, flush); ret = btrfs_reserve_metadata_bytes(fs_info, block_rsv, meta_reserve, flush);
if (ret) { if (ret) {
btrfs_qgroup_free_meta_prealloc(root, qgroup_reserve); btrfs_qgroup_free_meta_prealloc(root, qgroup_reserve);
return ret; return ret;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "ctree.h" #include "ctree.h"
#include "qgroup.h" #include "qgroup.h"
#include "locking.h" #include "locking.h"
#include "inode-item.h"
#define BTRFS_DELAYED_WRITEBACK 512 #define BTRFS_DELAYED_WRITEBACK 512
#define BTRFS_DELAYED_BACKGROUND 128 #define BTRFS_DELAYED_BACKGROUND 128
...@@ -629,7 +630,7 @@ static int btrfs_delayed_inode_reserve_metadata( ...@@ -629,7 +630,7 @@ static int btrfs_delayed_inode_reserve_metadata(
BTRFS_QGROUP_RSV_META_PREALLOC, true); BTRFS_QGROUP_RSV_META_PREALLOC, true);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = btrfs_block_rsv_add(root, dst_rsv, num_bytes, ret = btrfs_block_rsv_add(fs_info, dst_rsv, num_bytes,
BTRFS_RESERVE_NO_FLUSH); BTRFS_RESERVE_NO_FLUSH);
/* NO_FLUSH could only fail with -ENOSPC */ /* NO_FLUSH could only fail with -ENOSPC */
ASSERT(ret == 0 || ret == -ENOSPC); ASSERT(ret == 0 || ret == -ENOSPC);
......
...@@ -84,6 +84,17 @@ void btrfs_delayed_refs_rsv_release(struct btrfs_fs_info *fs_info, int nr) ...@@ -84,6 +84,17 @@ void btrfs_delayed_refs_rsv_release(struct btrfs_fs_info *fs_info, int nr)
u64 num_bytes = btrfs_calc_insert_metadata_size(fs_info, nr); u64 num_bytes = btrfs_calc_insert_metadata_size(fs_info, nr);
u64 released = 0; u64 released = 0;
/*
* We have to check the mount option here because we could be enabling
* the free space tree for the first time and don't have the compat_ro
* option set yet.
*
* We need extra reservations if we have the free space tree because
* we'll have to modify that tree as well.
*/
if (btrfs_test_opt(fs_info, FREE_SPACE_TREE))
num_bytes *= 2;
released = btrfs_block_rsv_release(fs_info, block_rsv, num_bytes, NULL); released = btrfs_block_rsv_release(fs_info, block_rsv, num_bytes, NULL);
if (released) if (released)
trace_btrfs_space_reservation(fs_info, "delayed_refs_rsv", trace_btrfs_space_reservation(fs_info, "delayed_refs_rsv",
...@@ -108,6 +119,17 @@ void btrfs_update_delayed_refs_rsv(struct btrfs_trans_handle *trans) ...@@ -108,6 +119,17 @@ void btrfs_update_delayed_refs_rsv(struct btrfs_trans_handle *trans)
num_bytes = btrfs_calc_insert_metadata_size(fs_info, num_bytes = btrfs_calc_insert_metadata_size(fs_info,
trans->delayed_ref_updates); trans->delayed_ref_updates);
/*
* We have to check the mount option here because we could be enabling
* the free space tree for the first time and don't have the compat_ro
* option set yet.
*
* We need extra reservations if we have the free space tree because
* we'll have to modify that tree as well.
*/
if (btrfs_test_opt(fs_info, FREE_SPACE_TREE))
num_bytes *= 2;
spin_lock(&delayed_rsv->lock); spin_lock(&delayed_rsv->lock);
delayed_rsv->size += num_bytes; delayed_rsv->size += num_bytes;
delayed_rsv->full = 0; delayed_rsv->full = 0;
...@@ -191,8 +213,7 @@ int btrfs_delayed_refs_rsv_refill(struct btrfs_fs_info *fs_info, ...@@ -191,8 +213,7 @@ int btrfs_delayed_refs_rsv_refill(struct btrfs_fs_info *fs_info,
if (!num_bytes) if (!num_bytes)
return 0; return 0;
ret = btrfs_reserve_metadata_bytes(fs_info->extent_root, block_rsv, ret = btrfs_reserve_metadata_bytes(fs_info, block_rsv, num_bytes, flush);
num_bytes, flush);
if (ret) if (ret)
return ret; return ret;
btrfs_block_rsv_add_bytes(block_rsv, num_bytes, 0); btrfs_block_rsv_add_bytes(block_rsv, num_bytes, 0);
......
...@@ -128,7 +128,7 @@ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info) ...@@ -128,7 +128,7 @@ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info)
} }
slot = path->slots[0]; slot = path->slots[0];
eb = path->nodes[0]; eb = path->nodes[0];
item_size = btrfs_item_size_nr(eb, slot); item_size = btrfs_item_size(eb, slot);
ptr = btrfs_item_ptr(eb, slot, struct btrfs_dev_replace_item); ptr = btrfs_item_ptr(eb, slot, struct btrfs_dev_replace_item);
if (item_size != sizeof(struct btrfs_dev_replace_item)) { if (item_size != sizeof(struct btrfs_dev_replace_item)) {
...@@ -322,7 +322,7 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info, ...@@ -322,7 +322,7 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
set_blocksize(device->bdev, BTRFS_BDEV_BLOCKSIZE); set_blocksize(device->bdev, BTRFS_BDEV_BLOCKSIZE);
device->fs_devices = fs_info->fs_devices; device->fs_devices = fs_info->fs_devices;
ret = btrfs_get_dev_zone_info(device); ret = btrfs_get_dev_zone_info(device, false);
if (ret) if (ret)
goto error; goto error;
...@@ -381,7 +381,7 @@ int btrfs_run_dev_replace(struct btrfs_trans_handle *trans) ...@@ -381,7 +381,7 @@ int btrfs_run_dev_replace(struct btrfs_trans_handle *trans)
} }
if (ret == 0 && if (ret == 0 &&
btrfs_item_size_nr(path->nodes[0], path->slots[0]) < sizeof(*ptr)) { btrfs_item_size(path->nodes[0], path->slots[0]) < sizeof(*ptr)) {
/* /*
* need to delete old one and insert a new one. * need to delete old one and insert a new one.
* Since no attempt is made to recover any old state, if the * Since no attempt is made to recover any old state, if the
...@@ -906,9 +906,6 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, ...@@ -906,9 +906,6 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
} }
btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1); btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1);
if (!scrub_ret)
btrfs_reada_remove_dev(src_device);
/* /*
* We have to use this loop approach because at this point src_device * We have to use this loop approach because at this point src_device
* has to be available for transaction commit to complete, yet new * has to be available for transaction commit to complete, yet new
...@@ -917,7 +914,6 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, ...@@ -917,7 +914,6 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
while (1) { while (1) {
trans = btrfs_start_transaction(root, 0); trans = btrfs_start_transaction(root, 0);
if (IS_ERR(trans)) { if (IS_ERR(trans)) {
btrfs_reada_undo_remove_dev(src_device);
mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
return PTR_ERR(trans); return PTR_ERR(trans);
} }
...@@ -968,7 +964,6 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, ...@@ -968,7 +964,6 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
up_write(&dev_replace->rwsem); up_write(&dev_replace->rwsem);
mutex_unlock(&fs_info->chunk_mutex); mutex_unlock(&fs_info->chunk_mutex);
mutex_unlock(&fs_info->fs_devices->device_list_mutex); mutex_unlock(&fs_info->fs_devices->device_list_mutex);
btrfs_reada_undo_remove_dev(src_device);
btrfs_rm_dev_replace_blocked(fs_info); btrfs_rm_dev_replace_blocked(fs_info);
if (tgt_device) if (tgt_device)
btrfs_destroy_dev_replace_tgtdev(tgt_device); btrfs_destroy_dev_replace_tgtdev(tgt_device);
......
...@@ -27,7 +27,6 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle ...@@ -27,7 +27,6 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_fs_info *fs_info = root->fs_info;
int ret; int ret;
char *ptr; char *ptr;
struct btrfs_item *item;
struct extent_buffer *leaf; struct extent_buffer *leaf;
ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size); ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
...@@ -41,10 +40,9 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle ...@@ -41,10 +40,9 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
return ERR_PTR(ret); return ERR_PTR(ret);
WARN_ON(ret > 0); WARN_ON(ret > 0);
leaf = path->nodes[0]; leaf = path->nodes[0];
item = btrfs_item_nr(path->slots[0]);
ptr = btrfs_item_ptr(leaf, path->slots[0], char); ptr = btrfs_item_ptr(leaf, path->slots[0], char);
BUG_ON(data_size > btrfs_item_size(leaf, item)); ASSERT(data_size <= btrfs_item_size(leaf, path->slots[0]));
ptr += btrfs_item_size(leaf, item) - data_size; ptr += btrfs_item_size(leaf, path->slots[0]) - data_size;
return (struct btrfs_dir_item *)ptr; return (struct btrfs_dir_item *)ptr;
} }
...@@ -271,7 +269,7 @@ int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir, ...@@ -271,7 +269,7 @@ int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
data_size = sizeof(*di) + name_len; data_size = sizeof(*di) + name_len;
leaf = path->nodes[0]; leaf = path->nodes[0];
slot = path->slots[0]; slot = path->slots[0];
if (data_size + btrfs_item_size_nr(leaf, slot) + if (data_size + btrfs_item_size(leaf, slot) +
sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root->fs_info)) { sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root->fs_info)) {
ret = -EOVERFLOW; ret = -EOVERFLOW;
} else { } else {
...@@ -409,7 +407,7 @@ struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info, ...@@ -409,7 +407,7 @@ struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info,
leaf = path->nodes[0]; leaf = path->nodes[0];
dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item); dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
total_len = btrfs_item_size_nr(leaf, path->slots[0]); total_len = btrfs_item_size(leaf, path->slots[0]);
while (cur < total_len) { while (cur < total_len) {
this_len = sizeof(*dir_item) + this_len = sizeof(*dir_item) +
btrfs_dir_name_len(leaf, dir_item) + btrfs_dir_name_len(leaf, dir_item) +
...@@ -445,7 +443,7 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, ...@@ -445,7 +443,7 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
leaf = path->nodes[0]; leaf = path->nodes[0];
sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) + sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) +
btrfs_dir_data_len(leaf, di); btrfs_dir_data_len(leaf, di);
item_len = btrfs_item_size_nr(leaf, path->slots[0]); item_len = btrfs_item_size(leaf, path->slots[0]);
if (sub_item_len == item_len) { if (sub_item_len == item_len) {
ret = btrfs_del_item(trans, root, path); ret = btrfs_del_item(trans, root, path);
} else { } else {
......
此差异已折叠。
...@@ -71,6 +71,12 @@ struct btrfs_root *btrfs_get_new_fs_root(struct btrfs_fs_info *fs_info, ...@@ -71,6 +71,12 @@ struct btrfs_root *btrfs_get_new_fs_root(struct btrfs_fs_info *fs_info,
struct btrfs_root *btrfs_get_fs_root_commit_root(struct btrfs_fs_info *fs_info, struct btrfs_root *btrfs_get_fs_root_commit_root(struct btrfs_fs_info *fs_info,
struct btrfs_path *path, struct btrfs_path *path,
u64 objectid); u64 objectid);
int btrfs_global_root_insert(struct btrfs_root *root);
void btrfs_global_root_delete(struct btrfs_root *root);
struct btrfs_root *btrfs_global_root(struct btrfs_fs_info *fs_info,
struct btrfs_key *key);
struct btrfs_root *btrfs_csum_root(struct btrfs_fs_info *fs_info, u64 bytenr);
struct btrfs_root *btrfs_extent_root(struct btrfs_fs_info *fs_info, u64 bytenr);
void btrfs_free_fs_info(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); int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info);
...@@ -103,6 +109,11 @@ static inline struct btrfs_root *btrfs_grab_root(struct btrfs_root *root) ...@@ -103,6 +109,11 @@ static inline struct btrfs_root *btrfs_grab_root(struct btrfs_root *root)
return NULL; return NULL;
} }
static inline struct btrfs_root *btrfs_block_group_root(struct btrfs_fs_info *fs_info)
{
return btrfs_extent_root(fs_info, 0);
}
void btrfs_put_root(struct btrfs_root *root); void btrfs_put_root(struct btrfs_root *root);
void btrfs_mark_buffer_dirty(struct extent_buffer *buf); void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid, int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid,
......
...@@ -87,6 +87,7 @@ void btrfs_free_excluded_extents(struct btrfs_block_group *cache) ...@@ -87,6 +87,7 @@ void btrfs_free_excluded_extents(struct btrfs_block_group *cache)
/* simple helper to search for an existing data extent at a given offset */ /* 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) int btrfs_lookup_data_extent(struct btrfs_fs_info *fs_info, u64 start, u64 len)
{ {
struct btrfs_root *root = btrfs_extent_root(fs_info, start);
int ret; int ret;
struct btrfs_key key; struct btrfs_key key;
struct btrfs_path *path; struct btrfs_path *path;
...@@ -98,7 +99,7 @@ int btrfs_lookup_data_extent(struct btrfs_fs_info *fs_info, u64 start, u64 len) ...@@ -98,7 +99,7 @@ int btrfs_lookup_data_extent(struct btrfs_fs_info *fs_info, u64 start, u64 len)
key.objectid = start; key.objectid = start;
key.offset = len; key.offset = len;
key.type = BTRFS_EXTENT_ITEM_KEY; key.type = BTRFS_EXTENT_ITEM_KEY;
ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0); ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
btrfs_free_path(path); btrfs_free_path(path);
return ret; return ret;
} }
...@@ -116,6 +117,7 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans, ...@@ -116,6 +117,7 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 bytenr, struct btrfs_fs_info *fs_info, u64 bytenr,
u64 offset, int metadata, u64 *refs, u64 *flags) u64 offset, int metadata, u64 *refs, u64 *flags)
{ {
struct btrfs_root *extent_root;
struct btrfs_delayed_ref_head *head; struct btrfs_delayed_ref_head *head;
struct btrfs_delayed_ref_root *delayed_refs; struct btrfs_delayed_ref_root *delayed_refs;
struct btrfs_path *path; struct btrfs_path *path;
...@@ -153,7 +155,8 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans, ...@@ -153,7 +155,8 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
else else
key.type = BTRFS_EXTENT_ITEM_KEY; key.type = BTRFS_EXTENT_ITEM_KEY;
ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0); extent_root = btrfs_extent_root(fs_info, bytenr);
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
if (ret < 0) if (ret < 0)
goto out_free; goto out_free;
...@@ -171,7 +174,7 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans, ...@@ -171,7 +174,7 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
if (ret == 0) { if (ret == 0) {
leaf = path->nodes[0]; leaf = path->nodes[0];
item_size = btrfs_item_size_nr(leaf, path->slots[0]); item_size = btrfs_item_size(leaf, path->slots[0]);
if (item_size >= sizeof(*ei)) { if (item_size >= sizeof(*ei)) {
ei = btrfs_item_ptr(leaf, path->slots[0], ei = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_extent_item); struct btrfs_extent_item);
...@@ -443,7 +446,7 @@ static noinline int lookup_extent_data_ref(struct btrfs_trans_handle *trans, ...@@ -443,7 +446,7 @@ static noinline int lookup_extent_data_ref(struct btrfs_trans_handle *trans,
u64 root_objectid, u64 root_objectid,
u64 owner, u64 offset) u64 owner, u64 offset)
{ {
struct btrfs_root *root = trans->fs_info->extent_root; struct btrfs_root *root = btrfs_extent_root(trans->fs_info, bytenr);
struct btrfs_key key; struct btrfs_key key;
struct btrfs_extent_data_ref *ref; struct btrfs_extent_data_ref *ref;
struct extent_buffer *leaf; struct extent_buffer *leaf;
...@@ -519,7 +522,7 @@ static noinline int insert_extent_data_ref(struct btrfs_trans_handle *trans, ...@@ -519,7 +522,7 @@ static noinline int insert_extent_data_ref(struct btrfs_trans_handle *trans,
u64 root_objectid, u64 owner, u64 root_objectid, u64 owner,
u64 offset, int refs_to_add) u64 offset, int refs_to_add)
{ {
struct btrfs_root *root = trans->fs_info->extent_root; struct btrfs_root *root = btrfs_extent_root(trans->fs_info, bytenr);
struct btrfs_key key; struct btrfs_key key;
struct extent_buffer *leaf; struct extent_buffer *leaf;
u32 size; u32 size;
...@@ -593,6 +596,7 @@ static noinline int insert_extent_data_ref(struct btrfs_trans_handle *trans, ...@@ -593,6 +596,7 @@ static noinline int insert_extent_data_ref(struct btrfs_trans_handle *trans,
} }
static noinline int remove_extent_data_ref(struct btrfs_trans_handle *trans, static noinline int remove_extent_data_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path, struct btrfs_path *path,
int refs_to_drop, int *last_ref) int refs_to_drop, int *last_ref)
{ {
...@@ -626,7 +630,7 @@ static noinline int remove_extent_data_ref(struct btrfs_trans_handle *trans, ...@@ -626,7 +630,7 @@ static noinline int remove_extent_data_ref(struct btrfs_trans_handle *trans,
num_refs -= refs_to_drop; num_refs -= refs_to_drop;
if (num_refs == 0) { if (num_refs == 0) {
ret = btrfs_del_item(trans, trans->fs_info->extent_root, path); ret = btrfs_del_item(trans, root, path);
*last_ref = 1; *last_ref = 1;
} else { } else {
if (key.type == BTRFS_EXTENT_DATA_REF_KEY) if (key.type == BTRFS_EXTENT_DATA_REF_KEY)
...@@ -685,7 +689,7 @@ static noinline int lookup_tree_block_ref(struct btrfs_trans_handle *trans, ...@@ -685,7 +689,7 @@ static noinline int lookup_tree_block_ref(struct btrfs_trans_handle *trans,
u64 bytenr, u64 parent, u64 bytenr, u64 parent,
u64 root_objectid) u64 root_objectid)
{ {
struct btrfs_root *root = trans->fs_info->extent_root; struct btrfs_root *root = btrfs_extent_root(trans->fs_info, bytenr);
struct btrfs_key key; struct btrfs_key key;
int ret; int ret;
...@@ -709,6 +713,7 @@ static noinline int insert_tree_block_ref(struct btrfs_trans_handle *trans, ...@@ -709,6 +713,7 @@ static noinline int insert_tree_block_ref(struct btrfs_trans_handle *trans,
u64 bytenr, u64 parent, u64 bytenr, u64 parent,
u64 root_objectid) u64 root_objectid)
{ {
struct btrfs_root *root = btrfs_extent_root(trans->fs_info, bytenr);
struct btrfs_key key; struct btrfs_key key;
int ret; int ret;
...@@ -721,8 +726,7 @@ static noinline int insert_tree_block_ref(struct btrfs_trans_handle *trans, ...@@ -721,8 +726,7 @@ static noinline int insert_tree_block_ref(struct btrfs_trans_handle *trans,
key.offset = root_objectid; key.offset = root_objectid;
} }
ret = btrfs_insert_empty_item(trans, trans->fs_info->extent_root, ret = btrfs_insert_empty_item(trans, root, path, &key, 0);
path, &key, 0);
btrfs_release_path(path); btrfs_release_path(path);
return ret; return ret;
} }
...@@ -787,7 +791,7 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans, ...@@ -787,7 +791,7 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
u64 owner, u64 offset, int insert) u64 owner, u64 offset, int insert)
{ {
struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_root *root = fs_info->extent_root; struct btrfs_root *root = btrfs_extent_root(fs_info, bytenr);
struct btrfs_key key; struct btrfs_key key;
struct extent_buffer *leaf; struct extent_buffer *leaf;
struct btrfs_extent_item *ei; struct btrfs_extent_item *ei;
...@@ -865,7 +869,7 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans, ...@@ -865,7 +869,7 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
} }
leaf = path->nodes[0]; leaf = path->nodes[0];
item_size = btrfs_item_size_nr(leaf, path->slots[0]); item_size = btrfs_item_size(leaf, path->slots[0]);
if (unlikely(item_size < sizeof(*ei))) { if (unlikely(item_size < sizeof(*ei))) {
err = -EINVAL; err = -EINVAL;
btrfs_print_v0_err(fs_info); btrfs_print_v0_err(fs_info);
...@@ -1007,7 +1011,7 @@ void setup_inline_extent_backref(struct btrfs_fs_info *fs_info, ...@@ -1007,7 +1011,7 @@ void setup_inline_extent_backref(struct btrfs_fs_info *fs_info,
__run_delayed_extent_op(extent_op, leaf, ei); __run_delayed_extent_op(extent_op, leaf, ei);
ptr = (unsigned long)ei + item_offset; ptr = (unsigned long)ei + item_offset;
end = (unsigned long)ei + btrfs_item_size_nr(leaf, path->slots[0]); end = (unsigned long)ei + btrfs_item_size(leaf, path->slots[0]);
if (ptr < end - size) if (ptr < end - size)
memmove_extent_buffer(leaf, ptr + size, ptr, memmove_extent_buffer(leaf, ptr + size, ptr,
end - size - ptr); end - size - ptr);
...@@ -1119,7 +1123,7 @@ void update_inline_extent_backref(struct btrfs_path *path, ...@@ -1119,7 +1123,7 @@ void update_inline_extent_backref(struct btrfs_path *path,
} else { } else {
*last_ref = 1; *last_ref = 1;
size = btrfs_extent_inline_ref_size(type); size = btrfs_extent_inline_ref_size(type);
item_size = btrfs_item_size_nr(leaf, path->slots[0]); item_size = btrfs_item_size(leaf, path->slots[0]);
ptr = (unsigned long)iref; ptr = (unsigned long)iref;
end = (unsigned long)ei + item_size; end = (unsigned long)ei + item_size;
if (ptr + size < end) if (ptr + size < end)
...@@ -1174,6 +1178,7 @@ int insert_inline_extent_backref(struct btrfs_trans_handle *trans, ...@@ -1174,6 +1178,7 @@ int insert_inline_extent_backref(struct btrfs_trans_handle *trans,
} }
static int remove_extent_backref(struct btrfs_trans_handle *trans, static int remove_extent_backref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path, struct btrfs_path *path,
struct btrfs_extent_inline_ref *iref, struct btrfs_extent_inline_ref *iref,
int refs_to_drop, int is_data, int *last_ref) int refs_to_drop, int is_data, int *last_ref)
...@@ -1185,11 +1190,11 @@ static int remove_extent_backref(struct btrfs_trans_handle *trans, ...@@ -1185,11 +1190,11 @@ static int remove_extent_backref(struct btrfs_trans_handle *trans,
update_inline_extent_backref(path, iref, -refs_to_drop, NULL, update_inline_extent_backref(path, iref, -refs_to_drop, NULL,
last_ref); last_ref);
} else if (is_data) { } else if (is_data) {
ret = remove_extent_data_ref(trans, path, refs_to_drop, ret = remove_extent_data_ref(trans, root, path, refs_to_drop,
last_ref); last_ref);
} else { } else {
*last_ref = 1; *last_ref = 1;
ret = btrfs_del_item(trans, trans->fs_info->extent_root, path); ret = btrfs_del_item(trans, root, path);
} }
return ret; return ret;
} }
...@@ -1572,6 +1577,7 @@ static int run_delayed_extent_op(struct btrfs_trans_handle *trans, ...@@ -1572,6 +1577,7 @@ static int run_delayed_extent_op(struct btrfs_trans_handle *trans,
struct btrfs_delayed_extent_op *extent_op) struct btrfs_delayed_extent_op *extent_op)
{ {
struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_root *root;
struct btrfs_key key; struct btrfs_key key;
struct btrfs_path *path; struct btrfs_path *path;
struct btrfs_extent_item *ei; struct btrfs_extent_item *ei;
...@@ -1601,8 +1607,9 @@ static int run_delayed_extent_op(struct btrfs_trans_handle *trans, ...@@ -1601,8 +1607,9 @@ static int run_delayed_extent_op(struct btrfs_trans_handle *trans,
key.offset = head->num_bytes; key.offset = head->num_bytes;
} }
root = btrfs_extent_root(fs_info, key.objectid);
again: again:
ret = btrfs_search_slot(trans, fs_info->extent_root, &key, path, 0, 1); ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
if (ret < 0) { if (ret < 0) {
err = ret; err = ret;
goto out; goto out;
...@@ -1634,7 +1641,7 @@ static int run_delayed_extent_op(struct btrfs_trans_handle *trans, ...@@ -1634,7 +1641,7 @@ static int run_delayed_extent_op(struct btrfs_trans_handle *trans,
} }
leaf = path->nodes[0]; leaf = path->nodes[0];
item_size = btrfs_item_size_nr(leaf, path->slots[0]); item_size = btrfs_item_size(leaf, path->slots[0]);
if (unlikely(item_size < sizeof(*ei))) { if (unlikely(item_size < sizeof(*ei))) {
err = -EINVAL; err = -EINVAL;
...@@ -1844,8 +1851,11 @@ static int cleanup_ref_head(struct btrfs_trans_handle *trans, ...@@ -1844,8 +1851,11 @@ static int cleanup_ref_head(struct btrfs_trans_handle *trans,
if (head->must_insert_reserved) { if (head->must_insert_reserved) {
btrfs_pin_extent(trans, head->bytenr, head->num_bytes, 1); btrfs_pin_extent(trans, head->bytenr, head->num_bytes, 1);
if (head->is_data) { if (head->is_data) {
ret = btrfs_del_csums(trans, fs_info->csum_root, struct btrfs_root *csum_root;
head->bytenr, head->num_bytes);
csum_root = btrfs_csum_root(fs_info, head->bytenr);
ret = btrfs_del_csums(trans, csum_root, head->bytenr,
head->num_bytes);
} }
} }
...@@ -2285,7 +2295,7 @@ static noinline int check_committed_ref(struct btrfs_root *root, ...@@ -2285,7 +2295,7 @@ static noinline int check_committed_ref(struct btrfs_root *root,
bool strict) bool strict)
{ {
struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_root *extent_root = fs_info->extent_root; struct btrfs_root *extent_root = btrfs_extent_root(fs_info, bytenr);
struct extent_buffer *leaf; struct extent_buffer *leaf;
struct btrfs_extent_data_ref *ref; struct btrfs_extent_data_ref *ref;
struct btrfs_extent_inline_ref *iref; struct btrfs_extent_inline_ref *iref;
...@@ -2316,7 +2326,7 @@ static noinline int check_committed_ref(struct btrfs_root *root, ...@@ -2316,7 +2326,7 @@ static noinline int check_committed_ref(struct btrfs_root *root,
goto out; goto out;
ret = 1; ret = 1;
item_size = btrfs_item_size_nr(leaf, path->slots[0]); item_size = btrfs_item_size(leaf, path->slots[0]);
ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);
/* If extent item has more than 1 inline ref then it's shared */ /* If extent item has more than 1 inline ref then it's shared */
...@@ -2920,7 +2930,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, ...@@ -2920,7 +2930,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *info = trans->fs_info; struct btrfs_fs_info *info = trans->fs_info;
struct btrfs_key key; struct btrfs_key key;
struct btrfs_path *path; struct btrfs_path *path;
struct btrfs_root *extent_root = info->extent_root; struct btrfs_root *extent_root;
struct extent_buffer *leaf; struct extent_buffer *leaf;
struct btrfs_extent_item *ei; struct btrfs_extent_item *ei;
struct btrfs_extent_inline_ref *iref; struct btrfs_extent_inline_ref *iref;
...@@ -2936,6 +2946,9 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, ...@@ -2936,6 +2946,9 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
int last_ref = 0; int last_ref = 0;
bool skinny_metadata = btrfs_fs_incompat(info, SKINNY_METADATA); bool skinny_metadata = btrfs_fs_incompat(info, SKINNY_METADATA);
extent_root = btrfs_extent_root(info, bytenr);
ASSERT(extent_root);
path = btrfs_alloc_path(); path = btrfs_alloc_path();
if (!path) if (!path)
return -ENOMEM; return -ENOMEM;
...@@ -2996,9 +3009,9 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, ...@@ -2996,9 +3009,9 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
goto err_dump; goto err_dump;
} }
/* Must be SHARED_* item, remove the backref first */ /* Must be SHARED_* item, remove the backref first */
ret = remove_extent_backref(trans, path, NULL, ret = remove_extent_backref(trans, extent_root, path,
refs_to_drop, NULL, refs_to_drop, is_data,
is_data, &last_ref); &last_ref);
if (ret) { if (ret) {
btrfs_abort_transaction(trans, ret); btrfs_abort_transaction(trans, ret);
goto out; goto out;
...@@ -3068,7 +3081,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, ...@@ -3068,7 +3081,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
} }
leaf = path->nodes[0]; leaf = path->nodes[0];
item_size = btrfs_item_size_nr(leaf, extent_slot); item_size = btrfs_item_size(leaf, extent_slot);
if (unlikely(item_size < sizeof(*ei))) { if (unlikely(item_size < sizeof(*ei))) {
ret = -EINVAL; ret = -EINVAL;
btrfs_print_v0_err(info); btrfs_print_v0_err(info);
...@@ -3122,8 +3135,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, ...@@ -3122,8 +3135,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
btrfs_mark_buffer_dirty(leaf); btrfs_mark_buffer_dirty(leaf);
} }
if (found_extent) { if (found_extent) {
ret = remove_extent_backref(trans, path, iref, ret = remove_extent_backref(trans, extent_root, path,
refs_to_drop, is_data, iref, refs_to_drop, is_data,
&last_ref); &last_ref);
if (ret) { if (ret) {
btrfs_abort_transaction(trans, ret); btrfs_abort_transaction(trans, ret);
...@@ -3179,7 +3192,9 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, ...@@ -3179,7 +3192,9 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
btrfs_release_path(path); btrfs_release_path(path);
if (is_data) { if (is_data) {
ret = btrfs_del_csums(trans, info->csum_root, bytenr, struct btrfs_root *csum_root;
csum_root = btrfs_csum_root(info, bytenr);
ret = btrfs_del_csums(trans, csum_root, bytenr,
num_bytes); num_bytes);
if (ret) { if (ret) {
btrfs_abort_transaction(trans, ret); btrfs_abort_transaction(trans, ret);
...@@ -3790,23 +3805,35 @@ static int do_allocation_zoned(struct btrfs_block_group *block_group, ...@@ -3790,23 +3805,35 @@ static int do_allocation_zoned(struct btrfs_block_group *block_group,
spin_unlock(&fs_info->relocation_bg_lock); spin_unlock(&fs_info->relocation_bg_lock);
if (skip) if (skip)
return 1; return 1;
/* Check RO and no space case before trying to activate it */ /* Check RO and no space case before trying to activate it */
spin_lock(&block_group->lock); spin_lock(&block_group->lock);
if (block_group->ro || if (block_group->ro ||
block_group->alloc_offset == block_group->zone_capacity) { block_group->alloc_offset == block_group->zone_capacity) {
spin_unlock(&block_group->lock); ret = 1;
return 1; /*
* May need to clear fs_info->{treelog,data_reloc}_bg.
* Return the error after taking the locks.
*/
} }
spin_unlock(&block_group->lock); spin_unlock(&block_group->lock);
if (!btrfs_zone_activate(block_group)) if (!ret && !btrfs_zone_activate(block_group)) {
return 1; ret = 1;
/*
* May need to clear fs_info->{treelog,data_reloc}_bg.
* Return the error after taking the locks.
*/
}
spin_lock(&space_info->lock); spin_lock(&space_info->lock);
spin_lock(&block_group->lock); spin_lock(&block_group->lock);
spin_lock(&fs_info->treelog_bg_lock); spin_lock(&fs_info->treelog_bg_lock);
spin_lock(&fs_info->relocation_bg_lock); spin_lock(&fs_info->relocation_bg_lock);
if (ret)
goto out;
ASSERT(!ffe_ctl->for_treelog || ASSERT(!ffe_ctl->for_treelog ||
block_group->start == fs_info->treelog_bg || block_group->start == fs_info->treelog_bg ||
fs_info->treelog_bg == 0); fs_info->treelog_bg == 0);
...@@ -3947,6 +3974,28 @@ static void found_extent(struct find_free_extent_ctl *ffe_ctl, ...@@ -3947,6 +3974,28 @@ static void found_extent(struct find_free_extent_ctl *ffe_ctl,
} }
} }
static bool can_allocate_chunk(struct btrfs_fs_info *fs_info,
struct find_free_extent_ctl *ffe_ctl)
{
switch (ffe_ctl->policy) {
case BTRFS_EXTENT_ALLOC_CLUSTERED:
return true;
case BTRFS_EXTENT_ALLOC_ZONED:
/*
* If we have enough free space left in an already
* active block group and we can't activate any other
* zone now, do not allow allocating a new chunk and
* let find_free_extent() retry with a smaller size.
*/
if (ffe_ctl->max_extent_size >= ffe_ctl->min_alloc_size &&
!btrfs_can_activate_zone(fs_info->fs_devices, ffe_ctl->flags))
return false;
return true;
default:
BUG();
}
}
static int chunk_allocation_failed(struct find_free_extent_ctl *ffe_ctl) static int chunk_allocation_failed(struct find_free_extent_ctl *ffe_ctl)
{ {
switch (ffe_ctl->policy) { switch (ffe_ctl->policy) {
...@@ -3975,7 +4024,7 @@ static int find_free_extent_update_loop(struct btrfs_fs_info *fs_info, ...@@ -3975,7 +4024,7 @@ static int find_free_extent_update_loop(struct btrfs_fs_info *fs_info,
struct find_free_extent_ctl *ffe_ctl, struct find_free_extent_ctl *ffe_ctl,
bool full_search) bool full_search)
{ {
struct btrfs_root *root = fs_info->extent_root; struct btrfs_root *root = fs_info->chunk_root;
int ret; int ret;
if ((ffe_ctl->loop == LOOP_CACHING_NOWAIT) && if ((ffe_ctl->loop == LOOP_CACHING_NOWAIT) &&
...@@ -3987,18 +4036,6 @@ static int find_free_extent_update_loop(struct btrfs_fs_info *fs_info, ...@@ -3987,18 +4036,6 @@ static int find_free_extent_update_loop(struct btrfs_fs_info *fs_info,
return 0; return 0;
} }
if (ffe_ctl->max_extent_size >= ffe_ctl->min_alloc_size &&
!btrfs_can_activate_zone(fs_info->fs_devices, ffe_ctl->index)) {
/*
* If we have enough free space left in an already active block
* group and we can't activate any other zone now, retry the
* active ones with a smaller allocation size. Returning early
* from here will tell btrfs_reserve_extent() to haven the
* size.
*/
return -ENOSPC;
}
if (ffe_ctl->loop >= LOOP_CACHING_WAIT && ffe_ctl->have_caching_bg) if (ffe_ctl->loop >= LOOP_CACHING_WAIT && ffe_ctl->have_caching_bg)
return 1; return 1;
...@@ -4034,6 +4071,10 @@ static int find_free_extent_update_loop(struct btrfs_fs_info *fs_info, ...@@ -4034,6 +4071,10 @@ static int find_free_extent_update_loop(struct btrfs_fs_info *fs_info,
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
int exist = 0; int exist = 0;
/*Check if allocation policy allows to create a new chunk */
if (!can_allocate_chunk(fs_info, ffe_ctl))
return -ENOSPC;
trans = current->journal_info; trans = current->journal_info;
if (trans) if (trans)
exist = 1; exist = 1;
...@@ -4570,6 +4611,7 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans, ...@@ -4570,6 +4611,7 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
struct btrfs_key *ins, int ref_mod) struct btrfs_key *ins, int ref_mod)
{ {
struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_root *extent_root;
int ret; int ret;
struct btrfs_extent_item *extent_item; struct btrfs_extent_item *extent_item;
struct btrfs_extent_inline_ref *iref; struct btrfs_extent_inline_ref *iref;
...@@ -4589,8 +4631,8 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans, ...@@ -4589,8 +4631,8 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
if (!path) if (!path)
return -ENOMEM; return -ENOMEM;
ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path, extent_root = btrfs_extent_root(fs_info, ins->objectid);
ins, size); ret = btrfs_insert_empty_item(trans, extent_root, path, ins, size);
if (ret) { if (ret) {
btrfs_free_path(path); btrfs_free_path(path);
return ret; return ret;
...@@ -4642,6 +4684,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans, ...@@ -4642,6 +4684,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
struct btrfs_delayed_extent_op *extent_op) struct btrfs_delayed_extent_op *extent_op)
{ {
struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_root *extent_root;
int ret; int ret;
struct btrfs_extent_item *extent_item; struct btrfs_extent_item *extent_item;
struct btrfs_key extent_key; struct btrfs_key extent_key;
...@@ -4673,8 +4716,9 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans, ...@@ -4673,8 +4716,9 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
if (!path) if (!path)
return -ENOMEM; return -ENOMEM;
ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path, extent_root = btrfs_extent_root(fs_info, extent_key.objectid);
&extent_key, size); ret = btrfs_insert_empty_item(trans, extent_root, path, &extent_key,
size);
if (ret) { if (ret) {
btrfs_free_path(path); btrfs_free_path(path);
return ret; return ret;
......
...@@ -2314,8 +2314,8 @@ static int repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 start, ...@@ -2314,8 +2314,8 @@ static int repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 start,
ASSERT(!(fs_info->sb->s_flags & SB_RDONLY)); ASSERT(!(fs_info->sb->s_flags & SB_RDONLY));
BUG_ON(!mirror_num); BUG_ON(!mirror_num);
if (btrfs_is_zoned(fs_info)) if (btrfs_repair_one_zone(fs_info, logical))
return btrfs_repair_one_zone(fs_info, logical); return 0;
bio = btrfs_bio_alloc(1); bio = btrfs_bio_alloc(1);
bio->bi_iter.bi_size = 0; bio->bi_iter.bi_size = 0;
...@@ -3087,9 +3087,6 @@ static void end_bio_extent_readpage(struct bio *bio) ...@@ -3087,9 +3087,6 @@ static void end_bio_extent_readpage(struct bio *bio)
set_bit(EXTENT_BUFFER_READ_ERR, &eb->bflags); set_bit(EXTENT_BUFFER_READ_ERR, &eb->bflags);
eb->read_mirror = mirror; eb->read_mirror = mirror;
atomic_dec(&eb->io_pages); atomic_dec(&eb->io_pages);
if (test_and_clear_bit(EXTENT_BUFFER_READAHEAD,
&eb->bflags))
btree_readahead_hook(eb, -EIO);
} }
readpage_ok: readpage_ok:
if (likely(uptodate)) { if (likely(uptodate)) {
...@@ -3187,13 +3184,12 @@ struct bio *btrfs_bio_clone_partial(struct bio *orig, u64 offset, u64 size) ...@@ -3187,13 +3184,12 @@ struct bio *btrfs_bio_clone_partial(struct bio *orig, u64 offset, u64 size)
/** /**
* Attempt to add a page to bio * Attempt to add a page to bio
* *
* @bio: destination bio * @bio_ctrl: record both the bio, and its bio_flags
* @page: page to add to the bio * @page: page to add to the bio
* @disk_bytenr: offset of the new bio or to check whether we are adding * @disk_bytenr: offset of the new bio or to check whether we are adding
* a contiguous page to the previous one * a contiguous page to the previous one
* @pg_offset: starting offset in the page
* @size: portion of page that we want to write * @size: portion of page that we want to write
* @prev_bio_flags: flags of previous bio to see if we can merge the current one * @pg_offset: starting offset in the page
* @bio_flags: flags of the current bio to see if we can merge them * @bio_flags: flags of the current bio to see if we can merge them
* *
* Attempt to add a page to bio considering stripe alignment etc. * Attempt to add a page to bio considering stripe alignment etc.
...@@ -3283,8 +3279,7 @@ static int calc_bio_boundaries(struct btrfs_bio_ctrl *bio_ctrl, ...@@ -3283,8 +3279,7 @@ static int calc_bio_boundaries(struct btrfs_bio_ctrl *bio_ctrl,
else else
bio_ctrl->len_to_stripe_boundary = (u32)geom.len; bio_ctrl->len_to_stripe_boundary = (u32)geom.len;
if (!btrfs_is_zoned(fs_info) || if (bio_op(bio_ctrl->bio) != REQ_OP_ZONE_APPEND) {
bio_op(bio_ctrl->bio) != REQ_OP_ZONE_APPEND) {
bio_ctrl->len_to_oe_boundary = U32_MAX; bio_ctrl->len_to_oe_boundary = U32_MAX;
return 0; return 0;
} }
...@@ -3339,7 +3334,7 @@ static int alloc_new_bio(struct btrfs_inode *inode, ...@@ -3339,7 +3334,7 @@ static int alloc_new_bio(struct btrfs_inode *inode,
bio_set_dev(bio, bdev); bio_set_dev(bio, bdev);
wbc_init_bio(wbc, bio); wbc_init_bio(wbc, bio);
} }
if (btrfs_is_zoned(fs_info) && bio_op(bio) == REQ_OP_ZONE_APPEND) { if (bio_op(bio) == REQ_OP_ZONE_APPEND) {
struct btrfs_device *device; struct btrfs_device *device;
device = btrfs_zoned_get_device(fs_info, disk_bytenr, device = btrfs_zoned_get_device(fs_info, disk_bytenr,
...@@ -3785,12 +3780,13 @@ static void update_nr_written(struct writeback_control *wbc, ...@@ -3785,12 +3780,13 @@ static void update_nr_written(struct writeback_control *wbc,
* This returns < 0 if there were errors (page still locked) * This returns < 0 if there were errors (page still locked)
*/ */
static noinline_for_stack int writepage_delalloc(struct btrfs_inode *inode, static noinline_for_stack int writepage_delalloc(struct btrfs_inode *inode,
struct page *page, struct writeback_control *wbc, struct page *page, struct writeback_control *wbc)
unsigned long *nr_written)
{ {
const u64 page_end = page_offset(page) + PAGE_SIZE - 1; const u64 page_end = page_offset(page) + PAGE_SIZE - 1;
u64 delalloc_start = page_offset(page); u64 delalloc_start = page_offset(page);
u64 delalloc_to_write = 0; u64 delalloc_to_write = 0;
/* How many pages are started by btrfs_run_delalloc_range() */
unsigned long nr_written = 0;
int ret; int ret;
int page_started = 0; int page_started = 0;
...@@ -3806,7 +3802,7 @@ static noinline_for_stack int writepage_delalloc(struct btrfs_inode *inode, ...@@ -3806,7 +3802,7 @@ static noinline_for_stack int writepage_delalloc(struct btrfs_inode *inode,
continue; continue;
} }
ret = btrfs_run_delalloc_range(inode, page, delalloc_start, ret = btrfs_run_delalloc_range(inode, page, delalloc_start,
delalloc_end, &page_started, nr_written, wbc); delalloc_end, &page_started, &nr_written, wbc);
if (ret) { if (ret) {
btrfs_page_set_error(inode->root->fs_info, page, btrfs_page_set_error(inode->root->fs_info, page,
page_offset(page), PAGE_SIZE); page_offset(page), PAGE_SIZE);
...@@ -3829,16 +3825,13 @@ static noinline_for_stack int writepage_delalloc(struct btrfs_inode *inode, ...@@ -3829,16 +3825,13 @@ static noinline_for_stack int writepage_delalloc(struct btrfs_inode *inode,
thresh); thresh);
} }
/* did the fill delalloc function already unlock and start /* Did btrfs_run_dealloc_range() already unlock and start the IO? */
* the IO?
*/
if (page_started) { if (page_started) {
/* /*
* we've unlocked the page, so we can't update * We've unlocked the page, so we can't update the mapping's
* the mapping's writeback index, just update * writeback index, just update nr_to_write.
* nr_to_write.
*/ */
wbc->nr_to_write -= *nr_written; wbc->nr_to_write -= nr_written;
return 1; return 1;
} }
...@@ -3910,7 +3903,6 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode, ...@@ -3910,7 +3903,6 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode,
struct writeback_control *wbc, struct writeback_control *wbc,
struct extent_page_data *epd, struct extent_page_data *epd,
loff_t i_size, loff_t i_size,
unsigned long nr_written,
int *nr_ret) int *nr_ret)
{ {
struct btrfs_fs_info *fs_info = inode->root->fs_info; struct btrfs_fs_info *fs_info = inode->root->fs_info;
...@@ -3929,7 +3921,6 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode, ...@@ -3929,7 +3921,6 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode,
if (ret) { if (ret) {
/* Fixup worker will requeue */ /* Fixup worker will requeue */
redirty_page_for_writepage(wbc, page); redirty_page_for_writepage(wbc, page);
update_nr_written(wbc, nr_written);
unlock_page(page); unlock_page(page);
return 1; return 1;
} }
...@@ -3938,7 +3929,7 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode, ...@@ -3938,7 +3929,7 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode,
* we don't want to touch the inode after unlocking the page, * we don't want to touch the inode after unlocking the page,
* so we update the mapping writeback index now * so we update the mapping writeback index now
*/ */
update_nr_written(wbc, nr_written + 1); update_nr_written(wbc, 1);
while (cur <= end) { while (cur <= end) {
u64 disk_bytenr; u64 disk_bytenr;
...@@ -4076,7 +4067,6 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, ...@@ -4076,7 +4067,6 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
size_t pg_offset; size_t pg_offset;
loff_t i_size = i_size_read(inode); loff_t i_size = i_size_read(inode);
unsigned long end_index = i_size >> PAGE_SHIFT; unsigned long end_index = i_size >> PAGE_SHIFT;
unsigned long nr_written = 0;
trace___extent_writepage(page, inode, wbc); trace___extent_writepage(page, inode, wbc);
...@@ -4105,7 +4095,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, ...@@ -4105,7 +4095,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
} }
if (!epd->extent_locked) { if (!epd->extent_locked) {
ret = writepage_delalloc(BTRFS_I(inode), page, wbc, &nr_written); ret = writepage_delalloc(BTRFS_I(inode), page, wbc);
if (ret == 1) if (ret == 1)
return 0; return 0;
if (ret) if (ret)
...@@ -4113,7 +4103,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, ...@@ -4113,7 +4103,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
} }
ret = __extent_writepage_io(BTRFS_I(inode), page, wbc, epd, i_size, ret = __extent_writepage_io(BTRFS_I(inode), page, wbc, epd, i_size,
nr_written, &nr); &nr);
if (ret == 1) if (ret == 1)
return 0; return 0;
...@@ -5189,8 +5179,6 @@ int extent_writepages(struct address_space *mapping, ...@@ -5189,8 +5179,6 @@ int extent_writepages(struct address_space *mapping,
struct writeback_control *wbc) struct writeback_control *wbc)
{ {
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
const bool data_reloc = btrfs_is_data_reloc_root(BTRFS_I(inode)->root);
const bool zoned = btrfs_is_zoned(BTRFS_I(inode)->root->fs_info);
int ret = 0; int ret = 0;
struct extent_page_data epd = { struct extent_page_data epd = {
.bio_ctrl = { 0 }, .bio_ctrl = { 0 },
...@@ -5202,11 +5190,9 @@ int extent_writepages(struct address_space *mapping, ...@@ -5202,11 +5190,9 @@ int extent_writepages(struct address_space *mapping,
* Allow only a single thread to do the reloc work in zoned mode to * Allow only a single thread to do the reloc work in zoned mode to
* protect the write pointer updates. * protect the write pointer updates.
*/ */
if (data_reloc && zoned) btrfs_zoned_data_reloc_lock(BTRFS_I(inode));
btrfs_inode_lock(inode, 0);
ret = extent_write_cache_pages(mapping, wbc, &epd); ret = extent_write_cache_pages(mapping, wbc, &epd);
if (data_reloc && zoned) btrfs_zoned_data_reloc_unlock(BTRFS_I(inode));
btrfs_inode_unlock(inode, 0);
ASSERT(ret <= 0); ASSERT(ret <= 0);
if (ret < 0) { if (ret < 0) {
end_write_bio(&epd, ret); end_write_bio(&epd, ret);
......
...@@ -208,7 +208,7 @@ btrfs_lookup_csum(struct btrfs_trans_handle *trans, ...@@ -208,7 +208,7 @@ btrfs_lookup_csum(struct btrfs_trans_handle *trans,
csum_offset = (bytenr - found_key.offset) >> csum_offset = (bytenr - found_key.offset) >>
fs_info->sectorsize_bits; fs_info->sectorsize_bits;
csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]); csums_in_item = btrfs_item_size(leaf, path->slots[0]);
csums_in_item /= csum_size; csums_in_item /= csum_size;
if (csum_offset == csums_in_item) { if (csum_offset == csums_in_item) {
...@@ -257,6 +257,7 @@ static int search_csum_tree(struct btrfs_fs_info *fs_info, ...@@ -257,6 +257,7 @@ static int search_csum_tree(struct btrfs_fs_info *fs_info,
struct btrfs_path *path, u64 disk_bytenr, struct btrfs_path *path, u64 disk_bytenr,
u64 len, u8 *dst) u64 len, u8 *dst)
{ {
struct btrfs_root *csum_root;
struct btrfs_csum_item *item = NULL; struct btrfs_csum_item *item = NULL;
struct btrfs_key key; struct btrfs_key key;
const u32 sectorsize = fs_info->sectorsize; const u32 sectorsize = fs_info->sectorsize;
...@@ -274,7 +275,7 @@ static int search_csum_tree(struct btrfs_fs_info *fs_info, ...@@ -274,7 +275,7 @@ static int search_csum_tree(struct btrfs_fs_info *fs_info,
item = btrfs_item_ptr(path->nodes[0], path->slots[0], item = btrfs_item_ptr(path->nodes[0], path->slots[0],
struct btrfs_csum_item); struct btrfs_csum_item);
btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
itemsize = btrfs_item_size_nr(path->nodes[0], path->slots[0]); itemsize = btrfs_item_size(path->nodes[0], path->slots[0]);
csum_start = key.offset; csum_start = key.offset;
csum_len = (itemsize / csum_size) * sectorsize; csum_len = (itemsize / csum_size) * sectorsize;
...@@ -285,13 +286,14 @@ static int search_csum_tree(struct btrfs_fs_info *fs_info, ...@@ -285,13 +286,14 @@ static int search_csum_tree(struct btrfs_fs_info *fs_info,
/* Current item doesn't contain the desired range, search again */ /* Current item doesn't contain the desired range, search again */
btrfs_release_path(path); btrfs_release_path(path);
item = btrfs_lookup_csum(NULL, fs_info->csum_root, path, disk_bytenr, 0); csum_root = btrfs_csum_root(fs_info, disk_bytenr);
item = btrfs_lookup_csum(NULL, csum_root, path, disk_bytenr, 0);
if (IS_ERR(item)) { if (IS_ERR(item)) {
ret = PTR_ERR(item); ret = PTR_ERR(item);
goto out; goto out;
} }
btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
itemsize = btrfs_item_size_nr(path->nodes[0], path->slots[0]); itemsize = btrfs_item_size(path->nodes[0], path->slots[0]);
csum_start = key.offset; csum_start = key.offset;
csum_len = (itemsize / csum_size) * sectorsize; csum_len = (itemsize / csum_size) * sectorsize;
...@@ -376,7 +378,8 @@ blk_status_t btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio, u8 *dst ...@@ -376,7 +378,8 @@ blk_status_t btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio, u8 *dst
const unsigned int nblocks = orig_len >> fs_info->sectorsize_bits; const unsigned int nblocks = orig_len >> fs_info->sectorsize_bits;
int count = 0; int count = 0;
if (!fs_info->csum_root || (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) if ((BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM) ||
test_bit(BTRFS_FS_STATE_NO_CSUMS, &fs_info->fs_state))
return BLK_STS_OK; return BLK_STS_OK;
/* /*
...@@ -534,7 +537,7 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, ...@@ -534,7 +537,7 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
key.type == BTRFS_EXTENT_CSUM_KEY) { key.type == BTRFS_EXTENT_CSUM_KEY) {
offset = (start - key.offset) >> fs_info->sectorsize_bits; offset = (start - key.offset) >> fs_info->sectorsize_bits;
if (offset * csum_size < if (offset * csum_size <
btrfs_item_size_nr(leaf, path->slots[0] - 1)) btrfs_item_size(leaf, path->slots[0] - 1))
path->slots[0]--; path->slots[0]--;
} }
} }
...@@ -559,7 +562,7 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, ...@@ -559,7 +562,7 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
if (key.offset > start) if (key.offset > start)
start = key.offset; start = key.offset;
size = btrfs_item_size_nr(leaf, path->slots[0]); size = btrfs_item_size(leaf, path->slots[0]);
csum_end = key.offset + (size / csum_size) * fs_info->sectorsize; csum_end = key.offset + (size / csum_size) * fs_info->sectorsize;
if (csum_end <= start) { if (csum_end <= start) {
path->slots[0]++; path->slots[0]++;
...@@ -750,7 +753,7 @@ static noinline void truncate_one_csum(struct btrfs_fs_info *fs_info, ...@@ -750,7 +753,7 @@ static noinline void truncate_one_csum(struct btrfs_fs_info *fs_info,
u32 blocksize_bits = fs_info->sectorsize_bits; u32 blocksize_bits = fs_info->sectorsize_bits;
leaf = path->nodes[0]; leaf = path->nodes[0];
csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; csum_end = btrfs_item_size(leaf, path->slots[0]) / csum_size;
csum_end <<= blocksize_bits; csum_end <<= blocksize_bits;
csum_end += key->offset; csum_end += key->offset;
...@@ -801,7 +804,7 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans, ...@@ -801,7 +804,7 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
const u32 csum_size = fs_info->csum_size; const u32 csum_size = fs_info->csum_size;
u32 blocksize_bits = fs_info->sectorsize_bits; u32 blocksize_bits = fs_info->sectorsize_bits;
ASSERT(root == fs_info->csum_root || ASSERT(root->root_key.objectid == BTRFS_CSUM_TREE_OBJECTID ||
root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID); root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID);
path = btrfs_alloc_path(); path = btrfs_alloc_path();
...@@ -834,7 +837,7 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans, ...@@ -834,7 +837,7 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
if (key.offset >= end_byte) if (key.offset >= end_byte)
break; break;
csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; csum_end = btrfs_item_size(leaf, path->slots[0]) / csum_size;
csum_end <<= blocksize_bits; csum_end <<= blocksize_bits;
csum_end += key.offset; csum_end += key.offset;
...@@ -1002,7 +1005,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, ...@@ -1002,7 +1005,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
item_end = btrfs_item_ptr(leaf, path->slots[0], item_end = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_csum_item); struct btrfs_csum_item);
item_end = (struct btrfs_csum_item *)((char *)item_end + item_end = (struct btrfs_csum_item *)((char *)item_end +
btrfs_item_size_nr(leaf, path->slots[0])); btrfs_item_size(leaf, path->slots[0]));
goto found; goto found;
} }
ret = PTR_ERR(item); ret = PTR_ERR(item);
...@@ -1013,7 +1016,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, ...@@ -1013,7 +1016,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
u32 item_size; u32 item_size;
/* we found one, but it isn't big enough yet */ /* we found one, but it isn't big enough yet */
leaf = path->nodes[0]; leaf = path->nodes[0];
item_size = btrfs_item_size_nr(leaf, path->slots[0]); item_size = btrfs_item_size(leaf, path->slots[0]);
if ((item_size / csum_size) >= if ((item_size / csum_size) >=
MAX_CSUM_ITEMS(fs_info, csum_size)) { MAX_CSUM_ITEMS(fs_info, csum_size)) {
/* already at max size, make a new one */ /* already at max size, make a new one */
...@@ -1070,7 +1073,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, ...@@ -1070,7 +1073,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
} }
extend_csum: extend_csum:
if (csum_offset == btrfs_item_size_nr(leaf, path->slots[0]) / if (csum_offset == btrfs_item_size(leaf, path->slots[0]) /
csum_size) { csum_size) {
int extend_nr; int extend_nr;
u64 tmp; u64 tmp;
...@@ -1125,7 +1128,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, ...@@ -1125,7 +1128,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
diff = min(diff, diff = min(diff,
MAX_CSUM_ITEMS(fs_info, csum_size) * csum_size); MAX_CSUM_ITEMS(fs_info, csum_size) * csum_size);
diff = diff - btrfs_item_size_nr(leaf, path->slots[0]); diff = diff - btrfs_item_size(leaf, path->slots[0]);
diff = min_t(u32, btrfs_leaf_free_space(leaf), diff); diff = min_t(u32, btrfs_leaf_free_space(leaf), diff);
diff /= csum_size; diff /= csum_size;
diff *= csum_size; diff *= csum_size;
...@@ -1162,7 +1165,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, ...@@ -1162,7 +1165,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
csum: csum:
item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
item_end = (struct btrfs_csum_item *)((unsigned char *)item + item_end = (struct btrfs_csum_item *)((unsigned char *)item +
btrfs_item_size_nr(leaf, path->slots[0])); btrfs_item_size(leaf, path->slots[0]));
item = (struct btrfs_csum_item *)((unsigned char *)item + item = (struct btrfs_csum_item *)((unsigned char *)item +
csum_offset * csum_size); csum_offset * csum_size);
found: found:
......
此差异已折叠。
...@@ -22,6 +22,7 @@ enum btrfs_trim_state { ...@@ -22,6 +22,7 @@ enum btrfs_trim_state {
struct btrfs_free_space { struct btrfs_free_space {
struct rb_node offset_index; struct rb_node offset_index;
struct rb_node bytes_index;
u64 offset; u64 offset;
u64 bytes; u64 bytes;
u64 max_extent_size; u64 max_extent_size;
...@@ -45,6 +46,7 @@ static inline bool btrfs_free_space_trimming_bitmap( ...@@ -45,6 +46,7 @@ static inline bool btrfs_free_space_trimming_bitmap(
struct btrfs_free_space_ctl { struct btrfs_free_space_ctl {
spinlock_t tree_lock; spinlock_t tree_lock;
struct rb_root free_space_offset; struct rb_root free_space_offset;
struct rb_root_cached free_space_bytes;
u64 free_space; u64 free_space;
int extents_thresh; int extents_thresh;
int free_extents; int free_extents;
...@@ -54,7 +56,7 @@ struct btrfs_free_space_ctl { ...@@ -54,7 +56,7 @@ struct btrfs_free_space_ctl {
s32 discardable_extents[BTRFS_STAT_NR_ENTRIES]; s32 discardable_extents[BTRFS_STAT_NR_ENTRIES];
s64 discardable_bytes[BTRFS_STAT_NR_ENTRIES]; s64 discardable_bytes[BTRFS_STAT_NR_ENTRIES];
const struct btrfs_free_space_op *op; const struct btrfs_free_space_op *op;
void *private; struct btrfs_block_group *block_group;
struct mutex cache_writeout_mutex; struct mutex cache_writeout_mutex;
struct list_head trimming_ranges; struct list_head trimming_ranges;
}; };
...@@ -101,10 +103,8 @@ int btrfs_write_out_cache(struct btrfs_trans_handle *trans, ...@@ -101,10 +103,8 @@ int btrfs_write_out_cache(struct btrfs_trans_handle *trans,
void btrfs_init_free_space_ctl(struct btrfs_block_group *block_group, void btrfs_init_free_space_ctl(struct btrfs_block_group *block_group,
struct btrfs_free_space_ctl *ctl); struct btrfs_free_space_ctl *ctl);
int __btrfs_add_free_space(struct btrfs_fs_info *fs_info, int __btrfs_add_free_space(struct btrfs_block_group *block_group, u64 bytenr,
struct btrfs_free_space_ctl *ctl, u64 size, enum btrfs_trim_state trim_state);
u64 bytenr, u64 size,
enum btrfs_trim_state trim_state);
int btrfs_add_free_space(struct btrfs_block_group *block_group, int btrfs_add_free_space(struct btrfs_block_group *block_group,
u64 bytenr, u64 size); u64 bytenr, u64 size);
int btrfs_add_free_space_unused(struct btrfs_block_group *block_group, int btrfs_add_free_space_unused(struct btrfs_block_group *block_group,
......
...@@ -16,6 +16,18 @@ static int __add_block_group_free_space(struct btrfs_trans_handle *trans, ...@@ -16,6 +16,18 @@ static int __add_block_group_free_space(struct btrfs_trans_handle *trans,
struct btrfs_block_group *block_group, struct btrfs_block_group *block_group,
struct btrfs_path *path); struct btrfs_path *path);
static struct btrfs_root *btrfs_free_space_root(
struct btrfs_block_group *block_group)
{
struct btrfs_key key = {
.objectid = BTRFS_FREE_SPACE_TREE_OBJECTID,
.type = BTRFS_ROOT_ITEM_KEY,
.offset = 0,
};
return btrfs_global_root(block_group->fs_info, &key);
}
void set_free_space_tree_thresholds(struct btrfs_block_group *cache) void set_free_space_tree_thresholds(struct btrfs_block_group *cache)
{ {
u32 bitmap_range; u32 bitmap_range;
...@@ -51,7 +63,7 @@ static int add_new_free_space_info(struct btrfs_trans_handle *trans, ...@@ -51,7 +63,7 @@ static int add_new_free_space_info(struct btrfs_trans_handle *trans,
struct btrfs_block_group *block_group, struct btrfs_block_group *block_group,
struct btrfs_path *path) struct btrfs_path *path)
{ {
struct btrfs_root *root = trans->fs_info->free_space_root; struct btrfs_root *root = btrfs_free_space_root(block_group);
struct btrfs_free_space_info *info; struct btrfs_free_space_info *info;
struct btrfs_key key; struct btrfs_key key;
struct extent_buffer *leaf; struct extent_buffer *leaf;
...@@ -85,7 +97,7 @@ struct btrfs_free_space_info *search_free_space_info( ...@@ -85,7 +97,7 @@ struct btrfs_free_space_info *search_free_space_info(
struct btrfs_path *path, int cow) struct btrfs_path *path, int cow)
{ {
struct btrfs_fs_info *fs_info = block_group->fs_info; struct btrfs_fs_info *fs_info = block_group->fs_info;
struct btrfs_root *root = fs_info->free_space_root; struct btrfs_root *root = btrfs_free_space_root(block_group);
struct btrfs_key key; struct btrfs_key key;
int ret; int ret;
...@@ -188,7 +200,7 @@ int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, ...@@ -188,7 +200,7 @@ int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans,
struct btrfs_path *path) struct btrfs_path *path)
{ {
struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_root *root = fs_info->free_space_root; struct btrfs_root *root = btrfs_free_space_root(block_group);
struct btrfs_free_space_info *info; struct btrfs_free_space_info *info;
struct btrfs_key key, found_key; struct btrfs_key key, found_key;
struct extent_buffer *leaf; struct extent_buffer *leaf;
...@@ -326,7 +338,7 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans, ...@@ -326,7 +338,7 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans,
struct btrfs_path *path) struct btrfs_path *path)
{ {
struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_root *root = fs_info->free_space_root; struct btrfs_root *root = btrfs_free_space_root(block_group);
struct btrfs_free_space_info *info; struct btrfs_free_space_info *info;
struct btrfs_key key, found_key; struct btrfs_key key, found_key;
struct extent_buffer *leaf; struct extent_buffer *leaf;
...@@ -586,7 +598,7 @@ static int modify_free_space_bitmap(struct btrfs_trans_handle *trans, ...@@ -586,7 +598,7 @@ static int modify_free_space_bitmap(struct btrfs_trans_handle *trans,
struct btrfs_path *path, struct btrfs_path *path,
u64 start, u64 size, int remove) u64 start, u64 size, int remove)
{ {
struct btrfs_root *root = block_group->fs_info->free_space_root; struct btrfs_root *root = btrfs_free_space_root(block_group);
struct btrfs_key key; struct btrfs_key key;
u64 end = start + size; u64 end = start + size;
u64 cur_start, cur_size; u64 cur_start, cur_size;
...@@ -699,7 +711,7 @@ static int remove_free_space_extent(struct btrfs_trans_handle *trans, ...@@ -699,7 +711,7 @@ static int remove_free_space_extent(struct btrfs_trans_handle *trans,
struct btrfs_path *path, struct btrfs_path *path,
u64 start, u64 size) u64 start, u64 size)
{ {
struct btrfs_root *root = trans->fs_info->free_space_root; struct btrfs_root *root = btrfs_free_space_root(block_group);
struct btrfs_key key; struct btrfs_key key;
u64 found_start, found_end; u64 found_start, found_end;
u64 end = start + size; u64 end = start + size;
...@@ -851,7 +863,7 @@ static int add_free_space_extent(struct btrfs_trans_handle *trans, ...@@ -851,7 +863,7 @@ static int add_free_space_extent(struct btrfs_trans_handle *trans,
struct btrfs_path *path, struct btrfs_path *path,
u64 start, u64 size) u64 start, u64 size)
{ {
struct btrfs_root *root = trans->fs_info->free_space_root; struct btrfs_root *root = btrfs_free_space_root(block_group);
struct btrfs_key key, new_key; struct btrfs_key key, new_key;
u64 found_start, found_end; u64 found_start, found_end;
u64 end = start + size; u64 end = start + size;
...@@ -1046,7 +1058,7 @@ int add_to_free_space_tree(struct btrfs_trans_handle *trans, ...@@ -1046,7 +1058,7 @@ int add_to_free_space_tree(struct btrfs_trans_handle *trans,
static int populate_free_space_tree(struct btrfs_trans_handle *trans, static int populate_free_space_tree(struct btrfs_trans_handle *trans,
struct btrfs_block_group *block_group) struct btrfs_block_group *block_group)
{ {
struct btrfs_root *extent_root = trans->fs_info->extent_root; struct btrfs_root *extent_root;
struct btrfs_path *path, *path2; struct btrfs_path *path, *path2;
struct btrfs_key key; struct btrfs_key key;
u64 start, end; u64 start, end;
...@@ -1080,6 +1092,7 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans, ...@@ -1080,6 +1092,7 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans,
key.type = BTRFS_EXTENT_ITEM_KEY; key.type = BTRFS_EXTENT_ITEM_KEY;
key.offset = 0; key.offset = 0;
extent_root = btrfs_extent_root(trans->fs_info, key.objectid);
ret = btrfs_search_slot_for_read(extent_root, &key, path, 1, 0); ret = btrfs_search_slot_for_read(extent_root, &key, path, 1, 0);
if (ret < 0) if (ret < 0)
goto out_locked; goto out_locked;
...@@ -1157,7 +1170,11 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info) ...@@ -1157,7 +1170,11 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info)
ret = PTR_ERR(free_space_root); ret = PTR_ERR(free_space_root);
goto abort; goto abort;
} }
fs_info->free_space_root = free_space_root; ret = btrfs_global_root_insert(free_space_root);
if (ret) {
btrfs_put_root(free_space_root);
goto abort;
}
node = rb_first(&fs_info->block_group_cache_tree); node = rb_first(&fs_info->block_group_cache_tree);
while (node) { while (node) {
...@@ -1232,7 +1249,12 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info) ...@@ -1232,7 +1249,12 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info)
{ {
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
struct btrfs_root *tree_root = fs_info->tree_root; struct btrfs_root *tree_root = fs_info->tree_root;
struct btrfs_root *free_space_root = fs_info->free_space_root; struct btrfs_key key = {
.objectid = BTRFS_FREE_SPACE_TREE_OBJECTID,
.type = BTRFS_ROOT_ITEM_KEY,
.offset = 0,
};
struct btrfs_root *free_space_root = btrfs_global_root(fs_info, &key);
int ret; int ret;
trans = btrfs_start_transaction(tree_root, 0); trans = btrfs_start_transaction(tree_root, 0);
...@@ -1241,7 +1263,6 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info) ...@@ -1241,7 +1263,6 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info)
btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE); btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE);
btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID); btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID);
fs_info->free_space_root = NULL;
ret = clear_free_space_tree(trans, free_space_root); ret = clear_free_space_tree(trans, free_space_root);
if (ret) if (ret)
...@@ -1251,6 +1272,7 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info) ...@@ -1251,6 +1272,7 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info)
if (ret) if (ret)
goto abort; goto abort;
btrfs_global_root_delete(free_space_root);
list_del(&free_space_root->dirty_list); list_del(&free_space_root->dirty_list);
btrfs_tree_lock(free_space_root->node); btrfs_tree_lock(free_space_root->node);
...@@ -1319,7 +1341,7 @@ int add_block_group_free_space(struct btrfs_trans_handle *trans, ...@@ -1319,7 +1341,7 @@ int add_block_group_free_space(struct btrfs_trans_handle *trans,
int remove_block_group_free_space(struct btrfs_trans_handle *trans, int remove_block_group_free_space(struct btrfs_trans_handle *trans,
struct btrfs_block_group *block_group) struct btrfs_block_group *block_group)
{ {
struct btrfs_root *root = trans->fs_info->free_space_root; struct btrfs_root *root = btrfs_free_space_root(block_group);
struct btrfs_path *path; struct btrfs_path *path;
struct btrfs_key key, found_key; struct btrfs_key key, found_key;
struct extent_buffer *leaf; struct extent_buffer *leaf;
...@@ -1410,7 +1432,7 @@ static int load_free_space_bitmaps(struct btrfs_caching_control *caching_ctl, ...@@ -1410,7 +1432,7 @@ static int load_free_space_bitmaps(struct btrfs_caching_control *caching_ctl,
block_group = caching_ctl->block_group; block_group = caching_ctl->block_group;
fs_info = block_group->fs_info; fs_info = block_group->fs_info;
root = fs_info->free_space_root; root = btrfs_free_space_root(block_group);
end = block_group->start + block_group->length; end = block_group->start + block_group->length;
...@@ -1488,7 +1510,7 @@ static int load_free_space_extents(struct btrfs_caching_control *caching_ctl, ...@@ -1488,7 +1510,7 @@ static int load_free_space_extents(struct btrfs_caching_control *caching_ctl,
block_group = caching_ctl->block_group; block_group = caching_ctl->block_group;
fs_info = block_group->fs_info; fs_info = block_group->fs_info;
root = fs_info->free_space_root; root = btrfs_free_space_root(block_group);
end = block_group->start + block_group->length; end = block_group->start + block_group->length;
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
*/ */
#include "ctree.h" #include "ctree.h"
#include "inode-item.h"
#include "disk-io.h" #include "disk-io.h"
#include "transaction.h" #include "transaction.h"
#include "print-tree.h" #include "print-tree.h"
...@@ -19,7 +20,7 @@ struct btrfs_inode_ref *btrfs_find_name_in_backref(struct extent_buffer *leaf, ...@@ -19,7 +20,7 @@ struct btrfs_inode_ref *btrfs_find_name_in_backref(struct extent_buffer *leaf,
u32 cur_offset = 0; u32 cur_offset = 0;
int len; int len;
item_size = btrfs_item_size_nr(leaf, slot); item_size = btrfs_item_size(leaf, slot);
ptr = btrfs_item_ptr_offset(leaf, slot); ptr = btrfs_item_ptr_offset(leaf, slot);
while (cur_offset < item_size) { while (cur_offset < item_size) {
ref = (struct btrfs_inode_ref *)(ptr + cur_offset); ref = (struct btrfs_inode_ref *)(ptr + cur_offset);
...@@ -45,7 +46,7 @@ struct btrfs_inode_extref *btrfs_find_name_in_ext_backref( ...@@ -45,7 +46,7 @@ struct btrfs_inode_extref *btrfs_find_name_in_ext_backref(
u32 cur_offset = 0; u32 cur_offset = 0;
int ref_name_len; int ref_name_len;
item_size = btrfs_item_size_nr(leaf, slot); item_size = btrfs_item_size(leaf, slot);
ptr = btrfs_item_ptr_offset(leaf, slot); ptr = btrfs_item_ptr_offset(leaf, slot);
/* /*
...@@ -139,7 +140,7 @@ static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans, ...@@ -139,7 +140,7 @@ static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,
} }
leaf = path->nodes[0]; leaf = path->nodes[0];
item_size = btrfs_item_size_nr(leaf, path->slots[0]); item_size = btrfs_item_size(leaf, path->slots[0]);
if (index) if (index)
*index = btrfs_inode_extref_index(leaf, extref); *index = btrfs_inode_extref_index(leaf, extref);
...@@ -208,7 +209,7 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, ...@@ -208,7 +209,7 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
goto out; goto out;
} }
leaf = path->nodes[0]; leaf = path->nodes[0];
item_size = btrfs_item_size_nr(leaf, path->slots[0]); item_size = btrfs_item_size(leaf, path->slots[0]);
if (index) if (index)
*index = btrfs_inode_ref_index(leaf, ref); *index = btrfs_inode_ref_index(leaf, ref);
...@@ -256,7 +257,6 @@ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans, ...@@ -256,7 +257,6 @@ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,
struct btrfs_path *path; struct btrfs_path *path;
struct btrfs_key key; struct btrfs_key key;
struct extent_buffer *leaf; struct extent_buffer *leaf;
struct btrfs_item *item;
key.objectid = inode_objectid; key.objectid = inode_objectid;
key.type = BTRFS_INODE_EXTREF_KEY; key.type = BTRFS_INODE_EXTREF_KEY;
...@@ -282,9 +282,8 @@ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans, ...@@ -282,9 +282,8 @@ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,
goto out; goto out;
leaf = path->nodes[0]; leaf = path->nodes[0];
item = btrfs_item_nr(path->slots[0]);
ptr = (unsigned long)btrfs_item_ptr(leaf, path->slots[0], char); ptr = (unsigned long)btrfs_item_ptr(leaf, path->slots[0], char);
ptr += btrfs_item_size(leaf, item) - ins_len; ptr += btrfs_item_size(leaf, path->slots[0]) - ins_len;
extref = (struct btrfs_inode_extref *)ptr; extref = (struct btrfs_inode_extref *)ptr;
btrfs_set_inode_extref_name_len(path->nodes[0], extref, name_len); btrfs_set_inode_extref_name_len(path->nodes[0], extref, name_len);
...@@ -332,7 +331,7 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, ...@@ -332,7 +331,7 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
if (ref) if (ref)
goto out; goto out;
old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]); old_size = btrfs_item_size(path->nodes[0], path->slots[0]);
btrfs_extend_item(path, ins_len); btrfs_extend_item(path, ins_len);
ref = btrfs_item_ptr(path->nodes[0], path->slots[0], ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
struct btrfs_inode_ref); struct btrfs_inode_ref);
...@@ -419,3 +418,332 @@ int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -419,3 +418,332 @@ int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
} }
return ret; return ret;
} }
static inline void btrfs_trace_truncate(struct btrfs_inode *inode,
struct extent_buffer *leaf,
struct btrfs_file_extent_item *fi,
u64 offset, int extent_type, int slot)
{
if (!inode)
return;
if (extent_type == BTRFS_FILE_EXTENT_INLINE)
trace_btrfs_truncate_show_fi_inline(inode, leaf, fi, slot,
offset);
else
trace_btrfs_truncate_show_fi_regular(inode, leaf, fi, offset);
}
/*
* Remove inode items from a given root.
*
* @trans: A transaction handle.
* @root: The root from which to remove items.
* @inode: The inode whose items we want to remove.
* @control: The btrfs_truncate_control to control how and what we
* are truncating.
*
* Remove all keys associated with the inode from the given root that have a key
* with a type greater than or equals to @min_type. When @min_type has a value of
* BTRFS_EXTENT_DATA_KEY, only remove file extent items that have an offset value
* greater than or equals to @new_size. If a file extent item that starts before
* @new_size and ends after it is found, its length is adjusted.
*
* Returns: 0 on success, < 0 on error and NEED_TRUNCATE_BLOCK when @min_type is
* BTRFS_EXTENT_DATA_KEY and the caller must truncate the last block.
*/
int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_truncate_control *control)
{
struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_path *path;
struct extent_buffer *leaf;
struct btrfs_file_extent_item *fi;
struct btrfs_key key;
struct btrfs_key found_key;
u64 new_size = control->new_size;
u64 extent_num_bytes = 0;
u64 extent_offset = 0;
u64 item_end = 0;
u32 found_type = (u8)-1;
int del_item;
int pending_del_nr = 0;
int pending_del_slot = 0;
int extent_type = -1;
int ret;
u64 bytes_deleted = 0;
bool be_nice = false;
ASSERT(control->inode || !control->clear_extent_range);
ASSERT(new_size == 0 || control->min_type == BTRFS_EXTENT_DATA_KEY);
control->last_size = new_size;
control->sub_bytes = 0;
/*
* For shareable roots we want to back off from time to time, this turns
* out to be subvolume roots, reloc roots, and data reloc roots.
*/
if (test_bit(BTRFS_ROOT_SHAREABLE, &root->state))
be_nice = true;
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
path->reada = READA_BACK;
key.objectid = control->ino;
key.offset = (u64)-1;
key.type = (u8)-1;
search_again:
/*
* With a 16K leaf size and 128MiB extents, you can actually queue up a
* huge file in a single leaf. Most of the time that bytes_deleted is
* > 0, it will be huge by the time we get here
*/
if (be_nice && bytes_deleted > SZ_32M &&
btrfs_should_end_transaction(trans)) {
ret = -EAGAIN;
goto out;
}
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
if (ret < 0)
goto out;
if (ret > 0) {
ret = 0;
/* There are no items in the tree for us to truncate, we're done */
if (path->slots[0] == 0)
goto out;
path->slots[0]--;
}
while (1) {
u64 clear_start = 0, clear_len = 0, extent_start = 0;
bool should_throttle = false;
fi = NULL;
leaf = path->nodes[0];
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
found_type = found_key.type;
if (found_key.objectid != control->ino)
break;
if (found_type < control->min_type)
break;
item_end = found_key.offset;
if (found_type == BTRFS_EXTENT_DATA_KEY) {
fi = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_file_extent_item);
extent_type = btrfs_file_extent_type(leaf, fi);
if (extent_type != BTRFS_FILE_EXTENT_INLINE)
item_end +=
btrfs_file_extent_num_bytes(leaf, fi);
else if (extent_type == BTRFS_FILE_EXTENT_INLINE)
item_end += btrfs_file_extent_ram_bytes(leaf, fi);
btrfs_trace_truncate(control->inode, leaf, fi,
found_key.offset, extent_type,
path->slots[0]);
item_end--;
}
if (found_type > control->min_type) {
del_item = 1;
} else {
if (item_end < new_size)
break;
if (found_key.offset >= new_size)
del_item = 1;
else
del_item = 0;
}
/* FIXME, shrink the extent if the ref count is only 1 */
if (found_type != BTRFS_EXTENT_DATA_KEY)
goto delete;
control->extents_found++;
if (extent_type != BTRFS_FILE_EXTENT_INLINE) {
u64 num_dec;
clear_start = found_key.offset;
extent_start = btrfs_file_extent_disk_bytenr(leaf, fi);
if (!del_item) {
u64 orig_num_bytes =
btrfs_file_extent_num_bytes(leaf, fi);
extent_num_bytes = ALIGN(new_size -
found_key.offset,
fs_info->sectorsize);
clear_start = ALIGN(new_size, fs_info->sectorsize);
btrfs_set_file_extent_num_bytes(leaf, fi,
extent_num_bytes);
num_dec = (orig_num_bytes - extent_num_bytes);
if (extent_start != 0)
control->sub_bytes += num_dec;
btrfs_mark_buffer_dirty(leaf);
} else {
extent_num_bytes =
btrfs_file_extent_disk_num_bytes(leaf, fi);
extent_offset = found_key.offset -
btrfs_file_extent_offset(leaf, fi);
/* FIXME blocksize != 4096 */
num_dec = btrfs_file_extent_num_bytes(leaf, fi);
if (extent_start != 0)
control->sub_bytes += num_dec;
}
clear_len = num_dec;
} else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
/*
* We can't truncate inline items that have had
* special encodings
*/
if (!del_item &&
btrfs_file_extent_encryption(leaf, fi) == 0 &&
btrfs_file_extent_other_encoding(leaf, fi) == 0 &&
btrfs_file_extent_compression(leaf, fi) == 0) {
u32 size = (u32)(new_size - found_key.offset);
btrfs_set_file_extent_ram_bytes(leaf, fi, size);
size = btrfs_file_extent_calc_inline_size(size);
btrfs_truncate_item(path, size, 1);
} else if (!del_item) {
/*
* We have to bail so the last_size is set to
* just before this extent.
*/
ret = BTRFS_NEED_TRUNCATE_BLOCK;
break;
} else {
/*
* Inline extents are special, we just treat
* them as a full sector worth in the file
* extent tree just for simplicity sake.
*/
clear_len = fs_info->sectorsize;
}
control->sub_bytes += item_end + 1 - new_size;
}
delete:
/*
* We only want to clear the file extent range if we're
* modifying the actual inode's mapping, which is just the
* normal truncate path.
*/
if (control->clear_extent_range) {
ret = btrfs_inode_clear_file_extent_range(control->inode,
clear_start, clear_len);
if (ret) {
btrfs_abort_transaction(trans, ret);
break;
}
}
if (del_item) {
ASSERT(!pending_del_nr ||
((path->slots[0] + 1) == pending_del_slot));
control->last_size = found_key.offset;
if (!pending_del_nr) {
/* No pending yet, add ourselves */
pending_del_slot = path->slots[0];
pending_del_nr = 1;
} else if (pending_del_nr &&
path->slots[0] + 1 == pending_del_slot) {
/* Hop on the pending chunk */
pending_del_nr++;
pending_del_slot = path->slots[0];
}
} else {
control->last_size = new_size;
break;
}
if (del_item && extent_start != 0 && !control->skip_ref_updates) {
struct btrfs_ref ref = { 0 };
bytes_deleted += extent_num_bytes;
btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF,
extent_start, extent_num_bytes, 0);
btrfs_init_data_ref(&ref, btrfs_header_owner(leaf),
control->ino, extent_offset,
root->root_key.objectid, false);
ret = btrfs_free_extent(trans, &ref);
if (ret) {
btrfs_abort_transaction(trans, ret);
break;
}
if (be_nice) {
if (btrfs_should_throttle_delayed_refs(trans))
should_throttle = true;
}
}
if (found_type == BTRFS_INODE_ITEM_KEY)
break;
if (path->slots[0] == 0 ||
path->slots[0] != pending_del_slot ||
should_throttle) {
if (pending_del_nr) {
ret = btrfs_del_items(trans, root, path,
pending_del_slot,
pending_del_nr);
if (ret) {
btrfs_abort_transaction(trans, ret);
break;
}
pending_del_nr = 0;
}
btrfs_release_path(path);
/*
* We can generate a lot of delayed refs, so we need to
* throttle every once and a while and make sure we're
* adding enough space to keep up with the work we are
* generating. Since we hold a transaction here we
* can't flush, and we don't want to FLUSH_LIMIT because
* we could have generated too many delayed refs to
* actually allocate, so just bail if we're short and
* let the normal reservation dance happen higher up.
*/
if (should_throttle) {
ret = btrfs_delayed_refs_rsv_refill(fs_info,
BTRFS_RESERVE_NO_FLUSH);
if (ret) {
ret = -EAGAIN;
break;
}
}
goto search_again;
} else {
path->slots[0]--;
}
}
out:
if (ret >= 0 && pending_del_nr) {
int err;
err = btrfs_del_items(trans, root, path, pending_del_slot,
pending_del_nr);
if (err) {
btrfs_abort_transaction(trans, err);
ret = err;
}
}
ASSERT(control->last_size >= new_size);
if (!ret && control->last_size > new_size)
control->last_size = new_size;
btrfs_free_path(path);
return ret;
}
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef BTRFS_INODE_ITEM_H
#define BTRFS_INODE_ITEM_H
#include <linux/types.h>
struct btrfs_trans_handle;
struct btrfs_root;
struct btrfs_path;
struct btrfs_key;
struct btrfs_inode_extref;
struct btrfs_inode;
struct extent_buffer;
/*
* Return this if we need to call truncate_block for the last bit of the
* truncate.
*/
#define BTRFS_NEED_TRUNCATE_BLOCK 1
struct btrfs_truncate_control {
/*
* IN: the inode we're operating on, this can be NULL if
* ->clear_extent_range is false.
*/
struct btrfs_inode *inode;
/* IN: the size we're truncating to. */
u64 new_size;
/* OUT: the number of extents truncated. */
u64 extents_found;
/* OUT: the last size we truncated this inode to. */
u64 last_size;
/* OUT: the number of bytes to sub from this inode. */
u64 sub_bytes;
/* IN: the ino we are truncating. */
u64 ino;
/*
* IN: minimum key type to remove. All key types with this type are
* removed only if their offset >= new_size.
*/
u32 min_type;
/*
* IN: true if we don't want to do extent reference updates for any file
* extents we drop.
*/
bool skip_ref_updates;
/*
* IN: true if we need to clear the file extent range for the inode as
* we drop the file extent items.
*/
bool clear_extent_range;
};
int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_truncate_control *control);
int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
const char *name, int name_len,
u64 inode_objectid, u64 ref_objectid, u64 index);
int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
const char *name, int name_len,
u64 inode_objectid, u64 ref_objectid, u64 *index);
int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path, u64 objectid);
int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_path *path,
struct btrfs_key *location, int mod);
struct btrfs_inode_extref *btrfs_lookup_inode_extref(
struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
const char *name, int name_len,
u64 inode_objectid, u64 ref_objectid, int ins_len,
int cow);
struct btrfs_inode_ref *btrfs_find_name_in_backref(struct extent_buffer *leaf,
int slot, const char *name,
int name_len);
struct btrfs_inode_extref *btrfs_find_name_in_ext_backref(
struct extent_buffer *leaf, int slot, u64 ref_objectid,
const char *name, int name_len);
#endif
此差异已折叠。
...@@ -387,6 +387,7 @@ bool btrfs_exclop_start(struct btrfs_fs_info *fs_info, ...@@ -387,6 +387,7 @@ bool btrfs_exclop_start(struct btrfs_fs_info *fs_info,
* *
* Compatibility: * Compatibility:
* - the same type is already running * - the same type is already running
* - when trying to add a device and balance has been paused
* - not BTRFS_EXCLOP_NONE - this is intentionally incompatible and the caller * - not BTRFS_EXCLOP_NONE - this is intentionally incompatible and the caller
* must check the condition first that would allow none -> @type * must check the condition first that would allow none -> @type
*/ */
...@@ -394,7 +395,9 @@ bool btrfs_exclop_start_try_lock(struct btrfs_fs_info *fs_info, ...@@ -394,7 +395,9 @@ bool btrfs_exclop_start_try_lock(struct btrfs_fs_info *fs_info,
enum btrfs_exclusive_operation type) enum btrfs_exclusive_operation type)
{ {
spin_lock(&fs_info->super_lock); spin_lock(&fs_info->super_lock);
if (fs_info->exclusive_operation == type) if (fs_info->exclusive_operation == type ||
(fs_info->exclusive_operation == BTRFS_EXCLOP_BALANCE_PAUSED &&
type == BTRFS_EXCLOP_DEV_ADD))
return true; return true;
spin_unlock(&fs_info->super_lock); spin_unlock(&fs_info->super_lock);
...@@ -414,6 +417,29 @@ void btrfs_exclop_finish(struct btrfs_fs_info *fs_info) ...@@ -414,6 +417,29 @@ void btrfs_exclop_finish(struct btrfs_fs_info *fs_info)
sysfs_notify(&fs_info->fs_devices->fsid_kobj, NULL, "exclusive_operation"); sysfs_notify(&fs_info->fs_devices->fsid_kobj, NULL, "exclusive_operation");
} }
void btrfs_exclop_balance(struct btrfs_fs_info *fs_info,
enum btrfs_exclusive_operation op)
{
switch (op) {
case BTRFS_EXCLOP_BALANCE_PAUSED:
spin_lock(&fs_info->super_lock);
ASSERT(fs_info->exclusive_operation == BTRFS_EXCLOP_BALANCE ||
fs_info->exclusive_operation == BTRFS_EXCLOP_DEV_ADD);
fs_info->exclusive_operation = BTRFS_EXCLOP_BALANCE_PAUSED;
spin_unlock(&fs_info->super_lock);
break;
case BTRFS_EXCLOP_BALANCE:
spin_lock(&fs_info->super_lock);
ASSERT(fs_info->exclusive_operation == BTRFS_EXCLOP_BALANCE_PAUSED);
fs_info->exclusive_operation = BTRFS_EXCLOP_BALANCE;
spin_unlock(&fs_info->super_lock);
break;
default:
btrfs_warn(fs_info,
"invalid exclop balance operation %d requested", op);
}
}
static int btrfs_ioctl_getversion(struct file *file, int __user *arg) static int btrfs_ioctl_getversion(struct file *file, int __user *arg)
{ {
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
...@@ -518,7 +544,6 @@ static noinline int create_subvol(struct user_namespace *mnt_userns, ...@@ -518,7 +544,6 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
struct timespec64 cur_time = current_time(dir); struct timespec64 cur_time = current_time(dir);
struct inode *inode; struct inode *inode;
int ret; int ret;
int err;
dev_t anon_dev = 0; dev_t anon_dev = 0;
u64 objectid; u64 objectid;
u64 index = 0; u64 index = 0;
...@@ -698,9 +723,10 @@ static noinline int create_subvol(struct user_namespace *mnt_userns, ...@@ -698,9 +723,10 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
trans->bytes_reserved = 0; trans->bytes_reserved = 0;
btrfs_subvolume_release_metadata(root, &block_rsv); btrfs_subvolume_release_metadata(root, &block_rsv);
err = btrfs_commit_transaction(trans); if (ret)
if (err && !ret) btrfs_end_transaction(trans);
ret = err; else
ret = btrfs_commit_transaction(trans);
if (!ret) { if (!ret) {
inode = btrfs_lookup_dentry(dir, dentry); inode = btrfs_lookup_dentry(dir, dentry);
...@@ -2084,7 +2110,7 @@ static noinline int copy_to_sk(struct btrfs_path *path, ...@@ -2084,7 +2110,7 @@ static noinline int copy_to_sk(struct btrfs_path *path,
for (i = slot; i < nritems; i++) { for (i = slot; i < nritems; i++) {
item_off = btrfs_item_ptr_offset(leaf, i); item_off = btrfs_item_ptr_offset(leaf, i);
item_len = btrfs_item_size_nr(leaf, i); item_len = btrfs_item_size(leaf, i);
btrfs_item_key_to_cpu(leaf, key, i); btrfs_item_key_to_cpu(leaf, key, i);
if (!key_in_sk(key, sk)) if (!key_in_sk(key, sk))
...@@ -2538,7 +2564,7 @@ static int btrfs_search_path_in_tree_user(struct user_namespace *mnt_userns, ...@@ -2538,7 +2564,7 @@ static int btrfs_search_path_in_tree_user(struct user_namespace *mnt_userns,
btrfs_item_key_to_cpu(leaf, &key, slot); btrfs_item_key_to_cpu(leaf, &key, slot);
item_off = btrfs_item_ptr_offset(leaf, slot); item_off = btrfs_item_ptr_offset(leaf, slot);
item_len = btrfs_item_size_nr(leaf, slot); item_len = btrfs_item_size(leaf, slot);
/* Check if dirid in ROOT_REF corresponds to passed dirid */ /* Check if dirid in ROOT_REF corresponds to passed dirid */
rref = btrfs_item_ptr(leaf, slot, struct btrfs_root_ref); rref = btrfs_item_ptr(leaf, slot, struct btrfs_root_ref);
if (args->dirid != btrfs_root_ref_dirid(leaf, rref)) { if (args->dirid != btrfs_root_ref_dirid(leaf, rref)) {
...@@ -2740,7 +2766,7 @@ static int btrfs_ioctl_get_subvol_info(struct file *file, void __user *argp) ...@@ -2740,7 +2766,7 @@ static int btrfs_ioctl_get_subvol_info(struct file *file, void __user *argp)
item_off = btrfs_item_ptr_offset(leaf, slot) item_off = btrfs_item_ptr_offset(leaf, slot)
+ sizeof(struct btrfs_root_ref); + sizeof(struct btrfs_root_ref);
item_len = btrfs_item_size_nr(leaf, slot) item_len = btrfs_item_size(leaf, slot)
- sizeof(struct btrfs_root_ref); - sizeof(struct btrfs_root_ref);
read_extent_buffer(leaf, subvol_info->name, read_extent_buffer(leaf, subvol_info->name,
item_off, item_len); item_off, item_len);
...@@ -3148,13 +3174,25 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) ...@@ -3148,13 +3174,25 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
static long btrfs_ioctl_add_dev(struct btrfs_fs_info *fs_info, void __user *arg) static long btrfs_ioctl_add_dev(struct btrfs_fs_info *fs_info, void __user *arg)
{ {
struct btrfs_ioctl_vol_args *vol_args; struct btrfs_ioctl_vol_args *vol_args;
bool restore_op = false;
int ret; int ret;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
if (!btrfs_exclop_start(fs_info, BTRFS_EXCLOP_DEV_ADD)) if (!btrfs_exclop_start(fs_info, BTRFS_EXCLOP_DEV_ADD)) {
return BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; if (!btrfs_exclop_start_try_lock(fs_info, BTRFS_EXCLOP_DEV_ADD))
return BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
/*
* We can do the device add because we have a paused balanced,
* change the exclusive op type and remember we should bring
* back the paused balance
*/
fs_info->exclusive_operation = BTRFS_EXCLOP_DEV_ADD;
btrfs_exclop_start_unlock(fs_info);
restore_op = true;
}
vol_args = memdup_user(arg, sizeof(*vol_args)); vol_args = memdup_user(arg, sizeof(*vol_args));
if (IS_ERR(vol_args)) { if (IS_ERR(vol_args)) {
...@@ -3170,7 +3208,10 @@ static long btrfs_ioctl_add_dev(struct btrfs_fs_info *fs_info, void __user *arg) ...@@ -3170,7 +3208,10 @@ static long btrfs_ioctl_add_dev(struct btrfs_fs_info *fs_info, void __user *arg)
kfree(vol_args); kfree(vol_args);
out: out:
btrfs_exclop_finish(fs_info); if (restore_op)
btrfs_exclop_balance(fs_info, BTRFS_EXCLOP_BALANCE_PAUSED);
else
btrfs_exclop_finish(fs_info);
return ret; return ret;
} }
...@@ -3622,7 +3663,6 @@ static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root, ...@@ -3622,7 +3663,6 @@ static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root,
{ {
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
u64 transid; u64 transid;
int ret;
trans = btrfs_attach_transaction_barrier(root); trans = btrfs_attach_transaction_barrier(root);
if (IS_ERR(trans)) { if (IS_ERR(trans)) {
...@@ -3634,11 +3674,7 @@ static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root, ...@@ -3634,11 +3674,7 @@ static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root,
goto out; goto out;
} }
transid = trans->transid; transid = trans->transid;
ret = btrfs_commit_transaction_async(trans); btrfs_commit_transaction_async(trans);
if (ret) {
btrfs_end_transaction(trans);
return ret;
}
out: out:
if (argp) if (argp)
if (copy_to_user(argp, &transid, sizeof(transid))) if (copy_to_user(argp, &transid, sizeof(transid)))
...@@ -4061,6 +4097,7 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg) ...@@ -4061,6 +4097,7 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
spin_lock(&fs_info->balance_lock); spin_lock(&fs_info->balance_lock);
bctl->flags |= BTRFS_BALANCE_RESUME; bctl->flags |= BTRFS_BALANCE_RESUME;
spin_unlock(&fs_info->balance_lock); spin_unlock(&fs_info->balance_lock);
btrfs_exclop_balance(fs_info, BTRFS_EXCLOP_BALANCE);
goto do_balance; goto do_balance;
} }
......
...@@ -85,7 +85,7 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type) ...@@ -85,7 +85,7 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type)
struct btrfs_disk_key key; struct btrfs_disk_key key;
unsigned long end; unsigned long end;
unsigned long ptr; unsigned long ptr;
u32 item_size = btrfs_item_size_nr(eb, slot); u32 item_size = btrfs_item_size(eb, slot);
u64 flags; u64 flags;
u64 offset; u64 offset;
int ref_index = 0; int ref_index = 0;
...@@ -200,7 +200,6 @@ void btrfs_print_leaf(struct extent_buffer *l) ...@@ -200,7 +200,6 @@ void btrfs_print_leaf(struct extent_buffer *l)
struct btrfs_fs_info *fs_info; struct btrfs_fs_info *fs_info;
int i; int i;
u32 type, nr; u32 type, nr;
struct btrfs_item *item;
struct btrfs_root_item *ri; struct btrfs_root_item *ri;
struct btrfs_dir_item *di; struct btrfs_dir_item *di;
struct btrfs_inode_item *ii; struct btrfs_inode_item *ii;
...@@ -224,12 +223,11 @@ void btrfs_print_leaf(struct extent_buffer *l) ...@@ -224,12 +223,11 @@ void btrfs_print_leaf(struct extent_buffer *l)
btrfs_leaf_free_space(l), btrfs_header_owner(l)); btrfs_leaf_free_space(l), btrfs_header_owner(l));
print_eb_refs_lock(l); print_eb_refs_lock(l);
for (i = 0 ; i < nr ; i++) { for (i = 0 ; i < nr ; i++) {
item = btrfs_item_nr(i);
btrfs_item_key_to_cpu(l, &key, i); btrfs_item_key_to_cpu(l, &key, i);
type = key.type; type = key.type;
pr_info("\titem %d key (%llu %u %llu) itemoff %d itemsize %d\n", pr_info("\titem %d key (%llu %u %llu) itemoff %d itemsize %d\n",
i, key.objectid, type, key.offset, i, key.objectid, type, key.offset,
btrfs_item_offset(l, item), btrfs_item_size(l, item)); btrfs_item_offset(l, i), btrfs_item_size(l, i));
switch (type) { switch (type) {
case BTRFS_INODE_ITEM_KEY: case BTRFS_INODE_ITEM_KEY:
ii = btrfs_item_ptr(l, i, struct btrfs_inode_item); ii = btrfs_item_ptr(l, i, struct btrfs_inode_item);
...@@ -347,7 +345,7 @@ void btrfs_print_leaf(struct extent_buffer *l) ...@@ -347,7 +345,7 @@ void btrfs_print_leaf(struct extent_buffer *l)
case BTRFS_UUID_KEY_SUBVOL: case BTRFS_UUID_KEY_SUBVOL:
case BTRFS_UUID_KEY_RECEIVED_SUBVOL: case BTRFS_UUID_KEY_RECEIVED_SUBVOL:
print_uuid_item(l, btrfs_item_ptr_offset(l, i), print_uuid_item(l, btrfs_item_ptr_offset(l, i),
btrfs_item_size_nr(l, i)); btrfs_item_size(l, i));
break; break;
} }
} }
......
...@@ -158,7 +158,7 @@ static int iterate_object_props(struct btrfs_root *root, ...@@ -158,7 +158,7 @@ static int iterate_object_props(struct btrfs_root *root,
di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item); di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
cur = 0; cur = 0;
total_len = btrfs_item_size_nr(leaf, slot); total_len = btrfs_item_size(leaf, slot);
while (cur < total_len) { while (cur < total_len) {
u32 name_len = btrfs_dir_name_len(leaf, di); u32 name_len = btrfs_dir_name_len(leaf, di);
...@@ -377,8 +377,9 @@ static int inherit_props(struct btrfs_trans_handle *trans, ...@@ -377,8 +377,9 @@ static int inherit_props(struct btrfs_trans_handle *trans,
*/ */
if (need_reserve) { if (need_reserve) {
num_bytes = btrfs_calc_insert_metadata_size(fs_info, 1); num_bytes = btrfs_calc_insert_metadata_size(fs_info, 1);
ret = btrfs_block_rsv_add(root, trans->block_rsv, ret = btrfs_block_rsv_add(fs_info, trans->block_rsv,
num_bytes, BTRFS_RESERVE_NO_FLUSH); num_bytes,
BTRFS_RESERVE_NO_FLUSH);
if (ret) if (ret)
return ret; return ret;
} }
......
...@@ -940,6 +940,14 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info) ...@@ -940,6 +940,14 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
int ret = 0; int ret = 0;
int slot; int slot;
/*
* We need to have subvol_sem write locked, to prevent races between
* concurrent tasks trying to enable quotas, because we will unlock
* and relock qgroup_ioctl_lock before setting fs_info->quota_root
* and before setting BTRFS_FS_QUOTA_ENABLED.
*/
lockdep_assert_held_write(&fs_info->subvol_sem);
mutex_lock(&fs_info->qgroup_ioctl_lock); mutex_lock(&fs_info->qgroup_ioctl_lock);
if (fs_info->quota_root) if (fs_info->quota_root)
goto out; goto out;
...@@ -1117,8 +1125,19 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info) ...@@ -1117,8 +1125,19 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
goto out_free_path; goto out_free_path;
} }
mutex_unlock(&fs_info->qgroup_ioctl_lock);
/*
* Commit the transaction while not holding qgroup_ioctl_lock, to avoid
* a deadlock with tasks concurrently doing other qgroup operations, such
* adding/removing qgroups or adding/deleting qgroup relations for example,
* because all qgroup operations first start or join a transaction and then
* lock the qgroup_ioctl_lock mutex.
* We are safe from a concurrent task trying to enable quotas, by calling
* this function, since we are serialized by fs_info->subvol_sem.
*/
ret = btrfs_commit_transaction(trans); ret = btrfs_commit_transaction(trans);
trans = NULL; trans = NULL;
mutex_lock(&fs_info->qgroup_ioctl_lock);
if (ret) if (ret)
goto out_free_path; goto out_free_path;
...@@ -3142,6 +3161,7 @@ static int qgroup_rescan_leaf(struct btrfs_trans_handle *trans, ...@@ -3142,6 +3161,7 @@ static int qgroup_rescan_leaf(struct btrfs_trans_handle *trans,
struct btrfs_path *path) struct btrfs_path *path)
{ {
struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_root *extent_root;
struct btrfs_key found; struct btrfs_key found;
struct extent_buffer *scratch_leaf = NULL; struct extent_buffer *scratch_leaf = NULL;
struct ulist *roots = NULL; struct ulist *roots = NULL;
...@@ -3151,7 +3171,9 @@ static int qgroup_rescan_leaf(struct btrfs_trans_handle *trans, ...@@ -3151,7 +3171,9 @@ static int qgroup_rescan_leaf(struct btrfs_trans_handle *trans,
int ret; int ret;
mutex_lock(&fs_info->qgroup_rescan_lock); mutex_lock(&fs_info->qgroup_rescan_lock);
ret = btrfs_search_slot_for_read(fs_info->extent_root, extent_root = btrfs_extent_root(fs_info,
fs_info->qgroup_rescan_progress.objectid);
ret = btrfs_search_slot_for_read(extent_root,
&fs_info->qgroup_rescan_progress, &fs_info->qgroup_rescan_progress,
path, 1, 0); path, 1, 0);
......
此差异已折叠。
此差异已折叠。
...@@ -439,7 +439,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode, ...@@ -439,7 +439,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
break; break;
} }
next_key_min_offset = key.offset + datal; next_key_min_offset = key.offset + datal;
size = btrfs_item_size_nr(leaf, slot); size = btrfs_item_size(leaf, slot);
read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf, slot), read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf, slot),
size); size);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -123,7 +123,7 @@ void btrfs_clear_space_info_full(struct btrfs_fs_info *info); ...@@ -123,7 +123,7 @@ void btrfs_clear_space_info_full(struct btrfs_fs_info *info);
void btrfs_dump_space_info(struct btrfs_fs_info *fs_info, void btrfs_dump_space_info(struct btrfs_fs_info *fs_info,
struct btrfs_space_info *info, u64 bytes, struct btrfs_space_info *info, u64 bytes,
int dump_block_groups); int dump_block_groups);
int btrfs_reserve_metadata_bytes(struct btrfs_root *root, int btrfs_reserve_metadata_bytes(struct btrfs_fs_info *fs_info,
struct btrfs_block_rsv *block_rsv, struct btrfs_block_rsv *block_rsv,
u64 orig_bytes, u64 orig_bytes,
enum btrfs_reserve_flush_enum flush); enum btrfs_reserve_flush_enum flush);
......
...@@ -1842,7 +1842,6 @@ static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info, ...@@ -1842,7 +1842,6 @@ static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info,
btrfs_workqueue_set_max(fs_info->endio_write_workers, new_pool_size); btrfs_workqueue_set_max(fs_info->endio_write_workers, new_pool_size);
btrfs_workqueue_set_max(fs_info->endio_freespace_worker, new_pool_size); btrfs_workqueue_set_max(fs_info->endio_freespace_worker, new_pool_size);
btrfs_workqueue_set_max(fs_info->delayed_workers, new_pool_size); btrfs_workqueue_set_max(fs_info->delayed_workers, new_pool_size);
btrfs_workqueue_set_max(fs_info->readahead_workers, new_pool_size);
btrfs_workqueue_set_max(fs_info->scrub_wr_completion_workers, btrfs_workqueue_set_max(fs_info->scrub_wr_completion_workers,
new_pool_size); new_pool_size);
} }
......
此差异已折叠。
...@@ -204,6 +204,7 @@ void btrfs_free_dummy_root(struct btrfs_root *root) ...@@ -204,6 +204,7 @@ void btrfs_free_dummy_root(struct btrfs_root *root)
/* Will be freed by btrfs_free_fs_roots */ /* Will be freed by btrfs_free_fs_roots */
if (WARN_ON(test_bit(BTRFS_ROOT_IN_RADIX, &root->state))) if (WARN_ON(test_bit(BTRFS_ROOT_IN_RADIX, &root->state)))
return; return;
btrfs_global_root_delete(root);
btrfs_put_root(root); btrfs_put_root(root);
} }
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册