To simplify the handling of Block devices and MTD devices,
the unique_chardev and unique_blkdev functions now use local
variable names instead of allocating device names from the heap.
Signed-off-by: jingfei <jingfei@xiaomi.com>
Fix a race on userfs_state_s iobuffer.
1. Task 1 takes the mutex and does a userfs operation.
2. A higher priority task 2 blocks on the mutex.
3. Task 1 releases the mutex when finished. The iobuffer response has not
been processed by task 1 yet, but task 2 is higher priority
and control switches to it.
4. Task 2 does a userfs operation and releases the mutex.
The iobuffer now contains task 2's response.
5. Control returns to task 1 for it to check the iobuffer
response. It contains task 2's response, not its own.
Fix it by releasing the mutex only after the exclusive iobuffer
usage lifecycle is complete.
Signed-off-by: liamHowatt <liamjmh0@gmail.com>
issue description:
task A: NSH:
1.open-> reboot->sync->task_fsfsync
2.nx_vopen-> context switch
3.fdlist_allocate: ----> 4.fsync->file_sync->assert(inode or priv is empty)
(new fd with empty filep)
5.file_vopen:
(init empty filep)
6.return fd
Task A allocates a new fd with an empty filep in fdlist_allocate. Before
it can fully initialize the filep in file_vopen, the NSH task triggers a
file - system sync operation. The sync operation encounters the empty
filep associated with the newly allocated fd, causing the assertion to
fail and the system to crash.
To resolve this race condition, we should modify the fd allocation
process. Instead of allocating a new fd with an empty filep first and
then initializing it later, we should use the file_allocate_from_inode
function. This function allows us to initialize the file structure first
and then bind it to the new filep when allocating the fd. By doing so,
we ensure that the filep is always properly initialized before it is
used in any file - system operations, thus preventing the assertion
failure and the subsequent system crash.
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
When a child process inherits file descriptors from its parent via
fdlist_copy(), the fd tags (fd_tag_fdsan and fd_tag_fdcheck) were not
being copied. This caused assertion failures when the child process
closed inherited file descriptors, because the fdcheck/fdsan subsystems
expected the tags to match.
Root Cause:
----------
The fdlist_install() function was not preserving the fd tags during
fd duplication. When copying fds from parent to child in fdlist_copy(),
the tags were lost, resulting in:
- fd_tag_fdsan: Used for file descriptor ownership tracking (FDSAN)
- fd_tag_fdcheck: Used for fd validity checking (FDCHECK)
Both tags being reset to 0/NULL instead of copied from parent.
Symptom:
--------
Child processes would crash with assertion failure in fdcheck_restore()
when closing inherited file descriptors:
fdcheck_restore+0x69/0xa0
fdlist_get2+0x11/0x48
fdlist_close+0xd/0x94
close+0x15/0x30
This occurred because fdcheck_restore() validates that the fd_tag_fdcheck
matches the expected value, and the mismatch triggered an assertion.
Solution:
---------
1. Add a 'copy' parameter to fdlist_install() to distinguish between:
- New fd allocation (copy=false): Initialize fresh tags
- Fd duplication (copy=true): Preserve tags from source fd
2. Add fdp parameter to fdlist_install() to access source fd tags
3. In fdlist_copy(), pass copy=true to preserve parent's fd tags
4. In fdlist_dup3(), pass copy=false since dup operations should
create independent fd tracking (not copy parent tags)
Changes:
--------
- fdlist_install(): Added 'fdp' and 'copy' parameters
- When copy=true, preserve fd_tag_fdsan and fd_tag_fdcheck from source
- fdlist_copy(): Pass copy=true to preserve parent tags
- fdlist_dup3(): Pass copy=false for normal dup behavior
Impact:
-------
This fix ensures that file descriptor ownership tracking and validity
checking work correctly across fork/clone operations, preventing
crashes when child processes close inherited file descriptors.
Without this fix, any program using fork() with inherited fds would
crash if CONFIG_FDSAN or CONFIG_FDCHECK were enabled.
Issue backtrace:
backtrace_unwind+0x105/0x108
sched_backtrace+0x6f/0x80
sched_dumpstack+0x33/0x80
_assert+0x229/0x510
arm_syscall+0x81/0x98
up_assert+0xd/0x18
__assert+0x1d/0x24
fdcheck_restore+0x69/0xa0
fdlist_get2+0x11/0x48
fdlist_close+0xd/0x94
close+0x15/0x30
closefd+0x5/0x30
notify_parent_process+0x2b/0x40
run_helper_tcp4_echo_server+0x75/0x114
run_test_part+0x5f/0x68
uv_run_tests_main+0x35/0x60
run_test_part+0x5f/0x68
uv_run_tests_main+0x35/0x60
nxtask_startup+0x13/0x2c
nxtask_start+0x4d/0x64
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
Before this fix, the check for OPEN_MAX was performed using orig_rows
instead of the new row count after extension. This caused the check to
pass even when the allocation would exceed OPEN_MAX limit.
For example:
- OPEN_MAX = 256
- CONFIG_NFILE_DESCRIPTORS_PER_BLOCK = 32
- orig_rows = 8 (8 * 32 = 256, at the limit)
The old code checked: 32 * 8 > 256 (false, allows extension)
The new code checks: 32 * (8 + 1) > 256 (true, correctly blocks)
Without this fix, the system could allocate more file descriptors than
OPEN_MAX allows, potentially causing memory corruption or exceeding
system limits.
This fix ensures the check evaluates the new total count (orig_rows + 1)
before allowing the extension to proceed.
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
Issue:
When using a stack-allocated file structure, the sequence:
1. file_open() initializes the stack file structure
2. file_mmap() creates memory mapping and increments reference count
3. file_munmap() decrements reference count and may free the file structure
4. file_close() attempts to close already freed structure → crash
Root cause:
The memory mapping operations (fs_reffilep/fs_putfilep) manage reference counts
independently and can free the stack-allocated file structure prematurely.
Solution:
- Add reference count protection during file_open() for stack-allocated files
- Clear reference count appropriately during file_close()
- This ensures the file structure remains valid throughout its lifetime
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
When a thread is terminated via pthread_exit() while blocked in epoll_wait(),
the file reference taken at the beginning of epoll_wait() is not properly
released, leading to resource leaks.
Problem scenario found during libuv test:
1. Echo server thread is blocked in epoll_wait()
2. Main task sends pthread_kill signal to the server thread
3. Signal handler calls pthread_exit() to terminate the thread
4. epoll_wait() is interrupted before reaching the file_put() call
5. The epoll fd reference count remains elevated
6. epoll_do_close() is never called, leaving fds in internal queues
7. File descriptors leak
Solution:
Register a TLS (Thread Local Storage) cleanup handler using tls_cleanup_push()
at the beginning of epoll_wait() blocking section. This ensures that if the
thread exits abnormally (via pthread_exit, pthread_cancel, etc.), the cleanup
handler (epoll_cleanup) will be called automatically to release the file
reference via file_put().
The cleanup handler is properly paired with tls_cleanup_pop() when epoll_wait()
completes normally, ensuring the handler is only invoked on abnormal exit.
This fix is applied to both epoll_wait() code paths (with and without extended
mode) to ensure consistent behavior.
Impact:
- Prevents epoll fd reference count leaks on thread cancellation
- Ensures proper cleanup even when epoll_wait() is interrupted by pthread_exit
- Critical for multi-threaded applications using signals and thread termination
- Works together with previous fix for teardown/oneshot list cleanup
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
When an epoll fd is closed, the file descriptors in the teardown and
oneshot lists were not being properly dereferenced, leading to fd leaks.
This fix ensures that all fds in the teardown and oneshot lists are
properly released via file_put() during epoll_do_close(), matching the
behavior for fds in the setup list.
Impact:
- Prevents fd leaks when epoll fd is closed
- Ensures proper cleanup of all tracked file descriptors
- Critical for applications using EPOLLONESHOT or fd removal operations
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
The 'created' flag values were incorrectly inverted in file_mq_vopen():
1. When opening an existing message queue (inode_find succeeds):
- Before: incorrectly set *created = 1 (indicating new creation)
- After: correctly set *created = 0 (indicating existing queue)
2. When creating a new message queue (inode_find fails):
- Before: incorrectly set *created = 0 (indicating existing queue)
- After: correctly set *created = 1 (indicating new creation)
This bug could lead to incorrect resource management and cleanup behavior
in the calling function nxmq_vopen() when file_allocate() returns an error,
as it relies on the 'created' flag to determine whether the message queue
was newly created and needs to be cleaned up.
Impact:
- Resource leak when opening existing queues that should not be released
- Missing cleanup when creating new queues that should be released on error
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
lfs_fs_size() can return more blocks than block_count during active
writes due to copy-on-write blocks. This caused f_bavail to underflow
to a large positive number. Add clamping to prevent this.
Signed-off-by: Julian Oes <julian@oes.ch>
This reverts commit ac6fff747a7a6122e61de373350148331a94692f.
This reverts commit c83e3f651b967c64b5652a6bd2e96bcae48417b4.
This reverts commit 133db24d072457331134b683ad7b84c8a002feb9.
This reverts commit 5c1248ec38964e7886b23e65f732241c5d870d69.
This reverts commit 2cc850b6dcbad904282f1a326f52bff054251591.
This reverts commit 49cad84508e7db903068180fe4ebdfaef335efac.
Signed-off-by: guohao15 <guohao15@xiaomi.com>
if first call unlink after call nxmq_file_close
cause i_crefs not 0 will leak msqg, inode will
free in unlink, but forget free msgq
Signed-off-by: anjiahao <anjiahao@xiaomi.com>
The lines will end with \n to prevent atoi('\n') from always being 0. It is recommended to check the first byte directly.
Signed-off-by: anjiahao <anjiahao@xiaomi.com>
when i is zero and file_get is failed, num is -1,
it's uint32_max for nfds.
so remove num and simplify code logic.
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
nxsig_ismember() has a return type of int, but the current
implementation returns a boolean value, which is incorrect.
All callers should determine membership by checking whether
the return value is 1 or 0, which is also consistent with the POSIX sigismember() API.
Signed-off-by: Chengdong Wang wangchengdong@lixiang.com
It acts as register_driver but also populates the inode size.
This allows to return a non-zero size when calling stat() on an eeprom
driver.
The conditions (CONFIG_PSEUDOFS_FILE or CONFIG_FS_SHMFS) for the
declaration of the inode size field have also been removed so that other
drivers can populate this field in the future.
Signed-off-by: Antoine Juckler <6445757+ajuckler@users.noreply.github.com>
Nuttx currently has 2 types of sleep interfaces:
1. Signal-scheduled sleep: nxsig_sleep() / nxsig_usleep() / nxsig_nanosleep()
Weaknesses:
a. Signal-dependent: The signal-scheduled sleep method is bound to the signal framework, while some driver sleep operations do not depend on signals.
b. Timespec conversion: Signal-scheduled sleep involves timespec conversion, which has a significant impact on performance.
2. Busy sleep: up_mdelay() / up_udelay()
Weaknesses:
a. Does not actively trigger scheduling, occupy the CPU loading.
3. New interfaces: Scheduled sleep: nxsched_sleep() / nxsched_usleep() / nxsched_msleep() / nxsched_ticksleep()
Strengths:
a. Does not depend on the signal framework.
b. Tick-based, without additional computational overhead.
Currently, the Nuttx driver framework extensively uses nxsig_* interfaces. However, the driver does not need to rely on signals or timespec conversion.
Therefore, a new set of APIs is added to reduce dependencies on other modules.
(This PR also aims to make signals optional, further reducing the code size of Nuttx.)
Signed-off-by: chao an <anchao.archer@bytedance.com>
mmap() should return EBADF errno when fd is not valid.
We can just return error code from file_get().
Signed-off-by: p-szafonimateusz <p-szafonimateusz@xiaomi.com>
changes should not be flushed to the underlying file if memory mapping is
marked as MAP_PRIVATE.
Signed-off-by: p-szafonimateusz <p-szafonimateusz@xiaomi.com>
Many times, context switching does not occur when the thread stack
memory is almost exhausted, so we need to mofify up_check_tcbstack to
accurately detect it.
Co-authored-by: Chengdong Wang <wangchengdong@lixiang.com>
Signed-off-by: guoshengyuan1 <guoshengyuan1@xiaomi.com>
Fat_zero_cluster() use fs_heap_malloc() for buffer that
is used to call fat_hwread().
Fat_hwread() must be called with IO buffer that have proper
alingment because it might use DMA.
Fix changes fs_heap_malloc() to fat_io_alloc() which uses
correct fat_dma_alloc() if CONFIG_FAT_DMAMEMORY is defined.
Signed-off-by: Ari Kimari <ari.kimari@tii.ae>
The previous approach with memfd has 3 problems:
1) The close operation on the memfd isn't tied with optee_shm_close,
therefore close(fd) doesn't free the optee_shm struct allocated
by the kernel.
2) The kernel unnecessarily maps the file descriptor to its memory,
however only userspace should need to do that.
3) Since the kernel doesn't need to map the file descriptor we
don't need to unmap it.
To use anonymous mapping, the prototype of map_anonymous() was
moved from fs/mmap/fs_anonmap.h to include/nuttx/fs/fs.h. Since
fs_anonmap.h didn't contain any other information it is deleted.
A type from fs/mmap/fs_rammap.h was moved to the public :
include/nuttx/fs/fs.h as well.
Signed-off-by: Theodore Karatapanis <tkaratapanis@census-labs.com>
* Recurrency is removed from filesystem directory rename.
* Fixes use after free in buffer that was used as output and argument.
Signed-off-by: Tomasz 'CeDeROM' CEDRO <tomek@cedro.info>
To save more space (equivalent to the size of one erase sector of
MTD device) and to achieve faster read and write speeds, a method
for direct writing was introduced at the FTL layer.
This can be accomplished simply by using the following oflags during
the open operation:
1. O_DIRECT. when this flag is passed in, ftl internally uses
the direct write strategy and no read cache is used in ftl;
otherwise, each write will be executed with the minimum
granularity of flash erase sector size which means a
"sector read back - erase sector - write sector" operation
is performed by using a read cache buffer in heap.
2. O_SYNC. When this flag is passed in, we assume that the
flash has been erased in advance and no erasure operation
will be performed internally within ftl. O_SYNC will take
effect only when both O_DIRECT and O_SYNC are passed in
simultaneously.
3. For uniformity, we remapped the mount flag in mount.h and
unified it with the open flag in fcntl.h. The repetitive
parts of their definitions were reused, and the remaining
part of the mount flag redefine to the unused bit of open
flags.
Signed-off-by: jingfei <jingfei@xiaomi.com>
Refered to PRINTF(3), the [v]snprintf returns the number of characters
printed (excluding the null byte used to end output to strings).
Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
Double free occurred in lib_put_pathbuffer if CONFIG_FS_NOTIFY option
was enabled. The second if statement has to be called only if the
close operation returned error. The bug was introduced in 14f5c48
and was causing misc/lib_tempbuffer.c:141 debug assertion.
Signed-off-by: Michal Lenc <michallenc@seznam.cz>
these command FIOGCLEX/FIOCLEX/FIONCLEX are related to struct fd,
so need to use ioctl to implement.
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
When writing to the next sector after the forward position has been written
by seek, the old sector buffer is used, which may corrupt the file system.
Therefore, the sector buffer must always be updated after a writing by seek.
Signed-off-by: SPRESENSE <41312067+SPRESENSE@users.noreply.github.com>