[PATCH V12 06/12] famfs: Introduce mmap and VM fault handling

From: John Groves

Date: Sun Aug 02 2026 - 22:33:09 EST


From: John Groves <john@xxxxxxxxxx>

This commit adds vm_operations, plus famfs_mmap() and fault handlers.
It is still missing iomap_ops, iomap mapping resolution, and
famfs_ioctl() for setting up file-to-memory mappings.

Signed-off-by: John Groves <john@xxxxxxxxxx>
---
fs/famfs/famfs_file.c | 101 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 100 insertions(+), 1 deletion(-)

diff --git a/fs/famfs/famfs_file.c b/fs/famfs/famfs_file.c
index e192b573c51f..678f2035fd5f 100644
--- a/fs/famfs/famfs_file.c
+++ b/fs/famfs/famfs_file.c
@@ -16,6 +16,75 @@

#include "famfs_internal.h"

+/*********************************************************************
+ * vm_operations
+ */
+static vm_fault_t
+__famfs_filemap_fault(struct vm_fault *vmf, unsigned int order,
+ bool write_fault)
+{
+ struct inode *inode = file_inode(vmf->vma->vm_file);
+ struct super_block *sb = inode->i_sb;
+ struct famfs_fs_info *fsi = sb->s_fs_info;
+ vm_fault_t ret;
+ unsigned long pfn;
+
+ if (fsi->deverror)
+ return VM_FAULT_SIGBUS;
+
+ if (!IS_DAX(file_inode(vmf->vma->vm_file))) {
+ pr_err("%s: file not marked IS_DAX!!\n", __func__);
+ return VM_FAULT_SIGBUS;
+ }
+
+ if (write_fault) {
+ sb_start_pagefault(inode->i_sb);
+ file_update_time(vmf->vma->vm_file);
+ }
+
+ ret = dax_iomap_fault(vmf, order, &pfn, NULL, NULL /*&famfs_iomap_ops */);
+ if (ret & VM_FAULT_NEEDDSYNC)
+ ret = dax_finish_sync_fault(vmf, order, pfn);
+
+ if (write_fault)
+ sb_end_pagefault(inode->i_sb);
+
+ return ret;
+}
+
+static inline bool
+famfs_is_write_fault(struct vm_fault *vmf)
+{
+ return (vmf->flags & FAULT_FLAG_WRITE) &&
+ (vmf->vma->vm_flags & VM_SHARED);
+}
+
+static vm_fault_t
+famfs_filemap_fault(struct vm_fault *vmf)
+{
+ return __famfs_filemap_fault(vmf, 0, famfs_is_write_fault(vmf));
+}
+
+static vm_fault_t
+famfs_filemap_huge_fault(struct vm_fault *vmf, unsigned int order)
+{
+ return __famfs_filemap_fault(vmf, order, famfs_is_write_fault(vmf));
+}
+
+static vm_fault_t
+famfs_filemap_mkwrite(struct vm_fault *vmf)
+{
+ return __famfs_filemap_fault(vmf, 0, true);
+}
+
+const struct vm_operations_struct famfs_file_vm_ops = {
+ .fault = famfs_filemap_fault,
+ .huge_fault = famfs_filemap_huge_fault,
+ .map_pages = filemap_map_pages,
+ .page_mkwrite = famfs_filemap_mkwrite,
+ .pfn_mkwrite = famfs_filemap_mkwrite,
+};
+
/*********************************************************************
* file_operations
*/
@@ -117,6 +186,36 @@ famfs_dax_write_iter(struct kiocb *iocb, struct iov_iter *from)
return rc;
}

+static int
+famfs_file_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct inode *inode = file_inode(file);
+ struct super_block *sb = inode->i_sb;
+ struct famfs_fs_info *fsi = sb->s_fs_info;
+ ssize_t rc;
+
+ if (fsi->deverror)
+ return -ENODEV;
+
+ /*
+ * Gate shared-writable mappings on FAMFS_OPT_WRITE. This is best
+ * effort: clearing the bit blocks new writable mappings and write(),
+ * but does not revoke mappings that already exist.
+ */
+ if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_WRITE) &&
+ !famfs_opt_enabled(fsi, FAMFS_OPT_WRITE))
+ return -EPERM;
+
+ rc = famfs_file_invalid(inode);
+ if (rc)
+ return (int)rc;
+
+ file_accessed(file);
+ vma->vm_ops = &famfs_file_vm_ops;
+ vm_flags_set(vma, VM_HUGEPAGE);
+ return 0;
+}
+
const struct file_operations famfs_file_operations = {
.owner = THIS_MODULE,

@@ -124,7 +223,7 @@ const struct file_operations famfs_file_operations = {
.write_iter = famfs_dax_write_iter,
.read_iter = famfs_dax_read_iter,
.unlocked_ioctl = NULL /*famfs_file_ioctl*/,
- .mmap = NULL /* famfs_file_mmap */,
+ .mmap = famfs_file_mmap,

/* Force PMD alignment for mmap */
.get_unmapped_area = thp_get_unmapped_area,
--
2.53.0