The whole idea of system calls being expensive is obsolete now that we're not using heavyweight software interrupts to implement them.
What the fuck do you think happens when you write to a mmap(2)ed page anyway? The kernel has to know the page is dirty somehow so that it can remember to flush it later. It learns about page dirtying by initially mapping the page read-only, letting the CPU fault when you try to write, marking the page dirty, and letting the write proceed.
You're entering the kernel either way.
In the vast majority of cases, you want plain read and write. In the vast majority of cases, the overhead of jumping into the kernel is not your bottleneck. Simplicity counts for a lot.
The reason LMDB can pack so much functionality into only 7KLOCs is because using mmap is much simpler than using read() and maintaining a user-level buffer cache.
In the vast majority of cases, developers need to profile their code if they actually care about performance - and fail to do so.