aboutsummaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds2023-03-10 08:39:13 -0800
committerLinus Torvalds2023-03-10 08:39:13 -0800
commitae195ca1a8a4af75073e82c485148897c923f88f (patch)
treee8c11342c76d15a8eafb205547ab5f31a919810d /fs
parentf331c5de7960d69fc767d2dc08f5f5859ce70061 (diff)
parent675dfe1223a69e270b3d52cb0211c8a501455cec (diff)
Merge tag 'for-6.3-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fixes from David Sterba: "First batch of fixes. Among them there are two updates to sysfs and ioctl which are not strictly fixes but are used for testing so there's no reason to delay them. - fix block group item corruption after inserting new block group - fix extent map logging bit not cleared for split maps after dropping range - fix calculation of unusable block group space reporting bogus values due to 32/64b division - fix unnecessary increment of read error stat on write error - improve error handling in inode update - export per-device fsid in DEV_INFO ioctl to distinguish seeding devices, needed for testing - allocator size classes: - fix potential dead lock in size class loading logic - print sysfs stats for the allocation classes" * tag 'for-6.3-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: fix block group item corruption after inserting new block group btrfs: fix extent map logging bit not cleared for split maps after dropping range btrfs: fix percent calculation for bg reclaim message btrfs: fix unnecessary increment of read error stat on write error btrfs: handle btrfs_del_item errors in __btrfs_update_delayed_inode btrfs: ioctl: return device fsid from DEV_INFO ioctl btrfs: fix potential dead lock in size class loading logic btrfs: sysfs: add size class stats
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/bio.c2
-rw-r--r--fs/btrfs/block-group.c58
-rw-r--r--fs/btrfs/delayed-inode.c2
-rw-r--r--fs/btrfs/extent_map.c7
-rw-r--r--fs/btrfs/ioctl.c1
-rw-r--r--fs/btrfs/sysfs.c42
6 files changed, 81 insertions, 31 deletions
diff --git a/fs/btrfs/bio.c b/fs/btrfs/bio.c
index d8b90f95b157..726592868e9c 100644
--- a/fs/btrfs/bio.c
+++ b/fs/btrfs/bio.c
@@ -287,7 +287,7 @@ static void btrfs_log_dev_io_error(struct bio *bio, struct btrfs_device *dev)
if (btrfs_op(bio) == BTRFS_MAP_WRITE)
btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS);
- if (!(bio->bi_opf & REQ_RAHEAD))
+ else if (!(bio->bi_opf & REQ_RAHEAD))
btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_READ_ERRS);
if (bio->bi_opf & REQ_PREFLUSH)
btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_FLUSH_ERRS);
diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
index 5b10401d803b..0ef8b8926bfa 100644
--- a/fs/btrfs/block-group.c
+++ b/fs/btrfs/block-group.c
@@ -558,14 +558,15 @@ u64 add_new_free_space(struct btrfs_block_group *block_group, u64 start, u64 end
static int sample_block_group_extent_item(struct btrfs_caching_control *caching_ctl,
struct btrfs_block_group *block_group,
int index, int max_index,
- struct btrfs_key *key)
+ struct btrfs_key *found_key)
{
struct btrfs_fs_info *fs_info = block_group->fs_info;
struct btrfs_root *extent_root;
- int ret = 0;
u64 search_offset;
u64 search_end = block_group->start + block_group->length;
struct btrfs_path *path;
+ struct btrfs_key search_key;
+ int ret = 0;
ASSERT(index >= 0);
ASSERT(index <= max_index);
@@ -585,37 +586,24 @@ static int sample_block_group_extent_item(struct btrfs_caching_control *caching_
path->reada = READA_FORWARD;
search_offset = index * div_u64(block_group->length, max_index);
- key->objectid = block_group->start + search_offset;
- key->type = BTRFS_EXTENT_ITEM_KEY;
- key->offset = 0;
+ search_key.objectid = block_group->start + search_offset;
+ search_key.type = BTRFS_EXTENT_ITEM_KEY;
+ search_key.offset = 0;
- while (1) {
- ret = btrfs_search_forward(extent_root, key, path, 0);
- if (ret != 0)
- goto out;
+ btrfs_for_each_slot(extent_root, &search_key, found_key, path, ret) {
/* Success; sampled an extent item in the block group */
- if (key->type == BTRFS_EXTENT_ITEM_KEY &&
- key->objectid >= block_group->start &&
- key->objectid + key->offset <= search_end)
- goto out;
+ if (found_key->type == BTRFS_EXTENT_ITEM_KEY &&
+ found_key->objectid >= block_group->start &&
+ found_key->objectid + found_key->offset <= search_end)
+ break;
/* We can't possibly find a valid extent item anymore */
- if (key->objectid >= search_end) {
+ if (found_key->objectid >= search_end) {
ret = 1;
break;
}
- if (key->type < BTRFS_EXTENT_ITEM_KEY)
- key->type = BTRFS_EXTENT_ITEM_KEY;
- else
- key->objectid++;
- 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);
}
-out:
+
lockdep_assert_held(&caching_ctl->mutex);
lockdep_assert_held_read(&fs_info->commit_root_sem);
btrfs_free_path(path);
@@ -659,6 +647,7 @@ out:
static int load_block_group_size_class(struct btrfs_caching_control *caching_ctl,
struct btrfs_block_group *block_group)
{
+ struct btrfs_fs_info *fs_info = block_group->fs_info;
struct btrfs_key key;
int i;
u64 min_size = block_group->length;
@@ -668,6 +657,8 @@ static int load_block_group_size_class(struct btrfs_caching_control *caching_ctl
if (!btrfs_block_group_should_use_size_class(block_group))
return 0;
+ lockdep_assert_held(&caching_ctl->mutex);
+ lockdep_assert_held_read(&fs_info->commit_root_sem);
for (i = 0; i < 5; ++i) {
ret = sample_block_group_extent_item(caching_ctl, block_group, i, 5, &key);
if (ret < 0)
@@ -682,7 +673,6 @@ static int load_block_group_size_class(struct btrfs_caching_control *caching_ctl
block_group->size_class = size_class;
spin_unlock(&block_group->lock);
}
-
out:
return ret;
}
@@ -1836,7 +1826,8 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
btrfs_info(fs_info,
"reclaiming chunk %llu with %llu%% used %llu%% unusable",
- bg->start, div_u64(bg->used * 100, bg->length),
+ bg->start,
+ div64_u64(bg->used * 100, bg->length),
div64_u64(zone_unusable * 100, bg->length));
trace_btrfs_reclaim_block_group(bg);
ret = btrfs_relocate_chunk(fs_info, bg->start);
@@ -2493,18 +2484,29 @@ static int insert_block_group_item(struct btrfs_trans_handle *trans,
struct btrfs_block_group_item bgi;
struct btrfs_root *root = btrfs_block_group_root(fs_info);
struct btrfs_key key;
+ u64 old_commit_used;
+ int ret;
spin_lock(&block_group->lock);
btrfs_set_stack_block_group_used(&bgi, block_group->used);
btrfs_set_stack_block_group_chunk_objectid(&bgi,
block_group->global_root_id);
btrfs_set_stack_block_group_flags(&bgi, block_group->flags);
+ old_commit_used = block_group->commit_used;
+ block_group->commit_used = block_group->used;
key.objectid = block_group->start;
key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
key.offset = block_group->length;
spin_unlock(&block_group->lock);
- return btrfs_insert_item(trans, root, &key, &bgi, sizeof(bgi));
+ ret = btrfs_insert_item(trans, root, &key, &bgi, sizeof(bgi));
+ if (ret < 0) {
+ spin_lock(&block_group->lock);
+ block_group->commit_used = old_commit_used;
+ spin_unlock(&block_group->lock);
+ }
+
+ return ret;
}
static int insert_dev_extent(struct btrfs_trans_handle *trans,
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c
index 0095c6e4c3d1..6b457b010cbc 100644
--- a/fs/btrfs/delayed-inode.c
+++ b/fs/btrfs/delayed-inode.c
@@ -1048,7 +1048,7 @@ again:
* so there is only one iref. The case that several irefs are
* in the same item doesn't exist.
*/
- btrfs_del_item(trans, root, path);
+ ret = btrfs_del_item(trans, root, path);
out:
btrfs_release_delayed_iref(node);
btrfs_release_path(path);
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
index be94030e1dfb..138afa955370 100644
--- a/fs/btrfs/extent_map.c
+++ b/fs/btrfs/extent_map.c
@@ -763,7 +763,13 @@ void btrfs_drop_extent_map_range(struct btrfs_inode *inode, u64 start, u64 end,
goto next;
}
+ flags = em->flags;
clear_bit(EXTENT_FLAG_PINNED, &em->flags);
+ /*
+ * In case we split the extent map, we want to preserve the
+ * EXTENT_FLAG_LOGGING flag on our extent map, but we don't want
+ * it on the new extent maps.
+ */
clear_bit(EXTENT_FLAG_LOGGING, &flags);
modified = !list_empty(&em->list);
@@ -774,7 +780,6 @@ void btrfs_drop_extent_map_range(struct btrfs_inode *inode, u64 start, u64 end,
if (em->start >= start && em_end <= end)
goto remove_em;
- flags = em->flags;
gen = em->generation;
compressed = test_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 84626c8ad5bf..a0ef1a1784c7 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2859,6 +2859,7 @@ static long btrfs_ioctl_dev_info(struct btrfs_fs_info *fs_info,
di_args->bytes_used = btrfs_device_get_bytes_used(dev);
di_args->total_bytes = btrfs_device_get_total_bytes(dev);
memcpy(di_args->uuid, dev->uuid, sizeof(di_args->uuid));
+ memcpy(di_args->fsid, dev->fs_devices->fsid, BTRFS_UUID_SIZE);
if (dev->name)
strscpy(di_args->path, btrfs_dev_name(dev), sizeof(di_args->path));
else
diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c
index 8c5efa5813b3..37fc58a7f27e 100644
--- a/fs/btrfs/sysfs.c
+++ b/fs/btrfs/sysfs.c
@@ -9,6 +9,7 @@
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/bug.h>
+#include <linux/list.h>
#include <crypto/hash.h>
#include "messages.h"
#include "ctree.h"
@@ -778,6 +779,45 @@ static ssize_t btrfs_chunk_size_store(struct kobject *kobj,
return len;
}
+static ssize_t btrfs_size_classes_show(struct kobject *kobj,
+ struct kobj_attribute *a, char *buf)
+{
+ struct btrfs_space_info *sinfo = to_space_info(kobj);
+ struct btrfs_block_group *bg;
+ u32 none = 0;
+ u32 small = 0;
+ u32 medium = 0;
+ u32 large = 0;
+
+ for (int i = 0; i < BTRFS_NR_RAID_TYPES; ++i) {
+ down_read(&sinfo->groups_sem);
+ list_for_each_entry(bg, &sinfo->block_groups[i], list) {
+ if (!btrfs_block_group_should_use_size_class(bg))
+ continue;
+ switch (bg->size_class) {
+ case BTRFS_BG_SZ_NONE:
+ none++;
+ break;
+ case BTRFS_BG_SZ_SMALL:
+ small++;
+ break;
+ case BTRFS_BG_SZ_MEDIUM:
+ medium++;
+ break;
+ case BTRFS_BG_SZ_LARGE:
+ large++;
+ break;
+ }
+ }
+ up_read(&sinfo->groups_sem);
+ }
+ return sysfs_emit(buf, "none %u\n"
+ "small %u\n"
+ "medium %u\n"
+ "large %u\n",
+ none, small, medium, large);
+}
+
#ifdef CONFIG_BTRFS_DEBUG
/*
* Request chunk allocation with current chunk size.
@@ -835,6 +875,7 @@ SPACE_INFO_ATTR(bytes_zone_unusable);
SPACE_INFO_ATTR(disk_used);
SPACE_INFO_ATTR(disk_total);
BTRFS_ATTR_RW(space_info, chunk_size, btrfs_chunk_size_show, btrfs_chunk_size_store);
+BTRFS_ATTR(space_info, size_classes, btrfs_size_classes_show);
static ssize_t btrfs_sinfo_bg_reclaim_threshold_show(struct kobject *kobj,
struct kobj_attribute *a,
@@ -887,6 +928,7 @@ static struct attribute *space_info_attrs[] = {
BTRFS_ATTR_PTR(space_info, disk_total),
BTRFS_ATTR_PTR(space_info, bg_reclaim_threshold),
BTRFS_ATTR_PTR(space_info, chunk_size),
+ BTRFS_ATTR_PTR(space_info, size_classes),
#ifdef CONFIG_BTRFS_DEBUG
BTRFS_ATTR_PTR(space_info, force_chunk_alloc),
#endif