This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit b8e30b54ec9c3092cb44394cdb6a4958dd6d3b42 Author: Ville Juven <ville.ju...@unikie.com> AuthorDate: Sat Jun 7 14:05:34 2025 +0800 fs/vfs: Separate file descriptors from file descriptions This patch is a rework of the NuttX file descriptor implementation. The goal is two-fold: 1. Improve POSIX compliance. The old implementation tied file description to inode only, not the file struct. POSIX however dictates otherwise. 2. Fix a bug with descriptor duplication (dup2() and dup3()). There is an existing race condition with this POSIX API that currently results in a kernel side crash. The crash occurs when a partially open / closed file descriptor is duplicated. The reason for the crash is that even if the descriptor is closed, the file might still be in use by the kernel (due to e.g. ongoing write to file). The open file data is changed by file_dup3() and this causes a crash in the device / drivers themselves as they lose access to the inode and private data. The fix is done by separating struct file into file and file descriptor structs. The file struct can live on even if the descriptor is closed, fixing the crash. This also fixes the POSIX issue, as two descriptors can now point to the same file. Signed-off-by: Ville Juven <ville.ju...@unikie.com> Signed-off-by: dongjiuzhu1 <dongjiuz...@xiaomi.com> --- crypto/cryptodev.c | 3 +- drivers/misc/optee.c | 3 +- fs/inode/fs_files.c | 641 +++++++++++++++++++++---------------- fs/inode/inode.h | 8 +- fs/mqueue/mq_open.c | 24 +- fs/notify/inotify.c | 6 +- fs/procfs/fs_procfsproc.c | 10 +- fs/shm/shm_open.c | 18 +- fs/socket/socket.c | 2 +- fs/vfs/fs_close.c | 49 +-- fs/vfs/fs_dup.c | 30 +- fs/vfs/fs_dup2.c | 59 +--- fs/vfs/fs_dup3.c | 3 +- fs/vfs/fs_epoll.c | 2 +- fs/vfs/fs_eventfd.c | 4 +- fs/vfs/fs_fcntl.c | 161 +++++----- fs/vfs/fs_ioctl.c | 123 +++---- fs/vfs/fs_open.c | 45 ++- fs/vfs/fs_signalfd.c | 4 +- fs/vfs/fs_timerfd.c | 4 +- include/nuttx/fs/fs.h | 290 ++++++++++------- include/nuttx/fs/ioctl.h | 10 + include/nuttx/sched.h | 16 +- sched/group/group_create.c | 2 +- sched/group/group_leave.c | 2 +- sched/group/group_setuptaskfiles.c | 4 +- sched/misc/assert.c | 8 +- sched/sched/sched_getfiles.c | 20 +- sched/task/task_spawnparms.c | 15 +- 29 files changed, 825 insertions(+), 741 deletions(-) diff --git a/crypto/cryptodev.c b/crypto/cryptodev.c index f5c17632cd..ce242b8718 100644 --- a/crypto/cryptodev.c +++ b/crypto/cryptodev.c @@ -1028,8 +1028,7 @@ static int cryptoioctl(FAR struct file *filep, int cmd, unsigned long arg) TAILQ_INIT(&fcr->csessions); TAILQ_INIT(&fcr->crpk_ret); - fd = file_allocate(&g_cryptoinode, 0, - 0, fcr, 0, true); + fd = file_allocate_from_inode(&g_cryptoinode, 0, 0, fcr, 0); if (fd < 0) { kmm_free(fcr); diff --git a/drivers/misc/optee.c b/drivers/misc/optee.c index 0415318566..43ec2a5e47 100644 --- a/drivers/misc/optee.c +++ b/drivers/misc/optee.c @@ -1038,7 +1038,8 @@ optee_ioctl_shm_register(FAR struct optee_priv_data *priv, return ret; } - ret = file_allocate(&g_optee_shm_inode, O_CLOEXEC, 0, shm, 0, true); + ret = file_allocate_from_inode(&g_optee_shm_inode, O_CLOEXEC, + 0, shm, 0, true); if (ret < 0) { optee_shm_free(shm); diff --git a/fs/inode/fs_files.c b/fs/inode/fs_files.c index 3b17194f86..a4e027541f 100644 --- a/fs/inode/fs_files.c +++ b/fs/inode/fs_files.c @@ -59,56 +59,39 @@ ****************************************************************************/ /**************************************************************************** - * Name: files_fget_by_index + * Name: fdlist_get_by_index ****************************************************************************/ -static FAR struct file *files_fget_by_index(FAR struct filelist *list, - int l1, int l2, FAR bool *new) +static void fdlist_get_by_index(FAR struct fdlist *list, + int l1, int l2, + FAR struct file **filep, + FAR struct fd **fdp) { - FAR struct file *filep; + FAR struct fd *fdp1; irqstate_t flags; flags = spin_lock_irqsave_notrace(&list->fl_lock); - filep = &list->fl_files[l1][l2]; - spin_unlock_irqrestore_notrace(&list->fl_lock, flags); - - if (filep->f_inode != NULL) + fdp1 = &list->fl_fds[l1][l2]; + *filep = fdp1->f_file; + if (*filep != NULL) { - /* When the reference count is zero but the inode has not yet been - * released, At this point we should return a null pointer - */ - - int32_t refs = atomic_read(&filep->f_refs); - do - { - if (refs == 0) - { - filep = NULL; - break; - } - } - while (!atomic_try_cmpxchg(&filep->f_refs, &refs, refs + 1)); - } - else if (new == NULL) - { - filep = NULL; + atomic_fetch_add(&(*filep)->f_refs, 1); } - else if (atomic_fetch_add(&filep->f_refs, 1) == 0) + + spin_unlock_irqrestore_notrace(&list->fl_lock, flags); + if (fdp != NULL) { - atomic_fetch_add(&filep->f_refs, 1); - *new = true; + *fdp = fdp1; } - - return filep; } /**************************************************************************** - * Name: files_extend + * Name: fdlist_extend ****************************************************************************/ -static int files_extend(FAR struct filelist *list, size_t row) +static int fdlist_extend(FAR struct fdlist *list, size_t row) { - FAR struct file **files; + FAR struct fd **fds; uint8_t orig_rows; FAR void *tmp; int flags; @@ -123,13 +106,13 @@ static int files_extend(FAR struct filelist *list, size_t row) if (CONFIG_NFILE_DESCRIPTORS_PER_BLOCK * orig_rows > OPEN_MAX) { - files_dumplist(list); + fdlist_dump(list); return -EMFILE; } - files = fs_heap_malloc(sizeof(FAR struct file *) * row); - DEBUGASSERT(files); - if (files == NULL) + fds = fs_heap_malloc(sizeof(FAR struct fd *) * row); + DEBUGASSERT(fds); + if (fds == NULL) { return -ENFILE; } @@ -137,16 +120,16 @@ static int files_extend(FAR struct filelist *list, size_t row) i = orig_rows; do { - files[i] = fs_heap_zalloc(sizeof(struct file) * - CONFIG_NFILE_DESCRIPTORS_PER_BLOCK); - if (files[i] == NULL) + fds[i] = fs_heap_zalloc(sizeof(struct fd) * + CONFIG_NFILE_DESCRIPTORS_PER_BLOCK); + if (fds[i] == NULL) { while (--i >= orig_rows) { - fs_heap_free(files[i]); + fs_heap_free(fds[i]); } - fs_heap_free(files); + fs_heap_free(fds); return -ENFILE; } } @@ -165,27 +148,26 @@ static int files_extend(FAR struct filelist *list, size_t row) for (j = orig_rows; j < i; j++) { - fs_heap_free(files[j]); + fs_heap_free(fds[j]); } - fs_heap_free(files); + fs_heap_free(fds); return OK; } - if (list->fl_files != NULL) + if (list->fl_fds != NULL) { - memcpy(files, list->fl_files, - list->fl_rows * sizeof(FAR struct file *)); + memcpy(fds, list->fl_fds, list->fl_rows * sizeof(FAR struct fd *)); } - tmp = list->fl_files; - list->fl_files = files; + tmp = list->fl_fds; + list->fl_fds = fds; list->fl_rows = row; spin_unlock_irqrestore_notrace(&list->fl_lock, flags); - if (tmp != NULL && tmp != &list->fl_prefile) + if (tmp != NULL && tmp != &list->fl_prefd) { fs_heap_free(tmp); } @@ -193,10 +175,65 @@ static int files_extend(FAR struct filelist *list, size_t row) return OK; } +/**************************************************************************** + * Name: fdlist_uninstall + ****************************************************************************/ + +static void fdlist_uninstall(FAR struct fdlist *list, FAR struct fd *fdp) +{ + FAR struct file *filep = NULL; + irqstate_t flags; + + flags = spin_lock_irqsave_notrace(&list->fl_lock); + + if (fdp->f_file != NULL) + { +#ifdef CONFIG_FDSAN + fdp->f_tag_fdsan = 0; +#endif +#ifdef CONFIG_FDCHECK + fdp->f_tag_fdcheck = 0; +#endif + filep = fdp->f_file; + fdp->f_file = NULL; + } + + spin_unlock_irqrestore_notrace(&list->fl_lock, flags); + file_put(filep); +} + +static void fdlist_install(FAR struct fdlist *list, int fd, + FAR struct file *filep, int oflags) +{ + FAR struct file *oldfilep; + FAR struct fd *fdp; + irqstate_t flags; + int l1; + int l2; + + l1 = fd / CONFIG_NFILE_DESCRIPTORS_PER_BLOCK; + l2 = fd % CONFIG_NFILE_DESCRIPTORS_PER_BLOCK; + + flags = spin_lock_irqsave_notrace(&list->fl_lock); + + fdp = &list->fl_fds[l1][l2]; + oldfilep = fdp->f_file; + fdp->f_file = filep; + file_ref(filep); + fdp->f_cloexec = !!(oflags & O_CLOEXEC); + FS_ADD_BACKTRACE(fdp); + + spin_unlock_irqrestore_notrace(&list->fl_lock, flags); + file_put(oldfilep); +} + +/**************************************************************************** + * Name: task_fssync + ****************************************************************************/ + static void task_fssync(FAR struct tcb_s *tcb, FAR void *arg) { FAR struct tcb_s *ctcb; - FAR struct file *filep; int pid = tcb->pid; uint8_t rows; int i; @@ -207,28 +244,25 @@ static void task_fssync(FAR struct tcb_s *tcb, FAR void *arg) return; } - rows = tcb->group->tg_filelist.fl_rows; + rows = tcb->group->tg_fdlist.fl_rows; for (i = 0; i < rows; i++) { for (j = 0; j < CONFIG_NFILE_DESCRIPTORS_PER_BLOCK; j++) { + FAR struct file *filep; + ctcb = nxsched_get_tcb(pid); if (ctcb == NULL || ctcb->group == NULL || ctcb != tcb) { return; } - filep = files_fget_by_index(&ctcb->group->tg_filelist, - i, j, NULL); + fdlist_get_by_index(&ctcb->group->tg_fdlist, i, j, &filep, NULL); if (filep != NULL) { file_fsync(filep); - ctcb = nxsched_get_tcb(pid); - if (ctcb != NULL && ctcb->group != NULL && ctcb == tcb) - { - file_put(filep); - } + file_put(filep); } } } @@ -239,14 +273,14 @@ static void task_fssync(FAR struct tcb_s *tcb, FAR void *arg) ****************************************************************************/ /**************************************************************************** - * Name: nx_dup3_from_tcb + * Name: fdlist_dup3 * * Description: - * nx_dup3_from_tcb() is similar to the standard 'dup3' interface + * fdlist_dup3() is similar to the standard 'dup3' interface * except that is not a cancellation point and it does not modify the * errno variable. * - * nx_dup3_from_tcb() is an internal NuttX interface and should not be + * fdlist_dup3() is an internal NuttX interface and should not be * called from applications. * * Clone a file descriptor to a specific descriptor number and @@ -258,70 +292,46 @@ static void task_fssync(FAR struct tcb_s *tcb, FAR void *arg) * ****************************************************************************/ -int nx_dup3_from_tcb(FAR struct tcb_s *tcb, int fd1, int fd2, int flags) +int fdlist_dup3(FAR struct fdlist *list, int fd1, int fd2, int flags) { - FAR struct filelist *list; FAR struct file *filep1; - FAR struct file *filep; - bool new = false; - int count; int ret; if (fd1 == fd2) { - return fd1; + return -EINVAL; } #ifdef CONFIG_FDCHECK - fd1 = fdcheck_restore(fd1); fd2 = fdcheck_restore(fd2); #endif /* Get the file descriptor list. It should not be NULL in this context. */ - list = nxsched_get_files_from_tcb(tcb); - count = files_countlist(list); - - if (fd1 < 0 || fd1 >= count || fd2 < 0) + if (fd2 < 0) { return -EBADF; } - if (fd2 >= count) + if (fd2 >= fdlist_count(list)) { - ret = files_extend(list, fd2 / CONFIG_NFILE_DESCRIPTORS_PER_BLOCK + 1); + ret = fdlist_extend(list, + fd2 / CONFIG_NFILE_DESCRIPTORS_PER_BLOCK + 1); if (ret < 0) { return ret; } } - filep1 = files_fget(list, fd1); - if (filep1 == NULL) - { - return -EBADF; - } - - filep = files_fget_by_index(list, - fd2 / CONFIG_NFILE_DESCRIPTORS_PER_BLOCK, - fd2 % CONFIG_NFILE_DESCRIPTORS_PER_BLOCK, - &new); - - /* Perform the dup3 operation */ - - ret = file_dup3(filep1, filep, flags); - file_put(filep1); - file_put(filep); + ret = fdlist_get(list, fd1, &filep1); if (ret < 0) { - if (new) - { - file_put(filep); - } - return ret; } + fdlist_install(list, fd2, filep1, flags); + file_put(filep1); + #ifdef CONFIG_FDCHECK return fdcheck_protect(fd2); #else @@ -330,37 +340,37 @@ int nx_dup3_from_tcb(FAR struct tcb_s *tcb, int fd1, int fd2, int flags) } /**************************************************************************** - * Name: files_initlist + * Name: fdlist_init * - * Description: Initializes the list of files for a new task + * Description: Initializes the list of file descriptors for a new task. * ****************************************************************************/ -void files_initlist(FAR struct filelist *list) +void fdlist_init(FAR struct fdlist *list) { /* The first row will reuse pre-allocated files, which will avoid * unnecessary allocator accesses during file initialization. */ list->fl_rows = 1; - list->fl_files = &list->fl_prefile; - list->fl_prefile = list->fl_prefiles; + list->fl_fds = &list->fl_prefd; + list->fl_prefd = list->fl_prefds; spin_lock_init(&list->fl_lock); } /**************************************************************************** - * Name: files_dumplist + * Name: fdlist_dump * * Description: - * Dump the list of files. + * Dump the list of file descriptors. * ****************************************************************************/ #ifdef CONFIG_SCHED_DUMP_ON_EXIT -void files_dumplist(FAR struct filelist *list) +void fdlist_dump(FAR struct fdlist *list) { FAR char *path; - int count = files_countlist(list); + int count = fdlist_count(list); int i; syslog(LOG_INFO, "%-4s%-4s%-8s%-5s%-10s%-14s" @@ -379,7 +389,8 @@ void files_dumplist(FAR struct filelist *list) for (i = 0; i < count; i++) { - FAR struct file *filep = files_fget(list, i); + FAR struct fd *fdp; + FAR struct file *filep; #if CONFIG_FS_BACKTRACE > 0 char buf[BACKTRACE_BUFFER_SIZE(CONFIG_FS_BACKTRACE)]; @@ -387,7 +398,7 @@ void files_dumplist(FAR struct filelist *list) /* Is there an inode associated with the file descriptor? */ - if (filep == NULL || filep->f_inode == NULL) + if (fdlist_get2(list, i, &filep, &fdp) < 0) { continue; } @@ -398,7 +409,7 @@ void files_dumplist(FAR struct filelist *list) } #if CONFIG_FS_BACKTRACE > 0 - backtrace_format(buf, sizeof(buf), filep->f_backtrace, + backtrace_format(buf, sizeof(buf), fdp->f_backtrace, CONFIG_FS_BACKTRACE); #endif @@ -413,6 +424,7 @@ void files_dumplist(FAR struct filelist *list) , buf #endif ); + file_put(filep); } @@ -421,17 +433,17 @@ void files_dumplist(FAR struct filelist *list) #endif /**************************************************************************** - * Name: files_putlist + * Name: fdlist_free * * Description: - * Release the list of files. + * Release the list of file descriptors. * * Assumptions: * Called during task deletion in a safe context. * ****************************************************************************/ -void files_putlist(FAR struct filelist *list) +void fdlist_free(FAR struct fdlist *list) { int i; int j; @@ -445,90 +457,120 @@ void files_putlist(FAR struct filelist *list) { for (j = CONFIG_NFILE_DESCRIPTORS_PER_BLOCK - 1; j >= 0; j--) { - file_close(&list->fl_files[i][j]); + fdlist_close(list, i * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK + j); } if (i != 0) { - fs_heap_free(list->fl_files[i]); + fs_heap_free(list->fl_fds[i]); } } - if (list->fl_files != &list->fl_prefile) + if (list->fl_fds != &list->fl_prefd) { - fs_heap_free(list->fl_files); + fs_heap_free(list->fl_fds); } } /**************************************************************************** - * Name: files_countlist + * Name: fdlist_count * * Description: - * Get file count from file list. + * Get file descriptor count from file list. * * Input Parameters: - * list - Pointer to the file list structure. + * list - Pointer to the file descriptor list structure. * * Returned Value: * file count of file list. * ****************************************************************************/ -int files_countlist(FAR struct filelist *list) +int fdlist_count(FAR struct fdlist *list) { return list->fl_rows * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK; } /**************************************************************************** - * Name: files_fget + * Name: fdlist_get2 * * Description: - * Get the instance of struct file from file list by file descriptor. + * Given a file descriptor, return the corresponding instance of struct + * fd and filep. * * Input Parameters: - * list - The list of files for a task. - * fd - A valid descriptor between 0 and files_countlist(list). + * list - Pointer to the file descriptor list structure. + * fd - The file descriptor + * filep - The location to return the struct file instance + * fdp - The location to return the struct fd instance * * Returned Value: - * Pointer to file structure of list[fd]. + * Return the pointer to file structure of list[fd] when list[fd].f_file + * is valid, otherwise, a null pointer is returned. * ****************************************************************************/ -FAR struct file *files_fget(FAR struct filelist *list, int fd) +int fdlist_get2(FAR struct fdlist *list, int fd, + FAR struct file **filep, FAR struct fd **fdp) { - return files_fget_by_index(list, fd / CONFIG_NFILE_DESCRIPTORS_PER_BLOCK, - fd % CONFIG_NFILE_DESCRIPTORS_PER_BLOCK, NULL); + if (list == NULL) + { + return -EINVAL; + } + +#ifdef CONFIG_FDCHECK + fd = fdcheck_restore(fd); +#endif + + if (fd < 0 || fd >= fdlist_count(list)) + { + return -EBADF; + } + + fdlist_get_by_index(list, + fd / CONFIG_NFILE_DESCRIPTORS_PER_BLOCK, + fd % CONFIG_NFILE_DESCRIPTORS_PER_BLOCK, + filep, fdp); + if (*filep == NULL) + { + return -EBADF; + } + + return 0; } /**************************************************************************** - * Name: file_allocate_from_tcb + * Name: fdlist_dupfile * * Description: - * Allocate a struct files instance and associate it with an inode - * instance. + * Allocate a struct fd instance and bind it to the corresponding file + * handle. * * Returned Value: - * Returns the file descriptor == index into the files array on success; - * a negated errno value is returned on any failure. + * Returns the file descriptor == index into the files array on success; + * a negated errno value is returned on any failure. * ****************************************************************************/ -int file_allocate_from_tcb(FAR struct tcb_s *tcb, FAR struct inode *inode, - int oflags, off_t pos, FAR void *priv, int minfd, - bool addref) +int fdlist_dupfile(FAR struct fdlist *list, int oflags, int minfd, + FAR struct file *filep) { - int i = minfd / CONFIG_NFILE_DESCRIPTORS_PER_BLOCK; - int j = minfd % CONFIG_NFILE_DESCRIPTORS_PER_BLOCK; - FAR struct filelist *list; - FAR struct file *filep; + FAR struct fd *fdp; irqstate_t flags; int ret; + int i; + int j; - /* Get the file descriptor list. It should not be NULL in this context. */ + DEBUGASSERT(filep); - list = nxsched_get_files_from_tcb(tcb); +#ifdef CONFIG_FDCHECK + minfd = fdcheck_restore(minfd); +#endif - /* Find free file */ + i = minfd / CONFIG_NFILE_DESCRIPTORS_PER_BLOCK; + j = minfd % CONFIG_NFILE_DESCRIPTORS_PER_BLOCK; + + /* Find free file descriptor */ flags = spin_lock_irqsave_notrace(&list->fl_lock); @@ -538,7 +580,7 @@ int file_allocate_from_tcb(FAR struct tcb_s *tcb, FAR struct inode *inode, { spin_unlock_irqrestore_notrace(&list->fl_lock, flags); - ret = files_extend(list, i + 1); + ret = fdlist_extend(list, i + 1); if (ret < 0) { return ret; @@ -549,21 +591,18 @@ int file_allocate_from_tcb(FAR struct tcb_s *tcb, FAR struct inode *inode, do { - filep = &list->fl_files[i][j]; - if (filep->f_inode == NULL) + fdp = &list->fl_fds[i][j]; + if (fdp->f_file == NULL) { - filep->f_oflags = oflags; - filep->f_pos = pos; - filep->f_inode = inode; - filep->f_priv = priv; - atomic_set(&filep->f_refs, 1); -#ifdef CONFIG_FDSAN - filep->f_tag_fdsan = 0; -#endif -#ifdef CONFIG_FDCHECK - filep->f_tag_fdcheck = 0; -#endif - + atomic_fetch_add(&filep->f_refs, 1); + fdp->f_file = filep; + fdp->f_cloexec = !!(oflags & O_CLOEXEC); + #ifdef CONFIG_FDSAN + fdp->f_tag_fdsan = 0; + #endif + #ifdef CONFIG_FDCHECK + fdp->f_tag_fdcheck = 0; + #endif goto found; } } @@ -573,12 +612,7 @@ int file_allocate_from_tcb(FAR struct tcb_s *tcb, FAR struct inode *inode, found: spin_unlock_irqrestore_notrace(&list->fl_lock, flags); - if (addref) - { - inode_addref(inode); - } - - FS_ADD_BACKTRACE(filep); + FS_ADD_BACKTRACE(fdp); #ifdef CONFIG_FDCHECK return fdcheck_protect(i * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK + j); @@ -587,37 +621,135 @@ found: #endif } +/**************************************************************************** + * Name: fdlist_allocate + * + * Description: + * Allocate a struct fd instance and associate it with an empty file + * instance. The difference between this function and + * file_allocate_from_inode is that this function is only used for + * placeholder purposes. Later, the caller will initialize the file entity + * through the returned filep. + * + * The fd allocated by this function can be released using fdlist_close. + * + * After the function call is completed, it will hold a reference count + * for the filep. Therefore, when the filep is no longer in use, it is + * necessary to call file_put to release the reference count, in order + * to avoid a race condition where the file might be closed during + * this process. + * + * Returned Value: + * Returns the file descriptor == index into the files array on success; + * a negated errno value is returned on any failure. + * + ****************************************************************************/ + +int fdlist_allocate(FAR struct fdlist *list, int oflags, + int minfd, FAR struct file **filep) +{ + int fd; + + *filep = fs_heap_zalloc(sizeof(struct file)); + if (*filep == NULL) + { + return -ENOMEM; + } + + file_ref(*filep); + fd = fdlist_dupfile(list, oflags, minfd, *filep); + if (fd < 0) + { + file_put(*filep); + } + + return fd; +} + /**************************************************************************** * Name: file_allocate * * Description: - * Allocate a struct files instance and associate it with an inode - * instance. + * Allocate a struct fd instance and associate it with an empty file + * instance. The difference between this function and + * file_allocate_from_inode is that this function is only used for + * placeholder purposes. Later, the caller will initialize the file entity + * through the returned filep. + * + * The fd allocated by this function can be released using nx_close. + * + * After the function call is completed, it will hold a reference count + * for the filep. Therefore, when the filep is no longer in use, it is + * necessary to call file_put to release the reference count, in order + * to avoid a race condition where the file might be closed during + * this process. * * Returned Value: - * Returns the file descriptor == index into the files array on success; - * a negated errno value is returned on any failure. + * Returns the file descriptor == index into the files array on success; + * a negated errno value is returned on any failure. * ****************************************************************************/ -int file_allocate(FAR struct inode *inode, int oflags, off_t pos, - FAR void *priv, int minfd, bool addref) +int file_allocate(int oflags, int minfd, FAR struct file **filep) { - return file_allocate_from_tcb(this_task(), inode, oflags, - pos, priv, minfd, addref); + return fdlist_allocate(nxsched_get_fdlist_from_tcb(this_task()), + oflags, minfd, filep); +} + +/**************************************************************************** + * Name: file_allocate_from_inode + * + * Description: + * Allocate a struct fd instance and associate it with an file instance. + * And initialize them with inode, oflags, pos and priv. + * + * Returned Value: + * Returns the file descriptor == index into the files array on success; + * a negated errno value is returned on any failure. + * + ****************************************************************************/ + +int file_allocate_from_inode(FAR struct inode *inode, int oflags, off_t pos, + FAR void *priv, int minfd) +{ + FAR struct file *filep; + int fd; + + fd = file_allocate(oflags, minfd, &filep); + if (fd < 0) + { + return fd; + } + + inode_addref(inode); + filep->f_inode = inode; + filep->f_pos = pos; + filep->f_oflags = oflags & ~O_CLOEXEC; + filep->f_priv = priv; +#if CONFIG_FS_LOCK_BUCKET_SIZE > 0 + filep->f_locked = false; +#endif + + file_put(filep); + + return fd; } /**************************************************************************** - * Name: files_duplist + * Name: fdlist_copy * * Description: - * Duplicate parent task's file descriptors. + * Copy parent task's file descriptors to child task. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. * ****************************************************************************/ -int files_duplist(FAR struct filelist *plist, FAR struct filelist *clist, - FAR const posix_spawn_file_actions_t *actions, - bool cloexec) +int fdlist_copy(FAR struct fdlist *plist, FAR struct fdlist *clist, + FAR const posix_spawn_file_actions_t *actions, + bool cloexec) { bool fcloexec; int ret; @@ -629,9 +761,8 @@ int files_duplist(FAR struct filelist *plist, FAR struct filelist *clist, { for (j = 0; j < CONFIG_NFILE_DESCRIPTORS_PER_BLOCK; j++) { - FAR struct file *filep2; FAR struct file *filep; - bool new = false; + FAR struct fd *fdp; fd = i * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK + j; #ifdef CONFIG_FDCLONE_STDIO @@ -649,13 +780,13 @@ int files_duplist(FAR struct filelist *plist, FAR struct filelist *clist, } #endif - filep = files_fget_by_index(plist, i, j, NULL); + fdlist_get_by_index(plist, i, j, &filep, &fdp); if (filep == NULL) { continue; } - fcloexec = (cloexec && (filep->f_oflags & O_CLOEXEC)); + fcloexec = cloexec && fdp->f_cloexec; /* Skip file dup if file action is unnecessary to duplicate */ @@ -676,28 +807,17 @@ int files_duplist(FAR struct filelist *plist, FAR struct filelist *clist, continue; } - ret = files_extend(clist, i + 1); + ret = fdlist_extend(clist, i + 1); if (ret < 0) { file_put(filep); return ret; } - /* Yes... duplicate it for the child, include O_CLOEXEC flag. */ + /* Assign filep to the child's descriptor list. Omit the flags */ - filep2 = files_fget_by_index(clist, i, j, &new); - ret = file_dup2(filep, filep2); - file_put(filep2); + fdlist_install(clist, fd, filep, 0); file_put(filep); - if (ret < 0) - { - if (new) - { - file_put(filep2); - } - - return ret; - } } } @@ -705,15 +825,16 @@ int files_duplist(FAR struct filelist *plist, FAR struct filelist *clist, } /**************************************************************************** - * Name: file_get + * Name: file_get2 * * Description: * Given a file descriptor, return the corresponding instance of struct - * file. + * fd and filep * * Input Parameters: * fd - The file descriptor * filep - The location to return the struct file instance + * fdp - The location to return the struct fd instance * * Returned Value: * Zero (OK) is returned on success; a negated errno value is returned on @@ -721,49 +842,9 @@ int files_duplist(FAR struct filelist *plist, FAR struct filelist *clist, * ****************************************************************************/ -int file_get(int fd, FAR struct file **filep) +int file_get2(int fd, FAR struct file **filep, FAR struct fd **fdp) { - FAR struct filelist *list; - -#ifdef CONFIG_FDCHECK - fd = fdcheck_restore(fd); -#endif - - *filep = NULL; - - list = nxsched_get_files(); - - /* The file list can be NULL under two cases: (1) One is an obscure - * cornercase: When memory management debug output is enabled. Then - * there may be attempts to write to stdout from malloc before the group - * data has been allocated. The other other is (2) if this is a kernel - * thread. Kernel threads have no allocated file descriptors. - */ - - if (list == NULL) - { - return -EAGAIN; - } - - if (fd < 0 || fd >= files_countlist(list)) - { - return -EBADF; - } - - /* The descriptor is in a valid range to file descriptor... Get the - * thread-specific file list. - */ - - *filep = files_fget(list, fd); - - /* if *filep is NULL, fd was closed */ - - if (*filep == NULL) - { - return -EBADF; - } - - return OK; + return fdlist_get2(nxsched_get_fdlist(), fd, filep, fdp); } /**************************************************************************** @@ -804,7 +885,10 @@ int file_put(FAR struct file *filep) { int ret = 0; - DEBUGASSERT(filep); + if (filep == NULL) + { + return ret; + } /* If refs is zero, the close() had called, closing it now. */ @@ -815,20 +899,22 @@ int file_put(FAR struct file *filep) { ferr("ERROR: fs putfilep file_close() failed: %d\n", ret); } + + fs_heap_free(filep); } return ret; } /**************************************************************************** - * Name: nx_dup2_from_tcb + * Name: fdlist_dup2 * * Description: - * nx_dup2_from_tcb() is similar to the standard 'dup2' interface + * fdlist_dup2() is similar to the standard 'dup2' interface * except that is not a cancellation point and it does not modify the * errno variable. * - * nx_dup2_from_tcb() is an internal NuttX interface and should not be + * fdlist_dup2() is an internal NuttX interface and should not be * called from applications. * * Clone a file descriptor to a specific descriptor number. @@ -839,20 +925,41 @@ int file_put(FAR struct file *filep) * ****************************************************************************/ -int nx_dup2_from_tcb(FAR struct tcb_s *tcb, int fd1, int fd2) +int fdlist_dup2(FAR struct fdlist *list, int fd1, int fd2) { - return nx_dup3_from_tcb(tcb, fd1, fd2, 0); + /* If fd1 is a valid file descriptor, and fd1 == fd2, then dup2() does + * nothing, and returns fd2. + */ + + if (fd1 == fd2) + { + FAR struct file *filep; + int ret; + + ret = file_get(fd1, &filep); + if (ret < 0) + { + return ret; + } + + /* Release the reference */ + + file_put(filep); + return fd2; + } + + return fdlist_dup3(list, fd1, fd2, 0); } /**************************************************************************** - * Name: nx_close_from_tcb + * Name: fdlist_close * * Description: - * nx_close_from_tcb() is similar to the standard 'close' interface + * fdlist_close() is similar to the standard 'close' interface * except that is not a cancellation point and it does not modify the * errno variable. * - * nx_close_from_tcb() is an internal NuttX interface and should not + * fdlist_close() is an internal NuttX interface and should not * be called from applications. * * Close an inode (if open) @@ -867,42 +974,26 @@ int nx_dup2_from_tcb(FAR struct tcb_s *tcb, int fd1, int fd2) * ****************************************************************************/ -int nx_close_from_tcb(FAR struct tcb_s *tcb, int fd) +int fdlist_close(FAR struct fdlist *list, int fd) { - FAR struct file *filep; - FAR struct filelist *list; - -#ifdef CONFIG_FDCHECK - fd = fdcheck_restore(fd); -#endif - - list = nxsched_get_files_from_tcb(tcb); - - /* Perform the protected close operation */ + FAR struct file *filep; + FAR struct fd *fdp; + int ret; - if (fd < 0 || fd >= files_countlist(list)) + ret = fdlist_get2(list, fd, &filep, &fdp); + if (ret < 0) { - return -EBADF; + return ret; } - filep = files_fget(list, fd); - - /* If the file was properly opened, there should be an inode assigned */ - - if (filep == NULL) - { - return -EBADF; - } + /* Perform the protected close operation */ + fdlist_uninstall(list, fdp); - /* files_fget will increase the reference count, there call file_put - * reduce reference count. + /* fdlist_get2 will increase the reference count, there call + * file_put reduce reference count. */ - file_put(filep); - - /* Undo the last reference count from file_allocate_from_tcb */ - return file_put(filep); } diff --git a/fs/inode/inode.h b/fs/inode/inode.h index 59dfc1d2d0..178368b730 100644 --- a/fs/inode/inode.h +++ b/fs/inode/inode.h @@ -72,21 +72,21 @@ while (0) #if CONFIG_FS_BACKTRACE > 0 -# define FS_ADD_BACKTRACE(filep) \ +# define FS_ADD_BACKTRACE(fd) \ do \ { \ int n = sched_backtrace(_SCHED_GETTID(), \ - (filep)->f_backtrace, \ + (fd)->f_backtrace, \ CONFIG_FS_BACKTRACE, \ CONFIG_FS_BACKTRACE_SKIP); \ if (n < CONFIG_FS_BACKTRACE) \ { \ - (filep)->f_backtrace[n] = NULL; \ + (fd)->f_backtrace[n] = NULL; \ } \ } \ while (0) #else -# define FS_ADD_BACKTRACE(filep) +# define FS_ADD_BACKTRACE(fd) #endif /**************************************************************************** diff --git a/fs/mqueue/mq_open.c b/fs/mqueue/mq_open.c index 402ed9a5d1..7b270bba1d 100644 --- a/fs/mqueue/mq_open.c +++ b/fs/mqueue/mq_open.c @@ -264,7 +264,6 @@ static int file_mq_vopen(FAR struct file *mq, FAR const char *mq_name, /* Associate the inode with a file structure */ - memset(mq, 0, sizeof(*mq)); mq->f_oflags = oflags; mq->f_inode = inode; @@ -308,7 +307,6 @@ static int file_mq_vopen(FAR struct file *mq, FAR const char *mq_name, /* Associate the inode with a file structure */ - memset(mq, 0, sizeof(*mq)); mq->f_oflags = oflags; mq->f_inode = inode; @@ -347,28 +345,26 @@ errout: static mqd_t nxmq_vopen(FAR const char *mq_name, int oflags, va_list ap) { - struct file mq; + FAR struct file *mq; int created; int ret; + int fd; - ret = file_mq_vopen(&mq, mq_name, oflags, getumask(), ap, &created); - if (ret < 0) + fd = file_allocate(oflags, 0, &mq); + if (fd < 0) { - return ret; + return fd; } - ret = file_allocate(mq.f_inode, mq.f_oflags, - mq.f_pos, mq.f_priv, 0, false); + ret = file_mq_vopen(mq, mq_name, oflags, getumask(), ap, &created); + file_put(mq); if (ret < 0) { - file_mq_close(&mq); - if (created) - { - file_mq_unlink(mq_name); - } + nx_close(fd); + return ret; } - return ret; + return fd; } /**************************************************************************** diff --git a/fs/notify/inotify.c b/fs/notify/inotify.c index ced0d5467e..92d0cdd21f 100644 --- a/fs/notify/inotify.c +++ b/fs/notify/inotify.c @@ -1025,7 +1025,7 @@ static inline void notify_queue_filep_event(FAR struct file *filep, static void notify_free_entry(FAR ENTRY *entry) { - /* Key is alloced by lib_malloc, value is alloced by fs_heap_malloc */ + /* Key is allocated by lib_malloc, value is allocated by fs_heap_malloc */ fs_heap_free(entry->key); fs_heap_free(entry->data); @@ -1255,8 +1255,8 @@ int inotify_init1(int flags) goto exit_set_errno; } - ret = file_allocate(&g_inotify_inode, O_RDOK | flags, - 0, dev, 0, true); + ret = file_allocate_from_inode(&g_inotify_inode, O_RDOK | flags, + 0, dev, 0); if (ret < 0) { ferr("Failed to allocate inotify fd\n"); diff --git a/fs/procfs/fs_procfsproc.c b/fs/procfs/fs_procfsproc.c index db29825c9c..94f3035770 100644 --- a/fs/procfs/fs_procfsproc.c +++ b/fs/procfs/fs_procfsproc.c @@ -1252,7 +1252,6 @@ static ssize_t proc_groupfd(FAR struct proc_file_s *procfile, size_t buflen, off_t offset) { FAR struct task_group_s *group = tcb->group; - FAR struct file *filep; FAR char *path; size_t remaining; size_t linesize; @@ -1263,7 +1262,7 @@ static ssize_t proc_groupfd(FAR struct proc_file_s *procfile, DEBUGASSERT(group != NULL); - count = files_countlist(&group->tg_filelist); + count = fdlist_count(&group->tg_fdlist); if (count == 0) { return 0; @@ -1303,11 +1302,12 @@ static ssize_t proc_groupfd(FAR struct proc_file_s *procfile, for (i = 0; i < count; i++) { - filep = files_fget(&group->tg_filelist, i); + FAR struct file *filep; + FAR struct fd *fdp; /* Is there an inode associated with the file descriptor? */ - if (filep == NULL) + if (fdlist_get2(&group->tg_fdlist, i, &filep, &fdp) < 0) { continue; } @@ -1327,7 +1327,7 @@ static ssize_t proc_groupfd(FAR struct proc_file_s *procfile, #if CONFIG_FS_BACKTRACE > 0 linesize += backtrace_format(procfile->line + linesize, STATUS_LINELEN - linesize, - filep->f_backtrace, + fdp->f_backtrace, CONFIG_FS_BACKTRACE); #endif procfile->line[linesize - 2] = '\n'; diff --git a/fs/shm/shm_open.c b/fs/shm/shm_open.c index 1230585ee6..cad2b97683 100644 --- a/fs/shm/shm_open.c +++ b/fs/shm/shm_open.c @@ -150,7 +150,6 @@ static int file_shm_open(FAR struct file *shm, FAR const char *name, /* Associate the inode with a file structure */ - memset(shm, 0, sizeof(*shm)); shm->f_oflags = oflags | O_CLOEXEC | O_NOFOLLOW; shm->f_inode = inode; @@ -173,24 +172,25 @@ errout_with_sem: int shm_open(FAR const char *name, int oflag, mode_t mode) { - struct file shm; + FAR struct file *shm; int ret; + int fd; - ret = file_shm_open(&shm, name, oflag, mode); - if (ret < 0) + fd = file_allocate(oflag, 0, &shm); + if (fd < 0) { - set_errno(-ret); + set_errno(-fd); return ERROR; } - ret = file_allocate(shm.f_inode, shm.f_oflags, shm.f_pos, shm.f_priv, 0, - false); + ret = file_shm_open(shm, name, oflag, mode); + file_put(shm); if (ret < 0) { + nx_close(fd); set_errno(-ret); - file_close(&shm); return ERROR; } - return ret; + return fd; } diff --git a/fs/socket/socket.c b/fs/socket/socket.c index 125bed1109..95252b3ddc 100644 --- a/fs/socket/socket.c +++ b/fs/socket/socket.c @@ -171,7 +171,7 @@ static int sock_file_truncate(FAR struct file *filep, off_t length) int sockfd_allocate(FAR struct socket *psock, int oflags) { - return file_allocate(&g_sock_inode, oflags, 0, psock, 0, true); + return file_allocate_from_inode(&g_sock_inode, oflags, 0, psock, 0); } /**************************************************************************** diff --git a/fs/vfs/fs_close.c b/fs/vfs/fs_close.c index c65c92b00c..980df65585 100644 --- a/fs/vfs/fs_close.c +++ b/fs/vfs/fs_close.c @@ -76,11 +76,10 @@ static FAR char *file_get_path(FAR struct file *filep) ****************************************************************************/ /**************************************************************************** - * Name: file_close_without_clear + * Name: file_close * * Description: - * Close a file that was previously opened with file_open(), but without - * clear filep. + * Close a file that was previously opened with file_open(). * * Input Parameters: * filep - A pointer to a user provided memory location containing the @@ -92,7 +91,7 @@ static FAR char *file_get_path(FAR struct file *filep) * ****************************************************************************/ -int file_close_without_clear(FAR struct file *filep) +int file_close(FAR struct file *filep) { struct inode *inode; #ifdef CONFIG_FS_NOTIFY @@ -140,44 +139,14 @@ int file_close_without_clear(FAR struct file *filep) inode_release(inode); } - } - return ret; -} - -/**************************************************************************** - * Name: file_close - * - * Description: - * Close a file that was previously opened with file_open(). - * - * Input Parameters: - * filep - A pointer to a user provided memory location containing the - * open file data returned by file_open(). - * - * Returned Value: - * Zero (OK) is returned on success; A negated errno value is returned on - * any failure to indicate the nature of the failure. - * - ****************************************************************************/ - -int file_close(FAR struct file *filep) -{ - int ret; - - ret = file_close_without_clear(filep); - if (ret >= 0 && filep->f_inode) - { -#ifdef CONFIG_FDCHECK - filep->f_tag_fdcheck = 0; -#endif - -#ifdef CONFIG_FDSAN - filep->f_tag_fdsan = 0; +#ifdef CONFIG_FS_NOTIFY + if (path != NULL) + { + lib_put_pathbuffer(path); + } #endif - /* Reset the user file struct instance so that it cannot be reused. */ - filep->f_inode = NULL; } @@ -208,7 +177,7 @@ int file_close(FAR struct file *filep) int nx_close(int fd) { - return nx_close_from_tcb(this_task(), fd); + return fdlist_close(nxsched_get_fdlist_from_tcb(this_task()), fd); } /**************************************************************************** diff --git a/fs/vfs/fs_dup.c b/fs/vfs/fs_dup.c index f00abd412c..092055ec05 100644 --- a/fs/vfs/fs_dup.c +++ b/fs/vfs/fs_dup.c @@ -33,7 +33,9 @@ #include <fcntl.h> #include <nuttx/fs/fs.h> + #include "inode/inode.h" +#include "sched/sched.h" /**************************************************************************** * Public Functions @@ -54,32 +56,8 @@ int file_dup(FAR struct file *filep, int minfd, int flags) { - FAR struct file *filep2; - int fd2; - int ret; -#ifdef CONFIG_FDCHECK - minfd = fdcheck_restore(minfd); -#endif - - fd2 = file_allocate(g_root_inode, 0, 0, NULL, minfd, true); - if (fd2 < 0) - { - return fd2; - } - - ret = file_get(fd2, &filep2); - DEBUGASSERT(ret >= 0); - - ret = file_dup3(filep, filep2, flags); - - file_put(filep2); - if (ret >= 0) - { - return fd2; - } - - file_put(filep2); - return ret; + return fdlist_dupfile(nxsched_get_fdlist_from_tcb(this_task()), + flags, minfd, filep); } /**************************************************************************** diff --git a/fs/vfs/fs_dup2.c b/fs/vfs/fs_dup2.c index d9e1d9e13a..62d4e267d6 100644 --- a/fs/vfs/fs_dup2.c +++ b/fs/vfs/fs_dup2.c @@ -42,13 +42,13 @@ ****************************************************************************/ /**************************************************************************** - * Name: file_dup3 + * Name: file_dup2 * * Description: * Assign an inode to a specific files structure. This is the heart of - * dup3. + * dup2. * - * Equivalent to the non-standard dup3() function except that it + * Equivalent to the non-standard dup2() function except that it * accepts struct file instances instead of file descriptors and it does * not set the errno variable. * @@ -58,7 +58,7 @@ * ****************************************************************************/ -int file_dup3(FAR struct file *filep1, FAR struct file *filep2, int flags) +int file_dup2(FAR struct file *filep1, FAR struct file *filep2) { FAR struct inode *inode; int ret; @@ -68,11 +68,6 @@ int file_dup3(FAR struct file *filep1, FAR struct file *filep2, int flags) return -EBADF; } - if (flags != 0 && flags != O_CLOEXEC) - { - return -EINVAL; - } - if (filep1 == filep2) { return OK; @@ -83,29 +78,15 @@ int file_dup3(FAR struct file *filep1, FAR struct file *filep2, int flags) inode = filep1->f_inode; inode_addref(inode); - /* If there is already an inode contained in the new file structure, - * close the file and release the inode. - * But we need keep the filep2->f_inode, in case of realloced by others. - */ + /* Close the second file */ - ret = file_close_without_clear(filep2); + ret = file_close(filep2); if (ret < 0) { inode_release(inode); return ret; } - /* The two filep don't share flags (the close-on-exec flag). */ - - if (flags == O_CLOEXEC) - { - filep2->f_oflags = filep1->f_oflags | O_CLOEXEC; - } - else - { - filep2->f_oflags = filep1->f_oflags & ~O_CLOEXEC; - } - filep2->f_priv = NULL; filep2->f_pos = filep1->f_pos; filep2->f_inode = inode; @@ -159,34 +140,10 @@ int file_dup3(FAR struct file *filep1, FAR struct file *filep2, int flags) if (ret < 0) { inode_release(inode); - return ret; } } - FS_ADD_BACKTRACE(filep2); - return OK; -} - -/**************************************************************************** - * Name: file_dup2 - * - * Description: - * Assign an inode to a specific files structure. This is the heart of - * dup2. - * - * Equivalent to the non-standard dup2() function except that it - * accepts struct file instances instead of file descriptors and it does - * not set the errno variable. - * - * Returned Value: - * Zero (OK) is returned on success; a negated errno value is return on - * any failure. - * - ****************************************************************************/ - -int file_dup2(FAR struct file *filep1, FAR struct file *filep2) -{ - return file_dup3(filep1, filep2, 0); + return ret; } /**************************************************************************** @@ -209,7 +166,7 @@ int file_dup2(FAR struct file *filep1, FAR struct file *filep2) int nx_dup2(int fd1, int fd2) { - return nx_dup2_from_tcb(this_task(), fd1, fd2); + return fdlist_dup2(nxsched_get_fdlist_from_tcb(this_task()), fd1, fd2); } /**************************************************************************** diff --git a/fs/vfs/fs_dup3.c b/fs/vfs/fs_dup3.c index 947b154212..ec44b0ab55 100644 --- a/fs/vfs/fs_dup3.c +++ b/fs/vfs/fs_dup3.c @@ -49,7 +49,8 @@ int dup3(int fd1, int fd2, int flags) { int ret; - ret = nx_dup3_from_tcb(this_task(), fd1, fd2, flags); + ret = fdlist_dup3(nxsched_get_fdlist_from_tcb(this_task()), + fd1, fd2, flags); if (ret < 0) { set_errno(-ret); diff --git a/fs/vfs/fs_epoll.c b/fs/vfs/fs_epoll.c index 5efbece61c..91181ea17c 100644 --- a/fs/vfs/fs_epoll.c +++ b/fs/vfs/fs_epoll.c @@ -258,7 +258,7 @@ static int epoll_do_create(int size, int flags) /* Alloc the file descriptor */ - fd = file_allocate(&g_epoll_inode, flags, 0, eph, 0, true); + fd = file_allocate_from_inode(&g_epoll_inode, flags, 0, eph, 0); if (fd < 0) { nxmutex_destroy(&eph->lock); diff --git a/fs/vfs/fs_eventfd.c b/fs/vfs/fs_eventfd.c index f5f614a7e5..0f63df25dc 100644 --- a/fs/vfs/fs_eventfd.c +++ b/fs/vfs/fs_eventfd.c @@ -528,8 +528,8 @@ int eventfd(unsigned int count, int flags) } new_dev->counter = count; - new_fd = file_allocate(&g_eventfd_inode, O_RDWR | flags, - 0, new_dev, 0, true); + new_fd = file_allocate_from_inode(&g_eventfd_inode, O_RDWR | flags, + 0, new_dev, 0); if (new_fd < 0) { ret = new_fd; diff --git a/fs/vfs/fs_fcntl.c b/fs/vfs/fs_fcntl.c index b923f5fd8f..406648d2ba 100644 --- a/fs/vfs/fs_fcntl.c +++ b/fs/vfs/fs_fcntl.c @@ -59,70 +59,6 @@ static int file_vfcntl(FAR struct file *filep, int cmd, va_list ap) switch (cmd) { - case F_DUPFD: - /* Return a new file descriptor which shall be the lowest numbered - * available (that is, not already open) file descriptor greater than - * or equal to the third argument, arg, taken as an integer of type - * int. The new file descriptor shall refer to the same open file - * description as the original file descriptor, and shall share any - * locks. The FD_CLOEXEC flag associated with the new file - * descriptor shall be cleared to keep the file open across calls to - * one of the exec functions. - */ - - { - /* Does not set the errno variable in the event of a failure */ - - ret = file_dup(filep, va_arg(ap, int), 0); - } - break; - - case F_DUPFD_CLOEXEC: - { - ret = file_dup(filep, va_arg(ap, int), O_CLOEXEC); - } - break; - - case F_GETFD: - /* Get the file descriptor flags defined in <fcntl.h> that are - * associated with the file descriptor fd. File descriptor flags are - * associated with a single file descriptor and do not affect other - * file descriptors that refer to the same file. - */ - - { - ret = filep->f_oflags & O_CLOEXEC ? FD_CLOEXEC : 0; - } - break; - - case F_SETFD: - /* Set the file descriptor flags defined in <fcntl.h>, that are - * associated with fd, to the third argument, arg, taken as type int. - * If the FD_CLOEXEC flag in the third argument is 0, the file shall - * remain open across the exec functions; otherwise, the file shall - * be closed upon successful execution of one of the exec functions. - */ - - { - int oflags = va_arg(ap, int); - - if (oflags & ~FD_CLOEXEC) - { - ret = -ENOSYS; - break; - } - - if (oflags & FD_CLOEXEC) - { - ret = file_ioctl(filep, FIOCLEX, NULL); - } - else - { - ret = file_ioctl(filep, FIONCLEX, NULL); - } - } - break; - case F_GETFL: /* Get the file status flags and file access modes, defined in * <fcntl.h>, for the file description associated with fd. The file @@ -347,27 +283,100 @@ int fcntl(int fd, int cmd, ...) va_start(ap, cmd); - /* Get the file structure corresponding to the file descriptor. */ - ret = file_get(fd, &filep); - if (ret >= 0) + if (ret < 0) { - /* Let file_vfcntl() do the real work. The errno is not set on - * failures. - */ - - ret = file_vfcntl(filep, cmd, ap); - file_put(filep); + goto errout; } - if (ret < 0) + switch (cmd) { - set_errno(-ret); - ret = ERROR; + case F_DUPFD: + /* Return a new file descriptor which shall be the lowest numbered + * available (that is, not already open) file descriptor greater than + * or equal to the third argument, arg, taken as an integer of type + * int. The new file descriptor shall refer to the same open file + * description as the original file descriptor, and shall share any + * locks. The FD_CLOEXEC flag associated with the new file + * descriptor shall be cleared to keep the file open across calls to + * one of the exec functions. + */ + + { + ret = file_dup(filep, va_arg(ap, int), 0); + } + break; + + case F_DUPFD_CLOEXEC: + { + ret = file_dup(filep, va_arg(ap, int), O_CLOEXEC); + } + break; + + case F_GETFD: + /* Get the file descriptor flags defined in <fcntl.h> that are + * associated with the file descriptor fd. File descriptor flags are + * associated with a single file descriptor and do not affect other + * file descriptors that refer to the same file. + */ + + { + int flags; + + ret = file_ioctl(filep, FIOGCLEX, &flags); + if (ret >= 0) + { + ret = flags; + } + } + break; + + case F_SETFD: + /* Set the file descriptor flags defined in <fcntl.h>, that are + * associated with fd, to the third argument, arg, taken as type int. + * If the FD_CLOEXEC flag in the third argument is 0, the file shall + * remain open across the exec functions; otherwise, the file shall + * be closed upon successful execution of one of the exec functions. + */ + + { + int oflags = va_arg(ap, int); + + if (oflags & ~FD_CLOEXEC) + { + ret = -ENOSYS; + break; + } + + if (oflags & FD_CLOEXEC) + { + ret = file_ioctl(filep, FIOCLEX, NULL); + } + else + { + ret = file_ioctl(filep, FIONCLEX, NULL); + } + } + break; + + default: + { + ret = file_vfcntl(filep, cmd, ap); + } + break; } + file_put(filep); + +errout: va_end(ap); leave_cancellation_point(); + if (ret < 0) + { + set_errno(-ret); + return ERROR; + } + return ret; } diff --git a/fs/vfs/fs_ioctl.c b/fs/vfs/fs_ioctl.c index 7df9733799..2b199609d8 100644 --- a/fs/vfs/fs_ioctl.c +++ b/fs/vfs/fs_ioctl.c @@ -89,22 +89,6 @@ static int file_vioctl(FAR struct file *filep, int req, va_list ap) } break; - case FIOCLEX: - if (ret == OK || ret == -ENOTTY) - { - filep->f_oflags |= O_CLOEXEC; - ret = OK; - } - break; - - case FIONCLEX: - if (ret == OK || ret == -ENOTTY) - { - filep->f_oflags &= ~O_CLOEXEC; - ret = OK; - } - break; - case FIOC_FILEPATH: if (ret == -ENOTTY && !INODE_IS_MOUNTPT(inode)) { @@ -135,30 +119,6 @@ static int file_vioctl(FAR struct file *filep, int req, va_list ap) } break; -#ifdef CONFIG_FDSAN - case FIOC_SETTAG_FDSAN: - filep->f_tag_fdsan = *(FAR uint64_t *)arg; - ret = OK; - break; - - case FIOC_GETTAG_FDSAN: - *(FAR uint64_t *)arg = filep->f_tag_fdsan; - ret = OK; - break; -#endif - -#ifdef CONFIG_FDCHECK - case FIOC_SETTAG_FDCHECK: - filep->f_tag_fdcheck = *(FAR uint8_t *)arg; - ret = OK; - break; - - case FIOC_GETTAG_FDCHECK: - *(FAR uint8_t *)arg = filep->f_tag_fdcheck; - ret = OK; - break; -#endif - #ifndef CONFIG_DISABLE_MOUNTPOINT case BIOC_BLKSSZGET: if (ret == -ENOTTY && inode->u.i_ops != NULL && @@ -194,6 +154,65 @@ static int file_vioctl(FAR struct file *filep, int req, va_list ap) return ret; } +/**************************************************************************** + * Name: nx_vioctl + ****************************************************************************/ + +static int nx_vioctl(int fd, int req, va_list ap) +{ + FAR struct file *filep; + FAR struct fd *fdp; + int ret; + + ret = file_get2(fd, &filep, &fdp); + if (ret < 0) + { + return ret; + } + + switch (req) + { + case FIOCLEX: + fdp->f_cloexec = true; + break; + + case FIONCLEX: + fdp->f_cloexec = false; + break; + + case FIOGCLEX: + *va_arg(ap, FAR int *) = fdp->f_cloexec ? O_CLOEXEC : 0; + break; + +#ifdef CONFIG_FDSAN + case FIOC_SETTAG_FDSAN: + fdp->f_tag_fdsan = *va_arg(ap, FAR uint64_t *); + break; + + case FIOC_GETTAG_FDSAN: + *va_arg(ap, FAR uint64_t *) = fdp->f_tag_fdsan; + break; +#endif + +#ifdef CONFIG_FDCHECK + case FIOC_SETTAG_FDCHECK: + fdp->f_tag_fdcheck = *va_arg(ap, FAR uint8_t *); + break; + + case FIOC_GETTAG_FDCHECK: + *va_arg(ap, FAR uint8_t *) = fdp->f_tag_fdcheck; + break; +#endif + + default: + ret = file_vioctl(filep, req, ap); + break; + } + + file_put(filep); + return ret; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -260,33 +279,21 @@ int file_ioctl(FAR struct file *filep, int req, ...) int ioctl(int fd, int req, ...) { - FAR struct file *filep; va_list ap; int ret; - /* Get the file structure corresponding to the file descriptor. */ + va_start(ap, req); + + /* Let nx_vioctl() do the real work. */ - ret = file_get(fd, &filep); + ret = nx_vioctl(fd, req, ap); if (ret < 0) { - goto err; + set_errno(-ret); + ret = ERROR; } - /* Let file_vioctl() do the real work. */ - - va_start(ap, req); - ret = file_vioctl(filep, req, ap); va_end(ap); - file_put(filep); - if (ret < 0) - { - goto err; - } - return ret; - -err: - set_errno(-ret); - return ERROR; } diff --git a/fs/vfs/fs_open.c b/fs/vfs/fs_open.c index 83f1eb279b..1d52889999 100644 --- a/fs/vfs/fs_open.c +++ b/fs/vfs/fs_open.c @@ -227,7 +227,6 @@ static int file_vopen(FAR struct file *filep, FAR const char *path, /* Associate the inode with a file structure */ - memset(filep, 0, sizeof(*filep)); filep->f_oflags = oflags; filep->f_inode = inode; @@ -308,28 +307,29 @@ errout_with_search: * ****************************************************************************/ -static int nx_vopen(FAR struct tcb_s *tcb, +static int nx_vopen(FAR struct fdlist *list, FAR const char *path, int oflags, va_list ap) { - struct file filep; + FAR struct file *filep; int ret; int fd; - /* Let file_vopen() do all of the work */ + /* Allocate a new file descriptor for the inode */ - ret = file_vopen(&filep, path, oflags, getumask(), ap); - if (ret < 0) + fd = fdlist_allocate(list, oflags, 0, &filep); + if (fd < 0) { - return ret; + return fd; } - /* Allocate a new file descriptor for the inode */ + /* Let file_vopen() do all of the work */ - fd = file_allocate_from_tcb(tcb, filep.f_inode, filep.f_oflags, - filep.f_pos, filep.f_priv, 0, false); - if (fd < 0) + ret = file_vopen(filep, path, oflags, getumask(), ap); + file_put(filep); + if (ret < 0) { - file_close(&filep); + fdlist_close(list, fd); + return ret; } return fd; @@ -370,23 +370,18 @@ int file_open(FAR struct file *filep, FAR const char *path, int oflags, ...) ret = file_vopen(filep, path, oflags, 0, ap); va_end(ap); - if (ret >= OK) - { - FS_ADD_BACKTRACE(filep); - } - return ret; } /**************************************************************************** - * Name: nx_open_from_tcb + * Name: fdlist_open * * Description: - * nx_open_from_tcb() is similar to the standard 'open' interface except + * fdlist_open() is similar to the standard 'open' interface except * that it is not a cancellation point and it does not modify the errno * variable. * - * nx_open_from_tcb() is an internal NuttX interface and should not be + * fdlist_open() is an internal NuttX interface and should not be * called from applications. * * Input Parameters: @@ -401,8 +396,8 @@ int file_open(FAR struct file *filep, FAR const char *path, int oflags, ...) * ****************************************************************************/ -int nx_open_from_tcb(FAR struct tcb_s *tcb, - FAR const char *path, int oflags, ...) +int fdlist_open(FAR struct fdlist *list, + FAR const char *path, int oflags, ...) { va_list ap; int fd; @@ -410,7 +405,7 @@ int nx_open_from_tcb(FAR struct tcb_s *tcb, /* Let nx_vopen() do all of the work */ va_start(ap, oflags); - fd = nx_vopen(tcb, path, oflags, ap); + fd = nx_vopen(list, path, oflags, ap); va_end(ap); return fd; @@ -445,7 +440,7 @@ int nx_open(FAR const char *path, int oflags, ...) /* Let nx_vopen() do all of the work */ va_start(ap, oflags); - fd = nx_vopen(this_task(), path, oflags, ap); + fd = nx_vopen(nxsched_get_fdlist_from_tcb(this_task()), path, oflags, ap); va_end(ap); return fd; @@ -475,7 +470,7 @@ int open(FAR const char *path, int oflags, ...) /* Let nx_vopen() do most of the work */ va_start(ap, oflags); - fd = nx_vopen(this_task(), path, oflags, ap); + fd = nx_vopen(nxsched_get_fdlist_from_tcb(this_task()), path, oflags, ap); va_end(ap); /* Set the errno value if any errors were reported by nx_open() */ diff --git a/fs/vfs/fs_signalfd.c b/fs/vfs/fs_signalfd.c index dedc3c3cc0..116c653e8a 100644 --- a/fs/vfs/fs_signalfd.c +++ b/fs/vfs/fs_signalfd.c @@ -352,8 +352,8 @@ int signalfd(int fd, FAR const sigset_t *mask, int flags) nxmutex_init(&dev->mutex); - fd = file_allocate(&g_signalfd_inode, O_RDOK | flags, - 0, dev, 0, true); + fd = file_allocate_from_inode(&g_signalfd_inode, O_RDOK | flags, + 0, dev, 0); if (fd < 0) { ret = -fd; diff --git a/fs/vfs/fs_timerfd.c b/fs/vfs/fs_timerfd.c index 5760da3eb5..5720b4f79f 100644 --- a/fs/vfs/fs_timerfd.c +++ b/fs/vfs/fs_timerfd.c @@ -462,8 +462,8 @@ int timerfd_create(int clockid, int flags) /* Initialize the timer instance */ new_dev->clock = clockid; - new_fd = file_allocate(&g_timerfd_inode, O_RDONLY | flags, - 0, new_dev, 0, true); + new_fd = file_allocate_from_inode(&g_timerfd_inode, O_RDONLY | flags, + 0, new_dev, 0); if (new_fd < 0) { ret = new_fd; diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h index 016fbc0618..992c4c69ff 100644 --- a/include/nuttx/fs/fs.h +++ b/include/nuttx/fs/fs.h @@ -188,7 +188,6 @@ struct stat; struct statfs; struct pollfd; struct mtd_dev_s; -struct tcb_s; struct uio; /* The internal representation of type DIR is just a container for an inode @@ -464,21 +463,24 @@ struct file off_t f_pos; /* File position */ FAR struct inode *f_inode; /* Driver or file system interface */ FAR void *f_priv; /* Per file driver private data */ -#ifdef CONFIG_FDSAN - uint64_t f_tag_fdsan; /* File owner fdsan tag, init to 0 */ +#if CONFIG_FS_LOCK_BUCKET_SIZE > 0 + bool f_locked; /* Filelock state: false - unlocked, true - locked */ #endif +}; +struct fd +{ + FAR struct file *f_file; /* The file associated with descriptor */ + bool f_cloexec; /* Close on exec */ #ifdef CONFIG_FDCHECK uint8_t f_tag_fdcheck; /* File owner fdcheck tag, init to 0 */ #endif - + #ifdef CONFIG_FDSAN + uint64_t f_tag_fdsan; /* File owner fdsan tag, init to 0 */ +#endif #if CONFIG_FS_BACKTRACE > 0 FAR void *f_backtrace[CONFIG_FS_BACKTRACE]; /* Backtrace to while file opens */ #endif - -#if CONFIG_FS_LOCK_BUCKET_SIZE > 0 - bool f_locked; /* Filelock state: false - unlocked, true - locked */ -#endif }; /* This defines a two layer array of files indexed by the file descriptor. @@ -488,20 +490,20 @@ struct file * (file descriptor % CONFIG_NFILE_DESCRIPTORS_PER_BLOCK) as column index. */ -struct filelist +struct fdlist { - spinlock_t fl_lock; /* Manage access to the file list */ - uint8_t fl_rows; /* The number of rows of fl_files array */ - FAR struct file **fl_files; /* The pointer of two layer file descriptors array */ + spinlock_t fl_lock; /* Manage access to the file descriptor list */ + uint8_t fl_rows; /* The number of rows of fl_fds array */ + FAR struct fd **fl_fds; /* The pointer of two layer file descriptors array */ - /* Pre-allocated files to avoid allocator access during thread creation - * phase, For functional safety requirements, increase + /* Pre-allocated file descriptors to avoid allocator access during thread + * creation phase, For functional safety requirements, increasing * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK could also avoid allocator access * caused by the file descriptor exceeding the limit. */ - FAR struct file *fl_prefile; - struct file fl_prefiles[CONFIG_NFILE_DESCRIPTORS_PER_BLOCK]; + FAR struct fd *fl_prefd; + struct fd fl_prefds[CONFIG_NFILE_DESCRIPTORS_PER_BLOCK]; }; /* The following structure defines the list of files used for standard C I/O. @@ -880,57 +882,63 @@ int nx_umount2(FAR const char *target, unsigned int flags); #endif /**************************************************************************** - * Name: files_initlist + * Name: fdlist_init * * Description: - * Initializes the list of files for a new task + * Initializes the list of file descriptors for a new task. * ****************************************************************************/ -void files_initlist(FAR struct filelist *list); +void fdlist_init(FAR struct fdlist *list); /**************************************************************************** - * Name: files_dumplist + * Name: fdlist_dump * * Description: - * Dump the list of files. + * Dump the list of file descriptors. * ****************************************************************************/ #ifdef CONFIG_SCHED_DUMP_ON_EXIT -void files_dumplist(FAR struct filelist *list); +void fdlist_dump(FAR struct fdlist *list); #else -# define files_dumplist(l) +# define fdlist_dump(l) #endif /**************************************************************************** - * Name: files_putlist + * Name: fdlist_free * * Description: - * Release the list of files. + * Release the list of file descriptors. + * + * Assumptions: + * Called during task deletion in a safe context. * ****************************************************************************/ -void files_putlist(FAR struct filelist * list); +void fdlist_free(FAR struct fdlist *list); /**************************************************************************** - * Name: files_countlist + * Name: fdlist_count * * Description: - * Get file count from file list + * Get file descriptor count from file list. + * + * Input Parameters: + * list - Pointer to the file descriptor list structure. * * Returned Value: - * file count of file list + * file descriptor count of file list. * ****************************************************************************/ -int files_countlist(FAR struct filelist *list); +int fdlist_count(FAR struct fdlist *list); /**************************************************************************** - * Name: files_duplist + * Name: fdlist_copy * * Description: - * Duplicate parent task's file descriptors. + * Copy parent task's file descriptors to child task. * * Returned Value: * Zero (OK) is returned on success; a negated errno value is returned on @@ -938,59 +946,136 @@ int files_countlist(FAR struct filelist *list); * ****************************************************************************/ -int files_duplist(FAR struct filelist *plist, FAR struct filelist *clist, - FAR const posix_spawn_file_actions_t *actions, - bool cloexec); +int fdlist_copy(FAR struct fdlist *plist, FAR struct fdlist *clist, + FAR const posix_spawn_file_actions_t *actions, + bool cloexec); /**************************************************************************** - * Name: files_fget + * Name: fdlist_get2 * * Description: - * Get the instance of struct file from file list by file descriptor. + * Given a file descriptor, return the corresponding instance of struct + * fd and filep. * * Input Parameters: - * list - The list of files for a task. - * fd - A valid descriptor between 0 and files_countlist(list). + * list - Pointer to the file descriptor list structure. + * fd - The file descriptor + * filep - The location to return the struct file instance + * fdp - The location to return the struct fd instance * * Returned Value: - * Pointer to file structure of list[fd]. + * Return the pointer to file structure of list[fd] when list[fd].f_file + * is valid, othersize, a null pointer is returned. * ****************************************************************************/ -FAR struct file *files_fget(FAR struct filelist *list, int fd); +int fdlist_get2(FAR struct fdlist *list, int fd, + FAR struct file **filep, FAR struct fd **fdp); /**************************************************************************** - * Name: file_allocate_from_tcb + * Name: fdlist_get * * Description: - * Allocate a struct files instance and associate it with an inode - * instance. + * Given a file descriptor, return the corresponding instance of struct + * filep. + * + * Input Parameters: + * list - Pointer to the file descriptor list structure. + * fd - The file descriptor + * filep - The location to return the struct file instance * * Returned Value: - * Returns the file descriptor == index into the files array on success; - * a negated errno value is returned on any failure. + * Return the pointer to file structure of list[fd] when list[fd].f_file + * is valid, othersize, a null pointer is returned. * ****************************************************************************/ -int file_allocate_from_tcb(FAR struct tcb_s *tcb, FAR struct inode *inode, - int oflags, off_t pos, FAR void *priv, int minfd, - bool addref); +#define fdlist_get(list, fd, filep) fdlist_get2(list, fd, filep, NULL) + +/**************************************************************************** + * Name: fdlist_dupfile + * + * Description: + * Allocate a struct fd instance and bind it to the corresponding file + * handle. + * + * Returned Value: + * Returns the file descriptor == index into the files array on success; + * a negated errno value is returned on any failure. + * + ****************************************************************************/ + +int fdlist_dupfile(FAR struct fdlist *list, int oflags, int minfd, + FAR struct file *filep); + +/**************************************************************************** + * Name: fdlist_allocate + * + * Description: + * Allocate a struct fd instance and associate it with an empty file + * instance. The difference between this function and + * file_allocate_from_inode is that this function is only used for + * placeholder purposes. Later, the caller will initialize the file entity + * through the returned filep. + * + * The fd allocated by this function can be released using fdlist_close. + * + * After the function call is completed, it will hold a reference count + * for the filep. Therefore, when the filep is no longer in use, it is + * necessary to call file_put to release the reference count, in order + * to avoid a race condition where the file might be closed during + * this process. + * + * Returned Value: + * Returns the file descriptor == index into the files array on success; + * a negated errno value is returned on any failure. + * + ****************************************************************************/ + +int fdlist_allocate(FAR struct fdlist *list, int oflags, + int minfd, FAR struct file **filep); /**************************************************************************** * Name: file_allocate * * Description: - * Allocate a struct files instance and associate it with an inode - * instance. + * Allocate a struct fd instance and associate it with an empty file + * instance. The difference between this function and + * file_allocate_from_inode is that this function is only used for + * placeholder purposes. Later, the caller will initialize the file entity + * through the returned filep. + * + * The fd allocated by this function can be released using nx_close. + * + * After the function call is completed, it will hold a reference count + * for the filep. Therefore, when the filep is no longer in use, it is + * necessary to call file_put to release the reference count, in order + * to avoid a race condition where the file might be closed during + * this process. + * + * Returned Value: + * Returns the file descriptor == index into the files array on success; + * a negated errno value is returned on any failure. + * + ****************************************************************************/ + +int file_allocate(int oflags, int minfd, FAR struct file **filep); + +/**************************************************************************** + * Name: file_allocate_from_inode + * + * Description: + * Allocate a struct fd instance and associate it with an file instance. + * And initialize them with inode, oflags, pos and priv. * * Returned Value: - * Returns the file descriptor == index into the files array on success; - * a negated errno value is returned on any failure. + * Returns the file descriptor == index into the files array on success; + * a negated errno value is returned on any failure. * ****************************************************************************/ -int file_allocate(FAR struct inode *inode, int oflags, off_t pos, - FAR void *priv, int minfd, bool addref); +int file_allocate_from_inode(FAR struct inode *inode, int oflags, off_t pos, + FAR void *priv, int minfd); /**************************************************************************** * Name: file_dup @@ -1026,14 +1111,14 @@ int file_dup(FAR struct file *filep, int minfd, int flags); int file_dup2(FAR struct file *filep1, FAR struct file *filep2); /**************************************************************************** - * Name: nx_dup3_from_tcb + * Name: fdlist_dup3 * * Description: - * nx_dup3_from_tcb() is similar to the standard 'dup3' interface + * fdlist_dup3() is similar to the standard 'dup3' interface * except that is not a cancellation point and it does not modify the * errno variable. * - * nx_dup3_from_tcb() is an internal NuttX interface and should not be + * fdlist_dup3() is an internal NuttX interface and should not be * called from applications. * * Clone a file descriptor to a specific descriptor number. @@ -1044,17 +1129,17 @@ int file_dup2(FAR struct file *filep1, FAR struct file *filep2); * ****************************************************************************/ -int nx_dup3_from_tcb(FAR struct tcb_s *tcb, int fd1, int fd2, int flags); +int fdlist_dup3(FAR struct fdlist *list, int fd1, int fd2, int flags); /**************************************************************************** - * Name: nx_dup2_from_tcb + * Name: fdlist_dup2 * * Description: - * nx_dup2_from_tcb() is similar to the standard 'dup2' interface + * fdlist_dup2() is similar to the standard 'dup2' interface * except that is not a cancellation point and it does not modify the * errno variable. * - * nx_dup2_from_tcb() is an internal NuttX interface and should not be + * fdlist_dup2() is an internal NuttX interface and should not be * called from applications. * * Clone a file descriptor to a specific descriptor number. @@ -1065,7 +1150,7 @@ int nx_dup3_from_tcb(FAR struct tcb_s *tcb, int fd1, int fd2, int flags); * ****************************************************************************/ -int nx_dup2_from_tcb(FAR struct tcb_s *tcb, int fd1, int fd2); +int fdlist_dup2(FAR struct fdlist *list, int fd1, int fd2); /**************************************************************************** * Name: nx_dup2 @@ -1085,24 +1170,6 @@ int nx_dup2_from_tcb(FAR struct tcb_s *tcb, int fd1, int fd2); int nx_dup2(int fd1, int fd2); -/**************************************************************************** - * Name: file_dup3 - * - * Description: - * Assign an inode to a specific files structure. This is the heart of - * dup3. - * - * Equivalent to the non-standard dup3() function except that it - * accepts struct file instances instead of file descriptors. - * - * Returned Value: - * Zero (OK) is returned on success; a negated errno value is return on - * any failure. - * - ****************************************************************************/ - -int file_dup3(FAR struct file *filep1, FAR struct file *filep2, int flags); - /**************************************************************************** * Name: file_open * @@ -1127,18 +1194,18 @@ int file_dup3(FAR struct file *filep1, FAR struct file *filep2, int flags); int file_open(FAR struct file *filep, FAR const char *path, int oflags, ...); /**************************************************************************** - * Name: nx_open_from_tcb + * Name: fdlist_open * * Description: - * nx_open_from_tcb() is similar to the standard 'open' interface except + * fdlist_open() is similar to the standard 'open' interface except * that it is not a cancellation point and it does not modify the errno * variable. * - * nx_open_from_tcb() is an internal NuttX interface and should not be + * fdlist_open() is an internal NuttX interface and should not be * called from applications. * * Input Parameters: - * tcb - Address of the task's TCB + * list - Pointer to the file descriptor list structure. * path - The full path to the file to be opened. * oflags - open flags. * ... - Variable number of arguments, may include 'mode_t mode' @@ -1149,8 +1216,8 @@ int file_open(FAR struct file *filep, FAR const char *path, int oflags, ...); * ****************************************************************************/ -int nx_open_from_tcb(FAR struct tcb_s *tcb, - FAR const char *path, int oflags, ...); +int fdlist_open(FAR struct fdlist *list, + FAR const char *path, int oflags, ...); /**************************************************************************** * Name: nx_open @@ -1170,6 +1237,26 @@ int nx_open_from_tcb(FAR struct tcb_s *tcb, int nx_open(FAR const char *path, int oflags, ...); +/**************************************************************************** + * Name: file_get2 + * + * Description: + * Given a file descriptor, return the corresponding instance of struct + * fd and filep + * + * Input Parameters: + * fd - The file descriptor + * filep - The location to return the struct file instance + * fdp - The location to return the struct fd instance + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +int file_get2(int fd, FAR struct file **filep, FAR struct fd **fdp); + /**************************************************************************** * Name: file_get * @@ -1188,7 +1275,7 @@ int nx_open(FAR const char *path, int oflags, ...); * ****************************************************************************/ -int file_get(int fd, FAR struct file **filep); +#define file_get(fd, filep) file_get2(fd, filep, NULL) /**************************************************************************** * Name: file_ref @@ -1240,33 +1327,14 @@ int file_put(FAR struct file *filep); int file_close(FAR struct file *filep); /**************************************************************************** - * Name: file_close_without_clear - * - * Description: - * Close a file that was previously opened with file_open(), but without - * clear filep. - * - * Input Parameters: - * filep - A pointer to a user provided memory location containing the - * open file data returned by file_open(). - * - * Returned Value: - * Zero (OK) is returned on success; A negated errno value is returned on - * any failure to indicate the nature of the failure. - * - ****************************************************************************/ - -int file_close_without_clear(FAR struct file *filep); - -/**************************************************************************** - * Name: nx_close_from_tcb + * Name: fdlist_close * * Description: - * nx_close_from_tcb() is similar to the standard 'close' interface + * fdlist_close() is similar to the standard 'close' interface * except that is not a cancellation point and it does not modify the * errno variable. * - * nx_close_from_tcb() is an internal NuttX interface and should not + * fdlist_close() is an internal NuttX interface and should not * be called from applications. * * Close an inode (if open) @@ -1281,7 +1349,7 @@ int file_close_without_clear(FAR struct file *filep); * ****************************************************************************/ -int nx_close_from_tcb(FAR struct tcb_s *tcb, int fd); +int fdlist_close(FAR struct fdlist *list, int fd); /**************************************************************************** * Name: nx_close diff --git a/include/nuttx/fs/ioctl.h b/include/nuttx/fs/ioctl.h index ed2d62bb67..469badb629 100644 --- a/include/nuttx/fs/ioctl.h +++ b/include/nuttx/fs/ioctl.h @@ -235,6 +235,16 @@ * OUT: Current file xip base address */ +#define FIOC_GETFLAGS _FIOC(0x0016) /* IN: None + * OUT: None + */ +#define FIOC_SETFLAGS _FIOC(0x0017) /* IN: The flags that need to set to file + * OUT: None + */ +#define FIOGCLEX _FIOC(0x0018) /* IN: FAR int * + * OUT: None + */ + /* NuttX file system ioctl definitions **************************************/ #define _DIOCVALID(c) (_IOC_TYPE(c)==_DIOCBASE) diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index a84936cd9d..0ae6d2c726 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -539,7 +539,7 @@ struct task_group_s /* File descriptors *******************************************************/ - struct filelist tg_filelist; /* Maps file descriptor to file */ + struct fdlist tg_fdlist; /* Maps file descriptor to file */ /* Virtual memory mapping info ********************************************/ @@ -932,10 +932,10 @@ int nxsched_release_tcb(FAR struct tcb_s *tcb, uint8_t ttype); */ /**************************************************************************** - * Name: nxsched_get_files_from_tcb + * Name: nxsched_get_fdlist_from_tcb * * Description: - * Return a pointer to the file list from task context + * Return a pointer to the file descriptor list from task context. * * Input Parameters: * tcb - Address of the new task's TCB @@ -947,25 +947,25 @@ int nxsched_release_tcb(FAR struct tcb_s *tcb, uint8_t ttype); * ****************************************************************************/ -FAR struct filelist *nxsched_get_files_from_tcb(FAR struct tcb_s *tcb); +FAR struct fdlist *nxsched_get_fdlist_from_tcb(FAR struct tcb_s *tcb); /**************************************************************************** - * Name: nxsched_get_files + * Name: nxsched_get_fdlist * * Description: - * Return a pointer to the file list for this thread + * Return a pointer to the file descriptor list for this thread. * * Input Parameters: * None * * Returned Value: - * A pointer to the errno. + * A pointer to the file descriptor list. * * Assumptions: * ****************************************************************************/ -FAR struct filelist *nxsched_get_files(void); +FAR struct fdlist *nxsched_get_fdlist(void); /**************************************************************************** * Name: nxtask_init diff --git a/sched/group/group_create.c b/sched/group/group_create.c index ceaf11bf7f..49a797d1f3 100644 --- a/sched/group/group_create.c +++ b/sched/group/group_create.c @@ -168,7 +168,7 @@ int group_initialize(FAR struct task_tcb_s *tcb, uint8_t ttype) /* Initialize file descriptors for the TCB */ - files_initlist(&group->tg_filelist); + fdlist_init(&group->tg_fdlist); /* Alloc task info for group */ diff --git a/sched/group/group_leave.c b/sched/group/group_leave.c index a8e6dc0d05..0ea281250d 100644 --- a/sched/group/group_leave.c +++ b/sched/group/group_leave.c @@ -102,7 +102,7 @@ group_release(FAR struct task_group_s *group, uint8_t ttype) /* Free resources held by the file descriptor list */ - files_putlist(&group->tg_filelist); + fdlist_free(&group->tg_fdlist); #ifndef CONFIG_DISABLE_ENVIRON /* Release all shared environment variables */ diff --git a/sched/group/group_setuptaskfiles.c b/sched/group/group_setuptaskfiles.c index 4189445e26..4af75193e0 100644 --- a/sched/group/group_setuptaskfiles.c +++ b/sched/group/group_setuptaskfiles.c @@ -83,8 +83,8 @@ int group_setuptaskfiles(FAR struct task_tcb_s *tcb, if (group != rtcb->group) { - files_duplist(&rtcb->group->tg_filelist, - &group->tg_filelist, actions, cloexec); + ret = fdlist_copy(&rtcb->group->tg_fdlist, + &group->tg_fdlist, actions, cloexec); } if (ret >= 0 && actions != NULL) diff --git a/sched/misc/assert.c b/sched/misc/assert.c index 969fbf68fe..7555d4c052 100644 --- a/sched/misc/assert.c +++ b/sched/misc/assert.c @@ -456,10 +456,10 @@ static void dump_backtrace(FAR struct tcb_s *tcb, FAR void *arg) ****************************************************************************/ #ifdef CONFIG_SCHED_DUMP_ON_EXIT -static void dump_filelist(FAR struct tcb_s *tcb, FAR void *arg) +static void dump_fdlist(FAR struct tcb_s *tcb, FAR void *arg) { - FAR struct filelist *filelist = &tcb->group->tg_filelist; - files_dumplist(filelist); + FAR struct fdlist *list = &tcb->group->tg_fdlist; + fdlist_dump(list); } #endif @@ -548,7 +548,7 @@ static void dump_tasks(void) #endif #ifdef CONFIG_SCHED_DUMP_ON_EXIT - nxsched_foreach(dump_filelist, NULL); + nxsched_foreach(dump_fdlist, NULL); #endif } diff --git a/sched/sched/sched_getfiles.c b/sched/sched/sched_getfiles.c index 53dabbf4b7..e2125a7ac7 100644 --- a/sched/sched/sched_getfiles.c +++ b/sched/sched/sched_getfiles.c @@ -33,22 +33,22 @@ ****************************************************************************/ /**************************************************************************** - * Name: nxsched_get_files_from_tcb + * Name: nxsched_get_fdlist_from_tcb * * Description: - * Return a pointer to the file list from task context + * Return a pointer to the file descriptor list from task context. * * Input Parameters: * tcb - Address of the new task's TCB * * Returned Value: - * A pointer to the errno. + * A pointer to the file descriptor list. * * Assumptions: * ****************************************************************************/ -FAR struct filelist *nxsched_get_files_from_tcb(FAR struct tcb_s *tcb) +FAR struct fdlist *nxsched_get_fdlist_from_tcb(FAR struct tcb_s *tcb) { FAR struct task_group_s *group = tcb->group; @@ -60,7 +60,7 @@ FAR struct filelist *nxsched_get_files_from_tcb(FAR struct tcb_s *tcb) if (group) { - return &group->tg_filelist; + return &group->tg_fdlist; } /* Higher level logic must handle the NULL gracefully */ @@ -69,22 +69,22 @@ FAR struct filelist *nxsched_get_files_from_tcb(FAR struct tcb_s *tcb) } /**************************************************************************** - * Name: nxsched_get_files + * Name: nxsched_get_fdlist * * Description: - * Return a pointer to the file list for this thread + * Return a pointer to the file descriptor list for this thread. * * Input Parameters: * None * * Returned Value: - * A pointer to the errno. + * A pointer to the file descriptor list. * * Assumptions: * ****************************************************************************/ -FAR struct filelist *nxsched_get_files(void) +FAR struct fdlist *nxsched_get_fdlist(void) { - return nxsched_get_files_from_tcb(this_task()); + return nxsched_get_fdlist_from_tcb(this_task()); } diff --git a/sched/task/task_spawnparms.c b/sched/task/task_spawnparms.c index 3066b32a7d..7022b5d576 100644 --- a/sched/task/task_spawnparms.c +++ b/sched/task/task_spawnparms.c @@ -68,7 +68,7 @@ nxspawn_close(FAR struct tcb_s *tcb, sinfo("Closing fd=%d\n", action->fd); - nx_close_from_tcb(tcb, action->fd); + fdlist_close(nxsched_get_fdlist_from_tcb(tcb), action->fd); } static inline int nxspawn_dup2(FAR struct tcb_s *tcb, @@ -78,12 +78,14 @@ static inline int nxspawn_dup2(FAR struct tcb_s *tcb, sinfo("Dup'ing %d->%d\n", action->fd1, action->fd2); - return nx_dup2_from_tcb(tcb, action->fd1, action->fd2); + return fdlist_dup2(nxsched_get_fdlist_from_tcb(tcb), + action->fd1, action->fd2); } static inline int nxspawn_open(FAR struct tcb_s *tcb, FAR struct spawn_open_file_action_s *action) { + FAR struct fdlist *list; int ret = OK; int fd; @@ -92,22 +94,23 @@ static inline int nxspawn_open(FAR struct tcb_s *tcb, sinfo("Open'ing path=%s oflags=%04x mode=%04x\n", action->path, action->oflags, action->mode); - nx_close_from_tcb(tcb, action->fd); + list = nxsched_get_fdlist_from_tcb(tcb); + fdlist_close(list, action->fd); - fd = nx_open_from_tcb(tcb, action->path, action->oflags, action->mode); + fd = fdlist_open(list, action->path, action->oflags, action->mode); if (fd < 0) { ret = fd; } else if (fd != action->fd) { - ret = nx_dup2_from_tcb(tcb, fd, action->fd); + ret = fdlist_dup2(list, fd, action->fd); if (ret >= 0) { ret = OK; } - nx_close_from_tcb(tcb, fd); + fdlist_close(list, fd); } return ret;