rue/io: check blkcg exist before doing account cgroup IO

It is possible block cgroup removed before io_completion,
and this happened in common IO path without switch to disable.

Add validation check before accounting. and use kernel.io_qos
switch to guard this function.

Oops message:
---
  BUG: kernel NULL pointer dereference, address: 0000000000000200
  CPU: 8 PID: 0 Comm: swapper/8 Kdump: loaded Tainted: G           O  K
  5.4.119-1-tlinux4-0007 #1

  RIP: 0010:blkcg_dkstats_find_create+0x16/0x250

  RSP: 0018:ffffc900069c0e80 EFLAGS: 00010082
  RAX: 0000000000000001 RBX: 000000000000a000 RCX: ffff89871191e848
  RDX: ffff89871191e848 RSI: 0000000000000008 RDI: 0000000000000000
  RBP: ffffc900069c0ee8 R08: 0000000000000000 R09: 0000000000000000
  R10: 0000000000000000 R11: 0000000000000008 R12: 000000000000a000
  R13: ffff898711a30000 R14: ffff898cf0c97100 R15: ffff89871191e848
  FS:  0000000000000000(0000) GS:ffff89871e600000(0000)
  knlGS:0000000000000000
  CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
  CR2: 0000000000000200 CR3: 00000106bdc6e000 CR4: 00000000003506e0
  Call Trace:
   <IRQ>
    ? xfs_end_bio+0x9a/0xe0 [xfs]
    ? sbitmap_queue_clear+0x41/0x70
      blk_update_request+0xd5/0x540
      blk_mq_end_request+0x20/0x120
      virtblk_request_done+0x3b/0x90
      __blk_mq_complete_request_remote+0x13/0x20
      flush_smp_call_function_queue+0x6b/0xe0
      generic_smp_call_function_single_interrupt+0x13/0x30
      smp_call_function_single_interrupt+0x3d/0xd0
      call_function_single_interrupt+0xf/0x20
   </IRQ>
---

Signed-off-by: Haisu Wang <haisuwang@tencent.com>
This commit is contained in:
Haisu Wang 2025-01-07 18:45:16 +08:00
parent 0b24bb19f3
commit 5161cf4ca0
3 changed files with 17 additions and 3 deletions

View File

@ -60,7 +60,10 @@ struct disk_stats_sum {
static inline int blkcg_do_io_stat(struct blkcg *blkcg)
{
return blkcg->dkstats_on;
if (blkcg)
return blkcg->dkstats_on;
return 0;
}
struct disk_stats *blkcg_dkstats_find(struct blkcg *blkcg,

View File

@ -10,6 +10,7 @@
#include <linux/scatterlist.h>
#include <linux/part_stat.h>
#include <linux/blk-cgroup.h>
#include <linux/rue.h>
#include <trace/events/block.h>
@ -976,7 +977,7 @@ static void blkcg_stat_acct(struct bio *bio, struct request *req, int new_io)
struct blkcg *blkcg = css_to_blkcg(bio_blkcg_css(bio));
int rw = rq_data_dir(req);
if (!new_io) {
if (rue_io_enabled() && blkcg && !new_io) {
part_stat_lock_rcu();
blkcg_part_stat_inc(blkcg, part, merges[rw]);
part_stat_unlock_rcu();

View File

@ -30,6 +30,7 @@
#include <linux/blk-crypto.h>
#include <linux/part_stat.h>
#include <linux/sli.h>
#include <linux/rue.h>
#include <trace/events/block.h>
@ -918,12 +919,18 @@ void blkcg_account_io_completion(struct request *req, struct bio *bio,
struct blkcg *blkcg = css_to_blkcg(bio_blkcg_css(bio));
struct block_device *part;
if (!blkcg)
return;
#ifdef CONFIG_CGROUP_SLI
if (static_branch_unlikely(&sli_io_enabled))
sli_iolat_stat_end_check(req->alloc_time_ns, req->io_start_time_ns,
bio, blkcg);
#endif
if (!rue_io_enabled())
return;
part_stat_lock_rcu();
part = req->part;
blkcg_part_stat_add(blkcg, part, sectors[rw], bytes >> 9);
@ -939,12 +946,15 @@ void blkcg_account_io_done(struct request *req, struct bio *bio)
* normal IO on queueing nor completion. Accounting the
* containing request is enough.
*/
if (blk_do_io_stat(req) && !(req->cmd_flags & RQF_FLUSH_SEQ)) {
if (rue_io_enabled() && blk_do_io_stat(req) && !(req->cmd_flags & RQF_FLUSH_SEQ)) {
unsigned long duration = ktime_get_ns() - req->start_time_ns;
const int rw = rq_data_dir(req);
struct block_device *part = req->part;
struct blkcg *blkcg = css_to_blkcg(bio_blkcg_css(bio));
if (!blkcg)
return;
part_stat_lock_rcu();
blkcg_part_stat_inc(blkcg, part, ios[rw]);
blkcg_part_stat_add(blkcg, part, nsecs[rw], duration);