mirror of
https://github.com/torvalds/linux.git
synced 2024-11-28 15:11:31 +00:00
xfs: factor out xfs_ioctl_setattr transaciton preamble
The setup of the transaction is done after a random smattering of checks and before another bunch of ioperations specific validity checks. Pull all the preamble out into a helper function that returns a transaction or error. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
This commit is contained in:
parent
29a17c00d4
commit
8f3d17ab06
@ -1042,7 +1042,6 @@ xfs_ioctl_setattr_xflags(
|
||||
!capable(CAP_LINUX_IMMUTABLE))
|
||||
return -EPERM;
|
||||
|
||||
xfs_trans_ijoin(tp, ip, 0);
|
||||
xfs_set_diflags(ip, fa->fsx_xflags);
|
||||
xfs_diflags_to_linux(ip);
|
||||
xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
|
||||
@ -1051,6 +1050,54 @@ xfs_ioctl_setattr_xflags(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up the transaction structure for the setattr operation, checking that we
|
||||
* have permission to do so. On success, return a clean transaction and the
|
||||
* inode locked exclusively ready for further operation specific checks. On
|
||||
* failure, return an error without modifying or locking the inode.
|
||||
*/
|
||||
static struct xfs_trans *
|
||||
xfs_ioctl_setattr_get_trans(
|
||||
struct xfs_inode *ip)
|
||||
{
|
||||
struct xfs_mount *mp = ip->i_mount;
|
||||
struct xfs_trans *tp;
|
||||
int error;
|
||||
|
||||
if (mp->m_flags & XFS_MOUNT_RDONLY)
|
||||
return ERR_PTR(-EROFS);
|
||||
if (XFS_FORCED_SHUTDOWN(mp))
|
||||
return ERR_PTR(-EIO);
|
||||
|
||||
tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);
|
||||
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0);
|
||||
if (error)
|
||||
goto out_cancel;
|
||||
|
||||
xfs_ilock(ip, XFS_ILOCK_EXCL);
|
||||
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
|
||||
|
||||
/*
|
||||
* 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 (!inode_owner_or_capable(VFS_I(ip))) {
|
||||
error = -EPERM;
|
||||
goto out_cancel;
|
||||
}
|
||||
|
||||
if (mp->m_flags & XFS_MOUNT_WSYNC)
|
||||
xfs_trans_set_sync(tp);
|
||||
|
||||
return tp;
|
||||
|
||||
out_cancel:
|
||||
xfs_trans_cancel(tp, 0);
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
#define FSX_PROJID 1
|
||||
#define FSX_EXTSIZE 2
|
||||
#define FSX_XFLAGS 4
|
||||
@ -1063,7 +1110,6 @@ xfs_ioctl_setattr(
|
||||
{
|
||||
struct xfs_mount *mp = ip->i_mount;
|
||||
struct xfs_trans *tp;
|
||||
unsigned int lock_flags = 0;
|
||||
struct xfs_dquot *udqp = NULL;
|
||||
struct xfs_dquot *pdqp = NULL;
|
||||
struct xfs_dquot *olddquot = NULL;
|
||||
@ -1071,11 +1117,6 @@ xfs_ioctl_setattr(
|
||||
|
||||
trace_xfs_ioctl_setattr(ip);
|
||||
|
||||
if (mp->m_flags & XFS_MOUNT_RDONLY)
|
||||
return -EROFS;
|
||||
if (XFS_FORCED_SHUTDOWN(mp))
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
* Disallow 32bit project ids when projid32bit feature is not enabled.
|
||||
*/
|
||||
@ -1099,28 +1140,10 @@ xfs_ioctl_setattr(
|
||||
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, &M_RES(mp)->tr_ichange, 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 (!inode_owner_or_capable(VFS_I(ip))) {
|
||||
code = -EPERM;
|
||||
goto error_return;
|
||||
tp = xfs_ioctl_setattr_get_trans(ip);
|
||||
if (IS_ERR(tp)) {
|
||||
code = PTR_ERR(tp);
|
||||
goto error_free_dquots;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1244,20 +1267,7 @@ xfs_ioctl_setattr(
|
||||
ip->i_d.di_extsize = extsize;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
@ -1268,12 +1278,11 @@ xfs_ioctl_setattr(
|
||||
|
||||
return code;
|
||||
|
||||
error_return:
|
||||
error_return:
|
||||
xfs_trans_cancel(tp, 0);
|
||||
error_free_dquots:
|
||||
xfs_qm_dqrele(udqp);
|
||||
xfs_qm_dqrele(pdqp);
|
||||
xfs_trans_cancel(tp, 0);
|
||||
if (lock_flags)
|
||||
xfs_iunlock(ip, lock_flags);
|
||||
return code;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user