Skip to content

drivers/mtd/filemtd: open the backing file O_RDWR - #20001

Open
AlmAck wants to merge 1 commit into
apache:masterfrom
AlmAck:fix/filemtd-open-rdwr
Open

drivers/mtd/filemtd: open the backing file O_RDWR#20001
AlmAck wants to merge 1 commit into
apache:masterfrom
AlmAck:fix/filemtd-open-rdwr

Conversation

@AlmAck

@AlmAck AlmAck commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Summary

filemtd_initialize() opens its backing file with

mode = O_RDONLY | O_WRONLY | O_CLOEXEC;

Commit 6161c73 ("include/fcntl.h: remove O_RDOK/O_WROK aliases")
introduced this when it replaced the non-standard O_RDOK | O_WROK
pair, describing the change as a pure text substitution. That held while
the access mode was a genuine bitmask: O_RDONLY was (1 << 0),
O_WRONLY was (1 << 1), O_RDWR was both bits, and O_ACCMODE was
defined as an alias for O_RDWR. OR-ing the two was meaningful and
produced O_RDWR.

Commit 9e141ac ("include/fcntl.h: align open flags with Linux
values") then made the low two bits an enumerationO_RDONLY 0,
O_WRONLY 1, O_RDWR 2 — and O_ACCMODE stopped being an alias for
O_RDWR, becoming an independent mask of 3. OR-ing two members of that
enumeration is no longer meaningful:

O_RDONLY | O_WRONLY  ==  0 | 1  ==  1
1 & O_ACCMODE        ==  O_WRONLY

The file is opened write-only, and fs/vfs/fs_read.c:202 rejects every
read on it with -EACCES.

Is this a pattern?

It looks like an isolated miss rather than a systematic one. Grepping
the tree:

  • Two access-mode constants OR-ed together — this call site only.
  • Bit-testing the mode instead of masking — one site,
    fs/xipfs/xipfs_vfs.c:606, which happens to be correct under the new
    values (and would have been wrong under the old ones, so it was
    clearly written after the change).
  • Unmasked equality against an access mode — none.
  • Host/guest translation — the NUTTX_O_* mirror in
    include/nuttx/fs/hostfs.h was updated in lockstep and
    host_oflags_convert() switches on flags & NUTTX_O_ACCMODE.

Impact

Affects every user of filemtd_initialize() — the simulator's
file-backed MTD, testing/fs, and any board that layers an MTD over a
file. Reads through the device fail, so any filesystem mounted on it
fails to come up.

On the simulator it surfaces as a LittleFS mount of a filemtd-backed
partition returning -ENOSPC, after which nothing that lives on that
volume works: the resource pack cannot be read, fonts load with zero
metrics, and a FlashDB partition on the same device logs out-of-bound
writes. None of those point at the open mode.

Testing

Evidence available (captured on this tree):

Host: Linux x86_64, GCC 15. Board: sim, configuration with a 4 MiB
file-backed MTD (filemtd_initialize) partitioned into an mtdconfig
partition, a LittleFS volume and a third raw partition.

Before, mounting the LittleFS volume on the filemtd partition:

sim_storage: mount /dev/rblflash -> /mnt/fs: errno 28
[E/FAL] (fal_partition_write:455) Partition write error! Partition address out of bound.
resource alloc of -1 bytes failed
GFont 0x40166fcc has line_height=0; falling back to default

After, same binary and same backing file, only this patch applied:

sim_storage: /dev/config + /dev/rblflash @/mnt/fs + /dev/rblflash_ts ready
             (fs 959 + tsdb 64 erase blks, 4096 B/erase blk)
seeded /mnt/fs/system.pbpack (147398 bytes)
pbpack table cached: 22 entries

The volume mounts, autoformat works, files read back, and the third
partition writes cleanly.

filemtd_initialize() opens its backing file with

  mode = O_RDONLY | O_WRONLY | O_CLOEXEC;

Commit 6161c73 introduced this when it replaced the non-standard
O_RDOK | O_WROK pair, describing the change as a pure text substitution.
That held while the access mode was a genuine bitmask: O_RDONLY was
(1 << 0), O_WRONLY was (1 << 1), and O_RDWR was both bits, so the OR
produced O_RDWR.  O_ACCMODE was defined as an alias for O_RDWR.

Commit 9e141ac then aligned the flags with Linux.  The low two bits
became an enumeration -- O_RDONLY 0, O_WRONLY 1, O_RDWR 2 -- and
O_ACCMODE stopped being an alias for O_RDWR and became an independent
mask of 3.  OR-ing two members of that enumeration is no longer
meaningful: O_RDONLY | O_WRONLY evaluates to 1, and masking it with
O_ACCMODE yields O_WRONLY.

The file is therefore opened write-only, and fs_read.c rejects every
read on it with -EACCES.  The failure does not name filemtd: on the
simulator it surfaces as a LittleFS mount of a filemtd-backed partition
returning -ENOSPC, after which nothing on that volume works.

This appears to be an isolated miss rather than a pattern.  Grepping the
tree for the same construct -- two access-mode constants OR-ed together
-- finds only this one call site.  The one remaining place that
bit-tests the mode, fs/xipfs/xipfs_vfs.c:606, happens to be correct
under the new values (and would have been wrong under the old ones).
The hostfs NUTTX_O_* mirror and host_oflags_convert() were updated in
lockstep and switch on the masked value.

Signed-off-by: AlmAck <gluca86@gmail.com>
@github-actions github-actions Bot added Area: Drivers Drivers issues Size: XS The size of the change in this PR is very small labels Aug 29, 2026
@github-actions

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: Drivers Drivers issues Size: XS The size of the change in this PR is very small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants