Journaling filesystems
The more modern approach is to use what's called a journal to improve this situation. A fully journaled write would look like this:
- Write transaction start metadata to the journal.
- Write used space metadata change to the journal.
- Write data block change to the journal.
- Write file metadata change to the journal.
- Add data block to the list of used space metadata.
- Write data block.
- Write file metadata referencing use of that block.
- Write transaction end metadata to the journal.
What this gets you is the ability to recover from any sort of crash the filesystem might encounter. If you didn't reach the final step here for a given write transaction, the filesystem can just either ignore (data block write) or undo (metadata write) any partially completed work that's part of that transaction. This lets you avoid long filesystem consistency checks after a crash, because you'll just need to replay any open journal entries to fix all the filesystem...