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 | 2 + include/xfs_mount.h | 1 + libxfs/inode.c | 80 +++++++++++++++++++++++++++++++++++++++----------- libxfs/libxfs_priv.h | 6 ++++ 4 files changed, 71 insertions(+), 18 deletions(-) diff --git a/include/xfs_inode.h b/include/xfs_inode.h index 04d971e744b..45d53d1eb00 100644 --- a/include/xfs_inode.h +++ b/include/xfs_inode.h @@ -398,4 +398,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 ec63c525fd4..da621f3b992 100644 --- a/include/xfs_mount.h +++ b/include/xfs_mount.h @@ -232,6 +232,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 */ diff --git a/libxfs/inode.c b/libxfs/inode.c index b61ad0f9e09..3d92e888a16 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) { @@ -99,31 +99,47 @@ xfs_inode_init( struct xfs_inode *ip) { struct xfs_inode *pip = args->pip; + struct inode *dir = pip ? VFS_I(pip) : NULL; + struct xfs_mount *mp = tp->t_mountp; + struct inode *inode = VFS_I(ip); unsigned int flags; int times = XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG | XFS_ICHGTIME_ACCESS; - VFS_I(ip)->i_mode = args->mode; - set_nlink(VFS_I(ip), args->nlink); - VFS_I(ip)->i_uid = args->uid; + set_nlink(inode, args->nlink); + inode->i_rdev = args->rdev; ip->i_projid = args->prid; - if (pip && (VFS_I(pip)->i_mode & S_ISGID)) { - if (!(args->flags & XFS_ICREATE_ARGS_FORCE_GID)) - VFS_I(ip)->i_gid = VFS_I(pip)->i_gid; - if ((VFS_I(pip)->i_mode & S_ISGID) && S_ISDIR(args->mode)) - VFS_I(ip)->i_mode |= S_ISGID; - } else - VFS_I(ip)->i_gid = args->gid; + if (dir && !(dir->i_mode & S_ISGID) && + xfs_has_grpid(mp)) { + inode->i_uid = args->uid; + inode->i_gid = dir->i_gid; + inode->i_mode = args->mode; + } else { + inode_init_owner(args->idmap, inode, dir, args->mode); + } + + /* struct copies */ + if (args->flags & XFS_ICREATE_ARGS_FORCE_UID) + inode->i_uid = args->uid; + else + ASSERT(uid_eq(inode->i_uid, args->uid)); + if (args->flags & XFS_ICREATE_ARGS_FORCE_GID) + inode->i_gid = args->gid; + else if (!pip || !XFS_INHERIT_GID(pip)) + ASSERT(gid_eq(inode->i_gid, args->gid)); + if (args->flags & XFS_ICREATE_ARGS_FORCE_MODE) + inode->i_mode = args->mode; 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)) { VFS_I(ip)->i_version = 1; - ip->i_diflags2 = ip->i_mount->m_ino_geo.new_diflags2; ip->i_cowextsize = 0; times |= XFS_ICHGTIME_CREATE; } @@ -138,12 +154,11 @@ 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 */ @@ -165,7 +180,8 @@ xfs_inode_init( * this saves us from needing to run a separate transaction to set the * fork offset in the immediate future. */ - if (xfs_has_parent(tp->t_mountp) && xfs_has_attr(tp->t_mountp)) { + if ((args->flags & XFS_ICREATE_ARGS_INIT_XATTRS) && + xfs_has_attr(mp)) { ip->i_forkoff = xfs_default_attroffset(ip) >> 3; xfs_ifork_init_attr(ip, XFS_DINODE_FMT_EXTENTS, 0); } @@ -293,15 +309,15 @@ libxfs_dir_ialloc( .nlink = nlink, .rdev = rdev, .mode = mode, + .flags = XFS_ICREATE_ARGS_FORCE_UID | + XFS_ICREATE_ARGS_FORCE_GID | + XFS_ICREATE_ARGS_FORCE_MODE, }; struct xfs_inode *ip; xfs_ino_t parent_ino = dp ? dp->i_ino : 0; xfs_ino_t ino; int error; - if (cr->cr_flags & CRED_FORCE_GID) - args.flags |= XFS_ICREATE_ARGS_FORCE_GID; - if (dp && xfs_has_parent(dp->i_mount)) args.flags |= XFS_ICREATE_ARGS_INIT_XATTRS; @@ -361,6 +377,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); @@ -442,3 +459,30 @@ libxfs_irele( kmem_cache_free(xfs_inode_cache, ip); } } + +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); +} + +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 90149b60c57..1609a8fd03f 100644 --- a/libxfs/libxfs_priv.h +++ b/libxfs/libxfs_priv.h @@ -220,6 +220,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__)) /*