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