Provide a fill_super hook for a subclass filesystem to use to get a reference on the resource it attaches to struct kernfs_super_info::root. Without this, error handling becomes tricky in the event that, say, kernfs_get_inode() fails in kernfs_fill_super() as the superblock destructor will be invoked before kernfs_get_tree() returns. Fixes: b3678086951a ("kernfs, sysfs, cgroup, intel_rdt: Support fs_context") Signed-off-by: David Howells <dhowells@xxxxxxxxxx> --- fs/kernfs/mount.c | 13 +++++++++++-- include/linux/kernfs.h | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c index 3b61a4bb02c4..f04173d29845 100644 --- a/fs/kernfs/mount.c +++ b/fs/kernfs/mount.c @@ -217,11 +217,13 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn, } while (true); } -static int kernfs_fill_super(struct super_block *sb, struct kernfs_fs_context *kfc) +static int kernfs_fill_super(struct super_block *sb, struct fs_context *fc) { + struct kernfs_fs_context *kfc = fc->fs_private; struct kernfs_super_info *info = kernfs_info(sb); struct inode *inode; struct dentry *root; + int ret; info->sb = sb; /* Userspace would break if executables or devices appear on sysfs */ @@ -238,6 +240,12 @@ static int kernfs_fill_super(struct super_block *sb, struct kernfs_fs_context *k /* sysfs dentries and inodes don't require IO to create */ sb->s_shrink.seeks = 0; + if (kfc->fill_super) { + ret = kfc->fill_super(sb, fc); + if (ret < 0) + return ret; + } + /* get root inode, initialize and unlock it */ mutex_lock(&kernfs_mutex); inode = kernfs_get_inode(sb, info->root->kn); @@ -290,6 +298,7 @@ const void *kernfs_super_ns(struct super_block *sb) /** * kernfs_get_tree - kernfs filesystem access/retrieval helper * @fc: The filesystem context. + * @fill_super: The subclass's superblock initialiser function * * This is to be called from each kernfs user's fs_context->ops->get_tree() * implementation, which should set the specified ->@fs_type and ->@flags, and @@ -321,7 +330,7 @@ int kernfs_get_tree(struct fs_context *fc) kfc->new_sb_created = true; - error = kernfs_fill_super(sb, kfc); + error = kernfs_fill_super(sb, fc); if (error) { deactivate_locked_super(sb); return error; diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 60ae0f862a79..a68e3fdd428c 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -277,6 +277,7 @@ struct kernfs_fs_context { struct kernfs_root *root; /* Root of the hierarchy being mounted */ void *ns_tag; /* Namespace tag of the mount (or NULL) */ unsigned long magic; /* File system specific magic number */ + int (*fill_super)(struct super_block *sb, struct fs_context *fc); /* The following are set/used by kernfs_mount() */ bool new_sb_created; /* Set to T if we allocated a new sb */