diff mbox series

[-v3] mm/shmem: support FS_IOC_[SG]ETFLAGS in tmpfs

Message ID 20220715015912.2560575-1-tytso@mit.edu (mailing list archive)
State New
Headers show
Series [-v3] mm/shmem: support FS_IOC_[SG]ETFLAGS in tmpfs | expand

Commit Message

Theodore Ts'o July 15, 2022, 1:59 a.m. UTC
This allows userspace to set flags like FS_APPEND_FL, FS_IMMUTABLE_FL,
FS_NODUMP_FL, etc., like all other standard Linux file systems.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
---
v3:
  - declare shmem_fileattr_get() and shmem_fileattr_set() as static functions

v2:
  - replace use of EXT2_xxx_FL with FS_xxx_FL
  - fix preservation of non-modifiable flags in shmem_fileattr_set()
  - update the commit summary description

 include/linux/shmem_fs.h | 11 +++++++
 mm/shmem.c               | 63 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 73 insertions(+), 1 deletion(-)

Comments

Theodore Ts'o July 20, 2022, 11:10 a.m. UTC | #1
On Thu, Jul 14, 2022 at 09:59:12PM -0400, Theodore Ts'o wrote:
> This allows userspace to set flags like FS_APPEND_FL, FS_IMMUTABLE_FL,
> FS_NODUMP_FL, etc., like all other standard Linux file systems.
> 
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>

Hi Andrew,

I notice that in your most recent mm-unstable tree, you still have the
v1 version of the patch plus your fixup:

* c523739526b3 - mm/shmem: support FS_IOC_[SG]ETFLAGS in tmpfs (6 hours ago)
* 2d6c68e33857 - mm-shmem-support-fs_ioc_etflags-in-tmpfs-fix (6 hours ago)

Could you please replace these two patches with the v3 version of the
patch at:

https://lore.kernel.org/all/20220715015912.2560575-1-tytso@mit.edu/

There haven't been any other comments in the past week, so I'm hopeful
this will be the final version of this proposed change.

Many thanks!

					- Ted
Andrew Morton July 20, 2022, 4:59 p.m. UTC | #2
On Wed, 20 Jul 2022 07:10:04 -0400 "Theodore Ts'o" <tytso@mit.edu> wrote:

> On Thu, Jul 14, 2022 at 09:59:12PM -0400, Theodore Ts'o wrote:
> > This allows userspace to set flags like FS_APPEND_FL, FS_IMMUTABLE_FL,
> > FS_NODUMP_FL, etc., like all other standard Linux file systems.
> > 
> > Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> 
> Hi Andrew,
> 
> I notice that in your most recent mm-unstable tree, you still have the
> v1 version of the patch plus your fixup:
> 
> * c523739526b3 - mm/shmem: support FS_IOC_[SG]ETFLAGS in tmpfs (6 hours ago)
> * 2d6c68e33857 - mm-shmem-support-fs_ioc_etflags-in-tmpfs-fix (6 hours ago)

What's there is actually v2, and the fixup which updates that to v3. 
I'll squash the fixup into the base patch before moving the patch into
mm-nonmm-stable (and then mainline) so it all comes good.

> There haven't been any other comments in the past week, so I'm hopeful
> this will be the final version of this proposed change.

Yup.
Hugh Dickins Aug. 11, 2022, 4:44 a.m. UTC | #3
On Thu, 14 Jul 2022, Theodore Ts'o wrote:

> This allows userspace to set flags like FS_APPEND_FL, FS_IMMUTABLE_FL,
> FS_NODUMP_FL, etc., like all other standard Linux file systems.
> 
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>

Many thanks for adding the chattr support to tmpfs: I'd rather wanted
to do that for a long time, but it's much better coming from you who
actually have a use for it.

But I do have some adjustments to make, coming up now...

Hugh
diff mbox series

Patch

diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index a68f982f22d1..1b6c4013f691 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -25,9 +25,20 @@  struct shmem_inode_info {
 	struct simple_xattrs	xattrs;		/* list of xattrs */
 	atomic_t		stop_eviction;	/* hold when working on inode */
 	struct timespec64	i_crtime;	/* file creation time */
+	unsigned int		fsflags;	/* flags for FS_IOC_[SG]ETFLAGS */
 	struct inode		vfs_inode;
 };
 
