[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:
Christoph Hellwig 2008-07-18 17:13:20 +10:00 committed by Niv Sardi
parent c032bfcf46
commit 25fe55e814
3 changed files with 311 additions and 212 deletions

View File

@ -48,6 +48,8 @@
#include "xfs_dfrag.h" #include "xfs_dfrag.h"
#include "xfs_fsops.h" #include "xfs_fsops.h"
#include "xfs_vnodeops.h" #include "xfs_vnodeops.h"
#include "xfs_quota.h"
#include "xfs_inode_item.h"
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/dcache.h> #include <linux/dcache.h>
@ -879,6 +881,297 @@ xfs_ioc_fsgetxattr(
return 0; 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 STATIC int
xfs_ioc_fssetxattr( xfs_ioc_fssetxattr(
xfs_inode_t *ip, xfs_inode_t *ip,
@ -886,31 +1179,16 @@ xfs_ioc_fssetxattr(
void __user *arg) void __user *arg)
{ {
struct fsxattr fa; struct fsxattr fa;
struct bhv_vattr *vattr; unsigned int mask;
int error;
int attr_flags;
if (copy_from_user(&fa, arg, sizeof(fa))) if (copy_from_user(&fa, arg, sizeof(fa)))
return -EFAULT; return -EFAULT;
vattr = kmalloc(sizeof(*vattr), GFP_KERNEL); mask = FSX_XFLAGS | FSX_EXTSIZE | FSX_PROJID;
if (unlikely(!vattr))
return -ENOMEM;
attr_flags = 0;
if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) 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; return -xfs_ioctl_setattr(ip, &fa, mask);
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;
} }
STATIC int STATIC int
@ -932,10 +1210,9 @@ xfs_ioc_setxflags(
struct file *filp, struct file *filp,
void __user *arg) void __user *arg)
{ {
struct bhv_vattr *vattr; struct fsxattr fa;
unsigned int flags; unsigned int flags;
int attr_flags; unsigned int mask;
int error;
if (copy_from_user(&flags, arg, sizeof(flags))) if (copy_from_user(&flags, arg, sizeof(flags)))
return -EFAULT; return -EFAULT;
@ -945,22 +1222,12 @@ xfs_ioc_setxflags(
FS_SYNC_FL)) FS_SYNC_FL))
return -EOPNOTSUPP; return -EOPNOTSUPP;
vattr = kmalloc(sizeof(*vattr), GFP_KERNEL); mask = FSX_XFLAGS;
if (unlikely(!vattr))
return -ENOMEM;
attr_flags = 0;
if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) 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; return -xfs_ioctl_setattr(ip, &fa, mask);
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;
} }
STATIC int STATIC int

View File

@ -117,26 +117,11 @@ typedef struct bhv_vattr {
#define XFS_AT_ACL 0x00080000 #define XFS_AT_ACL 0x00080000
#define XFS_AT_CAP 0x00100000 #define XFS_AT_CAP 0x00100000
#define XFS_AT_INF 0x00200000 #define XFS_AT_INF 0x00200000
#define XFS_AT_XFLAGS 0x00400000
#define XFS_AT_EXTSIZE 0x00800000
#define XFS_AT_NEXTENTS 0x01000000 #define XFS_AT_NEXTENTS 0x01000000
#define XFS_AT_ANEXTENTS 0x02000000 #define XFS_AT_ANEXTENTS 0x02000000
#define XFS_AT_PROJID 0x04000000
#define XFS_AT_SIZE_NOPERM 0x08000000 #define XFS_AT_SIZE_NOPERM 0x08000000
#define XFS_AT_GENCOUNT 0x10000000 #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_TIMES (XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME)
#define XFS_AT_UPDTIMES (XFS_AT_UPDATIME|XFS_AT_UPDMTIME|XFS_AT_UPDCTIME) #define XFS_AT_UPDTIMES (XFS_AT_UPDATIME|XFS_AT_UPDMTIME|XFS_AT_UPDCTIME)

View File

@ -94,7 +94,6 @@ xfs_setattr(
uid_t uid=0, iuid=0; uid_t uid=0, iuid=0;
gid_t gid=0, igid=0; gid_t gid=0, igid=0;
int timeflags = 0; int timeflags = 0;
xfs_prid_t projid=0, iprojid=0;
struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2;
int file_owner; int file_owner;
int need_iolock = 1; int need_iolock = 1;
@ -139,8 +138,7 @@ xfs_setattr(
* If the IDs do change before we take the ilock, we're covered * If the IDs do change before we take the ilock, we're covered
* because the i_*dquot fields will get updated anyway. * because the i_*dquot fields will get updated anyway.
*/ */
if (XFS_IS_QUOTA_ON(mp) && if (XFS_IS_QUOTA_ON(mp) && (mask & (XFS_AT_UID|XFS_AT_GID))) {
(mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID))) {
uint qflags = 0; uint qflags = 0;
if ((mask & XFS_AT_UID) && XFS_IS_UQUOTA_ON(mp)) { if ((mask & XFS_AT_UID) && XFS_IS_UQUOTA_ON(mp)) {
@ -155,12 +153,7 @@ xfs_setattr(
} else { } else {
gid = ip->i_d.di_gid; 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, * We take a reference when we initialize udqp and gdqp,
* so it is important that we never blindly double trip on * so it is important that we never blindly double trip on
@ -168,8 +161,8 @@ xfs_setattr(
*/ */
ASSERT(udqp == NULL); ASSERT(udqp == NULL);
ASSERT(gdqp == NULL); ASSERT(gdqp == NULL);
code = XFS_QM_DQVOPALLOC(mp, ip, uid, gid, projid, qflags, code = XFS_QM_DQVOPALLOC(mp, ip, uid, gid, ip->i_d.di_projid,
&udqp, &gdqp); qflags, &udqp, &gdqp);
if (code) if (code)
return code; return code;
} }
@ -219,9 +212,7 @@ xfs_setattr(
* Only the owner or users with CAP_FOWNER * Only the owner or users with CAP_FOWNER
* capability may do these things. * capability may do these things.
*/ */
if (mask & if (mask & (XFS_AT_MODE|XFS_AT_UID|XFS_AT_GID)) {
(XFS_AT_MODE|XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_UID|
XFS_AT_GID|XFS_AT_PROJID)) {
/* /*
* CAP_FOWNER overrides the following restrictions: * 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 * and can change the group id only to a group of which he
* or she is a member. * 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. * These IDs could have changed since we last looked at them.
* But, we're assured that if the ownership did change * But, we're assured that if the ownership did change
@ -278,12 +269,9 @@ xfs_setattr(
* would have changed also. * would have changed also.
*/ */
iuid = ip->i_d.di_uid; iuid = ip->i_d.di_uid;
iprojid = ip->i_d.di_projid;
igid = ip->i_d.di_gid; igid = ip->i_d.di_gid;
gid = (mask & XFS_AT_GID) ? vap->va_gid : igid; gid = (mask & XFS_AT_GID) ? vap->va_gid : igid;
uid = (mask & XFS_AT_UID) ? vap->va_uid : iuid; 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: * CAP_CHOWN overrides the following restrictions:
@ -303,11 +291,10 @@ xfs_setattr(
goto error_return; 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. * going to change.
*/ */
if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) || if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) ||
(XFS_IS_PQUOTA_ON(mp) && iprojid != projid) ||
(XFS_IS_GQUOTA_ON(mp) && igid != gid)) { (XFS_IS_GQUOTA_ON(mp) && igid != gid)) {
ASSERT(tp); ASSERT(tp);
code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp, 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 * Now we can make the changes. Before we join the inode
* to the transaction, if XFS_AT_SIZE is set then take care of * 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 * and can change the group id only to a group of which he
* or she is a member. * 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: * CAP_FSETID overrides the following restrictions:
* *
@ -603,23 +518,6 @@ xfs_setattr(
} }
ip->i_d.di_gid = gid; 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); xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE);
timeflags |= XFS_ICHGTIME_CHG; timeflags |= XFS_ICHGTIME_CHG;
@ -646,57 +544,6 @@ xfs_setattr(
xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); 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 * Change file inode change time only if XFS_AT_CTIME set
* AND we have been called by a DMI function. * AND we have been called by a DMI function.