[PATCH V11 6/9] famfs_fuse: Plumb dax iomap and fuse read/write/mmap
John Groves <[email protected]> Mon, 20 Jul 2026 03:46:24 +0000
| Newsgroups | dev.linux.lists.fuse-devel,dev.linux.lists.nvdimm,org.kernel.vger.linux-cxl,org.kernel.vger.linux-doc,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <0100019f7da1cf3d-bb04c043-a09f-4925-bf63-eb92452871e5-000000@email.amazonses.com> |
From: John Groves <[email protected]>=0D=0A=0D=0AFill in read/write/mmap ha= ndling for famfs files using the dev_dax_iomap=0D=0Ainterface, the same p= ath xfs uses in fs-dax mode.=0D=0A=0D=0A- Read/write go through famfs_fus= e_[read|write]_iter() via dax_iomap_rw()=0D=0A to fsdev_dax.=0D=0A- Mmap= is handled by famfs_fuse_mmap().=0D=0A- Faults are handled by famfs_file= map_fault() via dax_iomap_fault() to=0D=0A fsdev_dax.=0D=0A- File-offset= -to-dax-offset resolution is handled by=0D=0A famfs_fuse_iomap_begin(), = which uses the file's fmap to resolve a=0D=0A (file, offset) to an offse= t on a dax device via=0D=0A famfs_fileofs_to_daxofs().=0D=0A=0D=0ASigned= -off-by: John Groves <[email protected]>=0D=0A---=0D=0A fs/fuse/famfs.c | = 337 ++++++++++++++++++++++++++++++++++++++++++++++-=0D=0A fs/fuse/file.c = | 18 ++-=0D=0A fs/fuse/fuse_i.h | 19 +++=0D=0A 3 files changed, 371 i= nsertions(+), 3 deletions(-)=0D=0A=0D=0Adiff --git a/fs/fuse/famfs.c b/fs= /fuse/famfs.c=0D=0Aindex a2a7dd631dc0..ac56317944d9 100644=0D=0A--- a/fs/= fuse/famfs.c=0D=0A+++ b/fs/fuse/famfs.c=0D=0A@@ -580,7 +580,342 @@ famfs_= file_init_dax(=0D=0A =09return rc;=0D=0A }=0D=0A=20=0D=0A-#define FMAP_BU= FSIZE PAGE_SIZE=0D=0A+/**************************************************= *******************=0D=0A+ * iomap_operations=0D=0A+ *=0D=0A+ * This stuf= f uses the iomap (dax-related) helpers to resolve file offsets to=0D=0A+ = * offsets within a dax device.=0D=0A+ */=0D=0A+=0D=0A+static int famfs_fi= le_bad(struct inode *inode);=0D=0A+=0D=0A+/**=0D=0A+ * famfs_fileofs_to_d= axofs() - Resolve (file, offset, len) to (daxdev, offset, len)=0D=0A+ *=0D= =0A+ * This function is called by famfs_fuse_iomap_begin() to resolve an = offset in a=0D=0A+ * file to an offset in a dax device. This is upcalled = from dax from calls to=0D=0A+ * both * dax_iomap_fault() and dax_iomap_r= w(). Dax finishes the job resolving=0D=0A+ * a fault to a specific physic= al page (the fault case) or doing a memcpy=0D=0A+ * variant (the rw case)= =0D=0A+ *=0D=0A+ * Pages can be PTE (4k), PMD (2MiB) or (theoretically) P= uD (1GiB)=0D=0A+ * (these sizes are for X86; may vary on other cpu archit= ectures=0D=0A+ *=0D=0A+ * @inode: The file where the fault occurred=0D=0A= + * @iomap: To be filled in to indicate where to find the right mem= ory,=0D=0A+ * relative to a dax device.=0D=0A+ * @file_off= set: Within the file where the fault occurred (will be page boundary)=0D=0A= + * @len: The length of the faulted mapping (will be a page multi= ple)=0D=0A+ * (will be trimmed in *iomap if it's disjoint i= n the extent list)=0D=0A+ * @flags: flags passed to famfs_fuse_ioma= p_begin(), and sent back via=0D=0A+ * struct iomap=0D=0A+ *= =0D=0A+ * Return values: 0 on success, with the result in the modified @i= omap struct.=0D=0A+ * -EIO if (file_offset, len) cannot be= resolved to a dax extent,=0D=0A+ * which includes access = past EOF (the caller turns this into a=0D=0A+ * short read= /write or a SIGBUS).=0D=0A+ */=0D=0A+static int=0D=0A+famfs_fileofs_to_da= xofs(struct inode *inode, struct iomap *iomap,=0D=0A+=09=09=09loff_t file= _offset, off_t len, unsigned int flags)=0D=0A+{=0D=0A+=09struct fuse_inod= e *fi =3D get_fuse_inode(inode);=0D=0A+=09struct famfs_file_meta *meta =3D= fi->famfs_meta;=0D=0A+=09struct fuse_conn *fc =3D get_fuse_conn(inode);=0D= =0A+=09loff_t local_offset =3D file_offset;=0D=0A+=09u64 i;=0D=0A+=0D=0A+= =09if (!fc->dax_devlist) {=0D=0A+=09=09pr_err("%s: null dax_devlist\n", _= _func__);=0D=0A+=09=09goto err_out;=0D=0A+=09}=0D=0A+=0D=0A+=09if (famfs_= file_bad(inode))=0D=0A+=09=09goto err_out;=0D=0A+=0D=0A+=09iomap->offset = =3D file_offset;=0D=0A+=0D=0A+=09if (meta->ext_shift) {=0D=0A+=09=09/*=0D= =0A+=09=09 * Uniform extent size (detected at parse time): the containing= =0D=0A+=09=09 * extent index is a shift of the file offset, so resolve in= =0D=0A+=09=09 * O(1) instead of walking the extent list.=0D=0A+=09=09 */=0D= =0A+=09=09u64 ext_size =3D 1ULL << meta->ext_shift;=0D=0A+=0D=0A+=09=09i = =3D file_offset >> meta->ext_shift;=0D=0A+=09=09local_offset =3D file_off= set & (ext_size - 1);=0D=0A+=09} else {=0D=0A+=09=09/* Single extent or n= on-uniform list: walk it */=0D=0A+=09=09for (i =3D 0; i < meta->fm_nexten= ts; i++) {=0D=0A+=09=09=09if (local_offset < meta->se[i].ext_len)=0D=0A+=09= =09=09=09break;=0D=0A+=09=09=09local_offset -=3D meta->se[i].ext_len;=0D=0A= +=09=09}=0D=0A+=09}=0D=0A+=0D=0A+=09/* local_offset is now the offset wit= hin extent i (if i is in range) */=0D=0A+=09if (i < meta->fm_nextents && = local_offset < meta->se[i].ext_len) {=0D=0A+=09=09loff_t dax_ext_offset = =3D meta->se[i].ext_offset;=0D=0A+=09=09loff_t dax_ext_len =3D me= ta->se[i].ext_len;=0D=0A+=09=09u64 daxdev_idx =3D meta->se[i].d= ev_index;=0D=0A+=09=09loff_t ext_len_remainder =3D dax_ext_len - local_of= fset;=0D=0A+=09=09struct famfs_daxdev *dd;=0D=0A+=0D=0A+=09=09if (daxdev_= idx >=3D fc->dax_devlist->nslots) {=0D=0A+=09=09=09pr_err("%s: daxdev_idx= %llu >=3D nslots %d\n",=0D=0A+=09=09=09 __func__, daxdev_idx, fc->= dax_devlist->nslots);=0D=0A+=09=09=09goto err_out;=0D=0A+=09=09}=0D=0A+=0D= =0A+=09=09dd =3D &fc->dax_devlist->devlist[daxdev_idx];=0D=0A+=0D=0A+=09=09= iomap->addr =3D dax_ext_offset + local_offset;=0D=0A+=09=09iomap->offs= et =3D file_offset;=0D=0A+=09=09iomap->length =3D min_t(loff_t, len, ex= t_len_remainder);=0D=0A+=09=09iomap->dax_dev =3D dd->devp;=0D=0A+=09=09io= map->type =3D IOMAP_MAPPED;=0D=0A+=09=09iomap->flags =3D flags;=0D=0A= +=09=09return 0;=0D=0A+=09}=0D=0A+=0D=0A+ err_out:=0D=0A+=09/*=0D=0A+=09 = * We fell out the end of the extent list, i.e. the access is past EOF.=0D= =0A+=09 * This is a normal, unprivileged-reachable condition (e.g. a faul= t in=0D=0A+=09 * the tail of a mapping that extends past EOF), so log at = debug level.=0D=0A+=09 * The specific error cases above (null dax_devlist= , bad daxdev index)=0D=0A+=09 * have already logged at error level before= jumping here.=0D=0A+=09 */=0D=0A+=09pr_debug("%s: could not resolve file= _offset %lld (past EOF=3F)\n",=0D=0A+=09=09 __func__, (long long)file_off= set);=0D=0A+=0D=0A+=09/*=0D=0A+=09 * Return a zero-length mapping and -EI= O. dax turns this into a short=0D=0A+=09 * read/write or a SIGBUS rather = than touching dax memory.=0D=0A+=09 */=0D=0A+=09iomap->addr =3D 0; /* = there is no valid dax device offset */=0D=0A+=09iomap->offset =3D file_o= ffset; /* file offset */=0D=0A+=09iomap->length =3D 0; /* this had bette= r result in no access to dax mem */=0D=0A+=09iomap->dax_dev =3D NULL;=0D=0A= +=09iomap->type =3D IOMAP_MAPPED;=0D=0A+=09iomap->flags =3D flags;=0D= =0A+=0D=0A+=09return -EIO;=0D=0A+}=0D=0A+=0D=0A+/**=0D=0A+ * famfs_fuse_i= omap_begin() - Handler for iomap_begin upcall from dax=0D=0A+ *=0D=0A+ * = This function is pretty simple because files are=0D=0A+ * * never partial= ly allocated=0D=0A+ * * never have holes (never sparse)=0D=0A+ * * never = "allocate on write"=0D=0A+ *=0D=0A+ * @inode: inode for the file being a= ccessed=0D=0A+ * @offset: offset within the file=0D=0A+ * @length: Length= being accessed at offset=0D=0A+ * @flags: flags to be retured via struc= t iomap=0D=0A+ * @iomap: iomap struct to be filled in, resolving (offset= , length) to=0D=0A+ * (daxdev, offset, len)=0D=0A+ * @srcmap: so= urce mapping if it is a COW operation (which it is not here)=0D=0A+ */=0D= =0A+static int=0D=0A+famfs_fuse_iomap_begin(struct inode *inode, loff_t o= ffset, loff_t length,=0D=0A+=09=09 unsigned int flags, struct iomap *iom= ap, struct iomap *srcmap)=0D=0A+{=0D=0A+=09return famfs_fileofs_to_daxofs= (inode, iomap, offset, length, flags);=0D=0A+}=0D=0A+=0D=0A+/* Note: We n= ever need a special set of write_iomap_ops because famfs never=0D=0A+ * p= erforms allocation on write.=0D=0A+ */=0D=0A+const struct iomap_ops famfs= _iomap_ops =3D {=0D=0A+=09.iomap_begin=09=09=3D famfs_fuse_iomap_begin,=0D= =0A+};=0D=0A+=0D=0A+/****************************************************= *****************=0D=0A+ * vm_operations=0D=0A+ */=0D=0A+static vm_fault_= t=0D=0A+__famfs_fuse_filemap_fault(struct vm_fault *vmf, unsigned int ord= er,=0D=0A+=09=09 bool write_fault)=0D=0A+{=0D=0A+=09struct inode *in= ode =3D file_inode(vmf->vma->vm_file);=0D=0A+=09vm_fault_t ret;=0D=0A+=09= unsigned long pfn;=0D=0A+=0D=0A+=09if (!IS_DAX(file_inode(vmf->vma->vm_fi= le))) {=0D=0A+=09=09pr_err("%s: file not marked IS_DAX!!\n", __func__);=0D= =0A+=09=09return VM_FAULT_SIGBUS;=0D=0A+=09}=0D=0A+=0D=0A+=09if (write_fa= ult) {=0D=0A+=09=09sb_start_pagefault(inode->i_sb);=0D=0A+=09=09file_upda= te_time(vmf->vma->vm_file);=0D=0A+=09}=0D=0A+=0D=0A+=09ret =3D dax_iomap_= fault(vmf, order, &pfn, NULL, &famfs_iomap_ops);=0D=0A+=09if (ret & VM_FA= ULT_NEEDDSYNC)=0D=0A+=09=09ret =3D dax_finish_sync_fault(vmf, order, pfn)= ;=0D=0A+=0D=0A+=09if (write_fault)=0D=0A+=09=09sb_end_pagefault(inode->i_= sb);=0D=0A+=0D=0A+=09return ret;=0D=0A+}=0D=0A+=0D=0A+static inline bool=0D= =0A+famfs_is_write_fault(struct vm_fault *vmf)=0D=0A+{=0D=0A+=09return (v= mf->flags & FAULT_FLAG_WRITE) &&=0D=0A+=09 (vmf->vma->vm_flags & VM= _SHARED);=0D=0A+}=0D=0A+=0D=0A+static vm_fault_t=0D=0A+famfs_filemap_faul= t(struct vm_fault *vmf)=0D=0A+{=0D=0A+=09return __famfs_fuse_filemap_faul= t(vmf, 0, famfs_is_write_fault(vmf));=0D=0A+}=0D=0A+=0D=0A+static vm_faul= t_t=0D=0A+famfs_filemap_huge_fault(struct vm_fault *vmf, unsigned int ord= er)=0D=0A+{=0D=0A+=09return __famfs_fuse_filemap_fault(vmf, order,=0D=0A+= =09=09=09=09famfs_is_write_fault(vmf));=0D=0A+}=0D=0A+=0D=0A+static vm_fa= ult_t=0D=0A+famfs_filemap_mkwrite(struct vm_fault *vmf)=0D=0A+{=0D=0A+=09= return __famfs_fuse_filemap_fault(vmf, 0, true);=0D=0A+}=0D=0A+=0D=0A+con= st struct vm_operations_struct famfs_file_vm_ops =3D {=0D=0A+=09.fault=09= =09=3D famfs_filemap_fault,=0D=0A+=09.huge_fault=09=3D famfs_filemap_huge= _fault,=0D=0A+=09.map_pages=09=3D filemap_map_pages,=0D=0A+=09.page_mkwri= te=09=3D famfs_filemap_mkwrite,=0D=0A+=09.pfn_mkwrite=09=3D famfs_filemap= _mkwrite,=0D=0A+};=0D=0A+=0D=0A+/****************************************= *****************************=0D=0A+ * file_operations=0D=0A+ */=0D=0A+=0D= =0A+/**=0D=0A+ * famfs_file_bad() - Check for files that aren't in a vali= d state=0D=0A+ *=0D=0A+ * @inode: inode=0D=0A+ *=0D=0A+ * Returns: 0=3Dsu= ccess=0D=0A+ * -errno=3Dfailure=0D=0A+ */=0D=0A+static int=0D=0A= +famfs_file_bad(struct inode *inode)=0D=0A+{=0D=0A+=09struct fuse_inode *= fi =3D get_fuse_inode(inode);=0D=0A+=09struct famfs_file_meta *meta =3D f= i->famfs_meta;=0D=0A+=09size_t i_size =3D i_size_read(inode);=0D=0A+=0D=0A= +=09if (!meta) {=0D=0A+=09=09pr_err("%s: un-initialized famfs file\n", __= func__);=0D=0A+=09=09return -EIO;=0D=0A+=09}=0D=0A+=09if (meta->error) {=0D= =0A+=09=09pr_debug("%s: previously detected metadata errors\n", __func__)= ;=0D=0A+=09=09return -EIO;=0D=0A+=09}=0D=0A+=09if (i_size !=3D meta->file= _size) {=0D=0A+=09=09pr_warn("%s: i_size overwritten from %ld to %ld\n",=0D= =0A+=09=09 __func__, meta->file_size, i_size);=0D=0A+=09=09meta->er= ror =3D true;=0D=0A+=09=09return -ENXIO;=0D=0A+=09}=0D=0A+=09if (!IS_DAX(= inode)) {=0D=0A+=09=09pr_debug("%s: inode %llx IS_DAX is false\n",=0D=0A+= =09=09=09 __func__, (u64)inode);=0D=0A+=09=09return -ENXIO;=0D=0A+=09}=0D= =0A+=09return 0;=0D=0A+}=0D=0A+=0D=0A+static ssize_t=0D=0A+famfs_fuse_rw_= prep(struct kiocb *iocb, struct iov_iter *ubuf)=0D=0A+{=0D=0A+=09struct i= node *inode =3D iocb->ki_filp->f_mapping->host;=0D=0A+=09size_t i_size =3D= i_size_read(inode);=0D=0A+=09size_t count =3D iov_iter_count(ubuf);=0D=0A= +=09size_t max_count;=0D=0A+=09ssize_t rc;=0D=0A+=0D=0A+=09rc =3D famfs_f= ile_bad(inode);=0D=0A+=09if (rc)=0D=0A+=09=09return (ssize_t)rc;=0D=0A+=0D= =0A+=09/* Avoid unsigned underflow if position is past EOF */=0D=0A+=09if= (iocb->ki_pos >=3D i_size)=0D=0A+=09=09max_count =3D 0;=0D=0A+=09else=0D= =0A+=09=09max_count =3D i_size - iocb->ki_pos;=0D=0A+=0D=0A+=09if (count = > max_count)=0D=0A+=09=09iov_iter_truncate(ubuf, max_count);=0D=0A+=0D=0A= +=09if (!iov_iter_count(ubuf))=0D=0A+=09=09return 0;=0D=0A+=0D=0A+=09retu= rn rc;=0D=0A+}=0D=0A+=0D=0A+ssize_t=0D=0A+famfs_fuse_read_iter(struct kio= cb *iocb, struct iov_iter=09*to)=0D=0A+{=0D=0A+=09ssize_t rc;=0D=0A+=0D=0A= +=09rc =3D famfs_fuse_rw_prep(iocb, to);=0D=0A+=09if (rc)=0D=0A+=09=09ret= urn rc;=0D=0A+=0D=0A+=09if (!iov_iter_count(to))=0D=0A+=09=09return 0;=0D= =0A+=0D=0A+=09rc =3D dax_iomap_rw(iocb, to, &famfs_iomap_ops);=0D=0A+=0D=0A= +=09file_accessed(iocb->ki_filp);=0D=0A+=09return rc;=0D=0A+}=0D=0A+=0D=0A= +ssize_t=0D=0A+famfs_fuse_write_iter(struct kiocb *iocb, struct iov_iter = *from)=0D=0A+{=0D=0A+=09ssize_t rc;=0D=0A+=0D=0A+=09rc =3D famfs_fuse_rw_= prep(iocb, from);=0D=0A+=09if (rc)=0D=0A+=09=09return rc;=0D=0A+=0D=0A+=09= if (!iov_iter_count(from))=0D=0A+=09=09return 0;=0D=0A+=0D=0A+=09return d= ax_iomap_rw(iocb, from, &famfs_iomap_ops);=0D=0A+}=0D=0A+=0D=0A+int=0D=0A= +famfs_fuse_mmap(struct file *file, struct vm_area_struct *vma)=0D=0A+{=0D= =0A+=09struct inode *inode =3D file_inode(file);=0D=0A+=09ssize_t rc;=0D=0A= +=0D=0A+=09rc =3D famfs_file_bad(inode);=0D=0A+=09if (rc)=0D=0A+=09=09ret= urn rc;=0D=0A+=0D=0A+=09file_accessed(file);=0D=0A+=09vma->vm_ops =3D &fa= mfs_file_vm_ops;=0D=0A+=09vm_flags_set(vma, VM_HUGEPAGE);=0D=0A+=09return= 0;=0D=0A+}=0D=0A=20=0D=0A #define FMAP_BUFSIZE_INIT PAGE_SIZE=0D=0A /*=0D= =0Adiff --git a/fs/fuse/file.c b/fs/fuse/file.c=0D=0Aindex b4e7b6a64587..= 2435a79cbb4a 100644=0D=0A--- a/fs/fuse/file.c=0D=0A+++ b/fs/fuse/file.c=0D= =0A@@ -1859,6 +1859,8 @@ static ssize_t fuse_file_read_iter(struct kiocb = *iocb, struct iov_iter *to)=0D=0A=20=0D=0A =09if (FUSE_IS_VIRTIO_DAX(fi))= =0D=0A =09=09return fuse_dax_read_iter(iocb, to);=0D=0A+=09if (fuse_file_= famfs(fi))=0D=0A+=09=09return famfs_fuse_read_iter(iocb, to);=0D=0A=20=0D= =0A =09/* FOPEN_DIRECT_IO overrides FOPEN_PASSTHROUGH */=0D=0A =09if (ff-= >open_flags & FOPEN_DIRECT_IO)=0D=0A@@ -1881,6 +1883,8 @@ static ssize_t = fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from)=0D=0A=20=0D= =0A =09if (FUSE_IS_VIRTIO_DAX(fi))=0D=0A =09=09return fuse_dax_write_iter= (iocb, from);=0D=0A+=09if (fuse_file_famfs(fi))=0D=0A+=09=09return famfs_= fuse_write_iter(iocb, from);=0D=0A=20=0D=0A =09/* FOPEN_DIRECT_IO overrid= es FOPEN_PASSTHROUGH */=0D=0A =09if (ff->open_flags & FOPEN_DIRECT_IO)=0D= =0A@@ -1896,9 +1900,13 @@ static ssize_t fuse_splice_read(struct file *in= , loff_t *ppos,=0D=0A =09=09=09=09unsigned int flags)=0D=0A {=0D=0A =09st= ruct fuse_file *ff =3D in->private_data;=0D=0A+=09struct inode *inode =3D= file_inode(in);=0D=0A+=09struct fuse_inode *fi =3D get_fuse_inode(inode)= ;=0D=0A=20=0D=0A =09/* FOPEN_DIRECT_IO overrides FOPEN_PASSTHROUGH */=0D=0A= -=09if (fuse_file_passthrough(ff) && !(ff->open_flags & FOPEN_DIRECT_IO))= =0D=0A+=09if (fuse_file_famfs(fi))=0D=0A+=09=09return -EIO; /* famfs does= not use the page cache... */=0D=0A+=09else if (fuse_file_passthrough(ff)= && !(ff->open_flags & FOPEN_DIRECT_IO))=0D=0A =09=09return fuse_passthro= ugh_splice_read(in, ppos, pipe, len, flags);=0D=0A =09else=0D=0A =09=09re= turn filemap_splice_read(in, ppos, pipe, len, flags);=0D=0A@@ -1908,9 +19= 16,13 @@ static ssize_t fuse_splice_write(struct pipe_inode_info *pipe, s= truct file *out,=0D=0A =09=09=09=09 loff_t *ppos, size_t len, unsigned in= t flags)=0D=0A {=0D=0A =09struct fuse_file *ff =3D out->private_data;=0D=0A= +=09struct inode *inode =3D file_inode(out);=0D=0A+=09struct fuse_inode *= fi =3D get_fuse_inode(inode);=0D=0A=20=0D=0A =09/* FOPEN_DIRECT_IO overri= des FOPEN_PASSTHROUGH */=0D=0A-=09if (fuse_file_passthrough(ff) && !(ff->= open_flags & FOPEN_DIRECT_IO))=0D=0A+=09if (fuse_file_famfs(fi))=0D=0A+=09= =09return -EIO; /* famfs does not use the page cache... */=0D=0A+=09else = if (fuse_file_passthrough(ff) && !(ff->open_flags & FOPEN_DIRECT_IO))=0D=0A= =09=09return fuse_passthrough_splice_write(pipe, out, ppos, len, flags);= =0D=0A =09else=0D=0A =09=09return iter_file_splice_write(pipe, out, ppos,= len, flags);=0D=0A@@ -2420,6 +2432,8 @@ static int fuse_file_mmap(struct= file *file, struct vm_area_struct *vma)=0D=0A =09/* DAX mmap is superior= to direct_io mmap */=0D=0A =09if (FUSE_IS_VIRTIO_DAX(fi))=0D=0A =09=09re= turn fuse_dax_mmap(file, vma);=0D=0A+=09if (fuse_file_famfs(fi))=0D=0A+=09= =09return famfs_fuse_mmap(file, vma);=0D=0A=20=0D=0A =09/*=0D=0A =09 * If= inode is in passthrough io mode, because it has some file open=0D=0Adiff= --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h=0D=0Aindex 5394aae9dbac..728= 1fb8b6402 100644=0D=0A--- a/fs/fuse/fuse_i.h=0D=0A+++ b/fs/fuse/fuse_i.h=0D= =0A@@ -1355,6 +1355,9 @@ extern void fuse_sysctl_unregister(void);=0D=0A = int famfs_file_init_dax(struct fuse_mount *fm,=0D=0A =09=09=09struct inod= e *inode, void *fmap_buf,=0D=0A =09=09=09size_t fmap_size);=0D=0A+ssize_t= famfs_fuse_write_iter(struct kiocb *iocb, struct iov_iter *from);=0D=0A+= ssize_t famfs_fuse_read_iter(struct kiocb *iocb, struct iov_iter=09*to);=0D= =0A+int famfs_fuse_mmap(struct file *file, struct vm_area_struct *vma);=0D= =0A void __famfs_meta_free(void *map);=0D=0A=20=0D=0A void famfs_teardown= (struct fuse_conn *fc);=0D=0A@@ -1400,6 +1403,22 @@ static inline void fa= mfs_teardown(struct fuse_conn *fc)=0D=0A {=0D=0A }=0D=0A=20=0D=0A+static = inline ssize_t famfs_fuse_write_iter(struct kiocb *iocb,=0D=0A+=09=09=09=09= =09 struct iov_iter *to)=0D=0A+{=0D=0A+=09return -ENODEV;=0D=0A+}=0D=0A= +static inline ssize_t famfs_fuse_read_iter(struct kiocb *iocb,=0D=0A+=09= =09=09=09=09 struct iov_iter *to)=0D=0A+{=0D=0A+=09return -ENODEV;=0D=0A= +}=0D=0A+static inline int famfs_fuse_mmap(struct file *file,=0D=0A+=09=09= =09=09 struct vm_area_struct *vma)=0D=0A+{=0D=0A+=09return -ENODEV;=0D=0A= +}=0D=0A+=0D=0A static inline struct fuse_backing *famfs_meta_set(struct = fuse_inode *fi,=0D=0A =09=09=09=09=09=09 void *meta)=0D=0A {=0D=0A--=20=0D= =0A2.53.0=0D=0A=0D=0A