+#define SHMEM_FL_USER_VISIBLE FS_FL_USER_VISIBLE
+#define SHMEM_FL_USER_MODIFIABLE FS_FL_USER_MODIFIABLE
+#define SHMEM_FL_INHERITED FS_FL_USER_MODIFIABLE
+
+/* Flags that are appropriate for regular files (all but dir-specific ones). */
+#define SHMEM_REG_FLMASK (~(FS_DIRSYNC_FL | FS_TOPDIR_FL))
+
+/* Flags that are appropriate for non-directories/regular files. */
+#define SHMEM_OTHER_FLMASK (FS_NODUMP_FL | FS_NOATIME_FL)
+
 struct shmem_sb_info {
 	unsigned long max_blocks;   /* How many blocks are allowed */
 	struct percpu_counter used_blocks;  /* How many are allocated */
diff --git a/mm/shmem.c b/mm/shmem.c
index a6f565308133..fc48680b961a 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -28,6 +28,7 @@ 
 #include <linux/ramfs.h>
 #include <linux/pagemap.h>
 #include <linux/file.h>
+#include <linux/fileattr.h>
 #include <linux/mm.h>
 #include <linux/random.h>
 #include <linux/sched/signal.h>
@@ -1058,6 +1059,15 @@  static int shmem_getattr(struct user_namespace *mnt_userns,
 		shmem_recalc_inode(inode);
 		spin_unlock_irq(&info->lock);
 	}
+	if (info->fsflags & FS_APPEND_FL)
+		stat->attributes |= STATX_ATTR_APPEND;
+	if (info->fsflags & FS_IMMUTABLE_FL)
+		stat->attributes |= STATX_ATTR_IMMUTABLE;
+	if (info->fsflags & FS_NODUMP_FL)
+		stat->attributes |= STATX_ATTR_NODUMP;
+	stat->attributes_mask |= (STATX_ATTR_APPEND |
+			STATX_ATTR_IMMUTABLE |
+			STATX_ATTR_NODUMP);
 	generic_fillattr(&init_user_ns, inode, stat);
 
 	if (shmem_is_huge(NULL, inode, 0))
@@ -2272,7 +2282,18 @@  static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
 	return 0;
 }
 
-static struct inode *shmem_get_inode(struct super_block *sb, const struct inode *dir,
+/* Mask out flags that are inappropriate for the given type of inode. */
+static unsigned shmem_mask_flags(umode_t mode, __u32 flags)
+{
+	if (S_ISDIR(mode))
+		return flags;
+	else if (S_ISREG(mode))
+		return flags & SHMEM_REG_FLMASK;
+	else
+		return flags & SHMEM_OTHER_FLMASK;
+}
+
+static struct inode *shmem_get_inode(struct super_block *sb, struct inode *dir,
 				     umode_t mode, dev_t dev, unsigned long flags)
 {
 	struct inode *inode;
@@ -2297,6 +2318,9 @@  static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
 		info->seals = F_SEAL_SEAL;
 		info->flags = flags & VM_NORESERVE;
 		info->i_crtime = inode->i_mtime;
+		info->fsflags = (dir == NULL) ? 0 :
+			SHMEM_I(dir)->fsflags & SHMEM_FL_INHERITED;
+		info->fsflags = shmem_mask_flags(mode, info->fsflags);
 		INIT_LIST_HEAD(&info->shrinklist);
 		INIT_LIST_HEAD(&info->swaplist);
 		simple_xattrs_init(&info->xattrs);
@@ -2813,6 +2837,39 @@  static long shmem_fallocate(struct file *file, int mode, loff_t offset,
 	return error;
 }
 
+static int shmem_fileattr_get(struct dentry *dentry, struct fileattr *fa)
+{
+	struct shmem_inode_info *info = SHMEM_I(d_inode(dentry));
+
+	fileattr_fill_flags(fa, info->fsflags & SHMEM_FL_USER_VISIBLE);
+
+	return 0;
+}
+
+static int shmem_fileattr_set(struct user_namespace *mnt_userns,
+			      struct dentry *dentry, struct fileattr *fa)
+{
+	struct inode *inode = d_inode(dentry);
+	struct shmem_inode_info *info = SHMEM_I(inode);
+
+	if (fileattr_has_fsx(fa))
+		return -EOPNOTSUPP;
+
+	info->fsflags = (info->fsflags & ~SHMEM_FL_USER_MODIFIABLE) |
+		(fa->flags & SHMEM_FL_USER_MODIFIABLE);
+
+	inode->i_flags &= ~(S_APPEND | S_IMMUTABLE | S_NOATIME);
+	if (info->fsflags & FS_APPEND_FL)
+		inode->i_flags |= S_APPEND;
+	if (info->fsflags & FS_IMMUTABLE_FL)
+		inode->i_flags |= S_IMMUTABLE;
+	if (info->fsflags & FS_NOATIME_FL)
+		inode->i_flags |= S_NOATIME;
+
+	inode->i_ctime = current_time(inode);
+	return 0;
+}
+
 static int shmem_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
 	struct shmem_sb_info *sbinfo = SHMEM_SB(dentry->d_sb);
@@ -3828,6 +3885,8 @@  static const struct inode_operations shmem_inode_operations = {
 #ifdef CONFIG_TMPFS_XATTR
 	.listxattr	= shmem_listxattr,
 	.set_acl	= simple_set_acl,
+	.fileattr_get	= shmem_fileattr_get,
+	.fileattr_set	= shmem_fileattr_set,
 #endif
 };
 
@@ -3847,6 +3906,8 @@  static const struct inode_operations shmem_dir_inode_operations = {
 #endif
 #ifdef CONFIG_TMPFS_XATTR
 	.listxattr	= shmem_listxattr,
+	.fileattr_get	= shmem_fileattr_get,
+	.fileattr_set	= shmem_fileattr_set,
 #endif
 #ifdef CONFIG_TMPFS_POSIX_ACL
 	.setattr	= shmem_setattr,