aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2008-07-18 03:13:20 -0400
committerNiv Sardi <xaiki@debian.org>2008-07-28 02:59:36 -0400
commit25fe55e814a2964c7e16d16a5d08cae6e9313a3a (patch)
tree9337a4270cafe83a0bfd14e1c297aa5f24e02c33 /fs/xfs
parentc032bfcf468013643e05c8274824af10dd7cbb61 (diff)
[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>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl.c339
-rw-r--r--fs/xfs/linux-2.6/xfs_vnode.h15
-rw-r--r--fs/xfs/xfs_vnodeops.c169
3 files changed, 311 insertions, 212 deletions
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
index 8eddaff36843..d2bbb0532ef6 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -48,6 +48,8 @@
48#include "xfs_dfrag.h" 48#include "xfs_dfrag.h"
49#include "xfs_fsops.h" 49#include "xfs_fsops.h"
50#include "xfs_vnodeops.h" 50#include "xfs_vnodeops.h"
51#include "xfs_quota.h"
52#include "xfs_inode_item.h"
51 53
52#include <linux/capability.h> 54#include <linux/capability.h>
53#include <linux/dcache.h> 55#include <linux/dcache.h>
@@ -879,6 +881,297 @@ xfs_ioc_fsgetxattr(
879 return 0; 881 return 0;
880} 882}
881 883
884STATIC void
885xfs_set_diflags(
886 struct xfs_inode *ip,
887 unsigned int xflags)
888{
889 unsigned int di_flags;
890
891 /* can't set PREALLOC this way, just preserve it */
892 di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC);
893 if (xflags & XFS_XFLAG_IMMUTABLE)
894 di_flags |= XFS_DIFLAG_IMMUTABLE;
895 if (xflags & XFS_XFLAG_APPEND)
896 di_flags |= XFS_DIFLAG_APPEND;
897 if (xflags & XFS_XFLAG_SYNC)
898 di_flags |= XFS_DIFLAG_SYNC;
899 if (xflags & XFS_XFLAG_NOATIME)
900 di_flags |= XFS_DIFLAG_NOATIME;
901 if (xflags & XFS_XFLAG_NODUMP)
902 di_flags |= XFS_DIFLAG_NODUMP;
903 if (xflags & XFS_XFLAG_PROJINHERIT)
904 di_flags |= XFS_DIFLAG_PROJINHERIT;
905 if (xflags & XFS_XFLAG_NODEFRAG)
906 di_flags |= XFS_DIFLAG_NODEFRAG;
907 if (xflags & XFS_XFLAG_FILESTREAM)
908 di_flags |= XFS_DIFLAG_FILESTREAM;
909 if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
910 if (xflags & XFS_XFLAG_RTINHERIT)
911 di_flags |= XFS_DIFLAG_RTINHERIT;
912 if (xflags & XFS_XFLAG_NOSYMLINKS)
913 di_flags |= XFS_DIFLAG_NOSYMLINKS;
914 if (xflags & XFS_XFLAG_EXTSZINHERIT)
915 di_flags |= XFS_DIFLAG_EXTSZINHERIT;
916 } else if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) {
917 if (xflags & XFS_XFLAG_REALTIME)
918 di_flags |= XFS_DIFLAG_REALTIME;
919 if (xflags & XFS_XFLAG_EXTSIZE)
920 di_flags |= XFS_DIFLAG_EXTSIZE;
921 }
922
923 ip->i_d.di_flags = di_flags;
924}
925
926
927#define FSX_PROJID 1
928#define FSX_EXTSIZE 2
929#define FSX_XFLAGS 4
930#define FSX_NONBLOCK 8
931
932STATIC int
933xfs_ioctl_setattr(
934 xfs_inode_t *ip,
935 struct fsxattr *fa,
936 int mask)
937{
938 struct xfs_mount *mp = ip->i_mount;
939 struct xfs_trans *tp;
940 unsigned int lock_flags = 0;
941 struct xfs_dquot *udqp = NULL, *gdqp = NULL;
942 struct xfs_dquot *olddquot = NULL;
943 int code;
944
945 xfs_itrace_entry(ip);
946
947 if (mp->m_flags & XFS_MOUNT_RDONLY)
948 return XFS_ERROR(EROFS);
949 if (XFS_FORCED_SHUTDOWN(mp))
950 return XFS_ERROR(EIO);
951
952 /*
953 * If disk quotas is on, we make sure that the dquots do exist on disk,
954 * before we start any other transactions. Trying to do this later
955 * is messy. We don't care to take a readlock to look at the ids
956 * in inode here, because we can't hold it across the trans_reserve.
957 * If the IDs do change before we take the ilock, we're covered
958 * because the i_*dquot fields will get updated anyway.
959 */
960 if (XFS_IS_QUOTA_ON(mp) && (mask & FSX_PROJID)) {
961 code = XFS_QM_DQVOPALLOC(mp, ip, ip->i_d.di_uid,
962 ip->i_d.di_gid, fa->fsx_projid,
963 XFS_QMOPT_PQUOTA, &udqp, &gdqp);
964 if (code)
965 return code;
966 }
967
968 /*
969 * For the other attributes, we acquire the inode lock and
970 * first do an error checking pass.
971 */
972 tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);
973 code = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0);
974 if (code)
975 goto error_return;
976
977 lock_flags = XFS_ILOCK_EXCL;
978 xfs_ilock(ip, lock_flags);
979
980 /*
981 * CAP_FOWNER overrides the following restrictions:
982 *
983 * The user ID of the calling process must be equal
984 * to the file owner ID, except in cases where the
985 * CAP_FSETID capability is applicable.
986 */
987 if (current->fsuid != ip->i_d.di_uid && !capable(CAP_FOWNER)) {
988 code = XFS_ERROR(EPERM);
989 goto error_return;
990 }
991
992 /*
993 * Do a quota reservation only if projid is actually going to change.
994 */
995 if (mask & FSX_PROJID) {
996 if (XFS_IS_PQUOTA_ON(mp) &&
997 ip->i_d.di_projid != fa->fsx_projid) {
998 ASSERT(tp);
999 code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp,
1000 capable(CAP_FOWNER) ?
1001 XFS_QMOPT_FORCE_RES : 0);
1002 if (code) /* out of quota */
1003 goto error_return;
1004 }
1005 }
1006
1007 if (mask & FSX_EXTSIZE) {
1008 /*
1009 * Can't change extent size if any extents are allocated.
1010 */
1011 if (ip->i_d.di_nextents &&
1012 ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) !=
1013 fa->fsx_extsize)) {
1014 code = XFS_ERROR(EINVAL); /* EFBIG? */
1015 goto error_return;
1016 }
1017
1018 /*
1019 * Extent size must be a multiple of the appropriate block
1020 * size, if set at all.
1021 */
1022 if (fa->fsx_extsize != 0) {
1023 xfs_extlen_t size;
1024
1025 if (XFS_IS_REALTIME_INODE(ip) ||
1026 ((mask & FSX_XFLAGS) &&
1027 (fa->fsx_xflags & XFS_XFLAG_REALTIME))) {
1028 size = mp->m_sb.sb_rextsize <<
1029 mp->m_sb.sb_blocklog;
1030 } else {
1031 size = mp->m_sb.sb_blocksize;
1032 }
1033
1034 if (fa->fsx_extsize % size) {
1035 code = XFS_ERROR(EINVAL);
1036 goto error_return;
1037 }
1038 }
1039 }
1040
1041
1042 if (mask & FSX_XFLAGS) {
1043 /*
1044 * Can't change realtime flag if any extents are allocated.
1045 */
1046 if ((ip->i_d.di_nextents || ip->i_delayed_blks) &&
1047 (XFS_IS_REALTIME_INODE(ip)) !=
1048 (fa->fsx_xflags & XFS_XFLAG_REALTIME)) {
1049 code = XFS_ERROR(EINVAL); /* EFBIG? */
1050 goto error_return;
1051 }
1052
1053 /*
1054 * If realtime flag is set then must have realtime data.
1055 */
1056 if ((fa->fsx_xflags & XFS_XFLAG_REALTIME)) {
1057 if ((mp->m_sb.sb_rblocks == 0) ||
1058 (mp->m_sb.sb_rextsize == 0) ||
1059 (ip->i_d.di_extsize % mp->m_sb.sb_rextsize)) {
1060 code = XFS_ERROR(EINVAL);
1061 goto error_return;
1062 }
1063 }
1064
1065 /*
1066 * Can't modify an immutable/append-only file unless
1067 * we have appropriate permission.
1068 */
1069 if ((ip->i_d.di_flags &
1070 (XFS_DIFLAG_IMMUTABLE|XFS_DIFLAG_APPEND) ||
1071 (fa->fsx_xflags &
1072 (XFS_XFLAG_IMMUTABLE | XFS_XFLAG_APPEND))) &&
1073 !capable(CAP_LINUX_IMMUTABLE)) {
1074 code = XFS_ERROR(EPERM);
1075 goto error_return;
1076 }
1077 }
1078
1079 xfs_trans_ijoin(tp, ip, lock_flags);
1080 xfs_trans_ihold(tp, ip);
1081
1082 /*
1083 * Change file ownership. Must be the owner or privileged.
1084 * If the system was configured with the "restricted_chown"
1085 * option, the owner is not permitted to give away the file,
1086 * and can change the group id only to a group of which he
1087 * or she is a member.
1088 */
1089 if (mask & FSX_PROJID) {
1090 /*
1091 * CAP_FSETID overrides the following restrictions:
1092 *
1093 * The set-user-ID and set-group-ID bits of a file will be
1094 * cleared upon successful return from chown()
1095 */
1096 if ((ip->i_d.di_mode & (S_ISUID|S_ISGID)) &&
1097 !capable(CAP_FSETID))
1098 ip->i_d.di_mode &= ~(S_ISUID|S_ISGID);
1099
1100 /*
1101 * Change the ownerships and register quota modifications
1102 * in the transaction.
1103 */
1104 if (ip->i_d.di_projid != fa->fsx_projid) {
1105 if (XFS_IS_PQUOTA_ON(mp)) {
1106 olddquot = XFS_QM_DQVOPCHOWN(mp, tp, ip,
1107 &ip->i_gdquot, gdqp);
1108 }
1109 ip->i_d.di_projid = fa->fsx_projid;
1110
1111 /*
1112 * We may have to rev the inode as well as
1113 * the superblock version number since projids didn't
1114 * exist before DINODE_VERSION_2 and SB_VERSION_NLINK.
1115 */
1116 if (ip->i_d.di_version == XFS_DINODE_VERSION_1)
1117 xfs_bump_ino_vers2(tp, ip);
1118 }
1119
1120 }
1121
1122 if (mask & FSX_EXTSIZE)
1123 ip->i_d.di_extsize = fa->fsx_extsize >> mp->m_sb.sb_blocklog;
1124 if (mask & FSX_XFLAGS)
1125 xfs_set_diflags(ip, fa->fsx_xflags);
1126
1127 xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
1128 xfs_ichgtime(ip, XFS_ICHGTIME_CHG);
1129
1130 XFS_STATS_INC(xs_ig_attrchg);
1131
1132 /*
1133 * If this is a synchronous mount, make sure that the
1134 * transaction goes to disk before returning to the user.
1135 * This is slightly sub-optimal in that truncates require
1136 * two sync transactions instead of one for wsync filesystems.
1137 * One for the truncate and one for the timestamps since we
1138 * don't want to change the timestamps unless we're sure the
1139 * truncate worked. Truncates are less than 1% of the laddis
1140 * mix so this probably isn't worth the trouble to optimize.
1141 */
1142 if (mp->m_flags & XFS_MOUNT_WSYNC)
1143 xfs_trans_set_sync(tp);
1144 code = xfs_trans_commit(tp, 0);
1145 xfs_iunlock(ip, lock_flags);
1146
1147 /*
1148 * Release any dquot(s) the inode had kept before chown.
1149 */
1150 XFS_QM_DQRELE(mp, olddquot);
1151 XFS_QM_DQRELE(mp, udqp);
1152 XFS_QM_DQRELE(mp, gdqp);
1153
1154 if (code)
1155 return code;
1156
1157 if (DM_EVENT_ENABLED(ip, DM_EVENT_ATTRIBUTE)) {
1158 XFS_SEND_NAMESP(mp, DM_EVENT_ATTRIBUTE, ip, DM_RIGHT_NULL,
1159 NULL, DM_RIGHT_NULL, NULL, NULL, 0, 0,
1160 (mask & FSX_NONBLOCK) ? DM_FLAGS_NDELAY : 0);
1161 }
1162
1163 vn_revalidate(XFS_ITOV(ip)); /* update flags */
1164 return 0;
1165
1166 error_return:
1167 XFS_QM_DQRELE(mp, udqp);
1168 XFS_QM_DQRELE(mp, gdqp);
1169 xfs_trans_cancel(tp, 0);
1170 if (lock_flags)
1171 xfs_iunlock(ip, lock_flags);
1172 return code;
1173}
1174
882STATIC int 1175STATIC int
883xfs_ioc_fssetxattr( 1176xfs_ioc_fssetxattr(
884 xfs_inode_t *ip, 1177 xfs_inode_t *ip,
@@ -886,31 +1179,16 @@ xfs_ioc_fssetxattr(
886 void __user *arg) 1179 void __user *arg)
887{ 1180{
888 struct fsxattr fa; 1181 struct fsxattr fa;
889 struct bhv_vattr *vattr; 1182 unsigned int mask;
890 int error;
891 int attr_flags;
892 1183
893 if (copy_from_user(&fa, arg, sizeof(fa))) 1184 if (copy_from_user(&fa, arg, sizeof(fa)))
894 return -EFAULT; 1185 return -EFAULT;
895 1186
896 vattr = kmalloc(sizeof(*vattr), GFP_KERNEL); 1187 mask = FSX_XFLAGS | FSX_EXTSIZE | FSX_PROJID;
897 if (unlikely(!vattr))
898 return -ENOMEM;
899
900 attr_flags = 0;
901 if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) 1188 if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
902 attr_flags |= ATTR_NONBLOCK; 1189 mask |= FSX_NONBLOCK;
903 1190
904 vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | XFS_AT_PROJID; 1191 return -xfs_ioctl_setattr(ip, &fa, mask);
905 vattr->va_xflags = fa.fsx_xflags;
906 vattr->va_extsize = fa.fsx_extsize;
907 vattr->va_projid = fa.fsx_projid;
908
909 error = -xfs_setattr(ip, vattr, attr_flags, NULL);
910 if (!error)
911 vn_revalidate(XFS_ITOV(ip)); /* update flags */
912 kfree(vattr);
913 return 0;
914} 1192}
915 1193
916STATIC int 1194STATIC int
@@ -932,10 +1210,9 @@ xfs_ioc_setxflags(
932 struct file *filp, 1210 struct file *filp,
933 void __user *arg) 1211 void __user *arg)
934{ 1212{
935 struct bhv_vattr *vattr; 1213 struct fsxattr fa;
936 unsigned int flags; 1214 unsigned int flags;
937 int attr_flags; 1215 unsigned int mask;
938 int error;
939 1216
940 if (copy_from_user(&flags, arg, sizeof(flags))) 1217 if (copy_from_user(&flags, arg, sizeof(flags)))
941 return -EFAULT; 1218 return -EFAULT;
@@ -945,22 +1222,12 @@ xfs_ioc_setxflags(
945 FS_SYNC_FL)) 1222 FS_SYNC_FL))
946 return -EOPNOTSUPP; 1223 return -EOPNOTSUPP;
947 1224
948 vattr = kmalloc(sizeof(*vattr), GFP_KERNEL); 1225 mask = FSX_XFLAGS;
949 if (unlikely(!vattr))
950 return -ENOMEM;
951
952 attr_flags = 0;
953 if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) 1226 if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
954 attr_flags |= ATTR_NONBLOCK; 1227 mask |= FSX_NONBLOCK;
1228 fa.fsx_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip));
955 1229
956 vattr->va_mask = XFS_AT_XFLAGS; 1230 return -xfs_ioctl_setattr(ip, &fa, mask);
957 vattr->va_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip));
958
959 error = -xfs_setattr(ip, vattr, attr_flags, NULL);
960 if (likely(!error))
961 vn_revalidate(XFS_ITOV(ip)); /* update flags */
962 kfree(vattr);
963 return error;
964} 1231}
965 1232
966STATIC int 1233STATIC int
diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h
index 25eb2a9e8d9b..7797c9cdb591 100644
--- a/fs/xfs/linux-2.6/xfs_vnode.h
+++ b/fs/xfs/linux-2.6/xfs_vnode.h
@@ -117,26 +117,11 @@ typedef struct bhv_vattr {
117#define XFS_AT_ACL 0x00080000 117#define XFS_AT_ACL 0x00080000
118#define XFS_AT_CAP 0x00100000 118#define XFS_AT_CAP 0x00100000
119#define XFS_AT_INF 0x00200000 119#define XFS_AT_INF 0x00200000
120#define XFS_AT_XFLAGS 0x00400000
121#define XFS_AT_EXTSIZE 0x00800000
122#define XFS_AT_NEXTENTS 0x01000000 120#define XFS_AT_NEXTENTS 0x01000000
123#define XFS_AT_ANEXTENTS 0x02000000 121#define XFS_AT_ANEXTENTS 0x02000000
124#define XFS_AT_PROJID 0x04000000
125#define XFS_AT_SIZE_NOPERM 0x08000000 122#define XFS_AT_SIZE_NOPERM 0x08000000
126#define XFS_AT_GENCOUNT 0x10000000 123#define XFS_AT_GENCOUNT 0x10000000
127 124
128#define XFS_AT_ALL (XFS_AT_TYPE|XFS_AT_MODE|XFS_AT_UID|XFS_AT_GID|\
129 XFS_AT_FSID|XFS_AT_NODEID|XFS_AT_NLINK|XFS_AT_SIZE|\
130 XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME|XFS_AT_RDEV|\
131 XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_VCODE|XFS_AT_MAC|\
132 XFS_AT_ACL|XFS_AT_CAP|XFS_AT_INF|XFS_AT_XFLAGS|XFS_AT_EXTSIZE|\
133 XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|XFS_AT_PROJID|XFS_AT_GENCOUNT)
134
135#define XFS_AT_STAT (XFS_AT_TYPE|XFS_AT_MODE|XFS_AT_UID|XFS_AT_GID|\
136 XFS_AT_FSID|XFS_AT_NODEID|XFS_AT_NLINK|XFS_AT_SIZE|\
137 XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME|XFS_AT_RDEV|\
138 XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_PROJID)
139
140#define XFS_AT_TIMES (XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME) 125#define XFS_AT_TIMES (XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME)
141 126
142#define XFS_AT_UPDTIMES (XFS_AT_UPDATIME|XFS_AT_UPDMTIME|XFS_AT_UPDCTIME) 127#define XFS_AT_UPDTIMES (XFS_AT_UPDATIME|XFS_AT_UPDMTIME|XFS_AT_UPDCTIME)
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 8297a8c5af90..ed399523b782 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -94,7 +94,6 @@ xfs_setattr(
94 uid_t uid=0, iuid=0; 94 uid_t uid=0, iuid=0;
95 gid_t gid=0, igid=0; 95 gid_t gid=0, igid=0;
96 int timeflags = 0; 96 int timeflags = 0;
97 xfs_prid_t projid=0, iprojid=0;
98 struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; 97 struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2;
99 int file_owner; 98 int file_owner;
100 int need_iolock = 1; 99 int need_iolock = 1;
@@ -139,8 +138,7 @@ xfs_setattr(
139 * If the IDs do change before we take the ilock, we're covered 138 * If the IDs do change before we take the ilock, we're covered
140 * because the i_*dquot fields will get updated anyway. 139 * because the i_*dquot fields will get updated anyway.
141 */ 140 */
142 if (XFS_IS_QUOTA_ON(mp) && 141 if (XFS_IS_QUOTA_ON(mp) && (mask & (XFS_AT_UID|XFS_AT_GID))) {
143 (mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID))) {
144 uint qflags = 0; 142 uint qflags = 0;
145 143
146 if ((mask & XFS_AT_UID) && XFS_IS_UQUOTA_ON(mp)) { 144 if ((mask & XFS_AT_UID) && XFS_IS_UQUOTA_ON(mp)) {
@@ -155,12 +153,7 @@ xfs_setattr(
155 } else { 153 } else {
156 gid = ip->i_d.di_gid; 154 gid = ip->i_d.di_gid;
157 } 155 }
158 if ((mask & XFS_AT_PROJID) && XFS_IS_PQUOTA_ON(mp)) { 156
159 projid = vap->va_projid;
160 qflags |= XFS_QMOPT_PQUOTA;
161 } else {
162 projid = ip->i_d.di_projid;
163 }
164 /* 157 /*
165 * We take a reference when we initialize udqp and gdqp, 158 * We take a reference when we initialize udqp and gdqp,
166 * so it is important that we never blindly double trip on 159 * so it is important that we never blindly double trip on
@@ -168,8 +161,8 @@ xfs_setattr(
168 */ 161 */
169 ASSERT(udqp == NULL); 162 ASSERT(udqp == NULL);
170 ASSERT(gdqp == NULL); 163 ASSERT(gdqp == NULL);
171 code = XFS_QM_DQVOPALLOC(mp, ip, uid, gid, projid, qflags, 164 code = XFS_QM_DQVOPALLOC(mp, ip, uid, gid, ip->i_d.di_projid,
172 &udqp, &gdqp); 165 qflags, &udqp, &gdqp);
173 if (code) 166 if (code)
174 return code; 167 return code;
175 } 168 }
@@ -219,9 +212,7 @@ xfs_setattr(
219 * Only the owner or users with CAP_FOWNER 212 * Only the owner or users with CAP_FOWNER
220 * capability may do these things. 213 * capability may do these things.
221 */ 214 */
222 if (mask & 215 if (mask & (XFS_AT_MODE|XFS_AT_UID|XFS_AT_GID)) {
223 (XFS_AT_MODE|XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_UID|
224 XFS_AT_GID|XFS_AT_PROJID)) {
225 /* 216 /*
226 * CAP_FOWNER overrides the following restrictions: 217 * CAP_FOWNER overrides the following restrictions:
227 * 218 *
@@ -270,7 +261,7 @@ xfs_setattr(
270 * and can change the group id only to a group of which he 261 * and can change the group id only to a group of which he
271 * or she is a member. 262 * or she is a member.
272 */ 263 */
273 if (mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID)) { 264 if (mask & (XFS_AT_UID|XFS_AT_GID)) {
274 /* 265 /*
275 * These IDs could have changed since we last looked at them. 266 * These IDs could have changed since we last looked at them.
276 * But, we're assured that if the ownership did change 267 * But, we're assured that if the ownership did change
@@ -278,12 +269,9 @@ xfs_setattr(
278 * would have changed also. 269 * would have changed also.
279 */ 270 */
280 iuid = ip->i_d.di_uid; 271 iuid = ip->i_d.di_uid;
281 iprojid = ip->i_d.di_projid;
282 igid = ip->i_d.di_gid; 272 igid = ip->i_d.di_gid;
283 gid = (mask & XFS_AT_GID) ? vap->va_gid : igid; 273 gid = (mask & XFS_AT_GID) ? vap->va_gid : igid;
284 uid = (mask & XFS_AT_UID) ? vap->va_uid : iuid; 274 uid = (mask & XFS_AT_UID) ? vap->va_uid : iuid;
285 projid = (mask & XFS_AT_PROJID) ? (xfs_prid_t)vap->va_projid :
286 iprojid;
287 275
288 /* 276 /*
289 * CAP_CHOWN overrides the following restrictions: 277 * CAP_CHOWN overrides the following restrictions:
@@ -303,11 +291,10 @@ xfs_setattr(
303 goto error_return; 291 goto error_return;
304 } 292 }
305 /* 293 /*
306 * Do a quota reservation only if uid/projid/gid is actually 294 * Do a quota reservation only if uid/gid is actually
307 * going to change. 295 * going to change.
308 */ 296 */
309 if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) || 297 if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) ||
310 (XFS_IS_PQUOTA_ON(mp) && iprojid != projid) ||
311 (XFS_IS_GQUOTA_ON(mp) && igid != gid)) { 298 (XFS_IS_GQUOTA_ON(mp) && igid != gid)) {
312 ASSERT(tp); 299 ASSERT(tp);
313 code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp, 300 code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp,
@@ -361,78 +348,6 @@ xfs_setattr(
361 } 348 }
362 349
363 /* 350 /*
364 * Change extent size or realtime flag.
365 */
366 if (mask & (XFS_AT_EXTSIZE|XFS_AT_XFLAGS)) {
367 /*
368 * Can't change extent size if any extents are allocated.
369 */
370 if (ip->i_d.di_nextents && (mask & XFS_AT_EXTSIZE) &&
371 ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) !=
372 vap->va_extsize) ) {
373 code = XFS_ERROR(EINVAL); /* EFBIG? */
374 goto error_return;
375 }
376
377 /*
378 * Can't change realtime flag if any extents are allocated.
379 */
380 if ((ip->i_d.di_nextents || ip->i_delayed_blks) &&
381 (mask & XFS_AT_XFLAGS) &&
382 (XFS_IS_REALTIME_INODE(ip)) !=
383 (vap->va_xflags & XFS_XFLAG_REALTIME)) {
384 code = XFS_ERROR(EINVAL); /* EFBIG? */
385 goto error_return;
386 }
387 /*
388 * Extent size must be a multiple of the appropriate block
389 * size, if set at all.
390 */
391 if ((mask & XFS_AT_EXTSIZE) && vap->va_extsize != 0) {
392 xfs_extlen_t size;
393
394 if (XFS_IS_REALTIME_INODE(ip) ||
395 ((mask & XFS_AT_XFLAGS) &&
396 (vap->va_xflags & XFS_XFLAG_REALTIME))) {
397 size = mp->m_sb.sb_rextsize <<
398 mp->m_sb.sb_blocklog;
399 } else {
400 size = mp->m_sb.sb_blocksize;
401 }
402 if (vap->va_extsize % size) {
403 code = XFS_ERROR(EINVAL);
404 goto error_return;
405 }
406 }
407 /*
408 * If realtime flag is set then must have realtime data.
409 */
410 if ((mask & XFS_AT_XFLAGS) &&
411 (vap->va_xflags & XFS_XFLAG_REALTIME)) {
412 if ((mp->m_sb.sb_rblocks == 0) ||
413 (mp->m_sb.sb_rextsize == 0) ||
414 (ip->i_d.di_extsize % mp->m_sb.sb_rextsize)) {
415 code = XFS_ERROR(EINVAL);
416 goto error_return;
417 }
418 }
419
420 /*
421 * Can't modify an immutable/append-only file unless
422 * we have appropriate permission.
423 */
424 if ((mask & XFS_AT_XFLAGS) &&
425 (ip->i_d.di_flags &
426 (XFS_DIFLAG_IMMUTABLE|XFS_DIFLAG_APPEND) ||
427 (vap->va_xflags &
428 (XFS_XFLAG_IMMUTABLE | XFS_XFLAG_APPEND))) &&
429 !capable(CAP_LINUX_IMMUTABLE)) {
430 code = XFS_ERROR(EPERM);
431 goto error_return;
432 }
433 }
434
435 /*
436 * Now we can make the changes. Before we join the inode 351 * Now we can make the changes. Before we join the inode
437 * to the transaction, if XFS_AT_SIZE is set then take care of 352 * to the transaction, if XFS_AT_SIZE is set then take care of
438 * the part of the truncation that must be done without the 353 * the part of the truncation that must be done without the
@@ -568,7 +483,7 @@ xfs_setattr(
568 * and can change the group id only to a group of which he 483 * and can change the group id only to a group of which he
569 * or she is a member. 484 * or she is a member.
570 */ 485 */
571 if (mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID)) { 486 if (mask & (XFS_AT_UID|XFS_AT_GID)) {
572 /* 487 /*
573 * CAP_FSETID overrides the following restrictions: 488 * CAP_FSETID overrides the following restrictions:
574 * 489 *
@@ -603,23 +518,6 @@ xfs_setattr(
603 } 518 }
604 ip->i_d.di_gid = gid; 519 ip->i_d.di_gid = gid;
605 } 520 }
606 if (iprojid != projid) {
607 if (XFS_IS_PQUOTA_ON(mp)) {
608 ASSERT(!XFS_IS_GQUOTA_ON(mp));
609 ASSERT(mask & XFS_AT_PROJID);
610 ASSERT(gdqp);
611 olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip,
612 &ip->i_gdquot, gdqp);
613 }
614 ip->i_d.di_projid = projid;
615 /*
616 * We may have to rev the inode as well as
617 * the superblock version number since projids didn't
618 * exist before DINODE_VERSION_2 and SB_VERSION_NLINK.
619 */
620 if (ip->i_d.di_version == XFS_DINODE_VERSION_1)
621 xfs_bump_ino_vers2(tp, ip);
622 }
623 521
624 xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); 522 xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE);
625 timeflags |= XFS_ICHGTIME_CHG; 523 timeflags |= XFS_ICHGTIME_CHG;
@@ -647,57 +545,6 @@ xfs_setattr(
647 } 545 }
648 546
649 /* 547 /*
650 * Change XFS-added attributes.
651 */
652 if (mask & (XFS_AT_EXTSIZE|XFS_AT_XFLAGS)) {
653 if (mask & XFS_AT_EXTSIZE) {
654 /*
655 * Converting bytes to fs blocks.
656 */
657 ip->i_d.di_extsize = vap->va_extsize >>
658 mp->m_sb.sb_blocklog;
659 }
660 if (mask & XFS_AT_XFLAGS) {
661 uint di_flags;
662
663 /* can't set PREALLOC this way, just preserve it */
664 di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC);
665 if (vap->va_xflags & XFS_XFLAG_IMMUTABLE)
666 di_flags |= XFS_DIFLAG_IMMUTABLE;
667 if (vap->va_xflags & XFS_XFLAG_APPEND)
668 di_flags |= XFS_DIFLAG_APPEND;
669 if (vap->va_xflags & XFS_XFLAG_SYNC)
670 di_flags |= XFS_DIFLAG_SYNC;
671 if (vap->va_xflags & XFS_XFLAG_NOATIME)
672 di_flags |= XFS_DIFLAG_NOATIME;
673 if (vap->va_xflags & XFS_XFLAG_NODUMP)
674 di_flags |= XFS_DIFLAG_NODUMP;
675 if (vap->va_xflags & XFS_XFLAG_PROJINHERIT)
676 di_flags |= XFS_DIFLAG_PROJINHERIT;
677 if (vap->va_xflags & XFS_XFLAG_NODEFRAG)
678 di_flags |= XFS_DIFLAG_NODEFRAG;
679 if (vap->va_xflags & XFS_XFLAG_FILESTREAM)
680 di_flags |= XFS_DIFLAG_FILESTREAM;
681 if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
682 if (vap->va_xflags & XFS_XFLAG_RTINHERIT)
683 di_flags |= XFS_DIFLAG_RTINHERIT;
684 if (vap->va_xflags & XFS_XFLAG_NOSYMLINKS)
685 di_flags |= XFS_DIFLAG_NOSYMLINKS;
686 if (vap->va_xflags & XFS_XFLAG_EXTSZINHERIT)
687 di_flags |= XFS_DIFLAG_EXTSZINHERIT;
688 } else if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) {
689 if (vap->va_xflags & XFS_XFLAG_REALTIME)
690 di_flags |= XFS_DIFLAG_REALTIME;
691 if (vap->va_xflags & XFS_XFLAG_EXTSIZE)
692 di_flags |= XFS_DIFLAG_EXTSIZE;
693 }
694 ip->i_d.di_flags = di_flags;
695 }
696 xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
697 timeflags |= XFS_ICHGTIME_CHG;
698 }
699
700 /*
701 * Change file inode change time only if XFS_AT_CTIME set 548 * Change file inode change time only if XFS_AT_CTIME set
702 * AND we have been called by a DMI function. 549 * AND we have been called by a DMI function.
703 */ 550 */