mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
[XFS] xfs_setattr currently doesn't just handle the attributes set through
->setattr but also addition XFS-specific attributes: project id, inode flags and extent size hint. Having these in a single function makes it more complicated and forces to have us a bhv_vattr intermediate structure eating up stackspace. This patch adds a new xfs_ioctl_setattr helper for the XFS ioctls that set these attributes and remove the code to set them through xfs_setattr. SGI-PV: 984564 SGI-Modid: xfs-linux-melb:xfs-kern:31677a Signed-off-by: Christoph Hellwig <hch@infradead.org> Signed-off-by: Tim Shimmin <tes@sgi.com> Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
This commit is contained in:
parent
c032bfcf46
commit
25fe55e814
@ -48,6 +48,8 @@
|
||||
#include "xfs_dfrag.h"
|
||||
#include "xfs_fsops.h"
|
||||
#include "xfs_vnodeops.h"
|
||||
#include "xfs_quota.h"
|
||||
#include "xfs_inode_item.h"
|
||||
|
||||
#include <linux/capability.h>
|
||||
#include <linux/dcache.h>
|
||||
@ -879,6 +881,297 @@ xfs_ioc_fsgetxattr(
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC void
|
||||
xfs_set_diflags(
|
||||
struct xfs_inode *ip,
|
||||
unsigned int xflags)
|
||||
{
|
||||
unsigned int di_flags;
|
||||
|
||||
/* can't set PREALLOC this way, just preserve it */
|
||||
di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC);
|
||||
if (xflags & XFS_XFLAG_IMMUTABLE)
|
||||
di_flags |= XFS_DIFLAG_IMMUTABLE;
|
||||
if (xflags & XFS_XFLAG_APPEND)
|
||||
di_flags |= XFS_DIFLAG_APPEND;
|
||||
if (xflags & XFS_XFLAG_SYNC)
|
||||
di_flags |= XFS_DIFLAG_SYNC;
|
||||
if (xflags & XFS_XFLAG_NOATIME)
|
||||
di_flags |= XFS_DIFLAG_NOATIME;
|
||||
if (xflags & XFS_XFLAG_NODUMP)
|
||||
di_flags |= XFS_DIFLAG_NODUMP;
|
||||
if (xflags & XFS_XFLAG_PROJINHERIT)
|
||||
di_flags |= XFS_DIFLAG_PROJINHERIT;
|
||||
if (xflags & XFS_XFLAG_NODEFRAG)
|
||||
di_flags |= XFS_DIFLAG_NODEFRAG;
|
||||
if (xflags & XFS_XFLAG_FILESTREAM)
|
||||
di_flags |= XFS_DIFLAG_FILESTREAM;
|
||||
if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
|
||||
if (xflags & XFS_XFLAG_RTINHERIT)
|
||||
di_flags |= XFS_DIFLAG_RTINHERIT;
|
||||
if (xflags & XFS_XFLAG_NOSYMLINKS)
|
||||
di_flags |= XFS_DIFLAG_NOSYMLINKS;
|
||||
if (xflags & XFS_XFLAG_EXTSZINHERIT)
|
||||
di_flags |= XFS_DIFLAG_EXTSZINHERIT;
|
||||
} else if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) {
|
||||
if (xflags & XFS_XFLAG_REALTIME)
|
||||
di_flags |= XFS_DIFLAG_REALTIME;
|
||||
if (xflags & XFS_XFLAG_EXTSIZE)
|
||||
di_flags |= XFS_DIFLAG_EXTSIZE;
|
||||
}
|
||||
|
||||
ip->i_d.di_flags = di_flags;
|
||||
}
|
||||
|
||||
|
||||
#define FSX_PROJID 1
|
||||
#define FSX_EXTSIZE 2
|
||||
#define FSX_XFLAGS 4
|
||||
#define FSX_NONBLOCK 8
|
||||
|
||||
STATIC int
|
||||
xfs_ioctl_setattr(
|
||||
xfs_inode_t *ip,
|
||||
struct fsxattr *fa,
|
||||
int mask)
|
||||
{
|
||||
struct xfs_mount *mp = ip->i_mount;
|
||||
struct xfs_trans *tp;
|
||||
unsigned int lock_flags = 0;
|
||||
struct xfs_dquot *udqp = NULL, *gdqp = NULL;
|
||||
struct xfs_dquot *olddquot = NULL;
|
||||
int code;
|
||||
|
||||
xfs_itrace_entry(ip);
|
||||
|
||||
if (mp->m_flags & XFS_MOUNT_RDONLY)
|
||||
return XFS_ERROR(EROFS);
|
||||
if (XFS_FORCED_SHUTDOWN(mp))
|
||||
return XFS_ERROR(EIO);
|
||||
|
||||
/*
|
||||
* If disk quotas is on, we make sure that the dquots do exist on disk,
|
||||
* before we start any other transactions. Trying to do this later
|
||||
* is messy. We don't care to take a readlock to look at the ids
|
||||
* in inode here, because we can't hold it across the trans_reserve.
|
||||
* If the IDs do change before we take the ilock, we're covered
|
||||
* because the i_*dquot fields will get updated anyway.
|
||||
*/
|
||||
if (XFS_IS_QUOTA_ON(mp) && (mask & FSX_PROJID)) {
|
||||
code = XFS_QM_DQVOPALLOC(mp, ip, ip->i_d.di_uid,
|
||||
ip->i_d.di_gid, fa->fsx_projid,
|
||||
XFS_QMOPT_PQUOTA, &udqp, &gdqp);
|
||||
if (code)
|
||||
return code;
|
||||
}
|
||||
|
||||
/*
|
||||
* For the other attributes, we acquire the inode lock and
|
||||
* first do an error checking pass.
|
||||
*/
|
||||
tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);
|
||||
code = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0);
|
||||
if (code)
|
||||
goto error_return;
|
||||
|
||||
lock_flags = XFS_ILOCK_EXCL;
|
||||
xfs_ilock(ip, lock_flags);
|
||||
|
||||
/*
|
||||
* CAP_FOWNER overrides the following restrictions:
|
||||
*
|
||||
* 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 (current->fsuid != ip->i_d.di_uid && !capable(CAP_FOWNER)) {
|
||||
code = XFS_ERROR(EPERM);
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do a quota reservation only if projid is actually going to change.
|
||||
*/
|
||||
if (mask & FSX_PROJID) {
|
||||
if (XFS_IS_PQUOTA_ON(mp) &&
|
||||
ip->i_d.di_projid != fa->fsx_projid) {
|
||||
ASSERT(tp);
|
||||
code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp,
|
||||
capable(CAP_FOWNER) ?
|
||||
XFS_QMOPT_FORCE_RES : 0);
|
||||
if (code) /* out of quota */
|
||||
goto error_return;
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & FSX_EXTSIZE) {
|
||||
/*
|
||||
* Can't change extent size if any extents are allocated.
|
||||
*/
|
||||
if (ip->i_d.di_nextents &&
|
||||
((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) !=
|
||||
fa->fsx_extsize)) {
|
||||
code = XFS_ERROR(EINVAL); /* EFBIG? */
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extent size must be a multiple of the appropriate block
|
||||
* size, if set at all.
|
||||
*/
|
||||
if (fa->fsx_extsize != 0) {
|
||||
xfs_extlen_t size;
|
||||
|
||||
if (XFS_IS_REALTIME_INODE(ip) ||
|
||||
((mask & FSX_XFLAGS) &&
|
||||
(fa->fsx_xflags & XFS_XFLAG_REALTIME))) {
|
||||
size = mp->m_sb.sb_rextsize <<
|
||||
mp->m_sb.sb_blocklog;
|
||||
} else {
|
||||
size = mp->m_sb.sb_blocksize;
|
||||
}
|
||||
|
||||
if (fa->fsx_extsize % size) {
|
||||
code = XFS_ERROR(EINVAL);
|
||||
goto error_return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (mask & FSX_XFLAGS) {
|
||||
/*
|
||||
* Can't change realtime flag if any extents are allocated.
|
||||
*/
|
||||
if ((ip->i_d.di_nextents || ip->i_delayed_blks) &&
|
||||
(XFS_IS_REALTIME_INODE(ip)) !=
|
||||
(fa->fsx_xflags & XFS_XFLAG_REALTIME)) {
|
||||
code = XFS_ERROR(EINVAL); /* EFBIG? */
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If realtime flag is set then must have realtime data.
|
||||
*/
|
||||
if ((fa->fsx_xflags & XFS_XFLAG_REALTIME)) {
|
||||
if ((mp->m_sb.sb_rblocks == 0) ||
|
||||
(mp->m_sb.sb_rextsize == 0) ||
|
||||
(ip->i_d.di_extsize % mp->m_sb.sb_rextsize)) {
|
||||
code = XFS_ERROR(EINVAL);
|
||||
goto error_return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 &
|
||||
(XFS_XFLAG_IMMUTABLE | XFS_XFLAG_APPEND))) &&
|
||||
!capable(CAP_LINUX_IMMUTABLE)) {
|
||||
code = XFS_ERROR(EPERM);
|
||||
goto error_return;
|
||||
}
|
||||
}
|
||||
|
||||
xfs_trans_ijoin(tp, ip, lock_flags);
|
||||
xfs_trans_ihold(tp, ip);
|
||||
|
||||
/*
|
||||
* Change file ownership. Must be the owner or privileged.
|
||||
* If the system was configured with the "restricted_chown"
|
||||
* option, the owner is not permitted to give away the file,
|
||||
* and can change the group id only to a group of which he
|
||||
* or she is a member.
|
||||
*/
|
||||
if (mask & FSX_PROJID) {
|
||||
/*
|
||||
* CAP_FSETID overrides the following restrictions:
|
||||
*
|
||||
* The set-user-ID and set-group-ID bits of a file will be
|
||||
* cleared upon successful return from chown()
|
||||
*/
|
||||
if ((ip->i_d.di_mode & (S_ISUID|S_ISGID)) &&
|
||||
!capable(CAP_FSETID))
|
||||
ip->i_d.di_mode &= ~(S_ISUID|S_ISGID);
|
||||
|
||||
/*
|
||||
* Change the ownerships and register quota modifications
|
||||
* in the transaction.
|
||||
*/
|
||||
if (ip->i_d.di_projid != fa->fsx_projid) {
|
||||
if (XFS_IS_PQUOTA_ON(mp)) {
|
||||
olddquot = XFS_QM_DQVOPCHOWN(mp, tp, ip,
|
||||
&ip->i_gdquot, gdqp);
|
||||
}
|
||||
ip->i_d.di_projid = fa->fsx_projid;
|
||||
|
||||
/*
|
||||
* We may have to rev the inode as well as
|
||||
* the superblock version number since projids didn't
|
||||
* exist before DINODE_VERSION_2 and SB_VERSION_NLINK.
|
||||
*/
|
||||
if (ip->i_d.di_version == XFS_DINODE_VERSION_1)
|
||||
xfs_bump_ino_vers2(tp, ip);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (mask & FSX_EXTSIZE)
|
||||
ip->i_d.di_extsize = fa->fsx_extsize >> mp->m_sb.sb_blocklog;
|
||||
if (mask & FSX_XFLAGS)
|
||||
xfs_set_diflags(ip, fa->fsx_xflags);
|
||||
|
||||
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
|
||||
xfs_ichgtime(ip, XFS_ICHGTIME_CHG);
|
||||
|
||||
XFS_STATS_INC(xs_ig_attrchg);
|
||||
|
||||
/*
|
||||
* If this is a synchronous mount, make sure that the
|
||||
* transaction goes to disk before returning to the user.
|
||||
* This is slightly sub-optimal in that truncates require
|
||||
* two sync transactions instead of one for wsync filesystems.
|
||||
* One for the truncate and one for the timestamps since we
|
||||
* don't want to change the timestamps unless we're sure the
|
||||
* truncate worked. Truncates are less than 1% of the laddis
|
||||
* mix so this probably isn't worth the trouble to optimize.
|
||||
*/
|
||||
if (mp->m_flags & XFS_MOUNT_WSYNC)
|
||||
xfs_trans_set_sync(tp);
|
||||
code = xfs_trans_commit(tp, 0);
|
||||
xfs_iunlock(ip, lock_flags);
|
||||
|
||||
/*
|
||||
* Release any dquot(s) the inode had kept before chown.
|
||||
*/
|
||||
XFS_QM_DQRELE(mp, olddquot);
|
||||
XFS_QM_DQRELE(mp, udqp);
|
||||
XFS_QM_DQRELE(mp, gdqp);
|
||||
|
||||
if (code)
|
||||
return code;
|
||||
|
||||
if (DM_EVENT_ENABLED(ip, DM_EVENT_ATTRIBUTE)) {
|
||||
XFS_SEND_NAMESP(mp, DM_EVENT_ATTRIBUTE, ip, DM_RIGHT_NULL,
|
||||
NULL, DM_RIGHT_NULL, NULL, NULL, 0, 0,
|
||||
(mask & FSX_NONBLOCK) ? DM_FLAGS_NDELAY : 0);
|
||||
}
|
||||
|
||||
vn_revalidate(XFS_ITOV(ip)); /* update flags */
|
||||
return 0;
|
||||
|
||||
error_return:
|
||||
XFS_QM_DQRELE(mp, udqp);
|
||||
XFS_QM_DQRELE(mp, gdqp);
|
||||
xfs_trans_cancel(tp, 0);
|
||||
if (lock_flags)
|
||||
xfs_iunlock(ip, lock_flags);
|
||||
return code;
|
||||
}
|
||||
|
||||
STATIC int
|
||||
xfs_ioc_fssetxattr(
|
||||
xfs_inode_t *ip,
|
||||
@ -886,31 +1179,16 @@ xfs_ioc_fssetxattr(
|
||||
void __user *arg)
|
||||
{
|
||||
struct fsxattr fa;
|
||||
struct bhv_vattr *vattr;
|
||||
int error;
|
||||
int attr_flags;
|
||||
unsigned int mask;
|
||||
|
||||
if (copy_from_user(&fa, arg, sizeof(fa)))
|
||||
return -EFAULT;
|
||||
|
||||
vattr = kmalloc(sizeof(*vattr), GFP_KERNEL);
|
||||
if (unlikely(!vattr))
|
||||
return -ENOMEM;
|
||||
|
||||
attr_flags = 0;
|
||||
mask = FSX_XFLAGS | FSX_EXTSIZE | FSX_PROJID;
|
||||
if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
|
||||
attr_flags |= ATTR_NONBLOCK;
|
||||
mask |= FSX_NONBLOCK;
|
||||
|
||||
vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | XFS_AT_PROJID;
|
||||
vattr->va_xflags = fa.fsx_xflags;
|
||||
vattr->va_extsize = fa.fsx_extsize;
|
||||
vattr->va_projid = fa.fsx_projid;
|
||||
|
||||
error = -xfs_setattr(ip, vattr, attr_flags, NULL);
|
||||
if (!error)
|
||||
vn_revalidate(XFS_ITOV(ip)); /* update flags */
|
||||
kfree(vattr);
|
||||
return 0;
|
||||
return -xfs_ioctl_setattr(ip, &fa, mask);
|
||||
}
|
||||
|
||||
STATIC int
|
||||
@ -932,10 +1210,9 @@ xfs_ioc_setxflags(
|
||||
struct file *filp,
|
||||
void __user *arg)
|
||||
{
|
||||
struct bhv_vattr *vattr;
|
||||
struct fsxattr fa;
|
||||
unsigned int flags;
|
||||
int attr_flags;
|
||||
int error;
|
||||
unsigned int mask;
|
||||
|
||||
if (copy_from_user(&flags, arg, sizeof(flags)))
|
||||
return -EFAULT;
|
||||
@ -945,22 +1222,12 @@ xfs_ioc_setxflags(
|
||||
FS_SYNC_FL))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
vattr = kmalloc(sizeof(*vattr), GFP_KERNEL);
|
||||
if (unlikely(!vattr))
|
||||
return -ENOMEM;
|
||||
|
||||
attr_flags = 0;
|
||||
mask = FSX_XFLAGS;
|
||||
if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
|
||||
attr_flags |= ATTR_NONBLOCK;
|
||||
mask |= FSX_NONBLOCK;
|
||||
fa.fsx_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip));
|
||||
|
||||
vattr->va_mask = XFS_AT_XFLAGS;
|
||||
vattr->va_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip));
|
||||
|
||||
error = -xfs_setattr(ip, vattr, attr_flags, NULL);
|
||||
if (likely(!error))
|
||||
vn_revalidate(XFS_ITOV(ip)); /* update flags */
|
||||
kfree(vattr);
|
||||
return error;
|
||||
return -xfs_ioctl_setattr(ip, &fa, mask);
|
||||
}
|
||||
|
||||
STATIC int
|
||||
|
@ -117,26 +117,11 @@ typedef struct bhv_vattr {
|
||||
#define XFS_AT_ACL 0x00080000
|
||||
#define XFS_AT_CAP 0x00100000
|
||||
#define XFS_AT_INF 0x00200000
|
||||
#define XFS_AT_XFLAGS 0x00400000
|
||||
#define XFS_AT_EXTSIZE 0x00800000
|
||||
#define XFS_AT_NEXTENTS 0x01000000
|
||||
#define XFS_AT_ANEXTENTS 0x02000000
|
||||
#define XFS_AT_PROJID 0x04000000
|
||||
#define XFS_AT_SIZE_NOPERM 0x08000000
|
||||
#define XFS_AT_GENCOUNT 0x10000000
|
||||
|
||||
#define XFS_AT_ALL (XFS_AT_TYPE|XFS_AT_MODE|XFS_AT_UID|XFS_AT_GID|\
|
||||
XFS_AT_FSID|XFS_AT_NODEID|XFS_AT_NLINK|XFS_AT_SIZE|\
|
||||
XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME|XFS_AT_RDEV|\
|
||||
XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_VCODE|XFS_AT_MAC|\
|
||||
XFS_AT_ACL|XFS_AT_CAP|XFS_AT_INF|XFS_AT_XFLAGS|XFS_AT_EXTSIZE|\
|
||||
XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|XFS_AT_PROJID|XFS_AT_GENCOUNT)
|
||||
|
||||
#define XFS_AT_STAT (XFS_AT_TYPE|XFS_AT_MODE|XFS_AT_UID|XFS_AT_GID|\
|
||||
XFS_AT_FSID|XFS_AT_NODEID|XFS_AT_NLINK|XFS_AT_SIZE|\
|
||||
XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME|XFS_AT_RDEV|\
|
||||
XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_PROJID)
|
||||
|
||||
#define XFS_AT_TIMES (XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME)
|
||||
|
||||
#define XFS_AT_UPDTIMES (XFS_AT_UPDATIME|XFS_AT_UPDMTIME|XFS_AT_UPDCTIME)
|
||||
|
@ -94,7 +94,6 @@ xfs_setattr(
|
||||
uid_t uid=0, iuid=0;
|
||||
gid_t gid=0, igid=0;
|
||||
int timeflags = 0;
|
||||
xfs_prid_t projid=0, iprojid=0;
|
||||
struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2;
|
||||
int file_owner;
|
||||
int need_iolock = 1;
|
||||
@ -139,8 +138,7 @@ xfs_setattr(
|
||||
* If the IDs do change before we take the ilock, we're covered
|
||||
* because the i_*dquot fields will get updated anyway.
|
||||
*/
|
||||
if (XFS_IS_QUOTA_ON(mp) &&
|
||||
(mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID))) {
|
||||
if (XFS_IS_QUOTA_ON(mp) && (mask & (XFS_AT_UID|XFS_AT_GID))) {
|
||||
uint qflags = 0;
|
||||
|
||||
if ((mask & XFS_AT_UID) && XFS_IS_UQUOTA_ON(mp)) {
|
||||
@ -155,12 +153,7 @@ xfs_setattr(
|
||||
} else {
|
||||
gid = ip->i_d.di_gid;
|
||||
}
|
||||
if ((mask & XFS_AT_PROJID) && XFS_IS_PQUOTA_ON(mp)) {
|
||||
projid = vap->va_projid;
|
||||
qflags |= XFS_QMOPT_PQUOTA;
|
||||
} else {
|
||||
projid = ip->i_d.di_projid;
|
||||
}
|
||||
|
||||
/*
|
||||
* We take a reference when we initialize udqp and gdqp,
|
||||
* so it is important that we never blindly double trip on
|
||||
@ -168,8 +161,8 @@ xfs_setattr(
|
||||
*/
|
||||
ASSERT(udqp == NULL);
|
||||
ASSERT(gdqp == NULL);
|
||||
code = XFS_QM_DQVOPALLOC(mp, ip, uid, gid, projid, qflags,
|
||||
&udqp, &gdqp);
|
||||
code = XFS_QM_DQVOPALLOC(mp, ip, uid, gid, ip->i_d.di_projid,
|
||||
qflags, &udqp, &gdqp);
|
||||
if (code)
|
||||
return code;
|
||||
}
|
||||
@ -219,9 +212,7 @@ xfs_setattr(
|
||||
* Only the owner or users with CAP_FOWNER
|
||||
* capability may do these things.
|
||||
*/
|
||||
if (mask &
|
||||
(XFS_AT_MODE|XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_UID|
|
||||
XFS_AT_GID|XFS_AT_PROJID)) {
|
||||
if (mask & (XFS_AT_MODE|XFS_AT_UID|XFS_AT_GID)) {
|
||||
/*
|
||||
* CAP_FOWNER overrides the following restrictions:
|
||||
*
|
||||
@ -270,7 +261,7 @@ xfs_setattr(
|
||||
* and can change the group id only to a group of which he
|
||||
* or she is a member.
|
||||
*/
|
||||
if (mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID)) {
|
||||
if (mask & (XFS_AT_UID|XFS_AT_GID)) {
|
||||
/*
|
||||
* These IDs could have changed since we last looked at them.
|
||||
* But, we're assured that if the ownership did change
|
||||
@ -278,12 +269,9 @@ xfs_setattr(
|
||||
* would have changed also.
|
||||
*/
|
||||
iuid = ip->i_d.di_uid;
|
||||
iprojid = ip->i_d.di_projid;
|
||||
igid = ip->i_d.di_gid;
|
||||
gid = (mask & XFS_AT_GID) ? vap->va_gid : igid;
|
||||
uid = (mask & XFS_AT_UID) ? vap->va_uid : iuid;
|
||||
projid = (mask & XFS_AT_PROJID) ? (xfs_prid_t)vap->va_projid :
|
||||
iprojid;
|
||||
|
||||
/*
|
||||
* CAP_CHOWN overrides the following restrictions:
|
||||
@ -303,11 +291,10 @@ xfs_setattr(
|
||||
goto error_return;
|
||||
}
|
||||
/*
|
||||
* Do a quota reservation only if uid/projid/gid is actually
|
||||
* Do a quota reservation only if uid/gid is actually
|
||||
* going to change.
|
||||
*/
|
||||
if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) ||
|
||||
(XFS_IS_PQUOTA_ON(mp) && iprojid != projid) ||
|
||||
(XFS_IS_GQUOTA_ON(mp) && igid != gid)) {
|
||||
ASSERT(tp);
|
||||
code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp,
|
||||
@ -360,78 +347,6 @@ xfs_setattr(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Change extent size or realtime flag.
|
||||
*/
|
||||
if (mask & (XFS_AT_EXTSIZE|XFS_AT_XFLAGS)) {
|
||||
/*
|
||||
* Can't change extent size if any extents are allocated.
|
||||
*/
|
||||
if (ip->i_d.di_nextents && (mask & XFS_AT_EXTSIZE) &&
|
||||
((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) !=
|
||||
vap->va_extsize) ) {
|
||||
code = XFS_ERROR(EINVAL); /* EFBIG? */
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Can't change realtime flag if any extents are allocated.
|
||||
*/
|
||||
if ((ip->i_d.di_nextents || ip->i_delayed_blks) &&
|
||||
(mask & XFS_AT_XFLAGS) &&
|
||||
(XFS_IS_REALTIME_INODE(ip)) !=
|
||||
(vap->va_xflags & XFS_XFLAG_REALTIME)) {
|
||||
code = XFS_ERROR(EINVAL); /* EFBIG? */
|
||||
goto error_return;
|
||||
}
|
||||
/*
|
||||
* Extent size must be a multiple of the appropriate block
|
||||
* size, if set at all.
|
||||
*/
|
||||
if ((mask & XFS_AT_EXTSIZE) && vap->va_extsize != 0) {
|
||||
xfs_extlen_t size;
|
||||
|
||||
if (XFS_IS_REALTIME_INODE(ip) ||
|
||||
((mask & XFS_AT_XFLAGS) &&
|
||||
(vap->va_xflags & XFS_XFLAG_REALTIME))) {
|
||||
size = mp->m_sb.sb_rextsize <<
|
||||
mp->m_sb.sb_blocklog;
|
||||
} else {
|
||||
size = mp->m_sb.sb_blocksize;
|
||||
}
|
||||
if (vap->va_extsize % size) {
|
||||
code = XFS_ERROR(EINVAL);
|
||||
goto error_return;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If realtime flag is set then must have realtime data.
|
||||
*/
|
||||
if ((mask & XFS_AT_XFLAGS) &&
|
||||
(vap->va_xflags & XFS_XFLAG_REALTIME)) {
|
||||
if ((mp->m_sb.sb_rblocks == 0) ||
|
||||
(mp->m_sb.sb_rextsize == 0) ||
|
||||
(ip->i_d.di_extsize % mp->m_sb.sb_rextsize)) {
|
||||
code = XFS_ERROR(EINVAL);
|
||||
goto error_return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Can't modify an immutable/append-only file unless
|
||||
* we have appropriate permission.
|
||||
*/
|
||||
if ((mask & XFS_AT_XFLAGS) &&
|
||||
(ip->i_d.di_flags &
|
||||
(XFS_DIFLAG_IMMUTABLE|XFS_DIFLAG_APPEND) ||
|
||||
(vap->va_xflags &
|
||||
(XFS_XFLAG_IMMUTABLE | XFS_XFLAG_APPEND))) &&
|
||||
!capable(CAP_LINUX_IMMUTABLE)) {
|
||||
code = XFS_ERROR(EPERM);
|
||||
goto error_return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we can make the changes. Before we join the inode
|
||||
* to the transaction, if XFS_AT_SIZE is set then take care of
|
||||
@ -568,7 +483,7 @@ xfs_setattr(
|
||||
* and can change the group id only to a group of which he
|
||||
* or she is a member.
|
||||
*/
|
||||
if (mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID)) {
|
||||
if (mask & (XFS_AT_UID|XFS_AT_GID)) {
|
||||
/*
|
||||
* CAP_FSETID overrides the following restrictions:
|
||||
*
|
||||
@ -603,23 +518,6 @@ xfs_setattr(
|
||||
}
|
||||
ip->i_d.di_gid = gid;
|
||||
}
|
||||
if (iprojid != projid) {
|
||||
if (XFS_IS_PQUOTA_ON(mp)) {
|
||||
ASSERT(!XFS_IS_GQUOTA_ON(mp));
|
||||
ASSERT(mask & XFS_AT_PROJID);
|
||||
ASSERT(gdqp);
|
||||
olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip,
|
||||
&ip->i_gdquot, gdqp);
|
||||
}
|
||||
ip->i_d.di_projid = projid;
|
||||
/*
|
||||
* We may have to rev the inode as well as
|
||||
* the superblock version number since projids didn't
|
||||
* exist before DINODE_VERSION_2 and SB_VERSION_NLINK.
|
||||
*/
|
||||
if (ip->i_d.di_version == XFS_DINODE_VERSION_1)
|
||||
xfs_bump_ino_vers2(tp, ip);
|
||||
}
|
||||
|
||||
xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE);
|
||||
timeflags |= XFS_ICHGTIME_CHG;
|
||||
@ -646,57 +544,6 @@ xfs_setattr(
|
||||
xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change XFS-added attributes.
|
||||
*/
|
||||
if (mask & (XFS_AT_EXTSIZE|XFS_AT_XFLAGS)) {
|
||||
if (mask & XFS_AT_EXTSIZE) {
|
||||
/*
|
||||
* Converting bytes to fs blocks.
|
||||
*/
|
||||
ip->i_d.di_extsize = vap->va_extsize >>
|
||||
mp->m_sb.sb_blocklog;
|
||||
}
|
||||
if (mask & XFS_AT_XFLAGS) {
|
||||
uint di_flags;
|
||||
|
||||
/* can't set PREALLOC this way, just preserve it */
|
||||
di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC);
|
||||
if (vap->va_xflags & XFS_XFLAG_IMMUTABLE)
|
||||
di_flags |= XFS_DIFLAG_IMMUTABLE;
|
||||
if (vap->va_xflags & XFS_XFLAG_APPEND)
|
||||
di_flags |= XFS_DIFLAG_APPEND;
|
||||
if (vap->va_xflags & XFS_XFLAG_SYNC)
|
||||
di_flags |= XFS_DIFLAG_SYNC;
|
||||
if (vap->va_xflags & XFS_XFLAG_NOATIME)
|
||||
di_flags |= XFS_DIFLAG_NOATIME;
|
||||
if (vap->va_xflags & XFS_XFLAG_NODUMP)
|
||||
di_flags |= XFS_DIFLAG_NODUMP;
|
||||
if (vap->va_xflags & XFS_XFLAG_PROJINHERIT)
|
||||
di_flags |= XFS_DIFLAG_PROJINHERIT;
|
||||
if (vap->va_xflags & XFS_XFLAG_NODEFRAG)
|
||||
di_flags |= XFS_DIFLAG_NODEFRAG;
|
||||
if (vap->va_xflags & XFS_XFLAG_FILESTREAM)
|
||||
di_flags |= XFS_DIFLAG_FILESTREAM;
|
||||
if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
|
||||
if (vap->va_xflags & XFS_XFLAG_RTINHERIT)
|
||||
di_flags |= XFS_DIFLAG_RTINHERIT;
|
||||
if (vap->va_xflags & XFS_XFLAG_NOSYMLINKS)
|
||||
di_flags |= XFS_DIFLAG_NOSYMLINKS;
|
||||
if (vap->va_xflags & XFS_XFLAG_EXTSZINHERIT)
|
||||
di_flags |= XFS_DIFLAG_EXTSZINHERIT;
|
||||
} else if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) {
|
||||
if (vap->va_xflags & XFS_XFLAG_REALTIME)
|
||||
di_flags |= XFS_DIFLAG_REALTIME;
|
||||
if (vap->va_xflags & XFS_XFLAG_EXTSIZE)
|
||||
di_flags |= XFS_DIFLAG_EXTSIZE;
|
||||
}
|
||||
ip->i_d.di_flags = di_flags;
|
||||
}
|
||||
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
|
||||
timeflags |= XFS_ICHGTIME_CHG;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change file inode change time only if XFS_AT_CTIME set
|
||||
* AND we have been called by a DMI function.
|
||||
|
Loading…
Reference in New Issue
Block a user