]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
libxfs: backport inode init code from the kernel
authorDarrick J. Wong <djwong@kernel.org>
Wed, 2 Oct 2024 01:12:31 +0000 (18:12 -0700)
committerAndrey Albershteyn <aalbersh@redhat.com>
Fri, 4 Oct 2024 10:42:07 +0000 (12:42 +0200)
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>
Reviewed-by: Christoph Hellwig <hch@lst.de>
include/xfs_inode.h
include/xfs_mount.h
libxfs/inode.c
libxfs/libxfs_priv.h

index 4142c45e4e314e20b74d30a34499479b8e8ac2ce..d2f391ea872ceeb3d19673889ece5725661d4cf1 100644 (file)
@@ -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__ */
index a9525e4e054601e398f1fbee299bf22bf321981e..4492a2f28b11705f44b344a3d8e8b1ef52bfb1f1 100644 (file)
@@ -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__ */
index 206b779a8e96da706086927e6e1484285de53370..dda9b778dc6687a09465154e350bac93abf99131 100644 (file)
@@ -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 (!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 (pip && (dir->i_mode & S_ISGID)) {
-               inode->i_gid = dir->i_gid;
-               if (S_ISDIR(args->mode))
-                       inode->i_mode |= S_ISGID;
+               /*
+                * 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;
+}
index 0bf0c54ac2f7bec7dd046c115f0e0d3cf31e2e5e..ecacfff82d722b948e39459383f5fb5d535ed777 100644 (file)
@@ -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__ */