Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions block/bio.c
Original file line number Diff line number Diff line change
Expand Up @@ -1733,6 +1733,8 @@ static inline bool bio_remaining_done(struct bio *bio)
return true;
}

rq_qos_done_split_bio(bio);

return false;
}

Expand Down
34 changes: 34 additions & 0 deletions block/blk-iolatency.c
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,39 @@ static void blkcg_iolatency_done_bio(struct rq_qos *rqos, struct bio *bio)
}
}

static void blkcg_iolatency_done_split_bio(struct rq_qos *rqos, struct bio *bio)
{
struct blkcg_gq *blkg;
struct rq_wait *rqw;
struct iolatency_grp *iolat;
int inflight = 0;

blkg = bio->bi_blkg;
if (!blkg || !bio_flagged(bio, BIO_QOS_CHAIN_CHILD))
return;

iolat = blkg_to_lat(bio->bi_blkg);
if (!iolat)
return;

if (!iolat->blkiolat->enabled)
return;

while (blkg && blkg->parent) {
iolat = blkg_to_lat(blkg);
if (!iolat) {
blkg = blkg->parent;
continue;
}
rqw = &iolat->rq_wait;

inflight = atomic_dec_return(&rqw->inflight);
WARN_ON_ONCE(inflight < 0);

blkg = blkg->parent;
}
}

static void blkcg_iolatency_exit(struct rq_qos *rqos)
{
struct blk_iolatency *blkiolat = BLKIOLATENCY(rqos);
Expand All @@ -645,6 +678,7 @@ static void blkcg_iolatency_exit(struct rq_qos *rqos)
static const struct rq_qos_ops blkcg_iolatency_ops = {
.throttle = blkcg_iolatency_throttle,
.done_bio = blkcg_iolatency_done_bio,
.done_split_bio = blkcg_iolatency_done_split_bio,
.exit = blkcg_iolatency_exit,
};

Expand Down
7 changes: 6 additions & 1 deletion block/blk-merge.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,13 @@ static struct bio *bio_submit_split(struct bio *bio, int split_sectors)
if (split_sectors) {
bio = bio_submit_split_bioset(bio, split_sectors,
&bio->bi_bdev->bd_disk->bio_split);
if (bio)
if (bio) {
bio->bi_opf |= REQ_NOMERGE;
/* Fix the issue where the inflight statistics
* of the chained bio in the QoS are incorrect.
*/
bio_set_flag(bio, BIO_QOS_CHAIN_CHILD);
}
}

return bio;
Expand Down
11 changes: 11 additions & 0 deletions block/blk-rq-qos.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ struct rq_qos_ops {
void (*cleanup)(struct rq_qos *, struct bio *);
void (*queue_depth_changed)(struct rq_qos *);
void (*exit)(struct rq_qos *);
void (*done_split_bio)(struct rq_qos *, struct bio *);
const struct blk_mq_debugfs_attr *debugfs_attrs;
};

Expand Down Expand Up @@ -108,6 +109,7 @@ void __rq_qos_throttle(struct rq_qos *rqos, struct bio *bio);
void __rq_qos_track(struct rq_qos *rqos, struct request *rq, struct bio *bio);
void __rq_qos_merge(struct rq_qos *rqos, struct request *rq, struct bio *bio);
void __rq_qos_done_bio(struct rq_qos *rqos, struct bio *bio);
void __rq_qos_done_split_bio(struct rq_qos *rqos, struct bio *bio);
void __rq_qos_queue_depth_changed(struct rq_qos *rqos);

static inline void rq_qos_cleanup(struct request_queue *q, struct bio *bio)
Expand Down Expand Up @@ -157,6 +159,15 @@ static inline void rq_qos_done_bio(struct bio *bio)
__rq_qos_done_bio(q->rq_qos, bio);
}

static inline void rq_qos_done_split_bio(struct bio *bio)
{
if (bio->bi_bdev && bio_flagged(bio, BIO_QOS_CHAIN_CHILD)) {
struct request_queue *q = bdev_get_queue(bio->bi_bdev);
if (q->rq_qos)
__rq_qos_done_split_bio(q->rq_qos, bio);
}
}

static inline void rq_qos_throttle(struct request_queue *q, struct bio *bio)
{
if (test_bit(QUEUE_FLAG_QOS_ENABLED, &q->queue_flags) && q->rq_qos) {
Expand Down
2 changes: 2 additions & 0 deletions include/linux/blk_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,8 @@ enum {
BIO_REMAPPED,
BIO_ZONE_WRITE_PLUGGING, /* bio handled through zone write plugging */
BIO_EMULATES_ZONE_APPEND, /* bio emulates a zone append operation */
BIO_QOS_CHAIN_CHILD, /* chained bio child, used for segmenting out
* the bio */
BIO_FLAG_LAST
};

Expand Down