From: Jonathan Cameron <Jonathan.Cameron@huawei.com>
To: Dongsheng Yang <dongsheng.yang@linux.dev>
Cc: <mpatocka@redhat.com>, <agk@redhat.com>, <snitzer@kernel.org>,
<axboe@kernel.dk>, <hch@lst.de>, <dan.j.williams@intel.com>,
<linux-block@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
<linux-cxl@vger.kernel.org>, <nvdimm@lists.linux.dev>,
<dm-devel@lists.linux.dev>
Subject: Re: [PATCH v1 02/11] dm-pcache: add backing device management
Date: Tue, 1 Jul 2025 14:56:50 +0100 [thread overview]
Message-ID: <20250701145650.00004e72@huawei.com> (raw)
In-Reply-To: <20250624073359.2041340-3-dongsheng.yang@linux.dev>
On Tue, 24 Jun 2025 07:33:49 +0000
Dongsheng Yang <dongsheng.yang@linux.dev> wrote:
> This patch introduces *backing_dev.{c,h}*, a self-contained layer that
> handles all interaction with the *backing block device* where cache
> write-back and cache-miss reads are serviced. Isolating this logic
> keeps the core dm-pcache code free of low-level bio plumbing.
>
> * Device setup / teardown
> - Opens the target with `dm_get_device()`, stores `bdev`, file and
> size, and initialises a dedicated `bioset`.
> - Gracefully releases resources via `backing_dev_stop()`.
>
> * Request object (`struct pcache_backing_dev_req`)
> - Two request flavours:
> - REQ-type – cloned from an upper `struct bio` issued to
> dm-pcache; trimmed and re-targeted to the backing LBA.
> - KMEM-type – maps an arbitrary kernel memory buffer
> into a freshly built.
> - Private completion callback (`end_req`) propagates status to the
> upper layer and handles resource recycling.
>
> * Submission & completion path
> - Lock-protected submit queue + worker (`req_submit_work`) let pcache
> push many requests asynchronously, at the same time, allow caller
> to submit backing_dev_req in atomic context.
> - End-io handler moves finished requests to a completion list processed
> by `req_complete_work`, ensuring callbacks run in process context.
> - Direct-submit option for non-atomic context.
>
> * Flush
> - `backing_dev_flush()` issues a flush to persist backing-device data.
>
> Signed-off-by: Dongsheng Yang <dongsheng.yang@linux.dev>
> ---
> drivers/md/dm-pcache/backing_dev.c | 292 +++++++++++++++++++++++++++++
> drivers/md/dm-pcache/backing_dev.h | 88 +++++++++
> 2 files changed, 380 insertions(+)
> create mode 100644 drivers/md/dm-pcache/backing_dev.c
> create mode 100644 drivers/md/dm-pcache/backing_dev.h
>
> diff --git a/drivers/md/dm-pcache/backing_dev.c b/drivers/md/dm-pcache/backing_dev.c
> new file mode 100644
> index 000000000000..590c6415319d
> --- /dev/null
> +++ b/drivers/md/dm-pcache/backing_dev.c
> @@ -0,0 +1,292 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +#include <linux/blkdev.h>
> +
> +#include "../dm-core.h"
> +#include "pcache_internal.h"
> +#include "cache_dev.h"
> +#include "backing_dev.h"
> +#include "cache.h"
> +#include "dm_pcache.h"
> +
> +static void backing_dev_exit(struct pcache_backing_dev *backing_dev)
> +{
> + kmem_cache_destroy(backing_dev->backing_req_cache);
> +}
> +
> +static void req_submit_fn(struct work_struct *work);
> +static void req_complete_fn(struct work_struct *work);
> +static int backing_dev_init(struct dm_pcache *pcache)
> +{
> + struct pcache_backing_dev *backing_dev = &pcache->backing_dev;
> + int ret;
> +
> + backing_dev->backing_req_cache = KMEM_CACHE(pcache_backing_dev_req, 0);
> + if (!backing_dev->backing_req_cache) {
> + ret = -ENOMEM;
return -ENOMEM;
and drop the err label.
> + goto err;
> + }
> +
> + INIT_LIST_HEAD(&backing_dev->submit_list);
> + INIT_LIST_HEAD(&backing_dev->complete_list);
> + spin_lock_init(&backing_dev->submit_lock);
> + spin_lock_init(&backing_dev->complete_lock);
> + INIT_WORK(&backing_dev->req_submit_work, req_submit_fn);
> + INIT_WORK(&backing_dev->req_complete_work, req_complete_fn);
> +
> + return 0;
> +err:
> + return ret;
> +}
> +static void req_complete_fn(struct work_struct *work)
> +{
> + struct pcache_backing_dev *backing_dev = container_of(work, struct pcache_backing_dev, req_complete_work);
Very long line. Wrap it somewhere.
> + struct pcache_backing_dev_req *backing_req;
> + LIST_HEAD(tmp_list);
> +
> + spin_lock_irq(&backing_dev->complete_lock);
> + list_splice_init(&backing_dev->complete_list, &tmp_list);
> + spin_unlock_irq(&backing_dev->complete_lock);
> +
> + while (!list_empty(&tmp_list)) {
> + backing_req = list_first_entry(&tmp_list,
> + struct pcache_backing_dev_req, node);
> + list_del_init(&backing_req->node);
> + backing_dev_req_end(backing_req);
> + }
> +}
> +
> +static void backing_dev_bio_end(struct bio *bio)
> +{
> + struct pcache_backing_dev_req *backing_req = bio->bi_private;
> + struct pcache_backing_dev *backing_dev = backing_req->backing_dev;
> + unsigned long flags;
> +
> + backing_req->ret = bio->bi_status;
> +
> + spin_lock_irqsave(&backing_dev->complete_lock, flags);
> + list_move_tail(&backing_req->node, &backing_dev->complete_list);
> + queue_work(BACKING_DEV_TO_PCACHE(backing_dev)->task_wq, &backing_dev->req_complete_work);
> + spin_unlock_irqrestore(&backing_dev->complete_lock, flags);
> +}
> +
> +static void req_submit_fn(struct work_struct *work)
> +{
> + struct pcache_backing_dev *backing_dev = container_of(work, struct pcache_backing_dev, req_submit_work);
Very long line. Wrap after =
> + struct pcache_backing_dev_req *backing_req;
> + LIST_HEAD(tmp_list);
> +
> + spin_lock(&backing_dev->submit_lock);
> + list_splice_init(&backing_dev->submit_list, &tmp_list);
> + spin_unlock(&backing_dev->submit_lock);
> +
> + while (!list_empty(&tmp_list)) {
> + backing_req = list_first_entry(&tmp_list,
> + struct pcache_backing_dev_req, node);
> + list_del_init(&backing_req->node);
> + submit_bio_noacct(&backing_req->bio);
> + }
> +}
> +
> +static void bio_map(struct bio *bio, void *base, size_t size)
> +{
> + struct page *page;
> + unsigned int offset;
> + unsigned int len;
> +
> + if (!is_vmalloc_addr(base)) {
> + page = virt_to_page(base);
> + offset = offset_in_page(base);
> +
> + BUG_ON(!bio_add_page(bio, page, size, offset));
BUG_ON(!bio_add_page(bio, virt_to_page(base), size
offset_in_page(base));
Seems readable enough. Obviously that depends on whether those
local variables get more useage in later patches.
> + return;
> + }
> +
> + flush_kernel_vmap_range(base, size);
> + while (size) {
> + page = vmalloc_to_page(base);
> + offset = offset_in_page(base);
> + len = min_t(size_t, PAGE_SIZE - offset, size);
> +
> + BUG_ON(!bio_add_page(bio, page, len, offset));
> + size -= len;
> + base += len;
> + }
> +}
> +
> +static struct pcache_backing_dev_req *kmem_type_req_create(struct pcache_backing_dev *backing_dev,
> + struct pcache_backing_dev_req_opts *opts)
> +{
> + struct pcache_backing_dev_req *backing_req;
> + struct bio *backing_bio;
> + u32 n_vecs = get_n_vecs(opts->kmem.data, opts->kmem.len);
> +
> + backing_req = kmem_cache_zalloc(backing_dev->backing_req_cache, opts->gfp_mask);
> + if (!backing_req)
> + return NULL;
> +
> + if (n_vecs > BACKING_DEV_REQ_INLINE_BVECS) {
> + backing_req->kmem.bvecs = kmalloc_array(n_vecs, sizeof(struct bio_vec), opts->gfp_mask);
> + if (!backing_req->kmem.bvecs)
> + goto err_free_req;
> + } else {
> + backing_req->kmem.bvecs = backing_req->kmem.inline_bvecs;
> + }
> +
> + backing_req->type = BACKING_DEV_REQ_TYPE_KMEM;
> +
> + bio_init(&backing_req->bio, backing_dev->dm_dev->bdev, backing_req->kmem.bvecs,
> + n_vecs, opts->kmem.opf);
Odd alignment. Align second line under &
> +
> + backing_bio = &backing_req->bio;
> + bio_map(backing_bio, opts->kmem.data, opts->kmem.len);
> +
> + backing_bio->bi_iter.bi_sector = (opts->kmem.backing_off) >> SECTOR_SHIFT;
> + backing_bio->bi_private = backing_req;
> + backing_bio->bi_end_io = backing_dev_bio_end;
> +
> + backing_req->backing_dev = backing_dev;
> + INIT_LIST_HEAD(&backing_req->node);
> + backing_req->end_req = opts->end_fn;
> + backing_req->priv_data = opts->priv_data;
Bit of a mixture of formatting between aligned = and not. Pick one style.
I prefer never forcing alignment but others do like it. I'm fine with that
too, just not a mix.
> +
> + return backing_req;
> +
> +err_free_req:
> + kmem_cache_free(backing_dev->backing_req_cache, backing_req);
> + return NULL;
> +}
> +
> +struct pcache_backing_dev_req *backing_dev_req_create(struct pcache_backing_dev *backing_dev,
> + struct pcache_backing_dev_req_opts *opts)
> +{
> + if (opts->type == BACKING_DEV_REQ_TYPE_REQ)
> + return req_type_req_create(backing_dev, opts);
> + else if (opts->type == BACKING_DEV_REQ_TYPE_KMEM)
returned in earlier branch so go with simpler
if (opts->type..)
Or use a switch statement if you expect to get more entries in this over time.
> + return kmem_type_req_create(backing_dev, opts);
> +
> + return NULL;
> +}
> +
> +void backing_dev_flush(struct pcache_backing_dev *backing_dev)
> +{
> + blkdev_issue_flush(backing_dev->dm_dev->bdev);
> +}
next prev parent reply other threads:[~2025-07-01 13:56 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-24 7:33 [PATCH v1 00/11] dm-pcache – persistent-memory cache for block devices Dongsheng Yang
2025-06-24 7:33 ` [PATCH v1 01/11] dm-pcache: add pcache_internal.h Dongsheng Yang
2025-07-01 13:43 ` Jonathan Cameron
2025-06-24 7:33 ` [PATCH v1 02/11] dm-pcache: add backing device management Dongsheng Yang
2025-07-01 13:56 ` Jonathan Cameron [this message]
2025-07-07 6:25 ` Dongsheng Yang
2025-06-24 7:33 ` [PATCH v1 03/11] dm-pcache: add cache device Dongsheng Yang
2025-07-01 14:07 ` Jonathan Cameron
2025-06-24 7:33 ` [PATCH v1 04/11] dm-pcache: add segment layer Dongsheng Yang
2025-07-01 14:46 ` Jonathan Cameron
2025-07-07 6:24 ` Dongsheng Yang
2025-06-24 7:33 ` [PATCH v1 05/11] dm-pcache: add cache_segment Dongsheng Yang
2025-07-01 14:59 ` Jonathan Cameron
2025-07-07 6:24 ` Dongsheng Yang
2025-06-24 7:33 ` [PATCH v1 06/11] dm-pcache: add cache_writeback Dongsheng Yang
2025-06-24 7:33 ` [PATCH v1 07/11] dm-pcache: add cache_gc Dongsheng Yang
2025-06-24 7:33 ` [PATCH v1 08/11] dm-pcache: add cache_key Dongsheng Yang
2025-06-24 7:33 ` [PATCH v1 09/11] dm-pcache: add cache_req Dongsheng Yang
2025-06-24 7:33 ` [PATCH v1 10/11] dm-pcache: add cache core Dongsheng Yang
2025-06-24 7:33 ` [PATCH v1 11/11] dm-pcache: initial dm-pcache target Dongsheng Yang
2025-06-30 13:30 ` [PATCH v1 00/11] dm-pcache – persistent-memory cache for block devices Mikulas Patocka
2025-06-30 13:40 ` Dongsheng Yang
2025-06-30 14:16 ` Dongsheng Yang
2025-06-30 15:45 ` Mikulas Patocka
2025-06-30 16:30 ` Dongsheng Yang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250701145650.00004e72@huawei.com \
--to=jonathan.cameron@huawei.com \
--cc=agk@redhat.com \
--cc=axboe@kernel.dk \
--cc=dan.j.williams@intel.com \
--cc=dm-devel@lists.linux.dev \
--cc=dongsheng.yang@linux.dev \
--cc=hch@lst.de \
--cc=linux-block@vger.kernel.org \
--cc=linux-cxl@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mpatocka@redhat.com \
--cc=nvdimm@lists.linux.dev \
--cc=snitzer@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox