Message ID | ZN0p5_W-Q9mAHBVY@slm.duckdns.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [for-6.6/block] blk-cgroup: Fix NULL deref caused by blkg_policy_data being installed before init | expand |
On Wed, 16 Aug 2023 09:56:23 -1000, Tejun Heo wrote: > blk-iocost sometimes causes the following crash: > > BUG: kernel NULL pointer dereference, address: 00000000000000e0 > ... > RIP: 0010:_raw_spin_lock+0x17/0x30 > Code: be 01 02 00 00 e8 79 38 39 ff 31 d2 89 d0 5d c3 0f 1f 00 0f 1f 44 00 00 55 48 89 e5 65 ff 05 48 d0 34 7e b9 01 00 00 00 31 c0 <f0> 0f b1 0f 75 02 5d c3 89 c6 e8 ea 04 00 00 5d c3 0f 1f 84 00 00 > RSP: 0018:ffffc900023b3d40 EFLAGS: 00010046 > RAX: 0000000000000000 RBX: 00000000000000e0 RCX: 0000000000000001 > RDX: ffffc900023b3d20 RSI: ffffc900023b3cf0 RDI: 00000000000000e0 > RBP: ffffc900023b3d40 R08: ffffc900023b3c10 R09: 0000000000000003 > R10: 0000000000000064 R11: 000000000000000a R12: ffff888102337000 > R13: fffffffffffffff2 R14: ffff88810af408c8 R15: ffff8881070c3600 > FS: 00007faaaf364fc0(0000) GS:ffff88842fdc0000(0000) knlGS:0000000000000000 > CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 > CR2: 00000000000000e0 CR3: 00000001097b1000 CR4: 0000000000350ea0 > Call Trace: > <TASK> > ioc_weight_write+0x13d/0x410 > cgroup_file_write+0x7a/0x130 > kernfs_fop_write_iter+0xf5/0x170 > vfs_write+0x298/0x370 > ksys_write+0x5f/0xb0 > __x64_sys_write+0x1b/0x20 > do_syscall_64+0x3d/0x80 > entry_SYSCALL_64_after_hwframe+0x46/0xb0 > > [...] Applied, thanks! [1/1] blk-cgroup: Fix NULL deref caused by blkg_policy_data being installed before init commit: ec14a87ee1999b19d8b7ed0fa95fea80644624ae Best regards,
--- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -1509,7 +1509,7 @@ int blkcg_activate_policy(struct gendisk retry: spin_lock_irq(&q->queue_lock); - /* blkg_list is pushed at the head, reverse walk to allocate parents first */ + /* blkg_list is pushed at the head, reverse walk to initialize parents first */ list_for_each_entry_reverse(blkg, &q->blkg_list, q_node) { struct blkg_policy_data *pd; @@ -1547,21 +1547,20 @@ retry: goto enomem; } - blkg->pd[pol->plid] = pd; + spin_lock(&blkg->blkcg->lock); + pd->blkg = blkg; pd->plid = pol->plid; - pd->online = false; - } + blkg->pd[pol->plid] = pd; - /* all allocated, init in the same order */ - if (pol->pd_init_fn) - list_for_each_entry_reverse(blkg, &q->blkg_list, q_node) - pol->pd_init_fn(blkg->pd[pol->plid]); + if (pol->pd_init_fn) + pol->pd_init_fn(pd); - list_for_each_entry_reverse(blkg, &q->blkg_list, q_node) { if (pol->pd_online_fn) - pol->pd_online_fn(blkg->pd[pol->plid]); - blkg->pd[pol->plid]->online = true; + pol->pd_online_fn(pd); + pd->online = true; + + spin_unlock(&blkg->blkcg->lock); } __set_bit(pol->plid, q->blkcg_pols); @@ -1578,14 +1577,19 @@ out: return ret; enomem: - /* alloc failed, nothing's initialized yet, free everything */ + /* alloc failed, take down everything */ spin_lock_irq(&q->queue_lock); list_for_each_entry(blkg, &q->blkg_list, q_node) { struct blkcg *blkcg = blkg->blkcg; + struct blkg_policy_data *pd; spin_lock(&blkcg->lock); - if (blkg->pd[pol->plid]) { - pol->pd_free_fn(blkg->pd[pol->plid]); + pd = blkg->pd[pol->plid]; + if (pd) { + if (pd->online && pol->pd_offline_fn) + pol->pd_offline_fn(pd); + pd->online = false; + pol->pd_free_fn(pd); blkg->pd[pol->plid] = NULL; } spin_unlock(&blkcg->lock);