From: Darrick J. Wong <djwong@xxxxxxxxxx> 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@xxxxxxxxxx> --- 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(-) 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__ */