From d04205aa3d721d6415d2ee6206d4dfcfb1f02cb3 Mon Sep 17 00:00:00 2001 From: chenrun1 Date: Wed, 29 May 2024 11:47:01 +0800 Subject: [PATCH] fs/mmap/msync:support msync. Summary: 1.Added msync callback in struct mm_map_entry_s 2.Added msync API in fs_msync.c 3.Added static msync_rammap for rammap. Signed-off-by: chenrun1 --- fs/inode/fs_files.c | 28 ++++++++++- fs/mmap/CMakeLists.txt | 2 +- fs/mmap/Make.defs | 2 +- fs/mmap/fs_anonmap.c | 2 +- fs/mmap/fs_msync.c | 95 ++++++++++++++++++++++++++++++++++++ fs/mmap/fs_rammap.c | 78 ++++++++++++++++++++++++++++- include/nuttx/fs/fs.h | 16 ++++++ include/nuttx/mm/map.h | 13 +++-- include/sys/syscall_lookup.h | 1 + syscall/syscall.csv | 1 + 10 files changed, 227 insertions(+), 11 deletions(-) create mode 100644 fs/mmap/fs_msync.c diff --git a/fs/inode/fs_files.c b/fs/inode/fs_files.c index 2a01978acb..b26cc3aa7b 100644 --- a/fs/inode/fs_files.c +++ b/fs/inode/fs_files.c @@ -799,6 +799,33 @@ int fs_getfilep(int fd, FAR struct file **filep) return OK; } +/**************************************************************************** + * Name: fs_reffilep + * + * Description: + * To specify filep increase the reference count. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_FS_REFCOUNT +void fs_reffilep(FAR struct file *filep) +{ + /* This interface is used to increase the reference count of filep */ + + irqstate_t flags; + + DEBUGASSERT(filep); + flags = spin_lock_irqsave(NULL); + filep->f_refs++; + spin_unlock_irqrestore(NULL, flags); +} + /**************************************************************************** * Name: fs_putfilep * @@ -811,7 +838,6 @@ int fs_getfilep(int fd, FAR struct file **filep) * file' instance. ****************************************************************************/ -#ifdef CONFIG_FS_REFCOUNT int fs_putfilep(FAR struct file *filep) { irqstate_t flags; diff --git a/fs/mmap/CMakeLists.txt b/fs/mmap/CMakeLists.txt index 4417703553..d788cf02b1 100644 --- a/fs/mmap/CMakeLists.txt +++ b/fs/mmap/CMakeLists.txt @@ -18,7 +18,7 @@ # # ############################################################################## -set(SRCS fs_mmap.c fs_munmap.c fs_mmisc.c) +set(SRCS fs_mmap.c fs_munmap.c fs_mmisc.c fs_msync.c) if(CONFIG_FS_RAMMAP) list(APPEND SRCS fs_rammap.c) diff --git a/fs/mmap/Make.defs b/fs/mmap/Make.defs index dff6e732b8..09d757f899 100644 --- a/fs/mmap/Make.defs +++ b/fs/mmap/Make.defs @@ -18,7 +18,7 @@ # ############################################################################ -CSRCS += fs_mmap.c fs_munmap.c fs_mmisc.c +CSRCS += fs_mmap.c fs_munmap.c fs_mmisc.c fs_msync.c ifeq ($(CONFIG_FS_RAMMAP),y) CSRCS += fs_rammap.c diff --git a/fs/mmap/fs_anonmap.c b/fs/mmap/fs_anonmap.c index bc28245755..754f64d329 100644 --- a/fs/mmap/fs_anonmap.c +++ b/fs/mmap/fs_anonmap.c @@ -44,7 +44,7 @@ static int unmap_anonymous(FAR struct task_group_s *group, FAR void *start, size_t length) { - FAR void *newaddr; + FAR void *newaddr = NULL; off_t offset; bool kernel = entry->priv.i; int ret = OK; diff --git a/fs/mmap/fs_msync.c b/fs/mmap/fs_msync.c new file mode 100644 index 0000000000..f2efe33c2e --- /dev/null +++ b/fs/mmap/fs_msync.c @@ -0,0 +1,95 @@ +/**************************************************************************** + * fs/mmap/fs_msync.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include +#include + +#include "inode/inode.h" +#include "fs_rammap.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: msync + * + * Description: + * Equivalent to the standard msync() function except that it accepts + * a struct file instance instead of a memory address and it does not set + * the errno variable. + * + * Input Parameters: + * file - A pointer to the struct file instance representing the + * mappedfile + * start - The starting address of the memory region to be synchronized + * length - The length of the memory region to be synchronized + * flags - Flags that determine the type of synchronization to be + * performed + * + * Returned Value: + * On success, returns 0 (OK); On failure, returns a negated errno value. + * + ****************************************************************************/ + +int msync(FAR void *start, size_t length, int flags) +{ + FAR struct mm_map_entry_s *entry; + int ret; + + ret = mm_map_lock(); + if (ret < 0) + { + return ret; + } + + entry = mm_map_find(get_current_mm(), start, length); + if (!entry) + { + ferr("ERROR: Region not found\n"); + ret = -ENOMEM; + goto out; + } + + if (entry->msync == NULL) + { + ret = OK; + goto out; + } + + ret = entry->msync(entry, start, length, flags); +out: + mm_map_unlock(); + 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 af7f41653e..fbcc7507df 100644 --- a/fs/mmap/fs_rammap.c +++ b/fs/mmap/fs_rammap.c @@ -49,14 +49,84 @@ * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: msync_rammap + ****************************************************************************/ + +static int msync_rammap(FAR struct mm_map_entry_s *entry, FAR void *start, + size_t length, int flags) +{ + FAR struct file *filep = (FAR void *)((uintptr_t)entry->priv.p & ~1); + FAR uint8_t *wrbuffer = start; + ssize_t nwrite = 0; + off_t offset; + off_t fpos; + off_t opos; + + offset = (uintptr_t)start - (uintptr_t)entry->vaddr; + if (length > entry->length - offset) + { + length = entry->length - offset; + } + + opos = file_seek(filep, 0, SEEK_CUR); + if (opos < 0) + { + ferr("ERROR: Get current position failed\n"); + return opos; + } + + fpos = file_seek(filep, entry->offset + offset, SEEK_SET); + if (fpos < 0) + { + ferr("ERRORL Seek to position %"PRIdOFF" failed\n", fpos); + return fpos; + } + + while (length > 0) + { + nwrite = file_write(filep, wrbuffer, length); + if (nwrite < 0) + { + /* Handle the special case where the write was interrupted by a + * signal. + */ + + if (nwrite != -EINTR) + { + /* All other write errors are bad. */ + + ferr("ERROR: Write failed: offset=%"PRIdOFF" nwrite=%zd\n", + entry->offset, nwrite); + break; + } + } + + /* Increment number of bytes written */ + + wrbuffer += nwrite; + length -= nwrite; + } + + /* Restore file pos */ + + file_seek(filep, opos, SEEK_SET); + return nwrite >= 0 ? 0 : nwrite; +} + +/**************************************************************************** + * Name: unmap_rammap + ****************************************************************************/ + static int unmap_rammap(FAR struct task_group_s *group, FAR struct mm_map_entry_s *entry, FAR void *start, size_t length) { + FAR struct file *filep = (FAR void *)((uintptr_t)entry->priv.p & ~1); + enum mm_map_type_e type = (uintptr_t)entry->priv.p & 1; FAR void *newaddr = NULL; off_t offset; - enum mm_map_type_e type = entry->priv.i; int ret = OK; /* Get the offset from the beginning of the region and the actual number @@ -94,6 +164,8 @@ static int unmap_rammap(FAR struct task_group_s *group, kumm_free(entry->vaddr); } + fs_putfilep(filep); + /* Then remove the mapping from the list */ ret = mm_map_remove(get_group_mm(group), entry); @@ -248,8 +320,10 @@ int rammap(FAR struct file *filep, FAR struct mm_map_entry_s *entry, /* Add the buffer to the list of regions */ out: - entry->priv.i = type; + fs_reffilep(filep); + entry->priv.p = (FAR void *)((uintptr_t)filep | type); entry->munmap = unmap_rammap; + entry->msync = msync_rammap; ret = mm_map_add(get_current_mm(), entry); if (ret < 0) diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h index ac20d38b12..9a85594ff7 100644 --- a/include/nuttx/fs/fs.h +++ b/include/nuttx/fs/fs.h @@ -1159,6 +1159,22 @@ int nx_open(FAR const char *path, int oflags, ...); int fs_getfilep(int fd, FAR struct file **filep); +/**************************************************************************** + * Name: fs_reffilep + * + * Description: + * To specify filep increase the reference count. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void fs_reffilep(FAR struct file *filep); + /**************************************************************************** * Name: fs_putfilep * diff --git a/include/nuttx/mm/map.h b/include/nuttx/mm/map.h index 7405ebce0d..e9d9181807 100644 --- a/include/nuttx/mm/map.h +++ b/include/nuttx/mm/map.h @@ -56,11 +56,14 @@ struct mm_map_entry_s int i; } priv; - /* Drivers which register mappings may also implement the unmap function - * to undo anything done in mmap. - * Nb. Implementation must NOT use "this_task()->group" since it is not - * valid during process exit. The argument "group" will be NULL in this - * case. + int (*msync)(FAR struct mm_map_entry_s *entry, FAR void *start, + size_t length, int flags); + + /* Drivers which register mappings may also + * implement the unmap function to undo anything done in mmap. + * Nb. Implementation must NOT use "this_task()->group" since + * this is not valid during process exit. The argument "group" will be + * NULL in this case. */ int (*munmap)(FAR struct task_group_s *group, diff --git a/include/sys/syscall_lookup.h b/include/sys/syscall_lookup.h index 0f45083d9c..d64a9d7512 100644 --- a/include/sys/syscall_lookup.h +++ b/include/sys/syscall_lookup.h @@ -248,6 +248,7 @@ SYSCALL_LOOKUP(fchown, 3) SYSCALL_LOOKUP(utimens, 2) SYSCALL_LOOKUP(lutimens, 2) SYSCALL_LOOKUP(futimens, 2) +SYSCALL_LOOKUP(msync, 3) SYSCALL_LOOKUP(munmap, 2) #if defined(CONFIG_PSEUDOFS_SOFTLINKS) diff --git a/syscall/syscall.csv b/syscall/syscall.csv index 2c4797fb09..c26caca14a 100644 --- a/syscall/syscall.csv +++ b/syscall/syscall.csv @@ -77,6 +77,7 @@ "mq_timedreceive","mqueue.h","!defined(CONFIG_DISABLE_MQUEUE)","ssize_t","mqd_t","FAR char *","size_t","FAR unsigned int *","FAR const struct timespec *" "mq_timedsend","mqueue.h","!defined(CONFIG_DISABLE_MQUEUE)","int","mqd_t","FAR const char *","size_t","unsigned int","FAR const struct timespec *" "mq_unlink","mqueue.h","!defined(CONFIG_DISABLE_MQUEUE)","int","FAR const char *" +"msync","sys/mman.h","","int","FAR void *","size_t","int" "munmap","sys/mman.h","","int","FAR void *","size_t" "nanosleep","time.h","","int","FAR const struct timespec *","FAR struct timespec *" "nx_mkfifo","nuttx/fs/fs.h","defined(CONFIG_PIPES) && CONFIG_DEV_FIFO_SIZE > 0","int","FAR const char *","mode_t","size_t"