Skip to content

Commit 2b313b2

Browse files
committed
btrfs: add io read stats per device to devinfo
This adds read stats per device to devinfo to evaluate the effects of different read policies better. This adds a new file /sys/fs/btrfs/BTRFS-UUID/devinfo/ID/read_stats. Signed-off-by: Kai Krakow <kai@kaishome.de>
1 parent 2738442 commit 2b313b2

File tree

4 files changed

+75
-3
lines changed

4 files changed

+75
-3
lines changed

fs/btrfs/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,18 @@ config BTRFS_ALLOCATOR_HINTS
129129

130130
If unsure, say N.
131131

132+
config BTRFS_PER_DEVICE_IO_STATS
133+
bool "Btrfs per io devices stats"
134+
depends on BTRFS_FS
135+
default n
136+
help
137+
Enable collecting io read stats per devices to evaluate the effects
138+
of different read policies better.
139+
140+
This adds a new file /sys/fs/btrfs/BTRFS-UUID/devinfo/ID/read_stats.
141+
142+
If unsure, say N.
143+
132144
config BTRFS_EXPERIMENTAL
133145
bool "Btrfs experimental features"
134146
depends on BTRFS_FS

fs/btrfs/sysfs.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@
2626
#include "fs.h"
2727
#include "accessors.h"
2828

29+
#ifdef CONFIG_BTRFS_PER_DEVICE_IO_STATS
30+
#include <linux/part_stat.h>
31+
#endif
32+
2933
/*
3034
* Structure name Path
3135
* --------------------------------------------------------------------------
@@ -2214,12 +2218,36 @@ static ssize_t btrfs_devinfo_type_store(struct kobject *kobj,
22142218
BTRFS_ATTR_RW(devid, type, btrfs_devinfo_type_show, btrfs_devinfo_type_store);
22152219
#endif
22162220

2221+
#ifdef CONFIG_BTRFS_PER_DEVICE_IO_STATS
2222+
static ssize_t btrfs_devinfo_read_stats_show(struct kobject *kobj,
2223+
struct kobj_attribute *a, char *buf)
2224+
{
2225+
struct btrfs_device *device = container_of(kobj, struct btrfs_device,
2226+
devid_kobj);
2227+
u64 read_wait = part_stat_read(device->bdev, nsecs[READ]);
2228+
unsigned long read_ios = part_stat_read(device->bdev, ios[READ]);
2229+
2230+
u64 avg_wait = 0;
2231+
if (read_wait && read_ios && read_wait >= read_ios)
2232+
avg_wait = div_u64(read_wait, read_ios);
2233+
2234+
return scnprintf(buf, PAGE_SIZE, "ios %lu wait %llu avg %llu age %llu ignored %llu\n",
2235+
read_ios, read_wait, avg_wait,
2236+
(u64)atomic64_read(&device->last_io_age),
2237+
(u64)atomic64_read(&device->stripe_ignored));
2238+
}
2239+
BTRFS_ATTR(devid, read_stats, btrfs_devinfo_read_stats_show);
2240+
#endif
2241+
22172242
/*
22182243
* Information about one device.
22192244
*
22202245
* Path: /sys/fs/btrfs/<uuid>/devinfo/<devid>/
22212246
*/
22222247
static struct attribute *devid_attrs[] = {
2248+
#ifdef CONFIG_BTRFS_PER_DEVICE_IO_STATS
2249+
BTRFS_ATTR_PTR(devid, read_stats),
2250+
#endif
22232251
BTRFS_ATTR_PTR(devid, error_stats),
22242252
BTRFS_ATTR_PTR(devid, fsid),
22252253
BTRFS_ATTR_PTR(devid, in_fs_metadata),

fs/btrfs/volumes.c

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6139,6 +6139,15 @@ static int find_live_mirror(struct btrfs_fs_info *fs_info,
61396139
else
61406140
num_stripes = map->num_stripes;
61416141

6142+
#ifdef CONFIG_BTRFS_PER_DEVICE_IO_STATS
6143+
/* age each possible stripe by 1 IO */
6144+
for (int i = first; i < first + num_stripes; i++) {
6145+
struct btrfs_device *device = map->stripes[i].dev;
6146+
atomic64_inc(&device->last_io_age);
6147+
atomic64_inc(&device->stripe_ignored);
6148+
}
6149+
#endif
6150+
61426151
switch (policy) {
61436152
default:
61446153
/* Shouldn't happen, just warn and use pid instead of failing */
@@ -6174,14 +6183,29 @@ static int find_live_mirror(struct btrfs_fs_info *fs_info,
61746183
for (tolerance = 0; tolerance < 2; tolerance++) {
61756184
if (map->stripes[preferred_mirror].dev->bdev &&
61766185
(tolerance || map->stripes[preferred_mirror].dev != srcdev))
6177-
return preferred_mirror;
6186+
goto out;
61786187
for (i = first; i < first + num_stripes; i++) {
61796188
if (map->stripes[i].dev->bdev &&
6180-
(tolerance || map->stripes[i].dev != srcdev))
6181-
return i;
6189+
(tolerance || map->stripes[i].dev != srcdev)) {
6190+
preferred_mirror = i;
6191+
goto out;
6192+
}
61826193
}
61836194
}
61846195

6196+
out:
6197+
#ifdef CONFIG_BTRFS_PER_DEVICE_IO_STATS
6198+
do {
6199+
struct btrfs_device *preferred_device = map->stripes[preferred_mirror].dev;
6200+
6201+
/* reset age of selected stripe */
6202+
atomic64_set(&preferred_device->last_io_age, 0);
6203+
6204+
/* do not count ignores for the selected stripe */
6205+
atomic64_dec(&preferred_device->stripe_ignored);
6206+
} while (0);
6207+
#endif
6208+
61856209
/* we couldn't find one that doesn't fail. Just return something
61866210
* and the io error handling code will clean up eventually
61876211
*/

fs/btrfs/volumes.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,14 @@ struct btrfs_device {
201201

202202
/* Bandwidth limit for scrub, in bytes */
203203
u64 scrub_speed_max;
204+
205+
#ifdef CONFIG_BTRFS_PER_DEVICE_IO_STATS
206+
/* store an age of last read access */
207+
atomic64_t last_io_age;
208+
209+
/* store how often a stripe has been ignored as a read candidate */
210+
atomic64_t stripe_ignored;
211+
#endif
204212
};
205213

206214
/*

0 commit comments

Comments
 (0)