From fd0195b0d8efd25d501a73bb23ecb0b6587c81d4 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Wed, 11 Jan 2023 01:09:04 +0800 Subject: [PATCH] fs/mmap: Suppor the partial unmap for anonymous mapping Signed-off-by: Xiang Xiao --- fs/mmap/fs_anonmap.c | 59 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/fs/mmap/fs_anonmap.c b/fs/mmap/fs_anonmap.c index 534806e9af..9e53a49198 100644 --- a/fs/mmap/fs_anonmap.c +++ b/fs/mmap/fs_anonmap.c @@ -39,32 +39,69 @@ static int unmap_anonymous(FAR struct task_group_s *group, FAR void *start, size_t length) { - int ret; + FAR void *newaddr; + off_t offset; + bool kernel = entry->priv.i; + int ret = OK; - /* De-allocate memory. - * NB: This is incomplete anounymous mapping implementation - * see file_mmap_ below + /* Get the offset from the beginning of the region and the actual number + * of bytes to "unmap". All mappings must extend to the end of the region. + * There is no support for freeing a block of memory but leaving a block of + * memory at the end. This is a consequence of using kumm_realloc() to + * simulate the unmapping. */ - if (start == entry->vaddr && length == entry->length) + offset = start - entry->vaddr; + if (offset + length < entry->length) { - /* entry->priv marks allocation from kernel heap */ + ferr("ERROR: Cannot umap without unmapping to the end\n"); + return -ENOSYS; + } - if (entry->priv.i) + /* Okay.. the region is being unmapped to the end. Make sure the length + * indicates that. + */ + + length = entry->length - offset; + + /* Are we unmapping the entire region (offset == 0)? */ + + if (length >= entry->length) + { + /* Free the region */ + + if (kernel) { - kmm_free(start); + kmm_free(entry->vaddr); } else { - kumm_free(start); + kumm_free(entry->vaddr); } + /* Then remove the mapping from the list */ + ret = mm_map_remove(get_group_mm(group), entry); } + + /* No.. We have been asked to "unmap' only a portion of the memory + * (offset > 0). + */ + else { - ret = -EINVAL; - ferr("ERROR: Unknown map type\n"); + if (kernel) + { + newaddr = kmm_realloc(entry->vaddr, length); + } + else + { + newaddr = kumm_realloc(entry->vaddr, length); + } + + DEBUGASSERT(newaddr == entry->vaddr); + entry->vaddr = newaddr; + entry->length = length; } return ret;