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 --- 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