[Devel] [PATCH VZ10 02/11] block/bio: add bio_issue_elapsed_ns()
Andrey Zhadchenko
andrey.zhadchenko at virtuozzo.com
Thu Jul 23 23:17:24 MSK 2026
On 7/17/26 17:06, Pavel Tikhomirov wrote:
>
>
> On 7/13/26 02:36, Andrey Zhadchenko wrote:
>> If blkcgroup is present, each bio is stamped at the issue time.
>> Expose this via bio_issue_elapsed_ns() so we can accurately
>> calculate total time spent in the block layer.
>>
>> https://virtuozzo.atlassian.net/browse/VSTOR-103846
>> Signed-off-by: Andrey Zhadchenko <andrey.zhadchenko at virtuozzo.com>
>> ---
>> block/bio.c | 23 +++++++++++++++++++++++
>> include/linux/bio.h | 2 ++
>> 2 files changed, 25 insertions(+)
>>
>> diff --git a/block/bio.c b/block/bio.c
>> index 3c0a558c90f52..c26babfc5e1ce 100644
>> --- a/block/bio.c
>> +++ b/block/bio.c
>> @@ -1827,6 +1827,29 @@ int bioset_init(struct bio_set *bs,
>> }
>> EXPORT_SYMBOL(bioset_init);
>>
>> +/*
>> + * bio_issue_elapsed_ns - calculate elapsed time since issue
>> + * @bio: bio
>> + *
>> + * Return the elapsed nanoseconds since bio issue until now,
>> + * handling the 51-bit wraparound.
>> + */
>> +u64 bio_issue_elapsed_ns(struct bio *bio)
>> +{
>> +#ifdef CONFIG_BLK_CGROUP
>> + u64 now, elapsed;
>> +
>> + /* Mask both operands to 51 bits before the modular subtraction. */
>> + now = __bio_issue_time(blk_time_get_ns());
>> + elapsed = now - bio_issue_time(&bio->bi_issue);
>> +
>> + return elapsed & BIO_ISSUE_TIME_MASK;
>
> In ideal world (if now >= elapsed) this masking is not needed.
> Otherwise, I guess, it does not help either.
> See how iolatency_record_time() does no post-masking.
It is helping though. BIO_ISSUE_TIME_MASK is 2^51 - 1. It looks much,
but this is nanoseconds and wraps around eventually. Not so fast, but
the value seems reachable: 2^51 ns ~ 2*10^15ns ~ 2*10^6s. Given there is
86400 seconds in a day, 2000000/86400 is a somehow comparable to a
month. So bi_issue becomes bigger than masked now when they sit around 2^51.
Let's imagine bi->issue is 2^51 - 12345, blk_time_get_ns() returns 2^51
+ 12345. So the real elapsed time is 24690.
Following the code,
1. now is truncated to 12345
2. elapsed = 12345 - (2^51 - 12345) ->
unsigned integer underflow is defined behavior, so
-> 2^64 - 2^51 + 24690
3. Then we again apply our mask, 2^64 and 2^51 vanish, so we get 24690.
Checks!
BUT if the bio spent more then 2^51 ns before completing, we will mask
the duration along with it. Probably there will be more serious issues...
We can also skip transition case as you suggest, but then after
returning zero some bios may be recorded into wrong buckets as they will
default to non-precise service time counting.
Probably not so critical to bin some bios in the wrong bucket every
month. But the wrapping still helps. What do you think?
Also note that mainstream removed the mask and bi_issue is fully 2^64 in
latest versions, so we will eventually simplify this helper too and
avoid the problem.
>
> In case I miss something and it's needed, consider using __bio_issue_time() helper.
>
>> +#else
>> + return 0;
>> +#endif
>> +}
>> +EXPORT_SYMBOL_GPL(bio_issue_elapsed_ns);
>> +
>> static int __init init_bio(void)
>> {
>> int i;
>> diff --git a/include/linux/bio.h b/include/linux/bio.h
>> index 46ffac5caab78..00c116207a25a 100644
>> --- a/include/linux/bio.h
>> +++ b/include/linux/bio.h
>> @@ -714,4 +714,6 @@ struct bio *bio_chain_and_submit(struct bio *prev, struct bio *new);
>> struct bio *blk_alloc_discard_bio(struct block_device *bdev,
>> sector_t *sector, sector_t *nr_sects, gfp_t gfp_mask);
>>
>> +u64 bio_issue_elapsed_ns(struct bio *bio);
>> +
>> #endif /* __LINUX_BIO_H */
>
More information about the Devel
mailing list