Commit 25fe55e8 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Niv Sardi

[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: default avatarChristoph Hellwig <hch@infradead.org>
Signed-off-by: default avatarTim Shimmin <tes@sgi.com>
Signed-off-by: default avatarLachlan McIlroy <lachlan@sgi.com>
parent c032bfcf
This diff is collapsed.
......@@ -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.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment