xfs: factor out xfs_ioctl_setattr transaciton preamble
authorDave Chinner <dchinner@redhat.com>
Sun, 1 Feb 2015 23:15:35 +0000 (10:15 +1100)
committerDave Chinner <david@fromorbit.com>
Sun, 1 Feb 2015 23:15:35 +0000 (10:15 +1100)
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>
fs/xfs/xfs_ioctl.c

index b0064bdb7a6e804f971961834fc434f9a7343cd0..0f62f5b3e221b04c4a8734d44a9d9d0666998a63 100644 (file)
@@ -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;
 }