aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_vnodeops.c
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/xfs_vnodeops.c
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/xfs_vnodeops.c')
-rw-r--r--fs/xfs/xfs_vnodeops.c169
1 files changed, 8 insertions, 161 deletions
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 */