* -o shadow=<shadowpath>
* -o daxdev=<daxdev>
Signed-off-by: John Groves <john@groves.net>
---
fs/fuse/fuse_i.h | 8 +++++++-
fs/fuse/inode.c | 28 +++++++++++++++++++++++++++-
2 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index a592c1002861..f4ee61046578 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -583,9 +583,11 @@ struct fuse_fs_context {
unsigned int blksize;
const char *subtype;
- /* DAX device, may be NULL */
+ /* DAX device for virtiofs, may be NULL */
struct dax_device *dax_dev;
+ const char *shadow; /* famfs - null if not famfs */
+
/* fuse_dev pointer to fill in, should contain NULL on entry */
void **fudptr;
};
@@ -941,6 +943,10 @@ struct fuse_conn {
/** uring connection information*/
struct fuse_ring *ring;
#endif
+
+#if IS_ENABLED(CONFIG_FUSE_FAMFS_DAX)
+ char *shadow;
+#endif
};
/*
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index e48e11c3f9f3..a7e1cf8257b0 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -766,6 +766,9 @@ enum {
OPT_ALLOW_OTHER,
OPT_MAX_READ,
OPT_BLKSIZE,
+#if IS_ENABLED(CONFIG_FUSE_FAMFS_DAX)
+ OPT_SHADOW,
+#endif
OPT_ERR
};
@@ -780,6 +783,9 @@ static const struct fs_parameter_spec fuse_fs_parameters[] = {
fsparam_u32 ("max_read", OPT_MAX_READ),
fsparam_u32 ("blksize", OPT_BLKSIZE),
fsparam_string ("subtype", OPT_SUBTYPE),
+#if IS_ENABLED(CONFIG_FUSE_FAMFS_DAX)
+ fsparam_string("shadow", OPT_SHADOW),
+#endif
{}
};
@@ -875,6 +881,15 @@ static int fuse_parse_param(struct fs_context *fsc, struct fs_parameter *param)
ctx->blksize = result.uint_32;
break;
+#if IS_ENABLED(CONFIG_FUSE_FAMFS_DAX)
+ case OPT_SHADOW:
+ if (ctx->shadow)
+ return invalfc(fsc, "Multiple shadows specified");
+ ctx->shadow = param->string;
+ param->string = NULL;
+ break;
+#endif
+
default:
return -EINVAL;
}
@@ -888,6 +903,7 @@ static void fuse_free_fsc(struct fs_context *fsc)
if (ctx) {
kfree(ctx->subtype);
+ kfree(ctx->shadow);
kfree(ctx);
}
}
@@ -919,7 +935,10 @@ static int fuse_show_options(struct seq_file *m, struct dentry *root)
else if (fc->dax_mode == FUSE_DAX_INODE_USER)
seq_puts(m, ",dax=inode");
#endif
-
+#if IS_ENABLED(CONFIG_FUSE_FAMFS_DAX)
+ if (fc->shadow)
+ seq_printf(m, ",shadow=%s", fc->shadow);
+#endif
return 0;
}
@@ -1017,6 +1036,9 @@ void fuse_conn_put(struct fuse_conn *fc)
}
if (IS_ENABLED(CONFIG_FUSE_PASSTHROUGH))
fuse_backing_files_free(fc);
+#if IS_ENABLED(CONFIG_FUSE_FAMFS_DAX)
+ kfree(fc->shadow);
+#endif
call_rcu(&fc->rcu, delayed_release);
}
}
@@ -1834,6 +1856,10 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx)
sb->s_root = root_dentry;
if (ctx->fudptr)
*ctx->fudptr = fud;
+
+#if IS_ENABLED(CONFIG_FUSE_FAMFS_DAX)
+ fc->shadow = kstrdup(ctx->shadow, GFP_KERNEL);
+#endif
mutex_unlock(&fuse_mutex);
return 0;
--
2.49.0
On Thu, Jul 03, 2025 at 01:50:25PM -0500, John Groves wrote: > * -o shadow=<shadowpath> What is a shadow? > * -o daxdev=<daxdev> And, uh, if there's a FUSE_GET_DAXDEV command, then what does this mount option do? Pre-populate the first element of that set? --D > Signed-off-by: John Groves <john@groves.net> > --- > fs/fuse/fuse_i.h | 8 +++++++- > fs/fuse/inode.c | 28 +++++++++++++++++++++++++++- > 2 files changed, 34 insertions(+), 2 deletions(-) > > diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h > index a592c1002861..f4ee61046578 100644 > --- a/fs/fuse/fuse_i.h > +++ b/fs/fuse/fuse_i.h > @@ -583,9 +583,11 @@ struct fuse_fs_context { > unsigned int blksize; > const char *subtype; > > - /* DAX device, may be NULL */ > + /* DAX device for virtiofs, may be NULL */ > struct dax_device *dax_dev; > > + const char *shadow; /* famfs - null if not famfs */ > + > /* fuse_dev pointer to fill in, should contain NULL on entry */ > void **fudptr; > }; > @@ -941,6 +943,10 @@ struct fuse_conn { > /** uring connection information*/ > struct fuse_ring *ring; > #endif > + > +#if IS_ENABLED(CONFIG_FUSE_FAMFS_DAX) > + char *shadow; > +#endif > }; > > /* > diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c > index e48e11c3f9f3..a7e1cf8257b0 100644 > --- a/fs/fuse/inode.c > +++ b/fs/fuse/inode.c > @@ -766,6 +766,9 @@ enum { > OPT_ALLOW_OTHER, > OPT_MAX_READ, > OPT_BLKSIZE, > +#if IS_ENABLED(CONFIG_FUSE_FAMFS_DAX) > + OPT_SHADOW, > +#endif > OPT_ERR > }; > > @@ -780,6 +783,9 @@ static const struct fs_parameter_spec fuse_fs_parameters[] = { > fsparam_u32 ("max_read", OPT_MAX_READ), > fsparam_u32 ("blksize", OPT_BLKSIZE), > fsparam_string ("subtype", OPT_SUBTYPE), > +#if IS_ENABLED(CONFIG_FUSE_FAMFS_DAX) > + fsparam_string("shadow", OPT_SHADOW), > +#endif > {} > }; > > @@ -875,6 +881,15 @@ static int fuse_parse_param(struct fs_context *fsc, struct fs_parameter *param) > ctx->blksize = result.uint_32; > break; > > +#if IS_ENABLED(CONFIG_FUSE_FAMFS_DAX) > + case OPT_SHADOW: > + if (ctx->shadow) > + return invalfc(fsc, "Multiple shadows specified"); > + ctx->shadow = param->string; > + param->string = NULL; > + break; > +#endif > + > default: > return -EINVAL; > } > @@ -888,6 +903,7 @@ static void fuse_free_fsc(struct fs_context *fsc) > > if (ctx) { > kfree(ctx->subtype); > + kfree(ctx->shadow); > kfree(ctx); > } > } > @@ -919,7 +935,10 @@ static int fuse_show_options(struct seq_file *m, struct dentry *root) > else if (fc->dax_mode == FUSE_DAX_INODE_USER) > seq_puts(m, ",dax=inode"); > #endif > - > +#if IS_ENABLED(CONFIG_FUSE_FAMFS_DAX) > + if (fc->shadow) > + seq_printf(m, ",shadow=%s", fc->shadow); > +#endif > return 0; > } > > @@ -1017,6 +1036,9 @@ void fuse_conn_put(struct fuse_conn *fc) > } > if (IS_ENABLED(CONFIG_FUSE_PASSTHROUGH)) > fuse_backing_files_free(fc); > +#if IS_ENABLED(CONFIG_FUSE_FAMFS_DAX) > + kfree(fc->shadow); > +#endif > call_rcu(&fc->rcu, delayed_release); > } > } > @@ -1834,6 +1856,10 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx) > sb->s_root = root_dentry; > if (ctx->fudptr) > *ctx->fudptr = fud; > + > +#if IS_ENABLED(CONFIG_FUSE_FAMFS_DAX) > + fc->shadow = kstrdup(ctx->shadow, GFP_KERNEL); > +#endif > mutex_unlock(&fuse_mutex); > return 0; > > -- > 2.49.0 > >
On 25/07/08 08:59PM, Darrick J. Wong wrote: > On Thu, Jul 03, 2025 at 01:50:25PM -0500, John Groves wrote: > > * -o shadow=<shadowpath> > > What is a shadow? > > > * -o daxdev=<daxdev> Derp - OK, that's a stale commit message. Here is the one for the -next version of this patch: famfs_fuse: Basic famfs mount opt: -o shadow=<shadowpath> The shadow path is a (usually tmpfs) file system area used by the famfs user space to commuicate with the famfs fuse server. There is a minor dilemma that the user space tools must be able to resolve from a mount point path to a shadow path. The shadow path is exposed via /proc/mounts, but otherwise not used by the kernel. User space gets the shadow path from /proc/mounts... > > And, uh, if there's a FUSE_GET_DAXDEV command, then what does this mount > option do? Pre-populate the first element of that set? > > --D > I took out -o daxdev, but had failed to update the commit msg. The logic is this: The general model requires the FUSE_GET_DAXDEV message / response, so passing in the primary daxdev as a -o arg creates two ways to do the same thing. The only initial heartburn about this was one could imagine a case where a mount happens, but no I/O happens for a while so the mount could "succeed", only to fail later if the primary daxdev could not be accessed. But this can't happen with famfs, because the mount procedure includes creating "meta files" - .meta/.superblock and .meta/.log and accessing them immediately. So it is guaranteed that FUSE_GET_DAXDEV will be sent right away, and if it fails, the mount will be unwound. Thanks Darrick! John <snip>
On Fri, Jul 11, 2025 at 10:28:20AM -0500, John Groves wrote: > On 25/07/08 08:59PM, Darrick J. Wong wrote: > > On Thu, Jul 03, 2025 at 01:50:25PM -0500, John Groves wrote: > > > * -o shadow=<shadowpath> > > > > What is a shadow? > > > > > * -o daxdev=<daxdev> > > Derp - OK, that's a stale commit message. Here is the one for the -next > version of this patch: > > famfs_fuse: Basic famfs mount opt: -o shadow=<shadowpath> > > The shadow path is a (usually tmpfs) file system area used by the famfs > user space to commuicate with the famfs fuse server. There is a minor > dilemma that the user space tools must be able to resolve from a mount > point path to a shadow path. The shadow path is exposed via /proc/mounts, > but otherwise not used by the kernel. User space gets the shadow path > from /proc/mounts... Ah. A service directory, of sorts. > > And, uh, if there's a FUSE_GET_DAXDEV command, then what does this mount > > option do? Pre-populate the first element of that set? > > > > --D > > > > I took out -o daxdev, but had failed to update the commit msg. > > The logic is this: The general model requires the FUSE_GET_DAXDEV message / > response, so passing in the primary daxdev as a -o arg creates two ways to > do the same thing. > > The only initial heartburn about this was one could imagine a case where a > mount happens, but no I/O happens for a while so the mount could "succeed", > only to fail later if the primary daxdev could not be accessed. > > But this can't happen with famfs, because the mount procedure includes > creating "meta files" - .meta/.superblock and .meta/.log and accessing them > immediately. So it is guaranteed that FUSE_GET_DAXDEV will be sent right away, > and if it fails, the mount will be unwound. <nod> --D > Thanks Darrick! > John > > <snip> > >
On Sat, 12 Jul 2025 at 07:54, Darrick J. Wong <djwong@kernel.org> wrote: > > On Fri, Jul 11, 2025 at 10:28:20AM -0500, John Groves wrote: > > famfs_fuse: Basic famfs mount opt: -o shadow=<shadowpath> > > > > The shadow path is a (usually tmpfs) file system area used by the famfs > > user space to commuicate with the famfs fuse server. There is a minor > > dilemma that the user space tools must be able to resolve from a mount > > point path to a shadow path. The shadow path is exposed via /proc/mounts, > > but otherwise not used by the kernel. User space gets the shadow path > > from /proc/mounts... Don't know if we want to go that way. Is there no other way? But if we do, at least do it in a generic way. I.e. fuse server can tell the kernel to display options A, B and C in /proc/mounts. Thanks, Miklos
On 25/08/14 12:37PM, Miklos Szeredi wrote: > On Sat, 12 Jul 2025 at 07:54, Darrick J. Wong <djwong@kernel.org> wrote: > > > > On Fri, Jul 11, 2025 at 10:28:20AM -0500, John Groves wrote: > > > > famfs_fuse: Basic famfs mount opt: -o shadow=<shadowpath> > > > > > > The shadow path is a (usually tmpfs) file system area used by the famfs > > > user space to commuicate with the famfs fuse server. There is a minor > > > dilemma that the user space tools must be able to resolve from a mount > > > point path to a shadow path. The shadow path is exposed via /proc/mounts, > > > but otherwise not used by the kernel. User space gets the shadow path > > > from /proc/mounts... > > Don't know if we want to go that way. Is there no other way? > > But if we do, at least do it in a generic way. I.e. fuse server can > tell the kernel to display options A, B and C in /proc/mounts. > > Thanks, > Miklos So far I haven't come up with an alternative, other than bad ones. Could parse the shadow path from the fuse server with the correct mount point from 'ps -ef', but there are cases where a fuse server is killed and the kernel still thinks it's mounted (and we still might need to find the shadow path). Could write the shadow path to a systemd log and parse it from there, but that would break if the log wasn't enabled, and would disappear if the log was rotated during a long-running mount - and this resolution must happen every time the famfs cli does most anything (cp, creat, fsck, etc.). Could write it to a "secret file" somewhere, but that's kinda brittle. Shadow paths are almost always tmpdir paths that are generated at mount time, so there really isn't a good way to guess them, and it doesn't seem viable to require them to be in (e.g.) /tmp in all cases. Here is what it currently looks like on a running system: $ grep famfs /proc/mounts /dev/dax0.0 /mnt/famfs fuse rw,nosuid,nodev,relatime,user_id=0,group_id=0,shadow=/tmp/famfs_shadow_5m0dnH 0 0 $ ps -ef | grep /mnt/famfs | grep -v grep root 12775 1 0 07:04 ? 00:00:00 /dev/dax0.0 -o daxdev=/dev/dax0.0,shadow=/tmp/famfs_shadow_5m0dnH,fsname=/dev/dax0.0,timeout=31536000.000000 /mnt/famfs Having a generic approach rather than a '-o' option would be fine with me. Also happy to entertain other ideas... Thanks, John
On Thu, 14 Aug 2025 at 16:39, John Groves <John@groves.net> wrote: > Having a generic approach rather than a '-o' option would be fine with me. > Also happy to entertain other ideas... We could just allow arbitrary options to be set by the server. It might break cases where the server just passes unknown options down into the kernel, which currently are rejected. I don't think this is common practice, but still it sounds a bit risky. Alternatively allow INIT_REPLY to set up misc options, which can only be done explicitly, so no risk there. Thanks, Miklos
On 25/08/14 05:19PM, Miklos Szeredi wrote: > On Thu, 14 Aug 2025 at 16:39, John Groves <John@groves.net> wrote: > > > Having a generic approach rather than a '-o' option would be fine with me. > > Also happy to entertain other ideas... > > We could just allow arbitrary options to be set by the server. It > might break cases where the server just passes unknown options down > into the kernel, which currently are rejected. I don't think this is > common practice, but still it sounds a bit risky. > > Alternatively allow INIT_REPLY to set up misc options, which can only > be done explicitly, so no risk there. > > Thanks, > Miklos I'll take a look at INIT_REPLY; if I can make sense of it, I'll try something based on that in V3. Or I may have questions... Thanks, John
© 2016 - 2025 Red Hat, Inc.