3.4 KiB
B6J2 — rmtfs v1.3 source audit: RAM shadow lifetime with rmtfs -r -P -v (no -s)
Source: linux/initramfs-modem1/dl/rmtfs-src = git tag v1.3 (b30a3eb). Board binary: Alpine rmtfs 1.3-r0 (aports commit 1628fd4c),
sha256 1bf6b195… (same in initramfs-mm1); v1.3-specific strings present ("write to %zd bytes exceededs max size", "[RMTFS] bye from %d").
Data structures (storage.c)
static struct rmtfd rmtfds[MAX_CALLERS=10]— process-global static array; each slot:id,node,fd,partition,shadow_buf,shadow_len.storage_read_only(= -r) is a process-global flag set once instorage_init().storage_init()is called exactly once inmain()(rmtfs.c:575) and only initialises slots to fd=-1 / shadow_buf=NULL.
open/read path
- QMI OPEN (rmtfs.c:55
rmtfs_open) →storage_open(pkt->node, path)(storage.c:112). - storage.c:131-137: if a slot with
(fd != -1 || shadow_buf) && node == node && partition == partexists, that slot is returned as-is — noopen(), noread()of the partition. - Only for a free slot:
fd_open()→ with -rstorage_populate_shadow_buf()(storage.c:280): open(O_RDONLY) the by-partlabel device,calloc(len), oneread()of the whole partition intoshadow_buf, close the fd. This is the only place the backing partition is read.
request handling
- RW_IOVEC read →
storage_pread(): with -r, memcpy fromshadow_buf(storage.c:228-231). - RW_IOVEC write →
storage_pwrite(): with -r, memcpy intoshadow_buf(realloc if it grows), never touches the fd (storage.c:247-267);storage_sync()is a no-op with -r (storage.c:274). - QMI CLOSE →
storage_close()→free(shadow_buf)(storage.c:176-188). This andstorage_exit()(process exit) are the ONLY frees.
reconnect behaviour (MSS stop/start while rmtfs lives)
- QRTR BYE (
rmtfs_bye) and DEL_CLIENT (rmtfs_del_client) handlers only dbgprintf and return 0 (rmtfs.c:346-358): nothing is closed or freed. - ENETRESET on the QRTR socket:
main()loopsdo { run_rmtfs() } while (ret == -ENETRESET)(rmtfs.c:581-583);run_rmtfsonly re-opens/re-publishes the socket;storage_init/exitare outside the loop → shadows survive. - Without -s:
rprocfd = -1→ rmtfs never writes remoteproc state; SIGTERM → loopbreak→storage_exit()→ process exits (rmtfs.c:453-455). - The modem on this board never sends QMI CLOSE: session-28 rmtfs.log (11 MSS boots) has 0 "close" lines; each MSS stop shows only
del_client+bye from 0. The next MSS boot re-opens the same 4 paths from the same node 0 and gets the same caller ids 0..3.
Answer
With a single long-lived rmtfs -r -P -v process, a modem_fs1/fs2/fsg/fsc write received from MSS stays in that slot's shadow_buf
for the lifetime of the process, and a later MSS boot (same node, no CLOSE) is served from that modified RAM copy — the backing
partitions are NOT re-read on MSS reconnect. They are re-read only by a new rmtfs process (or after an explicit QMI CLOSE, which this
modem does not send). The old B6 flow started a new rmtfs per cycle, so every MSS boot saw the on-disk EFS image.
→ GO for B6J3.
Caveats: (1) a hypothetical CLOSE from the modem would free the shadow (debug printf in rmtfs_close also passes an int for %s —
would be UB with -v); not observed. (2) The shadow is only the EFS part of the modem's persistent state; USIM files (EF_EPSLOCI etc.)
persist across MSS restarts in both flows.