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.