Incidentally, this is the way it currently is. From rename(2): If "newpath already exists, it will be atomically replaced".
Just don't forget that "replacing" means to create a _new_ file, writing it, syncing it, and then replacing the old version with rename(2) (and fsyncing the directory).
> - "Temp" files always go away completely after a crash. This should be the default for designated temp directories.
You can have that: Just don't link the inode of the file. On Linux, you can use O_TMPFILE. Alternatively, just create the file, and keep it open but immediately unlink it (it's a little hack but nothing dramatic).
You can also write to /tmp. Normally that gets cleaned at reboot, which might be enough.
> - "Log" files can only be appended.
In open(2), look for O_APPEND.
> Writers cannot seek.
That's not how you write a kernel API. If you don't want to seek, then don't.
> The file system guarantees that after a crash, the end of the file is at the end of some write
How do you intend to implement that? Disks don't support arbitrarily large atomic commits. Making such a guarantee in software is necessarily inefficient. The kernel will not choose your tradeoffs for you. You can do it from userland. Decide yourself what is the least bad way to do it.
> "Managed" files are for structured databases. [..] The writer gets a callback when the write has committed to disk. The file system must guarantee that a write for which the callback has been made will survive a crash.
Fsync does just that, except it isn't asynchronous. Maybe there's something behind aio(7)?