U-Boot sf update: A Partial Sector Uses Read-Modify-Write, Not a Small Physical Write
A short sf update can cause an entire erase sector to be
rewritten. In U-Boot v2025.01, the command compares the requested bytes
but reads a full sector and, when those bytes differ, performs
sector-sized erase and write operations. Its byte statistics describe
requested content, not all physical work.
This analysis is deliberately limited to an erase-sector-aligned
starting offset and the tagged SPI-flash command implementation. It does
not qualify unaligned offsets, every flash driver’s erase geometry,
power-loss recovery or a particular storage device.
Resolve the
documentation and code difference
The sf
command guide describes sector-by-sector comparison and skipping.
Its update paragraph also says that the unused tail of a final partial
sector will be erased.
The v2025.01
implementation is more specific and differs on that tail behavior.
spi_flash_update_block() reads the complete sector into a
comparison buffer. If the requested slice differs, it merges the new
slice into that buffer for a partial-sector operation, then writes a
complete sector.
Under the stated aligned-offset scope and successful operations, the
bytes beyond the requested final slice come from the original sector
snapshot. They are not deliberately replaced with erased bytes by this
helper. Do not repeat the guide’s tail statement as the observed
behavior of this exact source path.

Compare the
requested slice, not the whole sector
The helper reads the sector first, but its equality comparison covers
only the requested length at the relevant in-sector offset. If those
bytes match, it adds that length to the skipped count and avoids
erase/write for that chunk.
This is a local update optimization. It says nothing about whether
bytes outside the requested slice contain an approved value. A
successful skip cannot establish the identity of the entire sector or of
a larger firmware artifact.
The surrounding loop splits the requested range into chunks ending at
sector boundaries. It allocates one sector-sized comparison buffer. A
buffer-allocation failure and read, erase or write errors are reported
as different failing steps, which helps distinguish resource failure
from a device operation failure.
A tiny change
still shares an erase boundary
For a partial final chunk that needs changing, the original
full-sector snapshot supplies the untouched tail. The helper erases the
sector, copies the new slice into that snapshot, and writes the full
sector back.
This makes preservation dependent on completing a
read-modify-erase-write sequence. If power is lost after erase but
before the complete write, bytes outside the requested slice can also be
affected. The helper does not make independently owned records in one
sector into independent atomic updates.
Preserve the entire erase-sector ownership map when reviewing an
update region. A byte-range permission or image length does not reduce
the physical erase boundary. If unrelated critical data shares that
boundary, the product needs an explicit storage design and recovery
contract rather than relying on the helper’s normal-success tail
preservation.
Interpret the
counters and verify the result
The final written count is requested length minus skipped length. A
one-byte difference can cause a full-sector rewrite while the output
attributes only the requested chunk length to bytes written. The speed
calculation also uses requested length. Neither counter is a direct
measurement of physical flash program traffic, erase count or wear.
The helper checks the flash-operation return values but does not
perform a final independent readback comparison after each write. For
qualification, use disposable media with known tail bytes, a matching
requested slice, a changed slice and injected operation failures.
Compare the whole affected sector afterward, keeping logical counters
separate from physical-operation traces.
No erase, write, endurance test or readback was executed for this
article. The verified mechanism is a requested-slice comparison
followed, when necessary, by a full-sector update. Its useful
optimization and its larger failure boundary should be documented
together.