This is an automated email from the ASF dual-hosted git repository. masayuki pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit 8612af4ae59a94cc27d57680acfc55ed926f9067 Author: Xiang Xiao <xiaoxi...@xiaomi.com> AuthorDate: Sat Mar 20 05:06:08 2021 +0800 fs: Implement file_mmap and file_munmap API Signed-off-by: Xiang Xiao <xiaoxi...@xiaomi.com> --- fs/mmap/fs_mmap.c | 250 ++++++++++++++++++++++++++++---------------------- fs/mmap/fs_munmap.c | 171 +++++++++++++++++++++------------- fs/mmap/fs_rammap.c | 37 +++++--- fs/mmap/fs_rammap.h | 10 +- include/nuttx/fs/fs.h | 24 +++++ 5 files changed, 302 insertions(+), 190 deletions(-) diff --git a/fs/mmap/fs_mmap.c b/fs/mmap/fs_mmap.c index baab91f..c764af2 100644 --- a/fs/mmap/fs_mmap.c +++ b/fs/mmap/fs_mmap.c @@ -38,88 +38,18 @@ #include "fs_rammap.h" /**************************************************************************** - * Public Functions + * Private Functions ****************************************************************************/ /**************************************************************************** - * Name: mmap - * - * Description: - * NuttX operates in a flat open address space. Therefore, it generally - * does not require mmap() functionality. There are two exceptions: - * - * 1. mmap() is the API that is used to support direct access to random - * access media under the following very restrictive conditions: - * - * a. The filesystem supports the FIOC_MMAP ioctl command. Any file - * system that maps files contiguously on the media should support - * this ioctl. (vs. file system that scatter files over the media - * in non-contiguous sectors). As of this writing, ROMFS is the - * only file system that meets this requirement. - * b. The underlying block driver supports the BIOC_XIPBASE ioctl - * command that maps the underlying media to a randomly accessible - * address. At present, only the RAM/ROM disk driver does this. - * - * 2. If CONFIG_FS_RAMMAP is defined in the configuration, then mmap() will - * support simulation of memory mapped files by copying files whole - * into RAM. - * - * Input Parameters: - * start A hint at where to map the memory -- ignored. The address - * of the underlying media is fixed and cannot be re-mapped without - * MMU support. - * length The length of the mapping. For exception #1 above, this length - * ignored: The entire underlying media is always accessible. - * prot See the PROT_* definitions in sys/mman.h. - * PROT_NONE - Will cause an error - * PROT_READ - PROT_WRITE and PROT_EXEC also assumed - * PROT_WRITE - PROT_READ and PROT_EXEC also assumed - * PROT_EXEC - PROT_READ and PROT_WRITE also assumed - * flags See the MAP_* definitions in sys/mman.h. - * MAP_SHARED - MAP_PRIVATE or MAP_SHARED required - * MAP_PRIVATE - MAP_PRIVATE or MAP_SHARED required - * MAP_FIXED - Will cause an error - * MAP_FILE - Ignored - * MAP_ANONYMOUS - Optional - * MAP_ANON - Will cause an error - * MAP_GROWSDOWN - Ignored - * MAP_DENYWRITE - Will cause an error - * MAP_EXECUTABLE - Ignored - * MAP_LOCKED - Ignored - * MAP_NORESERVE - Ignored - * MAP_POPULATE - Ignored - * MAP_NONBLOCK - Ignored - * fd file descriptor of the backing file -- required. - * offset The offset into the file to map - * - * Returned Value: - * On success, mmap() returns a pointer to the mapped area. On error, the - * value MAP_FAILED is returned, and errno is set appropriately. - * - * EACCES - * The fd argument is not open for read, regardless of the - * protection specified, or fd is not open for write and PROT_WRITE - * was specified for a MAP_SHARED type mapping. - * ENOSYS - * Returned if any of the unsupported mmap() features are attempted - * EBADF - * 'fd' is not a valid file descriptor. - * EINVAL - * Length is 0. flags contained neither MAP_PRIVATE or MAP_SHARED, or - * contained both of these values. - * ENODEV - * The underlying filesystem of the specified file does not support - * memory mapping. - * ENOMEM - * Insufficient memory is available to map the file. - * + * Name: file_mmap_ ****************************************************************************/ -FAR void *mmap(FAR void *start, size_t length, int prot, int flags, - int fd, off_t offset) +static int file_mmap_(FAR struct file *filep, FAR void *start, + size_t length, int prot, int flags, + off_t offset, bool kernel, FAR void **mapped) { FAR void *addr; - FAR struct file *filep; int ret; /* Since only a tiny subset of mmap() functionality, we have to verify many @@ -135,8 +65,7 @@ FAR void *mmap(FAR void *start, size_t length, int prot, int flags, if ((flags & (MAP_FIXED | MAP_DENYWRITE)) != 0) { ferr("ERROR: Unsupported options, prot=%x flags=%04x\n", prot, flags); - ret = -ENOSYS; - goto errout; + return -ENOSYS; } #ifndef CONFIG_FS_RAMMAP @@ -144,8 +73,7 @@ FAR void *mmap(FAR void *start, size_t length, int prot, int flags, { ferr("ERROR: MAP_PRIVATE is not supported without file mapping" "emulation\n"); - ret = -ENOSYS; - goto errout; + return -ENOSYS; } #endif /* CONFIG_FS_RAMMAP */ @@ -154,33 +82,22 @@ FAR void *mmap(FAR void *start, size_t length, int prot, int flags, if (length == 0) { ferr("ERROR: Invalid length, length=%zu\n", length); - ret = -EINVAL; - goto errout; + return -EINVAL; } #endif /* CONFIG_DEBUG_FEATURES */ - if (fs_getfilep(fd, &filep) < 0) - { - ferr("ERROR: Invalid file descriptor, fd=%d\n", fd); - ret = -EBADF; - goto errout; - } - if ((filep->f_oflags & O_WROK) == 0 && prot == PROT_WRITE && (flags & MAP_SHARED) != 0) { ferr("ERROR: Unsupported options for read-only file descriptor," - "fd=%d prot=%x flags=%04x\n", fd, prot, flags); - ret = -EACCES; - goto errout; + "prot=%x flags=%04x\n", prot, flags); + return -EACCES; } if ((filep->f_oflags & O_RDOK) == 0) { - ferr("ERROR: File descriptor does not have read permission," - "fd=%d\n", fd); - ret = -EACCES; - goto errout; + ferr("ERROR: File descriptor does not have read permission\n"); + return -EACCES; } /* Check if we are just be asked to allocate memory, i.e., MAP_ANONYMOUS @@ -191,23 +108,20 @@ FAR void *mmap(FAR void *start, size_t length, int prot, int flags, if ((flags & MAP_ANONYMOUS) != 0) { - FAR void *alloc; - /* REVISIT: Should reside outside of the heap. That is really the * only purpose of MAP_ANONYMOUS: To get non-heap memory. In KERNEL * build, this could be accomplished using pgalloc(), provided that * you had logic in place to assign a virtual address to the mapping. */ - alloc = kumm_zalloc(length); - if (alloc == NULL) + *mapped = kernel ? kmm_zalloc(length) : kumm_zalloc(length); + if (*mapped == NULL) { ferr("ERROR: kumm_alloc() failed: %d\n", ret); - ret = -ENOMEM; - goto errout; + return -ENOMEM; } - return alloc; + return OK; } if ((flags & MAP_PRIVATE) != 0) @@ -217,7 +131,7 @@ FAR void *mmap(FAR void *start, size_t length, int prot, int flags, * do much better in the KERNEL build using the MMU. */ - return rammap(fd, length, offset); + return rammap(filep, length, offset, kernel, mapped); #endif } @@ -227,7 +141,7 @@ FAR void *mmap(FAR void *start, size_t length, int prot, int flags, * a pointer). */ - ret = nx_ioctl(fd, FIOC_MMAP, (unsigned long)((uintptr_t)&addr)); + ret = file_ioctl(filep, FIOC_MMAP, (unsigned long)((uintptr_t)&addr)); if (ret < 0) { /* Not directly mappable, probably because the underlying media does @@ -239,16 +153,136 @@ FAR void *mmap(FAR void *start, size_t length, int prot, int flags, * do much better in the KERNEL build using the MMU. */ - return rammap(fd, length, offset); + return rammap(filep, length, offset, kernel, mapped); #else - ferr("ERROR: nx_ioctl(FIOC_MMAP) failed: %d\n", ret); - goto errout; + ferr("ERROR: file_ioctl(FIOC_MMAP) failed: %d\n", ret); + return ret; #endif } /* Return the offset address */ - return (FAR void *)(((FAR uint8_t *)addr) + offset); + *mapped = (FAR void *)(((FAR uint8_t *)addr) + offset); + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: file_mmap + * + * Description: + * Equivalent to the standard mmap() function except that is accepts + * a struct file instance instead of a file descriptor and it does not set + * the errno variable. + * + ****************************************************************************/ + +int file_mmap(FAR struct file *filep, FAR void *start, size_t length, + int prot, int flags, off_t offset, FAR void **mapped) +{ + return file_mmap_(filep, start, length, + prot, flags, offset, true, mapped); +} + +/**************************************************************************** + * Name: mmap + * + * Description: + * NuttX operates in a flat open address space. Therefore, it generally + * does not require mmap() functionality. There are two exceptions: + * + * 1. mmap() is the API that is used to support direct access to random + * access media under the following very restrictive conditions: + * + * a. The filesystem supports the FIOC_MMAP ioctl command. Any file + * system that maps files contiguously on the media should support + * this ioctl. (vs. file system that scatter files over the media + * in non-contiguous sectors). As of this writing, ROMFS is the + * only file system that meets this requirement. + * b. The underlying block driver supports the BIOC_XIPBASE ioctl + * command that maps the underlying media to a randomly accessible + * address. At present, only the RAM/ROM disk driver does this. + * + * 2. If CONFIG_FS_RAMMAP is defined in the configuration, then mmap() will + * support simulation of memory mapped files by copying files whole + * into RAM. + * + * Input Parameters: + * start A hint at where to map the memory -- ignored. The address + * of the underlying media is fixed and cannot be re-mapped without + * MMU support. + * length The length of the mapping. For exception #1 above, this length + * ignored: The entire underlying media is always accessible. + * prot See the PROT_* definitions in sys/mman.h. + * PROT_NONE - Will cause an error + * PROT_READ - PROT_WRITE and PROT_EXEC also assumed + * PROT_WRITE - PROT_READ and PROT_EXEC also assumed + * PROT_EXEC - PROT_READ and PROT_WRITE also assumed + * flags See the MAP_* definitions in sys/mman.h. + * MAP_SHARED - MAP_PRIVATE or MAP_SHARED required + * MAP_PRIVATE - MAP_PRIVATE or MAP_SHARED required + * MAP_FIXED - Will cause an error + * MAP_FILE - Ignored + * MAP_ANONYMOUS - Optional + * MAP_ANON - Will cause an error + * MAP_GROWSDOWN - Ignored + * MAP_DENYWRITE - Will cause an error + * MAP_EXECUTABLE - Ignored + * MAP_LOCKED - Ignored + * MAP_NORESERVE - Ignored + * MAP_POPULATE - Ignored + * MAP_NONBLOCK - Ignored + * fd file descriptor of the backing file -- required. + * offset The offset into the file to map + * + * Returned Value: + * On success, mmap() returns a pointer to the mapped area. On error, the + * value MAP_FAILED is returned, and errno is set appropriately. + * + * EACCES + * The fd argument is not open for read, regardless of the + * protection specified, or fd is not open for write and PROT_WRITE + * was specified for a MAP_SHARED type mapping. + * ENOSYS + * Returned if any of the unsupported mmap() features are attempted + * EBADF + * 'fd' is not a valid file descriptor. + * EINVAL + * Length is 0. flags contained neither MAP_PRIVATE or MAP_SHARED, or + * contained both of these values. + * ENODEV + * The underlying filesystem of the specified file does not support + * memory mapping. + * ENOMEM + * Insufficient memory is available to map the file. + * + ****************************************************************************/ + +FAR void *mmap(FAR void *start, size_t length, int prot, int flags, + int fd, off_t offset) +{ + FAR struct file *filep; + FAR void *mapped; + int ret; + + if (fs_getfilep(fd, &filep) < 0) + { + ferr("ERROR: Invalid file descriptor, fd=%d\n", fd); + ret = -EBADF; + goto errout; + } + + ret = file_mmap_(filep, start, length, + prot, flags, offset, false, &mapped); + if (ret < 0) + { + goto errout; + } + + return mapped; errout: set_errno(-ret); diff --git a/fs/mmap/fs_munmap.c b/fs/mmap/fs_munmap.c index bb4f127..9ef45f4 100644 --- a/fs/mmap/fs_munmap.c +++ b/fs/mmap/fs_munmap.c @@ -38,60 +38,10 @@ #include "fs_rammap.h" /**************************************************************************** - * Public Functions + * Private Functions ****************************************************************************/ -/**************************************************************************** - * Name: munmap - * - * Description: - * - * munmap() system call deletes mappings for the specified address range. - * All memory starting with 'start' and continuing for a length of 'length' - * bytes are removed. - * - * NuttX operates in a flat open address space. Therefore, it generally - * does not require mmap() and, hence, munmap functionality. There are - * two exceptions where mmap() is available: - * - * 1. mmap() is the API that is used to support direct access to random - * access media under the following very restrictive conditions: - * - * a. The filesystem supports the FIOC_MMAP ioctl command. Any file - * system that maps files contiguously on the media should support - * this ioctl. (vs. file system that scatter files over the media - * in non-contiguous sectors). As of this writing, ROMFS is the - * only file system that meets this requirement. - * b. The underlying block driver supports the BIOC_XIPBASE ioctl - * command that maps the underlying media to a randomly accessible - * address. At present, only the RAM/ROM disk driver does this. - * - * munmap() is still not required in this first case. In this first - * The mapped address is a static address in the MCUs address space - * does not need to be munmapped. Support for munmap() in this case - * provided by the simple definition in sys/mman.h: - * - * #define munmap(start, length) - * - * 2. If CONFIG_FS_RAMMAP is defined in the configuration, then mmap() will - * support simulation of memory mapped files by copying files whole - * into RAM. munmap() is required in this case to free the allocated - * memory holding the shared copy of the file. - * - * Input Parameters: - * start The start address of the mapping to delete. For this - * simplified munmap() implementation, the *must* be the start - * address of the memory region (the same address returned by - * mmap()). - * length The length region to be umapped. - * - * Returned Value: - * On success, munmap() returns 0, on failure -1, and errno is set - * (probably to EINVAL). - * - ****************************************************************************/ - -int munmap(FAR void *start, size_t length) +static int file_munmap_(FAR void *start, size_t length, bool kernel) { #ifdef CONFIG_FS_RAMMAP FAR struct fs_rammap_s *prev; @@ -99,15 +49,13 @@ int munmap(FAR void *start, size_t length) FAR void *newaddr; unsigned int offset; int ret; - int errcode; /* Find a region containing this start and length in the list of regions */ ret = nxsem_wait(&g_rammaps.exclsem); if (ret < 0) { - errcode = ret; - goto errout; + return ret; } /* Search the list of regions */ @@ -129,7 +77,7 @@ int munmap(FAR void *start, size_t length) if (!curr) { ferr("ERROR: Region not found\n"); - errcode = EINVAL; + ret = -EINVAL; goto errout_with_semaphore; } @@ -144,7 +92,7 @@ int munmap(FAR void *start, size_t length) if (offset + length < curr->length) { ferr("ERROR: Cannot umap without unmapping to the end\n"); - errcode = ENOSYS; + ret = -ENOSYS; goto errout_with_semaphore; } @@ -171,7 +119,14 @@ int munmap(FAR void *start, size_t length) /* Then free the region */ - kumm_free(curr); + if (curr->kernel) + { + kmm_free(curr) + } + else + { + kumm_free(curr); + } } /* No.. We have been asked to "unmap' only a portion of the memory @@ -180,8 +135,17 @@ int munmap(FAR void *start, size_t length) else { - newaddr = kumm_realloc(curr->addr, - sizeof(struct fs_rammap_s) + length); + if (kernel) + { + newaddr = kmm_realloc(curr->addr, + sizeof(struct fs_rammap_s) + length); + } + else + { + newaddr = kumm_realloc(curr->addr, + sizeof(struct fs_rammap_s) + length); + } + DEBUGASSERT(newaddr == (FAR void *)(curr->addr)); UNUSED(newaddr); /* May not be used */ curr->length = length; @@ -192,11 +156,90 @@ int munmap(FAR void *start, size_t length) errout_with_semaphore: nxsem_post(&g_rammaps.exclsem); - -errout: - set_errno(errcode); - return ERROR; + return ret; #else return OK; #endif /* CONFIG_FS_RAMMAP */ } + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: file_mummap + * + * Description: + * Equivalent to the standard file_mummap() function except it does not set + * the errno variable. + * + ****************************************************************************/ + +int file_munmap(FAR void *start, size_t length) +{ + return file_munmap_(start, length, true); +} + +/**************************************************************************** + * Name: munmap + * + * Description: + * + * munmap() system call deletes mappings for the specified address range. + * All memory starting with 'start' and continuing for a length of 'length' + * bytes are removed. + * + * NuttX operates in a flat open address space. Therefore, it generally + * does not require mmap() and, hence, munmap functionality. There are + * two exceptions where mmap() is available: + * + * 1. mmap() is the API that is used to support direct access to random + * access media under the following very restrictive conditions: + * + * a. The filesystem supports the FIOC_MMAP ioctl command. Any file + * system that maps files contiguously on the media should support + * this ioctl. (vs. file system that scatter files over the media + * in non-contiguous sectors). As of this writing, ROMFS is the + * only file system that meets this requirement. + * b. The underlying block driver supports the BIOC_XIPBASE ioctl + * command that maps the underlying media to a randomly accessible + * address. At present, only the RAM/ROM disk driver does this. + * + * munmap() is still not required in this first case. In this first + * The mapped address is a static address in the MCUs address space + * does not need to be munmapped. Support for munmap() in this case + * provided by the simple definition in sys/mman.h: + * + * #define munmap(start, length) + * + * 2. If CONFIG_FS_RAMMAP is defined in the configuration, then mmap() will + * support simulation of memory mapped files by copying files whole + * into RAM. munmap() is required in this case to free the allocated + * memory holding the shared copy of the file. + * + * Input Parameters: + * start The start address of the mapping to delete. For this + * simplified munmap() implementation, the *must* be the start + * address of the memory region (the same address returned by + * mmap()). + * length The length region to be umapped. + * + * Returned Value: + * On success, munmap() returns 0, on failure -1, and errno is set + * (probably to EINVAL). + * + ****************************************************************************/ + +int munmap(FAR void *start, size_t length) +{ + int ret; + + ret = file_munmap_(start, length, false); + if (ret < 0) + { + set_errno(-ret); + ret = ERROR; + } + + return ret; +} diff --git a/fs/mmap/fs_rammap.c b/fs/mmap/fs_rammap.c index 2145a7a..30f5d61 100644 --- a/fs/mmap/fs_rammap.c +++ b/fs/mmap/fs_rammap.c @@ -62,14 +62,15 @@ struct fs_allmaps_s g_rammaps = * Support simulation of memory mapped files by copying files into RAM. * * Input Parameters: - * fd file descriptor of the backing file -- required. + * filep file descriptor of the backing file -- required. * length The length of the mapping. For exception #1 above, this length * ignored: The entire underlying media is always accessible. * offset The offset into the file to map + * kernel kmm_zalloc or kumm_zalloc + * mapped The pointer to the mapped area * * Returned Value: - * On success, rammmap() returns a pointer to the mapped area. On error, - * the value MAP_FAILED is returned, and errno is set appropriately. + * On success, rammmap returns 0. Otherwise errno is returned appropriately. * * EBADF * 'fd' is not a valid file descriptor. @@ -80,7 +81,8 @@ struct fs_allmaps_s g_rammaps = * ****************************************************************************/ -FAR void *rammap(int fd, size_t length, off_t offset) +int rammap(FAR struct file *filep, size_t length, + off_t offset, bool kernel, FAR void **mapped) { FAR struct fs_rammap_s *map; FAR uint8_t *alloc; @@ -104,12 +106,13 @@ FAR void *rammap(int fd, size_t length, off_t offset) /* Allocate a region of memory of the specified size */ - alloc = (FAR uint8_t *)kumm_malloc(sizeof(struct fs_rammap_s) + length); + alloc = (FAR uint8_t *)kernel ? + kmm_malloc(sizeof(struct fs_rammap_s) + length); + kumm_malloc(sizeof(struct fs_rammap_s) + length); if (!alloc) { ferr("ERROR: Region allocation failed, length: %d\n", (int)length); - ret = -ENOMEM; - goto errout; + return -ENOMEM; } /* Initialize the region */ @@ -122,7 +125,7 @@ FAR void *rammap(int fd, size_t length, off_t offset) /* Seek to the specified file offset */ - fpos = nx_seek(fd, offset, SEEK_SET); + fpos = file_seek(filep, offset, SEEK_SET); if (fpos < 0) { /* Seek failed... errno has already been set, but EINVAL is probably @@ -139,7 +142,7 @@ FAR void *rammap(int fd, size_t length, off_t offset) rdbuffer = map->addr; while (length > 0) { - nread = nx_read(fd, rdbuffer, length); + nread = file_read(filep, rdbuffer, length); if (nread < 0) { /* Handle the special case where the read was interrupted by a @@ -187,14 +190,20 @@ FAR void *rammap(int fd, size_t length, off_t offset) g_rammaps.head = map; nxsem_post(&g_rammaps.exclsem); - return map->addr; + *mapped = map->addr; + return OK; errout_with_region: - kumm_free(alloc); + if (kernel) + { + kmm_free(alloc); + } + else + { + kumm_free(alloc); + } -errout: - set_errno(-ret); - return MAP_FAILED; + return ret; } #endif /* CONFIG_FS_RAMMAP */ diff --git a/fs/mmap/fs_rammap.h b/fs/mmap/fs_rammap.h index 096c9c3..ec4fbbc 100644 --- a/fs/mmap/fs_rammap.h +++ b/fs/mmap/fs_rammap.h @@ -88,14 +88,15 @@ extern struct fs_allmaps_s g_rammaps; * Support simulation of memory mapped files by copying files into RAM. * * Input Parameters: - * fd file descriptor of the backing file -- required. + * filep file descriptor of the backing file -- required. * length The length of the mapping. For exception #1 above, this length * ignored: The entire underlying media is always accessible. * offset The offset into the file to map + * kernel kmm_zalloc or kumm_zalloc + * mapped The pointer to the mapped area * * Returned Value: - * On success, rammmap() returns a pointer to the mapped area. On error, - * the value MAP_FAILED is returned, and errno is set appropriately. + * On success rammmap returns 0. Otherwise errno is returned appropriately. * * EBADF * 'fd' is not a valid file descriptor. @@ -106,7 +107,8 @@ extern struct fs_allmaps_s g_rammaps; * ****************************************************************************/ -FAR void *rammap(int fd, size_t length, off_t offset); +int rammap(FAR struct file *filep, size_t length, + off_t offset, bool kernel, FAR void **mapped); #endif /* CONFIG_FS_RAMMAP */ #endif /* __FS_MMAP_RAMMAP_H */ diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h index 6a2a557..af6157e 100644 --- a/include/nuttx/fs/fs.h +++ b/include/nuttx/fs/fs.h @@ -1169,6 +1169,30 @@ int file_truncate(FAR struct file *filep, off_t length); #endif /**************************************************************************** + * Name: file_mmap + * + * Description: + * Equivalent to the standard mmap() function except that is accepts + * a struct file instance instead of a file descriptor and it does not set + * the errno variable. + * + ****************************************************************************/ + +int file_mmap(FAR struct file *filep, FAR void *start, size_t length, + int prot, int flags, off_t offset, FAR void **mapped); + +/**************************************************************************** + * Name: file_mummap + * + * Description: + * Equivalent to the standard mummap() function except it does not set + * the errno variable. + * + ****************************************************************************/ + +int file_munmap(FAR void *start, size_t length); + +/**************************************************************************** * Name: file_ioctl * * Description: