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 | 92 +++++++++++++++++++++++++++++++++++++++++--------- libxfs/libxfs_priv.h | 6 +++ 4 files changed, 84 insertions(+), 17 deletions(-) diff --git a/include/xfs_inode.h b/include/xfs_inode.h index bf8322ee2ec..4e8a3dc6fd8 100644 --- a/include/xfs_inode.h +++ b/include/xfs_inode.h @@ -295,4 +295,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 c67d0237686..1690660ed5b 100644 --- a/include/xfs_mount.h +++ b/include/xfs_mount.h @@ -218,6 +218,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 44d889f3f0f..d311abafd79 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) { @@ -81,31 +81,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->mnt_userns, 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; } @@ -120,12 +136,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 */ @@ -138,6 +153,21 @@ xfs_inode_init( ASSERT(0); } + /* + * If we need to create attributes immediately after allocating the + * inode, initialise an empty attribute fork right now. We use the + * default fork offset for attributes here as we don't know exactly what + * size or how many attributes we might be adding. We can do this + * safely here because we know the data fork is completely empty and + * this saves us from needing to run a separate transaction to set the + * fork offset in the immediate future. + */ + 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); + } + /* * Log the new values stuffed into the inode. */ @@ -261,15 +291,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; - /* * Call the space management code to pick the on-disk inode to be * allocated. @@ -321,6 +351,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); @@ -399,3 +430,30 @@ libxfs_irele( kmem_cache_free(xfs_inode_cache, ip); } } + +static inline void inode_fsuid_set(struct inode *inode, + struct user_namespace *mnt_userns) +{ + inode->i_uid = make_kuid(0); +} + +static inline void inode_fsgid_set(struct inode *inode, + struct user_namespace *mnt_userns) +{ + inode->i_gid = make_kgid(0); +} + +void inode_init_owner(struct user_namespace *mnt_userns, struct inode *inode, + const struct inode *dir, umode_t mode) +{ + inode_fsuid_set(inode, mnt_userns); + 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, mnt_userns); + inode->i_mode = mode; +} diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h index 716e711cde4..acad5ccd228 100644 --- a/libxfs/libxfs_priv.h +++ b/libxfs/libxfs_priv.h @@ -219,6 +219,12 @@ static inline bool WARN_ON(bool expr) { (inode)->i_version = (version); \ } while (0) +struct inode; +struct user_namespace; + +void inode_init_owner(struct user_namespace *mnt_userns, struct inode *inode, + const struct inode *dir, umode_t mode); + #define __must_check __attribute__((__warn_unused_result__)) /*