diff mbox series

[18/64] libxfs: backport inode init code from the kernel

Message ID 172783102052.4036371.16066393511881832802.stgit@frogsfrogsfrogs (mailing list archive)
State New
Headers show
Series [01/64] xfs: avoid redundant AGFL buffer invalidation | expand

Commit Message

Darrick J. Wong Oct. 2, 2024, 1:12 a.m. UTC
From: Darrick J. Wong <djwong@kernel.org>

Reorganize the userspace inode initialization code to more closely
resemble its kernel counterpart.  This is preparation to hoist the
initialization routines to libxfs.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 include/xfs_inode.h  |   20 +++++++++++++++
 include/xfs_mount.h  |    8 ++++++
 libxfs/inode.c       |   68 +++++++++++++++++++++++++++++++++++++-------------
 libxfs/libxfs_priv.h |   10 +++++++
 4 files changed, 88 insertions(+), 18 deletions(-)

Comments

Christoph Hellwig Oct. 2, 2024, 5:50 a.m. UTC | #1
Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>
diff mbox series

Patch

diff --git a/include/xfs_inode.h b/include/xfs_inode.h
index 4142c45e4..d2f391ea8 100644
--- a/include/xfs_inode.h
+++ b/include/xfs_inode.h
@@ -78,6 +78,12 @@  struct inode {
 	spinlock_t		i_lock;
 };
 
+static inline void
+inode_set_iversion(struct inode *inode, uint64_t version)
+{
+	inode->i_version = version;
+}
+
 static inline uint32_t i_uid_read(struct inode *inode)
 {
 	return inode->i_uid.val;
@@ -95,6 +101,18 @@  static inline void i_gid_write(struct inode *inode, gid_t gid)
 	inode->i_gid.val = gid;
 }
 
+static inline void inode_fsuid_set(struct inode *inode,
+				   struct mnt_idmap *idmap)
+{
+	inode->i_uid = make_kuid(0);
+}
+
+static inline void inode_fsgid_set(struct inode *inode,
+				   struct mnt_idmap *idmap)
+{
+	inode->i_gid = make_kgid(0);
+}
+
 static inline void ihold(struct inode *inode)
 {
 	inode->i_count++;
@@ -408,4 +426,6 @@  extern void	libxfs_irele(struct xfs_inode *ip);
 
 #define XFS_DEFAULT_COWEXTSZ_HINT	32
 
+#define XFS_INHERIT_GID(pip)		(VFS_I(pip)->i_mode & S_ISGID)
+
 #endif /* __XFS_INODE_H__ */
diff --git a/include/xfs_mount.h b/include/xfs_mount.h
index a9525e4e0..4492a2f28 100644
--- a/include/xfs_mount.h
+++ b/include/xfs_mount.h
@@ -228,6 +228,7 @@  __XFS_UNSUPP_FEAT(ikeep)
 __XFS_UNSUPP_FEAT(swalloc)
 __XFS_UNSUPP_FEAT(small_inums)
 __XFS_UNSUPP_FEAT(readonly)
+__XFS_UNSUPP_FEAT(grpid)
 
 /* Operational mount state flags */
 #define XFS_OPSTATE_INODE32		0	/* inode32 allocator active */
@@ -308,4 +309,11 @@  static inline void libxfs_buftarg_drain(struct xfs_buftarg *btp)
 	cache_purge(btp->bcache);
 }
 
+struct mnt_idmap {
+	/* empty */
+};
+
+/* bogus idmapping so that mkfs can do directory inheritance correctly */
+#define libxfs_nop_idmap	((struct mnt_idmap *)1)
+
 #endif	/* __XFS_MOUNT_H__ */
diff --git a/libxfs/inode.c b/libxfs/inode.c
index 206b779a8..dda9b778d 100644
--- a/libxfs/inode.c
+++ b/libxfs/inode.c
@@ -31,7 +31,7 @@ 
 
 /* Propagate di_flags from a parent inode to a child inode. */
 static void
