[RFC V2 30/37] dmem: introduce dmem_bitmap_alloc() and dmem_bitmap_free()

From: yulei . kernel
Date: Mon Dec 07 2020 - 06:36:06 EST


From: Yulei Zhang <yuleixzhang@xxxxxxxxxxx>

If dmem contained in dmem region is too large and dmemfs is mounted as
4K pagesize, size of bitmap in this dmem region maybe exceed maximal
available memory of kzalloc(). It would cause kzalloc() fail.

So introduce dmem_bitmap_alloc() and use vzalloc() if bitmap is larger than
PAGE_SIZE as vzalloc() will get sparse page.

Signed-off-by: Chen Zhuo <sagazchen@xxxxxxxxxxx>
Signed-off-by: Yulei Zhang <yuleixzhang@xxxxxxxxxxx>
---
fs/inode.c | 6 +++++
include/linux/fs.h | 1 +
mm/dmem.c | 69 ++++++++++++++++++++++++++++++++++--------------------
3 files changed, 50 insertions(+), 26 deletions(-)

diff --git a/fs/inode.c b/fs/inode.c
index 9d78c37..9b6363d3 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -210,6 +210,12 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
}
EXPORT_SYMBOL(inode_init_always);

+struct inode *alloc_inode_nonrcu(void)
+{
+ return kmem_cache_alloc(inode_cachep, GFP_KERNEL);
+}
+EXPORT_SYMBOL(alloc_inode_nonrcu);
+
void free_inode_nonrcu(struct inode *inode)
{
kmem_cache_free(inode_cachep, inode);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 8667d0c..bc7a89c 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2937,6 +2937,7 @@ static inline bool is_zero_ino(ino_t ino)
extern void __destroy_inode(struct inode *);
extern struct inode *new_inode_pseudo(struct super_block *sb);
extern struct inode *new_inode(struct super_block *sb);
+extern struct inode *alloc_inode_nonrcu(void);
extern void free_inode_nonrcu(struct inode *inode);
extern int should_remove_suid(struct dentry *);
extern int file_remove_privs(struct file *);
diff --git a/mm/dmem.c b/mm/dmem.c
index eb6df70..50cdff9 100644
--- a/mm/dmem.c
+++ b/mm/dmem.c
@@ -17,6 +17,7 @@
#include <linux/dmem.h>
#include <linux/debugfs.h>
#include <linux/notifier.h>
+#include <linux/vmalloc.h>

#define CREATE_TRACE_POINTS
#include <trace/events/dmem.h>
@@ -362,9 +363,38 @@ static int __init dmem_node_init(struct dmem_node *dnode)
return 0;
}

+static unsigned long *dmem_bitmap_alloc(unsigned long pages,
+ unsigned long *static_bitmap)
+{
+ unsigned long *bitmap, size;
+
+ size = BITS_TO_LONGS(pages) * sizeof(long);
+ if (size <= sizeof(*static_bitmap))
+ bitmap = static_bitmap;
+ else if (size <= PAGE_SIZE)
+ bitmap = kzalloc(size, GFP_KERNEL);
+ else
+ bitmap = vzalloc(size);
+
+ return bitmap;
+}
+
+static void dmem_bitmap_free(unsigned long pages,
+ unsigned long *bitmap,
+ unsigned long *static_bitmap)
+{
+ unsigned long size;
+
+ size = BITS_TO_LONGS(pages) * sizeof(long);
+ if (size > PAGE_SIZE)
+ vfree(bitmap);
+ else if (bitmap != static_bitmap)
+ kfree(bitmap);
+}
+
static void __init dmem_region_uinit(struct dmem_region *dregion)
{
- unsigned long nr_pages, size, *bitmap = dregion->error_bitmap;
+ unsigned long nr_pages, *bitmap = dregion->error_bitmap;

if (!bitmap)
return;
@@ -374,9 +404,7 @@ static void __init dmem_region_uinit(struct dmem_region *dregion)

WARN_ON(!nr_pages);

- size = BITS_TO_LONGS(nr_pages) * sizeof(long);
- if (size > sizeof(dregion->static_bitmap))
- kfree(bitmap);
+ dmem_bitmap_free(nr_pages, bitmap, &dregion->static_error_bitmap);
dregion->error_bitmap = NULL;
}

@@ -405,19 +433,15 @@ static void __init dmem_uinit(void)

static int __init dmem_region_init(struct dmem_region *dregion)
{
- unsigned long *bitmap, size, nr_pages;
+ unsigned long *bitmap, nr_pages;

nr_pages = __phys_to_pfn(dregion->reserved_end_addr)
- __phys_to_pfn(dregion->reserved_start_addr);

- size = BITS_TO_LONGS(nr_pages) * sizeof(long);
- if (size <= sizeof(dregion->static_error_bitmap)) {
- bitmap = &dregion->static_error_bitmap;
- } else {
- bitmap = kzalloc(size, GFP_KERNEL);
- if (!bitmap)
- return -ENOMEM;
- }
+ bitmap = dmem_bitmap_alloc(nr_pages, &dregion->static_error_bitmap);
+ if (!bitmap)
+ return -ENOMEM;
+
dregion->error_bitmap = bitmap;
return 0;
}
@@ -472,7 +496,7 @@ static int __init dmem_late_init(void)
static int dmem_alloc_region_init(struct dmem_region *dregion,
unsigned long *dpages)
{
- unsigned long start, end, *bitmap, size;
+ unsigned long start, end, *bitmap;

start = DMEM_PAGE_UP(dregion->reserved_start_addr);
end = DMEM_PAGE_DOWN(dregion->reserved_end_addr);
@@ -481,14 +505,9 @@ static int dmem_alloc_region_init(struct dmem_region *dregion,
if (!*dpages)
return 0;

- size = BITS_TO_LONGS(*dpages) * sizeof(long);
- if (size <= sizeof(dregion->static_bitmap))
- bitmap = &dregion->static_bitmap;
- else {
- bitmap = kzalloc(size, GFP_KERNEL);
- if (!bitmap)
- return -ENOMEM;
- }
+ bitmap = dmem_bitmap_alloc(*dpages, &dregion->static_bitmap);
+ if (!bitmap)
+ return -ENOMEM;

dregion->bitmap = bitmap;
dregion->next_free_pos = 0;
@@ -582,7 +601,7 @@ static void dmem_uinit_check_alloc_bitmap(struct dmem_region *dregion)

static void dmem_alloc_region_uinit(struct dmem_region *dregion)
{
- unsigned long dpages, size, *bitmap = dregion->bitmap;
+ unsigned long dpages, *bitmap = dregion->bitmap;

if (!bitmap)
return;
@@ -592,9 +611,7 @@ static void dmem_alloc_region_uinit(struct dmem_region *dregion)

dmem_uinit_check_alloc_bitmap(dregion);

- size = BITS_TO_LONGS(dpages) * sizeof(long);
- if (size > sizeof(dregion->static_bitmap))
- kfree(bitmap);
+ dmem_bitmap_free(dpages, bitmap, &dregion->static_bitmap);
dregion->bitmap = NULL;
}

--
1.8.3.1