zhaoxingyu12 opened a new pull request, #21769:
URL: https://github.com/apache/nuttx/pull/21769

   The scratch buffers under fs/ are freed before the call returns.  Take them 
from the global temp buffer pool instead of fs_heap: allocation becomes a 
bitmap lookup, and the transient traffic no longer fragments fs_heap.
   
   ## Summary
   
   The scratch buffers under fs/ are allocated, used within a single call, and 
released before that call returns. They were taken from the filesystem private 
heap (fs_heap_malloc() / fs_heap_free()), which means every such call pays a 
heap allocation and a free, and this purely transient traffic interleaves with 
the long-lived allocations in fs_heap and fragments it.
   
   This change takes those buffers from the global temporary buffer pool 
(lib_get_tempbuffer() / lib_put_tempbuffer()) instead. When the request fits in 
the pool, the allocation is an ffs() on a free bitmap plus one 
atomic_cmpxchg(), with no heap involvement at all; requests that do not fit 
fall back to an ordinary allocation. The facility is already used for the same 
purpose in libs/libc and libs/libbuiltin, so this makes fs/ consistent with 
existing practice rather than introducing a new mechanism.
   
   Two API differences are absorbed at the call sites: lib_get_tempbuffer() 
does not zero its buffer, so the sites that previously used fs_heap_zalloc() 
clear it explicitly; and the facility has no strdup() equivalent, so the single 
site that duplicated a string now measures it with strlen() and copies it with 
memcpy().
   
   ## Impact
   
   Users / API: no change. No public interface, Kconfig option, on-disk format 
or error code is added, removed or renamed.
   Build: no change to the build system or to any defconfig.
   Hardware: none.
   Documentation: none.
   Security: no change. No new external input is parsed and no buffer size is 
derived from untrusted data.
   Compatibility: behaviour is preserved, but the memory a request is served 
from now depends on configuration. Requests up to TEMP_MAX_SIZE (the larger of 
CONFIG_PATH_MAX and CONFIG_LINE_MAX) come from the static pool of 
CONFIG_LIBC_MAX_TEMPBUFFER buffers. Larger requests fall back to lib_malloc() 
when CONFIG_LIBC_TEMPBUFFER_MALLOC=y. With CONFIG_LIBC_TEMPBUFFER=n the 
facility degrades to alloca(), so these buffers come from the caller stack; 
configurations that disable the option and run with tight stacks should be 
sized accordingly.
   
   ## Testing
   
   Host: Ubuntu x86_64, riscv-none-elf-gcc 13.4.0, QEMU 10.2.1
   
   Target: rv-virt:nsh64 (QEMU riscv64, single core)
   
   
   $ ./tools/configure.sh rv-virt:nsh64
   $ make
   $ qemu-system-riscv64 -semihosting -M virt,aclint=on -cpu rv64 -smp 1 \
         -bios none -kernel nuttx -nographic
   Relevant configuration of the test image:
   
   
   CONFIG_LIBC_TEMPBUFFER=y
   CONFIG_LIBC_MAX_TEMPBUFFER=2
   CONFIG_LIBC_TEMPBUFFER_MALLOC=y
   CONFIG_PATH_MAX=256        /* TEMP_MAX_SIZE = 256 */
   CONFIG_LINE_MAX=80
   CONFIG_SENDFILE_BUFSIZE=512
   A small test application exercises the two converted call sites that are 
reachable from user space, covering the normal path, the empty/NULL path and 
the path where the request exceeds the pool and falls back to a heap allocation:
   
   
   nsh> tbuftest
   tbuftest: TEMP_MAX_SIZE=256 MAX_TEMPBUFFER=2 SENDFILE_BUFSIZE=512
   --- fs/vfs/fs_select.c ---
   [ OK   ] select: timeout            ret=0 want 0
   [ OK   ] select: readable           ret=1 isset=1 want 1/1
   [ OK   ] select: nfds=0 x20         ret=0, no crash
   [ OK   ] select: 40fd pool-overflow ret=40 want 40 (320B)
   --- fs/vfs/fs_sendfile.c ---
   [ OK   ] sendfile: 2000B            sent=2000 verify=0 want 2000/0
   [ OK   ] sendfile: offset=1000      sent=1000 verify=0 want 1000/0
   [ OK   ] sendfile: 200x             no leak/assert
   What each case checks:
   
   select: timeout / select: readable — a pipe with and without pending data. 
The readable case also confirms that the explicit memset() correctly replaces 
the previous fs_heap_zalloc(), since a stale events field would produce wrong 
revents.
   select: nfds=0 x20 — with nfds == 0 no pollfd array is allocated and pollset 
stays NULL; repeated 20 times to confirm the release path handles it.
   select: 40fd pool-overflow — 40 pollfd entries are 320 bytes, above 
TEMP_MAX_SIZE, so this exercises the fallback allocation.
   sendfile: 2000B / offset=1000 — transfers larger than 
CONFIG_SENDFILE_BUFSIZE, so the buffer is reused across several iterations; the 
destination file is verified byte by byte, with and without the offset argument.
   sendfile: 200x — 200 consecutive get/put cycles, to catch a leaked pool slot 
or a double release tripping the DEBUGASSERT() in lib_put_tempbuffer().


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to