You (or some other code block) needs to look at how the memory pages are marked in the TLB system.
One way is to mark the page read only then on a write handle the
exception validate the writer and mark the page writable for that context.
Then mark a bit that the page needs to be pushed to disk.
Filesystem code also flows through code that can mark it as dirty and
needing to be pushed to media. Since some file writes are well managed
with exclusion flags at the open some things get easy.
Assumptions can be made as well on the last close and push any
page in memory back to disk.
It is possible for user space file system code to do bookkeeping and
tell the OS that pages have been modified. i.e. the content of the file
belong to user space. Meta data and the block list for the file belong
to the protected code in the kernel.
Without a TLB protection and exception there is no way to "know" and
other code must do the book keeping.
Big cautions about multi processor, multi user, access control lists,
files with holes (blocks of NULL) and as always meta data including
extended meta data. Least I forget filesystem design is difficult.