git.kernel.org

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

Pull btrfs updates from David Sterba: "This continues with work on code refactoring, sanity checks and space handling. There are some less user visible changes, nothing that would particularly stand out. User visible changes: - tree checker, more sanity checks of: - ROOT_ITEM (key, size, generation, level, alignment, flags) - EXTENT_ITEM and METADATA_ITEM checks (key, size, offset, alignment, refs) - tree block reference items - EXTENT_DATA_REF (key, hash, offset) - deprecate flag BTRFS_SUBVOL_CREATE_ASYNC for subvolume creation ioctl, scheduled removal in 5.7 - delete stale and unused UAPI definitions BTRFS_DEV_REPLACE_ITEM_STATE_* - improved export of debugging information available via existing sysfs directory structure - try harder to delete relations between qgroups and allow to delete orphan entries - remove unreliable space checks before relocation starts Core: - space handling: - improved ticket reservations and other high level logic in order to remove special cases - factor flushing infrastructure and use it for different contexts, allows to remove some special case handling - reduce metadata reservation when only updating inodes - reduce global block reserve minimum size (affects small filesystems) - improved overcommit logic wrt global block reserve - tests: - fix memory leaks in extent IO tree - catch all TRIM range Fixes: - fix ENOSPC errors, leading to transaction aborts, when cloning extents - several fixes for inode number cache (mount option inode_cache) - fix potential soft lockups during send when traversing large trees - fix unaligned access to space cache pages with SLUB debug on (PowerPC) Other: - refactoring public/private functions, moving to new or more appropriate files - defines converted to enums - error handling improvements - more assertions and comments - old code deletion" * tag 'for-5.4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: (138 commits) btrfs: Relinquish CPUs in btrfs_compare_trees btrfs: Don't assign retval of btrfs_try_tree_write_lock/btrfs_tree_read_lock_atomic btrfs: create structure to encode checksum type and length btrfs: turn checksum type define into an enum btrfs: add enospc debug messages for ticket failure btrfs: do not account global reserve in can_overcommit btrfs: use btrfs_try_granting_tickets in update_global_rsv btrfs: always reserve our entire size for the global reserve btrfs: change the minimum global reserve size btrfs: rename btrfs_space_info_add_old_bytes btrfs: remove orig_bytes from reserve_ticket btrfs: fix may_commit_transaction to deal with no partial filling btrfs: rework wake_all_tickets btrfs: refactor the ticket wakeup code btrfs: stop partially refilling tickets when releasing space btrfs: add space reservation tracepoint for reserved bytes btrfs: roll tracepoint into btrfs_space_info_update helper btrfs: do not allow reservations if we have pending tickets btrfs: stop clearing EXTENT_DIRTY in inode I/O tree btrfs: treat RWF_{,D}SYNC writes as sync for CRCs ...

diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile
index 76a843198bcb6..82200dbca5ac4 100644
--- a/fs/btrfs/Makefile
+++ b/fs/btrfs/Makefile

@@ -11,7 +11,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.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 \

uuid-tree.o props.o free-space-tree.o tree-checker.o space-info.o \

- block-rsv.o delalloc-space.o

+ block-rsv.o delalloc-space.o block-group.o

btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o

btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o

@@ -12,9 +12,11 @@

#include "async-thread.h"

#include "ctree.h"

-#define WORK_DONE_BIT 0

-#define WORK_ORDER_DONE_BIT 1

-#define WORK_HIGH_PRIO_BIT 2

+enum {

+ WORK_DONE_BIT,

+ WORK_ORDER_DONE_BIT,

+ WORK_HIGH_PRIO_BIT,

+};

#define NO_THRESHOLD (-1)

#define DFT_THRESHOLD (32)

diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
new file mode 100644
index 0000000000000..bf7e3f23bba74
--- /dev/null
+++ b/fs/btrfs/block-group.c

@@ -0,0 +1,3173 @@

+// SPDX-License-Identifier: GPL-2.0

+

+#include "misc.h"

+#include "ctree.h"

+#include "block-group.h"

+#include "space-info.h"

+#include "disk-io.h"

+#include "free-space-cache.h"

+#include "free-space-tree.h"

+#include "disk-io.h"

+#include "volumes.h"

+#include "transaction.h"

+#include "ref-verify.h"

+#include "sysfs.h"

+#include "tree-log.h"

+#include "delalloc-space.h"

+

+/*

+ * Return target flags in extended format or 0 if restripe for this chunk_type

+ * is not in progress

+ *

+ * Should be called with balance_lock held

+ */

+static u64 get_restripe_target(struct btrfs_fs_info *fs_info, u64 flags)

+{

+ struct btrfs_balance_control *bctl = fs_info->balance_ctl;

+ u64 target = 0;

+

+ if (!bctl)

+ return 0;

+

+ if (flags & BTRFS_BLOCK_GROUP_DATA &&

+ bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) {

+ target = BTRFS_BLOCK_GROUP_DATA | bctl->data.target;

+ } else if (flags & BTRFS_BLOCK_GROUP_SYSTEM &&

+ bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) {

+ target = BTRFS_BLOCK_GROUP_SYSTEM | bctl->sys.target;

+ } else if (flags & BTRFS_BLOCK_GROUP_METADATA &&

+ bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) {

+ target = BTRFS_BLOCK_GROUP_METADATA | bctl->meta.target;

+ }

+

+ return target;

+}

+

+/*

+ * @flags: available profiles in extended format (see ctree.h)

+ *

+ * Return reduced profile in chunk format. If profile changing is in progress

+ * (either running or paused) picks the target profile (if it's already

+ * available), otherwise falls back to plain reducing.

+ */

+static u64 btrfs_reduce_alloc_profile(struct btrfs_fs_info *fs_info, u64 flags)

+{

+ u64 num_devices = fs_info->fs_devices->rw_devices;

+ u64 target;

+ u64 raid_type;

+ u64 allowed = 0;

+

+ /*

+ * See if restripe for this chunk_type is in progress, if so try to

+ * reduce to the target profile

+ */

+ spin_lock(&fs_info->balance_lock);

+ target = get_restripe_target(fs_info, flags);

+ if (target) {

+ /* Pick target profile only if it's already available */

+ if ((flags & target) & BTRFS_EXTENDED_PROFILE_MASK) {

+ spin_unlock(&fs_info->balance_lock);

+ return extended_to_chunk(target);

+ }

+ }

+ spin_unlock(&fs_info->balance_lock);

+

+ /* First, mask out the RAID levels which aren't possible */

+ for (raid_type = 0; raid_type < BTRFS_NR_RAID_TYPES; raid_type++) {

+ if (num_devices >= btrfs_raid_array[raid_type].devs_min)

+ allowed |= btrfs_raid_array[raid_type].bg_flag;

+ }

+ allowed &= flags;

+

+ if (allowed & BTRFS_BLOCK_GROUP_RAID6)

+ allowed = BTRFS_BLOCK_GROUP_RAID6;

+ else if (allowed & BTRFS_BLOCK_GROUP_RAID5)

+ allowed = BTRFS_BLOCK_GROUP_RAID5;

+ else if (allowed & BTRFS_BLOCK_GROUP_RAID10)

+ allowed = BTRFS_BLOCK_GROUP_RAID10;

+ else if (allowed & BTRFS_BLOCK_GROUP_RAID1)

+ allowed = BTRFS_BLOCK_GROUP_RAID1;

+ else if (allowed & BTRFS_BLOCK_GROUP_RAID0)

+ allowed = BTRFS_BLOCK_GROUP_RAID0;

+

+ flags &= ~BTRFS_BLOCK_GROUP_PROFILE_MASK;

+

+ return extended_to_chunk(flags | allowed);

+}

+

+static u64 get_alloc_profile(struct btrfs_fs_info *fs_info, u64 orig_flags)

+{

+ unsigned seq;

+ u64 flags;

+

+ do {

+ flags = orig_flags;

+ seq = read_seqbegin(&fs_info->profiles_lock);

+

+ if (flags & BTRFS_BLOCK_GROUP_DATA)

+ flags |= fs_info->avail_data_alloc_bits;

+ else if (flags & BTRFS_BLOCK_GROUP_SYSTEM)

+ flags |= fs_info->avail_system_alloc_bits;

+ else if (flags & BTRFS_BLOCK_GROUP_METADATA)

+ flags |= fs_info->avail_metadata_alloc_bits;

+ } while (read_seqretry(&fs_info->profiles_lock, seq));

+

+ return btrfs_reduce_alloc_profile(fs_info, flags);

+}

+

+u64 btrfs_get_alloc_profile(struct btrfs_fs_info *fs_info, u64 orig_flags)

+{

+ return get_alloc_profile(fs_info, orig_flags);

+}

+

+void btrfs_get_block_group(struct btrfs_block_group_cache *cache)

+{

+ atomic_inc(&cache->count);

+}

+

+void btrfs_put_block_group(struct btrfs_block_group_cache *cache)

+{

+ if (atomic_dec_and_test(&cache->count)) {

+ WARN_ON(cache->pinned > 0);

+ WARN_ON(cache->reserved > 0);

+

+ /*

+ * If not empty, someone is still holding mutex of

+ * full_stripe_lock, which can only be released by caller.

+ * And it will definitely cause use-after-free when caller

+ * tries to release full stripe lock.

+ *

+ * No better way to resolve, but only to warn.

+ */

+ WARN_ON(!RB_EMPTY_ROOT(&cache->full_stripe_locks_root.root));

+ kfree(cache->free_space_ctl);

+ kfree(cache);

+ }

+}

+

+/*

+ * This adds the block group to the fs_info rb tree for the block group cache

+ */

+static int btrfs_add_block_group_cache(struct btrfs_fs_info *info,

+ struct btrfs_block_group_cache *block_group)

+{

+ struct rb_node **p;

+ struct rb_node *parent = NULL;

+ struct btrfs_block_group_cache *cache;

+

+ spin_lock(&info->block_group_cache_lock);

+ p = &info->block_group_cache_tree.rb_node;

+

+ while (*p) {

+ parent = *p;

+ cache = rb_entry(parent, struct btrfs_block_group_cache,

+ cache_node);

+ if (block_group->key.objectid < cache->key.objectid) {

+ p = &(*p)->rb_left;

+ } else if (block_group->key.objectid > cache->key.objectid) {

+ p = &(*p)->rb_right;

+ } else {

+ spin_unlock(&info->block_group_cache_lock);

+ return -EEXIST;

+ }

+ }

+

+ rb_link_node(&block_group->cache_node, parent, p);

+ rb_insert_color(&block_group->cache_node,

+ &info->block_group_cache_tree);

+

+ if (info->first_logical_byte > block_group->key.objectid)

+ info->first_logical_byte = block_group->key.objectid;

+

+ spin_unlock(&info->block_group_cache_lock);

+

+ return 0;

+}

+

+/*

+ * This will return the block group at or after bytenr if contains is 0, else

+ * it will return the block group that contains the bytenr

+ */

+static struct btrfs_block_group_cache *block_group_cache_tree_search(

+ struct btrfs_fs_info *info, u64 bytenr, int contains)

+{

+ struct btrfs_block_group_cache *cache, *ret = NULL;

+ struct rb_node *n;

+ u64 end, start;

+

+ spin_lock(&info->block_group_cache_lock);

+ n = info->block_group_cache_tree.rb_node;

+

+ while (n) {

+ cache = rb_entry(n, struct btrfs_block_group_cache,

+ cache_node);

+ end = cache->key.objectid + cache->key.offset - 1;

+ start = cache->key.objectid;

+

+ if (bytenr < start) {

+ if (!contains && (!ret || start < ret->key.objectid))

+ ret = cache;

+ n = n->rb_left;

+ } else if (bytenr > start) {

+ if (contains && bytenr <= end) {

+ ret = cache;

+ break;

+ }

+ n = n->rb_right;

+ } else {

+ ret = cache;

+ break;

+ }

+ }

+ if (ret) {

+ btrfs_get_block_group(ret);

+ if (bytenr == 0 && info->first_logical_byte > ret->key.objectid)

+ info->first_logical_byte = ret->key.objectid;

+ }

+ spin_unlock(&info->block_group_cache_lock);

+

+ return ret;

+}

+

+/*

+ * Return the block group that starts at or after bytenr

+ */

+struct btrfs_block_group_cache *btrfs_lookup_first_block_group(

+ struct btrfs_fs_info *info, u64 bytenr)

+{

+ return block_group_cache_tree_search(info, bytenr, 0);

+}

+

+/*

+ * Return the block group that contains the given bytenr

+ */

+struct btrfs_block_group_cache *btrfs_lookup_block_group(

+ struct btrfs_fs_info *info, u64 bytenr)

+{

+ return block_group_cache_tree_search(info, bytenr, 1);

+}

+

+struct btrfs_block_group_cache *btrfs_next_block_group(

+ struct btrfs_block_group_cache *cache)

+{

+ struct btrfs_fs_info *fs_info = cache->fs_info;

+ struct rb_node *node;

+

+ spin_lock(&fs_info->block_group_cache_lock);

+

+ /* If our block group was removed, we need a full search. */

+ if (RB_EMPTY_NODE(&cache->cache_node)) {

+ const u64 next_bytenr = cache->key.objectid + cache->key.offset;

+

+ spin_unlock(&fs_info->block_group_cache_lock);

+ btrfs_put_block_group(cache);

+ cache = btrfs_lookup_first_block_group(fs_info, next_bytenr); return cache;

+ }

+ node = rb_next(&cache->cache_node);

+ btrfs_put_block_group(cache);

+ if (node) {

+ cache = rb_entry(node, struct btrfs_block_group_cache,

+ cache_node);

+ btrfs_get_block_group(cache);

+ } else

+ cache = NULL;

+ spin_unlock(&fs_info->block_group_cache_lock);

+ return cache;

+}

+

+bool btrfs_inc_nocow_writers(struct btrfs_fs_info *fs_info, u64 bytenr)

+{

+ struct btrfs_block_group_cache *bg;

+ bool ret = true;

+

+ bg = btrfs_lookup_block_group(fs_info, bytenr);

+ if (!bg)

+ return false;

+

+ spin_lock(&bg->lock);

+ if (bg->ro)

+ ret = false;

+ else

+ atomic_inc(&bg->nocow_writers);

+ spin_unlock(&bg->lock);

+

+ /* No put on block group, done by btrfs_dec_nocow_writers */

+ if (!ret)

+ btrfs_put_block_group(bg);

+

+ return ret;

+}

+

+void btrfs_dec_nocow_writers(struct btrfs_fs_info *fs_info, u64 bytenr)

+{

+ struct btrfs_block_group_cache *bg;

+

+ bg = btrfs_lookup_block_group(fs_info, bytenr);

+ ASSERT(bg);

+ if (atomic_dec_and_test(&bg->nocow_writers))

+ wake_up_var(&bg->nocow_writers);

+ /*

+ * Once for our lookup and once for the lookup done by a previous call

+ * to btrfs_inc_nocow_writers()

+ */

+ btrfs_put_block_group(bg);

+ btrfs_put_block_group(bg);

+}

+

+void btrfs_wait_nocow_writers(struct btrfs_block_group_cache *bg)

+{

+ wait_var_event(&bg->nocow_writers, !atomic_read(&bg->nocow_writers));

+}

+

+void btrfs_dec_block_group_reservations(struct btrfs_fs_info *fs_info,

+ const u64 start)

+{

+ struct btrfs_block_group_cache *bg;

+

+ bg = btrfs_lookup_block_group(fs_info, start);

+ ASSERT(bg);

+ if (atomic_dec_and_test(&bg->reservations))

+ wake_up_var(&bg->reservations);

+ btrfs_put_block_group(bg);

+}

+

+void btrfs_wait_block_group_reservations(struct btrfs_block_group_cache *bg)

+{

+ struct btrfs_space_info *space_info = bg->space_info;

+

+ ASSERT(bg->ro);

+

+ if (!(bg->flags & BTRFS_BLOCK_GROUP_DATA))

+ return;

+

+ /*

+ * Our block group is read only but before we set it to read only,

+ * some task might have had allocated an extent from it already, but it

+ * has not yet created a respective ordered extent (and added it to a

+ * root's list of ordered extents).

+ * Therefore wait for any task currently allocating extents, since the

+ * block group's reservations counter is incremented while a read lock

+ * on the groups' semaphore is held and decremented after releasing

+ * the read access on that semaphore and creating the ordered extent.

+ */

+ down_write(&space_info->groups_sem);

+ up_write(&space_info->groups_sem);

+

+ wait_var_event(&bg->reservations, !atomic_read(&bg->reservations));

+}

+

+struct btrfs_caching_control *btrfs_get_caching_control(

+ struct btrfs_block_group_cache *cache)

+{

+ struct btrfs_caching_control *ctl;

+

+ spin_lock(&cache->lock);

+ if (!cache->caching_ctl) {

+ spin_unlock(&cache->lock);

+ return NULL;

+ }

+

+ ctl = cache->caching_ctl;

+ refcount_inc(&ctl->count);

+ spin_unlock(&cache->lock);

+ return ctl;

+}

+

+void btrfs_put_caching_control(struct btrfs_caching_control *ctl)

+{

+ if (refcount_dec_and_test(&ctl->count))

+ kfree(ctl);

+}

+

+/*

+ * When we wait for progress in the block group caching, its because our

+ * allocation attempt failed at least once. So, we must sleep and let some

+ * progress happen before we try again.

+ *

+ * This function will sleep at least once waiting for new free space to show

+ * up, and then it will check the block group free space numbers for our min

+ * num_bytes. Another option is to have it go ahead and look in the rbtree for

+ * a free extent of a given size, but this is a good start.

+ *

+ * Callers of this must check if cache->cached == BTRFS_CACHE_ERROR before using

+ * any of the information in this block group.

+ */

+void btrfs_wait_block_group_cache_progress(struct btrfs_block_group_cache *cache,

+ u64 num_bytes)

+{

+ struct btrfs_caching_control *caching_ctl;

+

+ caching_ctl = btrfs_get_caching_control(cache);

+ if (!caching_ctl)

+ return;

+

+ wait_event(caching_ctl->wait, btrfs_block_group_cache_done(cache) ||

+ (cache->free_space_ctl->free_space >= num_bytes));

+

+ btrfs_put_caching_control(caching_ctl);

+}

+

+int btrfs_wait_block_group_cache_done(struct btrfs_block_group_cache *cache)

+{

+ struct btrfs_caching_control *caching_ctl;

+ int ret = 0;

+

+ caching_ctl = btrfs_get_caching_control(cache);

+ if (!caching_ctl)

+ return (cache->cached == BTRFS_CACHE_ERROR) ? -EIO : 0;

+

+ wait_event(caching_ctl->wait, btrfs_block_group_cache_done(cache));

+ if (cache->cached == BTRFS_CACHE_ERROR)

+ ret = -EIO;

+ btrfs_put_caching_control(caching_ctl);

+ return ret;

+}

+

+#ifdef CONFIG_BTRFS_DEBUG

+static void fragment_free_space(struct btrfs_block_group_cache *block_group)

+{

+ struct btrfs_fs_info *fs_info = block_group->fs_info;

+ u64 start = block_group->key.objectid;

+ u64 len = block_group->key.offset;

+ u64 chunk = block_group->flags & BTRFS_BLOCK_GROUP_METADATA ?

+ fs_info->nodesize : fs_info->sectorsize;

+ u64 step = chunk << 1;

+

+ while (len > chunk) {

+ btrfs_remove_free_space(block_group, start, chunk);

+ start += step;

+ if (len < step)

+ len = 0;

+ else

+ len -= step;

+ }

+}

+#endif

+

+/*

+ * This is only called by btrfs_cache_block_group, since we could have freed

+ * extents we need to check the pinned_extents for any extents that can't be

+ * used yet since their free space will be released as soon as the transaction

+ * commits.

+ */

+u64 add_new_free_space(struct btrfs_block_group_cache *block_group,

+ u64 start, u64 end)

+{

+ struct btrfs_fs_info *info = block_group->fs_info;

+ u64 extent_start, extent_end, size, total_added = 0;

+ int ret;

+

+ while (start < end) {

+ ret = find_first_extent_bit(info->pinned_extents, start,

+ &extent_start, &extent_end,

+ EXTENT_DIRTY | EXTENT_UPTODATE,

+ NULL);

+ if (ret)

+ break;

+

+ if (extent_start <= start) {

+ start = extent_end + 1;

+ } else if (extent_start > start && extent_start < end) {

+ size = extent_start - start;

+ total_added += size;

+ ret = btrfs_add_free_space(block_group, start,

+ size);

+ BUG_ON(ret); /* -ENOMEM or logic error */

+ start = extent_end + 1;

+ } else {

+ break;

+ }

+ }

+

+ if (start < end) {

+ size = end - start;

+ total_added += size;

+ ret = btrfs_add_free_space(block_group, start, size);

+ BUG_ON(ret); /* -ENOMEM or logic error */

+ }

+

+ return total_added;

+}

+

+static int load_extent_tree_free(struct btrfs_caching_control *caching_ctl)

+{

+ struct btrfs_block_group_cache *block_group = caching_ctl->block_group;

+ struct btrfs_fs_info *fs_info = block_group->fs_info;

+ struct btrfs_root *extent_root = fs_info->extent_root;

+ struct btrfs_path *path;

+ struct extent_buffer *leaf;

+ struct btrfs_key key;

+ u64 total_found = 0;

+ u64 last = 0;

+ u32 nritems;

+ int ret;

+ bool wakeup = true;

+

+ path = btrfs_alloc_path();

+ if (!path)

+ return -ENOMEM;

+

+ last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET);

+

+#ifdef CONFIG_BTRFS_DEBUG

+ /*

+ * If we're fragmenting we don't want to make anybody think we can

+ * allocate from this block group until we've had a chance to fragment

+ * the free space.

+ */

+ if (btrfs_should_fragment_free_space(block_group))

+ wakeup = false;

+#endif

+ /*

+ * We don't want to deadlock with somebody trying to allocate a new

+ * extent for the extent root while also trying to search the extent

+ * root to add free space. So we skip locking and search the commit

+ * root, since its read-only

+ */

+ path->skip_locking = 1;

+ path->search_commit_root = 1;

+ path->reada = READA_FORWARD;

+

+ key.objectid = last;

+ key.offset = 0;

+ key.type = BTRFS_EXTENT_ITEM_KEY;

+

+next:

+ ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);

+ if (ret < 0)

+ goto out;

+

+ leaf = path->nodes[0];

+ nritems = btrfs_header_nritems(leaf);

+

+ while (1) {

+ if (btrfs_fs_closing(fs_info) > 1) {

+ last = (u64)-1;

+ break;

+ }

+

+ if (path->slots[0] < nritems) {

+ btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);

+ } else {

+ ret = btrfs_find_next_key(extent_root, path, &key, 0, 0);

+ if (ret)

+ break;

+

+ if (need_resched() ||

+ rwsem_is_contended(&fs_info->commit_root_sem)) {

+ if (wakeup)

+ caching_ctl->progress = last;

+ btrfs_release_path(path);

+ up_read(&fs_info->commit_root_sem);

+ mutex_unlock(&caching_ctl->mutex);

+ cond_resched();

+ mutex_lock(&caching_ctl->mutex);

+ down_read(&fs_info->commit_root_sem);

+ goto next;

+ }

+

+ ret = btrfs_next_leaf(extent_root, path);

+ if (ret < 0)

+ goto out;

+ if (ret)

+ break;

+ leaf = path->nodes[0];

+ nritems = btrfs_header_nritems(leaf);

+ continue;

+ }

+

+ if (key.objectid < last) {

+ key.objectid = last;

+ key.offset = 0;

+ key.type = BTRFS_EXTENT_ITEM_KEY;

+

+ if (wakeup)

+ caching_ctl->progress = last;

+ btrfs_release_path(path);

+ goto next;

+ }

+

+ if (key.objectid < block_group->key.objectid) {

+ path->slots[0]++;

+ continue;

+ }

+

+ if (key.objectid >= block_group->key.objectid +

+ block_group->key.offset)

+ break;

+

+ if (key.type == BTRFS_EXTENT_ITEM_KEY ||

+ key.type == BTRFS_METADATA_ITEM_KEY) {

+ total_found += add_new_free_space(block_group, last,

+ key.objectid);

+ if (key.type == BTRFS_METADATA_ITEM_KEY)

+ last = key.objectid +

+ fs_info->nodesize;

+ else

+ last = key.objectid + key.offset;

+

+ if (total_found > CACHING_CTL_WAKE_UP) {

+ total_found = 0;

+ if (wakeup)

+ wake_up(&caching_ctl->wait);

+ }

+ }

+ path->slots[0]++;

+ }

+ ret = 0;

+

+ total_found += add_new_free_space(block_group, last,

+ block_group->key.objectid +

+ block_group->key.offset);

+ caching_ctl->progress = (u64)-1;

+

+out:

+ btrfs_free_path(path);

+ return ret;

+}

+

+static noinline void caching_thread(struct btrfs_work *work)

+{

+ struct btrfs_block_group_cache *block_group;

+ struct btrfs_fs_info *fs_info;

+ struct btrfs_caching_control *caching_ctl;

+ int ret;

+

+ caching_ctl = container_of(work, struct btrfs_caching_control, work);

+ block_group = caching_ctl->block_group;

+ fs_info = block_group->fs_info;

+

+ mutex_lock(&caching_ctl->mutex);

+ down_read(&fs_info->commit_root_sem);

+

+ if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE))

+ ret = load_free_space_tree(caching_ctl);

+ else

+ ret = load_extent_tree_free(caching_ctl);

+

+ spin_lock(&block_group->lock);

+ block_group->caching_ctl = NULL;

+ block_group->cached = ret ? BTRFS_CACHE_ERROR : BTRFS_CACHE_FINISHED;

+ spin_unlock(&block_group->lock);

+

+#ifdef CONFIG_BTRFS_DEBUG

+ if (btrfs_should_fragment_free_space(block_group)) {

+ u64 bytes_used;

+

+ spin_lock(&block_group->space_info->lock);

+ spin_lock(&block_group->lock);

+ bytes_used = block_group->key.offset -

+ btrfs_block_group_used(&block_group->item);

+ block_group->space_info->bytes_used += bytes_used >> 1;

+ spin_unlock(&block_group->lock);

+ spin_unlock(&block_group->space_info->lock);

+ fragment_free_space(block_group);

+ }

+#endif

+

+ caching_ctl->progress = (u64)-1;

+

+ up_read(&fs_info->commit_root_sem);

+ btrfs_free_excluded_extents(block_group);

+ mutex_unlock(&caching_ctl->mutex);

+

+ wake_up(&caching_ctl->wait);

+

+ btrfs_put_caching_control(caching_ctl);

+ btrfs_put_block_group(block_group);

+}

+

+int btrfs_cache_block_group(struct btrfs_block_group_cache *cache,

+ int load_cache_only)

+{

+ DEFINE_WAIT(wait);

+ struct btrfs_fs_info *fs_info = cache->fs_info;

+ struct btrfs_caching_control *caching_ctl;

+ int ret = 0;

+

+ caching_ctl = kzalloc(sizeof(*caching_ctl), GFP_NOFS);

+ if (!caching_ctl)

+ return -ENOMEM;

+

+ INIT_LIST_HEAD(&caching_ctl->list);

+ mutex_init(&caching_ctl->mutex);

+ init_waitqueue_head(&caching_ctl->wait);

+ caching_ctl->block_group = cache;

+ caching_ctl->progress = cache->key.objectid;

+ refcount_set(&caching_ctl->count, 1);

+ btrfs_init_work(&caching_ctl->work, btrfs_cache_helper,

+ caching_thread, NULL, NULL);

+

+ spin_lock(&cache->lock);

+ /*

+ * This should be a rare occasion, but this could happen I think in the

+ * case where one thread starts to load the space cache info, and then

+ * some other thread starts a transaction commit which tries to do an

+ * allocation while the other thread is still loading the space cache

+ * info. The previous loop should have kept us from choosing this block

+ * group, but if we've moved to the state where we will wait on caching

+ * block groups we need to first check if we're doing a fast load here,

+ * so we can wait for it to finish, otherwise we could end up allocating

+ * from a block group who's cache gets evicted for one reason or

+ * another.

+ */

+ while (cache->cached == BTRFS_CACHE_FAST) {

+ struct btrfs_caching_control *ctl;

+

+ ctl = cache->caching_ctl;

+ refcount_inc(&ctl->count);

+ prepare_to_wait(&ctl->wait, &wait, TASK_UNINTERRUPTIBLE);

+ spin_unlock(&cache->lock);

+

+ schedule();

+

+ finish_wait(&ctl->wait, &wait);

+ btrfs_put_caching_control(ctl);

+ spin_lock(&cache->lock);

+ }

+

+ if (cache->cached != BTRFS_CACHE_NO) {

+ spin_unlock(&cache->lock);

+ kfree(caching_ctl);

+ return 0;

+ }

+ WARN_ON(cache->caching_ctl);

+ cache->caching_ctl = caching_ctl;

+ cache->cached = BTRFS_CACHE_FAST;

+ spin_unlock(&cache->lock);

+

+ if (btrfs_test_opt(fs_info, SPACE_CACHE)) {

+ mutex_lock(&caching_ctl->mutex);

+ ret = load_free_space_cache(cache);

+

+ spin_lock(&cache->lock);

+ if (ret == 1) {

+ cache->caching_ctl = NULL;

+ cache->cached = BTRFS_CACHE_FINISHED;

+ cache->last_byte_to_unpin = (u64)-1;

+ caching_ctl->progress = (u64)-1;

+ } else {

+ if (load_cache_only) {

+ cache->caching_ctl = NULL;

+ cache->cached = BTRFS_CACHE_NO;

+ } else {

+ cache->cached = BTRFS_CACHE_STARTED;

+ cache->has_caching_ctl = 1;

+ }

+ }

+ spin_unlock(&cache->lock);

+#ifdef CONFIG_BTRFS_DEBUG

+ if (ret == 1 &&

+ btrfs_should_fragment_free_space(cache)) {

+ u64 bytes_used;

+

+ spin_lock(&cache->space_info->lock);

+ spin_lock(&cache->lock);

+ bytes_used = cache->key.offset -

+ btrfs_block_group_used(&cache->item);

+ cache->space_info->bytes_used += bytes_used >> 1;

+ spin_unlock(&cache->lock);

+ spin_unlock(&cache->space_info->lock);

+ fragment_free_space(cache);

+ }

+#endif

+ mutex_unlock(&caching_ctl->mutex);

+

+ wake_up(&caching_ctl->wait);

+ if (ret == 1) {

+ btrfs_put_caching_control(caching_ctl);

+ btrfs_free_excluded_extents(cache);

+ return 0;

+ }

+ } else {

+ /*

+ * We're either using the free space tree or no caching at all.

+ * Set cached to the appropriate value and wakeup any waiters.

+ */

+ spin_lock(&cache->lock);

+ if (load_cache_only) {

+ cache->caching_ctl = NULL;

+ cache->cached = BTRFS_CACHE_NO;

+ } else {

+ cache->cached = BTRFS_CACHE_STARTED;

+ cache->has_caching_ctl = 1;

+ }

+ spin_unlock(&cache->lock);

+ wake_up(&caching_ctl->wait);

+ }

+

+ if (load_cache_only) {

+ btrfs_put_caching_control(caching_ctl);

+ return 0;

+ }

+

+ down_write(&fs_info->commit_root_sem);

+ refcount_inc(&caching_ctl->count);

+ list_add_tail(&caching_ctl->list, &fs_info->caching_block_groups);

+ up_write(&fs_info->commit_root_sem);

+

+ btrfs_get_block_group(cache);

+

+ btrfs_queue_work(fs_info->caching_workers, &caching_ctl->work);

+

+ return ret;

+}

+

+static void clear_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)

+{

+ u64 extra_flags = chunk_to_extended(flags) &

+ BTRFS_EXTENDED_PROFILE_MASK;

+

+ write_seqlock(&fs_info->profiles_lock);

+ if (flags & BTRFS_BLOCK_GROUP_DATA)

+ fs_info->avail_data_alloc_bits &= ~extra_flags;

+ if (flags & BTRFS_BLOCK_GROUP_METADATA)

+ fs_info->avail_metadata_alloc_bits &= ~extra_flags;

+ if (flags & BTRFS_BLOCK_GROUP_SYSTEM)

+ fs_info->avail_system_alloc_bits &= ~extra_flags;

+ write_sequnlock(&fs_info->profiles_lock);

+}

+

+/*

+ * Clear incompat bits for the following feature(s):

+ *

+ * - RAID56 - in case there's neither RAID5 nor RAID6 profile block group

+ * in the whole filesystem

+ */

+static void clear_incompat_bg_bits(struct btrfs_fs_info *fs_info, u64 flags)

+{

+ if (flags & BTRFS_BLOCK_GROUP_RAID56_MASK) {

+ struct list_head *head = &fs_info->space_info;

+ struct btrfs_space_info *sinfo;

+

+ list_for_each_entry_rcu(sinfo, head, list) {

+ bool found = false;

+

+ down_read(&sinfo->groups_sem);

+ if (!list_empty(&sinfo->block_groups[BTRFS_RAID_RAID5]))

+ found = true;

+ if (!list_empty(&sinfo->block_groups[BTRFS_RAID_RAID6]))

+ found = true;

+ up_read(&sinfo->groups_sem);

+

+ if (found)

+ return;

+ }

+ btrfs_clear_fs_incompat(fs_info, RAID56);

+ }

+}

+

+int btrfs_remove_block_group(struct btrfs_trans_handle *trans,

+ u64 group_start, struct extent_map *em)

+{

+ struct btrfs_fs_info *fs_info = trans->fs_info;

+ struct btrfs_root *root = fs_info->extent_root;

+ struct btrfs_path *path;

+ struct btrfs_block_group_cache *block_group;

+ struct btrfs_free_cluster *cluster;

+ struct btrfs_root *tree_root = fs_info->tree_root;

+ struct btrfs_key key;

+ struct inode *inode;

+ struct kobject *kobj = NULL;

+ int ret;

+ int index;

+ int factor;

+ struct btrfs_caching_control *caching_ctl = NULL;

+ bool remove_em;

+ bool remove_rsv = false;

+

+ block_group = btrfs_lookup_block_group(fs_info, group_start);

+ BUG_ON(!block_group);

+ BUG_ON(!block_group->ro);

+

+ trace_btrfs_remove_block_group(block_group);

+ /*

+ * Free the reserved super bytes from this block group before

+ * remove it.

+ */

+ btrfs_free_excluded_extents(block_group);

+ btrfs_free_ref_tree_range(fs_info, block_group->key.objectid,

+ block_group->key.offset);

+

+ memcpy(&key, &block_group->key, sizeof(key));

+ index = btrfs_bg_flags_to_raid_index(block_group->flags);

+ factor = btrfs_bg_type_to_factor(block_group->flags);

+

+ /* make sure this block group isn't part of an allocation cluster */

+ cluster = &fs_info->data_alloc_cluster;

+ spin_lock(&cluster->refill_lock);

+ btrfs_return_cluster_to_free_space(block_group, cluster);

+ spin_unlock(&cluster->refill_lock);

+

+ /*

+ * make sure this block group isn't part of a metadata

+ * allocation cluster

+ */

+ cluster = &fs_info->meta_alloc_cluster;

+ spin_lock(&cluster->refill_lock);

+ btrfs_return_cluster_to_free_space(block_group, cluster);

+ spin_unlock(&cluster->refill_lock);

+

+ path = btrfs_alloc_path();

+ if (!path) {

+ ret = -ENOMEM;

+ goto out;

+ }

+

+ /*

+ * get the inode first so any iput calls done for the io_list

+ * aren't the final iput (no unlinks allowed now)

+ */

+ inode = lookup_free_space_inode(block_group, path);

+

+ mutex_lock(&trans->transaction->cache_write_mutex);

+ /*

+ * Make sure our free space cache IO is done before removing the

+ * free space inode

+ */

+ spin_lock(&trans->transaction->dirty_bgs_lock);

+ if (!list_empty(&block_group->io_list)) {

+ list_del_init(&block_group->io_list);

+

+ WARN_ON(!IS_ERR(inode) && inode != block_group->io_ctl.inode);

+

+ spin_unlock(&trans->transaction->dirty_bgs_lock);

+ btrfs_wait_cache_io(trans, block_group, path);

+ btrfs_put_block_group(block_group);

+ spin_lock(&trans->transaction->dirty_bgs_lock);

+ }

+

+ if (!list_empty(&block_group->dirty_list)) {

+ list_del_init(&block_group->dirty_list);

+ remove_rsv = true;

+ btrfs_put_block_group(block_group);

+ }

+ spin_unlock(&trans->transaction->dirty_bgs_lock);

+ mutex_unlock(&trans->transaction->cache_write_mutex);

+

+ if (!IS_ERR(inode)) {

+ ret = btrfs_orphan_add(trans, BTRFS_I(inode));

+ if (ret) {

+ btrfs_add_delayed_iput(inode);

+ goto out;

+ }

+ clear_nlink(inode);

+ /* One for the block groups ref */

+ spin_lock(&block_group->lock);

+ if (block_group->iref) {

+ block_group->iref = 0;

+ block_group->inode = NULL;

+ spin_unlock(&block_group->lock);

+ iput(inode);

+ } else {

+ spin_unlock(&block_group->lock);

+ }

+ /* One for our lookup ref */

+ btrfs_add_delayed_iput(inode);

+ }

+

+ key.objectid = BTRFS_FREE_SPACE_OBJECTID;

+ key.offset = block_group->key.objectid;

+ key.type = 0;

+

+ ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1);

+ if (ret < 0)

+ goto out;

+ if (ret > 0)

+ btrfs_release_path(path);

+ if (ret == 0) {

+ ret = btrfs_del_item(trans, tree_root, path);

+ if (ret)

+ goto out;

+ btrfs_release_path(path);

+ }

+

+ spin_lock(&fs_info->block_group_cache_lock);

+ rb_erase(&block_group->cache_node,

+ &fs_info->block_group_cache_tree);

+ RB_CLEAR_NODE(&block_group->cache_node);

+

+ if (fs_info->first_logical_byte == block_group->key.objectid)

+ fs_info->first_logical_byte = (u64)-1;

+ spin_unlock(&fs_info->block_group_cache_lock);

+

+ down_write(&block_group->space_info->groups_sem);

+ /*

+ * we must use list_del_init so people can check to see if they

+ * are still on the list after taking the semaphore

+ */

+ list_del_init(&block_group->list);

+ if (list_empty(&block_group->space_info->block_groups[index])) {

+ kobj = block_group->space_info->block_group_kobjs[index];

+ block_group->space_info->block_group_kobjs[index] = NULL;

+ clear_avail_alloc_bits(fs_info, block_group->flags);

+ }

+ up_write(&block_group->space_info->groups_sem);

+ clear_incompat_bg_bits(fs_info, block_group->flags);

+ if (kobj) {

+ kobject_del(kobj);

+ kobject_put(kobj);

+ }

+

+ if (block_group->has_caching_ctl)

+ caching_ctl = btrfs_get_caching_control(block_group);

+ if (block_group->cached == BTRFS_CACHE_STARTED)

+ btrfs_wait_block_group_cache_done(block_group);

+ if (block_group->has_caching_ctl) {

+ down_write(&fs_info->commit_root_sem);

+ if (!caching_ctl) {

+ struct btrfs_caching_control *ctl;

+

+ list_for_each_entry(ctl,

+ &fs_info->caching_block_groups, list)

+ if (ctl->block_group == block_group) {

+ caching_ctl = ctl;

+ refcount_inc(&caching_ctl->count);

+ break;

+ }

+ }

+ if (caching_ctl)

+ list_del_init(&caching_ctl->list);

+ up_write(&fs_info->commit_root_sem);

+ if (caching_ctl) {

+ /* Once for the caching bgs list and once for us. */

+ btrfs_put_caching_control(caching_ctl);

+ btrfs_put_caching_control(caching_ctl);

+ }

+ }

+

+ spin_lock(&trans->transaction->dirty_bgs_lock);

+ WARN_ON(!list_empty(&block_group->dirty_list));

+ WARN_ON(!list_empty(&block_group->io_list));

+ spin_unlock(&trans->transaction->dirty_bgs_lock);

+

+ btrfs_remove_free_space_cache(block_group);

+

+ spin_lock(&block_group->space_info->lock);

+ list_del_init(&block_group->ro_list);

+

+ if (btrfs_test_opt(fs_info, ENOSPC_DEBUG)) {

+ WARN_ON(block_group->space_info->total_bytes

+ < block_group->key.offset);

+ WARN_ON(block_group->space_info->bytes_readonly

+ < block_group->key.offset);

+ WARN_ON(block_group->space_info->disk_total

+ < block_group->key.offset * factor);

+ }

+ block_group->space_info->total_bytes -= block_group->key.offset;

+ block_group->space_info->bytes_readonly -= block_group->key.offset;

+ block_group->space_info->disk_total -= block_group->key.offset * factor;

+

+ spin_unlock(&block_group->space_info->lock);

+

+ memcpy(&key, &block_group->key, sizeof(key));

+

+ mutex_lock(&fs_info->chunk_mutex);

+ spin_lock(&block_group->lock);

+ block_group->removed = 1;

+ /*

+ * At this point trimming can't start on this block group, because we

+ * removed the block group from the tree fs_info->block_group_cache_tree

+ * so no one can't find it anymore and even if someone already got this

+ * block group before we removed it from the rbtree, they have already

+ * incremented block_group->trimming - if they didn't, they won't find

+ * any free space entries because we already removed them all when we

+ * called btrfs_remove_free_space_cache().

+ *

+ * And we must not remove the extent map from the fs_info->mapping_tree

+ * to prevent the same logical address range and physical device space

+ * ranges from being reused for a new block group. This is because our

+ * fs trim operation (btrfs_trim_fs() / btrfs_ioctl_fitrim()) is

+ * completely transactionless, so while it is trimming a range the

+ * currently running transaction might finish and a new one start,

+ * allowing for new block groups to be created that can reuse the same

+ * physical device locations unless we take this special care.

+ *

+ * There may also be an implicit trim operation if the file system

+ * is mounted with -odiscard. The same protections must remain

+ * in place until the extents have been discarded completely when

+ * the transaction commit has completed.

+ */

+ remove_em = (atomic_read(&block_group->trimming) == 0);

+ spin_unlock(&block_group->lock);

+

+ mutex_unlock(&fs_info->chunk_mutex);

+

+ ret = remove_block_group_free_space(trans, block_group);

+ if (ret)

+ goto out;

+

+ btrfs_put_block_group(block_group);

+ btrfs_put_block_group(block_group);

+

+ ret = btrfs_search_slot(trans, root, &key, path, -1, 1);

+ if (ret > 0)

+ ret = -EIO;

+ if (ret < 0)

+ goto out;

+

+ ret = btrfs_del_item(trans, root, path);

+ if (ret)

+ goto out;

+

+ if (remove_em) {

+ struct extent_map_tree *em_tree;

+

+ em_tree = &fs_info->mapping_tree;

+ write_lock(&em_tree->lock);

+ remove_extent_mapping(em_tree, em);

+ write_unlock(&em_tree->lock);

+ /* once for the tree */

+ free_extent_map(em);

+ }

+out:

+ if (remove_rsv)

+ btrfs_delayed_refs_rsv_release(fs_info, 1);

+ btrfs_free_path(path);

+ return ret;

+}

+

+struct btrfs_trans_handle *btrfs_start_trans_remove_block_group(

+ struct btrfs_fs_info *fs_info, const u64 chunk_offset)

+{

+ struct extent_map_tree *em_tree = &fs_info->mapping_tree;

+ struct extent_map *em;

+ struct map_lookup *map;

+ unsigned int num_items;

+

+ read_lock(&em_tree->lock);

+ em = lookup_extent_mapping(em_tree, chunk_offset, 1);

+ read_unlock(&em_tree->lock);

+ ASSERT(em && em->start == chunk_offset);

+

+ /*

+ * We need to reserve 3 + N units from the metadata space info in order

+ * to remove a block group (done at btrfs_remove_chunk() and at

+ * btrfs_remove_block_group()), which are used for:

+ *

+ * 1 unit for adding the free space inode's orphan (located in the tree

+ * of tree roots).

+ * 1 unit for deleting the block group item (located in the extent

+ * tree).

+ * 1 unit for deleting the free space item (located in tree of tree

+ * roots).

+ * N units for deleting N device extent items corresponding to each

+ * stripe (located in the device tree).

+ *

+ * In order to remove a block group we also need to reserve units in the

+ * system space info in order to update the chunk tree (update one or

+ * more device items and remove one chunk item), but this is done at

+ * btrfs_remove_chunk() through a call to check_system_chunk().

+ */

+ map = em->map_lookup;

+ num_items = 3 + map->num_stripes;

+ free_extent_map(em);

+

+ return btrfs_start_transaction_fallback_global_rsv(fs_info->extent_root,

+ num_items, 1);

+}

+

+/*

+ * Mark block group @cache read-only, so later write won't happen to block

+ * group @cache.

+ *

+ * If @force is not set, this function will only mark the block group readonly

+ * if we have enough free space (1M) in other metadata/system block groups.

+ * If @force is not set, this function will mark the block group readonly

+ * without checking free space.

+ *

+ * NOTE: This function doesn't care if other block groups can contain all the

+ * data in this block group. That check should be done by relocation routine,

+ * not this function.

+ */

+static int inc_block_group_ro(struct btrfs_block_group_cache *cache, int force)

+{

+ struct btrfs_space_info *sinfo = cache->space_info;

+ u64 num_bytes;

+ u64 sinfo_used;

+ u64 min_allocable_bytes;

+ int ret = -ENOSPC;

+

+ /*

+ * We need some metadata space and system metadata space for

+ * allocating chunks in some corner cases until we force to set

+ * it to be readonly.

+ */

+ if ((sinfo->flags &

+ (BTRFS_BLOCK_GROUP_SYSTEM | BTRFS_BLOCK_GROUP_METADATA)) &&

+ !force)

+ min_allocable_bytes = SZ_1M;

+ else

+ min_allocable_bytes = 0;

+

+ spin_lock(&sinfo->lock);

+ spin_lock(&cache->lock);

+

+ if (cache->ro) {

+ cache->ro++;

+ ret = 0;

+ goto out;

+ }

+

+ num_bytes = cache->key.offset - cache->reserved - cache->pinned -

+ cache->bytes_super - btrfs_block_group_used(&cache->item);

+ sinfo_used = btrfs_space_info_used(sinfo, true);

+

+ /*

+ * sinfo_used + num_bytes should always <= sinfo->total_bytes.

+ *

+ * Here we make sure if we mark this bg RO, we still have enough

+ * free space as buffer (if min_allocable_bytes is not 0).

+ */

+ if (sinfo_used + num_bytes + min_allocable_bytes <=

+ sinfo->total_bytes) {

+ sinfo->bytes_readonly += num_bytes;

+ cache->ro++;

+ list_add_tail(&cache->ro_list, &sinfo->ro_bgs);

+ ret = 0;

+ }

+out:

+ spin_unlock(&cache->lock);

+ spin_unlock(&sinfo->lock);

+ if (ret == -ENOSPC && btrfs_test_opt(cache->fs_info, ENOSPC_DEBUG)) {

+ btrfs_info(cache->fs_info,

+ "unable to make block group %llu ro",

+ cache->key.objectid);

+ btrfs_info(cache->fs_info,

+ "sinfo_used=%llu bg_num_bytes=%llu min_allocable=%llu",

+ sinfo_used, num_bytes, min_allocable_bytes);

+ btrfs_dump_space_info(cache->fs_info, cache->space_info, 0, 0);

+ }

+ return ret;

+}

+

+/*

+ * Process the unused_bgs list and remove any that don't have any allocated

+ * space inside of them.

+ */

+void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)

+{

+ struct btrfs_block_group_cache *block_group;

+ struct btrfs_space_info *space_info;

+ struct btrfs_trans_handle *trans;

+ int ret = 0;

+

+ if (!test_bit(BTRFS_FS_OPEN, &fs_info->flags))

+ return;

+

+ spin_lock(&fs_info->unused_bgs_lock);

+ while (!list_empty(&fs_info->unused_bgs)) {

+ u64 start, end;

+ int trimming;

+

+ block_group = list_first_entry(&fs_info->unused_bgs,

+ struct btrfs_block_group_cache,

+ bg_list);

+ list_del_init(&block_group->bg_list);

+

+ space_info = block_group->space_info;

+

+ if (ret || btrfs_mixed_space_info(space_info)) {

+ btrfs_put_block_group(block_group);

+ continue;

+ }

+ spin_unlock(&fs_info->unused_bgs_lock);

+

+ mutex_lock(&fs_info->delete_unused_bgs_mutex);

+

+ /* Don't want to race with allocators so take the groups_sem */

+ down_write(&space_info->groups_sem);

+ spin_lock(&block_group->lock);

+ if (block_group->reserved || block_group->pinned ||

+ btrfs_block_group_used(&block_group->item) ||

+ block_group->ro ||

+ list_is_singular(&block_group->list)) {

+ /*

+ * We want to bail if we made new allocations or have

+ * outstanding allocations in this block group. We do

+ * the ro check in case balance is currently acting on

+ * this block group.

+ */

+ trace_btrfs_skip_unused_block_group(block_group);

+ spin_unlock(&block_group->lock);

+ up_write(&space_info->groups_sem);

+ goto next;

+ }

+ spin_unlock(&block_group->lock);

+

+ /* We don't want to force the issue, only flip if it's ok. */

+ ret = inc_block_group_ro(block_group, 0);

+ up_write(&space_info->groups_sem);

+ if (ret < 0) {

+ ret = 0;

+ goto next;

+ }

+

+ /*

+ * Want to do this before we do anything else so we can recover

+ * properly if we fail to join the transaction.

+ */

+ trans = btrfs_start_trans_remove_block_group(fs_info,

+ block_group->key.objectid);

+ if (IS_ERR(trans)) {

+ btrfs_dec_block_group_ro(block_group);

+ ret = PTR_ERR(trans);

+ goto next;

+ }

+

+ /*

+ * We could have pending pinned extents for this block group,

+ * just delete them, we don't care about them anymore.

+ */

+ start = block_group->key.objectid;

+ end = start + block_group->key.offset - 1;

+ /*

+ * Hold the unused_bg_unpin_mutex lock to avoid racing with

+ * btrfs_finish_extent_commit(). If we are at transaction N,

+ * another task might be running finish_extent_commit() for the

+ * previous transaction N - 1, and have seen a range belonging

+ * to the block group in freed_extents[] before we were able to

+ * clear the whole block group range from freed_extents[]. This

+ * means that task can lookup for the block group after we

+ * unpinned it from freed_extents[] and removed it, leading to

+ * a BUG_ON() at btrfs_unpin_extent_range().

+ */

+ mutex_lock(&fs_info->unused_bg_unpin_mutex);

+ ret = clear_extent_bits(&fs_info->freed_extents[0], start, end,

+ EXTENT_DIRTY);

+ if (ret) {

+ mutex_unlock(&fs_info->unused_bg_unpin_mutex);

+ btrfs_dec_block_group_ro(block_group);

+ goto end_trans;

+ }

+ ret = clear_extent_bits(&fs_info->freed_extents[1], start, end,

+ EXTENT_DIRTY);

+ if (ret) {

+ mutex_unlock(&fs_info->unused_bg_unpin_mutex);

+ btrfs_dec_block_group_ro(block_group);

+ goto end_trans;

+ }

+ mutex_unlock(&fs_info->unused_bg_unpin_mutex);

+

+ /* Reset pinned so btrfs_put_block_group doesn't complain */

+ spin_lock(&space_info->lock);

+ spin_lock(&block_group->lock);

+

+ btrfs_space_info_update_bytes_pinned(fs_info, space_info,

+ -block_group->pinned);

+ space_info->bytes_readonly += block_group->pinned;

+ percpu_counter_add_batch(&space_info->total_bytes_pinned,

+ -block_group->pinned,

+ BTRFS_TOTAL_BYTES_PINNED_BATCH);

+ block_group->pinned = 0;

+

+ spin_unlock(&block_group->lock);

+ spin_unlock(&space_info->lock);

+

+ /* DISCARD can flip during remount */

+ trimming = btrfs_test_opt(fs_info, DISCARD);

+

+ /* Implicit trim during transaction commit. */

+ if (trimming)

+ btrfs_get_block_group_trimming(block_group);

+

+ /*

+ * Btrfs_remove_chunk will abort the transaction if things go

+ * horribly wrong.

+ */

+ ret = btrfs_remove_chunk(trans, block_group->key.objectid);

+

+ if (ret) {

+ if (trimming)

+ btrfs_put_block_group_trimming(block_group);

+ goto end_trans;

+ }

+

+ /*

+ * If we're not mounted with -odiscard, we can just forget

+ * about this block group. Otherwise we'll need to wait

+ * until transaction commit to do the actual discard.

+ */

+ if (trimming) {

+ spin_lock(&fs_info->unused_bgs_lock);

+ /*

+ * A concurrent scrub might have added us to the list

+ * fs_info->unused_bgs, so use a list_move operation

+ * to add the block group to the deleted_bgs list.

+ */

+ list_move(&block_group->bg_list,

+ &trans->transaction->deleted_bgs);

+ spin_unlock(&fs_info->unused_bgs_lock);

+ btrfs_get_block_group(block_group);

+ }

+end_trans:

+ btrfs_end_transaction(trans);

+next:

+ mutex_unlock(&fs_info->delete_unused_bgs_mutex);

+ btrfs_put_block_group(block_group);

+ spin_lock(&fs_info->unused_bgs_lock);

+ }

+ spin_unlock(&fs_info->unused_bgs_lock);

+}

+

+void btrfs_mark_bg_unused(struct btrfs_block_group_cache *bg)

+{

+ struct btrfs_fs_info *fs_info = bg->fs_info;

+

+ spin_lock(&fs_info->unused_bgs_lock);

+ if (list_empty(&bg->bg_list)) {

+ btrfs_get_block_group(bg);

+ trace_btrfs_add_unused_block_group(bg);

+ list_add_tail(&bg->bg_list, &fs_info->unused_bgs);

+ }

+ spin_unlock(&fs_info->unused_bgs_lock);

+}

+

+static int find_first_block_group(struct btrfs_fs_info *fs_info,

+ struct btrfs_path *path,

+ struct btrfs_key *key)

+{

+ struct btrfs_root *root = fs_info->extent_root;

+ int ret = 0;

+ struct btrfs_key found_key;

+ struct extent_buffer *leaf;

+ struct btrfs_block_group_item bg;

+ u64 flags;

+ int slot;

+

+ ret = btrfs_search_slot(NULL, root, key, path, 0, 0);

+ if (ret < 0)

+ goto out;

+

+ while (1) {

+ slot = path->slots[0];

+ leaf = path->nodes[0];

+ if (slot >= btrfs_header_nritems(leaf)) {

+ ret = btrfs_next_leaf(root, path);

+ if (ret == 0)

+ continue;

+ if (ret < 0)

+ goto out;

+ break;

+ }

+ btrfs_item_key_to_cpu(leaf, &found_key, slot);

+

+ if (found_key.objectid >= key->objectid &&

+ found_key.type == BTRFS_BLOCK_GROUP_ITEM_KEY) {

+ struct extent_map_tree *em_tree;

+ struct extent_map *em;

+

+ em_tree = &root->fs_info->mapping_tree;

+ read_lock(&em_tree->lock);

+ em = lookup_extent_mapping(em_tree, found_key.objectid,

+ found_key.offset);

+ read_unlock(&em_tree->lock);

+ if (!em) {

+ btrfs_err(fs_info,

+ "logical %llu len %llu found bg but no related chunk",

+ found_key.objectid, found_key.offset);

+ ret = -ENOENT;

+ } else if (em->start != found_key.objectid ||

+ em->len != found_key.offset) {

+ btrfs_err(fs_info,

+ "block group %llu len %llu mismatch with chunk %llu len %llu",

+ found_key.objectid, found_key.offset,

+ em->start, em->len);

+ ret = -EUCLEAN;

+ } else {

+ read_extent_buffer(leaf, &bg,

+ btrfs_item_ptr_offset(leaf, slot),

+ sizeof(bg));

+ flags = btrfs_block_group_flags(&bg) &

+ BTRFS_BLOCK_GROUP_TYPE_MASK;

+

+ if (flags != (em->map_lookup->type &

+ BTRFS_BLOCK_GROUP_TYPE_MASK)) {

+ btrfs_err(fs_info,

+"block group %llu len %llu type flags 0x%llx mismatch with chunk type flags 0x%llx",

+ found_key.objectid,

+ found_key.offset, flags,

+ (BTRFS_BLOCK_GROUP_TYPE_MASK &

+ em->map_lookup->type));

+ ret = -EUCLEAN;

+ } else {

+ ret = 0;

+ }

+ }

+ free_extent_map(em);

+ goto out;

+ }

+ path->slots[0]++;

+ }

+out:

+ return ret;

+}

+

+static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)

+{

+ u64 extra_flags = chunk_to_extended(flags) &

+ BTRFS_EXTENDED_PROFILE_MASK;

+

+ write_seqlock(&fs_info->profiles_lock);

+ if (flags & BTRFS_BLOCK_GROUP_DATA)

+ fs_info->avail_data_alloc_bits |= extra_flags;

+ if (flags & BTRFS_BLOCK_GROUP_METADATA)

+ fs_info->avail_metadata_alloc_bits |= extra_flags;

+ if (flags & BTRFS_BLOCK_GROUP_SYSTEM)

+ fs_info->avail_system_alloc_bits |= extra_flags;

+ write_sequnlock(&fs_info->profiles_lock);

+}

+

+static int exclude_super_stripes(struct btrfs_block_group_cache *cache)

+{

+ struct btrfs_fs_info *fs_info = cache->fs_info;

+ u64 bytenr;

+ u64 *logical;

+ int stripe_len;

+ int i, nr, ret;

+

+ if (cache->key.objectid < BTRFS_SUPER_INFO_OFFSET) {

+ stripe_len = BTRFS_SUPER_INFO_OFFSET - cache->key.objectid;

+ cache->bytes_super += stripe_len;

+ ret = btrfs_add_excluded_extent(fs_info, cache->key.objectid,

+ stripe_len);

+ if (ret)

+ return ret;

+ }

+

+ for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {

+ bytenr = btrfs_sb_offset(i);

+ ret = btrfs_rmap_block(fs_info, cache->key.objectid,

+ bytenr, &logical, &nr, &stripe_len);

+ if (ret)

+ return ret;

+

+ while (nr--) {

+ u64 start, len;

+

+ if (logical[nr] > cache->key.objectid +

+ cache->key.offset)

+ continue;

+

+ if (logical[nr] + stripe_len <= cache->key.objectid)

+ continue;

+

+ start = logical[nr];

+ if (start < cache->key.objectid) {

+ start = cache->key.objectid;

+ len = (logical[nr] + stripe_len) - start;

+ } else {

+ len = min_t(u64, stripe_len,

+ cache->key.objectid +

+ cache->key.offset - start);

+ }

+

+ cache->bytes_super += len;

+ ret = btrfs_add_excluded_extent(fs_info, start, len);

+ if (ret) {

+ kfree(logical);

+ return ret;

+ }

+ }

+

+ kfree(logical);

+ }

+ return 0;

+}

+

+static void link_block_group(struct btrfs_block_group_cache *cache)

+{

+ struct btrfs_space_info *space_info = cache->space_info;

+ int index = btrfs_bg_flags_to_raid_index(cache->flags);

+ bool first = false;

+

+ down_write(&space_info->groups_sem);

+ if (list_empty(&space_info->block_groups[index]))

+ first = true;

+ list_add_tail(&cache->list, &space_info->block_groups[index]);

+ up_write(&space_info->groups_sem);

+

+ if (first)

+ btrfs_sysfs_add_block_group_type(cache);

+}

+

+static struct btrfs_block_group_cache *btrfs_create_block_group_cache(

+ struct btrfs_fs_info *fs_info, u64 start, u64 size)

+{

+ struct btrfs_block_group_cache *cache;

+

+ cache = kzalloc(sizeof(*cache), GFP_NOFS);

+ if (!cache)

+ return NULL;

+

+ cache->free_space_ctl = kzalloc(sizeof(*cache->free_space_ctl),

+ GFP_NOFS);

+ if (!cache->free_space_ctl) {

+ kfree(cache);

+ return NULL;

+ }

+

+ cache->key.objectid = start;

+ cache->key.offset = size;

+ cache->key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;

+

+ cache->fs_info = fs_info;

+ cache->full_stripe_len = btrfs_full_stripe_len(fs_info, start);

+ set_free_space_tree_thresholds(cache);

+

+ atomic_set(&cache->count, 1);

+ spin_lock_init(&cache->lock);

+ init_rwsem(&cache->data_rwsem);

+ INIT_LIST_HEAD(&cache->list);

+ INIT_LIST_HEAD(&cache->cluster_list);

+ INIT_LIST_HEAD(&cache->bg_list);

+ INIT_LIST_HEAD(&cache->ro_list);

+ INIT_LIST_HEAD(&cache->dirty_list);

+ INIT_LIST_HEAD(&cache->io_list);

+ btrfs_init_free_space_ctl(cache);

+ atomic_set(&cache->trimming, 0);

+ mutex_init(&cache->free_space_lock);

+ btrfs_init_full_stripe_locks_tree(&cache->full_stripe_locks_root);

+

+ return cache;

+}

+

+/*

+ * Iterate all chunks and verify that each of them has the corresponding block

+ * group

+ */

+static int check_chunk_block_group_mappings(struct btrfs_fs_info *fs_info)

+{

+ struct extent_map_tree *map_tree = &fs_info->mapping_tree;

+ struct extent_map *em;

+ struct btrfs_block_group_cache *bg;

+ u64 start = 0;

+ int ret = 0;

+

+ while (1) {

+ read_lock(&map_tree->lock);

+ /*

+ * lookup_extent_mapping will return the first extent map

+ * intersecting the range, so setting @len to 1 is enough to

+ * get the first chunk.

+ */

+ em = lookup_extent_mapping(map_tree, start, 1);

+ read_unlock(&map_tree->lock);

+ if (!em)

+ break;

+

+ bg = btrfs_lookup_block_group(fs_info, em->start);

+ if (!bg) {

+ btrfs_err(fs_info,

+ "chunk start=%llu len=%llu doesn't have corresponding block group",

+ em->start, em->len);

+ ret = -EUCLEAN;

+ free_extent_map(em);

+ break;

+ }

+ if (bg->key.objectid != em->start ||

+ bg->key.offset != em->len ||

+ (bg->flags & BTRFS_BLOCK_GROUP_TYPE_MASK) !=

+ (em->map_lookup->type & BTRFS_BLOCK_GROUP_TYPE_MASK)) {

+ btrfs_err(fs_info,

+"chunk start=%llu len=%llu flags=0x%llx doesn't match block group start=%llu len=%llu flags=0x%llx",

+ em->start, em->len,

+ em->map_lookup->type & BTRFS_BLOCK_GROUP_TYPE_MASK,

+ bg->key.objectid, bg->key.offset,

+ bg->flags & BTRFS_BLOCK_GROUP_TYPE_MASK);

+ ret = -EUCLEAN;

+ free_extent_map(em);

+ btrfs_put_block_group(bg);

+ break;

+ }

+ start = em->start + em->len;

+ free_extent_map(em);

+ btrfs_put_block_group(bg);

+ }

+ return ret;

+}

+

+int btrfs_read_block_groups(struct btrfs_fs_info *info)

+{

+ struct btrfs_path *path;

+ int ret;

+ struct btrfs_block_group_cache *cache;

+ struct btrfs_space_info *space_info;

+ struct btrfs_key key;

+ struct btrfs_key found_key;

+ struct extent_buffer *leaf;

+ int need_clear = 0;

+ u64 cache_gen;

+ u64 feature;

+ int mixed;

+

+ feature = btrfs_super_incompat_flags(info->super_copy);

+ mixed = !!(feature & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS);

+

+ key.objectid = 0;

+ key.offset = 0;

+ key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;

+ path = btrfs_alloc_path();

+ if (!path)

+ return -ENOMEM;

+ path->reada = READA_FORWARD;

+

+ cache_gen = btrfs_super_cache_generation(info->super_copy);

+ if (btrfs_test_opt(info, SPACE_CACHE) &&

+ btrfs_super_generation(info->super_copy) != cache_gen)

+ need_clear = 1;

+ if (btrfs_test_opt(info, CLEAR_CACHE))

+ need_clear = 1;

+

+ while (1) {

+ ret = find_first_block_group(info, path, &key);

+ if (ret > 0)

+ break;

+ if (ret != 0)

+ goto error;

+

+ leaf = path->nodes[0];

+ btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);

+

+ cache = btrfs_create_block_group_cache(info, found_key.objectid,

+ found_key.offset);

+ if (!cache) {

+ ret = -ENOMEM;

+ goto error;

+ }

+

+ if (need_clear) {

+ /*

+ * When we mount with old space cache, we need to

+ * set BTRFS_DC_CLEAR and set dirty flag.

+ *

+ * a) Setting 'BTRFS_DC_CLEAR' makes sure that we

+ * truncate the old free space cache inode and

+ * setup a new one.

+ * b) Setting 'dirty flag' makes sure that we flush

+ * the new space cache info onto disk.

+ */

+ if (btrfs_test_opt(info, SPACE_CACHE))

+ cache->disk_cache_state = BTRFS_DC_CLEAR;

+ }

+

+ read_extent_buffer(leaf, &cache->item,

+ btrfs_item_ptr_offset(leaf, path->slots[0]),

+ sizeof(cache->item));

+ cache->flags = btrfs_block_group_flags(&cache->item);

+ if (!mixed &&

+ ((cache->flags & BTRFS_BLOCK_GROUP_METADATA) &&

+ (cache->flags & BTRFS_BLOCK_GROUP_DATA))) {

+ btrfs_err(info,

+"bg %llu is a mixed block group but filesystem hasn't enabled mixed block groups",

+ cache->key.objectid);

+ ret = -EINVAL;

+ goto error;

+ }

+

+ key.objectid = found_key.objectid + found_key.offset;

+ btrfs_release_path(path);

+

+ /*

+ * We need to exclude the super stripes now so that the space

+ * info has super bytes accounted for, otherwise we'll think

+ * we have more space than we actually do.

+ */

+ ret = exclude_super_stripes(cache);

+ if (ret) {

+ /*

+ * We may have excluded something, so call this just in

+ * case.

+ */

+ btrfs_free_excluded_extents(cache);

+ btrfs_put_block_group(cache);

+ goto error;

+ }

+

+ /*

+ * Check for two cases, either we are full, and therefore

+ * don't need to bother with the caching work since we won't

+ * find any space, or we are empty, and we can just add all

+ * the space in and be done with it. This saves us _a_lot_ of

+ * time, particularly in the full case.

+ */

+ if (found_key.offset == btrfs_block_group_used(&cache->item)) {

+ cache->last_byte_to_unpin = (u64)-1;

+ cache->cached = BTRFS_CACHE_FINISHED;

+ btrfs_free_excluded_extents(cache);

+ } else if (btrfs_block_group_used(&cache->item) == 0) {

+ cache->last_byte_to_unpin = (u64)-1;

+ cache->cached = BTRFS_CACHE_FINISHED;

+ add_new_free_space(cache, found_key.objectid,

+ found_key.objectid +

+ found_key.offset);

+ btrfs_free_excluded_extents(cache);

+ }

+

+ ret = btrfs_add_block_group_cache(info, cache);

+ if (ret) {

+ btrfs_remove_free_space_cache(cache);

+ btrfs_put_block_group(cache);

+ goto error;

+ }

+

+ trace_btrfs_add_block_group(info, cache, 0);

+ btrfs_update_space_info(info, cache->flags, found_key.offset,

+ btrfs_block_group_used(&cache->item),

+ cache->bytes_super, &space_info);

+

+ cache->space_info = space_info;

+

+ link_block_group(cache);

+

+ set_avail_alloc_bits(info, cache->flags);

+ if (btrfs_chunk_readonly(info, cache->key.objectid)) {

+ inc_block_group_ro(cache, 1);

+ } else if (btrfs_block_group_used(&cache->item) == 0) {

+ ASSERT(list_empty(&cache->bg_list));

+ btrfs_mark_bg_unused(cache);

+ }

+ }

+

+ list_for_each_entry_rcu(space_info, &info->space_info, list) {

+ if (!(btrfs_get_alloc_profile(info, space_info->flags) &

+ (BTRFS_BLOCK_GROUP_RAID10 |

+ BTRFS_BLOCK_GROUP_RAID1_MASK |

+ BTRFS_BLOCK_GROUP_RAID56_MASK |

+ BTRFS_BLOCK_GROUP_DUP)))

+ continue;

+ /*

+ * Avoid allocating from un-mirrored block group if there are

+ * mirrored block groups.

+ */

+ list_for_each_entry(cache,

+ &space_info->block_groups[BTRFS_RAID_RAID0],

+ list)

+ inc_block_group_ro(cache, 1);

+ list_for_each_entry(cache,

+ &space_info->block_groups[BTRFS_RAID_SINGLE],

+ list)

+ inc_block_group_ro(cache, 1);

+ }

+

+ btrfs_init_global_block_rsv(info);

+ ret = check_chunk_block_group_mappings(info);

+error:

+ btrfs_free_path(path);

+ return ret;

+}

+

+void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans)

+{

+ struct btrfs_fs_info *fs_info = trans->fs_info;

+ struct btrfs_block_group_cache *block_group;

+ struct btrfs_root *extent_root = fs_info->extent_root;

+ struct btrfs_block_group_item item;

+ struct btrfs_key key;

+ int ret = 0;

+

+ if (!trans->can_flush_pending_bgs)

+ return;

+

+ while (!list_empty(&trans->new_bgs)) {

+ block_group = list_first_entry(&trans->new_bgs,

+ struct btrfs_block_group_cache,

+ bg_list);

+ if (ret)

+ goto next;

+

+ spin_lock(&block_group->lock);

+ memcpy(&item, &block_group->item, sizeof(item));

+ memcpy(&key, &block_group->key, sizeof(key));

+ spin_unlock(&block_group->lock);

+

+ ret = btrfs_insert_item(trans, extent_root, &key, &item,

+ sizeof(item));

+ if (ret)

+ btrfs_abort_transaction(trans, ret);

+ ret = btrfs_finish_chunk_alloc(trans, key.objectid, key.offset);

+ if (ret)

+ btrfs_abort_transaction(trans, ret);

+ add_block_group_free_space(trans, block_group);

+ /* Already aborted the transaction if it failed. */

+next:

+ btrfs_delayed_refs_rsv_release(fs_info, 1);

+ list_del_init(&block_group->bg_list);

+ }

+ btrfs_trans_release_chunk_metadata(trans);

+}

+

+int btrfs_make_block_group(struct btrfs_trans_handle *trans, u64 bytes_used,

+ u64 type, u64 chunk_offset, u64 size)

+{

+ struct btrfs_fs_info *fs_info = trans->fs_info;

+ struct btrfs_block_group_cache *cache;

+ int ret;

+

+ btrfs_set_log_full_commit(trans);

+

+ cache = btrfs_create_block_group_cache(fs_info, chunk_offset, size);

+ if (!cache)

+ return -ENOMEM;

+

+ btrfs_set_block_group_used(&cache->item, bytes_used);

+ btrfs_set_block_group_chunk_objectid(&cache->item,

+ BTRFS_FIRST_CHUNK_TREE_OBJECTID);

+ btrfs_set_block_group_flags(&cache->item, type);

+

+ cache->flags = type;

+ cache->last_byte_to_unpin = (u64)-1;

+ cache->cached = BTRFS_CACHE_FINISHED;

+ cache->needs_free_space = 1;

+ ret = exclude_super_stripes(cache);

+ if (ret) {

+ /* We may have excluded something, so call this just in case */

+ btrfs_free_excluded_extents(cache);

+ btrfs_put_block_group(cache);

+ return ret;

+ }

+

+ add_new_free_space(cache, chunk_offset, chunk_offset + size);

+

+ btrfs_free_excluded_extents(cache);

+

+#ifdef CONFIG_BTRFS_DEBUG

+ if (btrfs_should_fragment_free_space(cache)) {

+ u64 new_bytes_used = size - bytes_used;

+

+ bytes_used += new_bytes_used >> 1;

+ fragment_free_space(cache);

+ }

+#endif

+ /*

+ * Ensure the corresponding space_info object is created and

+ * assigned to our block group. We want our bg to be added to the rbtree

+ * with its ->space_info set.

+ */

+ cache->space_info = btrfs_find_space_info(fs_info, cache->flags);

+ ASSERT(cache->space_info);

+

+ ret = btrfs_add_block_group_cache(fs_info, cache);

+ if (ret) {

+ btrfs_remove_free_space_cache(cache);

+ btrfs_put_block_group(cache);

+ return ret;

+ }

+

+ /*

+ * Now that our block group has its ->space_info set and is inserted in

+ * the rbtree, update the space info's counters.

+ */

+ trace_btrfs_add_block_group(fs_info, cache, 1);

+ btrfs_update_space_info(fs_info, cache->flags, size, bytes_used,

+ cache->bytes_super, &cache->space_info);

+ btrfs_update_global_block_rsv(fs_info);

+

+ link_block_group(cache);

+

+ list_add_tail(&cache->bg_list, &trans->new_bgs);

+ trans->delayed_ref_updates++;

+ btrfs_update_delayed_refs_rsv(trans);

+

+ set_avail_alloc_bits(fs_info, type);

+ return 0;

+}

+

+static u64 update_block_group_flags(struct btrfs_fs_info *fs_info, u64 flags)

+{

+ u64 num_devices;

+ u64 stripped;

+

+ /*

+ * if restripe for this chunk_type is on pick target profile and

+ * return, otherwise do the usual balance

+ */

+ stripped = get_restripe_target(fs_info, flags);

+ if (stripped)

+ return extended_to_chunk(stripped);

+

+ num_devices = fs_info->fs_devices->rw_devices;

+

+ stripped = BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID56_MASK |

+ BTRFS_BLOCK_GROUP_RAID1_MASK | BTRFS_BLOCK_GROUP_RAID10;

+

+ if (num_devices == 1) {

+ stripped |= BTRFS_BLOCK_GROUP_DUP;

+ stripped = flags & ~stripped;

+

+ /* turn raid0 into single device chunks */

+ if (flags & BTRFS_BLOCK_GROUP_RAID0)

+ return stripped;

+

+ /* turn mirroring into duplication */

+ if (flags & (BTRFS_BLOCK_GROUP_RAID1_MASK |

+ BTRFS_BLOCK_GROUP_RAID10))

+ return stripped | BTRFS_BLOCK_GROUP_DUP;

+ } else {

+ /* they already had raid on here, just return */

+ if (flags & stripped)

+ return flags;

+

+ stripped |= BTRFS_BLOCK_GROUP_DUP;

+ stripped = flags & ~stripped;

+

+ /* switch duplicated blocks with raid1 */

+ if (flags & BTRFS_BLOCK_GROUP_DUP)

+ return stripped | BTRFS_BLOCK_GROUP_RAID1;

+

+ /* this is drive concat, leave it alone */

+ }

+

+ return flags;

+}

+

+int btrfs_inc_block_group_ro(struct btrfs_block_group_cache *cache)

+

+{

+ struct btrfs_fs_info *fs_info = cache->fs_info;

+ struct btrfs_trans_handle *trans;

+ u64 alloc_flags;

+ int ret;

+

+again:

+ trans = btrfs_join_transaction(fs_info->extent_root);

+ if (IS_ERR(trans))

+ return PTR_ERR(trans);

+

+ /*

+ * we're not allowed to set block groups readonly after the dirty

+ * block groups cache has started writing. If it already started,

+ * back off and let this transaction commit

+ */

+ mutex_lock(&fs_info->ro_block_group_mutex);

+ if (test_bit(BTRFS_TRANS_DIRTY_BG_RUN, &trans->transaction->flags)) {

+ u64 transid = trans->transid;

+

+ mutex_unlock(&fs_info->ro_block_group_mutex);

+ btrfs_end_transaction(trans);

+

+ ret = btrfs_wait_for_commit(fs_info, transid);

+ if (ret)

+ return ret;

+ goto again;

+ }

+

+ /*

+ * if we are changing raid levels, try to allocate a corresponding

+ * block group with the new raid level.

+ */

+ alloc_flags = update_block_group_flags(fs_info, cache->flags);

+ if (alloc_flags != cache->flags) {

+ ret = btrfs_chunk_alloc(trans, alloc_flags, CHUNK_ALLOC_FORCE);

+ /*

+ * ENOSPC is allowed here, we may have enough space

+ * already allocated at the new raid level to

+ * carry on

+ */

+ if (ret == -ENOSPC)

+ ret = 0;

+ if (ret < 0)

+ goto out;

+ }

+

+ ret = inc_block_group_ro(cache, 0);

+ if (!ret)

+ goto out;

+ alloc_flags = btrfs_get_alloc_profile(fs_info, cache->space_info->flags);

+ ret = btrfs_chunk_alloc(trans, alloc_flags, CHUNK_ALLOC_FORCE);

+ if (ret < 0)

+ goto out;

+ ret = inc_block_group_ro(cache, 0);

+out:

+ if (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM) {

+ alloc_flags = update_block_group_flags(fs_info, cache->flags);

+ mutex_lock(&fs_info->chunk_mutex);

+ check_system_chunk(trans, alloc_flags);

+ mutex_unlock(&fs_info->chunk_mutex);

+ }

+ mutex_unlock(&fs_info->ro_block_group_mutex);

+

+ btrfs_end_transaction(trans);

+ return ret;

+}

+

+void btrfs_dec_block_group_ro(struct btrfs_block_group_cache *cache)

+{

+ struct btrfs_space_info *sinfo = cache->space_info;

+ u64 num_bytes;

+

+ BUG_ON(!cache->ro);

+

+ spin_lock(&sinfo->lock);

+ spin_lock(&cache->lock);

+ if (!--cache->ro) {

+ num_bytes = cache->key.offset - cache->reserved -

+ cache->pinned - cache->bytes_super -

+ btrfs_block_group_used(&cache->item);

+ sinfo->bytes_readonly -= num_bytes;

+ list_del_init(&cache->ro_list);

+ }

+ spin_unlock(&cache->lock);

+ spin_unlock(&sinfo->lock);

+}

+

+static int write_one_cache_group(struct btrfs_trans_handle *trans,

+ struct btrfs_path *path,

+ struct btrfs_block_group_cache *cache)

+{

+ struct btrfs_fs_info *fs_info = trans->fs_info;

+ int ret;

+ struct btrfs_root *extent_root = fs_info->extent_root;

+ unsigned long bi;

+ struct extent_buffer *leaf;

+

+ ret = btrfs_search_slot(trans, extent_root, &cache->key, path, 0, 1);

+ if (ret) {

+ if (ret > 0)

+ ret = -ENOENT;

+ goto fail;

+ }

+

+ leaf = path->nodes[0];

+ bi = btrfs_item_ptr_offset(leaf, path->slots[0]);

+ write_extent_buffer(leaf, &cache->item, bi, sizeof(cache->item));

+ btrfs_mark_buffer_dirty(leaf);

+fail:

+ btrfs_release_path(path);

+ return ret;

+

+}

+

+static int cache_save_setup(struct btrfs_block_group_cache *block_group,

+ struct btrfs_trans_handle *trans,

+ struct btrfs_path *path)

+{

+ struct btrfs_fs_info *fs_info = block_group->fs_info;

+ struct btrfs_root *root = fs_info->tree_root;

+ struct inode *inode = NULL;

+ struct extent_changeset *data_reserved = NULL;

+ u64 alloc_hint = 0;

+ int dcs = BTRFS_DC_ERROR;

+ u64 num_pages = 0;

+ int retries = 0;

+ int ret = 0;

+

+ /*

+ * If this block group is smaller than 100 megs don't bother caching the

+ * block group.

+ */

+ if (block_group->key.offset < (100 * SZ_1M)) {

+ spin_lock(&block_group->lock);

+ block_group->disk_cache_state = BTRFS_DC_WRITTEN;

+ spin_unlock(&block_group->lock);

+ return 0;

+ }

+

+ if (trans->aborted)

+ return 0;

+again:

+ inode = lookup_free_space_inode(block_group, path);

+ if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) {

+ ret = PTR_ERR(inode);

+ btrfs_release_path(path);

+ goto out;

+ }

+

+ if (IS_ERR(inode)) {

+ BUG_ON(retries);

+ retries++;

+

+ if (block_group->ro)

+ goto out_free;

+

+ ret = create_free_space_inode(trans, block_group, path);

+ if (ret)

+ goto out_free;

+ goto again;

+ }

+

+ /*

+ * We want to set the generation to 0, that way if anything goes wrong

+ * from here on out we know not to trust this cache when we load up next

+ * time.

+ */

+ BTRFS_I(inode)->generation = 0;

+ ret = btrfs_update_inode(trans, root, inode);

+ if (ret) {

+ /*

+ * So theoretically we could recover from this, simply set the

+ * super cache generation to 0 so we know to invalidate the

+ * cache, but then we'd have to keep track of the block groups

+ * that fail this way so we know we _have_ to reset this cache

+ * before the next commit or risk reading stale cache. So to

+ * limit our exposure to horrible edge cases lets just abort the

+ * transaction, this only happens in really bad situations

+ * anyway.

+ */

+ btrfs_abort_transaction(trans, ret);

+ goto out_put;

+ }

+ WARN_ON(ret);

+

+ /* We've already setup this transaction, go ahead and exit */

+ if (block_group->cache_generation == trans->transid &&

+ i_size_read(inode)) {

+ dcs = BTRFS_DC_SETUP;

+ goto out_put;

+ }

+

+ if (i_size_read(inode) > 0) {

+ ret = btrfs_check_trunc_cache_free_space(fs_info,

+ &fs_info->global_block_rsv);

+ if (ret)

+ goto out_put;

+

+ ret = btrfs_truncate_free_space_cache(trans, NULL, inode);

+ if (ret)

+ goto out_put;

+ }

+

+ spin_lock(&block_group->lock);

+ if (block_group->cached != BTRFS_CACHE_FINISHED ||

+ !btrfs_test_opt(fs_info, SPACE_CACHE)) {

+ /*

+ * don't bother trying to write stuff out _if_

+ * a) we're not cached,

+ * b) we're with nospace_cache mount option,

+ * c) we're with v2 space_cache (FREE_SPACE_TREE).

+ */

+ dcs = BTRFS_DC_WRITTEN;

+ spin_unlock(&block_group->lock);

+ goto out_put;

+ }

+ spin_unlock(&block_group->lock);

+

+ /*

+ * We hit an ENOSPC when setting up the cache in this transaction, just

+ * skip doing the setup, we've already cleared the cache so we're safe.

+ */

+ if (test_bit(BTRFS_TRANS_CACHE_ENOSPC, &trans->transaction->flags)) {

+ ret = -ENOSPC;

+ goto out_put;

+ }

+

+ /*

+ * Try to preallocate enough space based on how big the block group is.

+ * Keep in mind this has to include any pinned space which could end up

+ * taking up quite a bit since it's not folded into the other space

+ * cache.

+ */

+ num_pages = div_u64(block_group->key.offset, SZ_256M);

+ if (!num_pages)

+ num_pages = 1;

+

+ num_pages *= 16;

+ num_pages *= PAGE_SIZE;

+

+ ret = btrfs_check_data_free_space(inode, &data_reserved, 0, num_pages);

+ if (ret)

+ goto out_put;

+

+ ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, num_pages,

+ num_pages, num_pages,

+ &alloc_hint);

+ /*

+ * Our cache requires contiguous chunks so that we don't modify a bunch

+ * of metadata or split extents when writing the cache out, which means

+ * we can enospc if we are heavily fragmented in addition to just normal

+ * out of space conditions. So if we hit this just skip setting up any

+ * other block groups for this transaction, maybe we'll unpin enough

+ * space the next time around.

+ */

+ if (!ret)

+ dcs = BTRFS_DC_SETUP;

+ else if (ret == -ENOSPC)

+ set_bit(BTRFS_TRANS_CACHE_ENOSPC, &trans->transaction->flags);

+

+out_put:

+ iput(inode);

+out_free:

+ btrfs_release_path(path);

+out:

+ spin_lock(&block_group->lock);

+ if (!ret && dcs == BTRFS_DC_SETUP)

+ block_group->cache_generation = trans->transid;

+ block_group->disk_cache_state = dcs;

+ spin_unlock(&block_group->lock);

+

+ extent_changeset_free(data_reserved);

+ return ret;

+}

+

+int btrfs_setup_space_cache(struct btrfs_trans_handle *trans)

+{

+ struct btrfs_fs_info *fs_info = trans->fs_info;

+ struct btrfs_block_group_cache *cache, *tmp;

+ struct btrfs_transaction *cur_trans = trans->transaction;

+ struct btrfs_path *path;

+

+ if (list_empty(&cur_trans->dirty_bgs) ||

+ !btrfs_test_opt(fs_info, SPACE_CACHE))

+ return 0;

+

+ path = btrfs_alloc_path();

+ if (!path)

+ return -ENOMEM;

+

+ /* Could add new block groups, use _safe just in case */

+ list_for_each_entry_safe(cache, tmp, &cur_trans->dirty_bgs,

+ dirty_list) {

+ if (cache->disk_cache_state == BTRFS_DC_CLEAR)

+ cache_save_setup(cache, trans, path);

+ }

+

+ btrfs_free_path(path);

+ return 0;

+}

+

+/*

+ * Transaction commit does final block group cache writeback during a critical

+ * section where nothing is allowed to change the FS. This is required in

+ * order for the cache to actually match the block group, but can introduce a

+ * lot of latency into the commit.

+ *

+ * So, btrfs_start_dirty_block_groups is here to kick off block group cache IO.

+ * There's a chance we'll have to redo some of it if the block group changes

+ * again during the commit, but it greatly reduces the commit latency by

+ * getting rid of the easy block groups while we're still allowing others to

+ * join the commit.

+ */

+int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans)

+{

+ struct btrfs_fs_info *fs_info = trans->fs_info;

+ struct btrfs_block_group_cache *cache;

+ struct btrfs_transaction *cur_trans = trans->transaction;

+ int ret = 0;

+ int should_put;

+ struct btrfs_path *path = NULL;

+ LIST_HEAD(dirty);

+ struct list_head *io = &cur_trans->io_bgs;

+ int num_started = 0;

+ int loops = 0;

+

+ spin_lock(&cur_trans->dirty_bgs_lock);

+ if (list_empty(&cur_trans->dirty_bgs)) {

+ spin_unlock(&cur_trans->dirty_bgs_lock);

+ return 0;

+ }

+ list_splice_init(&cur_trans->dirty_bgs, &dirty);

+ spin_unlock(&cur_trans->dirty_bgs_lock);

+

+again:

+ /* Make sure all the block groups on our dirty list actually exist */

+ btrfs_create_pending_block_groups(trans);

+

+ if (!path) {

+ path = btrfs_alloc_path();

+ if (!path)

+ return -ENOMEM;

+ }

+

+ /*

+ * cache_write_mutex is here only to save us from balance or automatic

+ * removal of empty block groups deleting this block group while we are

+ * writing out the cache

+ */

+ mutex_lock(&trans->transaction->cache_write_mutex);

+ while (!list_empty(&dirty)) {

+ bool drop_reserve = true;

+

+ cache = list_first_entry(&dirty,

+ struct btrfs_block_group_cache,

+ dirty_list);

+ /*

+ * This can happen if something re-dirties a block group that

+ * is already under IO. Just wait for it to finish and then do

+ * it all again

+ */

+ if (!list_empty(&cache->io_list)) {

+ list_del_init(&cache->io_list);

+ btrfs_wait_cache_io(trans, cache, path);

+ btrfs_put_block_group(cache);

+ }

+

+

+ /*

+ * btrfs_wait_cache_io uses the cache->dirty_list to decide if

+ * it should update the cache_state. Don't delete until after

+ * we wait.

+ *

+ * Since we're not running in the commit critical section

+ * we need the dirty_bgs_lock to protect from update_block_group

+ */

+ spin_lock(&cur_trans->dirty_bgs_lock);

+ list_del_init(&cache->dirty_list);

+ spin_unlock(&cur_trans->dirty_bgs_lock);

+

+ should_put = 1;

+

+ cache_save_setup(cache, trans, path);

+

+ if (cache->disk_cache_state == BTRFS_DC_SETUP) {

+ cache->io_ctl.inode = NULL;

+ ret = btrfs_write_out_cache(trans, cache, path);

+ if (ret == 0 && cache->io_ctl.inode) {

+ num_started++;

+ should_put = 0;

+

+ /*

+ * The cache_write_mutex is protecting the

+ * io_list, also refer to the definition of

+ * btrfs_transaction::io_bgs for more details

+ */

+ list_add_tail(&cache->io_list, io);

+ } else {

+ /*

+ * If we failed to write the cache, the

+ * generation will be bad and life goes on

+ */

+ ret = 0;

+ }

+ }

+ if (!ret) {

+ ret = write_one_cache_group(trans, path, cache);

+ /*

+ * Our block group might still be attached to the list

+ * of new block groups in the transaction handle of some

+ * other task (struct btrfs_trans_handle->new_bgs). This

+ * means its block group item isn't yet in the extent

+ * tree. If this happens ignore the error, as we will

+ * try again later in the critical section of the

+ * transaction commit.

+ */

+ if (ret == -ENOENT) {

+ ret = 0;

+ spin_lock(&cur_trans->dirty_bgs_lock);

+ if (list_empty(&cache->dirty_list)) {

+ list_add_tail(&cache->dirty_list,

+ &cur_trans->dirty_bgs);

+ btrfs_get_block_group(cache);

+ drop_reserve = false;

+ }

+ spin_unlock(&cur_trans->dirty_bgs_lock);

+ } else if (ret) {

+ btrfs_abort_transaction(trans, ret);

+ }

+ }

+

+ /* If it's not on the io list, we need to put the block group */

+ if (should_put)

+ btrfs_put_block_group(cache);

+ if (drop_reserve)

+ btrfs_delayed_refs_rsv_release(fs_info, 1);

+

+ if (ret)

+ break;

+

+ /*

+ * Avoid blocking other tasks for too long. It might even save

+ * us from writing caches for block groups that are going to be

+ * removed.

+ */

+ mutex_unlock(&trans->transaction->cache_write_mutex);

+ mutex_lock(&trans->transaction->cache_write_mutex);

+ }

+ mutex_unlock(&trans->transaction->cache_write_mutex);

+

+ /*

+ * Go through delayed refs for all the stuff we've just kicked off

+ * and then loop back (just once)

+ */

+ ret = btrfs_run_delayed_refs(trans, 0);

+ if (!ret && loops == 0) {

+ loops++;

+ spin_lock(&cur_trans->dirty_bgs_lock);

+ list_splice_init(&cur_trans->dirty_bgs, &dirty);

+ /*

+ * dirty_bgs_lock protects us from concurrent block group

+ * deletes too (not just cache_write_mutex).

+ */

+ if (!list_empty(&dirty)) {

+ spin_unlock(&cur_trans->dirty_bgs_lock);

+ goto again;

+ }

+ spin_unlock(&cur_trans->dirty_bgs_lock);

+ } else if (ret < 0) {

+ btrfs_cleanup_dirty_bgs(cur_trans, fs_info);

+ }

+

+ btrfs_free_path(path);

+ return ret;

+}

+

+int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans)

+{

+ struct btrfs_fs_info *fs_info = trans->fs_info;

+ struct btrfs_block_group_cache *cache;

+ struct btrfs_transaction *cur_trans = trans->transaction;

+ int ret = 0;

+ int should_put;

+ struct btrfs_path *path;

+ struct list_head *io = &cur_trans->io_bgs;

+ int num_started = 0;

+

+ path = btrfs_alloc_path();

+ if (!path)

+ return -ENOMEM;

+

+ /*

+ * Even though we are in the critical section of the transaction commit,

+ * we can still have concurrent tasks adding elements to this

+ * transaction's list of dirty block groups. These tasks correspond to

+ * endio free space workers started when writeback finishes for a

+ * space cache, which run inode.c:btrfs_finish_ordered_io(), and can

+ * allocate new block groups as a result of COWing nodes of the root

+ * tree when updating the free space inode. The writeback for the space

+ * caches is triggered by an earlier call to

+ * btrfs_start_dirty_block_groups() and iterations of the following

+ * loop.

+ * Also we want to do the cache_save_setup first and then run the

+ * delayed refs to make sure we have the best chance at doing this all

+ * in one shot.

+ */

+ spin_lock(&cur_trans->dirty_bgs_lock);

+ while (!list_empty(&cur_trans->dirty_bgs)) {

+ cache = list_first_entry(&cur_trans->dirty_bgs,

+ struct btrfs_block_group_cache,

+ dirty_list);

+

+ /*

+ * This can happen if cache_save_setup re-dirties a block group

+ * that is already under IO. Just wait for it to finish and

+ * then do it all again

+ */

+ if (!list_empty(&cache->io_list)) {

+ spin_unlock(&cur_trans->dirty_bgs_lock);

+ list_del_init(&cache->io_list);

+ btrfs_wait_cache_io(trans, cache, path);

+ btrfs_put_block_group(cache);

+ spin_lock(&cur_trans->dirty_bgs_lock);

+ }

+

+ /*

+ * Don't remove from the dirty list until after we've waited on

+ * any pending IO

+ */

+ list_del_init(&cache->dirty_list);

+ spin_unlock(&cur_trans->dirty_bgs_lock);

+ should_put = 1;

+

+ cache_save_setup(cache, trans, path);

+

+ if (!ret)

+ ret = btrfs_run_delayed_refs(trans,

+ (unsigned long) -1);

+

+ if (!ret && cache->disk_cache_state == BTRFS_DC_SETUP) {

+ cache->io_ctl.inode = NULL;

+ ret = btrfs_write_out_cache(trans, cache, path);

+ if (ret == 0 && cache->io_ctl.inode) {

+ num_started++;

+ should_put = 0;

+ list_add_tail(&cache->io_list, io);

+ } else {

+ /*

+ * If we failed to write the cache, the

+ * generation will be bad and life goes on

+ */

+ ret = 0;

+ }

+ }

+ if (!ret) {

+ ret = write_one_cache_group(trans, path, cache);

+ /*

+ * One of the free space endio workers might have

+ * created a new block group while updating a free space

+ * cache's inode (at inode.c:btrfs_finish_ordered_io())

+ * and hasn't released its transaction handle yet, in

+ * which case the new block group is still attached to

+ * its transaction handle and its creation has not

+ * finished yet (no block group item in the extent tree

+ * yet, etc). If this is the case, wait for all free

+ * space endio workers to finish and retry. This is a

+ * a very rare case so no need for a more efficient and

+ * complex approach.

+ */

+ if (ret == -ENOENT) {

+ wait_event(cur_trans->writer_wait,

+ atomic_read(&cur_trans->num_writers) == 1);

+ ret = write_one_cache_group(trans, path, cache);

+ }

+ if (ret)

+ btrfs_abort_transaction(trans, ret);

+ }

+

+ /* If its not on the io list, we need to put the block group */

+ if (should_put)

+ btrfs_put_block_group(cache);

+ btrfs_delayed_refs_rsv_release(fs_info, 1);

+ spin_lock(&cur_trans->dirty_bgs_lock);

+ }

+ spin_unlock(&cur_trans->dirty_bgs_lock);

+

+ /*

+ * Refer to the definition of io_bgs member for details why it's safe

+ * to use it without any locking

+ */

+ while (!list_empty(io)) {

+ cache = list_first_entry(io, struct btrfs_block_group_cache,

+ io_list);

+ list_del_init(&cache->io_list);

+ btrfs_wait_cache_io(trans, cache, path);

+ btrfs_put_block_group(cache);

+ }

+

+ btrfs_free_path(path);

+ return ret;

+}

+

+int btrfs_update_block_group(struct btrfs_trans_handle *trans,

+ u64 bytenr, u64 num_bytes, int alloc)

+{

+ struct btrfs_fs_info *info = trans->fs_info;

+ struct btrfs_block_group_cache *cache = NULL;

+ u64 total = num_bytes;

+ u64 old_val;

+ u64 byte_in_group;

+ int factor;

+ int ret = 0;

+

+ /* Block accounting for super block */

+ spin_lock(&info->delalloc_root_lock);

+ old_val = btrfs_super_bytes_used(info->super_copy);

+ if (alloc)

+ old_val += num_bytes;

+ else

+ old_val -= num_bytes;

+ btrfs_set_super_bytes_used(info->super_copy, old_val);

+ spin_unlock(&info->delalloc_root_lock);

+

+ while (total) {

+ cache = btrfs_lookup_block_group(info, bytenr);

+ if (!cache) {

+ ret = -ENOENT;

+ break;

+ }

+ factor = btrfs_bg_type_to_factor(cache->flags);

+

+ /*

+ * If this block group has free space cache written out, we

+ * need to make sure to load it if we are removing space. This

+ * is because we need the unpinning stage to actually add the

+ * space back to the block group, otherwise we will leak space.

+ */

+ if (!alloc && cache->cached == BTRFS_CACHE_NO)

+ btrfs_cache_block_group(cache, 1);

+

+ byte_in_group = bytenr - cache->key.objectid;

+ WARN_ON(byte_in_group > cache->key.offset);

+

+ spin_lock(&cache->space_info->lock);

+ spin_lock(&cache->lock);

+

+ if (btrfs_test_opt(info, SPACE_CACHE) &&

+ cache->disk_cache_state < BTRFS_DC_CLEAR)

+ cache->disk_cache_state = BTRFS_DC_CLEAR;

+

+ old_val = btrfs_block_group_used(&cache->item);

+ num_bytes = min(total, cache->key.offset - byte_in_group);

+ if (alloc) {

+ old_val += num_bytes;

+ btrfs_set_block_group_used(&cache->item, old_val);

+ cache->reserved -= num_bytes;

+ cache->space_info->bytes_reserved -= num_bytes;

+ cache->space_info->bytes_used += num_bytes;

+ cache->space_info->disk_used += num_bytes * factor;

+ spin_unlock(&cache->lock);

+ spin_unlock(&cache->space_info->lock);

+ } else {

+ old_val -= num_bytes;

+ btrfs_set_block_group_used(&cache->item, old_val);

+ cache->pinned += num_bytes;

+ btrfs_space_info_update_bytes_pinned(info,

+ cache->space_info, num_bytes);

+ cache->space_info->bytes_used -= num_bytes;

+ cache->space_info->disk_used -= num_bytes * factor;

+ spin_unlock(&cache->lock);

+ spin_unlock(&cache->space_info->lock);

+

+ percpu_counter_add_batch(

+ &cache->space_info->total_bytes_pinned,

+ num_bytes,

+ BTRFS_TOTAL_BYTES_PINNED_BATCH);

+ set_extent_dirty(info->pinned_extents,

+ bytenr, bytenr + num_bytes - 1,

+ GFP_NOFS | __GFP_NOFAIL);

+ }

+

+ spin_lock(&trans->transaction->dirty_bgs_lock);

+ if (list_empty(&cache->dirty_list)) {

+ list_add_tail(&cache->dirty_list,

+ &trans->transaction->dirty_bgs);

+ trans->delayed_ref_updates++;

+ btrfs_get_block_group(cache);

+ }

+ spin_unlock(&trans->transaction->dirty_bgs_lock);

+

+ /*

+ * No longer have used bytes in this block group, queue it for

+ * deletion. We do this after adding the block group to the

+ * dirty list to avoid races between cleaner kthread and space

+ * cache writeout.

+ */

+ if (!alloc && old_val == 0)

+ btrfs_mark_bg_unused(cache);

+

+ btrfs_put_block_group(cache);

+ total -= num_bytes;

+ bytenr += num_bytes;

+ }

+

+ /* Modified block groups are accounted for in the delayed_refs_rsv. */

+ btrfs_update_delayed_refs_rsv(trans);

+ return ret;

+}

+

+/**

+ * btrfs_add_reserved_bytes - update the block_group and space info counters

+ * @cache: The cache we are manipulating

+ * @ram_bytes: The number of bytes of file content, and will be same to

+ * @num_bytes except for the compress path.

+ * @num_bytes: The number of bytes in question

+ * @delalloc: The blocks are allocated for the delalloc write

+ *

+ * This is called by the allocator when it reserves space. If this is a

+ * reservation and the block group has become read only we cannot make the

+ * reservation and return -EAGAIN, otherwise this function always succeeds.

+ */

+int btrfs_add_reserved_bytes(struct btrfs_block_group_cache *cache,

+ u64 ram_bytes, u64 num_bytes, int delalloc)

+{

+ struct btrfs_space_info *space_info = cache->space_info;

+ int ret = 0;

+

+ spin_lock(&space_info->lock);

+ spin_lock(&cache->lock);

+ if (cache->ro) {

+ ret = -EAGAIN;

+ } else {

+ cache->reserved += num_bytes;

+ space_info->bytes_reserved += num_bytes;

+ trace_btrfs_space_reservation(cache->fs_info, "space_info",

+ space_info->flags, num_bytes, 1);

+ btrfs_space_info_update_bytes_may_use(cache->fs_info,

+ space_info, -ram_bytes);

+ if (delalloc)

+ cache->delalloc_bytes += num_bytes;

+ }

+ spin_unlock(&cache->lock);

+ spin_unlock(&space_info->lock);

+ return ret;

+}

+

+/**

+ * btrfs_free_reserved_bytes - update the block_group and space info counters

+ * @cache: The cache we are manipulating

+ * @num_bytes: The number of bytes in question

+ * @delalloc: The blocks are allocated for the delalloc write

+ *

+ * This is called by somebody who is freeing space that was never actually used

+ * on disk. For example if you reserve some space for a new leaf in transaction

+ * A and before transaction A commits you free that leaf, you call this with

+ * reserve set to 0 in order to clear the reservation.

+ */

+void btrfs_free_reserved_bytes(struct btrfs_block_group_cache *cache,

+ u64 num_bytes, int delalloc)

+{

+ struct btrfs_space_info *space_info = cache->space_info;

+

+ spin_lock(&space_info->lock);

+ spin_lock(&cache->lock);

+ if (cache->ro)

+ space_info->bytes_readonly += num_bytes;

+ cache->reserved -= num_bytes;

+ space_info->bytes_reserved -= num_bytes;

+ space_info->max_extent_size = 0;

+

+ if (delalloc)

+ cache->delalloc_bytes -= num_bytes;

+ spin_unlock(&cache->lock);

+ spin_unlock(&space_info->lock);

+}

+

+static void force_metadata_allocation(struct btrfs_fs_info *info)

+{

+ struct list_head *head = &info->space_info;

+ struct btrfs_space_info *found;

+

+ rcu_read_lock();

+ list_for_each_entry_rcu(found, head, list) {

+ if (found->flags & BTRFS_BLOCK_GROUP_METADATA)

+ found->force_alloc = CHUNK_ALLOC_FORCE;

+ }

+ rcu_read_unlock();

+}

+

+static int should_alloc_chunk(struct btrfs_fs_info *fs_info,

+ struct btrfs_space_info *sinfo, int force)

+{

+ u64 bytes_used = btrfs_space_info_used(sinfo, false);

+ u64 thresh;

+

+ if (force == CHUNK_ALLOC_FORCE)

+ return 1;

+

+ /*

+ * in limited mode, we want to have some free space up to

+ * about 1% of the FS size.

+ */

+ if (force == CHUNK_ALLOC_LIMITED) {

+ thresh = btrfs_super_total_bytes(fs_info->super_copy);

+ thresh = max_t(u64, SZ_64M, div_factor_fine(thresh, 1));

+

+ if (sinfo->total_bytes - bytes_used < thresh)

+ return 1;

+ }

+

+ if (bytes_used + SZ_2M < div_factor(sinfo->total_bytes, 8))

+ return 0;

+ return 1;

+}

+

+int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, u64 type)

+{

+ u64 alloc_flags = btrfs_get_alloc_profile(trans->fs_info, type);

+

+ return btrfs_chunk_alloc(trans, alloc_flags, CHUNK_ALLOC_FORCE);

+}

+

+/*

+ * If force is CHUNK_ALLOC_FORCE:

+ * - return 1 if it successfully allocates a chunk,

+ * - return errors including -ENOSPC otherwise.

+ * If force is NOT CHUNK_ALLOC_FORCE:

+ * - return 0 if it doesn't need to allocate a new chunk,

+ * - return 1 if it successfully allocates a chunk,

+ * - return errors including -ENOSPC otherwise.

+ */

+int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags,

+ enum btrfs_chunk_alloc_enum force)

+{

+ struct btrfs_fs_info *fs_info = trans->fs_info;

+ struct btrfs_space_info *space_info;

+ bool wait_for_alloc = false;

+ bool should_alloc = false;

+ int ret = 0;

+

+ /* Don't re-enter if we're already allocating a chunk */

+ if (trans->allocating_chunk)

+ return -ENOSPC;

+

+ space_info = btrfs_find_space_info(fs_info, flags);

+ ASSERT(space_info);

+

+ do {

+ spin_lock(&space_info->lock);

+ if (force < space_info->force_alloc)

+ force = space_info->force_alloc;

+ should_alloc = should_alloc_chunk(fs_info, space_info, force);

+ if (space_info->full) {

+ /* No more free physical space */

+ if (should_alloc)

+ ret = -ENOSPC;

+ else

+ ret = 0;

+ spin_unlock(&space_info->lock);

+ return ret;

+ } else if (!should_alloc) {

+ spin_unlock(&space_info->lock);

+ return 0;

+ } else if (space_info->chunk_alloc) {

+ /*

+ * Someone is already allocating, so we need to block

+ * until this someone is finished and then loop to

+ * recheck if we should continue with our allocation

+ * attempt.

+ */

+ wait_for_alloc = true;

+ spin_unlock(&space_info->lock);

+ mutex_lock(&fs_info->chunk_mutex);

+ mutex_unlock(&fs_info->chunk_mutex);

+ } else {

+ /* Proceed with allocation */

+ space_info->chunk_alloc = 1;

+ wait_for_alloc = false;

+ spin_unlock(&space_info->lock);

+ }

+

+ cond_resched();

+ } while (wait_for_alloc);

+

+ mutex_lock(&fs_info->chunk_mutex);

+ trans->allocating_chunk = true;

+

+ /*

+ * If we have mixed data/metadata chunks we want to make sure we keep

+ * allocating mixed chunks instead of individual chunks.

+ */

+ if (btrfs_mixed_space_info(space_info))

+ flags |= (BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA);

+

+ /*

+ * if we're doing a data chunk, go ahead and make sure that

+ * we keep a reasonable number of metadata chunks allocated in the

+ * FS as well.

+ */

+ if (flags & BTRFS_BLOCK_GROUP_DATA && fs_info->metadata_ratio) {

+ fs_info->data_chunk_allocations++;

+ if (!(fs_info->data_chunk_allocations %

+ fs_info->metadata_ratio))

+ force_metadata_allocation(fs_info);

+ }

+

+ /*

+ * Check if we have enough space in SYSTEM chunk because we may need

+ * to update devices.

+ */

+ check_system_chunk(trans, flags);

+

+ ret = btrfs_alloc_chunk(trans, flags);

+ trans->allocating_chunk = false;

+

+ spin_lock(&space_info->lock);

+ if (ret < 0) {

+ if (ret == -ENOSPC)

+ space_info->full = 1;

+ else

+ goto out;

+ } else {

+ ret = 1;

+ space_info->max_extent_size = 0;

+ }

+

+ space_info->force_alloc = CHUNK_ALLOC_NO_FORCE;

+out:

+ space_info->chunk_alloc = 0;

+ spin_unlock(&space_info->lock);

+ mutex_unlock(&fs_info->chunk_mutex);

+ /*

+ * When we allocate a new chunk we reserve space in the chunk block

+ * reserve to make sure we can COW nodes/leafs in the chunk tree or

+ * add new nodes/leafs to it if we end up needing to do it when

+ * inserting the chunk item and updating device items as part of the

+ * second phase of chunk allocation, performed by

+ * btrfs_finish_chunk_alloc(). So make sure we don't accumulate a

+ * large number of new block groups to create in our transaction

+ * handle's new_bgs list to avoid exhausting the chunk block reserve

+ * in extreme cases - like having a single transaction create many new

+ * block groups when starting to write out the free space caches of all

+ * the block groups that were made dirty during the lifetime of the

+ * transaction.

+ */

+ if (trans->chunk_bytes_reserved >= (u64)SZ_2M)

+ btrfs_create_pending_block_groups(trans);

+

+ return ret;

+}

+

+static u64 get_profile_num_devs(struct btrfs_fs_info *fs_info, u64 type)

+{

+ u64 num_dev;

+

+ num_dev = btrfs_raid_array[btrfs_bg_flags_to_raid_index(type)].devs_max;

+ if (!num_dev)

+ num_dev = fs_info->fs_devices->rw_devices;

+

+ return num_dev;

+}

+

+/*

+ * If @is_allocation is true, reserve space in the system space info necessary

+ * for allocating a chunk, otherwise if it's false, reserve space necessary for

+ * removing a chunk.

+ */

+void check_system_chunk(struct btrfs_trans_handle *trans, u64 type)

+{

+ struct btrfs_fs_info *fs_info = trans->fs_info;

+ struct btrfs_space_info *info;

+ u64 left;

+ u64 thresh;

+ int ret = 0;

+ u64 num_devs;

+

+ /*

+ * Needed because we can end up allocating a system chunk and for an

+ * atomic and race free space reservation in the chunk block reserve.

+ */

+ lockdep_assert_held(&fs_info->chunk_mutex);

+

+ info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_SYSTEM);

+ spin_lock(&info->lock);

+ left = info->total_bytes - btrfs_space_info_used(info, true);

+ spin_unlock(&info->lock);

+

+ num_devs = get_profile_num_devs(fs_info, type);

+

+ /* num_devs device items to update and 1 chunk item to add or remove */

+ thresh = btrfs_calc_metadata_size(fs_info, num_devs) +

+ btrfs_calc_insert_metadata_size(fs_info, 1);

+

+ if (left < thresh && btrfs_test_opt(fs_info, ENOSPC_DEBUG)) {

+ btrfs_info(fs_info, "left=%llu, need=%llu, flags=%llu",

+ left, thresh, type);

+ btrfs_dump_space_info(fs_info, info, 0, 0);

+ }

+

+ if (left < thresh) {

+ u64 flags = btrfs_system_alloc_profile(fs_info);

+

+ /*

+ * Ignore failure to create system chunk. We might end up not

+ * needing it, as we might not need to COW all nodes/leafs from

+ * the paths we visit in the chunk tree (they were already COWed

+ * or created in the current transaction for example).

+ */

+ ret = btrfs_alloc_chunk(trans, flags);

+ }

+

+ if (!ret) {

+ ret = btrfs_block_rsv_add(fs_info->chunk_root,

+ &fs_info->chunk_block_rsv,

+ thresh, BTRFS_RESERVE_NO_FLUSH);

+ if (!ret)

+ trans->chunk_bytes_reserved += thresh;

+ }

+}

+

+void btrfs_put_block_group_cache(struct btrfs_fs_info *info)

+{

+ struct btrfs_block_group_cache *block_group;

+ u64 last = 0;

+

+ while (1) {

+ struct inode *inode;

+

+ block_group = btrfs_lookup_first_block_group(info, last);

+ while (block_group) {

+ btrfs_wait_block_group_cache_done(block_group);

+ spin_lock(&block_group->lock);

+ if (block_group->iref)

+ break;

+ spin_unlock(&block_group->lock);

+ block_group = btrfs_next_block_group(block_group);

+ }

+ if (!block_group) {

+ if (last == 0)

+ break;

+ last = 0;

+ continue;

+ }

+

+ inode = block_group->inode;

+ block_group->iref = 0;

+ block_group->inode = NULL;

+ spin_unlock(&block_group->lock);

+ ASSERT(block_group->io_ctl.inode == NULL);

+ iput(inode);

+ last = block_group->key.objectid + block_group->key.offset;

+ btrfs_put_block_group(block_group);

+ }

+}

+

+/*

+ * Must be called only after stopping all workers, since we could have block

+ * group caching kthreads running, and therefore they could race with us if we

+ * freed the block groups before stopping them.

+ */

+int btrfs_free_block_groups(struct btrfs_fs_info *info)

+{

+ struct btrfs_block_group_cache *block_group;

+ struct btrfs_space_info *space_info;

+ struct btrfs_caching_control *caching_ctl;

+ struct rb_node *n;

+

+ down_write(&info->commit_root_sem);

+ while (!list_empty(&info->caching_block_groups)) {

+ caching_ctl = list_entry(info->caching_block_groups.next,

+ struct btrfs_caching_control, list);

+ list_del(&caching_ctl->list);

+ btrfs_put_caching_control(caching_ctl);

+ }

+ up_write(&info->commit_root_sem);

+

+ spin_lock(&info->unused_bgs_lock);

+ while (!list_empty(&info->unused_bgs)) {

+ block_group = list_first_entry(&info->unused_bgs,

+ struct btrfs_block_group_cache,

+ bg_list);

+ list_del_init(&block_group->bg_list);

+ btrfs_put_block_group(block_group);

+ }

+ spin_unlock(&info->unused_bgs_lock);

+

+ spin_lock(&info->block_group_cache_lock);

+ while ((n = rb_last(&info->block_group_cache_tree)) != NULL) {

+ block_group = rb_entry(n, struct btrfs_block_group_cache,

+ cache_node);

+ rb_erase(&block_group->cache_node,

+ &info->block_group_cache_tree);

+ RB_CLEAR_NODE(&block_group->cache_node);

+ spin_unlock(&info->block_group_cache_lock);

+

+ down_write(&block_group->space_info->groups_sem);

+ list_del(&block_group->list);

+ up_write(&block_group->space_info->groups_sem);

+

+ /*

+ * We haven't cached this block group, which means we could

+ * possibly have excluded extents on this block group.

+ */

+ if (block_group->cached == BTRFS_CACHE_NO ||

+ block_group->cached == BTRFS_CACHE_ERROR)

+ btrfs_free_excluded_extents(block_group);

+

+ btrfs_remove_free_space_cache(block_group);

+ ASSERT(block_group->cached != BTRFS_CACHE_STARTED);

+ ASSERT(list_empty(&block_group->dirty_list));

+ ASSERT(list_empty(&block_group->io_list));

+ ASSERT(list_empty(&block_group->bg_list));

+ ASSERT(atomic_read(&block_group->count) == 1);

+ btrfs_put_block_group(block_group);

+

+ spin_lock(&info->block_group_cache_lock);

+ }

+ spin_unlock(&info->block_group_cache_lock);

+

+ /*

+ * Now that all the block groups are freed, go through and free all the

+ * space_info structs. This is only called during the final stages of

+ * unmount, and so we know nobody is using them. We call

+ * synchronize_rcu() once before we start, just to be on the safe side.

+ */

+ synchronize_rcu();

+

+ btrfs_release_global_block_rsv(info);

+

+ while (!list_empty(&info->space_info)) {

+ space_info = list_entry(info->space_info.next,

+ struct btrfs_space_info,

+ list);

+

+ /*

+ * Do not hide this behind enospc_debug, this is actually

+ * important and indicates a real bug if this happens.

+ */

+ if (WARN_ON(space_info->bytes_pinned > 0 ||

+ space_info->bytes_reserved > 0 ||

+ space_info->bytes_may_use > 0))

+ btrfs_dump_space_info(info, space_info, 0, 0);

+ list_del(&space_info->list);

+ btrfs_sysfs_remove_space_info(space_info);

+ }

+ return 0;

+}

diff --git a/fs/btrfs/block-group.h b/fs/btrfs/block-group.h
new file mode 100644
index 0000000000000..c391800388dda
--- /dev/null
+++ b/fs/btrfs/block-group.h

@@ -0,0 +1,250 @@

+/* SPDX-License-Identifier: GPL-2.0 */

+

+#ifndef BTRFS_BLOCK_GROUP_H

+#define BTRFS_BLOCK_GROUP_H

+

+#include "free-space-cache.h"

+

+enum btrfs_disk_cache_state {

+ BTRFS_DC_WRITTEN,

+ BTRFS_DC_ERROR,

+ BTRFS_DC_CLEAR,

+ BTRFS_DC_SETUP,

+};

+

+/*

+ * Control flags for do_chunk_alloc's force field CHUNK_ALLOC_NO_FORCE means to

+ * only allocate a chunk if we really need one.

+ *

+ * CHUNK_ALLOC_LIMITED means to only try and allocate one if we have very few

+ * chunks already allocated. This is used as part of the clustering code to

+ * help make sure we have a good pool of storage to cluster in, without filling

+ * the FS with empty chunks

+ *

+ * CHUNK_ALLOC_FORCE means it must try to allocate one

+ */

+enum btrfs_chunk_alloc_enum {

+ CHUNK_ALLOC_NO_FORCE,

+ CHUNK_ALLOC_LIMITED,

+ CHUNK_ALLOC_FORCE,

+};

+

+struct btrfs_caching_control {

+ struct list_head list;

+ struct mutex mutex;

+ wait_queue_head_t wait;

+ struct btrfs_work work;

+ struct btrfs_block_group_cache *block_group;

+ u64 progress;

+ refcount_t count;

+};

+

+/* Once caching_thread() finds this much free space, it will wake up waiters. */

+#define CACHING_CTL_WAKE_UP SZ_2M

+

+struct btrfs_block_group_cache {

+ struct btrfs_key key;

+ struct btrfs_block_group_item item;

+ struct btrfs_fs_info *fs_info;

+ struct inode *inode;

+ spinlock_t lock;

+ u64 pinned;

+ u64 reserved;

+ u64 delalloc_bytes;

+ u64 bytes_super;

+ u64 flags;

+ u64 cache_generation;

+

+ /*

+ * If the free space extent count exceeds this number, convert the block

+ * group to bitmaps.

+ */

+ u32 bitmap_high_thresh;

+

+ /*

+ * If the free space extent count drops below this number, convert the

+ * block group back to extents.

+ */

+ u32 bitmap_low_thresh;

+

+ /*

+ * It is just used for the delayed data space allocation because

+ * only the data space allocation and the relative metadata update

+ * can be done cross the transaction.

+ */

+ struct rw_semaphore data_rwsem;

+

+ /* For raid56, this is a full stripe, without parity */

+ unsigned long full_stripe_len;

+

+ unsigned int ro;

+ unsigned int iref:1;

+ unsigned int has_caching_ctl:1;

+ unsigned int removed:1;

+

+ int disk_cache_state;

+

+ /* Cache tracking stuff */

+ int cached;

+ struct btrfs_caching_control *caching_ctl;

+ u64 last_byte_to_unpin;

+

+ struct btrfs_space_info *space_info;

+

+ /* Free space cache stuff */

+ struct btrfs_free_space_ctl *free_space_ctl;

+

+ /* Block group cache stuff */

+ struct rb_node cache_node;

+

+ /* For block groups in the same raid type */

+ struct list_head list;

+

+ /* Usage count */

+ atomic_t count;

+

+ /*

+ * List of struct btrfs_free_clusters for this block group.

+ * Today it will only have one thing on it, but that may change

+ */

+ struct list_head cluster_list;

+

+ /* For delayed block group creation or deletion of empty block groups */

+ struct list_head bg_list;

+

+ /* For read-only block groups */

+ struct list_head ro_list;

+

+ atomic_t trimming;

+

+ /* For dirty block groups */

+ struct list_head dirty_list;

+ struct list_head io_list;

+

+ struct btrfs_io_ctl io_ctl;

+

+ /*

+ * Incremented when doing extent allocations and holding a read lock

+ * on the space_info's groups_sem semaphore.

+ * Decremented when an ordered extent that represents an IO against this

+ * block group's range is created (after it's added to its inode's

+ * root's list of ordered extents) or immediately after the allocation

+ * if it's a metadata extent or fallocate extent (for these cases we

+ * don't create ordered extents).

+ */

+ atomic_t reservations;

+

+ /*

+ * Incremented while holding the spinlock *lock* by a task checking if

+ * it can perform a nocow write (incremented if the value for the *ro*

+ * field is 0). Decremented by such tasks once they create an ordered

+ * extent or before that if some error happens before reaching that step.

+ * This is to prevent races between block group relocation and nocow

+ * writes through direct IO.

+ */

+ atomic_t nocow_writers;

+

+ /* Lock for free space tree operations. */

+ struct mutex free_space_lock;

+

+ /*

+ * Does the block group need to be added to the free space tree?

+ * Protected by free_space_lock.

+ */

+ int needs_free_space;

+

+ /* Record locked full stripes for RAID5/6 block group */

+ struct btrfs_full_stripe_locks_tree full_stripe_locks_root;

+};

+

+#ifdef CONFIG_BTRFS_DEBUG

+static inline int btrfs_should_fragment_free_space(

+ struct btrfs_block_group_cache *block_group)

+{

+ struct btrfs_fs_info *fs_info = block_group->fs_info;

+

+ return (btrfs_test_opt(fs_info, FRAGMENT_METADATA) &&

+ block_group->flags & BTRFS_BLOCK_GROUP_METADATA) ||

+ (btrfs_test_opt(fs_info, FRAGMENT_DATA) &&

+ block_group->flags & BTRFS_BLOCK_GROUP_DATA);

+}

+#endif

+

+struct btrfs_block_group_cache *btrfs_lookup_first_block_group(

+ struct btrfs_fs_info *info, u64 bytenr);

+struct btrfs_block_group_cache *btrfs_lookup_block_group(

+ struct btrfs_fs_info *info, u64 bytenr);

+struct btrfs_block_group_cache *btrfs_next_block_group(

+ struct btrfs_block_group_cache *cache);

+void btrfs_get_block_group(struct btrfs_block_group_cache *cache);

+void btrfs_put_block_group(struct btrfs_block_group_cache *cache);

+void btrfs_dec_block_group_reservations(struct btrfs_fs_info *fs_info,

+ const u64 start);

+void btrfs_wait_block_group_reservations(struct btrfs_block_group_cache *bg);

+bool btrfs_inc_nocow_writers(struct btrfs_fs_info *fs_info, u64 bytenr);

+void btrfs_dec_nocow_writers(struct btrfs_fs_info *fs_info, u64 bytenr);

+void btrfs_wait_nocow_writers(struct btrfs_block_group_cache *bg);

+void btrfs_wait_block_group_cache_progress(struct btrfs_block_group_cache *cache,

+ u64 num_bytes);

+int btrfs_wait_block_group_cache_done(struct btrfs_block_group_cache *cache);

+int btrfs_cache_block_group(struct btrfs_block_group_cache *cache,

+ int load_cache_only);

+void btrfs_put_caching_control(struct btrfs_caching_control *ctl);

+struct btrfs_caching_control *btrfs_get_caching_control(

+ struct btrfs_block_group_cache *cache);

+u64 add_new_free_space(struct btrfs_block_group_cache *block_group,

+ u64 start, u64 end);

+struct btrfs_trans_handle *btrfs_start_trans_remove_block_group(

+ struct btrfs_fs_info *fs_info,

+ const u64 chunk_offset);

+int btrfs_remove_block_group(struct btrfs_trans_handle *trans,

+ u64 group_start, struct extent_map *em);

+void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info);

+void btrfs_mark_bg_unused(struct btrfs_block_group_cache *bg);

+int btrfs_read_block_groups(struct btrfs_fs_info *info);

+int btrfs_make_block_group(struct btrfs_trans_handle *trans, u64 bytes_used,

+ u64 type, u64 chunk_offset, u64 size);

+void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans);

+int btrfs_inc_block_group_ro(struct btrfs_block_group_cache *cache);

+void btrfs_dec_block_group_ro(struct btrfs_block_group_cache *cache);

+int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans);

+int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans);

+int btrfs_setup_space_cache(struct btrfs_trans_handle *trans);

+int btrfs_update_block_group(struct btrfs_trans_handle *trans,

+ u64 bytenr, u64 num_bytes, int alloc);

+int btrfs_add_reserved_bytes(struct btrfs_block_group_cache *cache,

+ u64 ram_bytes, u64 num_bytes, int delalloc);

+void btrfs_free_reserved_bytes(struct btrfs_block_group_cache *cache,

+ u64 num_bytes, int delalloc);

+int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags,

+ enum btrfs_chunk_alloc_enum force);

+int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, u64 type);

+void check_system_chunk(struct btrfs_trans_handle *trans, const u64 type);

+u64 btrfs_get_alloc_profile(struct btrfs_fs_info *fs_info, u64 orig_flags);

+void btrfs_put_block_group_cache(struct btrfs_fs_info *info);

+int btrfs_free_block_groups(struct btrfs_fs_info *info);

+

+static inline u64 btrfs_data_alloc_profile(struct btrfs_fs_info *fs_info)

+{

+ return btrfs_get_alloc_profile(fs_info, BTRFS_BLOCK_GROUP_DATA);

+}

+

+static inline u64 btrfs_metadata_alloc_profile(struct btrfs_fs_info *fs_info)

+{

+ return btrfs_get_alloc_profile(fs_info, BTRFS_BLOCK_GROUP_METADATA);

+}

+

+static inline u64 btrfs_system_alloc_profile(struct btrfs_fs_info *fs_info)

+{

+ return btrfs_get_alloc_profile(fs_info, BTRFS_BLOCK_GROUP_SYSTEM);

+}

+

+static inline int btrfs_block_group_cache_done(

+ struct btrfs_block_group_cache *cache)

+{

+ smp_mb();

+ return cache->cached == BTRFS_CACHE_FINISHED ||

+ cache->cached == BTRFS_CACHE_ERROR;

+}

+

+#endif /* BTRFS_BLOCK_GROUP_H */

@@ -1,9 +1,9 @@

// SPDX-License-Identifier: GPL-2.0

+#include "misc.h"

#include "ctree.h"

#include "block-rsv.h"

#include "space-info.h"

-#include "math.h"

#include "transaction.h"

static u64 block_rsv_release_bytes(struct btrfs_fs_info *fs_info,

@@ -54,8 +54,9 @@ static u64 block_rsv_release_bytes(struct btrfs_fs_info *fs_info,

spin_unlock(&dest->lock);

}

if (num_bytes)

- btrfs_space_info_add_old_bytes(fs_info, space_info,

- num_bytes);

+ btrfs_space_info_free_bytes_may_use(fs_info,

+ space_info,

+ num_bytes);

}

if (qgroup_to_release_ret)

*qgroup_to_release_ret = qgroup_to_release;

@@ -258,6 +259,7 @@ 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_space_info *sinfo = block_rsv->space_info;

u64 num_bytes;

+ unsigned min_items;

/*

* The global block rsv is based on the size of the extent tree, the

@@ -267,7 +269,26 @@ void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info)

num_bytes = btrfs_root_used(&fs_info->extent_root->root_item) +

btrfs_root_used(&fs_info->csum_root->root_item) +

btrfs_root_used(&fs_info->tree_root->root_item);

- num_bytes = max_t(u64, num_bytes, SZ_16M);

+

+ /*

+ * We at a minimum are going to modify the csum root, the tree root, and

+ * the extent root.

+ */

+ min_items = 3;

+

+ /*

+ * But we also want to reserve enough space so we can do the fallback

+ * global reserve for an unlink, which is an additional 5 items (see the

+ * comment in __unlink_start_trans for what we're modifying.)

+ *

+ * But we also need space for the delayed ref updates from the unlink,

+ * so its 10, 5 for the actual operation, and 5 for the delayed ref

+ * updates.

+ */

+ min_items += 10;

+

+ num_bytes = max_t(u64, num_bytes,

+ btrfs_calc_insert_metadata_size(fs_info, min_items));

spin_lock(&sinfo->lock);

spin_lock(&block_rsv->lock);

@@ -275,25 +296,16 @@ void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info)

block_rsv->size = min_t(u64, num_bytes, SZ_512M);

if (block_rsv->reserved < block_rsv->size) {

- num_bytes = btrfs_space_info_used(sinfo, true);

- if (sinfo->total_bytes > num_bytes) {

- num_bytes = sinfo->total_bytes - num_bytes;

- num_bytes = min(num_bytes,

- block_rsv->size - block_rsv->reserved);

- block_rsv->reserved += num_bytes;

- btrfs_space_info_update_bytes_may_use(fs_info, sinfo,

- num_bytes);

- trace_btrfs_space_reservation(fs_info, "space_info",

- sinfo->flags, num_bytes,

- 1);

- }

+ num_bytes = block_rsv->size - block_rsv->reserved;

+ block_rsv->reserved += num_bytes;

+ btrfs_space_info_update_bytes_may_use(fs_info, sinfo,

+ num_bytes);

} else if (block_rsv->reserved > block_rsv->size) {

num_bytes = block_rsv->reserved - block_rsv->size;

btrfs_space_info_update_bytes_may_use(fs_info, sinfo,

-num_bytes);

- trace_btrfs_space_reservation(fs_info, "space_info",

- sinfo->flags, num_bytes, 0);

block_rsv->reserved = block_rsv->size;

+ btrfs_try_granting_tickets(fs_info, sinfo);

}

if (block_rsv->reserved == block_rsv->size)

@@ -940,7 +940,7 @@ static void btrfsic_stack_frame_free(struct btrfsic_stack_frame *sf)

kfree(sf);

}

-static int btrfsic_process_metablock(

+static noinline_for_stack int btrfsic_process_metablock(

struct btrfsic_state *state,

struct btrfsic_block *const first_block,

struct btrfsic_block_data_ctx *const first_block_ctx,

@@ -1706,8 +1706,9 @@ static void btrfsic_dump_database(struct btrfsic_state *state)

* Test whether the disk block contains a tree block (leaf or node)

* (note that this test fails for the super block)

*/

-static int btrfsic_test_for_metadata(struct btrfsic_state *state,

- char **datav, unsigned int num_pages)

+static noinline_for_stack int btrfsic_test_for_metadata(

+ struct btrfsic_state *state,

+ char **datav, unsigned int num_pages)

{

struct btrfs_fs_info *fs_info = state->fs_info;

SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);

@@ -18,6 +18,7 @@

#include <linux/sched/mm.h>

#include <linux/log2.h>

#include <crypto/hash.h>

+#include "misc.h"

#include "ctree.h"

#include "disk-io.h"

#include "transaction.h"

@@ -1039,7 +1040,7 @@ int btrfs_compress_pages(unsigned int type_level, struct address_space *mapping,

struct list_head *workspace;

int ret;

- level = btrfs_compress_op[type]->set_level(level);

+ level = btrfs_compress_set_level(type, level);

workspace = get_workspace(type, level);

ret = btrfs_compress_op[type]->compress_pages(workspace, mapping,

start, pages,

@@ -1611,7 +1612,23 @@ unsigned int btrfs_compress_str2level(unsigned int type, const char *str)

level = 0;

}

- level = btrfs_compress_op[type]->set_level(level);

+ level = btrfs_compress_set_level(type, level);

+

+ return level;

+}

+

+/*

+ * Adjust @level according to the limits of the compression algorithm or

+ * fallback to default

+ */

+unsigned int btrfs_compress_set_level(int type, unsigned level)

+{

+ const struct btrfs_compress_op *ops = btrfs_compress_op[type];

+

+ if (level == 0)

+ level = ops->default_level;

+ else

+ level = min(level, ops->max_level);

return level;

}

@@ -156,12 +156,9 @@ struct btrfs_compress_op {

unsigned long start_byte,

size_t srclen, size_t destlen);

- /*

- * This bounds the level set by the user to be within range of a

- * particular compression type. It returns the level that will be used

- * if the level is out of bounds or the default if 0 is passed in.

- */

- unsigned int (*set_level)(unsigned int level);

+ /* Maximum level supported by the compression algorithm */

+ unsigned int max_level;

+ unsigned int default_level;

};

/* The heuristic workspaces are managed via the 0th workspace manager */

@@ -175,6 +172,8 @@ extern const struct btrfs_compress_op btrfs_zstd_compress;

const char* btrfs_compress_type2str(enum btrfs_compression_type type);

bool btrfs_compress_is_valid_type(const char *str, size_t len);

+unsigned int btrfs_compress_set_level(int type, unsigned level);

+

int btrfs_compress_heuristic(struct inode *inode, u64 start, u64 end);

#endif

diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 5df76c17775ad..e59cde204b2fe 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c

@@ -29,6 +29,28 @@ static int balance_node_right(struct btrfs_trans_handle *trans,

static void del_ptr(struct btrfs_root *root, struct btrfs_path *path,

int level, int slot);

+static const struct btrfs_csums {

+ u16 size;

+ const char *name;

+} btrfs_csums[] = {

+ [BTRFS_CSUM_TYPE_CRC32] = { .size = 4, .name = "crc32c" },

+};

+

+int btrfs_super_csum_size(const struct btrfs_super_block *s)

+{

+ u16 t = btrfs_super_csum_type(s);

+ /*

+ * csum type is validated at mount time

+ */

+ return btrfs_csums[t].size;

+}

+

+const char *btrfs_super_csum_name(u16 csum_type)

+{

+ /* csum type is validated at mount time */

+ return btrfs_csums[csum_type].name;

+}

+

struct btrfs_path *btrfs_alloc_path(void)

{

return kmem_cache_zalloc(btrfs_path_cachep, GFP_NOFS);

@@ -376,8 +398,6 @@ void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info,

* The 'start address' is the logical address of the *new* root node

* for root replace operations, or the logical address of the affected

* block for all other operations.

- *

- * Note: must be called with write lock for fs_info::tree_mod_log_lock.

*/

static noinline int

__tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm)

@@ -387,6 +407,8 @@ __tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm)

struct rb_node *parent = NULL;

struct tree_mod_elem *cur;

+ lockdep_assert_held_write(&fs_info->tree_mod_log_lock);

+

tm->seq = btrfs_inc_tree_mod_seq(fs_info);

tm_root = &fs_info->tree_mod_log;

@@ -1343,6 +1365,7 @@ get_old_root(struct btrfs_root *root, u64 time_seq)

struct tree_mod_elem *tm;

struct extent_buffer *eb = NULL;

struct extent_buffer *eb_root;

+ u64 eb_root_owner = 0;

struct extent_buffer *old;

struct tree_mod_root *old_root = NULL;

u64 old_generation = 0;

@@ -1380,6 +1403,7 @@ get_old_root(struct btrfs_root *root, u64 time_seq)

free_extent_buffer(old);

}

} else if (old_root) {

+ eb_root_owner = btrfs_header_owner(eb_root);

btrfs_tree_read_unlock(eb_root);

free_extent_buffer(eb_root);

eb = alloc_dummy_extent_buffer(fs_info, logical);

@@ -1396,7 +1420,7 @@ get_old_root(struct btrfs_root *root, u64 time_seq)

if (old_root) {

btrfs_set_header_bytenr(eb, eb->start);

btrfs_set_header_backref_rev(eb, BTRFS_MIXED_BACKREF_REV);

- btrfs_set_header_owner(eb, btrfs_header_owner(eb_root));

+ btrfs_set_header_owner(eb, eb_root_owner);

btrfs_set_header_level(eb, old_root->level);

btrfs_set_header_generation(eb, old_generation);

}

@@ -1790,8 +1814,8 @@ static void root_sub_used(struct btrfs_root *root, u32 size)

/* given a node and slot number, this reads the blocks it points to. The

* extent buffer is returned with a reference taken (but unlocked).

*/

-static noinline struct extent_buffer *read_node_slot(

- struct extent_buffer *parent, int slot)

+struct extent_buffer *btrfs_read_node_slot(struct extent_buffer *parent,

+ int slot)

{

int level = btrfs_header_level(parent);

struct extent_buffer *eb;

@@ -1860,7 +1884,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,

return 0;

/* promote the child to a root */

- child = read_node_slot(mid, 0);

+ child = btrfs_read_node_slot(mid, 0);

if (IS_ERR(child)) {

ret = PTR_ERR(child);

btrfs_handle_fs_error(fs_info, ret, NULL);

@@ -1900,7 +1924,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,

BTRFS_NODEPTRS_PER_BLOCK(fs_info) / 4)

return 0;

- left = read_node_slot(parent, pslot - 1);

+ left = btrfs_read_node_slot(parent, pslot - 1);

if (IS_ERR(left))

left = NULL;

@@ -1915,7 +1939,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,

}

}

- right = read_node_slot(parent, pslot + 1);

+ right = btrfs_read_node_slot(parent, pslot + 1);

if (IS_ERR(right))

right = NULL;

@@ -2075,7 +2099,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,

if (!parent)

return 1;

- left = read_node_slot(parent, pslot - 1);

+ left = btrfs_read_node_slot(parent, pslot - 1);

if (IS_ERR(left))

left = NULL;

@@ -2127,7 +2151,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,

btrfs_tree_unlock(left);

free_extent_buffer(left);

}

- right = read_node_slot(parent, pslot + 1);

+ right = btrfs_read_node_slot(parent, pslot + 1);

if (IS_ERR(right))

right = NULL;

@@ -2889,15 +2913,13 @@ cow_done:

if (!p->skip_locking) {

level = btrfs_header_level(b);

if (level <= write_lock_level) {

- err = btrfs_try_tree_write_lock(b);

- if (!err) {

+ if (!btrfs_try_tree_write_lock(b)) {

btrfs_set_path_blocking(p);

btrfs_tree_lock(b);

}

p->locks[level] = BTRFS_WRITE_LOCK;

} else {

- err = btrfs_tree_read_lock_atomic(b);

- if (!err) {

+ if (!btrfs_tree_read_lock_atomic(b)) {

btrfs_set_path_blocking(p);

btrfs_tree_read_lock(b);

}

@@ -3031,8 +3053,7 @@ again:

}

level = btrfs_header_level(b);

- err = btrfs_tree_read_lock_atomic(b);

- if (!err) {

+ if (!btrfs_tree_read_lock_atomic(b)) {

btrfs_set_path_blocking(p);

btrfs_tree_read_lock(b);

}

@@ -3572,7 +3593,7 @@ static int leaf_space_used(struct extent_buffer *l, int start, int nr)

if (!nr)

return 0;

- btrfs_init_map_token(&token);

+ btrfs_init_map_token(&token, l);

start_item = btrfs_item_nr(start);

end_item = btrfs_item_nr(end);

data_len = btrfs_token_item_offset(l, start_item, &token) +

@@ -3630,8 +3651,6 @@ static noinline int __push_leaf_right(struct btrfs_path *path,

u32 data_end;

u32 this_item_size;

- btrfs_init_map_token(&token);

-

if (empty)

nr = 0;

else

@@ -3704,6 +3723,7 @@ static noinline int __push_leaf_right(struct btrfs_path *path,

push_items * sizeof(struct btrfs_item));

/* update the item pointers */

+ btrfs_init_map_token(&token, right);

right_nritems += push_items;

btrfs_set_header_nritems(right, right_nritems);

push_space = BTRFS_LEAF_DATA_SIZE(fs_info);

@@ -3781,7 +3801,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root

btrfs_assert_tree_locked(path->nodes[1]);

- right = read_node_slot(upper, slot + 1);

+ right = btrfs_read_node_slot(upper, slot + 1);

/*

* slot + 1 is not valid or we fail to read the right node,

* no big deal, just return.

@@ -3858,8 +3878,6 @@ static noinline int __push_leaf_left(struct btrfs_path *path, int data_size,

u32 old_left_item_size;

struct btrfs_map_token token;

- btrfs_init_map_token(&token);

-

if (empty)

nr = min(right_nritems, max_slot);

else

@@ -3913,6 +3931,7 @@ static noinline int __push_leaf_left(struct btrfs_path *path, int data_size,

old_left_nritems = btrfs_header_nritems(left);

BUG_ON(old_left_nritems <= 0);

+ btrfs_init_map_token(&token, left);

old_left_item_size = btrfs_item_offset_nr(left, old_left_nritems - 1);

for (i = old_left_nritems; i < old_left_nritems + push_items; i++) {

u32 ioff;

@@ -3944,6 +3963,8 @@ static noinline int __push_leaf_left(struct btrfs_path *path, int data_size,

(btrfs_header_nritems(right) - push_items) *

sizeof(struct btrfs_item));

}

+

+ btrfs_init_map_token(&token, right);

right_nritems -= push_items;

btrfs_set_header_nritems(right, right_nritems);

push_space = BTRFS_LEAF_DATA_SIZE(fs_info);

@@ -4015,7 +4036,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root

btrfs_assert_tree_locked(path->nodes[1]);

- left = read_node_slot(path->nodes[1], slot - 1);

+ left = btrfs_read_node_slot(path->nodes[1], slot - 1);

/*

* slot - 1 is not valid or we fail to read the left node,

* no big deal, just return.

@@ -4074,8 +4095,6 @@ static noinline void copy_for_split(struct btrfs_trans_handle *trans,

struct btrfs_disk_key disk_key;

struct btrfs_map_token token;

- btrfs_init_map_token(&token);

-

nritems = nritems - mid;

btrfs_set_header_nritems(right, nritems);

data_copy_size = btrfs_item_end_nr(l, mid) - leaf_data_end(l);

@@ -4091,6 +4110,7 @@ static noinline void copy_for_split(struct btrfs_trans_handle *trans,

rt_data_off = BTRFS_LEAF_DATA_SIZE(fs_info) - btrfs_item_end_nr(l, mid);

+ btrfs_init_map_token(&token, right);

for (i = 0; i < nritems; i++) {

struct btrfs_item *item = btrfs_item_nr(i);

u32 ioff;

@@ -4574,8 +4594,6 @@ void btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end)

int i;

struct btrfs_map_token token;

- btrfs_init_map_token(&token);

-

leaf = path->nodes[0];

slot = path->slots[0];

@@ -4597,6 +4615,7 @@ void btrfs_truncate_item(struct btrfs_path *path, u32 new_size, int from_end)

* item0..itemN ... dataN.offset..dataN.size .. data0.size

*/

/* first correct the data pointers */

+ btrfs_init_map_token(&token, leaf);

for (i = slot; i < nritems; i++) {

u32 ioff;

item = btrfs_item_nr(i);

@@ -4671,8 +4690,6 @@ void btrfs_extend_item(struct btrfs_path *path, u32 data_size)

int i;

struct btrfs_map_token token;

- btrfs_init_map_token(&token);

-

leaf = path->nodes[0];

nritems = btrfs_header_nritems(leaf);

@@ -4697,6 +4714,7 @@ void btrfs_extend_item(struct btrfs_path *path, u32 data_size)

* item0..itemN ... dataN.offset..dataN.size .. data0.size

*/

/* first correct the data pointers */

+ btrfs_init_map_token(&token, leaf);

for (i = slot; i < nritems; i++) {

u32 ioff;

item = btrfs_item_nr(i);

@@ -4748,8 +4766,6 @@ void setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *path,

}

btrfs_unlock_up_safe(path, 1);

- btrfs_init_map_token(&token);

-

leaf = path->nodes[0];

slot = path->slots[0];

@@ -4763,6 +4779,7 @@ void setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *path,

BUG();

}

+ btrfs_init_map_token(&token, leaf);

if (slot != nritems) {

unsigned int old_data = btrfs_item_end_nr(leaf, slot);

@@ -4969,9 +4986,6 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,

int wret;

int i;

u32 nritems;

- struct btrfs_map_token token;

-

- btrfs_init_map_token(&token);

leaf = path->nodes[0];

last_off = btrfs_item_offset_nr(leaf, slot + nr - 1);

@@ -4983,12 +4997,14 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,

if (slot + nr != nritems) {

int data_end = leaf_data_end(leaf);

+ struct btrfs_map_token token;

memmove_extent_buffer(leaf, BTRFS_LEAF_DATA_OFFSET +

data_end + dsize,

BTRFS_LEAF_DATA_OFFSET + data_end,

last_off - data_end);

+ btrfs_init_map_token(&token, leaf);

for (i = slot + nr; i < nritems; i++) {

u32 ioff;

@@ -5222,7 +5238,7 @@ find_next_key:

goto out;

}

btrfs_set_path_blocking(path);

- cur = read_node_slot(cur, slot);

+ cur = btrfs_read_node_slot(cur, slot);

if (IS_ERR(cur)) {

ret = PTR_ERR(cur);

goto out;

@@ -5244,368 +5260,6 @@ out:

return ret;

}

-static int tree_move_down(struct btrfs_path *path, int *level)

-{

- struct extent_buffer *eb;

-

- BUG_ON(*level == 0);

- eb = read_node_slot(path->nodes[*level], path->slots[*level]);

- if (IS_ERR(eb))

- return PTR_ERR(eb);

-

- path->nodes[*level - 1] = eb;

- path->slots[*level - 1] = 0;

- (*level)--;

- return 0;

-}

-

-static int tree_move_next_or_upnext(struct btrfs_path *path,

- int *level, int root_level)

-{

- int ret = 0;

- int nritems;

- nritems = btrfs_header_nritems(path->nodes[*level]);

-

- path->slots[*level]++;

-

- while (path->slots[*level] >= nritems) {

- if (*level == root_level)

- return -1;

-

- /* move upnext */

- path->slots[*level] = 0;

- free_extent_buffer(path->nodes[*level]);

- path->nodes[*level] = NULL;

- (*level)++;

- path->slots[*level]++;

-

- nritems = btrfs_header_nritems(path->nodes[*level]);

- ret = 1;

- }

- return ret;

-}

-

-/*

- * Returns 1 if it had to move up and next. 0 is returned if it moved only next

- * or down.

- */

-static int tree_advance(struct btrfs_path *path,

- int *level, int root_level,

- int allow_down,

- struct btrfs_key *key)

-{

- int ret;

-

- if (*level == 0 || !allow_down) {

- ret = tree_move_next_or_upnext(path, level, root_level);

- } else {

- ret = tree_move_down(path, level);

- }

- if (ret >= 0) {

- if (*level == 0)

- btrfs_item_key_to_cpu(path->nodes[*level], key,

- path->slots[*level]);

- else

- btrfs_node_key_to_cpu(path->nodes[*level], key,

- path->slots[*level]);

- }

- return ret;

-}

-

-static int tree_compare_item(struct btrfs_path *left_path,

- struct btrfs_path *right_path,

- char *tmp_buf)

-{

- int cmp;

- int len1, len2;

- unsigned long off1, off2;

-

- len1 = btrfs_item_size_nr(left_path->nodes[0], left_path->slots[0]);

- len2 = btrfs_item_size_nr(right_path->nodes[0], right_path->slots[0]);

- if (len1 != len2)

- return 1;

-

- off1 = btrfs_item_ptr_offset(left_path->nodes[0], left_path->slots[0]);

- off2 = btrfs_item_ptr_offset(right_path->nodes[0],

- right_path->slots[0]);

-

- read_extent_buffer(left_path->nodes[0], tmp_buf, off1, len1);

-

- cmp = memcmp_extent_buffer(right_path->nodes[0], tmp_buf, off2, len1);

- if (cmp)

- return 1;

- return 0;

-}

-

-#define ADVANCE 1

-#define ADVANCE_ONLY_NEXT -1

-

-/*

- * This function compares two trees and calls the provided callback for

- * every changed/new/deleted item it finds.

- * If shared tree blocks are encountered, whole subtrees are skipped, making

- * the compare pretty fast on snapshotted subvolumes.

- *

- * This currently works on commit roots only. As commit roots are read only,

- * we don't do any locking. The commit roots are protected with transactions.

- * Transactions are ended and rejoined when a commit is tried in between.

- *

- * This function checks for modifications done to the trees while comparing.

- * If it detects a change, it aborts immediately.

- */

-int btrfs_compare_trees(struct btrfs_root *left_root,

- struct btrfs_root *right_root,

- btrfs_changed_cb_t changed_cb, void *ctx)

-{

- struct btrfs_fs_info *fs_info = left_root->fs_info;

- int ret;

- int cmp;

- struct btrfs_path *left_path = NULL;

- struct btrfs_path *right_path = NULL;

- struct btrfs_key left_key;

- struct btrfs_key right_key;

- char *tmp_buf = NULL;

- int left_root_level;

- int right_root_level;

- int left_level;

- int right_level;

- int left_end_reached;

- int right_end_reached;

- int advance_left;

- int advance_right;

- u64 left_blockptr;

- u64 right_blockptr;

- u64 left_gen;

- u64 right_gen;

-

- left_path = btrfs_alloc_path();

- if (!left_path) {

- ret = -ENOMEM;

- goto out;

- }

- right_path = btrfs_alloc_path();

- if (!right_path) {

- ret = -ENOMEM;

- goto out;

- }

-

- tmp_buf = kvmalloc(fs_info->nodesize, GFP_KERNEL);

- if (!tmp_buf) {

- ret = -ENOMEM;

- goto out;

- }

-

- left_path->search_commit_root = 1;

- left_path->skip_locking = 1;

- right_path->search_commit_root = 1;

- right_path->skip_locking = 1;

-

- /*

- * Strategy: Go to the first items of both trees. Then do

- *

- * If both trees are at level 0

- * Compare keys of current items

- * If left < right treat left item as new, advance left tree

- * and repeat

- * If left > right treat right item as deleted, advance right tree

- * and repeat

- * If left == right do deep compare of items, treat as changed if

- * needed, advance both trees and repeat

- * If both trees are at the same level but not at level 0

- * Compare keys of current nodes/leafs

- * If left < right advance left tree and repeat

- * If left > right advance right tree and repeat

- * If left == right compare blockptrs of the next nodes/leafs

- * If they match advance both trees but stay at the same level

- * and repeat

- * If they don't match advance both trees while allowing to go

- * deeper and repeat

- * If tree levels are different

- * Advance the tree that needs it and repeat

- *

- * Advancing a tree means:

- * If we are at level 0, try to go to the next slot. If that's not

- * possible, go one level up and repeat. Stop when we found a level

- * where we could go to the next slot. We may at this point be on a

- * node or a leaf.

- *

- * If we are not at level 0 and not on shared tree blocks, go one

- * level deeper.

- *

- * If we are not at level 0 and on shared tree blocks, go one slot to

- * the right if possible or go up and right.

- */

-

- down_read(&fs_info->commit_root_sem);

- left_level = btrfs_header_level(left_root->commit_root);

- left_root_level = left_level;

- left_path->nodes[left_level] =

- btrfs_clone_extent_buffer(left_root->commit_root);

- if (!left_path->nodes[left_level]) {

- up_read(&fs_info->commit_root_sem);

- ret = -ENOMEM;

- goto out;

- }

-

- right_level = btrfs_header_level(right_root->commit_root);

- right_root_level = right_level;

- right_path->nodes[right_level] =

- btrfs_clone_extent_buffer(right_root->commit_root);

- if (!right_path->nodes[right_level]) {

- up_read(&fs_info->commit_root_sem);

- ret = -ENOMEM;

- goto out;

- }

- up_read(&fs_info->commit_root_sem);

-

- if (left_level == 0)

- btrfs_item_key_to_cpu(left_path->nodes[left_level],

- &left_key, left_path->slots[left_level]);

- else

- btrfs_node_key_to_cpu(left_path->nodes[left_level],

- &left_key, left_path->slots[left_level]);

- if (right_level == 0)

- btrfs_item_key_to_cpu(right_path->nodes[right_level],

- &right_key, right_path->slots[right_level]);

- else

- btrfs_node_key_to_cpu(right_path->nodes[right_level],

- &right_key, right_path->slots[right_level]);

-

- left_end_reached = right_end_reached = 0;

- advance_left = advance_right = 0;

-

- while (1) {

- if (advance_left && !left_end_reached) {

- ret = tree_advance(left_path, &left_level,

- left_root_level,

- advance_left != ADVANCE_ONLY_NEXT,

- &left_key);

- if (ret == -1)

- left_end_reached = ADVANCE;

- else if (ret < 0)

- goto out;

- advance_left = 0;

- }

- if (advance_right && !right_end_reached) {

- ret = tree_advance(right_path, &right_level,

- right_root_level,

- advance_right != ADVANCE_ONLY_NEXT,

- &right_key);

- if (ret == -1)

- right_end_reached = ADVANCE;

- else if (ret < 0)

- goto out;

- advance_right = 0;

- }

-

- if (left_end_reached && right_end_reached) {

- ret = 0;

- goto out;

- } else if (left_end_reached) {

- if (right_level == 0) {

- ret = changed_cb(left_path, right_path,

- &right_key,

- BTRFS_COMPARE_TREE_DELETED,

- ctx);

- if (ret < 0)

- goto out;

- }

- advance_right = ADVANCE;

- continue;

- } else if (right_end_reached) {

- if (left_level == 0) {

- ret = changed_cb(left_path, right_path,

- &left_key,

- BTRFS_COMPARE_TREE_NEW,

- ctx);

- if (ret < 0)

- goto out;

- }

- advance_left = ADVANCE;

- continue;

- }

-

- if (left_level == 0 && right_level == 0) {

- cmp = btrfs_comp_cpu_keys(&left_key, &right_key);

- if (cmp < 0) {

- ret = changed_cb(left_path, right_path,

- &left_key,

- BTRFS_COMPARE_TREE_NEW,

- ctx);

- if (ret < 0)

- goto out;

- advance_left = ADVANCE;

- } else if (cmp > 0) {

- ret = changed_cb(left_path, right_path,

- &right_key,

- BTRFS_COMPARE_TREE_DELETED,

- ctx);

- if (ret < 0)

- goto out;

- advance_right = ADVANCE;

- } else {

- enum btrfs_compare_tree_result result;

-

- WARN_ON(!extent_buffer_uptodate(left_path->nodes[0]));

- ret = tree_compare_item(left_path, right_path,

- tmp_buf);

- if (ret)

- result = BTRFS_COMPARE_TREE_CHANGED;

- else

- result = BTRFS_COMPARE_TREE_SAME;

- ret = changed_cb(left_path, right_path,

- &left_key, result, ctx);

- if (ret < 0)

- goto out;

- advance_left = ADVANCE;

- advance_right = ADVANCE;

- }

- } else if (left_level == right_level) {

- cmp = btrfs_comp_cpu_keys(&left_key, &right_key);

- if (cmp < 0) {

- advance_left = ADVANCE;

- } else if (cmp > 0) {

- advance_right = ADVANCE;

- } else {

- left_blockptr = btrfs_node_blockptr(

- left_path->nodes[left_level],

- left_path->slots[left_level]);

- right_blockptr = btrfs_node_blockptr(

- right_path->nodes[right_level],

- right_path->slots[right_level]);

- left_gen = btrfs_node_ptr_generation(

- left_path->nodes[left_level],

- left_path->slots[left_level]);

- right_gen = btrfs_node_ptr_generation(

- right_path->nodes[right_level],

- right_path->slots[right_level]);

- if (left_blockptr == right_blockptr &&

- left_gen == right_gen) {

- /*

- * As we're on a shared block, don't

- * allow to go deeper.

- */

- advance_left = ADVANCE_ONLY_NEXT;

- advance_right = ADVANCE_ONLY_NEXT;

- } else {

- advance_left = ADVANCE;

- advance_right = ADVANCE;

- }

- }

- } else if (left_level < right_level) {

- advance_right = ADVANCE;

- } else {

- advance_left = ADVANCE;

- }

- }

-

-out:

- btrfs_free_path(left_path);

- btrfs_free_path(right_path);

- kvfree(tmp_buf);

- return ret;

-}

-

/*

* this is similar to btrfs_next_leaf, but does not try to preserve

* and fixup the path. It looks for and returns the next key in the

@@ -5623,7 +5277,7 @@ int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,

int slot;

struct extent_buffer *c;

- WARN_ON(!path->keep_locks);

+ WARN_ON(!path->keep_locks && !path->skip_locking);

while (level < BTRFS_MAX_LEVEL) {

if (!path->nodes[level])

return 1;

@@ -5639,7 +5293,7 @@ next:

!path->nodes[level + 1])

return 1;

- if (path->locks[level + 1]) {

+ if (path->locks[level + 1] || path->skip_locking) {

level++;

continue;

}

diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 94660063a1628..19d669d12ca15 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h

@@ -16,7 +16,6 @@

#include <linux/backing-dev.h>

#include <linux/wait.h>

#include <linux/slab.h>

-#include <linux/kobject.h>

#include <trace/events/btrfs.h>

#include <asm/kmap_types.h>

#include <asm/unaligned.h>

@@ -39,10 +38,12 @@ struct btrfs_transaction;

struct btrfs_pending_snapshot;

struct btrfs_delayed_ref_root;

struct btrfs_space_info;

+struct btrfs_block_group_cache;

extern struct kmem_cache *btrfs_trans_handle_cachep;

extern struct kmem_cache *btrfs_bit_radix_cachep;

extern struct kmem_cache *btrfs_path_cachep;

extern struct kmem_cache *btrfs_free_space_cachep;

+extern struct kmem_cache *btrfs_free_space_bitmap_cachep;

struct btrfs_ordered_sum;

struct btrfs_ref;

@@ -82,10 +83,6 @@ struct btrfs_ref;

*/

#define BTRFS_LINK_MAX 65535U

-/* four bytes for CRC32 */

-static const int btrfs_csum_sizes[] = { 4 };

-static const char *btrfs_csum_names[] = { "crc32c" };

-

#define BTRFS_EMPTY_DIR_SIZE 0

/* ioprio of readahead is set to idle */

@@ -397,12 +394,6 @@ struct btrfs_dev_replace {

wait_queue_head_t replace_wait;

};

-/* For raid type sysfs entries */

-struct raid_kobject {

- u64 flags;

- struct kobject kobj;

-};

-

/*

* free clusters are used to claim free space in relatively large chunks,

* allowing us to do less seeky writes. They are used for all metadata

@@ -439,40 +430,6 @@ enum btrfs_caching_type {

BTRFS_CACHE_ERROR,

};

-enum btrfs_disk_cache_state {

- BTRFS_DC_WRITTEN,

- BTRFS_DC_ERROR,

- BTRFS_DC_CLEAR,

- BTRFS_DC_SETUP,

-};

-

-struct btrfs_caching_control {

- struct list_head list;

- struct mutex mutex;

- wait_queue_head_t wait;

- struct btrfs_work work;

- struct btrfs_block_group_cache *block_group;

- u64 progress;

- refcount_t count;

-};

-

-/* Once caching_thread() finds this much free space, it will wake up waiters. */

-#define CACHING_CTL_WAKE_UP SZ_2M

-

-struct btrfs_io_ctl {

- void *cur, *orig;

- struct page *page;

- struct page **pages;

- struct btrfs_fs_info *fs_info;

- struct inode *inode;

- unsigned long size;

- int index;

- int num_pages;

- int entries;

- int bitmaps;

- unsigned check_crcs:1;

-};

-

/*

* Tree to record all locked full stripes of a RAID5/6 block group

*/

@@ -481,120 +438,6 @@ struct btrfs_full_stripe_locks_tree {

struct mutex lock;

};

-struct btrfs_block_group_cache {

- struct btrfs_key key;

- struct btrfs_block_group_item item;

- struct btrfs_fs_info *fs_info;

- struct inode *inode;

- spinlock_t lock;

- u64 pinned;

- u64 reserved;

- u64 delalloc_bytes;

- u64 bytes_super;

- u64 flags;

- u64 cache_generation;

-

- /*

- * If the free space extent count exceeds this number, convert the block

- * group to bitmaps.

- */

- u32 bitmap_high_thresh;

-

- /*

- * If the free space extent count drops below this number, convert the

- * block group back to extents.

- */

- u32 bitmap_low_thresh;

-

- /*

- * It is just used for the delayed data space allocation because

- * only the data space allocation and the relative metadata update

- * can be done cross the transaction.

- */

- struct rw_semaphore data_rwsem;

-

- /* for raid56, this is a full stripe, without parity */

- unsigned long full_stripe_len;

-

- unsigned int ro;

- unsigned int iref:1;

- unsigned int has_caching_ctl:1;

- unsigned int removed:1;

-

- int disk_cache_state;

-

- /* cache tracking stuff */

- int cached;

- struct btrfs_caching_control *caching_ctl;

- u64 last_byte_to_unpin;

-

- struct btrfs_space_info *space_info;

-

- /* free space cache stuff */

- struct btrfs_free_space_ctl *free_space_ctl;

-

- /* block group cache stuff */

- struct rb_node cache_node;

-

- /* for block groups in the same raid type */

- struct list_head list;

-

- /* usage count */

- atomic_t count;

-

- /* List of struct btrfs_free_clusters for this block group.

- * Today it will only have one thing on it, but that may change

- */

- struct list_head cluster_list;

-

- /* For delayed block group creation or deletion of empty block groups */

- struct list_head bg_list;

-

- /* For read-only block groups */

- struct list_head ro_list;

-

- atomic_t trimming;

-

- /* For dirty block groups */

- struct list_head dirty_list;

- struct list_head io_list;

-

- struct btrfs_io_ctl io_ctl;

-

- /*

- * Incremented when doing extent allocations and holding a read lock

- * on the space_info's groups_sem semaphore.

- * Decremented when an ordered extent that represents an IO against this

- * block group's range is created (after it's added to its inode's

- * root's list of ordered extents) or immediately after the allocation

- * if it's a metadata extent or fallocate extent (for these cases we

- * don't create ordered extents).

- */

- atomic_t reservations;

-

- /*

- * Incremented while holding the spinlock *lock* by a task checking if

- * it can perform a nocow write (incremented if the value for the *ro*

- * field is 0). Decremented by such tasks once they create an ordered

- * extent or before that if some error happens before reaching that step.

- * This is to prevent races between block group relocation and nocow

- * writes through direct IO.

- */

- atomic_t nocow_writers;

-

- /* Lock for free space tree operations. */

- struct mutex free_space_lock;

-

- /*

- * Does the block group need to be added to the free space tree?

- * Protected by free_space_lock.

- */

- int needs_free_space;

-

- /* Record locked full stripes for RAID5/6 block group */

- struct btrfs_full_stripe_locks_tree full_stripe_locks_root;

-};

-

/* delayed seq elem */

struct seq_list {

struct list_head list;

@@ -610,22 +453,6 @@ enum btrfs_orphan_cleanup_state {

ORPHAN_CLEANUP_DONE = 2,

};

-/* used by the raid56 code to lock stripes for read/modify/write */

-struct btrfs_stripe_hash {

- struct list_head hash_list;

- spinlock_t lock;

-};

-

-/* used by the raid56 code to lock stripes for read/modify/write */

-struct btrfs_stripe_hash_table {

- struct list_head stripe_cache;

- spinlock_t cache_lock;

- int cache_size;

- struct btrfs_stripe_hash table[];

-};

-

-#define BTRFS_STRIPE_HASH_TABLE_BITS 11

-

void btrfs_init_async_reclaim_work(struct work_struct *work);

/* fs_info */

@@ -1279,6 +1106,16 @@ struct btrfs_root {

#endif

};

+struct btrfs_clone_extent_info {

+ u64 disk_offset;

+ u64 disk_len;

+ u64 data_offset;

+ u64 data_len;

+ u64 file_offset;

+ char *extent_buf;

+ u32 item_size;

+};

+

struct btrfs_file_private {

void *filldir_buf;

};

@@ -1377,19 +1214,6 @@ static inline u32 BTRFS_MAX_XATTR_SIZE(const struct btrfs_fs_info *info)

btrfs_clear_opt(fs_info->mount_opt, opt); \

}

-#ifdef CONFIG_BTRFS_DEBUG

-static inline int

-btrfs_should_fragment_free_space(struct btrfs_block_group_cache *block_group)

-{

- struct btrfs_fs_info *fs_info = block_group->fs_info;

-

- return (btrfs_test_opt(fs_info, FRAGMENT_METADATA) &&

- block_group->flags & BTRFS_BLOCK_GROUP_METADATA) ||

- (btrfs_test_opt(fs_info, FRAGMENT_DATA) &&

- block_group->flags & BTRFS_BLOCK_GROUP_DATA);

-}

-#endif

-

/*

* Requests for changes that need to be done during transaction commit.

*

@@ -1475,8 +1299,10 @@ struct btrfs_map_token {

#define BTRFS_BYTES_TO_BLKS(fs_info, bytes) \

((bytes) >> (fs_info)->sb->s_blocksize_bits)

-static inline void btrfs_init_map_token (struct btrfs_map_token *token)

+static inline void btrfs_init_map_token(struct btrfs_map_token *token,

+ struct extent_buffer *eb)

{

+ token->eb = eb;

token->kaddr = NULL;

}

@@ -1507,17 +1333,10 @@ u##bits btrfs_get_token_##bits(const struct extent_buffer *eb, \

void btrfs_set_token_##bits(struct extent_buffer *eb, const void *ptr, \

unsigned long off, u##bits val, \

struct btrfs_map_token *token); \

-static inline u##bits btrfs_get_##bits(const struct extent_buffer *eb, \

- const void *ptr, \

- unsigned long off) \

-{ \

- return btrfs_get_token_##bits(eb, ptr, off, NULL); \

-} \

-static inline void btrfs_set_##bits(struct extent_buffer *eb, void *ptr,\

- unsigned long off, u##bits val) \

-{ \

- btrfs_set_token_##bits(eb, ptr, off, val, NULL); \

-}

+u##bits btrfs_get_##bits(const struct extent_buffer *eb, \

+ const void *ptr, unsigned long off); \

+void btrfs_set_##bits(struct extent_buffer *eb, void *ptr, \

+ unsigned long off, u##bits val);

DECLARE_BTRFS_SETGET_BITS(8)

DECLARE_BTRFS_SETGET_BITS(16)

@@ -2059,16 +1878,6 @@ static inline void btrfs_dir_item_key_to_cpu(const struct extent_buffer *eb,

btrfs_disk_key_to_cpu(key, &disk_key);

}

-static inline u8 btrfs_key_type(const struct btrfs_key *key)

-{

- return key->type;

-}

-

-static inline void btrfs_set_key_type(struct btrfs_key *key, u8 val)

-{

- key->type = val;

-}

-

/* struct btrfs_header */

BTRFS_SETGET_HEADER_FUNCS(header_bytenr, struct btrfs_header, bytenr, 64);

BTRFS_SETGET_HEADER_FUNCS(header_generation, struct btrfs_header,

@@ -2354,20 +2163,8 @@ BTRFS_SETGET_STACK_FUNCS(super_magic, struct btrfs_super_block, magic, 64);

BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,

uuid_tree_generation, 64);

-static inline int btrfs_super_csum_size(const struct btrfs_super_block *s)

-{

- u16 t = btrfs_super_csum_type(s);

- /*

- * csum type is validated at mount time

- */

- return btrfs_csum_sizes[t];

-}

-

-static inline const char *btrfs_super_csum_name(u16 csum_type)

-{

- /* csum type is validated at mount time */

- return btrfs_csum_names[csum_type];

-}

+int btrfs_super_csum_size(const struct btrfs_super_block *s);

+const char *btrfs_super_csum_name(u16 csum_type);

/*

* The leaf data grows from end-to-front in the node.

@@ -2440,30 +2237,6 @@ static inline u32 btrfs_file_extent_inline_item_len(

return btrfs_item_size(eb, e) - BTRFS_FILE_EXTENT_INLINE_DATA_START;

}

-/* btrfs_dev_stats_item */

-static inline u64 btrfs_dev_stats_value(const struct extent_buffer *eb,

- const struct btrfs_dev_stats_item *ptr,

- int index)

-{

- u64 val;

-

- read_extent_buffer(eb, &val,

- offsetof(struct btrfs_dev_stats_item, values) +

- ((unsigned long)ptr) + (index * sizeof(u64)),

- sizeof(val));

- return val;

-}

-

-static inline void btrfs_set_dev_stats_value(struct extent_buffer *eb,

- struct btrfs_dev_stats_item *ptr,

- int index, u64 val)

-{

- write_extent_buffer(eb, &val,

- offsetof(struct btrfs_dev_stats_item, values) +

- ((unsigned long)ptr) + (index * sizeof(u64)),

- sizeof(val));

-}

-

/* btrfs_qgroup_status_item */

BTRFS_SETGET_FUNCS(qgroup_status_generation, struct btrfs_qgroup_status_item,

generation, 64);

@@ -2600,32 +2373,33 @@ enum btrfs_inline_ref_type {

int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb,

struct btrfs_extent_inline_ref *iref,

enum btrfs_inline_ref_type is_data);

+u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset);

u64 btrfs_csum_bytes_to_leaves(struct btrfs_fs_info *fs_info, u64 csum_bytes);

-static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_fs_info *fs_info,

- unsigned num_items)

+/*

+ * Use this if we would be adding new items, as we could split nodes as we cow

+ * down the tree.

+ */

+static inline u64 btrfs_calc_insert_metadata_size(struct btrfs_fs_info *fs_info,

+ unsigned num_items)

{

return (u64)fs_info->nodesize * BTRFS_MAX_LEVEL * 2 * num_items;

}

/*

- * Doing a truncate won't result in new nodes or leaves, just what we need for

- * COW.

+ * Doing a truncate or a modification won't result in new nodes or leaves, just

+ * what we need for COW.

*/

-static inline u64 btrfs_calc_trunc_metadata_size(struct btrfs_fs_info *fs_info,

+static inline u64 btrfs_calc_metadata_size(struct btrfs_fs_info *fs_info,

unsigned num_items)

{

return (u64)fs_info->nodesize * BTRFS_MAX_LEVEL * num_items;

}

-void btrfs_dec_block_group_reservations(struct btrfs_fs_info *fs_info,

- const u64 start);

-void btrfs_wait_block_group_reservations(struct btrfs_block_group_cache *bg);

-bool btrfs_inc_nocow_writers(struct btrfs_fs_info *fs_info, u64 bytenr);

-void btrfs_dec_nocow_writers(struct btrfs_fs_info *fs_info, u64 bytenr);

-void btrfs_wait_nocow_writers(struct btrfs_block_group_cache *bg);

-void btrfs_put_block_group(struct btrfs_block_group_cache *cache);

+int btrfs_add_excluded_extent(struct btrfs_fs_info *fs_info,

+ u64 start, u64 num_bytes);

+void btrfs_free_excluded_extents(struct btrfs_block_group_cache *cache);

int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,

unsigned long count);

void btrfs_cleanup_ref_head_accounting(struct btrfs_fs_info *fs_info,

@@ -2642,11 +2416,6 @@ int btrfs_pin_extent_for_log_replay(struct btrfs_fs_info *fs_info,

int btrfs_exclude_logged_extents(struct extent_buffer *eb);

int btrfs_cross_ref_exist(struct btrfs_root *root,

u64 objectid, u64 offset, u64 bytenr);

-struct btrfs_block_group_cache *btrfs_lookup_block_group(

- struct btrfs_fs_info *info,

- u64 bytenr);

-void btrfs_get_block_group(struct btrfs_block_group_cache *cache);

-void btrfs_put_block_group(struct btrfs_block_group_cache *cache);

struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,

struct btrfs_root *root,

u64 parent, u64 root_objectid,

@@ -2685,28 +2454,9 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans);

int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,

struct btrfs_ref *generic_ref);

-int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans);

-int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans);

-int btrfs_setup_space_cache(struct btrfs_trans_handle *trans);

int btrfs_extent_readonly(struct btrfs_fs_info *fs_info, u64 bytenr);

-int btrfs_free_block_groups(struct btrfs_fs_info *info);

-int btrfs_read_block_groups(struct btrfs_fs_info *info);

-int btrfs_can_relocate(struct btrfs_fs_info *fs_info, u64 bytenr);

-int btrfs_make_block_group(struct btrfs_trans_handle *trans,

- u64 bytes_used, u64 type, u64 chunk_offset,

- u64 size);

-struct btrfs_trans_handle *btrfs_start_trans_remove_block_group(

- struct btrfs_fs_info *fs_info,

- const u64 chunk_offset);

-int btrfs_remove_block_group(struct btrfs_trans_handle *trans,

- u64 group_start, struct extent_map *em);

-void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info);

void btrfs_get_block_group_trimming(struct btrfs_block_group_cache *cache);

void btrfs_put_block_group_trimming(struct btrfs_block_group_cache *cache);

-void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans);

-u64 btrfs_data_alloc_profile(struct btrfs_fs_info *fs_info);

-u64 btrfs_metadata_alloc_profile(struct btrfs_fs_info *fs_info);

-u64 btrfs_system_alloc_profile(struct btrfs_fs_info *fs_info);

void btrfs_clear_space_info_full(struct btrfs_fs_info *info);

enum btrfs_reserve_flush_enum {

@@ -2717,6 +2467,7 @@ enum btrfs_reserve_flush_enum {

* case, use FLUSH LIMIT

*/

BTRFS_RESERVE_FLUSH_LIMIT,

+ BTRFS_RESERVE_FLUSH_EVICT,

BTRFS_RESERVE_FLUSH_ALL,

};

@@ -2729,31 +2480,10 @@ enum btrfs_flush_state {

FLUSH_DELALLOC_WAIT = 6,

ALLOC_CHUNK = 7,

ALLOC_CHUNK_FORCE = 8,

- COMMIT_TRANS = 9,

-};

-

-/*

- * control flags for do_chunk_alloc's force field

- * CHUNK_ALLOC_NO_FORCE means to only allocate a chunk

- * if we really need one.

- *

- * CHUNK_ALLOC_LIMITED means to only try and allocate one

- * if we have very few chunks already allocated. This is

- * used as part of the clustering code to help make sure

- * we have a good pool of storage to cluster in, without

- * filling the FS with empty chunks

- *

- * CHUNK_ALLOC_FORCE means it must try to allocate one

- *

- */

-enum btrfs_chunk_alloc_enum {

- CHUNK_ALLOC_NO_FORCE,

- CHUNK_ALLOC_LIMITED,

- CHUNK_ALLOC_FORCE,

+ RUN_DELAYED_IPUTS = 9,

+ COMMIT_TRANS = 10,

};

-int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags,

- enum btrfs_chunk_alloc_enum force);

int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,

struct btrfs_block_rsv *rsv,

int nitems, bool use_global_rsv);

@@ -2763,15 +2493,11 @@ void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes,

bool qgroup_free);

int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes);

-int btrfs_inc_block_group_ro(struct btrfs_block_group_cache *cache);

-void btrfs_dec_block_group_ro(struct btrfs_block_group_cache *cache);

-void btrfs_put_block_group_cache(struct btrfs_fs_info *info);

u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo);

int btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info,

u64 start, u64 end);

int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr,

u64 num_bytes, u64 *actual_bytes);

-int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, u64 type);

int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range);

int btrfs_init_space_info(struct btrfs_fs_info *fs_info);

@@ -2780,10 +2506,6 @@ int btrfs_delayed_refs_qgroup_accounting(struct btrfs_trans_handle *trans,

int btrfs_start_write_no_snapshotting(struct btrfs_root *root);

void btrfs_end_write_no_snapshotting(struct btrfs_root *root);

void btrfs_wait_for_snapshot_creation(struct btrfs_root *root);

-void check_system_chunk(struct btrfs_trans_handle *trans, const u64 type);

-u64 add_new_free_space(struct btrfs_block_group_cache *block_group,

- u64 start, u64 end);

-void btrfs_mark_bg_unused(struct btrfs_block_group_cache *bg);

/* ctree.c */

int btrfs_bin_search(struct extent_buffer *eb, const struct btrfs_key *key,

@@ -2806,20 +2528,9 @@ int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,

int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,

struct btrfs_path *path,

u64 min_trans);

-enum btrfs_compare_tree_result {

- BTRFS_COMPARE_TREE_NEW,

- BTRFS_COMPARE_TREE_DELETED,

- BTRFS_COMPARE_TREE_CHANGED,

- BTRFS_COMPARE_TREE_SAME,

-};

-typedef int (*btrfs_changed_cb_t)(struct btrfs_path *left_path,

- struct btrfs_path *right_path,

- struct btrfs_key *key,

- enum btrfs_compare_tree_result result,

- void *ctx);

-int btrfs_compare_trees(struct btrfs_root *left_root,

- struct btrfs_root *right_root,

- btrfs_changed_cb_t cb, void *ctx);

+struct extent_buffer *btrfs_read_node_slot(struct extent_buffer *parent,

+ int slot);

+

int btrfs_cow_block(struct btrfs_trans_handle *trans,

struct btrfs_root *root, struct extent_buffer *buf,

struct extent_buffer *parent, int parent_slot,

@@ -3068,14 +2779,12 @@ btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans,

u64 inode_objectid, u64 ref_objectid, int ins_len,

int cow);

-int btrfs_find_name_in_backref(struct extent_buffer *leaf, int slot,

- const char *name,

- int name_len, struct btrfs_inode_ref **ref_ret);

-int btrfs_find_name_in_ext_backref(struct extent_buffer *leaf, int slot,

- u64 ref_objectid, const char *name,

- int name_len,

- struct btrfs_inode_extref **extref_ret);

-

+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 */

struct btrfs_dio_private;

int btrfs_del_csums(struct btrfs_trans_handle *trans,

@@ -3137,7 +2846,7 @@ int btrfs_start_delalloc_snapshot(struct btrfs_root *root);

int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int nr);

int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end,

unsigned int extra_bits,

- struct extent_state **cached_state, int dedupe);

+ struct extent_state **cached_state);

int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,

struct btrfs_root *new_root,

struct btrfs_root *parent_root,

@@ -3233,6 +2942,10 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans,

int btrfs_drop_extents(struct btrfs_trans_handle *trans,

struct btrfs_root *root, struct inode *inode, u64 start,

u64 end, int drop_cache);

+int btrfs_punch_hole_range(struct inode *inode, struct btrfs_path *path,

+ const u64 start, const u64 end,

+ struct btrfs_clone_extent_info *clone_info,

+ struct btrfs_trans_handle **trans_out);

int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,

struct btrfs_inode *inode, u64 start, u64 end);

int btrfs_release_file(struct inode *inode, struct file *file);

@@ -3248,12 +2961,6 @@ loff_t btrfs_remap_file_range(struct file *file_in, loff_t pos_in,

int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,

struct btrfs_root *root);

-/* sysfs.c */

-int __init btrfs_init_sysfs(void);

-void __cold btrfs_exit_sysfs(void);

-int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info);

-void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info);

-

/* super.c */

int btrfs_parse_options(struct btrfs_fs_info *info, char *options,

unsigned long new_flags);

@@ -3722,26 +3429,4 @@ static inline int btrfs_is_testing(struct btrfs_fs_info *fs_info)

}

#endif

-static inline void cond_wake_up(struct wait_queue_head *wq)

-{

- /*

- * This implies a full smp_mb barrier, see comments for

- * waitqueue_active why.

- */

- if (wq_has_sleeper(wq))

- wake_up(wq);

-}

-

-static inline void cond_wake_up_nomb(struct wait_queue_head *wq)

-{

- /*

- * Special case for conditional wakeup where the barrier required for

- * waitqueue_active is implied by some of the preceding code. Eg. one

- * of such atomic operations (atomic_dec_and_return, ...), or a

- * unlock/lock sequence, etc.

- */

- if (waitqueue_active(wq))

- wake_up(wq);

-}

-

#endif

diff --git a/fs/btrfs/dedupe.h b/fs/btrfs/dedupe.h
deleted file mode 100644
index 90281a7a35a81..0000000000000
--- a/fs/btrfs/dedupe.h
+++ /dev/null

@@ -1,12 +0,0 @@

-/* SPDX-License-Identifier: GPL-2.0 */

-/*

- * Copyright (C) 2016 Fujitsu. All rights reserved.

- */

-

-#ifndef BTRFS_DEDUPE_H

-#define BTRFS_DEDUPE_H

-

-/* later in-band dedupe will expand this struct */

-struct btrfs_dedupe_hash;

-

-#endif

@@ -7,6 +7,7 @@

#include "space-info.h"

#include "transaction.h"

#include "qgroup.h"

+#include "block-group.h"

int btrfs_alloc_data_chunk_ondemand(struct btrfs_inode *inode, u64 bytes)

{

@@ -129,8 +130,6 @@ commit_trans:

return -ENOSPC;

}

btrfs_space_info_update_bytes_may_use(fs_info, data_sinfo, bytes);

- trace_btrfs_space_reservation(fs_info, "space_info",

- data_sinfo->flags, bytes, 1);

spin_unlock(&data_sinfo->lock);

return 0;

@@ -182,8 +181,6 @@ void btrfs_free_reserved_data_space_noquota(struct inode *inode, u64 start,

data_sinfo = fs_info->data_sinfo;

spin_lock(&data_sinfo->lock);

btrfs_space_info_update_bytes_may_use(fs_info, data_sinfo, -len);

- trace_btrfs_space_reservation(fs_info, "space_info",

- data_sinfo->flags, len, 0);

spin_unlock(&data_sinfo->lock);

}

@@ -254,13 +251,20 @@ static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info,

lockdep_assert_held(&inode->lock);

outstanding_extents = inode->outstanding_extents;

- if (outstanding_extents)

- reserve_size = btrfs_calc_trans_metadata_size(fs_info,

- outstanding_extents + 1);

+

+ /*

+ * Insert size for the number of outstanding extents, 1 normal size for

+ * updating the inode.

+ */

+ if (outstanding_extents) {

+ reserve_size = btrfs_calc_insert_metadata_size(fs_info,

+ outstanding_extents);

+ reserve_size += btrfs_calc_metadata_size(fs_info, 1);

+ }

csum_leaves = btrfs_csum_bytes_to_leaves(fs_info,

inode->csum_bytes);

- reserve_size += btrfs_calc_trans_metadata_size(fs_info,

- csum_leaves);

+ reserve_size += btrfs_calc_insert_metadata_size(fs_info,

+ csum_leaves);

/*

* For qgroup rsv, the calculation is very simple:

* account one nodesize for each outstanding extent

@@ -281,10 +285,16 @@ static void calc_inode_reservations(struct btrfs_fs_info *fs_info,

{

u64 nr_extents = count_max_extents(num_bytes);

u64 csum_leaves = btrfs_csum_bytes_to_leaves(fs_info, num_bytes);

+ u64 inode_update = btrfs_calc_metadata_size(fs_info, 1);

- /* We add one for the inode update at finish ordered time */

- *meta_reserve = btrfs_calc_trans_metadata_size(fs_info,

- nr_extents + csum_leaves + 1);

+ *meta_reserve = btrfs_calc_insert_metadata_size(fs_info,

+ nr_extents + csum_leaves);

+

+ /*

+ * finish_ordered_io has to update the inode, so add the space required

+ * for an inode update.

+ */

+ *meta_reserve += inode_update;

*qgroup_reserve = nr_extents * fs_info->nodesize;

}

@@ -6,6 +6,7 @@

#include <linux/slab.h>

#include <linux/iversion.h>

+#include "misc.h"

#include "delayed-inode.h"

#include "disk-io.h"

#include "transaction.h"

@@ -474,6 +475,9 @@ static void __btrfs_remove_delayed_item(struct btrfs_delayed_item *delayed_item)

struct rb_root_cached *root;

struct btrfs_delayed_root *delayed_root;

+ /* Not associated with any delayed_node */

+ if (!delayed_item->delayed_node)

+ return;

delayed_root = delayed_item->delayed_node->root->fs_info->delayed_root;

BUG_ON(!delayed_root);

@@ -555,7 +559,7 @@ static int btrfs_delayed_item_reserve_metadata(struct btrfs_trans_handle *trans,

src_rsv = trans->block_rsv;

dst_rsv = &fs_info->delayed_block_rsv;

- num_bytes = btrfs_calc_trans_metadata_size(fs_info, 1);

+ num_bytes = btrfs_calc_insert_metadata_size(fs_info, 1);

/*

* Here we migrate space rsv from transaction rsv, since have already

@@ -609,7 +613,7 @@ static int btrfs_delayed_inode_reserve_metadata(

src_rsv = trans->block_rsv;

dst_rsv = &fs_info->delayed_block_rsv;

- num_bytes = btrfs_calc_trans_metadata_size(fs_info, 1);

+ num_bytes = btrfs_calc_metadata_size(fs_info, 1);

/*

* btrfs_dirty_inode will update the inode under btrfs_join_transaction

@@ -1525,7 +1529,12 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans,

* we have reserved enough space when we start a new transaction,

* so reserving metadata failure is impossible.

*/

- BUG_ON(ret);

+ if (ret < 0) {

+ btrfs_err(trans->fs_info,

+"metadata reservation failed for delayed dir item deltiona, should have been reserved");

+ btrfs_release_delayed_item(item);

+ goto end;

+ }

mutex_lock(&node->mutex);

ret = __btrfs_add_delayed_deletion_item(node, item);

@@ -1534,7 +1543,8 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans,

"err add delayed dir index item(index: %llu) into the deletion tree of the delayed node(root id: %llu, inode id: %llu, errno: %d)",

index, node->root->root_key.objectid,

node->inode_id, ret);

- BUG();

+ btrfs_delayed_item_release_metadata(dir->root, item);

+ btrfs_release_delayed_item(item);

}

mutex_unlock(&node->mutex);

end:

@@ -79,7 +79,7 @@ int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans)

void btrfs_delayed_refs_rsv_release(struct btrfs_fs_info *fs_info, int nr)

{

struct btrfs_block_rsv *block_rsv = &fs_info->delayed_refs_rsv;

- u64 num_bytes = btrfs_calc_trans_metadata_size(fs_info, nr);

+ u64 num_bytes = btrfs_calc_insert_metadata_size(fs_info, nr);

u64 released = 0;

released = __btrfs_block_rsv_release(fs_info, block_rsv, num_bytes,

@@ -105,8 +105,8 @@ void btrfs_update_delayed_refs_rsv(struct btrfs_trans_handle *trans)

if (!trans->delayed_ref_updates)

return;

- num_bytes = btrfs_calc_trans_metadata_size(fs_info,

- trans->delayed_ref_updates);

+ num_bytes = btrfs_calc_insert_metadata_size(fs_info,

+ trans->delayed_ref_updates);

spin_lock(&delayed_rsv->lock);

delayed_rsv->size += num_bytes;

delayed_rsv->full = 0;

@@ -158,7 +158,7 @@ void btrfs_migrate_to_delayed_refs_rsv(struct btrfs_fs_info *fs_info,

trace_btrfs_space_reservation(fs_info, "delayed_refs_rsv",

0, num_bytes, 1);

if (to_free)

- btrfs_space_info_add_old_bytes(fs_info,

+ btrfs_space_info_free_bytes_may_use(fs_info,

delayed_refs_rsv->space_info, to_free);

}

@@ -174,7 +174,7 @@ int btrfs_delayed_refs_rsv_refill(struct btrfs_fs_info *fs_info,

enum btrfs_reserve_flush_enum flush)

{

struct btrfs_block_rsv *block_rsv = &fs_info->delayed_refs_rsv;

- u64 limit = btrfs_calc_trans_metadata_size(fs_info, 1);

+ u64 limit = btrfs_calc_insert_metadata_size(fs_info, 1);

u64 num_bytes = 0;

int ret = -ENOSPC;

@@ -9,6 +9,7 @@

#include <linux/blkdev.h>

#include <linux/kthread.h>

#include <linux/math64.h>

+#include "misc.h"

#include "ctree.h"

#include "extent_map.h"

#include "disk-io.h"

@@ -56,7 +57,7 @@ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info)

no_valid_dev_replace_entry_found:

ret = 0;

dev_replace->replace_state =

- BTRFS_DEV_REPLACE_ITEM_STATE_NEVER_STARTED;

+ BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED;

dev_replace->cont_reading_from_srcdev_mode =

BTRFS_DEV_REPLACE_ITEM_CONT_READING_FROM_SRCDEV_MODE_ALWAYS;

dev_replace->time_started = 0;

@@ -40,6 +40,7 @@

#include "compression.h"

#include "tree-checker.h"

#include "ref-verify.h"

+#include "block-group.h"

#define BTRFS_SUPER_FLAG_SUPP (BTRFS_HEADER_FLAG_WRITTEN |\

BTRFS_HEADER_FLAG_RELOC |\

@@ -416,6 +417,16 @@ int btrfs_verify_level_key(struct extent_buffer *eb, int level,

*/

if (btrfs_header_generation(eb) > fs_info->last_trans_committed)

return 0;

+

+ /* We have @first_key, so this @eb must have at least one item */

+ if (btrfs_header_nritems(eb) == 0) {

+ btrfs_err(fs_info,

+ "invalid tree nritems, bytenr=%llu nritems=0 expect >0",

+ eb->start);

+ WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG));

+ return -EUCLEAN;

+ }

+

if (found_level)

btrfs_node_key_to_cpu(eb, &found_key, 0);

else

@@ -1037,35 +1048,6 @@ void readahead_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr)

free_extent_buffer(buf);

}

-int reada_tree_block_flagged(struct btrfs_fs_info *fs_info, u64 bytenr,

- int mirror_num, struct extent_buffer **eb)

-{

- struct extent_buffer *buf = NULL;

- int ret;

-

- buf = btrfs_find_create_tree_block(fs_info, bytenr);

- if (IS_ERR(buf))

- return 0;

-

- set_bit(EXTENT_BUFFER_READAHEAD, &buf->bflags);

-

- ret = read_extent_buffer_pages(buf, WAIT_PAGE_LOCK, mirror_num);

- if (ret) {

- free_extent_buffer_stale(buf);

- return ret;

- }

-

- if (test_bit(EXTENT_BUFFER_CORRUPT, &buf->bflags)) {

- free_extent_buffer_stale(buf);

- return -EIO;

- } else if (extent_buffer_uptodate(buf)) {

- *eb = buf;

- } else {

- free_extent_buffer(buf);

- }

- return 0;

-}

-

struct extent_buffer *btrfs_find_create_tree_block(

struct btrfs_fs_info *fs_info,

u64 bytenr)

@@ -45,8 +45,6 @@ struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,

u64 parent_transid, int level,

struct btrfs_key *first_key);

void readahead_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr);

-int reada_tree_block_flagged(struct btrfs_fs_info *fs_info, u64 bytenr,

- int mirror_num, struct extent_buffer **eb);

struct extent_buffer *btrfs_find_create_tree_block(

struct btrfs_fs_info *fs_info,

u64 bytenr);

@@ -4,7 +4,6 @@

*/

#include <linux/sched.h>

-#include <linux/sched/mm.h>

#include <linux/sched/signal.h>

#include <linux/pagemap.h>

#include <linux/writeback.h>

@@ -17,6 +16,7 @@

#include <linux/percpu_counter.h>

#include <linux/lockdep.h>

#include <linux/crc32c.h>

+#include "misc.h"

#include "tree-log.h"

#include "disk-io.h"

#include "print-tree.h"

@@ -25,13 +25,13 @@

#include "locking.h"

#include "free-space-cache.h"

#include "free-space-tree.h"

-#include "math.h"

#include "sysfs.h"

#include "qgroup.h"

#include "ref-verify.h"

#include "space-info.h"

#include "block-rsv.h"

#include "delalloc-space.h"

+#include "block-group.h"

#undef SCRAMBLE_DELAYED_REFS

@@ -54,132 +54,13 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,

static int find_next_key(struct btrfs_path *path, int level,

struct btrfs_key *key);

-static noinline int

-block_group_cache_done(struct btrfs_block_group_cache *cache)

-{

- smp_mb();

- return cache->cached == BTRFS_CACHE_FINISHED ||

- cache->cached == BTRFS_CACHE_ERROR;

-}

-

static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits)

{

return (cache->flags & bits) == bits;

}

-void btrfs_get_block_group(struct btrfs_block_group_cache *cache)

-{

- atomic_inc(&cache->count);

-}

-

-void btrfs_put_block_group(struct btrfs_block_group_cache *cache)

-{

- if (atomic_dec_and_test(&cache->count)) {

- WARN_ON(cache->pinned > 0);

- WARN_ON(cache->reserved > 0);

-

- /*

- * If not empty, someone is still holding mutex of

- * full_stripe_lock, which can only be released by caller.

- * And it will definitely cause use-after-free when caller

- * tries to release full stripe lock.

- *

- * No better way to resolve, but only to warn.

- */

- WARN_ON(!RB_EMPTY_ROOT(&cache->full_stripe_locks_root.root));

- kfree(cache->free_space_ctl);

- kfree(cache);

- }

-}

-

-/*

- * this adds the block group to the fs_info rb tree for the block group

- * cache

- */

-static int btrfs_add_block_group_cache(struct btrfs_fs_info *info,

- struct btrfs_block_group_cache *block_group)

-{

- struct rb_node **p;

- struct rb_node *parent = NULL;

- struct btrfs_block_group_cache *cache;

-

- spin_lock(&info->block_group_cache_lock);

- p = &info->block_group_cache_tree.rb_node;

-

- while (*p) {

- parent = *p;

- cache = rb_entry(parent, struct btrfs_block_group_cache,

- cache_node);

- if (block_group->key.objectid < cache->key.objectid) {

- p = &(*p)->rb_left;

- } else if (block_group->key.objectid > cache->key.objectid) {

- p = &(*p)->rb_right;

- } else {

- spin_unlock(&info->block_group_cache_lock);

- return -EEXIST;

- }

- }

-

- rb_link_node(&block_group->cache_node, parent, p);

- rb_insert_color(&block_group->cache_node,

- &info->block_group_cache_tree);

-

- if (info->first_logical_byte > block_group->key.objectid)

- info->first_logical_byte = block_group->key.objectid;

-

- spin_unlock(&info->block_group_cache_lock);

-

- return 0;

-}

-

-/*

- * This will return the block group at or after bytenr if contains is 0, else

- * it will return the block group that contains the bytenr

- */

-static struct btrfs_block_group_cache *

-block_group_cache_tree_search(struct btrfs_fs_info *info, u64 bytenr,

- int contains)

-{

- struct btrfs_block_group_cache *cache, *ret = NULL;

- struct rb_node *n;

- u64 end, start;

-

- spin_lock(&info->block_group_cache_lock);

- n = info->block_group_cache_tree.rb_node;

-

- while (n) {

- cache = rb_entry(n, struct btrfs_block_group_cache,

- cache_node);

- end = cache->key.objectid + cache->key.offset - 1;

- start = cache->key.objectid;

-

- if (bytenr < start) {

- if (!contains && (!ret || start < ret->key.objectid))

- ret = cache;

- n = n->rb_left;

- } else if (bytenr > start) {

- if (contains && bytenr <= end) {

- ret = cache;

- break;

- }

- n = n->rb_right;

- } else {

- ret = cache;

- break;

- }

- }

- if (ret) {

- btrfs_get_block_group(ret);

- if (bytenr == 0 && info->first_logical_byte > ret->key.objectid)

- info->first_logical_byte = ret->key.objectid;

- }

- spin_unlock(&info->block_group_cache_lock);

-

- return ret;

-}

-

-static int add_excluded_extent(struct btrfs_fs_info *fs_info,

- u64 start, u64 num_bytes)

+int btrfs_add_excluded_extent(struct btrfs_fs_info *fs_info,

+ u64 start, u64 num_bytes)

{

u64 end = start + num_bytes - 1;

set_extent_bits(&fs_info->freed_extents[0],

@@ -189,7 +70,7 @@ static int add_excluded_extent(struct btrfs_fs_info *fs_info,

return 0;

}

-static void free_excluded_extents(struct btrfs_block_group_cache *cache)

+void btrfs_free_excluded_extents(struct btrfs_block_group_cache *cache)

{

struct btrfs_fs_info *fs_info = cache->fs_info;

u64 start, end;

@@ -203,494 +84,6 @@ static void free_excluded_extents(struct btrfs_block_group_cache *cache)

start, end, EXTENT_UPTODATE);

}

-static int exclude_super_stripes(struct btrfs_block_group_cache *cache)

-{

- struct btrfs_fs_info *fs_info = cache->fs_info;

- u64 bytenr;

- u64 *logical;

- int stripe_len;

- int i, nr, ret;

-

- if (cache->key.objectid < BTRFS_SUPER_INFO_OFFSET) {

- stripe_len = BTRFS_SUPER_INFO_OFFSET - cache->key.objectid;

- cache->bytes_super += stripe_len;

- ret = add_excluded_extent(fs_info, cache->key.objectid,

- stripe_len);

- if (ret)

- return ret;

- }

-

- for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {

- bytenr = btrfs_sb_offset(i);

- ret = btrfs_rmap_block(fs_info, cache->key.objectid,

- bytenr, &logical, &nr, &stripe_len);

- if (ret)

- return ret;

-

- while (nr--) {

- u64 start, len;

-

- if (logical[nr] > cache->key.objectid +

- cache->key.offset)

- continue;

-

- if (logical[nr] + stripe_len <= cache->key.objectid)

- continue;

-

- start = logical[nr];

- if (start < cache->key.objectid) {

- start = cache->key.objectid;

- len = (logical[nr] + stripe_len) - start;

- } else {

- len = min_t(u64, stripe_len,

- cache->key.objectid +

- cache->key.offset - start);

- }

-

- cache->bytes_super += len;

- ret = add_excluded_extent(fs_info, start, len);

- if (ret) {

- kfree(logical);

- return ret;

- }

- }

-

- kfree(logical);

- }

- return 0;

-}

-

-static struct btrfs_caching_control *

-get_caching_control(struct btrfs_block_group_cache *cache)

-{

- struct btrfs_caching_control *ctl;

-

- spin_lock(&cache->lock);

- if (!cache->caching_ctl) {

- spin_unlock(&cache->lock);

- return NULL;

- }

-

- ctl = cache->caching_ctl;

- refcount_inc(&ctl->count);

- spin_unlock(&cache->lock);

- return ctl;

-}

-

-static void put_caching_control(struct btrfs_caching_control *ctl)

-{

- if (refcount_dec_and_test(&ctl->count))

- kfree(ctl);

-}

-

-#ifdef CONFIG_BTRFS_DEBUG

-static void fragment_free_space(struct btrfs_block_group_cache *block_group)

-{

- struct btrfs_fs_info *fs_info = block_group->fs_info;

- u64 start = block_group->key.objectid;

- u64 len = block_group->key.offset;

- u64 chunk = block_group->flags & BTRFS_BLOCK_GROUP_METADATA ?

- fs_info->nodesize : fs_info->sectorsize;

- u64 step = chunk << 1;

-

- while (len > chunk) {

- btrfs_remove_free_space(block_group, start, chunk);

- start += step;

- if (len < step)

- len = 0;

- else

- len -= step;

- }

-}

-#endif

-

-/*

- * this is only called by cache_block_group, since we could have freed extents

- * we need to check the pinned_extents for any extents that can't be used yet

- * since their free space will be released as soon as the transaction commits.

- */

-u64 add_new_free_space(struct btrfs_block_group_cache *block_group,

- u64 start, u64 end)

-{

- struct btrfs_fs_info *info = block_group->fs_info;

- u64 extent_start, extent_end, size, total_added = 0;

- int ret;

-

- while (start < end) {

- ret = find_first_extent_bit(info->pinned_extents, start,

- &extent_start, &extent_end,

- EXTENT_DIRTY | EXTENT_UPTODATE,

- NULL);

- if (ret)

- break;

-

- if (extent_start <= start) {

- start = extent_end + 1;

- } else if (extent_start > start && extent_start < end) {

- size = extent_start - start;

- total_added += size;

- ret = btrfs_add_free_space(block_group, start,

- size);

- BUG_ON(ret); /* -ENOMEM or logic error */

- start = extent_end + 1;

- } else {

- break;

- }

- }

-

- if (start < end) {

- size = end - start;

- total_added += size;

- ret = btrfs_add_free_space(block_group, start, size);

- BUG_ON(ret); /* -ENOMEM or logic error */

- }

-

- return total_added;

-}

-

-static int load_extent_tree_free(struct btrfs_caching_control *caching_ctl)

-{

- struct btrfs_block_group_cache *block_group = caching_ctl->block_group;

- struct btrfs_fs_info *fs_info = block_group->fs_info;

- struct btrfs_root *extent_root = fs_info->extent_root;

- struct btrfs_path *path;

- struct extent_buffer *leaf;

- struct btrfs_key key;

- u64 total_found = 0;

- u64 last = 0;

- u32 nritems;

- int ret;

- bool wakeup = true;

-

- path = btrfs_alloc_path();

- if (!path)

- return -ENOMEM;

-

- last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET);

-

-#ifdef CONFIG_BTRFS_DEBUG

- /*

- * If we're fragmenting we don't want to make anybody think we can

- * allocate from this block group until we've had a chance to fragment

- * the free space.

- */

- if (btrfs_should_fragment_free_space(block_group))

- wakeup = false;

-#endif

- /*

- * We don't want to deadlock with somebody trying to allocate a new

- * extent for the extent root while also trying to search the extent

- * root to add free space. So we skip locking and search the commit

- * root, since its read-only

- */

- path->skip_locking = 1;

- path->search_commit_root = 1;

- path->reada = READA_FORWARD;

-

- key.objectid = last;

- key.offset = 0;

- key.type = BTRFS_EXTENT_ITEM_KEY;

-

-next:

- ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);

- if (ret < 0)

- goto out;

-

- leaf = path->nodes[0];

- nritems = btrfs_header_nritems(leaf);

-

- while (1) {

- if (btrfs_fs_closing(fs_info) > 1) {

- last = (u64)-1;

- break;

- }

-

- if (path->slots[0] < nritems) {

- btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);

- } else {

- ret = find_next_key(path, 0, &key);

- if (ret)

- break;

-

- if (need_resched() ||

- rwsem_is_contended(&fs_info->commit_root_sem)) {

- if (wakeup)

- caching_ctl->progress = last;

- btrfs_release_path(path);

- up_read(&fs_info->commit_root_sem);

- mutex_unlock(&caching_ctl->mutex);

- cond_resched();

- mutex_lock(&caching_ctl->mutex);

- down_read(&fs_info->commit_root_sem);

- goto next;

- }

-

- ret = btrfs_next_leaf(extent_root, path);

- if (ret < 0)

- goto out;

- if (ret)

- break;

- leaf = path->nodes[0];

- nritems = btrfs_header_nritems(leaf);

- continue;

- }

-

- if (key.objectid < last) {

- key.objectid = last;

- key.offset = 0;

- key.type = BTRFS_EXTENT_ITEM_KEY;

-

- if (wakeup)

- caching_ctl->progress = last;

- btrfs_release_path(path);

- goto next;

- }

-

- if (key.objectid < block_group->key.objectid) {

- path->slots[0]++;

- continue;

- }

-

- if (key.objectid >= block_group->key.objectid +

- block_group->key.offset)

- break;

-

- if (key.type == BTRFS_EXTENT_ITEM_KEY ||

- key.type == BTRFS_METADATA_ITEM_KEY) {

- total_found += add_new_free_space(block_group, last,

- key.objectid);

- if (key.type == BTRFS_METADATA_ITEM_KEY)

- last = key.objectid +

- fs_info->nodesize;

- else

- last = key.objectid + key.offset;

-

- if (total_found > CACHING_CTL_WAKE_UP) {

- total_found = 0;

- if (wakeup)

- wake_up(&caching_ctl->wait);

- }

- }

- path->slots[0]++;

- }

- ret = 0;

-

- total_found += add_new_free_space(block_group, last,

- block_group->key.objectid +

- block_group->key.offset);

- caching_ctl->progress = (u64)-1;

-

-out:

- btrfs_free_path(path);

- return ret;

-}

-

-static noinline void caching_thread(struct btrfs_work *work)

-{

- struct btrfs_block_group_cache *block_group;

- struct btrfs_fs_info *fs_info;

- struct btrfs_caching_control *caching_ctl;

- int ret;

-

- caching_ctl = container_of(work, struct btrfs_caching_control, work);

- block_group = caching_ctl->block_group;

- fs_info = block_group->fs_info;

-

- mutex_lock(&caching_ctl->mutex);

- down_read(&fs_info->commit_root_sem);

-

- if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE))

- ret = load_free_space_tree(caching_ctl);

- else

- ret = load_extent_tree_free(caching_ctl);

-

- spin_lock(&block_group->lock);

- block_group->caching_ctl = NULL;

- block_group->cached = ret ? BTRFS_CACHE_ERROR : BTRFS_CACHE_FINISHED;

- spin_unlock(&block_group->lock);

-

-#ifdef CONFIG_BTRFS_DEBUG

- if (btrfs_should_fragment_free_space(block_group)) {

- u64 bytes_used;

-

- spin_lock(&block_group->space_info->lock);

- spin_lock(&block_group->lock);

- bytes_used = block_group->key.offset -

- btrfs_block_group_used(&block_group->item);

- block_group->space_info->bytes_used += bytes_used >> 1;

- spin_unlock(&block_group->lock);

- spin_unlock(&block_group->space_info->lock);

- fragment_free_space(block_group);

- }

-#endif

-

- caching_ctl->progress = (u64)-1;

-

- up_read(&fs_info->commit_root_sem);

- free_excluded_extents(block_group);

- mutex_unlock(&caching_ctl->mutex);

-

- wake_up(&caching_ctl->wait);

-

- put_caching_control(caching_ctl);

- btrfs_put_block_group(block_group);

-}

-

-static int cache_block_group(struct btrfs_block_group_cache *cache,

- int load_cache_only)

-{

- DEFINE_WAIT(wait);

- struct btrfs_fs_info *fs_info = cache->fs_info;

- struct btrfs_caching_control *caching_ctl;

- int ret = 0;

-

- caching_ctl = kzalloc(sizeof(*caching_ctl), GFP_NOFS);

- if (!caching_ctl)

- return -ENOMEM;

-

- INIT_LIST_HEAD(&caching_ctl->list);

- mutex_init(&caching_ctl->mutex);

- init_waitqueue_head(&caching_ctl->wait);

- caching_ctl->block_group = cache;

- caching_ctl->progress = cache->key.objectid;

- refcount_set(&caching_ctl->count, 1);

- btrfs_init_work(&caching_ctl->work, btrfs_cache_helper,

- caching_thread, NULL, NULL);

-

- spin_lock(&cache->lock);

- /*

- * This should be a rare occasion, but this could happen I think in the

- * case where one thread starts to load the space cache info, and then

- * some other thread starts a transaction commit which tries to do an

- * allocation while the other thread is still loading the space cache

- * info. The previous loop should have kept us from choosing this block

- * group, but if we've moved to the state where we will wait on caching

- * block groups we need to first check if we're doing a fast load here,

- * so we can wait for it to finish, otherwise we could end up allocating

- * from a block group who's cache gets evicted for one reason or

- * another.

- */

- while (cache->cached == BTRFS_CACHE_FAST) {

- struct btrfs_caching_control *ctl;

-

- ctl = cache->caching_ctl;

- refcount_inc(&ctl->count);

- prepare_to_wait(&ctl->wait, &wait, TASK_UNINTERRUPTIBLE);

- spin_unlock(&cache->lock);

-

- schedule();

-

- finish_wait(&ctl->wait, &wait);

- put_caching_control(ctl);

- spin_lock(&cache->lock);

- }

-

- if (cache->cached != BTRFS_CACHE_NO) {

- spin_unlock(&cache->lock);

- kfree(caching_ctl);

- return 0;

- }

- WARN_ON(cache->caching_ctl);

- cache->caching_ctl = caching_ctl;

- cache->cached = BTRFS_CACHE_FAST;

- spin_unlock(&cache->lock);

-

- if (btrfs_test_opt(fs_info, SPACE_CACHE)) {

- mutex_lock(&caching_ctl->mutex);

- ret = load_free_space_cache(cache);

-

- spin_lock(&cache->lock);

- if (ret == 1) {

- cache->caching_ctl = NULL;

- cache->cached = BTRFS_CACHE_FINISHED;

- cache->last_byte_to_unpin = (u64)-1;

- caching_ctl->progress = (u64)-1;

- } else {

- if (load_cache_only) {

- cache->caching_ctl = NULL;

- cache->cached = BTRFS_CACHE_NO;

- } else {

- cache->cached = BTRFS_CACHE_STARTED;

- cache->has_caching_ctl = 1;

- }

- }

- spin_unlock(&cache->lock);

-#ifdef CONFIG_BTRFS_DEBUG

- if (ret == 1 &&

- btrfs_should_fragment_free_space(cache)) {

- u64 bytes_used;

-

- spin_lock(&cache->space_info->lock);

- spin_lock(&cache->lock);

- bytes_used = cache->key.offset -

- btrfs_block_group_used(&cache->item);

- cache->space_info->bytes_used += bytes_used >> 1;

- spin_unlock(&cache->lock);

- spin_unlock(&cache->space_info->lock);

- fragment_free_space(cache);

- }

-#endif

- mutex_unlock(&caching_ctl->mutex);

-

- wake_up(&caching_ctl->wait);

- if (ret == 1) {

- put_caching_control(caching_ctl);

- free_excluded_extents(cache);

- return 0;

- }

- } else {

- /*

- * We're either using the free space tree or no caching at all.

- * Set cached to the appropriate value and wakeup any waiters.

- */

- spin_lock(&cache->lock);

- if (load_cache_only) {

- cache->caching_ctl = NULL;

- cache->cached = BTRFS_CACHE_NO;

- } else {

- cache->cached = BTRFS_CACHE_STARTED;

- cache->has_caching_ctl = 1;

- }

- spin_unlock(&cache->lock);

- wake_up(&caching_ctl->wait);

- }

-

- if (load_cache_only) {

- put_caching_control(caching_ctl);

- return 0;

- }

-

- down_write(&fs_info->commit_root_sem);

- refcount_inc(&caching_ctl->count);

- list_add_tail(&caching_ctl->list, &fs_info->caching_block_groups);

- up_write(&fs_info->commit_root_sem);

-

- btrfs_get_block_group(cache);

-

- btrfs_queue_work(fs_info->caching_workers, &caching_ctl->work);

-

- return ret;

-}

-

-/*

- * return the block group that starts at or after bytenr

- */

-static struct btrfs_block_group_cache *

-btrfs_lookup_first_block_group(struct btrfs_fs_info *info, u64 bytenr)

-{

- return block_group_cache_tree_search(info, bytenr, 0);

-}

-

-/*

- * return the block group that contains the given bytenr

- */

-struct btrfs_block_group_cache *btrfs_lookup_block_group(

- struct btrfs_fs_info *info,

- u64 bytenr)

-{

- return block_group_cache_tree_search(info, bytenr, 1);

-}

-

static u64 generic_ref_to_space_flags(struct btrfs_ref *ref)

{

if (ref->type == BTRFS_REF_METADATA) {

@@ -1045,7 +438,7 @@ int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb,

return BTRFS_REF_TYPE_INVALID;

}

-static u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset)

+u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset)

{

u32 high_crc = ~(u32)0;

u32 low_crc = ~(u32)0;

@@ -2964,16 +2357,19 @@ static noinline int check_committed_ref(struct btrfs_root *root,

item_size = btrfs_item_size_nr(leaf, path->slots[0]);

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 (item_size != sizeof(*ei) +

btrfs_extent_inline_ref_size(BTRFS_EXTENT_DATA_REF_KEY))

goto out;

+ /* If extent created before last snapshot => it's definitely shared */

if (btrfs_extent_generation(leaf, ei) <=

btrfs_root_last_snapshot(&root->root_item))

goto out;

iref = (struct btrfs_extent_inline_ref *)(ei + 1);

+ /* If this extent has SHARED_DATA_REF then it's shared */

type = btrfs_get_extent_inline_ref_type(leaf, iref, BTRFS_REF_TYPE_DATA);

if (type != BTRFS_EXTENT_DATA_REF_KEY)

goto out;

@@ -3118,552 +2514,6 @@ int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,

return __btrfs_mod_ref(trans, root, buf, full_backref, 0);

}

-static int write_one_cache_group(struct btrfs_trans_handle *trans,

- struct btrfs_path *path,

- struct btrfs_block_group_cache *cache)

-{

- struct btrfs_fs_info *fs_info = trans->fs_info;

- int ret;

- struct btrfs_root *extent_root = fs_info->extent_root;

- unsigned long bi;

- struct extent_buffer *leaf;

-

- ret = btrfs_search_slot(trans, extent_root, &cache->key, path, 0, 1);

- if (ret) {

- if (ret > 0)

- ret = -ENOENT;

- goto fail;

- }

-

- leaf = path->nodes[0];

- bi = btrfs_item_ptr_offset(leaf, path->slots[0]);

- write_extent_buffer(leaf, &cache->item, bi, sizeof(cache->item));

- btrfs_mark_buffer_dirty(leaf);

-fail:

- btrfs_release_path(path);

- return ret;

-

-}

-

-static struct btrfs_block_group_cache *next_block_group(

- struct btrfs_block_group_cache *cache)

-{

- struct btrfs_fs_info *fs_info = cache->fs_info;

- struct rb_node *node;

-

- spin_lock(&fs_info->block_group_cache_lock);

-

- /* If our block group was removed, we need a full search. */

- if (RB_EMPTY_NODE(&cache->cache_node)) {

- const u64 next_bytenr = cache->key.objectid + cache->key.offset;

-

- spin_unlock(&fs_info->block_group_cache_lock);

- btrfs_put_block_group(cache);

- cache = btrfs_lookup_first_block_group(fs_info, next_bytenr); return cache;

- }

- node = rb_next(&cache->cache_node);

- btrfs_put_block_group(cache);

- if (node) {

- cache = rb_entry(node, struct btrfs_block_group_cache,

- cache_node);

- btrfs_get_block_group(cache);

- } else

- cache = NULL;

- spin_unlock(&fs_info->block_group_cache_lock);

- return cache;

-}

-

-static int cache_save_setup(struct btrfs_block_group_cache *block_group,

- struct btrfs_trans_handle *trans,

- struct btrfs_path *path)

-{

- struct btrfs_fs_info *fs_info = block_group->fs_info;

- struct btrfs_root *root = fs_info->tree_root;

- struct inode *inode = NULL;

- struct extent_changeset *data_reserved = NULL;

- u64 alloc_hint = 0;

- int dcs = BTRFS_DC_ERROR;

- u64 num_pages = 0;

- int retries = 0;

- int ret = 0;

-

- /*

- * If this block group is smaller than 100 megs don't bother caching the

- * block group.

- */

- if (block_group->key.offset < (100 * SZ_1M)) {

- spin_lock(&block_group->lock);

- block_group->disk_cache_state = BTRFS_DC_WRITTEN;

- spin_unlock(&block_group->lock);

- return 0;

- }

-

- if (trans->aborted)

- return 0;

-again:

- inode = lookup_free_space_inode(block_group, path);

- if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) {

- ret = PTR_ERR(inode);

- btrfs_release_path(path);

- goto out;

- }

-

- if (IS_ERR(inode)) {

- BUG_ON(retries);

- retries++;

-

- if (block_group->ro)

- goto out_free;

-

- ret = create_free_space_inode(trans, block_group, path);

- if (ret)

- goto out_free;

- goto again;

- }

-

- /*

- * We want to set the generation to 0, that way if anything goes wrong

- * from here on out we know not to trust this cache when we load up next

- * time.

- */

- BTRFS_I(inode)->generation = 0;

- ret = btrfs_update_inode(trans, root, inode);

- if (ret) {

- /*

- * So theoretically we could recover from this, simply set the

- * super cache generation to 0 so we know to invalidate the

- * cache, but then we'd have to keep track of the block groups

- * that fail this way so we know we _have_ to reset this cache

- * before the next commit or risk reading stale cache. So to

- * limit our exposure to horrible edge cases lets just abort the

- * transaction, this only happens in really bad situations

- * anyway.

- */

- btrfs_abort_transaction(trans, ret);

- goto out_put;

- }

- WARN_ON(ret);

-

- /* We've already setup this transaction, go ahead and exit */

- if (block_group->cache_generation == trans->transid &&

- i_size_read(inode)) {

- dcs = BTRFS_DC_SETUP;

- goto out_put;

- }

-

- if (i_size_read(inode) > 0) {

- ret = btrfs_check_trunc_cache_free_space(fs_info,

- &fs_info->global_block_rsv);

- if (ret)

- goto out_put;

-

- ret = btrfs_truncate_free_space_cache(trans, NULL, inode);

- if (ret)

- goto out_put;

- }

-

- spin_lock(&block_group->lock);

- if (block_group->cached != BTRFS_CACHE_FINISHED ||

- !btrfs_test_opt(fs_info, SPACE_CACHE)) {

- /*

- * don't bother trying to write stuff out _if_

- * a) we're not cached,

- * b) we're with nospace_cache mount option,

- * c) we're with v2 space_cache (FREE_SPACE_TREE).

- */

- dcs = BTRFS_DC_WRITTEN;

- spin_unlock(&block_group->lock);

- goto out_put;

- }

- spin_unlock(&block_group->lock);

-

- /*

- * We hit an ENOSPC when setting up the cache in this transaction, just

- * skip doing the setup, we've already cleared the cache so we're safe.

- */

- if (test_bit(BTRFS_TRANS_CACHE_ENOSPC, &trans->transaction->flags)) {

- ret = -ENOSPC;

- goto out_put;

- }

-

- /*

- * Try to preallocate enough space based on how big the block group is.

- * Keep in mind this has to include any pinned space which could end up

- * taking up quite a bit since it's not folded into the other space

- * cache.

- */

- num_pages = div_u64(block_group->key.offset, SZ_256M);

- if (!num_pages)

- num_pages = 1;

-

- num_pages *= 16;

- num_pages *= PAGE_SIZE;

-

- ret = btrfs_check_data_free_space(inode, &data_reserved, 0, num_pages);

- if (ret)

- goto out_put;

-

- ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, num_pages,

- num_pages, num_pages,

- &alloc_hint);

- /*

- * Our cache requires contiguous chunks so that we don't modify a bunch

- * of metadata or split extents when writing the cache out, which means

- * we can enospc if we are heavily fragmented in addition to just normal

- * out of space conditions. So if we hit this just skip setting up any

- * other block groups for this transaction, maybe we'll unpin enough

- * space the next time around.

- */

- if (!ret)

- dcs = BTRFS_DC_SETUP;

- else if (ret == -ENOSPC)

- set_bit(BTRFS_TRANS_CACHE_ENOSPC, &trans->transaction->flags);

-

-out_put:

- iput(inode);

-out_free:

- btrfs_release_path(path);

-out:

- spin_lock(&block_group->lock);

- if (!ret && dcs == BTRFS_DC_SETUP)

- block_group->cache_generation = trans->transid;

- block_group->disk_cache_state = dcs;

- spin_unlock(&block_group->lock);

-

- extent_changeset_free(data_reserved);

- return ret;

-}

-

-int btrfs_setup_space_cache(struct btrfs_trans_handle *trans)

-{

- struct btrfs_fs_info *fs_info = trans->fs_info;

- struct btrfs_block_group_cache *cache, *tmp;

- struct btrfs_transaction *cur_trans = trans->transaction;

- struct btrfs_path *path;

-

- if (list_empty(&cur_trans->dirty_bgs) ||

- !btrfs_test_opt(fs_info, SPACE_CACHE))

- return 0;

-

- path = btrfs_alloc_path();

- if (!path)

- return -ENOMEM;

-

- /* Could add new block groups, use _safe just in case */

- list_for_each_entry_safe(cache, tmp, &cur_trans->dirty_bgs,

- dirty_list) {

- if (cache->disk_cache_state == BTRFS_DC_CLEAR)

- cache_save_setup(cache, trans, path);

- }

-

- btrfs_free_path(path);

- return 0;

-}

-

-/*

- * transaction commit does final block group cache writeback during a

- * critical section where nothing is allowed to change the FS. This is

- * required in order for the cache to actually match the block group,

- * but can introduce a lot of latency into the commit.

- *

- * So, btrfs_start_dirty_block_groups is here to kick off block group

- * cache IO. There's a chance we'll have to redo some of it if the

- * block group changes again during the commit, but it greatly reduces

- * the commit latency by getting rid of the easy block groups while

- * we're still allowing others to join the commit.

- */

-int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans)

-{

- struct btrfs_fs_info *fs_info = trans->fs_info;

- struct btrfs_block_group_cache *cache;

- struct btrfs_transaction *cur_trans = trans->transaction;

- int ret = 0;

- int should_put;

- struct btrfs_path *path = NULL;

- LIST_HEAD(dirty);

- struct list_head *io = &cur_trans->io_bgs;

- int num_started = 0;

- int loops = 0;

-

- spin_lock(&cur_trans->dirty_bgs_lock);

- if (list_empty(&cur_trans->dirty_bgs)) {

- spin_unlock(&cur_trans->dirty_bgs_lock);

- return 0;

- }

- list_splice_init(&cur_trans->dirty_bgs, &dirty);

- spin_unlock(&cur_trans->dirty_bgs_lock);

-

-again:

- /*

- * make sure all the block groups on our dirty list actually

- * exist

- */

- btrfs_create_pending_block_groups(trans);

-

- if (!path) {

- path = btrfs_alloc_path();

- if (!path)

- return -ENOMEM;

- }

-

- /*

- * cache_write_mutex is here only to save us from balance or automatic

- * removal of empty block groups deleting this block group while we are

- * writing out the cache

- */

- mutex_lock(&trans->transaction->cache_write_mutex);

- while (!list_empty(&dirty)) {

- bool drop_reserve = true;

-

- cache = list_first_entry(&dirty,

- struct btrfs_block_group_cache,

- dirty_list);

- /*

- * this can happen if something re-dirties a block

- * group that is already under IO. Just wait for it to

- * finish and then do it all again

- */

- if (!list_empty(&cache->io_list)) {

- list_del_init(&cache->io_list);

- btrfs_wait_cache_io(trans, cache, path);

- btrfs_put_block_group(cache);

- }

-

-

- /*

- * btrfs_wait_cache_io uses the cache->dirty_list to decide

- * if it should update the cache_state. Don't delete

- * until after we wait.

- *

- * Since we're not running in the commit critical section

- * we need the dirty_bgs_lock to protect from update_block_group

- */

- spin_lock(&cur_trans->dirty_bgs_lock);

- list_del_init(&cache->dirty_list);

- spin_unlock(&cur_trans->dirty_bgs_lock);

-

- should_put = 1;

-

- cache_save_setup(cache, trans, path);

-

- if (cache->disk_cache_state == BTRFS_DC_SETUP) {

- cache->io_ctl.inode = NULL;

- ret = btrfs_write_out_cache(trans, cache, path);

- if (ret == 0 && cache->io_ctl.inode) {

- num_started++;

- should_put = 0;

-

- /*

- * The cache_write_mutex is protecting the

- * io_list, also refer to the definition of

- * btrfs_transaction::io_bgs for more details

- */

- list_add_tail(&cache->io_list, io);

- } else {

- /*

- * if we failed to write the cache, the

- * generation will be bad and life goes on

- */

- ret = 0;

- }

- }

- if (!ret) {

- ret = write_one_cache_group(trans, path, cache);

- /*

- * Our block group might still be attached to the list

- * of new block groups in the transaction handle of some

- * other task (struct btrfs_trans_handle->new_bgs). This

- * means its block group item isn't yet in the extent

- * tree. If this happens ignore the error, as we will

- * try again later in the critical section of the

- * transaction commit.

- */

- if (ret == -ENOENT) {

- ret = 0;

- spin_lock(&cur_trans->dirty_bgs_lock);

- if (list_empty(&cache->dirty_list)) {

- list_add_tail(&cache->dirty_list,

- &cur_trans->dirty_bgs);

- btrfs_get_block_group(cache);

- drop_reserve = false;

- }

- spin_unlock(&cur_trans->dirty_bgs_lock);

- } else if (ret) {

- btrfs_abort_transaction(trans, ret);

- }

- }

-

- /* if it's not on the io list, we need to put the block group */

- if (should_put)

- btrfs_put_block_group(cache);

- if (drop_reserve)

- btrfs_delayed_refs_rsv_release(fs_info, 1);

-

- if (ret)

- break;

-

- /*

- * Avoid blocking other tasks for too long. It might even save

- * us from writing caches for block groups that are going to be

- * removed.

- */

- mutex_unlock(&trans->transaction->cache_write_mutex);

- mutex_lock(&trans->transaction->cache_write_mutex);

- }

- mutex_unlock(&trans->transaction->cache_write_mutex);

-

- /*

- * go through delayed refs for all the stuff we've just kicked off

- * and then loop back (just once)

- */

- ret = btrfs_run_delayed_refs(trans, 0);

- if (!ret && loops == 0) {

- loops++;

- spin_lock(&cur_trans->dirty_bgs_lock);

- list_splice_init(&cur_trans->dirty_bgs, &dirty);

- /*

- * dirty_bgs_lock protects us from concurrent block group

- * deletes too (not just cache_write_mutex).

- */

- if (!list_empty(&dirty)) {

- spin_unlock(&cur_trans->dirty_bgs_lock);

- goto again;

- }

- spin_unlock(&cur_trans->dirty_bgs_lock);

- } else if (ret < 0) {

- btrfs_cleanup_dirty_bgs(cur_trans, fs_info);

- }

-

- btrfs_free_path(path);

- return ret;

-}

-

-int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans)

-{

- struct btrfs_fs_info *fs_info = trans->fs_info;

- struct btrfs_block_group_cache *cache;

- struct btrfs_transaction *cur_trans = trans->transaction;

- int ret = 0;

- int should_put;

- struct btrfs_path *path;

- struct list_head *io = &cur_trans->io_bgs;

- int num_started = 0;

-

- path = btrfs_alloc_path();

- if (!path)

- return -ENOMEM;

-

- /*

- * Even though we are in the critical section of the transaction commit,

- * we can still have concurrent tasks adding elements to this

- * transaction's list of dirty block groups. These tasks correspond to

- * endio free space workers started when writeback finishes for a

- * space cache, which run inode.c:btrfs_finish_ordered_io(), and can

- * allocate new block groups as a result of COWing nodes of the root

- * tree when updating the free space inode. The writeback for the space

- * caches is triggered by an earlier call to

- * btrfs_start_dirty_block_groups() and iterations of the following

- * loop.

- * Also we want to do the cache_save_setup first and then run the

- * delayed refs to make sure we have the best chance at doing this all

- * in one shot.

- */

- spin_lock(&cur_trans->dirty_bgs_lock);

- while (!list_empty(&cur_trans->dirty_bgs)) {

- cache = list_first_entry(&cur_trans->dirty_bgs,

- struct btrfs_block_group_cache,

- dirty_list);

-

- /*

- * this can happen if cache_save_setup re-dirties a block

- * group that is already under IO. Just wait for it to

- * finish and then do it all again

- */

- if (!list_empty(&cache->io_list)) {

- spin_unlock(&cur_trans->dirty_bgs_lock);

- list_del_init(&cache->io_list);

- btrfs_wait_cache_io(trans, cache, path);

- btrfs_put_block_group(cache);

- spin_lock(&cur_trans->dirty_bgs_lock);

- }

-

- /*

- * don't remove from the dirty list until after we've waited

- * on any pending IO

- */

- list_del_init(&cache->dirty_list);

- spin_unlock(&cur_trans->dirty_bgs_lock);

- should_put = 1;

-

- cache_save_setup(cache, trans, path);

-

- if (!ret)

- ret = btrfs_run_delayed_refs(trans,

- (unsigned long) -1);

-

- if (!ret && cache->disk_cache_state == BTRFS_DC_SETUP) {

- cache->io_ctl.inode = NULL;

- ret = btrfs_write_out_cache(trans, cache, path);

- if (ret == 0 && cache->io_ctl.inode) {

- num_started++;

- should_put = 0;

- list_add_tail(&cache->io_list, io);

- } else {

- /*

- * if we failed to write the cache, the

- * generation will be bad and life goes on

- */

- ret = 0;

- }

- }

- if (!ret) {

- ret = write_one_cache_group(trans, path, cache);

- /*

- * One of the free space endio workers might have

- * created a new block group while updating a free space

- * cache's inode (at inode.c:btrfs_finish_ordered_io())

- * and hasn't released its transaction handle yet, in

- * which case the new block group is still attached to

- * its transaction handle and its creation has not

- * finished yet (no block group item in the extent tree

- * yet, etc). If this is the case, wait for all free

- * space endio workers to finish and retry. This is a

- * a very rare case so no need for a more efficient and

- * complex approach.

- */

- if (ret == -ENOENT) {

- wait_event(cur_trans->writer_wait,

- atomic_read(&cur_trans->num_writers) == 1);

- ret = write_one_cache_group(trans, path, cache);

- }

- if (ret)

- btrfs_abort_transaction(trans, ret);

- }

-

- /* if its not on the io list, we need to put the block group */

- if (should_put)

- btrfs_put_block_group(cache);

- btrfs_delayed_refs_rsv_release(fs_info, 1);

- spin_lock(&cur_trans->dirty_bgs_lock);

- }

- spin_unlock(&cur_trans->dirty_bgs_lock);

-

- /*

- * Refer to the definition of io_bgs member for details why it's safe

- * to use it without any locking

- */

- while (!list_empty(io)) {

- cache = list_first_entry(io, struct btrfs_block_group_cache,

- io_list);

- list_del_init(&cache->io_list);

- btrfs_wait_cache_io(trans, cache, path);

- btrfs_put_block_group(cache);

- }

-

- btrfs_free_path(path);

- return ret;

-}

-

int btrfs_extent_readonly(struct btrfs_fs_info *fs_info, u64 bytenr)

{

struct btrfs_block_group_cache *block_group;

@@ -3677,166 +2527,6 @@ int btrfs_extent_readonly(struct btrfs_fs_info *fs_info, u64 bytenr)

return readonly;

}

-bool btrfs_inc_nocow_writers(struct btrfs_fs_info *fs_info, u64 bytenr)

-{

- struct btrfs_block_group_cache *bg;

- bool ret = true;

-

- bg = btrfs_lookup_block_group(fs_info, bytenr);

- if (!bg)

- return false;

-

- spin_lock(&bg->lock);

- if (bg->ro)

- ret = false;

- else

- atomic_inc(&bg->nocow_writers);

- spin_unlock(&bg->lock);

-

- /* no put on block group, done by btrfs_dec_nocow_writers */

- if (!ret)

- btrfs_put_block_group(bg);

-

- return ret;

-

-}

-

-void btrfs_dec_nocow_writers(struct btrfs_fs_info *fs_info, u64 bytenr)

-{

- struct btrfs_block_group_cache *bg;

-

- bg = btrfs_lookup_block_group(fs_info, bytenr);

- ASSERT(bg);

- if (atomic_dec_and_test(&bg->nocow_writers))

- wake_up_var(&bg->nocow_writers);

- /*

- * Once for our lookup and once for the lookup done by a previous call

- * to btrfs_inc_nocow_writers()

- */

- btrfs_put_block_group(bg);

- btrfs_put_block_group(bg);

-}

-

-void btrfs_wait_nocow_writers(struct btrfs_block_group_cache *bg)

-{

- wait_var_event(&bg->nocow_writers, !atomic_read(&bg->nocow_writers));

-}

-

-static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)

-{

- u64 extra_flags = chunk_to_extended(flags) &

- BTRFS_EXTENDED_PROFILE_MASK;

-

- write_seqlock(&fs_info->profiles_lock);

- if (flags & BTRFS_BLOCK_GROUP_DATA)

- fs_info->avail_data_alloc_bits |= extra_flags;

- if (flags & BTRFS_BLOCK_GROUP_METADATA)

- fs_info->avail_metadata_alloc_bits |= extra_flags;

- if (flags & BTRFS_BLOCK_GROUP_SYSTEM)

- fs_info->avail_system_alloc_bits |= extra_flags;

- write_sequnlock(&fs_info->profiles_lock);

-}

-

-/*

- * returns target flags in extended format or 0 if restripe for this

- * chunk_type is not in progress

- *

- * should be called with balance_lock held

- */

-static u64 get_restripe_target(struct btrfs_fs_info *fs_info, u64 flags)

-{

- struct btrfs_balance_control *bctl = fs_info->balance_ctl;

- u64 target = 0;

-

- if (!bctl)

- return 0;

-

- if (flags & BTRFS_BLOCK_GROUP_DATA &&

- bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) {

- target = BTRFS_BLOCK_GROUP_DATA | bctl->data.target;

- } else if (flags & BTRFS_BLOCK_GROUP_SYSTEM &&

- bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) {

- target = BTRFS_BLOCK_GROUP_SYSTEM | bctl->sys.target;

- } else if (flags & BTRFS_BLOCK_GROUP_METADATA &&

- bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) {

- target = BTRFS_BLOCK_GROUP_METADATA | bctl->meta.target;

- }

-

- return target;

-}

-

-/*

- * @flags: available profiles in extended format (see ctree.h)

- *

- * Returns reduced profile in chunk format. If profile changing is in

- * progress (either running or paused) picks the target profile (if it's

- * already available), otherwise falls back to plain reducing.

- */

-static u64 btrfs_reduce_alloc_profile(struct btrfs_fs_info *fs_info, u64 flags)

-{

- u64 num_devices = fs_info->fs_devices->rw_devices;

- u64 target;

- u64 raid_type;

- u64 allowed = 0;

-

- /*

- * see if restripe for this chunk_type is in progress, if so

- * try to reduce to the target profile

- */

- spin_lock(&fs_info->balance_lock);

- target = get_restripe_target(fs_info, flags);

- if (target) {

- /* pick target profile only if it's already available */

- if ((flags & target) & BTRFS_EXTENDED_PROFILE_MASK) {

- spin_unlock(&fs_info->balance_lock);

- return extended_to_chunk(target);

- }

- }

- spin_unlock(&fs_info->balance_lock);

-

- /* First, mask out the RAID levels which aren't possible */

- for (raid_type = 0; raid_type < BTRFS_NR_RAID_TYPES; raid_type++) {

- if (num_devices >= btrfs_raid_array[raid_type].devs_min)

- allowed |= btrfs_raid_array[raid_type].bg_flag;

- }

- allowed &= flags;

-

- if (allowed & BTRFS_BLOCK_GROUP_RAID6)

- allowed = BTRFS_BLOCK_GROUP_RAID6;

- else if (allowed & BTRFS_BLOCK_GROUP_RAID5)

- allowed = BTRFS_BLOCK_GROUP_RAID5;

- else if (allowed & BTRFS_BLOCK_GROUP_RAID10)

- allowed = BTRFS_BLOCK_GROUP_RAID10;

- else if (allowed & BTRFS_BLOCK_GROUP_RAID1)

- allowed = BTRFS_BLOCK_GROUP_RAID1;

- else if (allowed & BTRFS_BLOCK_GROUP_RAID0)

- allowed = BTRFS_BLOCK_GROUP_RAID0;

-

- flags &= ~BTRFS_BLOCK_GROUP_PROFILE_MASK;

-

- return extended_to_chunk(flags | allowed);

-}

-

-static u64 get_alloc_profile(struct btrfs_fs_info *fs_info, u64 orig_flags)

-{

- unsigned seq;

- u64 flags;

-

- do {

- flags = orig_flags;

- seq = read_seqbegin(&fs_info->profiles_lock);

-

- if (flags & BTRFS_BLOCK_GROUP_DATA)

- flags |= fs_info->avail_data_alloc_bits;

- else if (flags & BTRFS_BLOCK_GROUP_SYSTEM)

- flags |= fs_info->avail_system_alloc_bits;

- else if (flags & BTRFS_BLOCK_GROUP_METADATA)

- flags |= fs_info->avail_metadata_alloc_bits;

- } while (read_seqretry(&fs_info->profiles_lock, seq));

-

- return btrfs_reduce_alloc_profile(fs_info, flags);

-}

-

static u64 get_alloc_profile_by_root(struct btrfs_root *root, int data)

{

struct btrfs_fs_info *fs_info = root->fs_info;

@@ -3850,368 +2540,7 @@ static u64 get_alloc_profile_by_root(struct btrfs_root *root, int data)

else

flags = BTRFS_BLOCK_GROUP_METADATA;

- ret = get_alloc_profile(fs_info, flags);

- return ret;

-}

-

-u64 btrfs_data_alloc_profile(struct btrfs_fs_info *fs_info)

-{

- return get_alloc_profile(fs_info, BTRFS_BLOCK_GROUP_DATA);

-}

-

-u64 btrfs_metadata_alloc_profile(struct btrfs_fs_info *fs_info)

-{

- return get_alloc_profile(fs_info, BTRFS_BLOCK_GROUP_METADATA);

-}

-

-u64 btrfs_system_alloc_profile(struct btrfs_fs_info *fs_info)

-{

- return get_alloc_profile(fs_info, BTRFS_BLOCK_GROUP_SYSTEM);

-}

-

-static void force_metadata_allocation(struct btrfs_fs_info *info)

-{

- struct list_head *head = &info->space_info;

- struct btrfs_space_info *found;

-

- rcu_read_lock();

- list_for_each_entry_rcu(found, head, list) {

- if (found->flags & BTRFS_BLOCK_GROUP_METADATA)

- found->force_alloc = CHUNK_ALLOC_FORCE;

- }

- rcu_read_unlock();

-}

-

-static int should_alloc_chunk(struct btrfs_fs_info *fs_info,

- struct btrfs_space_info *sinfo, int force)

-{

- u64 bytes_used = btrfs_space_info_used(sinfo, false);

- u64 thresh;

-

- if (force == CHUNK_ALLOC_FORCE)

- return 1;

-

- /*

- * in limited mode, we want to have some free space up to

- * about 1% of the FS size.

- */

- if (force == CHUNK_ALLOC_LIMITED) {

- thresh = btrfs_super_total_bytes(fs_info->super_copy);

- thresh = max_t(u64, SZ_64M, div_factor_fine(thresh, 1));

-

- if (sinfo->total_bytes - bytes_used < thresh)

- return 1;

- }

-

- if (bytes_used + SZ_2M < div_factor(sinfo->total_bytes, 8))

- return 0;

- return 1;

-}

-

-static u64 get_profile_num_devs(struct btrfs_fs_info *fs_info, u64 type)

-{

- u64 num_dev;

-

- num_dev = btrfs_raid_array[btrfs_bg_flags_to_raid_index(type)].devs_max;

- if (!num_dev)

- num_dev = fs_info->fs_devices->rw_devices;

-

- return num_dev;

-}

-

-/*

- * If @is_allocation is true, reserve space in the system space info necessary

- * for allocating a chunk, otherwise if it's false, reserve space necessary for

- * removing a chunk.

- */

-void check_system_chunk(struct btrfs_trans_handle *trans, u64 type)

-{

- struct btrfs_fs_info *fs_info = trans->fs_info;

- struct btrfs_space_info *info;

- u64 left;

- u64 thresh;

- int ret = 0;

- u64 num_devs;

-

- /*

- * Needed because we can end up allocating a system chunk and for an

- * atomic and race free space reservation in the chunk block reserve.

- */

- lockdep_assert_held(&fs_info->chunk_mutex);

-

- info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_SYSTEM);

- spin_lock(&info->lock);

- left = info->total_bytes - btrfs_space_info_used(info, true);

- spin_unlock(&info->lock);

-

- num_devs = get_profile_num_devs(fs_info, type);

-

- /* num_devs device items to update and 1 chunk item to add or remove */

- thresh = btrfs_calc_trunc_metadata_size(fs_info, num_devs) +

- btrfs_calc_trans_metadata_size(fs_info, 1);

-

- if (left < thresh && btrfs_test_opt(fs_info, ENOSPC_DEBUG)) {

- btrfs_info(fs_info, "left=%llu, need=%llu, flags=%llu",

- left, thresh, type);

- btrfs_dump_space_info(fs_info, info, 0, 0);

- }

-

- if (left < thresh) {

- u64 flags = btrfs_system_alloc_profile(fs_info);

-

- /*

- * Ignore failure to create system chunk. We might end up not

- * needing it, as we might not need to COW all nodes/leafs from

- * the paths we visit in the chunk tree (they were already COWed

- * or created in the current transaction for example).

- */

- ret = btrfs_alloc_chunk(trans, flags);

- }

-

- if (!ret) {

- ret = btrfs_block_rsv_add(fs_info->chunk_root,

- &fs_info->chunk_block_rsv,

- thresh, BTRFS_RESERVE_NO_FLUSH);

- if (!ret)

- trans->chunk_bytes_reserved += thresh;

- }

-}

-

-/*

- * If force is CHUNK_ALLOC_FORCE:

- * - return 1 if it successfully allocates a chunk,

- * - return errors including -ENOSPC otherwise.

- * If force is NOT CHUNK_ALLOC_FORCE:

- * - return 0 if it doesn't need to allocate a new chunk,

- * - return 1 if it successfully allocates a chunk,

- * - return errors including -ENOSPC otherwise.

- */

-int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags,

- enum btrfs_chunk_alloc_enum force)

-{

- struct btrfs_fs_info *fs_info = trans->fs_info;

- struct btrfs_space_info *space_info;

- bool wait_for_alloc = false;

- bool should_alloc = false;

- int ret = 0;

-

- /* Don't re-enter if we're already allocating a chunk */

- if (trans->allocating_chunk)

- return -ENOSPC;

-

- space_info = btrfs_find_space_info(fs_info, flags);

- ASSERT(space_info);

-

- do {

- spin_lock(&space_info->lock);

- if (force < space_info->force_alloc)

- force = space_info->force_alloc;

- should_alloc = should_alloc_chunk(fs_info, space_info, force);

- if (space_info->full) {

- /* No more free physical space */

- if (should_alloc)

- ret = -ENOSPC;

- else

- ret = 0;

- spin_unlock(&space_info->lock);

- return ret;

- } else if (!should_alloc) {

- spin_unlock(&space_info->lock);

- return 0;

- } else if (space_info->chunk_alloc) {

- /*

- * Someone is already allocating, so we need to block

- * until this someone is finished and then loop to

- * recheck if we should continue with our allocation

- * attempt.

- */

- wait_for_alloc = true;

- spin_unlock(&space_info->lock);

- mutex_lock(&fs_info->chunk_mutex);

- mutex_unlock(&fs_info->chunk_mutex);

- } else {

- /* Proceed with allocation */

- space_info->chunk_alloc = 1;

- wait_for_alloc = false;

- spin_unlock(&space_info->lock);

- }

-

- cond_resched();

- } while (wait_for_alloc);

-

- mutex_lock(&fs_info->chunk_mutex);

- trans->allocating_chunk = true;

-

- /*

- * If we have mixed data/metadata chunks we want to make sure we keep

- * allocating mixed chunks instead of individual chunks.

- */

- if (btrfs_mixed_space_info(space_info))

- flags |= (BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA);

-

- /*

- * if we're doing a data chunk, go ahead and make sure that

- * we keep a reasonable number of metadata chunks allocated in the

- * FS as well.

- */

- if (flags & BTRFS_BLOCK_GROUP_DATA && fs_info->metadata_ratio) {

- fs_info->data_chunk_allocations++;

- if (!(fs_info->data_chunk_allocations %

- fs_info->metadata_ratio))

- force_metadata_allocation(fs_info);

- }

-

- /*

- * Check if we have enough space in SYSTEM chunk because we may need

- * to update devices.

- */

- check_system_chunk(trans, flags);

-

- ret = btrfs_alloc_chunk(trans, flags);

- trans->allocating_chunk = false;

-

- spin_lock(&space_info->lock);

- if (ret < 0) {

- if (ret == -ENOSPC)

- space_info->full = 1;

- else

- goto out;

- } else {

- ret = 1;

- space_info->max_extent_size = 0;

- }

-

- space_info->force_alloc = CHUNK_ALLOC_NO_FORCE;

-out:

- space_info->chunk_alloc = 0;

- spin_unlock(&space_info->lock);

- mutex_unlock(&fs_info->chunk_mutex);

- /*

- * When we allocate a new chunk we reserve space in the chunk block

- * reserve to make sure we can COW nodes/leafs in the chunk tree or

- * add new nodes/leafs to it if we end up needing to do it when

- * inserting the chunk item and updating device items as part of the

- * second phase of chunk allocation, performed by

- * btrfs_finish_chunk_alloc(). So make sure we don't accumulate a

- * large number of new block groups to create in our transaction

- * handle's new_bgs list to avoid exhausting the chunk block reserve

- * in extreme cases - like having a single transaction create many new

- * block groups when starting to write out the free space caches of all

- * the block groups that were made dirty during the lifetime of the

- * transaction.

- */

- if (trans->chunk_bytes_reserved >= (u64)SZ_2M)

- btrfs_create_pending_block_groups(trans);

-

- return ret;

-}

-

-static int update_block_group(struct btrfs_trans_handle *trans,

- u64 bytenr, u64 num_bytes, int alloc)

-{

- struct btrfs_fs_info *info = trans->fs_info;

- struct btrfs_block_group_cache *cache = NULL;

- u64 total = num_bytes;

- u64 old_val;

- u64 byte_in_group;

- int factor;

- int ret = 0;

-

- /* block accounting for super block */

- spin_lock(&info->delalloc_root_lock);

- old_val = btrfs_super_bytes_used(info->super_copy);

- if (alloc)

- old_val += num_bytes;

- else

- old_val -= num_bytes;

- btrfs_set_super_bytes_used(info->super_copy, old_val);

- spin_unlock(&info->delalloc_root_lock);

-

- while (total) {

- cache = btrfs_lookup_block_group(info, bytenr);

- if (!cache) {

- ret = -ENOENT;

- break;

- }

- factor = btrfs_bg_type_to_factor(cache->flags);

-

- /*

- * If this block group has free space cache written out, we

- * need to make sure to load it if we are removing space. This

- * is because we need the unpinning stage to actually add the

- * space back to the block group, otherwise we will leak space.

- */

- if (!alloc && cache->cached == BTRFS_CACHE_NO)

- cache_block_group(cache, 1);

-

- byte_in_group = bytenr - cache->key.objectid;

- WARN_ON(byte_in_group > cache->key.offset);

-

- spin_lock(&cache->space_info->lock);

- spin_lock(&cache->lock);

-

- if (btrfs_test_opt(info, SPACE_CACHE) &&

- cache->disk_cache_state < BTRFS_DC_CLEAR)

- cache->disk_cache_state = BTRFS_DC_CLEAR;

-

- old_val = btrfs_block_group_used(&cache->item);

- num_bytes = min(total, cache->key.offset - byte_in_group);

- if (alloc) {

- old_val += num_bytes;

- btrfs_set_block_group_used(&cache->item, old_val);

- cache->reserved -= num_bytes;

- cache->space_info->bytes_reserved -= num_bytes;

- cache->space_info->bytes_used += num_bytes;

- cache->space_info->disk_used += num_bytes * factor;

- spin_unlock(&cache->lock);

- spin_unlock(&cache->space_info->lock);

- } else {

- old_val -= num_bytes;

- btrfs_set_block_group_used(&cache->item, old_val);

- cache->pinned += num_bytes;

- btrfs_space_info_update_bytes_pinned(info,

- cache->space_info, num_bytes);

- cache->space_info->bytes_used -= num_bytes;

- cache->space_info->disk_used -= num_bytes * factor;

- spin_unlock(&cache->lock);

- spin_unlock(&cache->space_info->lock);

-

- trace_btrfs_space_reservation(info, "pinned",

- cache->space_info->flags,

- num_bytes, 1);

- percpu_counter_add_batch(&cache->space_info->total_bytes_pinned,

- num_bytes,

- BTRFS_TOTAL_BYTES_PINNED_BATCH);

- set_extent_dirty(info->pinned_extents,

- bytenr, bytenr + num_bytes - 1,

- GFP_NOFS | __GFP_NOFAIL);

- }

-

- spin_lock(&trans->transaction->dirty_bgs_lock);

- if (list_empty(&cache->dirty_list)) {

- list_add_tail(&cache->dirty_list,

- &trans->transaction->dirty_bgs);

- trans->delayed_ref_updates++;

- btrfs_get_block_group(cache);

- }

- spin_unlock(&trans->transaction->dirty_bgs_lock);

-

- /*

- * No longer have used bytes in this block group, queue it for

- * deletion. We do this after adding the block group to the

- * dirty list to avoid races between cleaner kthread and space

- * cache writeout.

- */

- if (!alloc && old_val == 0)

- btrfs_mark_bg_unused(cache);

-

- btrfs_put_block_group(cache);

- total -= num_bytes;

- bytenr += num_bytes;

- }

-

- /* Modified block groups are accounted for in the delayed_refs_rsv. */

- btrfs_update_delayed_refs_rsv(trans);

+ ret = btrfs_get_alloc_profile(fs_info, flags);

return ret;

}

@@ -4254,8 +2583,6 @@ static int pin_down_extent(struct btrfs_block_group_cache *cache,

spin_unlock(&cache->lock);

spin_unlock(&cache->space_info->lock);

- trace_btrfs_space_reservation(fs_info, "pinned",

- cache->space_info->flags, num_bytes, 1);

percpu_counter_add_batch(&cache->space_info->total_bytes_pinned,

num_bytes, BTRFS_TOTAL_BYTES_PINNED_BATCH);

set_extent_dirty(fs_info->pinned_extents, bytenr,

@@ -4299,7 +2626,7 @@ int btrfs_pin_extent_for_log_replay(struct btrfs_fs_info *fs_info,

* to one because the slow code to read in the free extents does check

* the pinned extents.

*/

- cache_block_group(cache, 1);

+ btrfs_cache_block_group(cache, 1);

pin_down_extent(cache, bytenr, num_bytes, 0);

@@ -4320,18 +2647,19 @@ static int __exclude_logged_extent(struct btrfs_fs_info *fs_info,

if (!block_group)

return -EINVAL;

- cache_block_group(block_group, 0);

- caching_ctl = get_caching_control(block_group);

+ btrfs_cache_block_group(block_group, 0);

+ caching_ctl = btrfs_get_caching_control(block_group);

if (!caching_ctl) {

/* Logic error */

- BUG_ON(!block_group_cache_done(block_group));

+ BUG_ON(!btrfs_block_group_cache_done(block_group));

ret = btrfs_remove_free_space(block_group, start, num_bytes);

} else {

mutex_lock(&caching_ctl->mutex);

if (start >= caching_ctl->progress) {

- ret = add_excluded_extent(fs_info, start, num_bytes);

+ ret = btrfs_add_excluded_extent(fs_info, start,

+ num_bytes);

} else if (start + num_bytes <= caching_ctl->progress) {

ret = btrfs_remove_free_space(block_group,

start, num_bytes);

@@ -4345,11 +2673,12 @@ static int __exclude_logged_extent(struct btrfs_fs_info *fs_info,

num_bytes = (start + num_bytes) -

caching_ctl->progress;

start = caching_ctl->progress;

- ret = add_excluded_extent(fs_info, start, num_bytes);

+ ret = btrfs_add_excluded_extent(fs_info, start,

+ num_bytes);

}

out_lock:

mutex_unlock(&caching_ctl->mutex);

- put_caching_control(caching_ctl);

+ btrfs_put_caching_control(caching_ctl);

}

btrfs_put_block_group(block_group);

return ret;

@@ -4393,108 +2722,6 @@ btrfs_inc_block_group_reservations(struct btrfs_block_group_cache *bg)

atomic_inc(&bg->reservations);

}

-void btrfs_dec_block_group_reservations(struct btrfs_fs_info *fs_info,

- const u64 start)

-{

- struct btrfs_block_group_cache *bg;

-

- bg = btrfs_lookup_block_group(fs_info, start);

- ASSERT(bg);

- if (atomic_dec_and_test(&bg->reservations))

- wake_up_var(&bg->reservations);

- btrfs_put_block_group(bg);

-}

-

-void btrfs_wait_block_group_reservations(struct btrfs_block_group_cache *bg)

-{

- struct btrfs_space_info *space_info = bg->space_info;

-

- ASSERT(bg->ro);

-

- if (!(bg->flags & BTRFS_BLOCK_GROUP_DATA))

- return;

-

- /*

- * Our block group is read only but before we set it to read only,

- * some task might have had allocated an extent from it already, but it

- * has not yet created a respective ordered extent (and added it to a

- * root's list of ordered extents).

- * Therefore wait for any task currently allocating extents, since the

- * block group's reservations counter is incremented while a read lock

- * on the groups' semaphore is held and decremented after releasing

- * the read access on that semaphore and creating the ordered extent.

- */

- down_write(&space_info->groups_sem);

- up_write(&space_info->groups_sem);

-

- wait_var_event(&bg->reservations, !atomic_read(&bg->reservations));

-}

-

-/**

- * btrfs_add_reserved_bytes - update the block_group and space info counters

- * @cache: The cache we are manipulating

- * @ram_bytes: The number of bytes of file content, and will be same to

- * @num_bytes except for the compress path.

- * @num_bytes: The number of bytes in question

- * @delalloc: The blocks are allocated for the delalloc write

- *

- * This is called by the allocator when it reserves space. If this is a

- * reservation and the block group has become read only we cannot make the

- * reservation and return -EAGAIN, otherwise this function always succeeds.

- */

-static int btrfs_add_reserved_bytes(struct btrfs_block_group_cache *cache,

- u64 ram_bytes, u64 num_bytes, int delalloc)

-{

- struct btrfs_space_info *space_info = cache->space_info;

- int ret = 0;

-

- spin_lock(&space_info->lock);

- spin_lock(&cache->lock);

- if (cache->ro) {

- ret = -EAGAIN;

- } else {

- cache->reserved += num_bytes;

- space_info->bytes_reserved += num_bytes;

- btrfs_space_info_update_bytes_may_use(cache->fs_info,

- space_info, -ram_bytes);

- if (delalloc)

- cache->delalloc_bytes += num_bytes;

- }

- spin_unlock(&cache->lock);

- spin_unlock(&space_info->lock);

- return ret;

-}

-

-/**

- * btrfs_free_reserved_bytes - update the block_group and space info counters

- * @cache: The cache we are manipulating

- * @num_bytes: The number of bytes in question

- * @delalloc: The blocks are allocated for the delalloc write

- *

- * This is called by somebody who is freeing space that was never actually used

- * on disk. For example if you reserve some space for a new leaf in transaction

- * A and before transaction A commits you free that leaf, you call this with

- * reserve set to 0 in order to clear the reservation.

- */

-

-static void btrfs_free_reserved_bytes(struct btrfs_block_group_cache *cache,

- u64 num_bytes, int delalloc)

-{

- struct btrfs_space_info *space_info = cache->space_info;

-

- spin_lock(&space_info->lock);

- spin_lock(&cache->lock);

- if (cache->ro)

- space_info->bytes_readonly += num_bytes;

- cache->reserved -= num_bytes;

- space_info->bytes_reserved -= num_bytes;

- space_info->max_extent_size = 0;

-

- if (delalloc)

- cache->delalloc_bytes -= num_bytes;

- spin_unlock(&cache->lock);

- spin_unlock(&space_info->lock);

-}

void btrfs_prepare_extent_commit(struct btrfs_fs_info *fs_info)

{

struct btrfs_caching_control *next;

@@ -4506,10 +2733,10 @@ void btrfs_prepare_extent_commit(struct btrfs_fs_info *fs_info)

list_for_each_entry_safe(caching_ctl, next,

&fs_info->caching_block_groups, list) {

cache = caching_ctl->block_group;

- if (block_group_cache_done(cache)) {

+ if (btrfs_block_group_cache_done(cache)) {

cache->last_byte_to_unpin = (u64)-1;

list_del_init(&caching_ctl->list);

- put_caching_control(caching_ctl);

+ btrfs_put_caching_control(caching_ctl);

} else {

cache->last_byte_to_unpin = caching_ctl->progress;

}

@@ -4613,9 +2840,6 @@ static int unpin_extent_range(struct btrfs_fs_info *fs_info,

spin_lock(&cache->lock);

cache->pinned -= len;

btrfs_space_info_update_bytes_pinned(fs_info, space_info, -len);

-

- trace_btrfs_space_reservation(fs_info, "pinned",

- space_info->flags, len, 0);

space_info->max_extent_size = 0;

percpu_counter_add_batch(&space_info->total_bytes_pinned,

-len, BTRFS_TOTAL_BYTES_PINNED_BATCH);

@@ -4637,17 +2861,13 @@ static int unpin_extent_range(struct btrfs_fs_info *fs_info,

space_info, to_add);

if (global_rsv->reserved >= global_rsv->size)

global_rsv->full = 1;

- trace_btrfs_space_reservation(fs_info,

- "space_info",

- space_info->flags,

- to_add, 1);

len -= to_add;

}

spin_unlock(&global_rsv->lock);

/* Add to any tickets we may have */

if (len)

- btrfs_space_info_add_new_bytes(fs_info,

- space_info, len);

+ btrfs_try_granting_tickets(fs_info,

+ space_info);

}

spin_unlock(&space_info->lock);

}

@@ -4948,7 +3168,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,

goto out;

}

- ret = update_block_group(trans, bytenr, num_bytes, 0);

+ ret = btrfs_update_block_group(trans, bytenr, num_bytes, 0);

if (ret) {

btrfs_abort_transaction(trans, ret);

goto out;

@@ -5121,53 +3341,6 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_ref *ref)

return ret;

}

-/*

- * when we wait for progress in the block group caching, its because

- * our allocation attempt failed at least once. So, we must sleep

- * and let some progress happen before we try again.

- *

- * This function will sleep at least once waiting for new free space to

- * show up, and then it will check the block group free space numbers

- * for our min num_bytes. Another option is to have it go ahead

- * and look in the rbtree for a free extent of a given size, but this

- * is a good start.

- *

- * Callers of this must check if cache->cached == BTRFS_CACHE_ERROR before using

- * any of the information in this block group.

- */

-static noinline void

-wait_block_group_cache_progress(struct btrfs_block_group_cache *cache,

- u64 num_bytes)

-{

- struct btrfs_caching_control *caching_ctl;

-

- caching_ctl = get_caching_control(cache);

- if (!caching_ctl)

- return;

-

- wait_event(caching_ctl->wait, block_group_cache_done(cache) ||

- (cache->free_space_ctl->free_space >= num_bytes));

-

- put_caching_control(caching_ctl);

-}

-

-static noinline int

-wait_block_group_cache_done(struct btrfs_block_group_cache *cache)

-{

- struct btrfs_caching_control *caching_ctl;

- int ret = 0;

-

- caching_ctl = get_caching_control(cache);

- if (!caching_ctl)

- return (cache->cached == BTRFS_CACHE_ERROR) ? -EIO : 0;

-

- wait_event(caching_ctl->wait, block_group_cache_done(cache));

- if (cache->cached == BTRFS_CACHE_ERROR)

- ret = -EIO;

- put_caching_control(caching_ctl);

- return ret;

-}

-

enum btrfs_loop_type {

LOOP_CACHING_NOWAIT,

LOOP_CACHING_WAIT,

@@ -5387,7 +3560,7 @@ refill_cluster:

spin_unlock(&last_ptr->refill_lock);

ffe_ctl->retry_clustered = true;

- wait_block_group_cache_progress(bg, ffe_ctl->num_bytes +

+ btrfs_wait_block_group_cache_progress(bg, ffe_ctl->num_bytes +

ffe_ctl->empty_cluster + ffe_ctl->empty_size);

return -EAGAIN;

}

@@ -5454,8 +3627,8 @@ static int find_free_extent_unclustered(struct btrfs_block_group_cache *bg,

*/

if (!offset && !ffe_ctl->retry_unclustered && !ffe_ctl->cached &&

ffe_ctl->loop > LOOP_CACHING_NOWAIT) {

- wait_block_group_cache_progress(bg, ffe_ctl->num_bytes +

- ffe_ctl->empty_size);

+ btrfs_wait_block_group_cache_progress(bg, ffe_ctl->num_bytes +

+ ffe_ctl->empty_size);

ffe_ctl->retry_unclustered = true;

return -EAGAIN;

} else if (!offset) {

@@ -5751,13 +3924,21 @@ search:

*/

if ((flags & extra) && !(block_group->flags & extra))

goto loop;

+

+ /*

+ * This block group has different flags than we want.

+ * It's possible that we have MIXED_GROUP flag but no

+ * block group is mixed. Just skip such block group.

+ */

+ btrfs_release_block_group(block_group, delalloc);

+ continue;

}

have_block_group:

- ffe_ctl.cached = block_group_cache_done(block_group);

+ ffe_ctl.cached = btrfs_block_group_cache_done(block_group);

if (unlikely(!ffe_ctl.cached)) {

ffe_ctl.have_caching_bg = true;

- ret = cache_block_group(block_group, 0);

+ ret = btrfs_cache_block_group(block_group, 0);

BUG_ON(ret < 0);

ret = 0;

}

@@ -6052,7 +4233,7 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,

if (ret)

return ret;

- ret = update_block_group(trans, ins->objectid, ins->offset, 1);

+ ret = btrfs_update_block_group(trans, ins->objectid, ins->offset, 1);

if (ret) { /* -ENOENT, logic error */

btrfs_err(fs_info, "update block group failed for %llu %llu",

ins->objectid, ins->offset);

@@ -6142,8 +4323,8 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,

if (ret)

return ret;

- ret = update_block_group(trans, extent_key.objectid,

- fs_info->nodesize, 1);

+ ret = btrfs_update_block_group(trans, extent_key.objectid,

+ fs_info->nodesize, 1);

if (ret) { /* -ENOENT, logic error */

btrfs_err(fs_info, "update block group failed for %llu %llu",

extent_key.objectid, extent_key.offset);

@@ -7293,186 +5474,6 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans,

return ret;

}

-static u64 update_block_group_flags(struct btrfs_fs_info *fs_info, u64 flags)

-{

- u64 num_devices;

- u64 stripped;

-

- /*

- * if restripe for this chunk_type is on pick target profile and

- * return, otherwise do the usual balance

- */

- stripped = get_restripe_target(fs_info, flags);

- if (stripped)

- return extended_to_chunk(stripped);

-

- num_devices = fs_info->fs_devices->rw_devices;

-

- stripped = BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID56_MASK |

- BTRFS_BLOCK_GROUP_RAID1_MASK | BTRFS_BLOCK_GROUP_RAID10;

-

- if (num_devices == 1) {

- stripped |= BTRFS_BLOCK_GROUP_DUP;

- stripped = flags & ~stripped;

-

- /* turn raid0 into single device chunks */

- if (flags & BTRFS_BLOCK_GROUP_RAID0)

- return stripped;

-

- /* turn mirroring into duplication */

- if (flags & (BTRFS_BLOCK_GROUP_RAID1_MASK |

- BTRFS_BLOCK_GROUP_RAID10))

- return stripped | BTRFS_BLOCK_GROUP_DUP;

- } else {

- /* they already had raid on here, just return */

- if (flags & stripped)

- return flags;

-

- stripped |= BTRFS_BLOCK_GROUP_DUP;

- stripped = flags & ~stripped;

-

- /* switch duplicated blocks with raid1 */

- if (flags & BTRFS_BLOCK_GROUP_DUP)

- return stripped | BTRFS_BLOCK_GROUP_RAID1;

-

- /* this is drive concat, leave it alone */

- }

-

- return flags;

-}

-

-static int inc_block_group_ro(struct btrfs_block_group_cache *cache, int force)

-{

- struct btrfs_space_info *sinfo = cache->space_info;

- u64 num_bytes;

- u64 sinfo_used;

- u64 min_allocable_bytes;

- int ret = -ENOSPC;

-

- /*

- * We need some metadata space and system metadata space for

- * allocating chunks in some corner cases until we force to set

- * it to be readonly.

- */

- if ((sinfo->flags &

- (BTRFS_BLOCK_GROUP_SYSTEM | BTRFS_BLOCK_GROUP_METADATA)) &&

- !force)

- min_allocable_bytes = SZ_1M;

- else

- min_allocable_bytes = 0;

-

- spin_lock(&sinfo->lock);

- spin_lock(&cache->lock);

-

- if (cache->ro) {

- cache->ro++;

- ret = 0;

- goto out;

- }

-

- num_bytes = cache->key.offset - cache->reserved - cache->pinned -

- cache->bytes_super - btrfs_block_group_used(&cache->item);

- sinfo_used = btrfs_space_info_used(sinfo, true);

-

- if (sinfo_used + num_bytes + min_allocable_bytes <=

- sinfo->total_bytes) {

- sinfo->bytes_readonly += num_bytes;

- cache->ro++;

- list_add_tail(&cache->ro_list, &sinfo->ro_bgs);

- ret = 0;

- }

-out:

- spin_unlock(&cache->lock);

- spin_unlock(&sinfo->lock);

- if (ret == -ENOSPC && btrfs_test_opt(cache->fs_info, ENOSPC_DEBUG)) {

- btrfs_info(cache->fs_info,

- "unable to make block group %llu ro",

- cache->key.objectid);

- btrfs_info(cache->fs_info,

- "sinfo_used=%llu bg_num_bytes=%llu min_allocable=%llu",

- sinfo_used, num_bytes, min_allocable_bytes);

- btrfs_dump_space_info(cache->fs_info, cache->space_info, 0, 0);

- }

- return ret;

-}

-

-int btrfs_inc_block_group_ro(struct btrfs_block_group_cache *cache)

-

-{

- struct btrfs_fs_info *fs_info = cache->fs_info;

- struct btrfs_trans_handle *trans;

- u64 alloc_flags;

- int ret;

-

-again:

- trans = btrfs_join_transaction(fs_info->extent_root);

- if (IS_ERR(trans))

- return PTR_ERR(trans);

-

- /*

- * we're not allowed to set block groups readonly after the dirty

- * block groups cache has started writing. If it already started,

- * back off and let this transaction commit

- */

- mutex_lock(&fs_info->ro_block_group_mutex);

- if (test_bit(BTRFS_TRANS_DIRTY_BG_RUN, &trans->transaction->flags)) {

- u64 transid = trans->transid;

-

- mutex_unlock(&fs_info->ro_block_group_mutex);

- btrfs_end_transaction(trans);

-

- ret = btrfs_wait_for_commit(fs_info, transid);

- if (ret)

- return ret;

- goto again;

- }

-

- /*

- * if we are changing raid levels, try to allocate a corresponding

- * block group with the new raid level.

- */

- alloc_flags = update_block_group_flags(fs_info, cache->flags);

- if (alloc_flags != cache->flags) {

- ret = btrfs_chunk_alloc(trans, alloc_flags, CHUNK_ALLOC_FORCE);

- /*

- * ENOSPC is allowed here, we may have enough space

- * already allocated at the new raid level to

- * carry on

- */

- if (ret == -ENOSPC)

- ret = 0;

- if (ret < 0)

- goto out;

- }

-

- ret = inc_block_group_ro(cache, 0);

- if (!ret)

- goto out;

- alloc_flags = get_alloc_profile(fs_info, cache->space_info->flags);

- ret = btrfs_chunk_alloc(trans, alloc_flags, CHUNK_ALLOC_FORCE);

- if (ret < 0)

- goto out;

- ret = inc_block_group_ro(cache, 0);

-out:

- if (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM) {

- alloc_flags = update_block_group_flags(fs_info, cache->flags);

- mutex_lock(&fs_info->chunk_mutex);

- check_system_chunk(trans, alloc_flags);

- mutex_unlock(&fs_info->chunk_mutex);

- }

- mutex_unlock(&fs_info->ro_block_group_mutex);

-

- btrfs_end_transaction(trans);

- return ret;

-}

-

-int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, u64 type)

-{

- u64 alloc_flags = get_alloc_profile(trans->fs_info, type);

-

- return btrfs_chunk_alloc(trans, alloc_flags, CHUNK_ALLOC_FORCE);

-}

-

/*

* helper to account the unused space of all the readonly block group in the

* space_info. takes mirrors into account.

@@ -7508,1346 +5509,6 @@ u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo)

return free_bytes;

}

-void btrfs_dec_block_group_ro(struct btrfs_block_group_cache *cache)

-{

- struct btrfs_space_info *sinfo = cache->space_info;

- u64 num_bytes;

-

- BUG_ON(!cache->ro);

-

- spin_lock(&sinfo->lock);

- spin_lock(&cache->lock);

- if (!--cache->ro) {

- num_bytes = cache->key.offset - cache->reserved -

- cache->pinned - cache->bytes_super -

- btrfs_block_group_used(&cache->item);

- sinfo->bytes_readonly -= num_bytes;

- list_del_init(&cache->ro_list);

- }

- spin_unlock(&cache->lock);

- spin_unlock(&sinfo->lock);

-}

-

-/*

- * Checks to see if it's even possible to relocate this block group.

- *

- * @return - -1 if it's not a good idea to relocate this block group, 0 if its

- * ok to go ahead and try.

- */

-int btrfs_can_relocate(struct btrfs_fs_info *fs_info, u64 bytenr)

-{

- struct btrfs_block_group_cache *block_group;

- struct btrfs_space_info *space_info;

- struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;

- struct btrfs_device *device;

- u64 min_free;

- u64 dev_min = 1;

- u64 dev_nr = 0;

- u64 target;

- int debug;

- int index;

- int full = 0;

- int ret = 0;

-

- debug = btrfs_test_opt(fs_info, ENOSPC_DEBUG);

-

- block_group = btrfs_lookup_block_group(fs_info, bytenr);

-

- /* odd, couldn't find the block group, leave it alone */

- if (!block_group) {

- if (debug)

- btrfs_warn(fs_info,

- "can't find block group for bytenr %llu",

- bytenr);

- return -1;

- }

-

- min_free = btrfs_block_group_used(&block_group->item);

-

- /* no bytes used, we're good */

- if (!min_free)

- goto out;

-

- space_info = block_group->space_info;

- spin_lock(&space_info->lock);

-

- full = space_info->full;

-

- /*

- * if this is the last block group we have in this space, we can't

- * relocate it unless we're able to allocate a new chunk below.

- *

- * Otherwise, we need to make sure we have room in the space to handle

- * all of the extents from this block group. If we can, we're good

- */

- if ((space_info->total_bytes != block_group->key.offset) &&

- (btrfs_space_info_used(space_info, false) + min_free <

- space_info->total_bytes)) {

- spin_unlock(&space_info->lock);

- goto out;

- }

- spin_unlock(&space_info->lock);

-

- /*

- * ok we don't have enough space, but maybe we have free space on our

- * devices to allocate new chunks for relocation, so loop through our

- * alloc devices and guess if we have enough space. if this block

- * group is going to be restriped, run checks against the target

- * profile instead of the current one.

- */

- ret = -1;

-

- /*

- * index:

- * 0: raid10

- * 1: raid1

- * 2: dup

- * 3: raid0

- * 4: single

- */

- target = get_restripe_target(fs_info, block_group->flags);

- if (target) {

- index = btrfs_bg_flags_to_raid_index(extended_to_chunk(target));

- } else {

- /*

- * this is just a balance, so if we were marked as full

- * we know there is no space for a new chunk

- */

- if (full) {

- if (debug)

- btrfs_warn(fs_info,

- "no space to alloc new chunk for block group %llu",

- block_group->key.objectid);

- goto out;

- }

-

- index = btrfs_bg_flags_to_raid_index(block_group->flags);

- }

-

- if (index == BTRFS_RAID_RAID10) {

- dev_min = 4;

- /* Divide by 2 */

- min_free >>= 1;

- } else if (index == BTRFS_RAID_RAID1) {

- dev_min = 2;

- } else if (index == BTRFS_RAID_DUP) {

- /* Multiply by 2 */

- min_free <<= 1;

- } else if (index == BTRFS_RAID_RAID0) {

- dev_min = fs_devices->rw_devices;

- min_free = div64_u64(min_free, dev_min);

- }

-

- mutex_lock(&fs_info->chunk_mutex);

- list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) {

- u64 dev_offset;

-

- /*

- * check to make sure we can actually find a chunk with enough

- * space to fit our block group in.

- */

- if (device->total_bytes > device->bytes_used + min_free &&

- !test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state)) {

- ret = find_free_dev_extent(device, min_free,

- &dev_offset, NULL);

- if (!ret)

- dev_nr++;

-

- if (dev_nr >= dev_min)

- break;

-

- ret = -1;

- }

- }

- if (debug && ret == -1)

- btrfs_warn(fs_info,

- "no space to allocate a new chunk for block group %llu",

- block_group->key.objectid);

- mutex_unlock(&fs_info->chunk_mutex);

-out:

- btrfs_put_block_group(block_group);

- return ret;

-}

-

-static int find_first_block_group(struct btrfs_fs_info *fs_info,

- struct btrfs_path *path,

- struct btrfs_key *key)

-{

- struct btrfs_root *root = fs_info->extent_root;

- int ret = 0;

- struct btrfs_key found_key;

- struct extent_buffer *leaf;

- struct btrfs_block_group_item bg;

- u64 flags;

- int slot;

-

- ret = btrfs_search_slot(NULL, root, key, path, 0, 0);

- if (ret < 0)

- goto out;

-

- while (1) {

- slot = path->slots[0];

- leaf = path->nodes[0];

- if (slot >= btrfs_header_nritems(leaf)) {

- ret = btrfs_next_leaf(root, path);

- if (ret == 0)

- continue;

- if (ret < 0)

- goto out;

- break;

- }

- btrfs_item_key_to_cpu(leaf, &found_key, slot);

-

- if (found_key.objectid >= key->objectid &&

- found_key.type == BTRFS_BLOCK_GROUP_ITEM_KEY) {

- struct extent_map_tree *em_tree;

- struct extent_map *em;

-

- em_tree = &root->fs_info->mapping_tree;

- read_lock(&em_tree->lock);

- em = lookup_extent_mapping(em_tree, found_key.objectid,

- found_key.offset);

- read_unlock(&em_tree->lock);

- if (!em) {

- btrfs_err(fs_info,

- "logical %llu len %llu found bg but no related chunk",

- found_key.objectid, found_key.offset);

- ret = -ENOENT;

- } else if (em->start != found_key.objectid ||

- em->len != found_key.offset) {

- btrfs_err(fs_info,

- "block group %llu len %llu mismatch with chunk %llu len %llu",

- found_key.objectid, found_key.offset,

- em->start, em->len);

- ret = -EUCLEAN;

- } else {

- read_extent_buffer(leaf, &bg,

- btrfs_item_ptr_offset(leaf, slot),

- sizeof(bg));

- flags = btrfs_block_group_flags(&bg) &

- BTRFS_BLOCK_GROUP_TYPE_MASK;

-

- if (flags != (em->map_lookup->type &

- BTRFS_BLOCK_GROUP_TYPE_MASK)) {

- btrfs_err(fs_info,

-"block group %llu len %llu type flags 0x%llx mismatch with chunk type flags 0x%llx",

- found_key.objectid,

- found_key.offset, flags,

- (BTRFS_BLOCK_GROUP_TYPE_MASK &

- em->map_lookup->type));

- ret = -EUCLEAN;

- } else {

- ret = 0;

- }

- }

- free_extent_map(em);

- goto out;

- }

- path->slots[0]++;

- }

-out:

- return ret;

-}

-

-void btrfs_put_block_group_cache(struct btrfs_fs_info *info)

-{

- struct btrfs_block_group_cache *block_group;

- u64 last = 0;

-

- while (1) {

- struct inode *inode;

-

- block_group = btrfs_lookup_first_block_group(info, last);

- while (block_group) {

- wait_block_group_cache_done(block_group);

- spin_lock(&block_group->lock);

- if (block_group->iref)

- break;

- spin_unlock(&block_group->lock);

- block_group = next_block_group(block_group);

- }

- if (!block_group) {

- if (last == 0)

- break;

- last = 0;

- continue;

- }

-

- inode = block_group->inode;

- block_group->iref = 0;

- block_group->inode = NULL;

- spin_unlock(&block_group->lock);

- ASSERT(block_group->io_ctl.inode == NULL);

- iput(inode);

- last = block_group->key.objectid + block_group->key.offset;

- btrfs_put_block_group(block_group);

- }

-}

-

-/*

- * Must be called only after stopping all workers, since we could have block

- * group caching kthreads running, and therefore they could race with us if we

- * freed the block groups before stopping them.

- */

-int btrfs_free_block_groups(struct btrfs_fs_info *info)

-{

- struct btrfs_block_group_cache *block_group;

- struct btrfs_space_info *space_info;

- struct btrfs_caching_control *caching_ctl;

- struct rb_node *n;

-

- down_write(&info->commit_root_sem);

- while (!list_empty(&info->caching_block_groups)) {

- caching_ctl = list_entry(info->caching_block_groups.next,

- struct btrfs_caching_control, list);

- list_del(&caching_ctl->list);

- put_caching_control(caching_ctl);

- }

- up_write(&info->commit_root_sem);

-

- spin_lock(&info->unused_bgs_lock);

- while (!list_empty(&info->unused_bgs)) {

- block_group = list_first_entry(&info->unused_bgs,

- struct btrfs_block_group_cache,

- bg_list);

- list_del_init(&block_group->bg_list);

- btrfs_put_block_group(block_group);

- }

- spin_unlock(&info->unused_bgs_lock);

-

- spin_lock(&info->block_group_cache_lock);

- while ((n = rb_last(&info->block_group_cache_tree)) != NULL) {

- block_group = rb_entry(n, struct btrfs_block_group_cache,

- cache_node);

- rb_erase(&block_group->cache_node,

- &info->block_group_cache_tree);

- RB_CLEAR_NODE(&block_group->cache_node);

- spin_unlock(&info->block_group_cache_lock);

-

- down_write(&block_group->space_info->groups_sem);

- list_del(&block_group->list);

- up_write(&block_group->space_info->groups_sem);

-

- /*

- * We haven't cached this block group, which means we could

- * possibly have excluded extents on this block group.

- */

- if (block_group->cached == BTRFS_CACHE_NO ||

- block_group->cached == BTRFS_CACHE_ERROR)

- free_excluded_extents(block_group);

-

- btrfs_remove_free_space_cache(block_group);

- ASSERT(block_group->cached != BTRFS_CACHE_STARTED);

- ASSERT(list_empty(&block_group->dirty_list));

- ASSERT(list_empty(&block_group->io_list));

- ASSERT(list_empty(&block_group->bg_list));

- ASSERT(atomic_read(&block_group->count) == 1);

- btrfs_put_block_group(block_group);

-

- spin_lock(&info->block_group_cache_lock);

- }

- spin_unlock(&info->block_group_cache_lock);

-

- /* now that all the block groups are freed, go through and

- * free all the space_info structs. This is only called during

- * the final stages of unmount, and so we know nobody is

- * using them. We call synchronize_rcu() once before we start,

- * just to be on the safe side.

- */

- synchronize_rcu();

-

- btrfs_release_global_block_rsv(info);

-

- while (!list_empty(&info->space_info)) {

- int i;

-

- space_info = list_entry(info->space_info.next,

- struct btrfs_space_info,

- list);

-

- /*

- * Do not hide this behind enospc_debug, this is actually

- * important and indicates a real bug if this happens.

- */

- if (WARN_ON(space_info->bytes_pinned > 0 ||

- space_info->bytes_reserved > 0 ||

- space_info->bytes_may_use > 0))

- btrfs_dump_space_info(info, space_info, 0, 0);

- list_del(&space_info->list);

- for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) {

- struct kobject *kobj;

- kobj = space_info->block_group_kobjs[i];

- space_info->block_group_kobjs[i] = NULL;

- if (kobj) {

- kobject_del(kobj);

- kobject_put(kobj);

- }

- }

- kobject_del(&space_info->kobj);

- kobject_put(&space_info->kobj);

- }

- return 0;

-}

-

-static void link_block_group(struct btrfs_block_group_cache *cache)

-{

- struct btrfs_space_info *space_info = cache->space_info;

- struct btrfs_fs_info *fs_info = cache->fs_info;

- int index = btrfs_bg_flags_to_raid_index(cache->flags);

- bool first = false;

-

- down_write(&space_info->groups_sem);

- if (list_empty(&space_info->block_groups[index]))

- first = true;

- list_add_tail(&cache->list, &space_info->block_groups[index]);

- up_write(&space_info->groups_sem);

-

- if (first) {

- struct raid_kobject *rkobj;

- unsigned int nofs_flag;

- int ret;

-

- /*

- * Setup a NOFS context because kobject_add(), deep in its call

- * chain, does GFP_KERNEL allocations, and we are often called

- * in a context where if reclaim is triggered we can deadlock

- * (we are either holding a transaction handle or some lock

- * required for a transaction commit).

- */

- nofs_flag = memalloc_nofs_save();

- rkobj = kzalloc(sizeof(*rkobj), GFP_KERNEL);

- if (!rkobj) {

- memalloc_nofs_restore(nofs_flag);

- btrfs_warn(cache->fs_info,

- "couldn't alloc memory for raid level kobject");

- return;

- }

- rkobj->flags = cache->flags;

- kobject_init(&rkobj->kobj, &btrfs_raid_ktype);

- ret = kobject_add(&rkobj->kobj, &space_info->kobj, "%s",

- btrfs_bg_type_to_raid_name(rkobj->flags));

- memalloc_nofs_restore(nofs_flag);

- if (ret) {

- kobject_put(&rkobj->kobj);

- btrfs_warn(fs_info,

- "failed to add kobject for block cache, ignoring");

- return;

- }

- space_info->block_group_kobjs[index] = &rkobj->kobj;

- }

-}

-

-static struct btrfs_block_group_cache *

-btrfs_create_block_group_cache(struct btrfs_fs_info *fs_info,

- u64 start, u64 size)

-{

- struct btrfs_block_group_cache *cache;

-

- cache = kzalloc(sizeof(*cache), GFP_NOFS);

- if (!cache)

- return NULL;

-

- cache->free_space_ctl = kzalloc(sizeof(*cache->free_space_ctl),

- GFP_NOFS);

- if (!cache->free_space_ctl) {

- kfree(cache);

- return NULL;

- }

-

- cache->key.objectid = start;

- cache->key.offset = size;

- cache->key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;

-

- cache->fs_info = fs_info;

- cache->full_stripe_len = btrfs_full_stripe_len(fs_info, start);

- set_free_space_tree_thresholds(cache);

-

- atomic_set(&cache->count, 1);

- spin_lock_init(&cache->lock);

- init_rwsem(&cache->data_rwsem);

- INIT_LIST_HEAD(&cache->list);

- INIT_LIST_HEAD(&cache->cluster_list);

- INIT_LIST_HEAD(&cache->bg_list);

- INIT_LIST_HEAD(&cache->ro_list);

- INIT_LIST_HEAD(&cache->dirty_list);

- INIT_LIST_HEAD(&cache->io_list);

- btrfs_init_free_space_ctl(cache);

- atomic_set(&cache->trimming, 0);

- mutex_init(&cache->free_space_lock);

- btrfs_init_full_stripe_locks_tree(&cache->full_stripe_locks_root);

-

- return cache;

-}

-

-

-/*

- * Iterate all chunks and verify that each of them has the corresponding block

- * group

- */

-static int check_chunk_block_group_mappings(struct btrfs_fs_info *fs_info)

-{

- struct extent_map_tree *map_tree = &fs_info->mapping_tree;

- struct extent_map *em;

- struct btrfs_block_group_cache *bg;

- u64 start = 0;

- int ret = 0;

-

- while (1) {

- read_lock(&map_tree->lock);

- /*

- * lookup_extent_mapping will return the first extent map

- * intersecting the range, so setting @len to 1 is enough to

- * get the first chunk.

- */

- em = lookup_extent_mapping(map_tree, start, 1);

- read_unlock(&map_tree->lock);

- if (!em)

- break;

-

- bg = btrfs_lookup_block_group(fs_info, em->start);

- if (!bg) {

- btrfs_err(fs_info,

- "chunk start=%llu len=%llu doesn't have corresponding block group",

- em->start, em->len);

- ret = -EUCLEAN;

- free_extent_map(em);

- break;

- }

- if (bg->key.objectid != em->start ||

- bg->key.offset != em->len ||

- (bg->flags & BTRFS_BLOCK_GROUP_TYPE_MASK) !=

- (em->map_lookup->type & BTRFS_BLOCK_GROUP_TYPE_MASK)) {

- btrfs_err(fs_info,

-"chunk start=%llu len=%llu flags=0x%llx doesn't match block group start=%llu len=%llu flags=0x%llx",

- em->start, em->len,

- em->map_lookup->type & BTRFS_BLOCK_GROUP_TYPE_MASK,

- bg->key.objectid, bg->key.offset,

- bg->flags & BTRFS_BLOCK_GROUP_TYPE_MASK);

- ret = -EUCLEAN;

- free_extent_map(em);

- btrfs_put_block_group(bg);

- break;

- }

- start = em->start + em->len;

- free_extent_map(em);

- btrfs_put_block_group(bg);

- }

- return ret;

-}

-

-int btrfs_read_block_groups(struct btrfs_fs_info *info)

-{

- struct btrfs_path *path;

- int ret;

- struct btrfs_block_group_cache *cache;

- struct btrfs_space_info *space_info;

- struct btrfs_key key;

- struct btrfs_key found_key;

- struct extent_buffer *leaf;

- int need_clear = 0;

- u64 cache_gen;

- u64 feature;

- int mixed;

-

- feature = btrfs_super_incompat_flags(info->super_copy);

- mixed = !!(feature & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS);

-

- key.objectid = 0;

- key.offset = 0;

- key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;

- path = btrfs_alloc_path();

- if (!path)

- return -ENOMEM;

- path->reada = READA_FORWARD;

-

- cache_gen = btrfs_super_cache_generation(info->super_copy);

- if (btrfs_test_opt(info, SPACE_CACHE) &&

- btrfs_super_generation(info->super_copy) != cache_gen)

- need_clear = 1;

- if (btrfs_test_opt(info, CLEAR_CACHE))

- need_clear = 1;

-

- while (1) {

- ret = find_first_block_group(info, path, &key);

- if (ret > 0)

- break;

- if (ret != 0)

- goto error;

-

- leaf = path->nodes[0];

- btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);

-

- cache = btrfs_create_block_group_cache(info, found_key.objectid,

- found_key.offset);

- if (!cache) {

- ret = -ENOMEM;

- goto error;

- }

-

- if (need_clear) {

- /*

- * When we mount with old space cache, we need to

- * set BTRFS_DC_CLEAR and set dirty flag.

- *

- * a) Setting 'BTRFS_DC_CLEAR' makes sure that we

- * truncate the old free space cache inode and

- * setup a new one.

- * b) Setting 'dirty flag' makes sure that we flush

- * the new space cache info onto disk.

- */

- if (btrfs_test_opt(info, SPACE_CACHE))

- cache->disk_cache_state = BTRFS_DC_CLEAR;

- }

-

- read_extent_buffer(leaf, &cache->item,

- btrfs_item_ptr_offset(leaf, path->slots[0]),

- sizeof(cache->item));

- cache->flags = btrfs_block_group_flags(&cache->item);

- if (!mixed &&

- ((cache->flags & BTRFS_BLOCK_GROUP_METADATA) &&

- (cache->flags & BTRFS_BLOCK_GROUP_DATA))) {

- btrfs_err(info,

-"bg %llu is a mixed block group but filesystem hasn't enabled mixed block groups",

- cache->key.objectid);

- ret = -EINVAL;

- goto error;

- }

-

- key.objectid = found_key.objectid + found_key.offset;

- btrfs_release_path(path);

-

- /*

- * We need to exclude the super stripes now so that the space

- * info has super bytes accounted for, otherwise we'll think

- * we have more space than we actually do.

- */

- ret = exclude_super_stripes(cache);

- if (ret) {

- /*

- * We may have excluded something, so call this just in

- * case.

- */

- free_excluded_extents(cache);

- btrfs_put_block_group(cache);

- goto error;

- }

-

- /*

- * check for two cases, either we are full, and therefore

- * don't need to bother with the caching work since we won't

- * find any space, or we are empty, and we can just add all

- * the space in and be done with it. This saves us _a_lot_ of

- * time, particularly in the full case.

- */

- if (found_key.offset == btrfs_block_group_used(&cache->item)) {

- cache->last_byte_to_unpin = (u64)-1;

- cache->cached = BTRFS_CACHE_FINISHED;

- free_excluded_extents(cache);

- } else if (btrfs_block_group_used(&cache->item) == 0) {

- cache->last_byte_to_unpin = (u64)-1;

- cache->cached = BTRFS_CACHE_FINISHED;

- add_new_free_space(cache, found_key.objectid,

- found_key.objectid +

- found_key.offset);

- free_excluded_extents(cache);

- }

-

- ret = btrfs_add_block_group_cache(info, cache);

- if (ret) {

- btrfs_remove_free_space_cache(cache);

- btrfs_put_block_group(cache);

- goto error;

- }

-

- trace_btrfs_add_block_group(info, cache, 0);

- btrfs_update_space_info(info, cache->flags, found_key.offset,

- btrfs_block_group_used(&cache->item),

- cache->bytes_super, &space_info);

-

- cache->space_info = space_info;

-

- link_block_group(cache);

-

- set_avail_alloc_bits(info, cache->flags);

- if (btrfs_chunk_readonly(info, cache->key.objectid)) {

- inc_block_group_ro(cache, 1);

- } else if (btrfs_block_group_used(&cache->item) == 0) {

- ASSERT(list_empty(&cache->bg_list));

- btrfs_mark_bg_unused(cache);

- }

- }

-

- list_for_each_entry_rcu(space_info, &info->space_info, list) {

- if (!(get_alloc_profile(info, space_info->flags) &

- (BTRFS_BLOCK_GROUP_RAID10 |

- BTRFS_BLOCK_GROUP_RAID1_MASK |

- BTRFS_BLOCK_GROUP_RAID56_MASK |

- BTRFS_BLOCK_GROUP_DUP)))

- continue;

- /*

- * avoid allocating from un-mirrored block group if there are

- * mirrored block groups.

- */

- list_for_each_entry(cache,

- &space_info->block_groups[BTRFS_RAID_RAID0],

- list)

- inc_block_group_ro(cache, 1);

- list_for_each_entry(cache,

- &space_info->block_groups[BTRFS_RAID_SINGLE],

- list)

- inc_block_group_ro(cache, 1);

- }

-

- btrfs_init_global_block_rsv(info);

- ret = check_chunk_block_group_mappings(info);

-error:

- btrfs_free_path(path);

- return ret;

-}

-

-void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans)

-{

- struct btrfs_fs_info *fs_info = trans->fs_info;

- struct btrfs_block_group_cache *block_group;

- struct btrfs_root *extent_root = fs_info->extent_root;

- struct btrfs_block_group_item item;

- struct btrfs_key key;

- int ret = 0;

-

- if (!trans->can_flush_pending_bgs)

- return;

-

- while (!list_empty(&trans->new_bgs)) {

- block_group = list_first_entry(&trans->new_bgs,

- struct btrfs_block_group_cache,

- bg_list);

- if (ret)

- goto next;

-

- spin_lock(&block_group->lock);

- memcpy(&item, &block_group->item, sizeof(item));

- memcpy(&key, &block_group->key, sizeof(key));

- spin_unlock(&block_group->lock);

-

- ret = btrfs_insert_item(trans, extent_root, &key, &item,

- sizeof(item));

- if (ret)

- btrfs_abort_transaction(trans, ret);

- ret = btrfs_finish_chunk_alloc(trans, key.objectid, key.offset);

- if (ret)

- btrfs_abort_transaction(trans, ret);

- add_block_group_free_space(trans, block_group);

- /* already aborted the transaction if it failed. */

-next:

- btrfs_delayed_refs_rsv_release(fs_info, 1);

- list_del_init(&block_group->bg_list);

- }

- btrfs_trans_release_chunk_metadata(trans);

-}

-

-int btrfs_make_block_group(struct btrfs_trans_handle *trans, u64 bytes_used,

- u64 type, u64 chunk_offset, u64 size)

-{

- struct btrfs_fs_info *fs_info = trans->fs_info;

- struct btrfs_block_group_cache *cache;

- int ret;

-

- btrfs_set_log_full_commit(trans);

-

- cache = btrfs_create_block_group_cache(fs_info, chunk_offset, size);

- if (!cache)

- return -ENOMEM;

-

- btrfs_set_block_group_used(&cache->item, bytes_used);

- btrfs_set_block_group_chunk_objectid(&cache->item,

- BTRFS_FIRST_CHUNK_TREE_OBJECTID);

- btrfs_set_block_group_flags(&cache->item, type);

-

- cache->flags = type;

- cache->last_byte_to_unpin = (u64)-1;

- cache->cached = BTRFS_CACHE_FINISHED;

- cache->needs_free_space = 1;

- ret = exclude_super_stripes(cache);

- if (ret) {

- /*

- * We may have excluded something, so call this just in

- * case.

- */

- free_excluded_extents(cache);

- btrfs_put_block_group(cache);

- return ret;

- }

-

- add_new_free_space(cache, chunk_offset, chunk_offset + size);

-

- free_excluded_extents(cache);

-

-#ifdef CONFIG_BTRFS_DEBUG

- if (btrfs_should_fragment_free_space(cache)) {

- u64 new_bytes_used = size - bytes_used;

-

- bytes_used += new_bytes_used >> 1;

- fragment_free_space(cache);

- }

-#endif

- /*

- * Ensure the corresponding space_info object is created and

- * assigned to our block group. We want our bg to be added to the rbtree

- * with its ->space_info set.

- */

- cache->space_info = btrfs_find_space_info(fs_info, cache->flags);

- ASSERT(cache->space_info);

-

- ret = btrfs_add_block_group_cache(fs_info, cache);

- if (ret) {

- btrfs_remove_free_space_cache(cache);

- btrfs_put_block_group(cache);

- return ret;

- }

-

- /*

- * Now that our block group has its ->space_info set and is inserted in

- * the rbtree, update the space info's counters.

- */

- trace_btrfs_add_block_group(fs_info, cache, 1);

- btrfs_update_space_info(fs_info, cache->flags, size, bytes_used,

- cache->bytes_super, &cache->space_info);

- btrfs_update_global_block_rsv(fs_info);

-

- link_block_group(cache);

-

- list_add_tail(&cache->bg_list, &trans->new_bgs);

- trans->delayed_ref_updates++;

- btrfs_update_delayed_refs_rsv(trans);

-

- set_avail_alloc_bits(fs_info, type);

- return 0;

-}

-

-static void clear_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)

-{

- u64 extra_flags = chunk_to_extended(flags) &

- BTRFS_EXTENDED_PROFILE_MASK;

-

- write_seqlock(&fs_info->profiles_lock);

- if (flags & BTRFS_BLOCK_GROUP_DATA)

- fs_info->avail_data_alloc_bits &= ~extra_flags;

- if (flags & BTRFS_BLOCK_GROUP_METADATA)

- fs_info->avail_metadata_alloc_bits &= ~extra_flags;

- if (flags & BTRFS_BLOCK_GROUP_SYSTEM)

- fs_info->avail_system_alloc_bits &= ~extra_flags;

- write_sequnlock(&fs_info->profiles_lock);

-}

-

-/*

- * Clear incompat bits for the following feature(s):

- *

- * - RAID56 - in case there's neither RAID5 nor RAID6 profile block group

- * in the whole filesystem

- */

-static void clear_incompat_bg_bits(struct btrfs_fs_info *fs_info, u64 flags)

-{

- if (flags & BTRFS_BLOCK_GROUP_RAID56_MASK) {

- struct list_head *head = &fs_info->space_info;

- struct btrfs_space_info *sinfo;

-

- list_for_each_entry_rcu(sinfo, head, list) {

- bool found = false;

-

- down_read(&sinfo->groups_sem);

- if (!list_empty(&sinfo->block_groups[BTRFS_RAID_RAID5]))

- found = true;

- if (!list_empty(&sinfo->block_groups[BTRFS_RAID_RAID6]))

- found = true;

- up_read(&sinfo->groups_sem);

-

- if (found)

- return;

- }

- btrfs_clear_fs_incompat(fs_info, RAID56);

- }

-}

-

-int btrfs_remove_block_group(struct btrfs_trans_handle *trans,

- u64 group_start, struct extent_map *em)

-{

- struct btrfs_fs_info *fs_info = trans->fs_info;

- struct btrfs_root *root = fs_info->extent_root;

- struct btrfs_path *path;

- struct btrfs_block_group_cache *block_group;

- struct btrfs_free_cluster *cluster;

- struct btrfs_root *tree_root = fs_info->tree_root;

- struct btrfs_key key;

- struct inode *inode;

- struct kobject *kobj = NULL;

- int ret;

- int index;

- int factor;

- struct btrfs_caching_control *caching_ctl = NULL;

- bool remove_em;

- bool remove_rsv = false;

-

- block_group = btrfs_lookup_block_group(fs_info, group_start);

- BUG_ON(!block_group);

- BUG_ON(!block_group->ro);

-

- trace_btrfs_remove_block_group(block_group);

- /*

- * Free the reserved super bytes from this block group before

- * remove it.

- */

- free_excluded_extents(block_group);

- btrfs_free_ref_tree_range(fs_info, block_group->key.objectid,

- block_group->key.offset);

-

- memcpy(&key, &block_group->key, sizeof(key));

- index = btrfs_bg_flags_to_raid_index(block_group->flags);

- factor = btrfs_bg_type_to_factor(block_group->flags);

-

- /* make sure this block group isn't part of an allocation cluster */

- cluster = &fs_info->data_alloc_cluster;

- spin_lock(&cluster->refill_lock);

- btrfs_return_cluster_to_free_space(block_group, cluster);

- spin_unlock(&cluster->refill_lock);

-

- /*

- * make sure this block group isn't part of a metadata

- * allocation cluster

- */

- cluster = &fs_info->meta_alloc_cluster;

- spin_lock(&cluster->refill_lock);

- btrfs_return_cluster_to_free_space(block_group, cluster);

- spin_unlock(&cluster->refill_lock);

-

- path = btrfs_alloc_path();

- if (!path) {

- ret = -ENOMEM;

- goto out;

- }

-

- /*

- * get the inode first so any iput calls done for the io_list

- * aren't the final iput (no unlinks allowed now)

- */

- inode = lookup_free_space_inode(block_group, path);

-

- mutex_lock(&trans->transaction->cache_write_mutex);

- /*

- * Make sure our free space cache IO is done before removing the

- * free space inode

- */

- spin_lock(&trans->transaction->dirty_bgs_lock);

- if (!list_empty(&block_group->io_list)) {

- list_del_init(&block_group->io_list);

-

- WARN_ON(!IS_ERR(inode) && inode != block_group->io_ctl.inode);

-

- spin_unlock(&trans->transaction->dirty_bgs_lock);

- btrfs_wait_cache_io(trans, block_group, path);

- btrfs_put_block_group(block_group);

- spin_lock(&trans->transaction->dirty_bgs_lock);

- }

-

- if (!list_empty(&block_group->dirty_list)) {

- list_del_init(&block_group->dirty_list);

- remove_rsv = true;

- btrfs_put_block_group(block_group);

- }

- spin_unlock(&trans->transaction->dirty_bgs_lock);

- mutex_unlock(&trans->transaction->cache_write_mutex);

-

- if (!IS_ERR(inode)) {

- ret = btrfs_orphan_add(trans, BTRFS_I(inode));

- if (ret) {

- btrfs_add_delayed_iput(inode);

- goto out;

- }

- clear_nlink(inode);

- /* One for the block groups ref */

- spin_lock(&block_group->lock);

- if (block_group->iref) {

- block_group->iref = 0;

- block_group->inode = NULL;

- spin_unlock(&block_group->lock);

- iput(inode);

- } else {

- spin_unlock(&block_group->lock);

- }

- /* One for our lookup ref */

- btrfs_add_delayed_iput(inode);

- }

-

- key.objectid = BTRFS_FREE_SPACE_OBJECTID;

- key.offset = block_group->key.objectid;

- key.type = 0;

-

- ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1);

- if (ret < 0)

- goto out;

- if (ret > 0)

- btrfs_release_path(path);

- if (ret == 0) {

- ret = btrfs_del_item(trans, tree_root, path);

- if (ret)

- goto out;

- btrfs_release_path(path);

- }

-

- spin_lock(&fs_info->block_group_cache_lock);

- rb_erase(&block_group->cache_node,

- &fs_info->block_group_cache_tree);

- RB_CLEAR_NODE(&block_group->cache_node);

-

- if (fs_info->first_logical_byte == block_group->key.objectid)

- fs_info->first_logical_byte = (u64)-1;

- spin_unlock(&fs_info->block_group_cache_lock);

-

- down_write(&block_group->space_info->groups_sem);

- /*

- * we must use list_del_init so people can check to see if they

- * are still on the list after taking the semaphore

- */

- list_del_init(&block_group->list);

- if (list_empty(&block_group->space_info->block_groups[index])) {

- kobj = block_group->space_info->block_group_kobjs[index];

- block_group->space_info->block_group_kobjs[index] = NULL;

- clear_avail_alloc_bits(fs_info, block_group->flags);

- }

- up_write(&block_group->space_info->groups_sem);

- clear_incompat_bg_bits(fs_info, block_group->flags);

- if (kobj) {

- kobject_del(kobj);

- kobject_put(kobj);

- }

-

- if (block_group->has_caching_ctl)

- caching_ctl = get_caching_control(block_group);

- if (block_group->cached == BTRFS_CACHE_STARTED)

- wait_block_group_cache_done(block_group);

- if (block_group->has_caching_ctl) {

- down_write(&fs_info->commit_root_sem);

- if (!caching_ctl) {

- struct btrfs_caching_control *ctl;

-

- list_for_each_entry(ctl,

- &fs_info->caching_block_groups, list)

- if (ctl->block_group == block_group) {

- caching_ctl = ctl;

- refcount_inc(&caching_ctl->count);

- break;

- }

- }

- if (caching_ctl)

- list_del_init(&caching_ctl->list);

- up_write(&fs_info->commit_root_sem);

- if (caching_ctl) {

- /* Once for the caching bgs list and once for us. */

- put_caching_control(caching_ctl);

- put_caching_control(caching_ctl);

- }

- }

-

- spin_lock(&trans->transaction->dirty_bgs_lock);

- WARN_ON(!list_empty(&block_group->dirty_list));

- WARN_ON(!list_empty(&block_group->io_list));

- spin_unlock(&trans->transaction->dirty_bgs_lock);

-

- btrfs_remove_free_space_cache(block_group);

-

- spin_lock(&block_group->space_info->lock);

- list_del_init(&block_group->ro_list);

-

- if (btrfs_test_opt(fs_info, ENOSPC_DEBUG)) {

- WARN_ON(block_group->space_info->total_bytes

- < block_group->key.offset);

- WARN_ON(block_group->space_info->bytes_readonly

- < block_group->key.offset);

- WARN_ON(block_group->space_info->disk_total

- < block_group->key.offset * factor);

- }

- block_group->space_info->total_bytes -= block_group->key.offset;

- block_group->space_info->bytes_readonly -= block_group->key.offset;

- block_group->space_info->disk_total -= block_group->key.offset * factor;

-

- spin_unlock(&block_group->space_info->lock);

-

- memcpy(&key, &block_group->key, sizeof(key));

-

- mutex_lock(&fs_info->chunk_mutex);

- spin_lock(&block_group->lock);

- block_group->removed = 1;

- /*

- * At this point trimming can't start on this block group, because we

- * removed the block group from the tree fs_info->block_group_cache_tree

- * so no one can't find it anymore and even if someone already got this

- * block group before we removed it from the rbtree, they have already

- * incremented block_group->trimming - if they didn't, they won't find

- * any free space entries because we already removed them all when we

- * called btrfs_remove_free_space_cache().

- *

- * And we must not remove the extent map from the fs_info->mapping_tree

- * to prevent the same logical address range and physical device space

- * ranges from being reused for a new block group. This is because our

- * fs trim operation (btrfs_trim_fs() / btrfs_ioctl_fitrim()) is

- * completely transactionless, so while it is trimming a range the

- * currently running transaction might finish and a new one start,

- * allowing for new block groups to be created that can reuse the same

- * physical device locations unless we take this special care.

- *

- * There may also be an implicit trim operation if the file system

- * is mounted with -odiscard. The same protections must remain

- * in place until the extents have been discarded completely when

- * the transaction commit has completed.

- */

- remove_em = (atomic_read(&block_group->trimming) == 0);

- spin_unlock(&block_group->lock);

-

- mutex_unlock(&fs_info->chunk_mutex);

-

- ret = remove_block_group_free_space(trans, block_group);

- if (ret)

- goto out;

-

- btrfs_put_block_group(block_group);

- btrfs_put_block_group(block_group);

-

- ret = btrfs_search_slot(trans, root, &key, path, -1, 1);

- if (ret > 0)

- ret = -EIO;

- if (ret < 0)

- goto out;

-

- ret = btrfs_del_item(trans, root, path);

- if (ret)

- goto out;

-

- if (remove_em) {

- struct extent_map_tree *em_tree;

-

- em_tree = &fs_info->mapping_tree;

- write_lock(&em_tree->lock);

- remove_extent_mapping(em_tree, em);

- write_unlock(&em_tree->lock);

- /* once for the tree */

- free_extent_map(em);

- }

-out:

- if (remove_rsv)

- btrfs_delayed_refs_rsv_release(fs_info, 1);

- btrfs_free_path(path);

- return ret;

-}

-

-struct btrfs_trans_handle *

-btrfs_start_trans_remove_block_group(struct btrfs_fs_info *fs_info,

- const u64 chunk_offset)

-{

- struct extent_map_tree *em_tree = &fs_info->mapping_tree;

- struct extent_map *em;

- struct map_lookup *map;

- unsigned int num_items;

-

- read_lock(&em_tree->lock);

- em = lookup_extent_mapping(em_tree, chunk_offset, 1);

- read_unlock(&em_tree->lock);

- ASSERT(em && em->start == chunk_offset);

-

- /*

- * We need to reserve 3 + N units from the metadata space info in order

- * to remove a block group (done at btrfs_remove_chunk() and at

- * btrfs_remove_block_group()), which are used for:

- *

- * 1 unit for adding the free space inode's orphan (located in the tree

- * of tree roots).

- * 1 unit for deleting the block group item (located in the extent

- * tree).

- * 1 unit for deleting the free space item (located in tree of tree

- * roots).

- * N units for deleting N device extent items corresponding to each

- * stripe (located in the device tree).

- *

- * In order to remove a block group we also need to reserve units in the

- * system space info in order to update the chunk tree (update one or

- * more device items and remove one chunk item), but this is done at

- * btrfs_remove_chunk() through a call to check_system_chunk().

- */

- map = em->map_lookup;

- num_items = 3 + map->num_stripes;

- free_extent_map(em);

-

- return btrfs_start_transaction_fallback_global_rsv(fs_info->extent_root,

- num_items, 1);

-}

-

-/*

- * Process the unused_bgs list and remove any that don't have any allocated

- * space inside of them.

- */

-void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)

-{

- struct btrfs_block_group_cache *block_group;

- struct btrfs_space_info *space_info;

- struct btrfs_trans_handle *trans;

- int ret = 0;

-

- if (!test_bit(BTRFS_FS_OPEN, &fs_info->flags))

- return;

-

- spin_lock(&fs_info->unused_bgs_lock);

- while (!list_empty(&fs_info->unused_bgs)) {

- u64 start, end;

- int trimming;

-

- block_group = list_first_entry(&fs_info->unused_bgs,

- struct btrfs_block_group_cache,

- bg_list);

- list_del_init(&block_group->bg_list);

-

- space_info = block_group->space_info;

-

- if (ret || btrfs_mixed_space_info(space_info)) {

- btrfs_put_block_group(block_group);

- continue;

- }

- spin_unlock(&fs_info->unused_bgs_lock);

-

- mutex_lock(&fs_info->delete_unused_bgs_mutex);

-

- /* Don't want to race with allocators so take the groups_sem */

- down_write(&space_info->groups_sem);

- spin_lock(&block_group->lock);

- if (block_group->reserved || block_group->pinned ||

- btrfs_block_group_used(&block_group->item) ||

- block_group->ro ||

- list_is_singular(&block_group->list)) {

- /*

- * We want to bail if we made new allocations or have

- * outstanding allocations in this block group. We do

- * the ro check in case balance is currently acting on

- * this block group.

- */

- trace_btrfs_skip_unused_block_group(block_group);

- spin_unlock(&block_group->lock);

- up_write(&space_info->groups_sem);

- goto next;

- }

- spin_unlock(&block_group->lock);

-

- /* We don't want to force the issue, only flip if it's ok. */

- ret = inc_block_group_ro(block_group, 0);

- up_write(&space_info->groups_sem);

- if (ret < 0) {

- ret = 0;

- goto next;

- }

-

- /*

- * Want to do this before we do anything else so we can recover

- * properly if we fail to join the transaction.

- */

- trans = btrfs_start_trans_remove_block_group(fs_info,

- block_group->key.objectid);

- if (IS_ERR(trans)) {

- btrfs_dec_block_group_ro(block_group);

- ret = PTR_ERR(trans);

- goto next;

- }

-

- /*

- * We could have pending pinned extents for this block group,

- * just delete them, we don't care about them anymore.

- */

- start = block_group->key.objectid;

- end = start + block_group->key.offset - 1;

- /*

- * Hold the unused_bg_unpin_mutex lock to avoid racing with

- * btrfs_finish_extent_commit(). If we are at transaction N,

- * another task might be running finish_extent_commit() for the

- * previous transaction N - 1, and have seen a range belonging

- * to the block group in freed_extents[] before we were able to

- * clear the whole block group range from freed_extents[]. This

- * means that task can lookup for the block group after we

- * unpinned it from freed_extents[] and removed it, leading to

- * a BUG_ON() at btrfs_unpin_extent_range().

- */

- mutex_lock(&fs_info->unused_bg_unpin_mutex);

- ret = clear_extent_bits(&fs_info->freed_extents[0], start, end,

- EXTENT_DIRTY);

- if (ret) {

- mutex_unlock(&fs_info->unused_bg_unpin_mutex);

- btrfs_dec_block_group_ro(block_group);

- goto end_trans;

- }

- ret = clear_extent_bits(&fs_info->freed_extents[1], start, end,

- EXTENT_DIRTY);

- if (ret) {

- mutex_unlock(&fs_info->unused_bg_unpin_mutex);

- btrfs_dec_block_group_ro(block_group);

- goto end_trans;

- }

- mutex_unlock(&fs_info->unused_bg_unpin_mutex);

-

- /* Reset pinned so btrfs_put_block_group doesn't complain */

- spin_lock(&space_info->lock);

- spin_lock(&block_group->lock);

-

- btrfs_space_info_update_bytes_pinned(fs_info, space_info,

- -block_group->pinned);

- space_info->bytes_readonly += block_group->pinned;

- percpu_counter_add_batch(&space_info->total_bytes_pinned,

- -block_group->pinned,

- BTRFS_TOTAL_BYTES_PINNED_BATCH);

- block_group->pinned = 0;

-

- spin_unlock(&block_group->lock);

- spin_unlock(&space_info->lock);

-

- /* DISCARD can flip during remount */

- trimming = btrfs_test_opt(fs_info, DISCARD);

-

- /* Implicit trim during transaction commit. */

- if (trimming)

- btrfs_get_block_group_trimming(block_group);

-

- /*

- * Btrfs_remove_chunk will abort the transaction if things go

- * horribly wrong.

- */

- ret = btrfs_remove_chunk(trans, block_group->key.objectid);

-

- if (ret) {

- if (trimming)

- btrfs_put_block_group_trimming(block_group);

- goto end_trans;

- }

-

- /*

- * If we're not mounted with -odiscard, we can just forget

- * about this block group. Otherwise we'll need to wait

- * until transaction commit to do the actual discard.

- */

- if (trimming) {

- spin_lock(&fs_info->unused_bgs_lock);

- /*

- * A concurrent scrub might have added us to the list

- * fs_info->unused_bgs, so use a list_move operation

- * to add the block group to the deleted_bgs list.

- */

- list_move(&block_group->bg_list,

- &trans->transaction->deleted_bgs);

- spin_unlock(&fs_info->unused_bgs_lock);

- btrfs_get_block_group(block_group);

- }

-end_trans:

- btrfs_end_transaction(trans);

-next:

- mutex_unlock(&fs_info->delete_unused_bgs_mutex);

- btrfs_put_block_group(block_group);

- spin_lock(&fs_info->unused_bgs_lock);

- }

- spin_unlock(&fs_info->unused_bgs_lock);

-}

-

int btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info,

u64 start, u64 end)

{

@@ -8985,7 +5646,7 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)

return -EINVAL;

cache = btrfs_lookup_first_block_group(fs_info, range->start);

- for (; cache; cache = next_block_group(cache)) {

+ for (; cache; cache = btrfs_next_block_group(cache)) {

if (cache->key.objectid >= range_end) {

btrfs_put_block_group(cache);

break;

@@ -8995,14 +5656,14 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)

end = min(range_end, cache->key.objectid + cache->key.offset);

if (end - start >= range->minlen) {

- if (!block_group_cache_done(cache)) {

- ret = cache_block_group(cache, 0);

+ if (!btrfs_block_group_cache_done(cache)) {

+ ret = btrfs_cache_block_group(cache, 0);

if (ret) {

bg_failed++;

bg_ret = ret;

continue;

}

- ret = wait_block_group_cache_done(cache);

+ ret = btrfs_wait_block_group_cache_done(cache);

if (ret) {

bg_failed++;

bg_ret = ret;

@@ -9095,16 +5756,3 @@ void btrfs_wait_for_snapshot_creation(struct btrfs_root *root)

!atomic_read(&root->will_be_snapshotted));

}

}

-

-void btrfs_mark_bg_unused(struct btrfs_block_group_cache *bg)

-{

- struct btrfs_fs_info *fs_info = bg->fs_info;

-

- spin_lock(&fs_info->unused_bgs_lock);

- if (list_empty(&bg->bg_list)) {

- btrfs_get_block_group(bg);

- trace_btrfs_add_unused_block_group(bg);

- list_add_tail(&bg->bg_list, &fs_info->unused_bgs);

- }

- spin_unlock(&fs_info->unused_bgs_lock);

-}

@@ -1938,9 +1938,9 @@ out:

}

void extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,

- u64 delalloc_end, struct page *locked_page,

- unsigned clear_bits,

- unsigned long page_ops)

+ struct page *locked_page,

+ unsigned clear_bits,

+ unsigned long page_ops)

{

clear_extent_bit(&BTRFS_I(inode)->io_tree, start, end, clear_bits, 1, 0,

NULL);

@@ -4339,10 +4339,8 @@ int extent_invalidatepage(struct extent_io_tree *tree,

lock_extent_bits(tree, start, end, &cached_state);

wait_on_page_writeback(page);

- clear_extent_bit(tree, start, end,

- EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC |

- EXTENT_DO_ACCOUNTING,

- 1, 1, &cached_state);

+ clear_extent_bit(tree, start, end, EXTENT_LOCKED | EXTENT_DELALLOC |

+ EXTENT_DO_ACCOUNTING, 1, 1, &cached_state);

return 0;

}

@@ -494,9 +494,9 @@ int map_private_extent_buffer(const struct extent_buffer *eb,

void extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end);

void extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end);

void extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,

- u64 delalloc_end, struct page *locked_page,

- unsigned bits_to_clear,

- unsigned long page_ops);

+ struct page *locked_page,

+ unsigned bits_to_clear,

+ unsigned long page_ops);

struct bio *btrfs_bio_alloc(u64 first_byte);

struct bio *btrfs_io_bio_alloc(unsigned int nr_iovecs);

struct bio *btrfs_bio_clone(struct bio *bio);

@@ -384,6 +384,8 @@ int add_extent_mapping(struct extent_map_tree *tree,

{

int ret = 0;

+ lockdep_assert_held_write(&tree->lock);

+

ret = tree_insert(&tree->map, em);

if (ret)

goto out;

diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 58a18ed11546f..8fe4eb7e50452 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c

@@ -537,8 +537,8 @@ int btrfs_dirty_pages(struct inode *inode, struct page **pages,

* we can set things up properly

*/

clear_extent_bit(&BTRFS_I(inode)->io_tree, start_pos, end_of_last_block,

- EXTENT_DIRTY | EXTENT_DELALLOC |

- EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, 0, 0, cached);

+ EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG,

+ 0, 0, cached);

if (!btrfs_is_free_space_inode(BTRFS_I(inode))) {

if (start_pos >= isize &&

@@ -559,7 +559,7 @@ int btrfs_dirty_pages(struct inode *inode, struct page **pages,

}

err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block,

- extra_bits, cached, 0);

+ extra_bits, cached);

if (err)

return err;

@@ -1882,10 +1882,10 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,

u64 start_pos;

u64 end_pos;

ssize_t num_written = 0;

- bool sync = (file->f_flags & O_DSYNC) || IS_SYNC(file->f_mapping->host);

+ const bool sync = iocb->ki_flags & IOCB_DSYNC;

ssize_t err;

loff_t pos;

- size_t count = iov_iter_count(from);

+ size_t count;

loff_t oldsize;

int clean_page = 0;

@@ -1906,6 +1906,7 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,

}

pos = iocb->ki_pos;

+ count = iov_iter_count(from);

if (iocb->ki_flags & IOCB_NOWAIT) {

/*

* We will allocate space in case nodatacow is not set,

@@ -2439,27 +2440,286 @@ static int btrfs_punch_hole_lock_range(struct inode *inode,

return 0;

}

+static int btrfs_insert_clone_extent(struct btrfs_trans_handle *trans,

+ struct inode *inode,

+ struct btrfs_path *path,

+ struct btrfs_clone_extent_info *clone_info,

+ const u64 clone_len)

+{

+ struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);

+ struct btrfs_root *root = BTRFS_I(inode)->root;

+ struct btrfs_file_extent_item *extent;

+ struct extent_buffer *leaf;

+ struct btrfs_key key;

+ int slot;

+ struct btrfs_ref ref = { 0 };

+ u64 ref_offset;

+ int ret;

+

+ if (clone_len == 0)

+ return 0;

+

+ if (clone_info->disk_offset == 0 &&

+ btrfs_fs_incompat(fs_info, NO_HOLES))

+ return 0;

+

+ key.objectid = btrfs_ino(BTRFS_I(inode));

+ key.type = BTRFS_EXTENT_DATA_KEY;

+ key.offset = clone_info->file_offset;

+ ret = btrfs_insert_empty_item(trans, root, path, &key,

+ clone_info->item_size);

+ if (ret)

+ return ret;

+ leaf = path->nodes[0];

+ slot = path->slots[0];

+ write_extent_buffer(leaf, clone_info->extent_buf,

+ btrfs_item_ptr_offset(leaf, slot),

+ clone_info->item_size);

+ extent = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);

+ btrfs_set_file_extent_offset(leaf, extent, clone_info->data_offset);

+ btrfs_set_file_extent_num_bytes(leaf, extent, clone_len);

+ btrfs_mark_buffer_dirty(leaf);

+ btrfs_release_path(path);

+

+ /* If it's a hole, nothing more needs to be done. */

+ if (clone_info->disk_offset == 0)

+ return 0;

+

+ inode_add_bytes(inode, clone_len);

+ btrfs_init_generic_ref(&ref, BTRFS_ADD_DELAYED_REF,

+ clone_info->disk_offset,

+ clone_info->disk_len, 0);

+ ref_offset = clone_info->file_offset - clone_info->data_offset;

+ btrfs_init_data_ref(&ref, root->root_key.objectid,

+ btrfs_ino(BTRFS_I(inode)), ref_offset);

+ ret = btrfs_inc_extent_ref(trans, &ref);

+

+ return ret;

+}

+

+/*

+ * The respective range must have been previously locked, as well as the inode.

+ * The end offset is inclusive (last byte of the range).

+ * @clone_info is NULL for fallocate's hole punching and non-NULL for extent

+ * cloning.

+ * When cloning, we don't want to end up in a state where we dropped extents

+ * without inserting a new one, so we must abort the transaction to avoid a

+ * corruption.

+ */

+int btrfs_punch_hole_range(struct inode *inode, struct btrfs_path *path,

+ const u64 start, const u64 end,

+ struct btrfs_clone_extent_info *clone_info,

+ struct btrfs_trans_handle **trans_out)

+{

+ struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);

+ u64 min_size = btrfs_calc_insert_metadata_size(fs_info, 1);

+ u64 ino_size = round_up(inode->i_size, fs_info->sectorsize);

+ struct btrfs_root *root = BTRFS_I(inode)->root;

+ struct btrfs_trans_handle *trans = NULL;

+ struct btrfs_block_rsv *rsv;

+ unsigned int rsv_count;

+ u64 cur_offset;

+ u64 drop_end;

+ u64 len = end - start;

+ int ret = 0;

+

+ if (end <= start)

+ return -EINVAL;

+

+ rsv = btrfs_alloc_block_rsv(fs_info, BTRFS_BLOCK_RSV_TEMP);

+ if (!rsv) {

+ ret = -ENOMEM;

+ goto out;

+ }

+ rsv->size = btrfs_calc_insert_metadata_size(fs_info, 1);

+ rsv->failfast = 1;

+

+ /*

+ * 1 - update the inode

+ * 1 - removing the extents in the range

+ * 1 - adding the hole extent if no_holes isn't set or if we are cloning

+ * an extent

+ */

+ if (!btrfs_fs_incompat(fs_info, NO_HOLES) || clone_info)

+ rsv_count = 3;

+ else

+ rsv_count = 2;

+

+ trans = btrfs_start_transaction(root, rsv_count);

+ if (IS_ERR(trans)) {

+ ret = PTR_ERR(trans);

+ trans = NULL;

+ goto out_free;

+ }

+

+ ret = btrfs_block_rsv_migrate(&fs_info->trans_block_rsv, rsv,

+ min_size, false);

+ BUG_ON(ret);

+ trans->block_rsv = rsv;

+

+ cur_offset = start;

+ while (cur_offset < end) {

+ ret = __btrfs_drop_extents(trans, root, inode, path,

+ cur_offset, end + 1, &drop_end,

+ 1, 0, 0, NULL);

+ if (ret != -ENOSPC) {

+ /*

+ * When cloning we want to avoid transaction aborts when

+ * nothing was done and we are attempting to clone parts

+ * of inline extents, in such cases -EOPNOTSUPP is

+ * returned by __btrfs_drop_extents() without having

+ * changed anything in the file.

+ */

+ if (clone_info && ret && ret != -EOPNOTSUPP)

+ btrfs_abort_transaction(trans, ret);

+ break;

+ }

+

+ trans->block_rsv = &fs_info->trans_block_rsv;

+

+ if (!clone_info && cur_offset < drop_end &&

+ cur_offset < ino_size) {

+ ret = fill_holes(trans, BTRFS_I(inode), path,

+ cur_offset, drop_end);

+ if (ret) {

+ /*

+ * If we failed then we didn't insert our hole

+ * entries for the area we dropped, so now the

+ * fs is corrupted, so we must abort the

+ * transaction.

+ */

+ btrfs_abort_transaction(trans, ret);

+ break;

+ }

+ }

+

+ if (clone_info) {

+ u64 clone_len = drop_end - cur_offset;

+

+ ret = btrfs_insert_clone_extent(trans, inode, path,

+ clone_info, clone_len);

+ if (ret) {

+ btrfs_abort_transaction(trans, ret);

+ break;

+ }

+ clone_info->data_len -= clone_len;

+ clone_info->data_offset += clone_len;

+ clone_info->file_offset += clone_len;

+ }

+

+ cur_offset = drop_end;

+

+ ret = btrfs_update_inode(trans, root, inode);

+ if (ret)

+ break;

+

+ btrfs_end_transaction(trans);

+ btrfs_btree_balance_dirty(fs_info);

+

+ trans = btrfs_start_transaction(root, rsv_count);

+ if (IS_ERR(trans)) {

+ ret = PTR_ERR(trans);

+ trans = NULL;

+ break;

+ }

+

+ ret = btrfs_block_rsv_migrate(&fs_info->trans_block_rsv,

+ rsv, min_size, false);

+ BUG_ON(ret); /* shouldn't happen */

+ trans->block_rsv = rsv;

+

+ if (!clone_info) {

+ ret = find_first_non_hole(inode, &cur_offset, &len);

+ if (unlikely(ret < 0))

+ break;

+ if (ret && !len) {

+ ret = 0;

+ break;

+ }

+ }

+ }

+

+ /*

+ * If we were cloning, force the next fsync to be a full one since we

+ * we replaced (or just dropped in the case of cloning holes when

+ * NO_HOLES is enabled) extents and extent maps.

+ * This is for the sake of simplicity, and cloning into files larger

+ * than 16Mb would force the full fsync any way (when

+ * try_release_extent_mapping() is invoked during page cache truncation.

+ */

+ if (clone_info)

+ set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,

+ &BTRFS_I(inode)->runtime_flags);

+

+ if (ret)

+ goto out_trans;

+

+ trans->block_rsv = &fs_info->trans_block_rsv;

+ /*

+ * If we are using the NO_HOLES feature we might have had already an

+ * hole that overlaps a part of the region [lockstart, lockend] and

+ * ends at (or beyond) lockend. Since we have no file extent items to

+ * represent holes, drop_end can be less than lockend and so we must

+ * make sure we have an extent map representing the existing hole (the

+ * call to __btrfs_drop_extents() might have dropped the existing extent

+ * map representing the existing hole), otherwise the fast fsync path

+ * will not record the existence of the hole region

+ * [existing_hole_start, lockend].

+ */

+ if (drop_end <= end)

+ drop_end = end + 1;

+ /*

+ * Don't insert file hole extent item if it's for a range beyond eof

+ * (because it's useless) or if it represents a 0 bytes range (when

+ * cur_offset == drop_end).

+ */

+ if (!clone_info && cur_offset < ino_size && cur_offset < drop_end) {

+ ret = fill_holes(trans, BTRFS_I(inode), path,

+ cur_offset, drop_end);

+ if (ret) {

+ /* Same comment as above. */

+ btrfs_abort_transaction(trans, ret);

+ goto out_trans;

+ }

+ }

+ if (clone_info) {

+ ret = btrfs_insert_clone_extent(trans, inode, path, clone_info,

+ clone_info->data_len);

+ if (ret) {

+ btrfs_abort_transaction(trans, ret);

+ goto out_trans;

+ }

+ }

+

+out_trans:

+ if (!trans)

+ goto out_free;

+

+ trans->block_rsv = &fs_info->trans_block_rsv;

+ if (ret)

+ btrfs_end_transaction(trans);

+ else

+ *trans_out = trans;

+out_free:

+ btrfs_free_block_rsv(fs_info, rsv);

+out:

+ return ret;

+}

+

static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)

{

struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);

struct btrfs_root *root = BTRFS_I(inode)->root;

struct extent_state *cached_state = NULL;

struct btrfs_path *path;

- struct btrfs_block_rsv *rsv;

- struct btrfs_trans_handle *trans;

+ struct btrfs_trans_handle *trans = NULL;

u64 lockstart;

u64 lockend;

u64 tail_start;

u64 tail_len;

u64 orig_start = offset;

- u64 cur_offset;

- u64 min_size = btrfs_calc_trans_metadata_size(fs_info, 1);

- u64 drop_end;

int ret = 0;

- int err = 0;

- unsigned int rsv_count;

bool same_block;

- bool no_holes = btrfs_fs_incompat(fs_info, NO_HOLES);

u64 ino_size;

bool truncated_block = false;

bool updated_inode = false;

@@ -2566,145 +2826,24 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)

goto out;

}

- rsv = btrfs_alloc_block_rsv(fs_info, BTRFS_BLOCK_RSV_TEMP);

- if (!rsv) {

- ret = -ENOMEM;

- goto out_free;

- }

- rsv->size = btrfs_calc_trans_metadata_size(fs_info, 1);

- rsv->failfast = 1;

-

- /*

- * 1 - update the inode

- * 1 - removing the extents in the range

- * 1 - adding the hole extent if no_holes isn't set

- */

- rsv_count = no_holes ? 2 : 3;

- trans = btrfs_start_transaction(root, rsv_count);

- if (IS_ERR(trans)) {

- err = PTR_ERR(trans);

- goto out_free;

- }

-

- ret = btrfs_block_rsv_migrate(&fs_info->trans_block_rsv, rsv,

- min_size, false);

- BUG_ON(ret);

- trans->block_rsv = rsv;

-

- cur_offset = lockstart;

- len = lockend - cur_offset;

- while (cur_offset < lockend) {

- ret = __btrfs_drop_extents(trans, root, inode, path,

- cur_offset, lockend + 1,

- &drop_end, 1, 0, 0, NULL);

- if (ret != -ENOSPC)

- break;

-

- trans->block_rsv = &fs_info->trans_block_rsv;

-

- if (cur_offset < drop_end && cur_offset < ino_size) {

- ret = fill_holes(trans, BTRFS_I(inode), path,

- cur_offset, drop_end);

- if (ret) {

- /*

- * If we failed then we didn't insert our hole

- * entries for the area we dropped, so now the

- * fs is corrupted, so we must abort the

- * transaction.

- */

- btrfs_abort_transaction(trans, ret);

- err = ret;

- break;

- }

- }

-

- cur_offset = drop_end;

-

- ret = btrfs_update_inode(trans, root, inode);

- if (ret) {

- err = ret;

- break;

- }

-

- btrfs_end_transaction(trans);

- btrfs_btree_balance_dirty(fs_info);

-

- trans = btrfs_start_transaction(root, rsv_count);

- if (IS_ERR(trans)) {

- ret = PTR_ERR(trans);

- trans = NULL;

- break;

- }

-

- ret = btrfs_block_rsv_migrate(&fs_info->trans_block_rsv,

- rsv, min_size, false);

- BUG_ON(ret); /* shouldn't happen */

- trans->block_rsv = rsv;

-

- ret = find_first_non_hole(inode, &cur_offset, &len);

- if (unlikely(ret < 0))

- break;

- if (ret && !len) {

- ret = 0;

- break;

- }

- }

-

- if (ret) {

- err = ret;

- goto out_trans;

- }

-

- trans->block_rsv = &fs_info->trans_block_rsv;

- /*

- * If we are using the NO_HOLES feature we might have had already an

- * hole that overlaps a part of the region [lockstart, lockend] and

- * ends at (or beyond) lockend. Since we have no file extent items to

- * represent holes, drop_end can be less than lockend and so we must

- * make sure we have an extent map representing the existing hole (the

- * call to __btrfs_drop_extents() might have dropped the existing extent

- * map representing the existing hole), otherwise the fast fsync path

- * will not record the existence of the hole region

- * [existing_hole_start, lockend].

- */

- if (drop_end <= lockend)

- drop_end = lockend + 1;

- /*

- * Don't insert file hole extent item if it's for a range beyond eof

- * (because it's useless) or if it represents a 0 bytes range (when

- * cur_offset == drop_end).

- */

- if (cur_offset < ino_size && cur_offset < drop_end) {

- ret = fill_holes(trans, BTRFS_I(inode), path,

- cur_offset, drop_end);

- if (ret) {

- /* Same comment as above. */

- btrfs_abort_transaction(trans, ret);

- err = ret;

- goto out_trans;

- }

- }

-

-out_trans:

- if (!trans)

- goto out_free;

+ ret = btrfs_punch_hole_range(inode, path, lockstart, lockend, NULL,

+ &trans);

+ btrfs_free_path(path);

+ if (ret)

+ goto out;

+ ASSERT(trans != NULL);

inode_inc_iversion(inode);

inode->i_mtime = inode->i_ctime = current_time(inode);

-

- trans->block_rsv = &fs_info->trans_block_rsv;

ret = btrfs_update_inode(trans, root, inode);

updated_inode = true;

btrfs_end_transaction(trans);

btrfs_btree_balance_dirty(fs_info);

-out_free:

- btrfs_free_path(path);

- btrfs_free_block_rsv(fs_info, rsv);

out:

unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,

&cached_state);

out_only_mutex:

- if (!updated_inode && truncated_block && !ret && !err) {

+ if (!updated_inode && truncated_block && !ret) {

/*

* If we only end up zeroing part of a page, we still need to

* update the inode item, so that all the time fields are

@@ -2719,16 +2858,18 @@ out_only_mutex:

inode->i_ctime = now;

trans = btrfs_start_transaction(root, 1);

if (IS_ERR(trans)) {

- err = PTR_ERR(trans);

+ ret = PTR_ERR(trans);

} else {

- err = btrfs_update_inode(trans, root, inode);

- ret = btrfs_end_transaction(trans);

+ int ret2;

+

+ ret = btrfs_update_inode(trans, root, inode);

+ ret2 = btrfs_end_transaction(trans);

+ if (!ret)

+ ret = ret2;

}

}

inode_unlock(inode);

- if (ret && !err)

- err = ret;

- return err;

+ return ret;

}

/* Helper structure to record which range is already reserved */

@@ -20,6 +20,7 @@

#include "volumes.h"

#include "space-info.h"

#include "delalloc-space.h"

+#include "block-group.h"

#define BITS_PER_BITMAP (PAGE_SIZE * 8UL)

#define MAX_CACHE_BYTES_PER_GIG SZ_32K

@@ -210,8 +211,8 @@ int btrfs_check_trunc_cache_free_space(struct btrfs_fs_info *fs_info,

int ret;

/* 1 for slack space, 1 for updating the inode */

- needed_bytes = btrfs_calc_trunc_metadata_size(fs_info, 1) +

- btrfs_calc_trans_metadata_size(fs_info, 1);

+ needed_bytes = btrfs_calc_insert_metadata_size(fs_info, 1) +

+ btrfs_calc_metadata_size(fs_info, 1);

spin_lock(&rsv->lock);

if (rsv->reserved < needed_bytes)

@@ -764,7 +765,8 @@ static int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,

} else {

ASSERT(num_bitmaps);

num_bitmaps--;

- e->bitmap = kzalloc(PAGE_SIZE, GFP_NOFS);

+ e->bitmap = kmem_cache_zalloc(

+ btrfs_free_space_bitmap_cachep, GFP_NOFS);

if (!e->bitmap) {

kmem_cache_free(

btrfs_free_space_cachep, e);

@@ -1004,7 +1006,7 @@ update_cache_item(struct btrfs_trans_handle *trans,

ret = btrfs_search_slot(trans, root, &key, path, 0, 1);

if (ret < 0) {

clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1,

- EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, NULL);

+ EXTENT_DELALLOC, 0, 0, NULL);

goto fail;

}

leaf = path->nodes[0];

@@ -1016,9 +1018,8 @@ update_cache_item(struct btrfs_trans_handle *trans,

if (found_key.objectid != BTRFS_FREE_SPACE_OBJECTID ||

found_key.offset != offset) {

clear_extent_bit(&BTRFS_I(inode)->io_tree, 0,

- inode->i_size - 1,

- EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0,

- NULL);

+ inode->i_size - 1, EXTENT_DELALLOC, 0,

+ 0, NULL);

btrfs_release_path(path);

goto fail;

}

@@ -1114,7 +1115,7 @@ static int flush_dirty_cache(struct inode *inode)

ret = btrfs_wait_ordered_range(inode, 0, (u64)-1);

if (ret)

clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1,

- EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, NULL);

+ EXTENT_DELALLOC, 0, 0, NULL);

return ret;

}

@@ -1881,7 +1882,7 @@ static void free_bitmap(struct btrfs_free_space_ctl *ctl,

struct btrfs_free_space *bitmap_info)

{

unlink_free_space(ctl, bitmap_info);

- kfree(bitmap_info->bitmap);

+ kmem_cache_free(btrfs_free_space_bitmap_cachep, bitmap_info->bitmap);

kmem_cache_free(btrfs_free_space_cachep, bitmap_info);

ctl->total_bitmaps--;

ctl->op->recalc_thresholds(ctl);

@@ -2135,7 +2136,8 @@ new_bitmap:

}

/* allocate the bitmap */

- info->bitmap = kzalloc(PAGE_SIZE, GFP_NOFS);

+ info->bitmap = kmem_cache_zalloc(btrfs_free_space_bitmap_cachep,

+ GFP_NOFS);

spin_lock(&ctl->tree_lock);

if (!info->bitmap) {

ret = -ENOMEM;

@@ -2146,7 +2148,9 @@ new_bitmap:

out:

if (info) {

- kfree(info->bitmap);

+ if (info->bitmap)

+ kmem_cache_free(btrfs_free_space_bitmap_cachep,

+ info->bitmap);

kmem_cache_free(btrfs_free_space_cachep, info);

}

@@ -2376,6 +2380,14 @@ out:

return ret;

}

+int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,

+ u64 bytenr, u64 size)

+{

+ return __btrfs_add_free_space(block_group->fs_info,

+ block_group->free_space_ctl,

+ bytenr, size);

+}

+

int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,

u64 offset, u64 bytes)

{

@@ -2802,7 +2814,8 @@ out:

if (entry->bytes == 0) {

ctl->free_extents--;

if (entry->bitmap) {

- kfree(entry->bitmap);

+ kmem_cache_free(btrfs_free_space_bitmap_cachep,

+ entry->bitmap);

ctl->total_bitmaps--;

ctl->op->recalc_thresholds(ctl);

}

@@ -3606,7 +3619,7 @@ again:

}

if (!map) {

- map = kzalloc(PAGE_SIZE, GFP_NOFS);

+ map = kmem_cache_zalloc(btrfs_free_space_bitmap_cachep, GFP_NOFS);

if (!map) {

kmem_cache_free(btrfs_free_space_cachep, info);

return -ENOMEM;

@@ -3635,7 +3648,8 @@ again:

if (info)

kmem_cache_free(btrfs_free_space_cachep, info);

- kfree(map);

+ if (map)

+ kmem_cache_free(btrfs_free_space_bitmap_cachep, map);

return 0;

}

@@ -36,7 +36,19 @@ struct btrfs_free_space_op {

struct btrfs_free_space *info);

};

-struct btrfs_io_ctl;

+struct btrfs_io_ctl {

+ void *cur, *orig;

+ struct page *page;

+ struct page **pages;

+ struct btrfs_fs_info *fs_info;

+ struct inode *inode;

+ unsigned long size;

+ int index;

+ int num_pages;

+ int entries;

+ int bitmaps;

+ unsigned check_crcs:1;

+};

struct inode *lookup_free_space_inode(

struct btrfs_block_group_cache *block_group,

@@ -73,14 +85,8 @@ void btrfs_init_free_space_ctl(struct btrfs_block_group_cache *block_group);

int __btrfs_add_free_space(struct btrfs_fs_info *fs_info,

struct btrfs_free_space_ctl *ctl,

u64 bytenr, u64 size);

-static inline int

-btrfs_add_free_space(struct btrfs_block_group_cache *block_group,

- u64 bytenr, u64 size)

-{

- return __btrfs_add_free_space(block_group->fs_info,

- block_group->free_space_ctl,

- bytenr, size);

-}

+int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,

+ u64 bytenr, u64 size);

int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,

u64 bytenr, u64 size);

void __btrfs_remove_free_space_cache(struct btrfs_free_space_ctl *ctl);

@@ -10,6 +10,7 @@

#include "locking.h"

#include "free-space-tree.h"

#include "transaction.h"

+#include "block-group.h"

static int __add_block_group_free_space(struct btrfs_trans_handle *trans,

struct btrfs_block_group_cache *block_group,

@@ -6,6 +6,8 @@

#ifndef BTRFS_FREE_SPACE_TREE_H

#define BTRFS_FREE_SPACE_TREE_H

+struct btrfs_caching_control;

+

/*

* The default size for new free space bitmap items. The last bitmap in a block

* group may be truncated, and none of the free space tree code assumes that

@@ -8,9 +8,9 @@

#include "transaction.h"

#include "print-tree.h"

-int btrfs_find_name_in_backref(struct extent_buffer *leaf, int slot,

- const char *name,

- int name_len, struct btrfs_inode_ref **ref_ret)

+struct btrfs_inode_ref *btrfs_find_name_in_backref(struct extent_buffer *leaf,

+ int slot, const char *name,

+ int name_len)

{

struct btrfs_inode_ref *ref;

unsigned long ptr;

@@ -28,19 +28,15 @@ int btrfs_find_name_in_backref(struct extent_buffer *leaf, int slot,

cur_offset += len + sizeof(*ref);

if (len != name_len)

continue;

- if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) {

- if (ref_ret)

- *ref_ret = ref;

- return 1;

- }

+ if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)

+ return ref;

}

- return 0;

+ return NULL;

}

-int btrfs_find_name_in_ext_backref(struct extent_buffer *leaf, int slot,

- u64 ref_objectid,

- const char *name, int name_len,

- struct btrfs_inode_extref **extref_ret)

+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)

{

struct btrfs_inode_extref *extref;

unsigned long ptr;

@@ -65,15 +61,12 @@ int btrfs_find_name_in_ext_backref(struct extent_buffer *leaf, int slot,

if (ref_name_len == name_len &&

btrfs_inode_extref_parent(leaf, extref) == ref_objectid &&

- (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)) {

- if (extref_ret)

- *extref_ret = extref;

- return 1;

- }

+ (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0))

+ return extref;

cur_offset += ref_name_len + sizeof(*extref);

}

- return 0;

+ return NULL;

}

/* Returns NULL if no extref found */

@@ -87,7 +80,6 @@ btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans,

{

int ret;

struct btrfs_key key;

- struct btrfs_inode_extref *extref;

key.objectid = inode_objectid;

key.type = BTRFS_INODE_EXTREF_KEY;

@@ -98,11 +90,9 @@ btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans,

return ERR_PTR(ret);

if (ret > 0)

return NULL;

- if (!btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0],

- ref_objectid, name, name_len,

- &extref))

- return NULL;

- return extref;

+ return btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0],

+ ref_objectid, name, name_len);

+

}

static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,

@@ -142,9 +132,9 @@ static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,

* This should always succeed so error here will make the FS

* readonly.

*/

- if (!btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0],

- ref_objectid,

- name, name_len, &extref)) {

+ extref = btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0],

+ ref_objectid, name, name_len);

+ if (!extref) {

btrfs_handle_fs_error(root->fs_info, -ENOENT, NULL);

ret = -EROFS;

goto out;

@@ -213,8 +203,10 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,

} else if (ret < 0) {

goto out;

}

- if (!btrfs_find_name_in_backref(path->nodes[0], path->slots[0],

- name, name_len, &ref)) {

+

+ ref = btrfs_find_name_in_backref(path->nodes[0], path->slots[0], name,

+ name_len);

+ if (!ref) {

ret = -ENOENT;

search_ext_refs = 1;

goto out;

@@ -285,7 +277,7 @@ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,

if (btrfs_find_name_in_ext_backref(path->nodes[0],

path->slots[0],

ref_objectid,

- name, name_len, NULL))

+ name, name_len))

goto out;

btrfs_extend_item(path, ins_len);

@@ -341,9 +333,9 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,

ins_len);

if (ret == -EEXIST) {

u32 old_size;

-

- if (btrfs_find_name_in_backref(path->nodes[0], path->slots[0],

- name, name_len, &ref))

+ ref = btrfs_find_name_in_backref(path->nodes[0], path->slots[0],

+ name, name_len);

+ if (ref)

goto out;

old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]);

@@ -359,7 +351,7 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,

if (ret == -EOVERFLOW) {

if (btrfs_find_name_in_backref(path->nodes[0],

path->slots[0],

- name, name_len, &ref))

+ name, name_len))

ret = -EEXIST;

else

ret = -EMLINK;

@@ -13,6 +13,19 @@

#include "transaction.h"

#include "delalloc-space.h"

+static void fail_caching_thread(struct btrfs_root *root)

+{

+ struct btrfs_fs_info *fs_info = root->fs_info;

+

+ btrfs_warn(fs_info, "failed to start inode caching task");

+ btrfs_clear_pending_and_info(fs_info, INODE_MAP_CACHE,

+ "disabling inode map caching");

+ spin_lock(&root->ino_cache_lock);

+ root->ino_cache_state = BTRFS_CACHE_ERROR;

+ spin_unlock(&root->ino_cache_lock);

+ wake_up(&root->ino_cache_wait);

+}

+

static int caching_kthread(void *data)

{

struct btrfs_root *root = data;

@@ -29,8 +42,10 @@ static int caching_kthread(void *data)

return 0;

path = btrfs_alloc_path();

- if (!path)

+ if (!path) {

+ fail_caching_thread(root);

return -ENOMEM;

+ }

/* Since the commit root is read-only, we can safely skip locking. */

path->skip_locking = 1;

@@ -146,6 +161,7 @@ static void start_caching(struct btrfs_root *root)

spin_lock(&root->ino_cache_lock);

root->ino_cache_state = BTRFS_CACHE_FINISHED;

spin_unlock(&root->ino_cache_lock);

+ wake_up(&root->ino_cache_wait);

return;

}

@@ -160,15 +176,13 @@ static void start_caching(struct btrfs_root *root)

if (!ret && objectid <= BTRFS_LAST_FREE_OBJECTID) {

__btrfs_add_free_space(fs_info, ctl, objectid,

BTRFS_LAST_FREE_OBJECTID - objectid + 1);

+ wake_up(&root->ino_cache_wait);

}

tsk = kthread_run(caching_kthread, root, "btrfs-ino-cache-%llu",

root->root_key.objectid);

- if (IS_ERR(tsk)) {

- btrfs_warn(fs_info, "failed to start inode caching task");

- btrfs_clear_pending_and_info(fs_info, INODE_MAP_CACHE,

- "disabling inode map caching");

- }

+ if (IS_ERR(tsk))

+ fail_caching_thread(root);

}

int btrfs_find_free_ino(struct btrfs_root *root, u64 *objectid)

@@ -186,11 +200,14 @@ again:

wait_event(root->ino_cache_wait,

root->ino_cache_state == BTRFS_CACHE_FINISHED ||

+ root->ino_cache_state == BTRFS_CACHE_ERROR ||

root->free_ino_ctl->free_space > 0);

if (root->ino_cache_state == BTRFS_CACHE_FINISHED &&

root->free_ino_ctl->free_space == 0)

return -ENOSPC;

+ else if (root->ino_cache_state == BTRFS_CACHE_ERROR)

+ return btrfs_find_free_objectid(root, objectid);

else

goto again;

}

@@ -419,7 +436,7 @@ int btrfs_save_ino_cache(struct btrfs_root *root,

* 1 item for free space object

* 3 items for pre-allocation

*/

- trans->bytes_reserved = btrfs_calc_trans_metadata_size(fs_info, 10);

+ trans->bytes_reserved = btrfs_calc_insert_metadata_size(fs_info, 10);

ret = btrfs_block_rsv_add(root, trans->block_rsv,

trans->bytes_reserved,

BTRFS_RESERVE_NO_FLUSH);

@@ -485,6 +502,7 @@ again:

prealloc, prealloc, &alloc_hint);

if (ret) {

btrfs_delalloc_release_extents(BTRFS_I(inode), prealloc, true);

+ btrfs_delalloc_release_metadata(BTRFS_I(inode), prealloc, true);

goto out_put;

}

diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index ee582a36653d3..a0546401bc0ab 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c

@@ -30,6 +30,7 @@

#include <linux/swap.h>

#include <linux/sched/mm.h>

#include <asm/unaligned.h>

+#include "misc.h"

#include "ctree.h"

#include "disk-io.h"

#include "transaction.h"

@@ -46,8 +47,8 @@

#include "backref.h"

#include "props.h"

#include "qgroup.h"

-#include "dedupe.h"

#include "delalloc-space.h"

+#include "block-group.h"

struct btrfs_iget_args {

struct btrfs_key *location;

@@ -74,15 +75,15 @@ static struct kmem_cache *btrfs_inode_cachep;

struct kmem_cache *btrfs_trans_handle_cachep;

struct kmem_cache *btrfs_path_cachep;

struct kmem_cache *btrfs_free_space_cachep;

+struct kmem_cache *btrfs_free_space_bitmap_cachep;

static int btrfs_setsize(struct inode *inode, struct iattr *attr);

static int btrfs_truncate(struct inode *inode, bool skip_writeback);

static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent);

static noinline int cow_file_range(struct inode *inode,

struct page *locked_page,

- u64 start, u64 end, u64 delalloc_end,

- int *page_started, unsigned long *nr_written,

- int unlock, struct btrfs_dedupe_hash *hash);

+ u64 start, u64 end, int *page_started,

+ unsigned long *nr_written, int unlock);

static struct extent_map *create_io_em(struct inode *inode, u64 start, u64 len,

u64 orig_start, u64 block_start,

u64 block_len, u64 orig_block_len,

@@ -178,6 +179,9 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans,

size_t cur_size = size;

unsigned long offset;

+ ASSERT((compressed_size > 0 && compressed_pages) ||

+ (compressed_size == 0 && !compressed_pages));

+

if (compressed_size && compressed_pages)

cur_size = compressed_size;

@@ -462,8 +466,7 @@ static inline void inode_should_defrag(struct btrfs_inode *inode,

* are written in the same order that the flusher thread sent them

* down.

*/

-static noinline void compress_file_range(struct async_chunk *async_chunk,

- int *num_added)

+static noinline int compress_file_range(struct async_chunk *async_chunk)

{

struct inode *inode = async_chunk->inode;

struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);

@@ -479,6 +482,7 @@ static noinline void compress_file_range(struct async_chunk *async_chunk,

int i;

int will_compress;

int compress_type = fs_info->compress_type;

+ int compressed_extents = 0;

int redirty = 0;

inode_should_defrag(BTRFS_I(inode), start, end, end - start + 1,

@@ -615,14 +619,21 @@ cont:

* our outstanding extent for clearing delalloc for this

* range.

*/

- extent_clear_unlock_delalloc(inode, start, end, end,

- NULL, clear_flags,

+ extent_clear_unlock_delalloc(inode, start, end, NULL,

+ clear_flags,

PAGE_UNLOCK |

PAGE_CLEAR_DIRTY |

PAGE_SET_WRITEBACK |

page_error_op |

PAGE_END_WRITEBACK);

- goto free_pages_out;

+

+ for (i = 0; i < nr_pages; i++) {

+ WARN_ON(pages[i]->mapping);

+ put_page(pages[i]);

+ }

+ kfree(pages);

+

+ return 0;

}

}

@@ -641,7 +652,7 @@ cont:

*/

total_in = ALIGN(total_in, PAGE_SIZE);

if (total_compressed + blocksize <= total_in) {

- *num_added += 1;

+ compressed_extents++;

/*

* The async work queues will take care of doing actual

@@ -658,7 +669,7 @@ cont:

cond_resched();

goto again;

}

- return;

+ return compressed_extents;

}

}

if (pages) {

@@ -697,16 +708,9 @@ cleanup_and_bail_uncompressed:

extent_range_redirty_for_io(inode, start, end);

add_async_extent(async_chunk, start, end - start + 1, 0, NULL, 0,

BTRFS_COMPRESS_NONE);

- *num_added += 1;

-

- return;

+ compressed_extents++;

-free_pages_out:

- for (i = 0; i < nr_pages; i++) {

- WARN_ON(pages[i]->mapping);

- put_page(pages[i]);

- }

- kfree(pages);

+ return compressed_extents;

}

static void free_async_extent_pages(struct async_extent *async_extent)

@@ -762,10 +766,7 @@ retry:

async_extent->start,

async_extent->start +

async_extent->ram_size - 1,

- async_extent->start +

- async_extent->ram_size - 1,

- &page_started, &nr_written, 0,

- NULL);

+ &page_started, &nr_written, 0);

/* JDM XXX */

@@ -855,8 +856,6 @@ retry:

extent_clear_unlock_delalloc(inode, async_extent->start,

async_extent->start +

async_extent->ram_size - 1,

- async_extent->start +

- async_extent->ram_size - 1,

NULL, EXTENT_LOCKED | EXTENT_DELALLOC,

PAGE_UNLOCK | PAGE_CLEAR_DIRTY |

PAGE_SET_WRITEBACK);

@@ -875,7 +874,7 @@ retry:

btrfs_writepage_endio_finish_ordered(p, start, end, 0);

p->mapping = NULL;

- extent_clear_unlock_delalloc(inode, start, end, end,

+ extent_clear_unlock_delalloc(inode, start, end,

NULL, 0,

PAGE_END_WRITEBACK |

PAGE_SET_ERROR);

@@ -893,8 +892,6 @@ out_free:

extent_clear_unlock_delalloc(inode, async_extent->start,

async_extent->start +

async_extent->ram_size - 1,

- async_extent->start +

- async_extent->ram_size - 1,

NULL, EXTENT_LOCKED | EXTENT_DELALLOC |

EXTENT_DELALLOC_NEW |

EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING,

@@ -953,9 +950,8 @@ static u64 get_extent_allocation_hint(struct inode *inode, u64 start,

*/

static noinline int cow_file_range(struct inode *inode,

struct page *locked_page,

- u64 start, u64 end, u64 delalloc_end,

- int *page_started, unsigned long *nr_written,

- int unlock, struct btrfs_dedupe_hash *hash)

+ u64 start, u64 end, int *page_started,

+ unsigned long *nr_written, int unlock)

{

struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);

struct btrfs_root *root = BTRFS_I(inode)->root;

@@ -994,8 +990,7 @@ static noinline int cow_file_range(struct inode *inode,

* our outstanding extent for clearing delalloc for this

* range.

*/

- extent_clear_unlock_delalloc(inode, start, end,

- delalloc_end, NULL,

+ extent_clear_unlock_delalloc(inode, start, end, NULL,

EXTENT_LOCKED | EXTENT_DELALLOC |

EXTENT_DELALLOC_NEW | EXTENT_DEFRAG |

EXTENT_DO_ACCOUNTING, PAGE_UNLOCK |

@@ -1078,7 +1073,7 @@ static noinline int cow_file_range(struct inode *inode,

extent_clear_unlock_delalloc(inode, start,

start + ram_size - 1,

- delalloc_end, locked_page,

+ locked_page,

EXTENT_LOCKED | EXTENT_DELALLOC,

page_ops);

if (num_bytes < cur_alloc_size)

@@ -1123,7 +1118,6 @@ out_unlock:

if (extent_reserved) {

extent_clear_unlock_delalloc(inode, start,

start + cur_alloc_size,

- start + cur_alloc_size,

locked_page,

clear_bits,

page_ops);

@@ -1131,8 +1125,7 @@ out_unlock:

if (start >= end)

goto out;

}

- extent_clear_unlock_delalloc(inode, start, end, delalloc_end,

- locked_page,

+ extent_clear_unlock_delalloc(inode, start, end, locked_page,

clear_bits | EXTENT_CLEAR_DATA_RESV,

page_ops);

goto out;

@@ -1144,12 +1137,12 @@ out_unlock:

static noinline void async_cow_start(struct btrfs_work *work)

{

struct async_chunk *async_chunk;

- int num_added = 0;

+ int compressed_extents;

async_chunk = container_of(work, struct async_chunk, work);

- compress_file_range(async_chunk, &num_added);

- if (num_added == 0) {

+ compressed_extents = compress_file_range(async_chunk);

+ if (compressed_extents == 0) {

btrfs_add_delayed_iput(async_chunk->inode);

async_chunk->inode = NULL;

}

@@ -1235,7 +1228,7 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page,

PAGE_SET_WRITEBACK | PAGE_END_WRITEBACK |

PAGE_SET_ERROR;

- extent_clear_unlock_delalloc(inode, start, end, 0, locked_page,

+ extent_clear_unlock_delalloc(inode, start, end, locked_page,

clear_bits, page_ops);

return -ENOMEM;

}

@@ -1310,36 +1303,25 @@ static noinline int csum_exist_in_range(struct btrfs_fs_info *fs_info,

*/

static noinline int run_delalloc_nocow(struct inode *inode,

struct page *locked_page,

- u64 start, u64 end, int *page_started, int force,

- unsigned long *nr_written)

+ const u64 start, const u64 end,

+ int *page_started, int force,

+ unsigned long *nr_written)

{

struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);

struct btrfs_root *root = BTRFS_I(inode)->root;

- struct extent_buffer *leaf;

struct btrfs_path *path;

- struct btrfs_file_extent_item *fi;

- struct btrfs_key found_key;

- struct extent_map *em;

- u64 cow_start;

- u64 cur_offset;

- u64 extent_end;

- u64 extent_offset;

- u64 disk_bytenr;

- u64 num_bytes;

- u64 disk_num_bytes;

- u64 ram_bytes;

- int extent_type;

+ u64 cow_start = (u64)-1;

+ u64 cur_offset = start;

int ret;

- int type;

- int nocow;

- int check_prev = 1;

- bool nolock;

+ bool check_prev = true;

+ const bool freespace_inode = btrfs_is_free_space_inode(BTRFS_I(inode));

u64 ino = btrfs_ino(BTRFS_I(inode));

+ bool nocow = false;

+ u64 disk_bytenr = 0;

path = btrfs_alloc_path();

if (!path) {

- extent_clear_unlock_delalloc(inode, start, end, end,

- locked_page,

+ extent_clear_unlock_delalloc(inode, start, end, locked_page,

EXTENT_LOCKED | EXTENT_DELALLOC |

EXTENT_DO_ACCOUNTING |

EXTENT_DEFRAG, PAGE_UNLOCK |

@@ -1349,15 +1331,29 @@ static noinline int run_delalloc_nocow(struct inode *inode,

return -ENOMEM;

}

- nolock = btrfs_is_free_space_inode(BTRFS_I(inode));

-

- cow_start = (u64)-1;

- cur_offset = start;

while (1) {

+ struct btrfs_key found_key;

+ struct btrfs_file_extent_item *fi;

+ struct extent_buffer *leaf;

+ u64 extent_end;

+ u64 extent_offset;

+ u64 num_bytes = 0;

+ u64 disk_num_bytes;

+ u64 ram_bytes;

+ int extent_type;

+

+ nocow = false;

+

ret = btrfs_lookup_file_extent(NULL, root, path, ino,

cur_offset, 0);

if (ret < 0)

goto error;

+

+ /*

+ * If there is no extent for our range when doing the initial

+ * search, then go back to the previous slot as it will be the

+ * one containing the search offset

+ */

if (ret > 0 && path->slots[0] > 0 && check_prev) {

leaf = path->nodes[0];

btrfs_item_key_to_cpu(leaf, &found_key,

@@ -1366,8 +1362,9 @@ static noinline int run_delalloc_nocow(struct inode *inode,

found_key.type == BTRFS_EXTENT_DATA_KEY)

path->slots[0]--;

}

- check_prev = 0;

+ check_prev = false;

next_slot:

+ /* Go to next leaf if we have exhausted the current one */

leaf = path->nodes[0];

if (path->slots[0] >= btrfs_header_nritems(leaf)) {

ret = btrfs_next_leaf(root, path);

@@ -1381,28 +1378,40 @@ next_slot:

leaf = path->nodes[0];

}

- nocow = 0;

- disk_bytenr = 0;

- num_bytes = 0;

btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);

+ /* Didn't find anything for our INO */

if (found_key.objectid > ino)

break;

+ /*

+ * Keep searching until we find an EXTENT_ITEM or there are no

+ * more extents for this inode

+ */

if (WARN_ON_ONCE(found_key.objectid < ino) ||

found_key.type < BTRFS_EXTENT_DATA_KEY) {

path->slots[0]++;

goto next_slot;

}

+

+ /* Found key is not EXTENT_DATA_KEY or starts after req range */

if (found_key.type > BTRFS_EXTENT_DATA_KEY ||

found_key.offset > end)

break;

+ /*

+ * If the found extent starts after requested offset, then

+ * adjust extent_end to be right before this extent begins

+ */

if (found_key.offset > cur_offset) {

extent_end = found_key.offset;

extent_type = 0;

goto out_check;

}

+ /*

+ * Found extent which begins before our range and potentially

+ * intersect it

+ */

fi = btrfs_item_ptr(leaf, path->slots[0],

struct btrfs_file_extent_item);

extent_type = btrfs_file_extent_type(leaf, fi);

@@ -1416,26 +1425,36 @@ next_slot:

btrfs_file_extent_num_bytes(leaf, fi);

disk_num_bytes =

btrfs_file_extent_disk_num_bytes(leaf, fi);

+ /*

+ * If extent we got ends before our range starts, skip

+ * to next extent

+ */

if (extent_end <= start) {

path->slots[0]++;

goto next_slot;

}

+ /* Skip holes */

if (disk_bytenr == 0)

goto out_check;

+ /* Skip compressed/encrypted/encoded extents */

if (btrfs_file_extent_compression(leaf, fi) ||

btrfs_file_extent_encryption(leaf, fi) ||

btrfs_file_extent_other_encoding(leaf, fi))

goto out_check;

/*

- * Do the same check as in btrfs_cross_ref_exist but

- * without the unnecessary search.

+ * If extent is created before the last volume's snapshot

+ * this implies the extent is shared, hence we can't do

+ * nocow. This is the same check as in

+ * btrfs_cross_ref_exist but without calling

+ * btrfs_search_slot.

*/

- if (!nolock &&

+ if (!freespace_inode &&

btrfs_file_extent_generation(leaf, fi) <=

btrfs_root_last_snapshot(&root->root_item))

goto out_check;

if (extent_type == BTRFS_FILE_EXTENT_REG && !force)

goto out_check;

+ /* If extent is RO, we must COW it */

if (btrfs_extent_readonly(fs_info, disk_bytenr))

goto out_check;

ret = btrfs_cross_ref_exist(root, ino,

@@ -1452,17 +1471,17 @@ next_slot:

goto error;

}

- WARN_ON_ONCE(nolock);

+ WARN_ON_ONCE(freespace_inode);

goto out_check;

}

disk_bytenr += extent_offset;

disk_bytenr += cur_offset - found_key.offset;

num_bytes = min(end + 1, extent_end) - cur_offset;

/*

- * if there are pending snapshots for this root,

- * we fall into common COW way.

+ * If there are pending snapshots for this root, we

+ * fall into common COW way

*/

- if (!nolock && atomic_read(&root->snapshot_force_cow))

+ if (!freespace_inode && atomic_read(&root->snapshot_force_cow))

goto out_check;

/*

* force cow if csum exists in the range.

@@ -1481,27 +1500,29 @@ next_slot:

cur_offset = cow_start;

goto error;

}

- WARN_ON_ONCE(nolock);

+ WARN_ON_ONCE(freespace_inode);

goto out_check;

}

if (!btrfs_inc_nocow_writers(fs_info, disk_bytenr))

goto out_check;

- nocow = 1;

+ nocow = true;

} else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {

- extent_end = found_key.offset +

- btrfs_file_extent_ram_bytes(leaf, fi);

- extent_end = ALIGN(extent_end,

- fs_info->sectorsize);

+ extent_end = found_key.offset + ram_bytes;

+ extent_end = ALIGN(extent_end, fs_info->sectorsize);

+ /* Skip extents outside of our requested range */

+ if (extent_end <= start) {

+ path->slots[0]++;

+ goto next_slot;

+ }

} else {

+ /* If this triggers then we have a memory corruption */

BUG();

}

out_check:

- if (extent_end <= start) {

- path->slots[0]++;

- if (nocow)

- btrfs_dec_nocow_writers(fs_info, disk_bytenr);

- goto next_slot;

- }

+ /*

+ * If nocow is false then record the beginning of the range

+ * that needs to be COWed

+ */

if (!nocow) {

if (cow_start == (u64)-1)

cow_start = cur_offset;

@@ -1513,11 +1534,16 @@ out_check:

}

btrfs_release_path(path);

+

+ /*

+ * COW range from cow_start to found_key.offset - 1. As the key

+ * will contain the beginning of the first extent that can be

+ * NOCOW, following one which needs to be COW'ed

+ */

if (cow_start != (u64)-1) {

ret = cow_file_range(inode, locked_page,

cow_start, found_key.offset - 1,

- end, page_started, nr_written, 1,

- NULL);

Read the original on git.kernel.org ↗