@@ -7,6 +7,31 @@
#ifndef __XFS_INODE_H__
#define __XFS_INODE_H__
+/*
+ * Borrow the kernel's uid/gid types. These are used by xfs_inode_util.h, so
+ * they must come first in the header file.
+ */
+
+typedef struct {
+ uid_t val;
+} kuid_t;
+
+typedef struct {
+ gid_t val;
+} kgid_t;
+
+static inline kuid_t make_kuid(uid_t uid)
+{
+ kuid_t v = { .val = uid };
+ return v;
+}
+
+static inline kgid_t make_kgid(gid_t gid)
+{
+ kgid_t v = { .val = gid };
+ return v;
+}
+
/* These match kernel side includes */
#include "xfs_inode_buf.h"
#include "xfs_inode_fork.h"
@@ -33,8 +58,8 @@ struct xfs_inode_log_item;
*/
struct inode {
mode_t i_mode;
- uint32_t i_uid;
- uint32_t i_gid;
+ kuid_t i_uid;
+ kgid_t i_gid;
uint32_t i_nlink;
xfs_dev_t i_rdev; /* This actually holds xfs_dev_t */
unsigned int i_count;
@@ -49,19 +74,19 @@ struct inode {
static inline uint32_t i_uid_read(struct inode *inode)
{
- return inode->i_uid;
+ return inode->i_uid.val;
}
static inline uint32_t i_gid_read(struct inode *inode)
{
- return inode->i_gid;
+ return inode->i_gid.val;
}
static inline void i_uid_write(struct inode *inode, uint32_t uid)
{
- inode->i_uid = uid;
+ inode->i_uid.val = uid;
}
static inline void i_gid_write(struct inode *inode, uint32_t gid)
{
- inode->i_gid = gid;
+ inode->i_gid.val = gid;
}
static inline void ihold(struct inode *inode)
@@ -64,17 +64,13 @@ xfs_inode_propagate_flags(
* caller locked exclusively.
*/
static int
-libxfs_init_new_inode(
+libxfs_icreate(
struct xfs_trans *tp,
- struct xfs_inode *pip,
xfs_ino_t ino,
- umode_t mode,
- xfs_nlink_t nlink,
- dev_t rdev,
- struct cred *cr,
- struct fsxattr *fsx,
+ const struct xfs_icreate_args *args,
struct xfs_inode **ipp)
{
+ struct xfs_inode *pip = args->pip;
struct xfs_inode *ip;
unsigned int flags;
int error;
@@ -84,48 +80,41 @@ libxfs_init_new_inode(
return error;
ASSERT(ip != NULL);
- VFS_I(ip)->i_mode = mode;
- set_nlink(VFS_I(ip), nlink);
- i_uid_write(VFS_I(ip), cr->cr_uid);
- i_gid_write(VFS_I(ip), cr->cr_gid);
- ip->i_projid = pip ? 0 : fsx->fsx_projid;
+ VFS_I(ip)->i_mode = args->mode;
+ set_nlink(VFS_I(ip), args->nlink);
+ VFS_I(ip)->i_uid = args->uid;
+ ip->i_projid = args->prid;
xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG | XFS_ICHGTIME_MOD);
if (pip && (VFS_I(pip)->i_mode & S_ISGID)) {
- if (!(cr->cr_flags & CRED_FORCE_GID))
+ 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) && (mode & S_IFMT) == S_IFDIR)
+ 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;
ip->i_disk_size = 0;
ip->i_df.if_nextents = 0;
ASSERT(ip->i_nblocks == 0);
- ip->i_extsize = pip ? 0 : fsx->fsx_extsize;
- ip->i_diflags = pip ? 0 : xfs_flags2diflags(ip, fsx->fsx_xflags);
-
+ 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;
- if (!pip)
- ip->i_diflags2 = xfs_flags2diflags2(ip,
- fsx->fsx_xflags);
- ip->i_crtime = VFS_I(ip)->i_mtime; /* struct copy */
- ip->i_cowextsize = pip ? 0 : fsx->fsx_cowextsize;
+ ip->i_crtime = VFS_I(ip)->i_mtime;
+ ip->i_cowextsize = 0;
}
flags = XFS_ILOG_CORE;
- switch (mode & S_IFMT) {
+ switch (args->mode & S_IFMT) {
case S_IFIFO:
case S_IFSOCK:
- /* doesn't make sense to set an rdev for these */
- rdev = 0;
- /* FALLTHROUGH */
case S_IFCHR:
case S_IFBLK:
ip->i_df.if_format = XFS_DINODE_FMT_DEV;
flags |= XFS_ILOG_DEV;
- VFS_I(ip)->i_rdev = rdev;
+ VFS_I(ip)->i_rdev = args->rdev;
break;
case S_IFREG:
case S_IFDIR:
@@ -235,10 +224,22 @@ libxfs_dir_ialloc(
struct fsxattr *fsx,
struct xfs_inode **ipp)
{
+ struct xfs_icreate_args args = {
+ .pip = dp,
+ .uid = make_kuid(cr->cr_uid),
+ .gid = make_kgid(cr->cr_gid),
+ .nlink = nlink,
+ .rdev = rdev,
+ .mode = 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.
@@ -247,8 +248,22 @@ libxfs_dir_ialloc(
if (error)
return error;
- return libxfs_init_new_inode(*tpp, dp, ino, mode, nlink, rdev, cr,
- fsx, ipp);
+ error = libxfs_icreate(*tpp, ino, &args, ipp);
+ if (error || dp)
+ return error;
+
+ /* If there is no parent dir, initialize the file from fsxattr data. */
+ ip = *ipp;
+ ip->i_projid = fsx->fsx_projid;
+ ip->i_extsize = fsx->fsx_extsize;
+ ip->i_diflags = xfs_flags2diflags(ip, fsx->fsx_xflags);
+
+ if (xfs_has_v3inodes(ip->i_mount)) {
+ ip->i_diflags2 = xfs_flags2diflags2(ip, fsx->fsx_xflags);
+ ip->i_cowextsize = fsx->fsx_cowextsize;
+ }
+ xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE);
+ return 0;
}
/*
@@ -13,4 +13,35 @@ uint32_t xfs_ip2xflags(struct xfs_inode *ip);
prid_t xfs_get_initial_prid(struct xfs_inode *dp);
+/*
+ * Initial ids, link count, device number, and mode of a new inode.
+ *
+ * Due to our only partial reliance on the VFS to propagate uid and gid values
+ * according to accepted Unix behaviors, callers must initialize mnt_userns to
+ * the appropriate namespace, uid to fsuid_into_mnt(), and gid to
+ * fsgid_into_mnt() to get the correct inheritance behaviors when
+ * XFS_MOUNT_GRPID is set. Use the xfs_ialloc_inherit_args() helper.
+ *
+ * To override the default ids, use the FORCE flags defined below.
+ */
+struct xfs_icreate_args {
+ struct user_namespace *mnt_userns;
+ struct xfs_inode *pip; /* parent inode or null */
+
+ kuid_t uid;
+ kgid_t gid;
+ prid_t prid;
+
+ xfs_nlink_t nlink;
+ dev_t rdev;
+
+ umode_t mode;
+
+#define XFS_ICREATE_ARGS_FORCE_UID (1 << 0)
+#define XFS_ICREATE_ARGS_FORCE_GID (1 << 1)
+#define XFS_ICREATE_ARGS_FORCE_MODE (1 << 2)
+#define XFS_ICREATE_ARGS_INIT_XATTRS (1 << 3)
+ uint16_t flags;
+};
+
#endif /* __XFS_INODE_UTIL_H__ */