-xfs_inode_propagate_flags(
+xfs_inode_inherit_flags(
 	struct xfs_inode	*ip,
 	const struct xfs_inode	*pip)
 {
@@ -106,35 +106,52 @@  xfs_inode_init(
 	int			times = XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG |
 					XFS_ICHGTIME_ACCESS;
 
-	inode->i_mode = args->mode;
 	if (args->flags & XFS_ICREATE_TMPFILE)
 		set_nlink(inode, 0);
 	else if (S_ISDIR(args->mode))
 		set_nlink(inode, 2);
 	else
 		set_nlink(inode, 1);
-	inode->i_uid = GLOBAL_ROOT_UID;
-	inode->i_gid = GLOBAL_ROOT_GID;
-	ip->i_projid = 0;
+	inode->i_rdev = args->rdev;
 
-	if (pip && (dir->i_mode & S_ISGID)) {
-		inode->i_gid = dir->i_gid;
-		if (S_ISDIR(args->mode))
-			inode->i_mode |= S_ISGID;
+	if (!args->idmap || pip == NULL) {
+		/* creating a tree root, sb rooted, or detached file */
+		inode->i_uid = GLOBAL_ROOT_UID;
+		inode->i_gid = GLOBAL_ROOT_GID;
+		ip->i_projid = 0;
+		inode->i_mode = args->mode;
+	} else {
+		/* creating a child in the directory tree */
+		if (dir && !(dir->i_mode & S_ISGID) && xfs_has_grpid(mp)) {
+			inode_fsuid_set(inode, args->idmap);
+			inode->i_gid = dir->i_gid;
+			inode->i_mode = args->mode;
+		} else {
+			inode_init_owner(args->idmap, inode, dir, args->mode);
+		}
+
+		/*
+		 * If the group ID of the new file does not match the effective
+		 * group ID or one of the supplementary group IDs, the S_ISGID
+		 * bit is cleared (and only if the irix_sgid_inherit
+		 * compatibility variable is set).
+		 */
+		if (irix_sgid_inherit && (inode->i_mode & S_ISGID) &&
+		    !vfsgid_in_group_p(i_gid_into_vfsgid(args->idmap, inode)))
+			inode->i_mode &= ~S_ISGID;
+
+		ip->i_projid = pip ? xfs_get_initial_prid(pip) : 0;
 	}
 
-	if (pip)
-		ip->i_projid = libxfs_get_initial_prid(pip);
-
 	ip->i_disk_size = 0;
 	ip->i_df.if_nextents = 0;
 	ASSERT(ip->i_nblocks == 0);
+
 	ip->i_extsize = 0;
 	ip->i_diflags = 0;
 
-	if (xfs_has_v3inodes(ip->i_mount)) {
-		inode->i_version = 1;
-		ip->i_diflags2 = ip->i_mount->m_ino_geo.new_diflags2;
+	if (xfs_has_v3inodes(mp)) {
+		inode_set_iversion(inode, 1);
 		ip->i_cowextsize = 0;
 		times |= XFS_ICHGTIME_CREATE;
 	}
@@ -149,15 +166,14 @@  xfs_inode_init(
 	case S_IFBLK:
 		ip->i_df.if_format = XFS_DINODE_FMT_DEV;
 		flags |= XFS_ILOG_DEV;
-		VFS_I(ip)->i_rdev = args->rdev;
 		break;
 	case S_IFREG:
 	case S_IFDIR:
 		if (pip && (pip->i_diflags & XFS_DIFLAG_ANY))
-			xfs_inode_propagate_flags(ip, pip);
+			xfs_inode_inherit_flags(ip, pip);
 		if (pip && (pip->i_diflags2 & XFS_DIFLAG2_ANY))
 			xfs_inode_inherit_flags2(ip, pip);
-		/* FALLTHROUGH */
+		fallthrough;
 	case S_IFLNK:
 		ip->i_df.if_format = XFS_DINODE_FMT_EXTENTS;
 		ip->i_df.if_bytes = 0;
@@ -391,6 +407,7 @@  libxfs_iget(
 	VFS_I(ip)->i_count = 1;
 	ip->i_ino = ino;
 	ip->i_mount = mp;
+	ip->i_diflags2 = mp->m_ino_geo.new_diflags2;
 	ip->i_af.if_format = XFS_DINODE_FMT_EXTENTS;
 	spin_lock_init(&VFS_I(ip)->i_lock);
 
@@ -472,3 +489,18 @@  libxfs_irele(
 		kmem_cache_free(xfs_inode_cache, ip);
 	}
 }
+
+void inode_init_owner(struct mnt_idmap *idmap, struct inode *inode,
+		      const struct inode *dir, umode_t mode)
+{
+	inode_fsuid_set(inode, idmap);
+	if (dir && dir->i_mode & S_ISGID) {
+		inode->i_gid = dir->i_gid;
+
+		/* Directories are special, and always inherit S_ISGID */
+		if (S_ISDIR(mode))
+			mode |= S_ISGID;
+	} else
+		inode_fsgid_set(inode, idmap);
+	inode->i_mode = mode;
+}
diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h
index 0bf0c54ac..ecacfff82 100644
--- a/libxfs/libxfs_priv.h
+++ b/libxfs/libxfs_priv.h
@@ -225,6 +225,12 @@  static inline bool WARN_ON(bool expr) {
 	(inode)->i_version = (version);	\
 } while (0)
 
+struct inode;
+struct mnt_idmap;
+
+void inode_init_owner(struct mnt_idmap *idmap, struct inode *inode,
+		      const struct inode *dir, umode_t mode);
+
 #define __must_check	__attribute__((__warn_unused_result__))
 
 /*
@@ -639,4 +645,8 @@  int xfs_bmap_last_extent(struct xfs_trans *tp, struct xfs_inode *ip,
 
 #define cond_resched()	((void)0)
 
+/* xfs_linux.h */
+#define irix_sgid_inherit		(false)
+#define vfsgid_in_group_p(...)		(false)
+
 #endif	/* __LIBXFS_INTERNAL_XFS_H__ */