Comment 141 for bug 317781

Revision history for this message
Daniel Colascione (dcolascione) wrote :

@Arial

> No. If I overwrite a file the filesystem MUST guarantee that either the old version will be there or the new one.

Err, no it's perfectly fine for a filesystem to give you a zero-byte file if you truncate, then write over the truncated file. Why should the filesystem try to guess the future and hold off on that truncate? As long as the relative ordering of the truncate and write is preserved, you're fine.

Why is it okay for the filesystem to give you a zero-byte file between a truncate() and a write()? Because the filesystem gives you a facility for asking for an atomic commit instead: write to a scratch file and rename() that scratch file over the original. That's been the unix technique since time immemorial, and it works fine.

1. When you need neither atomicity nor durability, truncate() and write().
2. When you need atomicity but not durability, write() to a temporary and rename()
3. When you need both atomicity and durability, write() to a temporary, fsync the file, rename, and fsync the directory.
4. When you need just durability, truncate(), write(), and fsync().

The problem isn't a zero-length file in cases 1 and 4. That's an expected danger. You asked for those semantics but not using atomic rename, so you can deal with them.

The real insidious problem is getting a zero-byte file under scenarios 2 and 3. rename() on top of an existing file should *always* make sure the data blocks for the new file are committed before the record of the rename itself is. It's absolutely critical that this work correctly because there's no other good way of achieving atomicity.