Re: [PATCH v5 02/29] md/md-llbitmap: use GFP_NOIO for cache allocations
[email protected] Sun, 02 Aug 2026 20:44:28 +0000
| Newsgroups | org.kernel.vger.linux-raid |
|---|---|
| Message-ID | <[email protected]> |
Thank you for your contribution! Sashiko AI review found 3 potential issue(= s) to consider: Pre-existing issues: - [High] `llbitmap_resize()` recalculates capacity limits but fails to real= locate the `pctl` array, causing out-of-bounds pointer dereferences during = subsequent operations. - [High] `blkdev_issue_zeroout()` is called with `GFP_KERNEL` while `mddev_= lock()` is held, risking a direct reclaim deadlock. - [High] The background timer and workqueue can re-arm each other during te= ardown, leading to a Use-After-Free of the `llbitmap` struct. -- --- Patch [2]: [PATCH v5 02/29] md/md-llbitmap: use GFP_NOIO for cache allo= cations --- commit 0ace115175e6f1ed40865ea8b812e7ca53aadaed Author: Yu Kuai <[email protected]> md/md-llbitmap: use GFP_NOIO for cache allocations This commit changes the memory allocation flags from GFP_KERNEL to GFP_NOIO= for the llbitmap object and its related structures. This change prevents direct memory reclaim from triggering block I/O while MD resize state locks are he= ld, avoiding potential deadlocks. > llbitmap allocates its in-memory page cache and page-control structures f= rom > paths that can already be holding MD reconfiguration or bitmap state lock= s. > For example, component_size_store() takes mddev_lock(), update_size() cal= ls > the personality resize method, and llbitmap_resize() can grow the page ca= che > through llbitmap_prepare_resize(). [Severity: High] This is a pre-existing issue, but the commit message claims that llbitmap_resize() grows the page cache through llbitmap_prepare_resize(). Looking at llbitmap_resize(): llbitmap_resize(struct mddev *mddev, sector_t blocks, int chunksize) { ... llbitmap->chunks =3D chunks; return 0; } The function updates the capacity limits but does not update llbitmap->nr_p= ages or reallocate the llbitmap->pctl array. The referenced llbitmap_prepare_res= ize() function does not seem to exist. Because the pctl array is not reallocated, won't subsequent I/O operations = call llbitmap_write() with an index that exceeds the original nr_pages length? llbitmap_write() calculates the index: idx =3D pos >> PAGE_SHIFT; bit =3D offset_in_page(pos); llbitmap->pctl[idx]->state[bit] =3D state; Could this lead to an out-of-bounds pointer dereference when accessing the = new chunks limit? > Use GFP_NOIO for the llbitmap object, cached bitmap pages, page controls, > page-control arrays, and percpu_ref initialization. Leave the explicit > metadata zeroout path unchanged because it is intentional bitmap I/O rath= er > than reclaim-driven allocation. [Severity: High] This isn't a bug introduced by this patch, but the commit message explicitly notes that the metadata zeroout path was left unchanged. Looking at llbitmap_zero_all_disks(), which is called during array initialization or reconfiguration with mddev_lock() held: ret =3D blkdev_issue_zeroout(rdev->bdev, rdev->data_offset, dev_sectors, GFP_KERNEL, 0); While the I/O itself is intentional, blkdev_issue_zeroout() uses the provid= ed GFP flags internally to allocate the bio and payload pages. If memory is ti= ght, won't GFP_KERNEL enter direct reclaim, potentially submitting a bio back to= the same mddev and causing a deadlock? Should this also be updated to use GFP_NOIO? > diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c > index 71e9a21b98b2e..3cd8373bc9b22 100644 > --- a/drivers/md/md-llbitmap.c > +++ b/drivers/md/md-llbitmap.c [ ... ] [Severity: High] This is a pre-existing issue, but there appears to be a resource lifecycle regression during teardown. Looking at llbitmap_destroy(): timer_delete_sync(&llbitmap->pending_timer); flush_workqueue(md_llbitmap_io_wq); ... kfree(llbitmap); If the timer had already fired and queued the daemon_work, timer_delete_syn= c() returns immediately. flush_workqueue() then blocks waiting for the work ite= m to execute. Inside md_llbitmap_daemon_fn(): if (restart) mod_timer(&llbitmap->pending_timer, jiffies + llbitmap->mddev->bitmap_info.daemon_sleep * HZ); If unexpired dirty pages are found, it sets restart =3D true and unconditio= nally calls mod_timer(), re-arming the timer while the subsystem is undergoing destruction. After flush_workqueue() finishes, llbitmap_destroy() frees the llbitmap obj= ect. When the newly re-armed timer fires, won't it access the freed object? --=20 Sashiko AI review =C2=B7 https://sashiko.dev/#/patchset/20260802195038.1642= [email protected]?part=3D2