[PATCH V12 09/12] famfs: Register secondary daxdevs by path (FAMFSIOC_DAXDEV_OPEN)
John Groves <[email protected]> Mon, 3 Aug 2026 02:29:47 +0000
| Newsgroups | dev.linux.lists.nvdimm,dev.linux.lists.fuse-devel,org.kernel.vger.linux-cxl,org.kernel.vger.linux-doc,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <0100019fc574b43d-effbc86f-dd35-4154-8c2e-17699ef0edb6-000000@email.amazonses.com> |
From: John Groves <[email protected]>=0D=0A=0D=0AFamfs file maps (fmaps) ma= y reference multiple daxdevs. Before passing=0D=0Aan fmap that references= a new daxdev, the daxdev is pushed into the=0D=0Akernel via FAMFSIOC_DAX= DEV_OPEN). This adds daxdevs to daxdev_table for=0D=0Aindex-based resolut= ion from famfs extents to daxdevs.=0D=0A=0D=0ASigned-off-by: John Groves = <[email protected]>=0D=0A---=0D=0A fs/famfs/famfs_file.c | 74 ++= ++++++++++++++++++++++++++++++=0D=0A include/uapi/linux/famfs_ioctl.h | 2= 4 +++++++++++=0D=0A 2 files changed, 98 insertions(+)=0D=0A=0D=0Adiff --g= it a/fs/famfs/famfs_file.c b/fs/famfs/famfs_file.c=0D=0Aindex e7f271ce6d0= 3..e11a55ecf8d7 100644=0D=0A--- a/fs/famfs/famfs_file.c=0D=0A+++ b/fs/fam= fs/famfs_file.c=0D=0A@@ -287,6 +287,76 @@ famfs_file_init_dax(struct file= *file, void __user *arg)=0D=0A =09return rc;=0D=0A }=0D=0A=20=0D=0A+/**=0D= =0A+ * famfs_daxdev_open() - FAMFSIOC_DAXDEV_OPEN ioctl handler=0D=0A+ * = @file: any file in the famfs mount (the table is per-superblock)=0D=0A+ *= @arg: ptr to struct famfs_ioc_daxdev in user space=0D=0A+ *=0D=0A+ * Re= gister a devdax device (identified by path) into the mount's daxdev table= =0D=0A+ * at the caller-specified index, so files whose extents reference= that index=0D=0A+ * can be mapped. The path is resolved by lookup_daxdev= () - the same helper the=0D=0A+ * mount uses for the primary daxdev - so = every slot is resolved identically.=0D=0A+ * Registering exposes raw devi= ce memory, so it requires CAP_SYS_RAWIO.=0D=0A+ */=0D=0A+static int=0D=0A= +famfs_daxdev_open(struct file *file, void __user *arg)=0D=0A+{=0D=0A+=09= struct super_block *sb =3D file_inode(file)->i_sb;=0D=0A+=09struct famfs_= fs_info *fsi =3D sb->s_fs_info;=0D=0A+=09struct famfs_ioc_daxdev dd;=0D=0A= +=09dev_t devno;=0D=0A+=09char *path;=0D=0A+=09int rc;=0D=0A+=0D=0A+=09if= (!capable(CAP_SYS_RAWIO))=0D=0A+=09=09return -EPERM;=0D=0A+=0D=0A+=09if = (copy_from_user(&dd, arg, sizeof(dd)))=0D=0A+=09=09return -EFAULT;=0D=0A+= =0D=0A+=09/* @flags is reserved; reject non-zero so it stays available */= =0D=0A+=09if (dd.flags)=0D=0A+=09=09return -EINVAL;=0D=0A+=0D=0A+=09/*=0D= =0A+=09 * If this daxdev index is already populated there is nothing to d= o.=0D=0A+=09 * The index is cluster-invariant, so a valid slot already na= mes this=0D=0A+=09 * device; skip the path resolution entirely. install_d= axdev() rechecks=0D=0A+=09 * ->valid under the write lock, so this is pur= ely an optimization.=0D=0A+=09 */=0D=0A+=09scoped_guard(rwsem_read, &fsi-= >devlist_sem) {=0D=0A+=09=09if (dd.daxdev_index >=3D fsi->dax_devlist->ns= lots)=0D=0A+=09=09=09return -EINVAL;=0D=0A+=09=09if (fsi->dax_devlist->de= vlist[dd.daxdev_index].valid)=0D=0A+=09=09=09return 0;=0D=0A+=09}=0D=0A+=0D= =0A+=09if (dd.daxdev_path_len =3D=3D 0 || dd.daxdev_path_len >=3D PATH_MA= X)=0D=0A+=09=09return -EINVAL;=0D=0A+=0D=0A+=09/* +1 so the terminating N= UL is included within the bound */=0D=0A+=09path =3D strndup_user((const = char __user *)(uintptr_t)dd.daxdev_path,=0D=0A+=09=09=09 dd.daxdev_pat= h_len + 1);=0D=0A+=09if (IS_ERR(path))=0D=0A+=09=09return PTR_ERR(path);=0D= =0A+=0D=0A+=09rc =3D lookup_daxdev(path, &devno);=0D=0A+=09if (rc)=0D=0A+= =09=09goto out;=0D=0A+=0D=0A+=09/*=0D=0A+=09 * The daxdev table is alloca= ted at mount time (for the slot-0 primary),=0D=0A+=09 * so it is always p= resent here; no need to allocate it.=0D=0A+=09 */=0D=0A+=09rc =3D famfs_i= nstall_daxdev(fsi, sb, dd.daxdev_index, devno, path);=0D=0A+=09if (rc)=0D= =0A+=09=09pr_debug("%s: failed to install daxdev index %llu (%s)\n",=0D=0A= +=09=09 __func__, dd.daxdev_index, path);=0D=0A+out:=0D=0A+=09kfree= (path);=0D=0A+=09return rc;=0D=0A+}=0D=0A+=0D=0A /**=0D=0A * famfs_file_= ioctl() - Top-level famfs file ioctl handler=0D=0A * @file: the file=0D=0A= @@ -308,6 +378,10 @@ famfs_file_ioctl(struct file *file, unsigned int cmd= , unsigned long arg)=0D=0A =09=09rc =3D 0;=0D=0A =09=09break;=0D=0A=20=0D= =0A+=09case FAMFSIOC_DAXDEV_OPEN:=0D=0A+=09=09rc =3D famfs_daxdev_open(fi= le, (void __user *)arg);=0D=0A+=09=09break;=0D=0A+=0D=0A =09case FAMFSIOC= _MAP_CREATE:=0D=0A =09=09rc =3D famfs_file_init_dax(file, (void __user *)= arg);=0D=0A =09=09break;=0D=0Adiff --git a/include/uapi/linux/famfs_ioctl= =2Eh b/include/uapi/linux/famfs_ioctl.h=0D=0Aindex b4eb373c1ade..751d8b03= 3c2e 100644=0D=0A--- a/include/uapi/linux/famfs_ioctl.h=0D=0A+++ b/includ= e/uapi/linux/famfs_ioctl.h=0D=0A@@ -77,6 +77,29 @@ struct famfs_ioc_fmap_= header {=0D=0A =09__u64 reserved1;=0D=0A };=0D=0A=20=0D=0A+/**=0D=0A+ * s= truct famfs_ioc_daxdev - register an additional backing daxdev by path=0D= =0A+ * @daxdev_index: the (cluster-invariant) index this daxdev occupi= es in=0D=0A+ * extent dev_index fields. Index 0 is the = mount-time primary.=0D=0A+ * @daxdev_path: userspace pointer to the d= evdax device path (e.g.=0D=0A+ * "/dev/dax0.0"); resolv= ed in the kernel the same way the=0D=0A+ * mount primar= y is.=0D=0A+ * @daxdev_path_len: length of the path string, not counting = the NUL.=0D=0A+ * @flags: reserved; must be zero.=0D=0A+ *=0D=0A= + * Standalone famfs registers every daxdev by path: the mount primary co= mes in=0D=0A+ * as the mount device name, and slots 1..n come in here. (T= his deliberately=0D=0A+ * differs from fuse's fd-based FUSE_DEV_IOC_DAXDE= V_OPEN; each side is uniform=0D=0A+ * within itself.) Passing the path by= pointer keeps the struct fixed-size, so=0D=0A+ * longer paths never requ= ire an ABI change.=0D=0A+ */=0D=0A+struct famfs_ioc_daxdev {=0D=0A+=09__u= 64 daxdev_index;=0D=0A+=09__u64 daxdev_path;=0D=0A+=09__u32 daxdev_path_l= en;=0D=0A+=09__u32 flags;=0D=0A+};=0D=0A+=0D=0A #define FAMFSIOC_MAGIC 'u= '=0D=0A=20=0D=0A /* famfs file ioctl opcodes */=0D=0A@@ -87,5 +110,6 @@ s= truct famfs_ioc_fmap_header {=0D=0A * famfs_ioc_fmap_header followed by = the extent list (see above).=0D=0A */=0D=0A #define FAMFSIOC_MAP_CREATE = _IOW(FAMFSIOC_MAGIC, 0x51, struct famfs_ioc_fmap_header)=0D=0A+#defin= e FAMFSIOC_DAXDEV_OPEN _IOW(FAMFSIOC_MAGIC, 0x52, struct famfs_ioc_dax= dev)=0D=0A=20=0D=0A #endif /* FAMFS_IOCTL_H */=0D=0A--=20=0D=0A2.53.0=0D=0A= =0D=0A