*/
#define RBIO_PADDED_BIT 5
+/* Set at park time and never cleared: this rbio once parked (stats). */
+#define RBIO_WAS_PARKED_BIT 7
+
#define RBIO_CACHE_SIZE 1024
/*
static void merge_rbio(struct btrfs_raid_bio *dest,
struct btrfs_raid_bio *victim)
{
+ if (test_bit(RBIO_PARKED_BIT, &dest->flags))
+ atomic64_add(victim->bio_list_bytes,
+ &dest->bioc->fs_info->stripe_park_stats.merged_bytes);
bio_list_merge_init(&dest->bio_list, &victim->bio_list);
dest->bio_list_bytes += victim->bio_list_bytes;
/* Also inherit the bitmaps from @victim. */
spin_lock(&table->parked_lock);
set_bit(RBIO_PARKED_BIT, &rbio->flags);
+ set_bit(RBIO_WAS_PARKED_BIT, &rbio->flags);
rbio->park_deadline = jiffies + msecs_to_jiffies(timeout_ms);
list_add_tail(&rbio->parked_node, &table->parked);
spin_unlock(&table->parked_lock);
+ atomic64_inc(&fs_info->stripe_park_stats.parked);
queue_delayed_work(system_percpu_wq, &table->parked_work,
msecs_to_jiffies(BTRFS_RBIO_PARK_SCAN_MS));
}
rbio_unpark_locked(rbio);
spin_unlock(&table->parked_lock);
+ atomic64_inc(&rbio->bioc->fs_info->stripe_park_stats.filled);
start_async_work(rbio, rmw_rbio_work_locked);
}
list_for_each_entry_safe(rbio, tmp, &flush, parked_node) {
list_del_init(&rbio->parked_node);
+ atomic64_inc(&fs_info->stripe_park_stats.kicked);
start_async_work(rbio, rmw_rbio_work_locked);
}
}
list_for_each_entry_safe(rbio, tmp, &flush, parked_node) {
list_del_init(&rbio->parked_node);
+ atomic64_inc(&rbio->bioc->fs_info->stripe_park_stats.expired);
start_async_work(rbio, rmw_rbio_work_locked);
}
if (rearm)
set_bit(RBIO_PADDED_BIT, &rbio->flags);
/* The whole stripe goes out: every vertical position is written. */
bitmap_set(&rbio->dbitmap, 0, rbio->stripe_nsectors);
+ atomic64_inc(&fs_info->stripe_park_stats.padded);
return true;
}
*/
if (!rbio_is_full(rbio) && !rmw_try_pad_full(rbio) &&
need_read_stripe_sectors(rbio)) {
+ /* A parked-then-flushed write that still had to read. */
+ if (test_bit(RBIO_WAS_PARKED_BIT, &rbio->flags))
+ atomic64_inc(&rbio->bioc->fs_info->
+ stripe_park_stats.rmw_reads);
/*
* Now we're doing sub-stripe write, also need all data stripes
* to do the full RMW.
}
BTRFS_ATTR_RW(, commit_stats, btrfs_commit_stats_show, btrfs_commit_stats_store);
+static ssize_t btrfs_stripe_park_stats_show(struct kobject *kobj,
+ struct kobj_attribute *a, char *buf)
+{
+ struct btrfs_fs_info *fs_info = to_fs_info(kobj);
+
+ return sysfs_emit(buf,
+ "parked %lld\n"
+ "merged_bytes %lld\n"
+ "filled %lld\n"
+ "kicked %lld\n"
+ "expired %lld\n"
+ "padded %lld\n"
+ "rmw_reads %lld\n",
+ atomic64_read(&fs_info->stripe_park_stats.parked),
+ atomic64_read(&fs_info->stripe_park_stats.merged_bytes),
+ atomic64_read(&fs_info->stripe_park_stats.filled),
+ atomic64_read(&fs_info->stripe_park_stats.kicked),
+ atomic64_read(&fs_info->stripe_park_stats.expired),
+ atomic64_read(&fs_info->stripe_park_stats.padded),
+ atomic64_read(&fs_info->stripe_park_stats.rmw_reads));
+}
+BTRFS_ATTR(, stripe_park_stats, btrfs_stripe_park_stats_show);
+
static ssize_t btrfs_clone_alignment_show(struct kobject *kobj,
struct kobj_attribute *a, char *buf)
{
BTRFS_ATTR_PTR(, read_policy),
BTRFS_ATTR_PTR(, bg_reclaim_threshold),
BTRFS_ATTR_PTR(, commit_stats),
+ BTRFS_ATTR_PTR(, stripe_park_stats),
BTRFS_ATTR_PTR(, temp_fsid),
#ifdef CONFIG_BTRFS_EXPERIMENTAL
BTRFS_ATTR_PTR(, offload_csum),