md: add io accounting for raid0 and raid5
We introduce a new bioset (io_acct_set) for raid0 and raid5 since they don't own clone infrastructure to accounting io. And the bioset is added to mddev instead of to raid0 and raid5 layer, because with this way, we can put common functions to md.h and reuse them in raid0 and raid5. Also struct md_io_acct is added accordingly which includes io start_time, the origin bio and cloned bio. Then we can call bio_{start,end}_io_acct to get related io status. Signed-off-by: Guoqing Jiang <jiangguoqing@kylinos.cn> Signed-off-by: Song Liu <song@kernel.org>
This commit is contained in:
parent
ad3fc79880
commit
10764815ff
4 changed files with 68 additions and 3 deletions
|
@ -2340,7 +2340,8 @@ int md_integrity_register(struct mddev *mddev)
|
||||||
bdev_get_integrity(reference->bdev));
|
bdev_get_integrity(reference->bdev));
|
||||||
|
|
||||||
pr_debug("md: data integrity enabled on %s\n", mdname(mddev));
|
pr_debug("md: data integrity enabled on %s\n", mdname(mddev));
|
||||||
if (bioset_integrity_create(&mddev->bio_set, BIO_POOL_SIZE)) {
|
if (bioset_integrity_create(&mddev->bio_set, BIO_POOL_SIZE) ||
|
||||||
|
bioset_integrity_create(&mddev->io_acct_set, BIO_POOL_SIZE)) {
|
||||||
pr_err("md: failed to create integrity pool for %s\n",
|
pr_err("md: failed to create integrity pool for %s\n",
|
||||||
mdname(mddev));
|
mdname(mddev));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -5569,6 +5570,7 @@ static void md_free(struct kobject *ko)
|
||||||
|
|
||||||
bioset_exit(&mddev->bio_set);
|
bioset_exit(&mddev->bio_set);
|
||||||
bioset_exit(&mddev->sync_set);
|
bioset_exit(&mddev->sync_set);
|
||||||
|
bioset_exit(&mddev->io_acct_set);
|
||||||
kfree(mddev);
|
kfree(mddev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5862,7 +5864,13 @@ int md_run(struct mddev *mddev)
|
||||||
if (!bioset_initialized(&mddev->sync_set)) {
|
if (!bioset_initialized(&mddev->sync_set)) {
|
||||||
err = bioset_init(&mddev->sync_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
|
err = bioset_init(&mddev->sync_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
goto exit_bio_set;
|
||||||
|
}
|
||||||
|
if (!bioset_initialized(&mddev->io_acct_set)) {
|
||||||
|
err = bioset_init(&mddev->io_acct_set, BIO_POOL_SIZE,
|
||||||
|
offsetof(struct md_io_acct, bio_clone), 0);
|
||||||
|
if (err)
|
||||||
|
goto exit_sync_set;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock(&pers_lock);
|
spin_lock(&pers_lock);
|
||||||
|
@ -5990,6 +5998,7 @@ int md_run(struct mddev *mddev)
|
||||||
blk_queue_flag_set(QUEUE_FLAG_NONROT, mddev->queue);
|
blk_queue_flag_set(QUEUE_FLAG_NONROT, mddev->queue);
|
||||||
else
|
else
|
||||||
blk_queue_flag_clear(QUEUE_FLAG_NONROT, mddev->queue);
|
blk_queue_flag_clear(QUEUE_FLAG_NONROT, mddev->queue);
|
||||||
|
blk_queue_flag_set(QUEUE_FLAG_IO_STAT, mddev->queue);
|
||||||
}
|
}
|
||||||
if (pers->sync_request) {
|
if (pers->sync_request) {
|
||||||
if (mddev->kobj.sd &&
|
if (mddev->kobj.sd &&
|
||||||
|
@ -6039,8 +6048,11 @@ bitmap_abort:
|
||||||
module_put(pers->owner);
|
module_put(pers->owner);
|
||||||
md_bitmap_destroy(mddev);
|
md_bitmap_destroy(mddev);
|
||||||
abort:
|
abort:
|
||||||
bioset_exit(&mddev->bio_set);
|
bioset_exit(&mddev->io_acct_set);
|
||||||
|
exit_sync_set:
|
||||||
bioset_exit(&mddev->sync_set);
|
bioset_exit(&mddev->sync_set);
|
||||||
|
exit_bio_set:
|
||||||
|
bioset_exit(&mddev->bio_set);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(md_run);
|
EXPORT_SYMBOL_GPL(md_run);
|
||||||
|
@ -6264,6 +6276,7 @@ void md_stop(struct mddev *mddev)
|
||||||
__md_stop(mddev);
|
__md_stop(mddev);
|
||||||
bioset_exit(&mddev->bio_set);
|
bioset_exit(&mddev->bio_set);
|
||||||
bioset_exit(&mddev->sync_set);
|
bioset_exit(&mddev->sync_set);
|
||||||
|
bioset_exit(&mddev->io_acct_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(md_stop);
|
EXPORT_SYMBOL_GPL(md_stop);
|
||||||
|
@ -8568,6 +8581,38 @@ void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(md_submit_discard_bio);
|
EXPORT_SYMBOL_GPL(md_submit_discard_bio);
|
||||||
|
|
||||||
|
static void md_end_io_acct(struct bio *bio)
|
||||||
|
{
|
||||||
|
struct md_io_acct *md_io_acct = bio->bi_private;
|
||||||
|
struct bio *orig_bio = md_io_acct->orig_bio;
|
||||||
|
|
||||||
|
orig_bio->bi_status = bio->bi_status;
|
||||||
|
|
||||||
|
bio_end_io_acct(orig_bio, md_io_acct->start_time);
|
||||||
|
bio_put(bio);
|
||||||
|
bio_endio(orig_bio);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* used by personalities (raid0 and raid5) to account io stats */
|
||||||
|
void md_account_bio(struct mddev *mddev, struct bio **bio)
|
||||||
|
{
|
||||||
|
struct md_io_acct *md_io_acct;
|
||||||
|
struct bio *clone;
|
||||||
|
|
||||||
|
if (!blk_queue_io_stat((*bio)->bi_bdev->bd_disk->queue))
|
||||||
|
return;
|
||||||
|
|
||||||
|
clone = bio_clone_fast(*bio, GFP_NOIO, &mddev->io_acct_set);
|
||||||
|
md_io_acct = container_of(clone, struct md_io_acct, bio_clone);
|
||||||
|
md_io_acct->orig_bio = *bio;
|
||||||
|
md_io_acct->start_time = bio_start_io_acct(*bio);
|
||||||
|
|
||||||
|
clone->bi_end_io = md_end_io_acct;
|
||||||
|
clone->bi_private = md_io_acct;
|
||||||
|
*bio = clone;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(md_account_bio);
|
||||||
|
|
||||||
/* md_allow_write(mddev)
|
/* md_allow_write(mddev)
|
||||||
* Calling this ensures that the array is marked 'active' so that writes
|
* Calling this ensures that the array is marked 'active' so that writes
|
||||||
* may proceed without blocking. It is important to call this before
|
* may proceed without blocking. It is important to call this before
|
||||||
|
|
|
@ -487,6 +487,7 @@ struct mddev {
|
||||||
struct bio_set sync_set; /* for sync operations like
|
struct bio_set sync_set; /* for sync operations like
|
||||||
* metadata and bitmap writes
|
* metadata and bitmap writes
|
||||||
*/
|
*/
|
||||||
|
struct bio_set io_acct_set; /* for raid0 and raid5 io accounting */
|
||||||
|
|
||||||
/* Generic flush handling.
|
/* Generic flush handling.
|
||||||
* The last to finish preflush schedules a worker to submit
|
* The last to finish preflush schedules a worker to submit
|
||||||
|
@ -683,6 +684,12 @@ struct md_thread {
|
||||||
void *private;
|
void *private;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct md_io_acct {
|
||||||
|
struct bio *orig_bio;
|
||||||
|
unsigned long start_time;
|
||||||
|
struct bio bio_clone;
|
||||||
|
};
|
||||||
|
|
||||||
#define THREAD_WAKEUP 0
|
#define THREAD_WAKEUP 0
|
||||||
|
|
||||||
static inline void safe_put_page(struct page *p)
|
static inline void safe_put_page(struct page *p)
|
||||||
|
@ -714,6 +721,7 @@ extern void md_error(struct mddev *mddev, struct md_rdev *rdev);
|
||||||
extern void md_finish_reshape(struct mddev *mddev);
|
extern void md_finish_reshape(struct mddev *mddev);
|
||||||
void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
|
void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
|
||||||
struct bio *bio, sector_t start, sector_t size);
|
struct bio *bio, sector_t start, sector_t size);
|
||||||
|
void md_account_bio(struct mddev *mddev, struct bio **bio);
|
||||||
|
|
||||||
extern bool __must_check md_flush_request(struct mddev *mddev, struct bio *bio);
|
extern bool __must_check md_flush_request(struct mddev *mddev, struct bio *bio);
|
||||||
extern void md_super_write(struct mddev *mddev, struct md_rdev *rdev,
|
extern void md_super_write(struct mddev *mddev, struct md_rdev *rdev,
|
||||||
|
|
|
@ -546,6 +546,9 @@ static bool raid0_make_request(struct mddev *mddev, struct bio *bio)
|
||||||
bio = split;
|
bio = split;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bio->bi_pool != &mddev->bio_set)
|
||||||
|
md_account_bio(mddev, &bio);
|
||||||
|
|
||||||
orig_sector = sector;
|
orig_sector = sector;
|
||||||
zone = find_zone(mddev->private, §or);
|
zone = find_zone(mddev->private, §or);
|
||||||
switch (conf->layout) {
|
switch (conf->layout) {
|
||||||
|
|
|
@ -5468,6 +5468,7 @@ static struct bio *chunk_aligned_read(struct mddev *mddev, struct bio *raid_bio)
|
||||||
sector_t sector = raid_bio->bi_iter.bi_sector;
|
sector_t sector = raid_bio->bi_iter.bi_sector;
|
||||||
unsigned chunk_sects = mddev->chunk_sectors;
|
unsigned chunk_sects = mddev->chunk_sectors;
|
||||||
unsigned sectors = chunk_sects - (sector & (chunk_sects-1));
|
unsigned sectors = chunk_sects - (sector & (chunk_sects-1));
|
||||||
|
struct r5conf *conf = mddev->private;
|
||||||
|
|
||||||
if (sectors < bio_sectors(raid_bio)) {
|
if (sectors < bio_sectors(raid_bio)) {
|
||||||
struct r5conf *conf = mddev->private;
|
struct r5conf *conf = mddev->private;
|
||||||
|
@ -5477,6 +5478,9 @@ static struct bio *chunk_aligned_read(struct mddev *mddev, struct bio *raid_bio)
|
||||||
raid_bio = split;
|
raid_bio = split;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (raid_bio->bi_pool != &conf->bio_split)
|
||||||
|
md_account_bio(mddev, &raid_bio);
|
||||||
|
|
||||||
if (!raid5_read_one_chunk(mddev, raid_bio))
|
if (!raid5_read_one_chunk(mddev, raid_bio))
|
||||||
return raid_bio;
|
return raid_bio;
|
||||||
|
|
||||||
|
@ -5756,6 +5760,7 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
|
||||||
DEFINE_WAIT(w);
|
DEFINE_WAIT(w);
|
||||||
bool do_prepare;
|
bool do_prepare;
|
||||||
bool do_flush = false;
|
bool do_flush = false;
|
||||||
|
bool do_clone = false;
|
||||||
|
|
||||||
if (unlikely(bi->bi_opf & REQ_PREFLUSH)) {
|
if (unlikely(bi->bi_opf & REQ_PREFLUSH)) {
|
||||||
int ret = log_handle_flush_request(conf, bi);
|
int ret = log_handle_flush_request(conf, bi);
|
||||||
|
@ -5784,6 +5789,7 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
|
||||||
if (rw == READ && mddev->degraded == 0 &&
|
if (rw == READ && mddev->degraded == 0 &&
|
||||||
mddev->reshape_position == MaxSector) {
|
mddev->reshape_position == MaxSector) {
|
||||||
bi = chunk_aligned_read(mddev, bi);
|
bi = chunk_aligned_read(mddev, bi);
|
||||||
|
do_clone = true;
|
||||||
if (!bi)
|
if (!bi)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -5798,6 +5804,9 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
|
||||||
last_sector = bio_end_sector(bi);
|
last_sector = bio_end_sector(bi);
|
||||||
bi->bi_next = NULL;
|
bi->bi_next = NULL;
|
||||||
|
|
||||||
|
if (!do_clone)
|
||||||
|
md_account_bio(mddev, &bi);
|
||||||
|
|
||||||
prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE);
|
prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE);
|
||||||
for (; logical_sector < last_sector; logical_sector += RAID5_STRIPE_SECTORS(conf)) {
|
for (; logical_sector < last_sector; logical_sector += RAID5_STRIPE_SECTORS(conf)) {
|
||||||
int previous;
|
int previous;
|
||||||
|
|
Loading…
Add table
Reference in a new issue