From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CF02A2F1FEA; Sun, 2 Aug 2026 19:51:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700300; cv=none; b=bOb2DXAFg7EOfnMnsJd+VkrErYqPhaHbge5PxE18lb4GMlFaWhduRyInzgS2CrFveD6HiVKSX9VzSOxKJNKf8XOy77waa599j/c7/U6Q6NYwjX/BrAoNGuATmjVCD6TxGLghP9e1E3rZpGImP5wz4+Rmghif5AwogVRtFhyv0jU= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785700300; c=relaxed/simple; bh=c1vYLYUv45quP/gFZnFqwcW3id/Y6lrfHIFoIdy8k2w=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=IdEXBb9o/NQ0Uvhc4XGDVm3A+p2dURTsLIdnBe5nzAbNtIhlgfOUzJUawF34fKidCR4r5lXMmEtXJs7kgaeNkkNfmCodRzLavm8z5sjLsoSlR2relOzgRzOYIqfBssC07/0b448nOhavwioFB4M1ytUDsKfrQMH2+8OPfW8Jn1o= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=R2cHPt0z; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="R2cHPt0z" Received: by smtp.kernel.org (Postfix) with ESMTPSA id ECAD51F000E9; Sun, 2 Aug 2026 19:51:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785700298; bh=Pyxb5ixBGyVEK4ViIPlMA4hkma7e+3/Jmkws8oBWmEA=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=R2cHPt0zUJV9osj3JZbYbOGNyj19EtXWojRomGOBELQmQAxadA4oFy9jKPeG0khWJ bD2I2hcrjK+ny3fH4FpcIpjog0blyOSiwkJ/U9QoCYSfl9td1DFKb1pV3+Fajzmvkt mqlWBSyvtS0Thsro9ORDyOhZEXF49NtkeYeaYdsIbvQs+ODncegUXTXyrJKPW1EExA TzfYteJVrzCfWhRXxlk25N2PSyWCbKe2AoKJ9IhqKjXejp3DrAd2QeT2MsdRq66NXd l2UdaEtGSxcld/Bz1DjHoktj6Vq4/u5bvs0bn07QbfaVdNAko5IlZMii/iXXQSK4IR ZGHSPVcf3xyhw== From: Yu Kuai To: Song Liu , Li Nan , Xiao Ni Cc: Yu Kuai , linux-raid@vger.kernel.org, linux-kernel@vger.kernel.org, Mykola Marzhan , Su Yue Subject: [PATCH v5 14/29] md/md-llbitmap: allocate page controls independently Date: Mon, 3 Aug 2026 03:50:23 +0800 Message-ID: <20260802195038.164272-15-yukuai@kernel.org> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260802195038.164272-1-yukuai@kernel.org> References: <20260802195038.164272-1-yukuai@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Yu Kuai 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 Tested-by: Mykola Marzhan Signed-off-by: Yu Kuai --- drivers/md/md-llbitmap.c | 99 +++++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 37 deletions(-) diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c index 0813cebfbdeb..300dd8b93b01 100644 --- a/drivers/md/md-llbitmap.c +++ b/drivers/md/md-llbitmap.c @@ -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)); - int i; - - llbitmap->pctl = kmalloc_array(nr_pages, sizeof(void *), - GFP_NOIO | __GFP_ZERO); - 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; + 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); } - llbitmap->nr_pages = nr_pages; + if (percpu_ref_init(&pctl->active, active_release, + PERCPU_REF_ALLOW_REINIT, GFP_NOIO)) { + __free_page(page); + kfree(pctl); + return ERR_PTR(-ENOMEM); + } - for (i = 0; i < nr_pages; i++, pctl = (void *)pctl + size) { - struct page *page = llbitmap_read_page(llbitmap, i); + pctl->page = page; + pctl->state = page_address(page); + init_waitqueue_head(&pctl->wait); + return pctl; +} - llbitmap->pctl[i] = pctl; +static unsigned int llbitmap_reserved_pages(struct llbitmap *llbitmap) +{ + return DIV_ROUND_UP(llbitmap->mddev->bitmap_info.space << SECTOR_SHIFT, + PAGE_SIZE); +} - if (IS_ERR(page)) { - llbitmap_free_pages(llbitmap); - return PTR_ERR(page); - } +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 = kcalloc(nr_pages, sizeof(*llbitmap->pctl), GFP_NOIO); + if (!llbitmap->pctl) + return -ENOMEM; - if (percpu_ref_init(&pctl->active, active_release, - PERCPU_REF_ALLOW_REINIT, GFP_NOIO)) { - __free_page(page); + llbitmap->nr_pages = nr_pages; + + 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] = NULL; llbitmap_free_pages(llbitmap); - return -ENOMEM; + return ret; } - - 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); -- 2.51.0