diff options
author | Darrick J. Wong <darrick.wong@oracle.com> | 2019-07-01 08:25:35 -0700 |
---|---|---|
committer | Darrick J. Wong <darrick.wong@oracle.com> | 2019-07-01 08:25:35 -0700 |
commit | 7b0e492e6b80d51db4156996b248522c7b50d467 (patch) | |
tree | 7b7e23b0a4bc9c2a97b1af4cb977cf0a5033ca59 /fs/xfs | |
parent | 5aca284210ce827f780ea2f4f9c6ab8d6e2d6648 (diff) | |
download | linux-7b0e492e6b80d51db4156996b248522c7b50d467.tar.bz2 |
vfs: create a generic checking function for FS_IOC_FSSETXATTR
Create a generic checking function for the incoming FS_IOC_FSSETXATTR
fsxattr values so that we can standardize some of the implementation
behaviors.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/xfs')
-rw-r--r-- | fs/xfs/xfs_ioctl.c | 69 |
1 files changed, 40 insertions, 29 deletions
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index d7dfc13f30f5..458a7043b4d2 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -879,37 +879,44 @@ xfs_di2lxflags( return flags; } -STATIC int -xfs_ioc_fsgetxattr( - xfs_inode_t *ip, - int attr, - void __user *arg) +static void +xfs_fill_fsxattr( + struct xfs_inode *ip, + bool attr, + struct fsxattr *fa) { - struct fsxattr fa; - - memset(&fa, 0, sizeof(struct fsxattr)); - - xfs_ilock(ip, XFS_ILOCK_SHARED); - fa.fsx_xflags = xfs_ip2xflags(ip); - fa.fsx_extsize = ip->i_d.di_extsize << ip->i_mount->m_sb.sb_blocklog; - fa.fsx_cowextsize = ip->i_d.di_cowextsize << + simple_fill_fsxattr(fa, xfs_ip2xflags(ip)); + fa->fsx_extsize = ip->i_d.di_extsize << ip->i_mount->m_sb.sb_blocklog; + fa->fsx_cowextsize = ip->i_d.di_cowextsize << ip->i_mount->m_sb.sb_blocklog; - fa.fsx_projid = xfs_get_projid(ip); + fa->fsx_projid = xfs_get_projid(ip); if (attr) { if (ip->i_afp) { if (ip->i_afp->if_flags & XFS_IFEXTENTS) - fa.fsx_nextents = xfs_iext_count(ip->i_afp); + fa->fsx_nextents = xfs_iext_count(ip->i_afp); else - fa.fsx_nextents = ip->i_d.di_anextents; + fa->fsx_nextents = ip->i_d.di_anextents; } else - fa.fsx_nextents = 0; + fa->fsx_nextents = 0; } else { if (ip->i_df.if_flags & XFS_IFEXTENTS) - fa.fsx_nextents = xfs_iext_count(&ip->i_df); + fa->fsx_nextents = xfs_iext_count(&ip->i_df); else - fa.fsx_nextents = ip->i_d.di_nextents; + fa->fsx_nextents = ip->i_d.di_nextents; } +} + +STATIC int +xfs_ioc_fsgetxattr( + xfs_inode_t *ip, + int attr, + void __user *arg) +{ + struct fsxattr fa; + + xfs_ilock(ip, XFS_ILOCK_SHARED); + xfs_fill_fsxattr(ip, attr, &fa); xfs_iunlock(ip, XFS_ILOCK_SHARED); if (copy_to_user(arg, &fa, sizeof(fa))) @@ -1035,15 +1042,6 @@ xfs_ioctl_setattr_xflags( if ((fa->fsx_xflags & FS_XFLAG_DAX) && xfs_is_reflink_inode(ip)) return -EINVAL; - /* - * Can't modify an immutable/append-only file unless - * we have appropriate permission. - */ - if (((ip->i_d.di_flags & (XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND)) || - (fa->fsx_xflags & (FS_XFLAG_IMMUTABLE | FS_XFLAG_APPEND))) && - !capable(CAP_LINUX_IMMUTABLE)) - return -EPERM; - /* diflags2 only valid for v3 inodes. */ di_flags2 = xfs_flags2diflags2(ip, fa->fsx_xflags); if (di_flags2 && ip->i_d.di_version < 3) @@ -1323,6 +1321,7 @@ xfs_ioctl_setattr( xfs_inode_t *ip, struct fsxattr *fa) { + struct fsxattr old_fa; struct xfs_mount *mp = ip->i_mount; struct xfs_trans *tp; struct xfs_dquot *udqp = NULL; @@ -1370,7 +1369,6 @@ xfs_ioctl_setattr( goto error_free_dquots; } - if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp) && xfs_get_projid(ip) != fa->fsx_projid) { code = xfs_qm_vop_chown_reserve(tp, ip, udqp, NULL, pdqp, @@ -1379,6 +1377,11 @@ xfs_ioctl_setattr( goto error_trans_cancel; } + xfs_fill_fsxattr(ip, false, &old_fa); + code = vfs_ioc_fssetxattr_check(VFS_I(ip), &old_fa, fa); + if (code) + goto error_trans_cancel; + code = xfs_ioctl_setattr_check_extsize(ip, fa); if (code) goto error_trans_cancel; @@ -1489,6 +1492,7 @@ xfs_ioc_setxflags( { struct xfs_trans *tp; struct fsxattr fa; + struct fsxattr old_fa; unsigned int flags; int join_flags = 0; int error; @@ -1524,6 +1528,13 @@ xfs_ioc_setxflags( goto out_drop_write; } + xfs_fill_fsxattr(ip, false, &old_fa); + error = vfs_ioc_fssetxattr_check(VFS_I(ip), &old_fa, &fa); + if (error) { + xfs_trans_cancel(tp); + goto out_drop_write; + } + error = xfs_ioctl_setattr_xflags(tp, ip, &fa); if (error) { xfs_trans_cancel(tp); |