mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 13:14:02 +02:00
md/md-llbitmap: allocate page controls independently
Allocate one llbitmap page-control object at a time and free each object through the same model. Let llbitmap_read_page() return a zeroed page without reading disk when the page index is beyond the current bitmap size, so page-control allocation no longer needs a separate read_existing flag. This keeps the llbitmap page-control lifetime self-consistent and prepares the page-cache code for later in-place growth. Reviewed-by: Su Yue <glass.su@suse.com> Tested-by: Mykola Marzhan <mykola@meshstor.io> Link: https://patch.msgid.link/20260802195038.164272-15-yukuai@kernel.org Signed-off-by: Yu Kuai <yukuai@fygo.io>
This commit is contained in:
parent
35320d21e8
commit
e9f0d66b57
|
|
@ -512,13 +512,19 @@ static void llbitmap_write(struct llbitmap *llbitmap, enum llbitmap_state state,
|
|||
llbitmap_set_page_dirty(llbitmap, idx, bit, false);
|
||||
}
|
||||
|
||||
static unsigned int llbitmap_used_pages(struct llbitmap *llbitmap,
|
||||
unsigned long chunks)
|
||||
{
|
||||
return DIV_ROUND_UP(chunks + BITMAP_DATA_OFFSET, PAGE_SIZE);
|
||||
}
|
||||
|
||||
static struct page *llbitmap_read_page(struct llbitmap *llbitmap, int idx)
|
||||
{
|
||||
struct mddev *mddev = llbitmap->mddev;
|
||||
struct page *page = NULL;
|
||||
struct md_rdev *rdev;
|
||||
|
||||
if (llbitmap->pctl && llbitmap->pctl[idx])
|
||||
if (llbitmap->pctl && idx < llbitmap->nr_pages && llbitmap->pctl[idx])
|
||||
page = llbitmap->pctl[idx]->page;
|
||||
if (page)
|
||||
return page;
|
||||
|
|
@ -526,6 +532,8 @@ static struct page *llbitmap_read_page(struct llbitmap *llbitmap, int idx)
|
|||
page = alloc_page(GFP_NOIO | __GFP_ZERO);
|
||||
if (!page)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (idx >= llbitmap_used_pages(llbitmap, llbitmap->chunks))
|
||||
return page;
|
||||
|
||||
rdev_for_each(rdev, mddev) {
|
||||
sector_t sector;
|
||||
|
|
@ -596,61 +604,78 @@ static void llbitmap_free_pages(struct llbitmap *llbitmap)
|
|||
for (i = 0; i < llbitmap->nr_pages; i++) {
|
||||
struct llbitmap_page_ctl *pctl = llbitmap->pctl[i];
|
||||
|
||||
if (!pctl || !pctl->page)
|
||||
break;
|
||||
|
||||
__free_page(pctl->page);
|
||||
if (!pctl)
|
||||
continue;
|
||||
if (pctl->page)
|
||||
__free_page(pctl->page);
|
||||
percpu_ref_exit(&pctl->active);
|
||||
kfree(pctl);
|
||||
}
|
||||
|
||||
kfree(llbitmap->pctl[0]);
|
||||
kfree(llbitmap->pctl);
|
||||
llbitmap->pctl = NULL;
|
||||
}
|
||||
|
||||
static int llbitmap_cache_pages(struct llbitmap *llbitmap)
|
||||
static struct llbitmap_page_ctl *
|
||||
llbitmap_alloc_page_ctl(struct llbitmap *llbitmap, int idx)
|
||||
{
|
||||
struct llbitmap_page_ctl *pctl;
|
||||
unsigned int nr_pages = DIV_ROUND_UP(llbitmap->chunks +
|
||||
BITMAP_DATA_OFFSET, PAGE_SIZE);
|
||||
struct page *page;
|
||||
unsigned int size = struct_size(pctl, dirty, BITS_TO_LONGS(
|
||||
llbitmap->blocks_per_page));
|
||||
|
||||
size = round_up(size, cache_line_size());
|
||||
pctl = kzalloc(size, GFP_NOIO);
|
||||
if (!pctl)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
page = llbitmap_read_page(llbitmap, idx);
|
||||
|
||||
if (IS_ERR(page)) {
|
||||
kfree(pctl);
|
||||
return ERR_CAST(page);
|
||||
}
|
||||
|
||||
if (percpu_ref_init(&pctl->active, active_release,
|
||||
PERCPU_REF_ALLOW_REINIT, GFP_NOIO)) {
|
||||
__free_page(page);
|
||||
kfree(pctl);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
pctl->page = page;
|
||||
pctl->state = page_address(page);
|
||||
init_waitqueue_head(&pctl->wait);
|
||||
return pctl;
|
||||
}
|
||||
|
||||
static unsigned int llbitmap_reserved_pages(struct llbitmap *llbitmap)
|
||||
{
|
||||
return DIV_ROUND_UP(llbitmap->mddev->bitmap_info.space << SECTOR_SHIFT,
|
||||
PAGE_SIZE);
|
||||
}
|
||||
|
||||
static int llbitmap_alloc_pages(struct llbitmap *llbitmap)
|
||||
{
|
||||
unsigned int used_pages = llbitmap_used_pages(llbitmap, llbitmap->chunks);
|
||||
unsigned int nr_pages = max(used_pages, llbitmap_reserved_pages(llbitmap));
|
||||
int i;
|
||||
|
||||
llbitmap->pctl = kmalloc_array(nr_pages, sizeof(void *),
|
||||
GFP_NOIO | __GFP_ZERO);
|
||||
llbitmap->pctl = kcalloc(nr_pages, sizeof(*llbitmap->pctl), GFP_NOIO);
|
||||
if (!llbitmap->pctl)
|
||||
return -ENOMEM;
|
||||
|
||||
size = round_up(size, cache_line_size());
|
||||
pctl = kmalloc_array(nr_pages, size, GFP_NOIO | __GFP_ZERO);
|
||||
if (!pctl) {
|
||||
kfree(llbitmap->pctl);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
llbitmap->nr_pages = nr_pages;
|
||||
|
||||
for (i = 0; i < nr_pages; i++, pctl = (void *)pctl + size) {
|
||||
struct page *page = llbitmap_read_page(llbitmap, i);
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
llbitmap->pctl[i] = llbitmap_alloc_page_ctl(llbitmap, i);
|
||||
if (IS_ERR(llbitmap->pctl[i])) {
|
||||
int ret = PTR_ERR(llbitmap->pctl[i]);
|
||||
|
||||
llbitmap->pctl[i] = pctl;
|
||||
|
||||
if (IS_ERR(page)) {
|
||||
llbitmap->pctl[i] = NULL;
|
||||
llbitmap_free_pages(llbitmap);
|
||||
return PTR_ERR(page);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (percpu_ref_init(&pctl->active, active_release,
|
||||
PERCPU_REF_ALLOW_REINIT, GFP_NOIO)) {
|
||||
__free_page(page);
|
||||
llbitmap_free_pages(llbitmap);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pctl->page = page;
|
||||
pctl->state = page_address(page);
|
||||
init_waitqueue_head(&pctl->wait);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -924,7 +949,7 @@ static int llbitmap_init(struct llbitmap *llbitmap)
|
|||
llbitmap->sync_size = blocks;
|
||||
mddev->bitmap_info.daemon_sleep = DEFAULT_DAEMON_SLEEP;
|
||||
|
||||
ret = llbitmap_cache_pages(llbitmap);
|
||||
ret = llbitmap_alloc_pages(llbitmap);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -1038,7 +1063,7 @@ static int llbitmap_read_sb(struct llbitmap *llbitmap)
|
|||
llbitmap->chunks = DIV_ROUND_UP_SECTOR_T(sync_size, chunksize);
|
||||
llbitmap->chunkshift = ffz(~chunksize);
|
||||
llbitmap->sync_size = sync_size;
|
||||
ret = llbitmap_cache_pages(llbitmap);
|
||||
ret = llbitmap_alloc_pages(llbitmap);
|
||||
|
||||
out_put_page:
|
||||
__free_page(sb_page);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user