On Saturday 22 April 2006 03:27, Vitaly Wool wrote:
> thanks! However I meant the following situation: suppose we've
> got 500k free, and we're trying to write a new version of 1M
> file (i. e. rewrite the old one). How will the filesystem
> handle this? I. e. will it refuse the write operation or grant
> it? If latter, what will happen if a power failure happens in
> the midst of the write (for instance, when 600k is written
> already -- there's not enough space to hold both the old and
> the new versions so how will the incomplete write be
> reverted?) OTOH, if there's enough space to hold both the old
> and the new versions, will the power pailure always be handled
> by the filesystem in such a way that retains the integrity of
> the file being written (i. e. either the old or the new
> version). I hope it will, but still being sure is better than
> thinking 'probably it will' :):)
A lot of what happens when you do this will depends more on the
UNIX/Posix filesystem calls than Yaffs.
If you hold the new data in memory, and open the old file with
O_TRUNC, then write out the update, then the old data is 'lost'
from the filesystem on the open(2) call. This frees the storage,
so it can be used to hold new data; but leaves you with a big
window without data.
Under the covers a large write is the same as a sequence of
smaller writes, and Yaffs performs the write operation in chunk
(nand-page) sized steps.
An update that over-writes the existing file, without O_TRUNC,
will replace the old chunks (nand-pages) with new ones,
containing the updated data (one-by-one in a sequence). If Yaffs
runs low on chunks, the garbage collector will erase a block
that contained old data. This gets us to the question of
'reserve', and perhaps Charles can tell us how the reserve is
managed. I can imagine getting into a corner, when performing
an update such as this, where there is insufficient 'elbow' room
for the garbage collector to free up a complete block. In which
case, somewhere along the sequence of chunk/page writes, it will
fail and return a partial write (large buffer) or a failed write
(small buffer). Now you are left with new data at the start of
the file and old data at the end. Perhaps this is OK for your
application(?).
On Unix, the semantics of rename(2) help solve this common
problem. Write out the new data to a new file (requiring twice
the NAND space in the process); close the old file; then rename
new file to the name of the old file. If rename(2) fails to
fully complete (due to powerdown for example), you either have
two files, the old and the new; or you have the new, and the old
one is found in lost+found (unless it had multiple links). If
rename(2) succeeds, the new file takes the place of old, the old
file is unlinked and its storage is released ready for the
garbage collector to gobble up. The application will need to
'reopen' the new file.
-imcd