Unverified Commit f736d93d authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Christian Brauner
Browse files

xfs: support idmapped mounts

Enable idmapped mounts for xfs. This basically just means passing down
the user_namespace argument from the VFS methods down to where it is
passed to the relevant helpers.

Note that full-filesystem bulkstat is not supported from inside idmapped
mounts as it is an administrative operation that acts on the whole file
system. The limitation is not applied to the bulkstat single operation
that just operates on a single inode.

Link: https://lore.kernel.org/r/20210121131959.646623-40-christian.brauner@ubuntu.com


Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarChristian Brauner <christian.brauner@ubuntu.com>
parent 14f3db55
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -253,8 +253,7 @@ xfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
		return error;

	if (type == ACL_TYPE_ACCESS) {
		error = posix_acl_update_mode(&init_user_ns, inode, &mode,
					      &acl);
		error = posix_acl_update_mode(mnt_userns, inode, &mode, &acl);
		if (error)
			return error;
		set_mode = true;
+3 −1
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include <linux/backing-dev.h>
#include <linux/mman.h>
#include <linux/fadvise.h>
#include <linux/mount.h>

static const struct vm_operations_struct xfs_file_vm_ops;

@@ -994,7 +995,8 @@ xfs_file_fallocate(

		iattr.ia_valid = ATTR_SIZE;
		iattr.ia_size = new_size;
		error = xfs_vn_setattr_size(file_dentry(file), &iattr);
		error = xfs_vn_setattr_size(file_mnt_user_ns(file),
					    file_dentry(file), &iattr);
		if (error)
			goto out_unlock;
	}
+18 −8
Original line number Diff line number Diff line
@@ -766,6 +766,7 @@ xfs_inode_inherit_flags2(
 */
static int
xfs_init_new_inode(
	struct user_namespace	*mnt_userns,
	struct xfs_trans	*tp,
	struct xfs_inode	*pip,
	xfs_ino_t		ino,
@@ -806,7 +807,7 @@ xfs_init_new_inode(
	inode = VFS_I(ip);
	inode->i_mode = mode;
	set_nlink(inode, nlink);
	inode->i_uid = current_fsuid();
	inode->i_uid = fsuid_into_mnt(mnt_userns);
	inode->i_rdev = rdev;
	ip->i_d.di_projid = prid;

@@ -815,7 +816,7 @@ xfs_init_new_inode(
		if ((VFS_I(pip)->i_mode & S_ISGID) && S_ISDIR(mode))
			inode->i_mode |= S_ISGID;
	} else {
		inode->i_gid = current_fsgid();
		inode->i_gid = fsgid_into_mnt(mnt_userns);
	}

	/*
@@ -824,7 +825,8 @@ xfs_init_new_inode(
	 * (and only if the irix_sgid_inherit compatibility variable is set).
	 */
	if (irix_sgid_inherit &&
	    (inode->i_mode & S_ISGID) && !in_group_p(inode->i_gid))
	    (inode->i_mode & S_ISGID) &&
	    !in_group_p(i_gid_into_mnt(mnt_userns, inode)))
		inode->i_mode &= ~S_ISGID;

	ip->i_d.di_size = 0;
@@ -901,6 +903,7 @@ xfs_init_new_inode(
 */
int
xfs_dir_ialloc(
	struct user_namespace	*mnt_userns,
	struct xfs_trans	**tpp,
	struct xfs_inode	*dp,
	umode_t			mode,
@@ -933,7 +936,8 @@ xfs_dir_ialloc(
		return error;
	ASSERT(ino != NULLFSINO);

	return xfs_init_new_inode(*tpp, dp, ino, mode, nlink, rdev, prid, ipp);
	return xfs_init_new_inode(mnt_userns, *tpp, dp, ino, mode, nlink, rdev,
				  prid, ipp);
}

/*
@@ -973,6 +977,7 @@ xfs_bumplink(

int
xfs_create(
	struct user_namespace	*mnt_userns,
	xfs_inode_t		*dp,
	struct xfs_name		*name,
	umode_t			mode,
@@ -1047,7 +1052,8 @@ xfs_create(
	 * entry pointing to them, but a directory also the "." entry
	 * pointing to itself.
	 */
	error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, prid, &ip);
	error = xfs_dir_ialloc(mnt_userns, &tp, dp, mode, is_dir ? 2 : 1, rdev,
			       prid, &ip);
	if (error)
		goto out_trans_cancel;

@@ -1128,6 +1134,7 @@ xfs_create(

int
xfs_create_tmpfile(
	struct user_namespace	*mnt_userns,
	struct xfs_inode	*dp,
	umode_t			mode,
	struct xfs_inode	**ipp)
@@ -1169,7 +1176,7 @@ xfs_create_tmpfile(
	if (error)
		goto out_trans_cancel;

	error = xfs_dir_ialloc(&tp, dp, mode, 0, 0, prid, &ip);
	error = xfs_dir_ialloc(mnt_userns, &tp, dp, mode, 0, 0, prid, &ip);
	if (error)
		goto out_trans_cancel;

@@ -2977,13 +2984,15 @@ xfs_cross_rename(
 */
static int
xfs_rename_alloc_whiteout(
	struct user_namespace	*mnt_userns,
	struct xfs_inode	*dp,
	struct xfs_inode	**wip)
{
	struct xfs_inode	*tmpfile;
	int			error;

	error = xfs_create_tmpfile(dp, S_IFCHR | WHITEOUT_MODE, &tmpfile);
	error = xfs_create_tmpfile(mnt_userns, dp, S_IFCHR | WHITEOUT_MODE,
				   &tmpfile);
	if (error)
		return error;

@@ -3005,6 +3014,7 @@ xfs_rename_alloc_whiteout(
 */
int
xfs_rename(
	struct user_namespace	*mnt_userns,
	struct xfs_inode	*src_dp,
	struct xfs_name		*src_name,
	struct xfs_inode	*src_ip,
@@ -3036,7 +3046,7 @@ xfs_rename(
	 */
	if (flags & RENAME_WHITEOUT) {
		ASSERT(!(flags & (RENAME_NOREPLACE | RENAME_EXCHANGE)));
		error = xfs_rename_alloc_whiteout(target_dp, &wip);
		error = xfs_rename_alloc_whiteout(mnt_userns, target_dp, &wip);
		if (error)
			return error;

+10 −6
Original line number Diff line number Diff line
@@ -369,15 +369,18 @@ int xfs_release(struct xfs_inode *ip);
void		xfs_inactive(struct xfs_inode *ip);
int		xfs_lookup(struct xfs_inode *dp, struct xfs_name *name,
			   struct xfs_inode **ipp, struct xfs_name *ci_name);
int		xfs_create(struct xfs_inode *dp, struct xfs_name *name,
int		xfs_create(struct user_namespace *mnt_userns,
			   struct xfs_inode *dp, struct xfs_name *name,
			   umode_t mode, dev_t rdev, struct xfs_inode **ipp);
int		xfs_create_tmpfile(struct xfs_inode *dp, umode_t mode,
int		xfs_create_tmpfile(struct user_namespace *mnt_userns,
			   struct xfs_inode *dp, umode_t mode,
			   struct xfs_inode **ipp);
int		xfs_remove(struct xfs_inode *dp, struct xfs_name *name,
			   struct xfs_inode *ip);
int		xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip,
			 struct xfs_name *target_name);
int		xfs_rename(struct xfs_inode *src_dp, struct xfs_name *src_name,
int		xfs_rename(struct user_namespace *mnt_userns,
			   struct xfs_inode *src_dp, struct xfs_name *src_name,
			   struct xfs_inode *src_ip, struct xfs_inode *target_dp,
			   struct xfs_name *target_name,
			   struct xfs_inode *target_ip, unsigned int flags);
@@ -407,9 +410,10 @@ void xfs_lock_two_inodes(struct xfs_inode *ip0, uint ip0_mode,
xfs_extlen_t	xfs_get_extsz_hint(struct xfs_inode *ip);
xfs_extlen_t	xfs_get_cowextsz_hint(struct xfs_inode *ip);

int xfs_dir_ialloc(struct xfs_trans **tpp, struct xfs_inode *dp, umode_t mode,
		   xfs_nlink_t nlink, dev_t dev, prid_t prid,
		   struct xfs_inode **ipp);
int		xfs_dir_ialloc(struct user_namespace *mnt_userns,
			       struct xfs_trans **tpp, struct xfs_inode *dp,
			       umode_t mode, xfs_nlink_t nlink, dev_t dev,
			       prid_t prid, struct xfs_inode **ipp);

static inline int
xfs_itruncate_extents(
+21 −14
Original line number Diff line number Diff line
@@ -693,7 +693,8 @@ xfs_ioc_space(

	iattr.ia_valid = ATTR_SIZE;
	iattr.ia_size = bf->l_start;
	error = xfs_vn_setattr_size(file_dentry(filp), &iattr);
	error = xfs_vn_setattr_size(file_mnt_user_ns(filp), file_dentry(filp),
				    &iattr);
	if (error)
		goto out_unlock;

@@ -734,13 +735,15 @@ xfs_fsinumbers_fmt(

STATIC int
xfs_ioc_fsbulkstat(
	xfs_mount_t		*mp,
	struct file		*file,
	unsigned int		cmd,
	void			__user *arg)
{
	struct xfs_mount	*mp = XFS_I(file_inode(file))->i_mount;
	struct xfs_fsop_bulkreq	bulkreq;
	struct xfs_ibulk	breq = {
		.mp		= mp,
		.mnt_userns	= file_mnt_user_ns(file),
		.ocount		= 0,
	};
	xfs_ino_t		lastino;
@@ -908,13 +911,15 @@ xfs_bulk_ireq_teardown(
/* Handle the v5 bulkstat ioctl. */
STATIC int
xfs_ioc_bulkstat(
	struct xfs_mount		*mp,
	struct file			*file,
	unsigned int			cmd,
	struct xfs_bulkstat_req __user	*arg)
{
	struct xfs_mount		*mp = XFS_I(file_inode(file))->i_mount;
	struct xfs_bulk_ireq		hdr;
	struct xfs_ibulk		breq = {
		.mp			= mp,
		.mnt_userns		= file_mnt_user_ns(file),
	};
	int				error;

@@ -1275,8 +1280,9 @@ xfs_ioctl_setattr_prepare_dax(
 */
static struct xfs_trans *
xfs_ioctl_setattr_get_trans(
	struct xfs_inode	*ip)
	struct file		*file)
{
	struct xfs_inode	*ip = XFS_I(file_inode(file));
	struct xfs_mount	*mp = ip->i_mount;
	struct xfs_trans	*tp;
	int			error = -EROFS;
@@ -1300,7 +1306,7 @@ xfs_ioctl_setattr_get_trans(
	 * The user ID of the calling process must be equal to the file owner
	 * ID, except in cases where the CAP_FSETID capability is applicable.
	 */
	if (!inode_owner_or_capable(&init_user_ns, VFS_I(ip))) {
	if (!inode_owner_or_capable(file_mnt_user_ns(file), VFS_I(ip))) {
		error = -EPERM;
		goto out_cancel;
	}
@@ -1428,9 +1434,11 @@ xfs_ioctl_setattr_check_projid(

STATIC int
xfs_ioctl_setattr(
	xfs_inode_t		*ip,
	struct file		*file,
	struct fsxattr		*fa)
{
	struct user_namespace	*mnt_userns = file_mnt_user_ns(file);
	struct xfs_inode	*ip = XFS_I(file_inode(file));
	struct fsxattr		old_fa;
	struct xfs_mount	*mp = ip->i_mount;
	struct xfs_trans	*tp;
@@ -1462,7 +1470,7 @@ xfs_ioctl_setattr(

	xfs_ioctl_setattr_prepare_dax(ip, fa);

	tp = xfs_ioctl_setattr_get_trans(ip);
	tp = xfs_ioctl_setattr_get_trans(file);
	if (IS_ERR(tp)) {
		code = PTR_ERR(tp);
		goto error_free_dquots;
@@ -1502,7 +1510,7 @@ xfs_ioctl_setattr(
	 */

	if ((VFS_I(ip)->i_mode & (S_ISUID|S_ISGID)) &&
	    !capable_wrt_inode_uidgid(&init_user_ns, VFS_I(ip), CAP_FSETID))
	    !capable_wrt_inode_uidgid(mnt_userns, VFS_I(ip), CAP_FSETID))
		VFS_I(ip)->i_mode &= ~(S_ISUID|S_ISGID);

	/* Change the ownerships and register project quota modifications */
@@ -1549,7 +1557,6 @@ xfs_ioctl_setattr(

STATIC int
xfs_ioc_fssetxattr(
	xfs_inode_t		*ip,
	struct file		*filp,
	void			__user *arg)
{
@@ -1562,7 +1569,7 @@ xfs_ioc_fssetxattr(
	error = mnt_want_write_file(filp);
	if (error)
		return error;
	error = xfs_ioctl_setattr(ip, &fa);
	error = xfs_ioctl_setattr(filp, &fa);
	mnt_drop_write_file(filp);
	return error;
}
@@ -1608,7 +1615,7 @@ xfs_ioc_setxflags(

	xfs_ioctl_setattr_prepare_dax(ip, &fa);

	tp = xfs_ioctl_setattr_get_trans(ip);
	tp = xfs_ioctl_setattr_get_trans(filp);
	if (IS_ERR(tp)) {
		error = PTR_ERR(tp);
		goto out_drop_write;
@@ -2119,10 +2126,10 @@ xfs_file_ioctl(
	case XFS_IOC_FSBULKSTAT_SINGLE:
	case XFS_IOC_FSBULKSTAT:
	case XFS_IOC_FSINUMBERS:
		return xfs_ioc_fsbulkstat(mp, cmd, arg);
		return xfs_ioc_fsbulkstat(filp, cmd, arg);

	case XFS_IOC_BULKSTAT:
		return xfs_ioc_bulkstat(mp, cmd, arg);
		return xfs_ioc_bulkstat(filp, cmd, arg);
	case XFS_IOC_INUMBERS:
		return xfs_ioc_inumbers(mp, cmd, arg);

@@ -2144,7 +2151,7 @@ xfs_file_ioctl(
	case XFS_IOC_FSGETXATTRA:
		return xfs_ioc_fsgetxattr(ip, 1, arg);
	case XFS_IOC_FSSETXATTR:
		return xfs_ioc_fssetxattr(ip, filp, arg);
		return xfs_ioc_fssetxattr(filp, arg);
	case XFS_IOC_GETXFLAGS:
		return xfs_ioc_getxflags(ip, arg);
	case XFS_IOC_SETXFLAGS:
Loading