Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible issues when allocate page-sized memory in snapshot management #150

Open
iaoing opened this issue Jan 2, 2024 · 0 comments
Open

Comments

@iaoing
Copy link
Contributor

iaoing commented Jan 2, 2024

Issue

In snapshot management, NOVA uses kmalloc to allocate the page-sized memory, and then checks the alignment, as the below code shows.

new_page = (unsigned long)kmalloc(PAGE_SIZE,
GFP_KERNEL);
/* Aligned to PAGE_SIZE */
if (!new_page || ENTRY_LOC(new_page)) {
nova_dbg("%s: failed\n", __func__);
kfree((void *)new_page);
return -ENOMEM;
}

However, the allocated memory space might not be aligned to the page size. I have encountered this situation where the allocation is successful but the alignment is not satisfied, but I am not sure whether it was caused by VMs or small DRAM size that was used in the VM.

The documentation of kernel-5.1 does not say the alignment is guaranteed (https://www.kernel.org/doc/html/v5.1/core-api/memory-allocation.html). There also have discussions regarding the alignment of kmalloc (https://lwn.net/Articles/787740/).

From kernel-5.4, the documentation confirms the alignment guarantee of kmalloc. However, it also suggests to use the page allocator for large allocations. The blow code is the APIs of the page allocator.

#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)
#define alloc_page_vma(gfp_mask, vma, addr) \
alloc_pages_vma(gfp_mask, 0, vma, addr, numa_node_id(), false)
#define alloc_page_vma_node(gfp_mask, vma, addr, node) \
alloc_pages_vma(gfp_mask, 0, vma, addr, node, false)
extern unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order);
extern unsigned long get_zeroed_page(gfp_t gfp_mask);
void *alloc_pages_exact(size_t size, gfp_t gfp_mask);
void free_pages_exact(void *virt, size_t size);
void * __meminit alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask);
#define __get_free_page(gfp_mask) \
__get_free_pages((gfp_mask), 0)
#define __get_dma_pages(gfp_mask, order) \
__get_free_pages((gfp_mask) | GFP_DMA, (order))
extern void __free_pages(struct page *page, unsigned int order);
extern void free_pages(unsigned long addr, unsigned int order);
extern void free_unref_page(struct page *page);
extern void free_unref_page_list(struct list_head *list);
struct page_frag_cache;
extern void __page_frag_cache_drain(struct page *page, unsigned int count);
extern void *page_frag_alloc(struct page_frag_cache *nc,
unsigned int fragsz, gfp_t gfp_mask);
extern void page_frag_free(void *addr);
#define __free_page(page) __free_pages((page), 0)
#define free_page(addr) free_pages((addr), 0)

Fix

Replacing kmalloc as __get_free_page and kfree as free_page, as below code shows

// new_page = (unsigned long)kmalloc(PAGE_SIZE, GFP_KERNEL);
new_page = __get_free_page(GFP_KERNEL);
if (!new_page || ENTRY_LOC(new_page)) {
    // kfree((void *)new_page);
    free_page((unsigned long)new_page);
    nova_err(sb, "%s: allocation failed\n", __func__);
    return -ENOMEM;
}

// and other places to fix
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant