[RFC PATCH v2 12/16] mm: Define the make_alloc() function

Juan Yescas <[email protected]>
Newsgroups gmane.linux.kernel,gmane.linux.kernel.mm,gmane.linux.kernel.mm
Message-ID <[email protected]>
The make_alloc() is the core function that performs the allocation.

The tasks of this function are:

- Call the Buddy allocator to make the allocation.
- Store the details of the allocation in struct page_alloc.
- Insert the struct page_alloc in an xarray using the allocation id
as key.

If something fails during the allocation, the pages and cache
will be freed.

Signed-off-by: Juan Yescas <[email protected]>
---

Changes in v2:
	- Once that page_alloc is initialized, insert it in xarray.
	- Use 20 characters for the file name instead of 12.
	- Fix use-after-free issue while releasing the pages.

 mm/page_alloc_hogger.c | 72 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/mm/page_alloc_hogger.c b/mm/page_alloc_hogger.c
index 4b72acfbc087..e22247b7bd98 100644
--- a/mm/page_alloc_hogger.c
+++ b/mm/page_alloc_hogger.c
@@ -96,6 +96,18 @@
 
 static struct dentry *mmdir;
 
+/**
+ * atomic_long_t allocs_file_seq - Represents the naming sequence used for
+ * allocation files.
+ */
+static atomic_long_t allocs_file_seq = ATOMIC_INIT(0);
+
+/**
+ * allocs_xa - Represent the xarray that contains the actual allocations perform
+ * by this driver.
+ */
+static DEFINE_XARRAY(allocs_xa);
+
 /**
  * struct req_alloc - Represents the requested allocation
  * @node_idx: The Node index to allocate from.
@@ -173,6 +185,47 @@ static inline void set_migrate_type_to_alloc_from(int migrate_type, gfp_t *flags
 	}
 }
 
+static int make_alloc(struct req_alloc *req,
+			    gfp_t flags, unsigned long *alloc_id)
+{
+	struct page_alloc *pa;
+	struct page *page;
+	char new_alloc_name[20];
+	int ret;
+
+	page = alloc_pages_node_noprof(req->node_idx, flags, req->order);
+	if (page) {
+		pa = kmem_cache_alloc(page_alloc_cache, GFP_KERNEL);
+		if (!pa) {
+			ret = -ENOMEM;
+			goto free_pages;
+		}
+
+		*alloc_id = atomic_long_inc_return(&allocs_file_seq);
+		snprintf(new_alloc_name, sizeof(new_alloc_name), "%lu",
+			 *alloc_id);
+
+		pa->req_alloc = req;
+		pa->page = page;
+
+		ret = xa_insert(&allocs_xa, *alloc_id, pa, GFP_KERNEL);
+		if (ret)
+			goto free_page_alloc;
+	} else {
+		return -ENOMEM;
+	}
+
+	return 0;
+
+free_page_alloc:
+	kmem_cache_free(page_alloc_cache, pa);
+
+free_pages:
+	__free_pages(page, req->order);
+
+	return ret;
+}
+
 /**
  * req_page_alloc_write() - Allocates the pages on the requested node, zone,
  * order and migrate type. Once the allocation is performed, a file is created
@@ -182,10 +235,12 @@ static ssize_t req_page_alloc_write(struct file *file, const char __user *ubuf,
 				     size_t cnt, loff_t *ppos)
 {
 	struct req_alloc *req = file->private_data;
+	unsigned long alloc_id;
 	unsigned long nr_pages_allocs;
 	unsigned long *allocs_ids;
 	gfp_t flags = 0;
 	int ret;
+	int i;
 
 	ret = kstrtoul_from_user(ubuf, cnt, 10, &nr_pages_allocs);
 	if (ret)
@@ -199,9 +254,26 @@ static ssize_t req_page_alloc_write(struct file *file, const char __user *ubuf,
 	set_zone_to_alloc_from(req->zone_idx, &flags);
 	set_migrate_type_to_alloc_from(req->migrate_type, &flags);
 
+	for (i = 0; i < nr_pages_allocs; i++) {
+		ret = make_alloc(req, flags, &alloc_id);
+		if (ret)
+			goto free_allocs;
+
+		allocs_ids[i] = alloc_id;
+	}
+
 	kfree(allocs_ids);
 
 	return cnt;
+
+free_allocs:
+	/*
+	 * A proper clean up of the pages and page_alloc allocations will
+	 * be done in a follow up patch of this topic.
+	 */
+	kfree(allocs_ids);
+
+	return ret;
 }
 
 static const struct file_operations req_page_alloc_fops = {
-- 
2.55.0.629.g250fe7f194-goog
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.