From: Coly Li <colyli@suse.de>
To: linux-bcache@vger.kernel.org
Cc: linux-block@vger.kernel.org, linux-nvdimm@lists.linux.dev,
axboe@kernel.dk, hare@suse.com, jack@suse.cz,
dan.j.williams@intel.com, hch@lst.de, ying.huang@intel.com,
Jianpeng Ma <jianpeng.ma@intel.com>,
kernel test robot <lkp@intel.com>,
Dan Carpenter <dan.carpenter@oracle.com>,
Qiaowei Ren <qiaowei.ren@intel.com>,
Hannes Reinecke <hare@suse.de>
Subject: [PATCH v12 03/12] bcache: initialization of the buddy
Date: Thu, 12 Aug 2021 01:02:15 +0800 [thread overview]
Message-ID: <20210811170224.42837-4-colyli@suse.de> (raw)
In-Reply-To: <20210811170224.42837-1-colyli@suse.de>
From: Jianpeng Ma <jianpeng.ma@intel.com>
This nvm pages allocator will implement the simple buddy allocator to
anage the nvm address space. This patch initializes this buddy allocator
for new namespace.
the unit of alloc/free of the buddy allocator is page. DAX device has
their struct page(in dram or PMEM).
struct { /* ZONE_DEVICE pages */
/** @pgmap: Points to the hosting device page map. */
struct dev_pagemap *pgmap;
void *zone_device_data;
/*
* ZONE_DEVICE private pages are counted as being
* mapped so the next 3 words hold the mapping, index,
* and private fields from the source anonymous or
* page cache page while the page is migrated to device
* private memory.
* ZONE_DEVICE MEMORY_DEVICE_FS_DAX pages also
* use the mapping, index, and private fields when
* pmem backed DAX files are mapped.
*/
};
ZONE_DEVICE pages only use pgmap. Other 4 words[16/32 bytes] don't use.
So the second/third word will be used as 'struct list_head ' which list
in buddy. The fourth word(that is normal struct page::index) store pgoff
which the page-offset in the dax device. And the fifth word (that is
normal struct page::private) store order of buddy. page_type will be used
to store buddy flags.
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Jianpeng Ma <jianpeng.ma@intel.com>
Co-developed-by: Qiaowei Ren <qiaowei.ren@intel.com>
Signed-off-by: Qiaowei Ren <qiaowei.ren@intel.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Hannes Reinecke <hare@suse.de>
Cc: Jens Axboe <axboe@kernel.dk>
---
drivers/md/bcache/nvm-pages.c | 212 +++++++++++++++++++++++++++++++++-
drivers/md/bcache/nvm-pages.h | 12 ++
2 files changed, 221 insertions(+), 3 deletions(-)
diff --git a/drivers/md/bcache/nvm-pages.c b/drivers/md/bcache/nvm-pages.c
index 6184c628d9cc..677fdb62f737 100644
--- a/drivers/md/bcache/nvm-pages.c
+++ b/drivers/md/bcache/nvm-pages.c
@@ -50,6 +50,36 @@ unsigned long bch_nvmpg_ptr_to_offset(struct bch_nvmpg_ns *ns, void *ptr)
return BCH_NVMPG_OFFSET(ns_id, offset);
}
+static struct page *bch_nvmpg_va_to_pg(void *addr)
+{
+ return virt_to_page(addr);
+}
+
+static void *bch_nvmpg_pgoff_to_ptr(struct bch_nvmpg_ns *ns, pgoff_t pgoff)
+{
+ return ns->base_addr + (pgoff << PAGE_SHIFT);
+}
+
+static void *bch_nvmpg_rec_to_ptr(struct bch_nvmpg_rec *r)
+{
+ struct bch_nvmpg_ns *ns = global_nvmpg_set->ns_tbl[r->ns_id];
+ pgoff_t pgoff = r->pgoff;
+
+ return bch_nvmpg_pgoff_to_ptr(ns, pgoff);
+}
+
+static inline void reserve_nvmpg_pages(struct bch_nvmpg_ns *ns,
+ pgoff_t pgoff, u64 nr)
+{
+ while (nr > 0) {
+ unsigned int num = nr > UINT_MAX ? UINT_MAX : nr;
+
+ bitmap_set(ns->pages_bitmap, pgoff, num);
+ nr -= num;
+ pgoff += num;
+ }
+}
+
static void release_ns_tbl(struct bch_nvmpg_set *set)
{
int i;
@@ -58,6 +88,10 @@ static void release_ns_tbl(struct bch_nvmpg_set *set)
for (i = 0; i < BCH_NVMPG_NS_MAX; i++) {
ns = set->ns_tbl[i];
if (ns) {
+ kvfree(ns->pages_bitmap);
+ if (ns->recs_bitmap)
+ bitmap_free(ns->recs_bitmap);
+
blkdev_put(ns->bdev, FMODE_READ|FMODE_WRITE|FMODE_EXEC);
set->ns_tbl[i] = NULL;
set->attached_ns--;
@@ -75,10 +109,73 @@ static void release_nvmpg_set(struct bch_nvmpg_set *set)
kfree(set);
}
+static int validate_recs(int ns_id,
+ struct bch_nvmpg_head *head,
+ struct bch_nvmpg_recs *recs)
+{
+ if (memcmp(recs->magic, bch_nvmpg_recs_magic, 16)) {
+ pr_err("Invalid bch_nvmpg_recs magic\n");
+ return -EINVAL;
+ }
+
+ if (memcmp(recs->uuid, head->uuid, 16)) {
+ pr_err("Invalid bch_nvmpg_recs uuid\n");
+ return -EINVAL;
+ }
+
+ if (recs->head_offset !=
+ bch_nvmpg_ptr_to_offset(global_nvmpg_set->ns_tbl[ns_id], head)) {
+ pr_err("Invalid recs head_offset\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int reserve_nvmpg_recs(struct bch_nvmpg_recs *recs)
+{
+ int i, used = 0;
+
+ for (i = 0; i < recs->size; i++) {
+ struct bch_nvmpg_rec *r = &recs->recs[i];
+ struct bch_nvmpg_ns *ns;
+ struct page *page;
+ void *addr;
+
+ if (r->pgoff == 0)
+ continue;
+
+ ns = global_nvmpg_set->ns_tbl[r->ns_id];
+ addr = bch_nvmpg_rec_to_ptr(r);
+ if (addr < ns->base_addr) {
+ pr_err("Invalid recorded address\n");
+ return -EINVAL;
+ }
+
+ /* init struct page: index/private */
+ page = bch_nvmpg_va_to_pg(addr);
+ set_page_private(page, r->order);
+ page->index = r->pgoff;
+
+ reserve_nvmpg_pages(ns, r->pgoff, 1L << r->order);
+ used++;
+ }
+
+ if (used != recs->used) {
+ pr_err("used %d doesn't match recs->used %d\n",
+ used, recs->used);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/* Namespace 0 contains all meta data of the nvmpg allocation set */
static int init_nvmpg_set_header(struct bch_nvmpg_ns *ns)
{
struct bch_nvmpg_set_header *set_header;
+ struct bch_nvmpg_recs *sys_recs;
+ int i, j, used = 0, rc = 0;
if (ns->ns_id != 0) {
pr_err("unexpected ns_id %u for first nvmpg namespace.\n",
@@ -92,9 +189,83 @@ static int init_nvmpg_set_header(struct bch_nvmpg_ns *ns)
global_nvmpg_set->set_header = set_header;
global_nvmpg_set->heads_size = set_header->size;
global_nvmpg_set->heads_used = set_header->used;
+
+ /* Reserve the used space from buddy allocator */
+ reserve_nvmpg_pages(ns, 0, div_u64(ns->pages_offset, ns->page_size));
+
+ sys_recs = ns->base_addr + BCH_NVMPG_SYSRECS_OFFSET;
+ for (i = 0; i < set_header->size; i++) {
+ struct bch_nvmpg_head *head;
+
+ head = &set_header->heads[i];
+ if (head->state == BCH_NVMPG_HD_STAT_FREE)
+ continue;
+
+ used++;
+ if (used > global_nvmpg_set->heads_size) {
+ pr_err("used heads %d > heads size %d.\n",
+ used, global_nvmpg_set->heads_size);
+ goto unlock;
+ }
+
+ for (j = 0; j < BCH_NVMPG_NS_MAX; j++) {
+ struct bch_nvmpg_recs *recs;
+
+ recs = bch_nvmpg_offset_to_ptr(head->recs_offset[j]);
+
+ /* Iterate the recs list */
+ while (recs) {
+ rc = validate_recs(j, head, recs);
+ if (rc < 0)
+ goto unlock;
+
+ rc = reserve_nvmpg_recs(recs);
+ if (rc < 0)
+ goto unlock;
+
+ bitmap_set(ns->recs_bitmap, recs - sys_recs, 1);
+ recs = bch_nvmpg_offset_to_ptr(recs->next_offset);
+ }
+ }
+ }
+unlock:
mutex_unlock(&global_nvmpg_set->lock);
+ return rc;
+}
- return 0;
+static void bch_nvmpg_init_free_space(struct bch_nvmpg_ns *ns)
+{
+ unsigned int start, end, pages;
+ int i;
+ struct page *page;
+ pgoff_t pgoff_start;
+
+ bitmap_for_each_clear_region(ns->pages_bitmap,
+ start, end, 0, ns->pages_total) {
+ pgoff_start = start;
+ pages = end - start;
+
+ while (pages) {
+ void *addr;
+
+ for (i = BCH_MAX_ORDER - 1; i >= 0; i--) {
+ if ((pgoff_start % (1L << i) == 0) &&
+ (pages >= (1L << i)))
+ break;
+ }
+
+ addr = bch_nvmpg_pgoff_to_ptr(ns, pgoff_start);
+ page = bch_nvmpg_va_to_pg(addr);
+ set_page_private(page, i);
+ page->index = pgoff_start;
+ __SetPageBuddy(page);
+ list_add((struct list_head *)&page->zone_device_data,
+ &ns->free_area[i]);
+
+ pgoff_start += 1L << i;
+ pages -= 1L << i;
+ }
+ }
}
static int attach_nvmpg_set(struct bch_nvmpg_ns *ns)
@@ -199,7 +370,7 @@ struct bch_nvmpg_ns *bch_register_namespace(const char *dev_path)
char buf[BDEVNAME_SIZE];
struct block_device *bdev;
pgoff_t pgoff;
- int id, err;
+ int id, i, err;
char *path;
long dax_ret = 0;
@@ -303,13 +474,48 @@ struct bch_nvmpg_ns *bch_register_namespace(const char *dev_path)
mutex_init(&ns->lock);
+ /*
+ * parameters of bitmap_set/clear are unsigned int.
+ * Given currently size of nvm is far from exceeding this limit,
+ * so only add a WARN_ON message.
+ */
+ WARN_ON(BITS_TO_LONGS(ns->pages_total) > UINT_MAX);
+ ns->pages_bitmap = kvcalloc(BITS_TO_LONGS(ns->pages_total),
+ sizeof(unsigned long), GFP_KERNEL);
+ if (!ns->pages_bitmap) {
+ err = -ENOMEM;
+ goto clear_ns_nr;
+ }
+
+ if (ns->sb->this_ns == 0) {
+ ns->recs_bitmap =
+ bitmap_zalloc(BCH_MAX_PGALLOC_RECS, GFP_KERNEL);
+ if (ns->recs_bitmap == NULL) {
+ err = -ENOMEM;
+ goto free_pages_bitmap;
+ }
+ }
+
+ for (i = 0; i < BCH_MAX_ORDER; i++)
+ INIT_LIST_HEAD(&ns->free_area[i]);
+
err = init_nvmpg_set_header(ns);
if (err < 0)
- goto free_ns;
+ goto free_recs_bitmap;
+
+ if (ns->sb->this_ns == 0)
+ /* init buddy allocator */
+ bch_nvmpg_init_free_space(ns);
kfree(path);
return ns;
+free_recs_bitmap:
+ bitmap_free(ns->recs_bitmap);
+free_pages_bitmap:
+ kvfree(ns->pages_bitmap);
+clear_ns_nr:
+ global_nvmpg_set->ns_tbl[sb->this_ns] = NULL;
free_ns:
kfree(ns);
bdput:
diff --git a/drivers/md/bcache/nvm-pages.h b/drivers/md/bcache/nvm-pages.h
index 827cff695608..2116086c4d01 100644
--- a/drivers/md/bcache/nvm-pages.h
+++ b/drivers/md/bcache/nvm-pages.h
@@ -10,6 +10,8 @@
* Bcache NVDIMM in memory data structures
*/
+#define BCH_MAX_ORDER 20
+
/*
* The following three structures in memory records which page(s) allocated
* to which owner. After reboot from power failure, they will be initialized
@@ -27,6 +29,11 @@ struct bch_nvmpg_ns {
unsigned long pages_total;
pfn_t start_pfn;
+ unsigned long *pages_bitmap;
+ struct list_head free_area[BCH_MAX_ORDER];
+
+ unsigned long *recs_bitmap;
+
struct dax_device *dax_dev;
struct block_device *bdev;
struct bch_nvmpg_set *set;
@@ -68,6 +75,11 @@ struct bch_nvmpg_set {
/* Indicate which field in bch_nvmpg_sb to be updated */
#define BCH_NVMPG_TOTAL_NS 0 /* total_ns */
+#define BCH_MAX_PGALLOC_RECS \
+ (min_t(unsigned int, 64, \
+ (BCH_NVMPG_START - BCH_NVMPG_SYSRECS_OFFSET) / \
+ sizeof(struct bch_nvmpg_recs)))
+
void *bch_nvmpg_offset_to_ptr(unsigned long offset);
unsigned long bch_nvmpg_ptr_to_offset(struct bch_nvmpg_ns *ns, void *ptr);
--
2.26.2
next prev parent reply other threads:[~2021-08-11 17:04 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-08-11 17:02 [PATCH v12 00/12] bcache: support NVDIMM for journaling Coly Li
2021-08-11 17:02 ` [PATCH v12 01/12] bcache: add initial data structures for nvm pages Coly Li
2021-08-11 17:02 ` [PATCH v12 02/12] bcache: initialize the nvm pages allocator Coly Li
2021-08-12 5:43 ` Dan Williams
2021-08-12 8:26 ` Coly Li
2021-08-11 17:02 ` Coly Li [this message]
2021-08-11 17:02 ` [PATCH v12 04/12] bcache: bch_nvmpg_alloc_pages() of the buddy Coly Li
2021-08-11 17:02 ` [PATCH v12 05/12] bcache: bch_nvmpg_free_pages() of the buddy allocator Coly Li
2021-08-11 17:02 ` [PATCH v12 06/12] bcache: get recs list head for allocated pages by specific uuid Coly Li
2021-08-11 17:02 ` [PATCH v12 07/12] bcache: use bucket index to set GC_MARK_METADATA for journal buckets in bch_btree_gc_finish() Coly Li
2021-08-11 17:02 ` [PATCH v12 08/12] bcache: add BCH_FEATURE_INCOMPAT_NVDIMM_META into incompat feature set Coly Li
2021-08-11 17:02 ` [PATCH v12 09/12] bcache: initialize bcache journal for NVDIMM meta device Coly Li
2021-08-11 17:02 ` [PATCH v12 10/12] bcache: support storing bcache journal into " Coly Li
2021-08-11 17:02 ` [PATCH v12 11/12] bcache: read jset from NVDIMM pages for journal replay Coly Li
2021-08-11 17:02 ` [PATCH v12 12/12] bcache: add sysfs interface register_nvdimm_meta to register NVDIMM meta device Coly Li
2021-08-15 16:21 ` [PATCH v12 00/12] bcache: support NVDIMM for journaling Coly Li
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=20210811170224.42837-4-colyli@suse.de \
--to=colyli@suse.de \
--cc=axboe@kernel.dk \
--cc=dan.carpenter@oracle.com \
--cc=dan.j.williams@intel.com \
--cc=hare@suse.com \
--cc=hare@suse.de \
--cc=hch@lst.de \
--cc=jack@suse.cz \
--cc=jianpeng.ma@intel.com \
--cc=linux-bcache@vger.kernel.org \
--cc=linux-block@vger.kernel.org \
--cc=linux-nvdimm@lists.linux.dev \
--cc=lkp@intel.com \
--cc=qiaowei.ren@intel.com \
--cc=ying.huang@intel.com \
/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;
as well as URLs for NNTP newsgroup(s).