diff mbox series

[v3,11/16] bcache: handle cache set verify_ondisk properly for bucket size > 8MB

Message ID 20200715143015.14957-12-colyli@suse.de (mailing list archive)
State New, archived
Headers show
Series bcache: extend bucket size to 32bit width | expand

Commit Message

Coly Li July 15, 2020, 2:30 p.m. UTC
From: Coly Li <colyli@suse.de>

In bch_btree_cache_alloc() when CONFIG_BCACHE_DEBUG is configured,
allocate memory for c->verify_ondisk may fail if the bucket size > 8MB,
which will require __get_free_pages() to allocate continuous pages
with order > 11 (the default MAX_ORDER of Linux buddy allocator). Such
over size allocation will fail, and cause 2 problems,
- When CONFIG_BCACHE_DEBUG is configured,  bch_btree_verify() does not
  work, because c->verify_ondisk is NULL and bch_btree_verify() returns
  immediately.
- bch_btree_cache_alloc() will fail due to c->verify_ondisk allocation
  failed, then the whole cache device registration fails. And because of
  this failure, the first problem of bch_btree_verify() has no chance to
  be triggered.

This patch fixes the above problem by two means,
1) If pages allocation of c->verify_ondisk fails, set it to NULL and
   returns bch_btree_cache_alloc() with -ENOMEM.
2) When calling __get_free_pages() to allocate c->verify_ondisk pages,
   use ilog2(meta_bucket_pages(&c->sb)) to make sure ilog2() will always
   generate a pages order <= MAX_ORDER (or CONFIG_FORCE_MAX_ZONEORDER).
   Then the buddy system won't directly reject the allocation request.

Signed-off-by: Coly Li <colyli@suse.de>
---
 drivers/md/bcache/btree.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

Comments

Hannes Reinecke July 16, 2020, 6:07 a.m. UTC | #1
On 7/15/20 4:30 PM, colyli@suse.de wrote:
> From: Coly Li <colyli@suse.de>
> 
> In bch_btree_cache_alloc() when CONFIG_BCACHE_DEBUG is configured,
> allocate memory for c->verify_ondisk may fail if the bucket size > 8MB,
> which will require __get_free_pages() to allocate continuous pages
> with order > 11 (the default MAX_ORDER of Linux buddy allocator). Such
> over size allocation will fail, and cause 2 problems,
> - When CONFIG_BCACHE_DEBUG is configured,  bch_btree_verify() does not
>    work, because c->verify_ondisk is NULL and bch_btree_verify() returns
>    immediately.
> - bch_btree_cache_alloc() will fail due to c->verify_ondisk allocation
>    failed, then the whole cache device registration fails. And because of
>    this failure, the first problem of bch_btree_verify() has no chance to
>    be triggered.
> 
> This patch fixes the above problem by two means,
> 1) If pages allocation of c->verify_ondisk fails, set it to NULL and
>     returns bch_btree_cache_alloc() with -ENOMEM.
> 2) When calling __get_free_pages() to allocate c->verify_ondisk pages,
>     use ilog2(meta_bucket_pages(&c->sb)) to make sure ilog2() will always
>     generate a pages order <= MAX_ORDER (or CONFIG_FORCE_MAX_ZONEORDER).
>     Then the buddy system won't directly reject the allocation request.
> 
> Signed-off-by: Coly Li <colyli@suse.de>
> ---
>   drivers/md/bcache/btree.c | 12 ++++++++++--
>   1 file changed, 10 insertions(+), 2 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@suse.de>

Cheers,

Hannes
diff mbox series

Patch

diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
index dd116c83de80..79716ac9fb5d 100644
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -738,7 +738,7 @@  void bch_btree_cache_free(struct cache_set *c)
 	if (c->verify_data)
 		list_move(&c->verify_data->list, &c->btree_cache);
 
-	free_pages((unsigned long) c->verify_ondisk, ilog2(bucket_pages(c)));
+	free_pages((unsigned long) c->verify_ondisk, ilog2(meta_bucket_pages(&c->sb)));
 #endif
 
 	list_splice(&c->btree_cache_freeable,
@@ -785,7 +785,15 @@  int bch_btree_cache_alloc(struct cache_set *c)
 	mutex_init(&c->verify_lock);
 
 	c->verify_ondisk = (void *)
-		__get_free_pages(GFP_KERNEL|__GFP_COMP, ilog2(bucket_pages(c)));
+		__get_free_pages(GFP_KERNEL|__GFP_COMP, ilog2(meta_bucket_pages(&c->sb)));
+	if (!c->verify_ondisk) {
+		/*
+		 * Don't worry about the mca_rereserve buckets
+		 * allocated in previous for-loop, they will be
+		 * handled properly in bch_cache_set_unregister().
+		 */
+		return -ENOMEM;
+	}
 
 	c->verify_data = mca_bucket_alloc(c, &ZERO_KEY, GFP_KERNEL);