Re: [PATCH V12 04/12] famfs: Introduce inode_operations and super_operations

"Darrick J. Wong" <[email protected]>
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 <20260806051230.GD3560084@frogsfrogsfrogs>
On Mon, Aug 03, 2026 at 02:28:56AM +0000, John Groves wrote:
> From: John Groves <[email protected]>
> 
> The famfs inode and super operations are generic other than
> show_options, evict_inode and setattr (which prevents truncation..
> 
> This commit builds but is still too incomplete to run
> 
> Signed-off-by: John Groves <[email protected]>
> ---
>  fs/famfs/famfs_inode.c    | 249 +++++++++++++++++++++++++++++++++++++-
>  fs/famfs/famfs_internal.h |   6 +
>  2 files changed, 252 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/famfs/famfs_inode.c b/fs/famfs/famfs_inode.c
> index ad71e5e7a8e3..efc6b852eca0 100644
> --- a/fs/famfs/famfs_inode.c
> +++ b/fs/famfs/famfs_inode.c
> @@ -29,6 +29,9 @@
>  
>  #define FAMFS_DEFAULT_MODE	0755
>  
> +static const struct inode_operations famfs_file_inode_operations;
> +static const struct inode_operations famfs_dir_inode_operations;
> +
>  static struct inode *famfs_get_inode(
>  			struct super_block *sb,
>  			const struct inode *dir,
> @@ -54,11 +57,11 @@ static struct inode *famfs_get_inode(
>  		init_special_inode(inode, mode, dev);
>  		break;
>  	case S_IFREG:
> -		inode->i_op = NULL /* famfs_file_inode_operations */;
> +		inode->i_op = &famfs_file_inode_operations;
>  		inode->i_fop = NULL /* &famfs_file_operations */;
>  		break;
>  	case S_IFDIR:
> -		inode->i_op = NULL /* famfs_dir_inode_operations */;
> +		inode->i_op = &famfs_dir_inode_operations;
>  		inode->i_fop = &simple_dir_operations;
>  
>  		/* Directory inodes start off with i_nlink == 2 (for ".") */
> @@ -72,6 +75,246 @@ static struct inode *famfs_get_inode(
>  	return inode;
>  }
>  
> +/***************************************************************************
> + * famfs inode_operations
> + */
> +
> +static int
> +famfs_setattr(
> +	struct mnt_idmap *idmap,
> +	struct dentry *dentry,
> +	struct iattr *iattr)
> +{
> +	struct inode *inode = d_inode(dentry);
> +	struct famfs_fs_info *fsi = inode->i_sb->s_fs_info;
> +
> +	/* Resizing a famfs file (its size is pinned to the fmap) */
> +	if ((iattr->ia_valid & ATTR_SIZE) &&
> +	    !famfs_opt_enabled(fsi, FAMFS_OPT_TRUNCATE) &&

Does truncating the file down release the mapped memory?
Can you truncate it up?  How does the famfs manager deal with this?

> +	    iattr->ia_size != i_size_read(inode))
> +		return -EPERM;
> +	if ((iattr->ia_valid & ATTR_MODE) &&
> +	    !famfs_opt_enabled(fsi, FAMFS_OPT_CHMOD))
> +		return -EPERM;
> +	if ((iattr->ia_valid & (ATTR_UID | ATTR_GID)) &&
> +	    !famfs_opt_enabled(fsi, FAMFS_OPT_CHOWN))
> +		return -EPERM;
> +	if ((iattr->ia_valid & (ATTR_ATIME | ATTR_MTIME)) &&
> +	    !famfs_opt_enabled(fsi, FAMFS_OPT_UTIMES))
> +		return -EPERM;
> +
> +	return simple_setattr(idmap, dentry, iattr);
> +}
> +
> +static const struct inode_operations famfs_file_inode_operations = {
> +	/* All generic */
> +	.setattr	   = famfs_setattr,
> +	.getattr	   = simple_getattr,
> +};
> +
> +/*
> + * Internal inode creation helper, shared by ->create, ->mkdir, ->mknod and
> + * ->symlink. Each of those callers is responsible for its own FAMFS_OPT_*
> + * permission check before getting here.
> + */
> +static int
> +famfs_mknod(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry,
> +	    umode_t mode, dev_t dev)
> +{
> +	struct famfs_fs_info *fsi = dir->i_sb->s_fs_info;
> +	struct timespec64 tv;
> +	struct inode *inode;
> +
> +	if (fsi->deverror)
> +		return -ENODEV;
> +
> +	inode = famfs_get_inode(dir->i_sb, dir, mode, dev);
> +	if (!inode)
> +		return -ENOSPC;
> +
> +	d_make_persistent(dentry, inode);
> +	tv = inode_set_ctime_current(inode);
> +	inode_set_mtime_to_ts(inode, tv);
> +	inode_set_atime_to_ts(inode, tv);
> +
> +	return 0;
> +}
> +
> +static struct dentry *famfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
> +		struct dentry *dentry, umode_t mode)
> +{
> +	struct famfs_fs_info *fsi = dir->i_sb->s_fs_info;
> +	int rc;
> +
> +	if (fsi->deverror)
> +		return ERR_PTR(-ENODEV);
> +	if (!famfs_opt_enabled(fsi, FAMFS_OPT_MKDIR))
> +		return ERR_PTR(-EPERM);
> +
> +	rc = famfs_mknod(&nop_mnt_idmap, dir, dentry, mode | S_IFDIR, 0);
> +	if (rc)
> +		return ERR_PTR(rc);
> +
> +	inc_nlink(dir);
> +
> +	return ERR_PTR(0);
> +}
> +
> +static int famfs_create(struct mnt_idmap *idmap, struct inode *dir,
> +			struct dentry *dentry, umode_t mode, bool excl)
> +{
> +	struct famfs_fs_info *fsi = dir->i_sb->s_fs_info;
> +
> +	if (fsi->deverror)
> +		return -ENODEV;
> +	if (!famfs_opt_enabled(fsi, FAMFS_OPT_CREATE))
> +		return -EPERM;
> +
> +	return famfs_mknod(&nop_mnt_idmap, dir, dentry, mode | S_IFREG, 0);

Is the model here that you creat() a file and then the famfs server has
to go find it some cxl memory?  I was kinda under the impression that
you'd get the famfs software to map some memory to a name, and then the
famfs server on each node would create it and upload the mapping, and
now the cxlmem-backed file can be mmaped from multiple nodes?

But maybe this is less of a cluster filesystem than I assumed it was.

--D

> +}
> +
> +static int
> +famfs_mknod_op(struct mnt_idmap *idmap, struct inode *dir,
> +	       struct dentry *dentry, umode_t mode, dev_t dev)
> +{
> +	struct famfs_fs_info *fsi = dir->i_sb->s_fs_info;
> +
> +	if (!famfs_opt_enabled(fsi, FAMFS_OPT_MKNOD))
> +		return -EPERM;
> +
> +	return famfs_mknod(idmap, dir, dentry, mode, dev);
> +}
> +
> +static int
> +famfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
> +	      struct dentry *dentry, const char *symname)
> +{
> +	struct famfs_fs_info *fsi = dir->i_sb->s_fs_info;
> +	struct inode *inode;
> +	int len, rc;
> +
> +	if (fsi->deverror)
> +		return -ENODEV;
> +	if (!famfs_opt_enabled(fsi, FAMFS_OPT_SYMLINK))
> +		return -EPERM;
> +
> +	inode = famfs_get_inode(dir->i_sb, dir, S_IFLNK | 0777, 0);
> +	if (!inode)
> +		return -ENOSPC;
> +
> +	len = strlen(symname) + 1;
> +	rc = page_symlink(inode, symname, len);
> +	if (rc) {
> +		iput(inode);
> +		return rc;
> +	}
> +
> +	d_make_persistent(dentry, inode);
> +	inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
> +
> +	return 0;
> +}
> +
> +static int
> +famfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
> +{
> +	struct famfs_fs_info *fsi = dir->i_sb->s_fs_info;
> +
> +	if (!famfs_opt_enabled(fsi, FAMFS_OPT_LINK))
> +		return -EPERM;
> +
> +	return simple_link(old_dentry, dir, dentry);
> +}
> +
> +static int famfs_unlink(struct inode *dir, struct dentry *dentry)
> +{
> +	struct inode *inode = d_inode(dentry);
> +	struct famfs_fs_info *fsi = dir->i_sb->s_fs_info;
> +
> +	/* A file with an fmap may only be unlinked when explicitly enabled */
> +	if (inode->i_private && !famfs_opt_enabled(fsi, FAMFS_OPT_UNLINK))
> +		return -EPERM;
> +
> +	return simple_unlink(dir, dentry);
> +}
> +
> +static int famfs_rmdir(struct inode *dir, struct dentry *dentry)
> +{
> +	struct famfs_fs_info *fsi = dir->i_sb->s_fs_info;
> +
> +	if (!famfs_opt_enabled(fsi, FAMFS_OPT_RMDIR))
> +		return -EPERM;
> +
> +	return simple_rmdir(dir, dentry);
> +}
> +
> +static int
> +famfs_rename(
> +	struct mnt_idmap *idmap,
> +	struct inode *old_dir,
> +	struct dentry *old_dentry,
> +	struct inode *new_dir,
> +	struct dentry *new_dentry,
> +	unsigned int flags)
> +{
> +	struct famfs_fs_info *fsi = old_dir->i_sb->s_fs_info;
> +
> +	if (!famfs_opt_enabled(fsi, FAMFS_OPT_RENAME))
> +		return -EPERM;
> +
> +	return simple_rename(idmap, old_dir, old_dentry, new_dir, new_dentry,
> +			     flags);
> +}
> +
> +static const struct inode_operations famfs_dir_inode_operations = {
> +	.create		= famfs_create,
> +	.lookup		= simple_lookup,
> +	.link		= famfs_link,
> +	.unlink		= famfs_unlink,
> +	.symlink	= famfs_symlink,
> +	.mkdir		= famfs_mkdir,
> +	.mknod		= famfs_mknod_op,
> +	.rmdir		= famfs_rmdir,
> +	.rename		= famfs_rename,
> +};
> +
> +/*****************************************************************************
> + * famfs super_operations
> + *
> + * TODO: implement a famfs_statfs() that shows size, free and available space,
> + * etc.
> + */
> +
> +/*
> + * famfs_show_options() - Display the mount options in /proc/mounts.
> + */
> +static int famfs_show_options(struct seq_file *m, struct dentry *root)
> +{
> +	struct famfs_fs_info *fsi = root->d_sb->s_fs_info;
> +
> +	if (fsi->mount_opts.mode != FAMFS_DEFAULT_MODE)
> +		seq_printf(m, ",mode=%o", fsi->mount_opts.mode);
> +
> +	return 0;
> +}
> +
> +static void famfs_evict_inode(struct inode *inode)
> +{
> +	inode->i_private = NULL;
> +	dax_break_layout_final(inode);
> +	truncate_inode_pages_final(&inode->i_data);
> +	clear_inode(inode);
> +}
> +
> +static const struct super_operations famfs_super_ops = {
> +	.statfs		= simple_statfs,
> +	.drop_inode	= inode_just_drop,
> +	.show_options	= famfs_show_options,
> +	.evict_inode    = famfs_evict_inode,
> +};
> +
> +/*****************************************************************************/
> +
>  /*
>   * famfs dax_operations (for famfs-mode dax)
>   */
> @@ -305,7 +548,7 @@ famfs_fill_super(struct super_block *sb, struct fs_context *fc)
>  	sb->s_blocksize		= PAGE_SIZE;
>  	sb->s_blocksize_bits	= PAGE_SHIFT;
>  	sb->s_magic		= FAMFS_SUPER_MAGIC;
> -	sb->s_op		= NULL /* famfs_super_ops */;
> +	sb->s_op		= &famfs_super_ops;
>  	sb->s_time_gran		= 1;
>  }
>  
> diff --git a/fs/famfs/famfs_internal.h b/fs/famfs/famfs_internal.h
> index ebb9c499cf69..485087588a11 100644
> --- a/fs/famfs/famfs_internal.h
> +++ b/fs/famfs/famfs_internal.h
> @@ -70,6 +70,12 @@ struct famfs_fs_info {
>  	struct rw_semaphore       devlist_sem;
>  };
>  
> +/* This stub will be replaced in a later commit 
> + * Note: the opt parameter is intentionally unused, and will be used by
> + * the replacement function when that commit lands
> + */
> +#define famfs_opt_enabled(fsi, opt) (fsi != 0)
> +
>  int lookup_daxdev(const char *pathname, dev_t *devno);
>  int famfs_devlist_alloc(struct famfs_fs_info *fsi);
>  int famfs_install_daxdev(struct famfs_fs_info *fsi, struct super_block *sb,
> -- 
> 2.53.0
> 
> 
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.