@@ -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__ */
@@ -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__ */
@@ -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;
+}
@@ -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__ */