This series stops the EFI file protocol Write() from cutting a FAT file
at the end of the written range. It is an RFC, mainly for the naming and
for the shape of the new interface.
The problem
-----------
fs_write() with an offset trims the file at offset + len. This was chosen
on purpose in commit cb8af8af5ba0 ("fs: fat: support write with non-zero
offset") to stay compatible with the fatwrite command, which replaces a
whole file. efi_file_write_int() uses fs_write(), so a write in the middle
of a file through EFI_FILE_PROTOCOL.Write() loses the data after it.
I found this with an EFI application that keeps a 256 MiB file on the
ESP and updates it in small pieces. With U-Boot 2025.01 on qemu_arm64 the
file went from 268435456 to 602112 bytes after one run. The code is the
same in current master (used for this submission).
What the specification and others do
------------------------------------
- UEFI 2.10, section 13.5.6, EFI_FILE_PROTOCOL.Write(): the data is
written at the current position, the file grows if required, and
partial writes only happen on a data error. Nothing allows a successful
Write() to drop data after the written range.
- The UEFI SCT checks it: BBTestWriteBasicTestCheckpoint1 in edk2-test
writes 50 bytes at position 0 of a 200 byte file and expects the size to
stay 200. I did not run SCT on U-Boot. By reading it, this case fails
today (and its set-up needs SetInfo() to change the file size, which
U-Boot refuses).
- EDK2's FAT driver (FatIFileAccess) only grows the file when a write goes
past the end.
So U-Boot's behaviour is surprising for EFI applications, and I believe
it is not conforming. I may be missing a reason for it, hence the RFC.
The series
----------
1. fs: fat: add a write that keeps the end of the file. The body of
file_fat_write_at() moves to a static function with a keep_tail flag.
file_fat_write_at() keeps its behaviour as a wrapper.
file_fat_overwrite() is the new entry point.
2. fs: add fs_overwrite(). It uses an optional overwrite() operation in
struct fstype_info. A filesystem without it falls back to write().
3. efi_loader: use fs_overwrite() in Write().
fs_write() and the fatwrite command do not change.
Questions
---------
- Naming: fs_overwrite() is what I chose. fs_write_inplace(),
fs_write_keep_tail() and fs_update() were also considered. Please
suggest a better one.
- exFAT has the same trim (exfat_fs_write() calls exfat_truncate() with
offset + size). ext4 refuses a non-zero offset and replaces the file at
offset 0. I did not touch them. Should exFAT get the same operation in
this series? A test for efi_selftest is not included yet.
Cedric Hombourger (3):
fs: fat: add a write that keeps the end of the file
fs: add fs_overwrite() to write without trimming the file
efi_loader: do not trim files in Write()
fs/fat/fat_write.c | 32 ++++++++++++++++++++++++--------
fs/fs.c | 25 ++++++++++++++++++++++---
include/fat.h | 2 ++
include/fs.h | 16 ++++++++++++++++
lib/efi_loader/efi_file.c | 4 ++--
5 files changed, 66 insertions(+), 13 deletions(-)
To: [email protected]
Cc: Tom Rini <[email protected]>
Cc: Cedric Hombourger <[email protected]>
Cc: Simon Glass <[email protected]>
Cc: Heinrich Schuchardt <[email protected]>
Cc: Qu Wenruo <[email protected]>
Cc: Alexey Charkov <[email protected]>
Cc: Kuan-Wei Chiu <[email protected]>
Cc: Vincent Jardin <[email protected]>
Cc: Ilias Apalodimas <[email protected]>
Cc: Neil Armstrong <[email protected]>
Cc: Jorge Ramirez-Ortiz <[email protected]>
--
2.47.3
Signed-off-by: Cedric Hombourger <[email protected]>
---
Changes in v2:
- EDITME: describe what is new in this series revision.
- EDITME: use bulletpoints and terse descriptions.
- Link to v1:
https://lore.kernel.org/r/[email protected]
---
Cedric Hombourger (3):
fs: fat: add a write that keeps the end of the file
fs: add fs_overwrite() to write without trimming the file
efi_loader: do not trim files in Write()
fs/fat/fat_write.c | 32 ++++++++++++++++++++++++--------
fs/fs.c | 25 ++++++++++++++++++++++---
include/fat.h | 2 ++
include/fs.h | 16 ++++++++++++++++
lib/efi_loader/efi_file.c | 4 ++--
5 files changed, 66 insertions(+), 13 deletions(-)
---
base-commit: 2203aabfa59826d04d9e2094c6b32c1029cd01f8
change-id: 20261026-fat-fs-fixes-c5eb444f1e63
prerequisite-change-id: 20261026-fat-fixes:v1
Best regards,
--
Cedric Hombourger <[email protected]>