split out xfs value-add from xfs_setattr
PATCH 1/3 split out xfs value-add from xfs_setattr
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.
fs/xfs/linux-2.6/xfs_ioctl.c +303 -36
@@ -47,6 +47,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>
@@ -875,6 +877,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,
@@ -882,31 +1175,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
@@ -928,10 +1206,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 ;
@@ -941,22 +1218,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
fs/xfs/linux-2.6/xfs_vnode.h +0 -15
@@ -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)
fs/xfs/xfs_vnodeops.c +8 -161
247 lines not on this page · raw message
Christoph,
I've gone thru this and it looks good to me.
However, there is enough stuff which was extracted and duplicated from different places in xfs_setattr to easily miss something (IMHO) and so we would need to test this carefully I reckon.
I'll have a look at the other 2 patches tomorrow.
Below are my notes:
* remove related code to quota, xflags, etc from xfs_setattr
* duplicate support code from xfs_setattr
* I need to compare old xfs_setattr() with xfs_ioctl_setattr() to check that the code is still doing the same thing for the relevant cases...
* The "can't change extent size test" is duplicated as we split up the predicate of EXTSIZE and XFLAGS into two
Okay
* xfs_trans_log_inode doesn't need to be called
in 2 spots now it can be done after the di_extsize and the set_diflags spot and no need for just after the projid one.
Okay
* And we just call xfs_ichgtime directly instead of noting a timeflag Okay
* commit_flags are zero as are non-zero for AT_SIZE changes which we don't deal with here
Okay
* This code is different:
+ 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 */
Q: What happened to the ATTR_DMI flag testing?
A: We never set ATTR_DMI in the flags by the ioctls. Okay cool.
Q: Why have you introduced the vn_revalidate?
A: Because you took it out of the callers to xfs_ioctl_setattr. Okay
* So XFS_AT_ALL and XFS_AT_STAT are not used currently Okay
--Tim
Quoted 695 lines · Christoph Hellwig
xfs_setattrcurrently 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 abhv_vattrintermediate structure eating up stackspace.This patch adds a new
xfs_ioctl_setattrhelper for the XFS ioctls that set these attributes and remove the code to set them throughxfs_setattr.Signed-off-by Christoph Hellwig <[email protected]>Index:
linux-2.6-xfs/fs/xfs/linux-2.6/xfs_ioctl.c
===================================================================fs/xfs/linux-2.6/xfs_ioctl.c +303
-36@@ -47,6 +47,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> @@ -875,6 +877,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,@@ -882,31 +1175,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@@ -928,10 +1206,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 ;@@ -941,22 +1218,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 intIndex:
linux-2.6-xfs/fs/xfs/linux-2.6/xfs_vnode.h
===================================================================fs/xfs/linux-2.6/xfs_vnode.h +0
-15@@ -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)Index:
linux-2.6-xfs/fs/xfs/xfs_vnodeops.c
===================================================================fs/xfs/xfs_vnodeops.c +8
-161@@ -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,@@ -361,78 +348,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 * the part of the truncation that must be done without the @@ -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 ;@@ -647,57 +545,6 @@ xfs_setattr( }/* -* 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. */