aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-05-31 17:50:16 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-05-31 17:50:16 -0400
commite8d256aca05b6de163605a04f86e5827ef77899f (patch)
tree05de636b72b3d96808daea2aba104e07d722f79d /fs
parent977b55cf988b86cdc929fef730a78aca98a8ebdb (diff)
parente400d27d1690d609f203f2d7d8efebc98cbc3089 (diff)
Merge tag 'for-linus-v3.10-rc4' of git://oss.sgi.com/xfs/xfs
Pull xfs fixes from Ben Myers: - Fix nested transactions in xfs_qm_scall_setqlim - Clear suid/sgid bits when we truncate with size update - Fix recovery for split buffers - Fix block count on remote symlinks - Add fsgeom flag for v5 superblock support - Disable XFS_IOC_SWAPEXT for CRC enabled filesystems - Fix dirv3 freespace block corruption * tag 'for-linus-v3.10-rc4' of git://oss.sgi.com/xfs/xfs: xfs: fix dir3 freespace block corruption xfs: disable swap extents ioctl on CRC enabled filesystems xfs: add fsgeom flag for v5 superblock support. xfs: fix incorrect remote symlink block count xfs: fix split buffer vector log recovery support xfs: kill suid/sgid through the truncate path. xfs: avoid nesting transactions in xfs_qm_scall_setqlim()
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/xfs_buf_item.c7
-rw-r--r--fs/xfs/xfs_dfrag.c8
-rw-r--r--fs/xfs/xfs_dir2_format.h1
-rw-r--r--fs/xfs/xfs_dir2_node.c13
-rw-r--r--fs/xfs/xfs_fs.h1
-rw-r--r--fs/xfs/xfs_fsops.c4
-rw-r--r--fs/xfs/xfs_iops.c47
-rw-r--r--fs/xfs/xfs_log_recover.c11
-rw-r--r--fs/xfs/xfs_qm_syscalls.c40
-rw-r--r--fs/xfs/xfs_symlink.c20
10 files changed, 92 insertions, 60 deletions
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index cf263476d6b4..4ec431777048 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -262,12 +262,7 @@ xfs_buf_item_format_segment(
262 vecp->i_addr = xfs_buf_offset(bp, buffer_offset); 262 vecp->i_addr = xfs_buf_offset(bp, buffer_offset);
263 vecp->i_len = nbits * XFS_BLF_CHUNK; 263 vecp->i_len = nbits * XFS_BLF_CHUNK;
264 vecp->i_type = XLOG_REG_TYPE_BCHUNK; 264 vecp->i_type = XLOG_REG_TYPE_BCHUNK;
265/* 265 nvecs++;
266 * You would think we need to bump the nvecs here too, but we do not
267 * this number is used by recovery, and it gets confused by the boundary
268 * split here
269 * nvecs++;
270 */
271 vecp++; 266 vecp++;
272 first_bit = next_bit; 267 first_bit = next_bit;
273 last_bit = next_bit; 268 last_bit = next_bit;
diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c
index f852b082a084..c407e1ccff43 100644
--- a/fs/xfs/xfs_dfrag.c
+++ b/fs/xfs/xfs_dfrag.c
@@ -219,6 +219,14 @@ xfs_swap_extents(
219 int taforkblks = 0; 219 int taforkblks = 0;
220 __uint64_t tmp; 220 __uint64_t tmp;
221 221
222 /*
223 * We have no way of updating owner information in the BMBT blocks for
224 * each inode on CRC enabled filesystems, so to avoid corrupting the
225 * this metadata we simply don't allow extent swaps to occur.
226 */
227 if (xfs_sb_version_hascrc(&mp->m_sb))
228 return XFS_ERROR(EINVAL);
229
222 tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL); 230 tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL);
223 if (!tempifp) { 231 if (!tempifp) {
224 error = XFS_ERROR(ENOMEM); 232 error = XFS_ERROR(ENOMEM);
diff --git a/fs/xfs/xfs_dir2_format.h b/fs/xfs/xfs_dir2_format.h
index a3b1bd841a80..995f1f505a52 100644
--- a/fs/xfs/xfs_dir2_format.h
+++ b/fs/xfs/xfs_dir2_format.h
@@ -715,6 +715,7 @@ struct xfs_dir3_free_hdr {
715 __be32 firstdb; /* db of first entry */ 715 __be32 firstdb; /* db of first entry */
716 __be32 nvalid; /* count of valid entries */ 716 __be32 nvalid; /* count of valid entries */
717 __be32 nused; /* count of used entries */ 717 __be32 nused; /* count of used entries */
718 __be32 pad; /* 64 bit alignment. */
718}; 719};
719 720
720struct xfs_dir3_free { 721struct xfs_dir3_free {
diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c
index 5246de4912d4..2226a00acd15 100644
--- a/fs/xfs/xfs_dir2_node.c
+++ b/fs/xfs/xfs_dir2_node.c
@@ -263,18 +263,19 @@ xfs_dir3_free_get_buf(
263 * Initialize the new block to be empty, and remember 263 * Initialize the new block to be empty, and remember
264 * its first slot as our empty slot. 264 * its first slot as our empty slot.
265 */ 265 */
266 hdr.magic = XFS_DIR2_FREE_MAGIC; 266 memset(bp->b_addr, 0, sizeof(struct xfs_dir3_free_hdr));
267 hdr.firstdb = 0; 267 memset(&hdr, 0, sizeof(hdr));
268 hdr.nused = 0; 268
269 hdr.nvalid = 0;
270 if (xfs_sb_version_hascrc(&mp->m_sb)) { 269 if (xfs_sb_version_hascrc(&mp->m_sb)) {
271 struct xfs_dir3_free_hdr *hdr3 = bp->b_addr; 270 struct xfs_dir3_free_hdr *hdr3 = bp->b_addr;
272 271
273 hdr.magic = XFS_DIR3_FREE_MAGIC; 272 hdr.magic = XFS_DIR3_FREE_MAGIC;
273
274 hdr3->hdr.blkno = cpu_to_be64(bp->b_bn); 274 hdr3->hdr.blkno = cpu_to_be64(bp->b_bn);
275 hdr3->hdr.owner = cpu_to_be64(dp->i_ino); 275 hdr3->hdr.owner = cpu_to_be64(dp->i_ino);
276 uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_uuid); 276 uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_uuid);
277 } 277 } else
278 hdr.magic = XFS_DIR2_FREE_MAGIC;
278 xfs_dir3_free_hdr_to_disk(bp->b_addr, &hdr); 279 xfs_dir3_free_hdr_to_disk(bp->b_addr, &hdr);
279 *bpp = bp; 280 *bpp = bp;
280 return 0; 281 return 0;
@@ -1921,8 +1922,6 @@ xfs_dir2_node_addname_int(
1921 */ 1922 */
1922 freehdr.firstdb = (fbno - XFS_DIR2_FREE_FIRSTDB(mp)) * 1923 freehdr.firstdb = (fbno - XFS_DIR2_FREE_FIRSTDB(mp)) *
1923 xfs_dir3_free_max_bests(mp); 1924 xfs_dir3_free_max_bests(mp);
1924 free->hdr.nvalid = 0;
1925 free->hdr.nused = 0;
1926 } else { 1925 } else {
1927 free = fbp->b_addr; 1926 free = fbp->b_addr;
1928 bests = xfs_dir3_free_bests_p(mp, free); 1927 bests = xfs_dir3_free_bests_p(mp, free);
diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h
index 6dda3f949b04..d04695545397 100644
--- a/fs/xfs/xfs_fs.h
+++ b/fs/xfs/xfs_fs.h
@@ -236,6 +236,7 @@ typedef struct xfs_fsop_resblks {
236#define XFS_FSOP_GEOM_FLAGS_PROJID32 0x0800 /* 32-bit project IDs */ 236#define XFS_FSOP_GEOM_FLAGS_PROJID32 0x0800 /* 32-bit project IDs */
237#define XFS_FSOP_GEOM_FLAGS_DIRV2CI 0x1000 /* ASCII only CI names */ 237#define XFS_FSOP_GEOM_FLAGS_DIRV2CI 0x1000 /* ASCII only CI names */
238#define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */ 238#define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */
239#define XFS_FSOP_GEOM_FLAGS_V5SB 0x8000 /* version 5 superblock */
239 240
240 241
241/* 242/*
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index 87595b211da1..3c3644ea825b 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -99,7 +99,9 @@ xfs_fs_geometry(
99 (xfs_sb_version_hasattr2(&mp->m_sb) ? 99 (xfs_sb_version_hasattr2(&mp->m_sb) ?
100 XFS_FSOP_GEOM_FLAGS_ATTR2 : 0) | 100 XFS_FSOP_GEOM_FLAGS_ATTR2 : 0) |
101 (xfs_sb_version_hasprojid32bit(&mp->m_sb) ? 101 (xfs_sb_version_hasprojid32bit(&mp->m_sb) ?
102 XFS_FSOP_GEOM_FLAGS_PROJID32 : 0); 102 XFS_FSOP_GEOM_FLAGS_PROJID32 : 0) |
103 (xfs_sb_version_hascrc(&mp->m_sb) ?
104 XFS_FSOP_GEOM_FLAGS_V5SB : 0);
103 geo->logsectsize = xfs_sb_version_hassector(&mp->m_sb) ? 105 geo->logsectsize = xfs_sb_version_hassector(&mp->m_sb) ?
104 mp->m_sb.sb_logsectsize : BBSIZE; 106 mp->m_sb.sb_logsectsize : BBSIZE;
105 geo->rtsectsize = mp->m_sb.sb_blocksize; 107 geo->rtsectsize = mp->m_sb.sb_blocksize;
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index d82efaa2ac73..ca9ecaa81112 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -455,6 +455,28 @@ xfs_vn_getattr(
455 return 0; 455 return 0;
456} 456}
457 457
458static void
459xfs_setattr_mode(
460 struct xfs_trans *tp,
461 struct xfs_inode *ip,
462 struct iattr *iattr)
463{
464 struct inode *inode = VFS_I(ip);
465 umode_t mode = iattr->ia_mode;
466
467 ASSERT(tp);
468 ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
469
470 if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
471 mode &= ~S_ISGID;
472
473 ip->i_d.di_mode &= S_IFMT;
474 ip->i_d.di_mode |= mode & ~S_IFMT;
475
476 inode->i_mode &= S_IFMT;
477 inode->i_mode |= mode & ~S_IFMT;
478}
479
458int 480int
459xfs_setattr_nonsize( 481xfs_setattr_nonsize(
460 struct xfs_inode *ip, 482 struct xfs_inode *ip,
@@ -606,18 +628,8 @@ xfs_setattr_nonsize(
606 /* 628 /*
607 * Change file access modes. 629 * Change file access modes.
608 */ 630 */
609 if (mask & ATTR_MODE) { 631 if (mask & ATTR_MODE)
610 umode_t mode = iattr->ia_mode; 632 xfs_setattr_mode(tp, ip, iattr);
611
612 if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
613 mode &= ~S_ISGID;
614
615 ip->i_d.di_mode &= S_IFMT;
616 ip->i_d.di_mode |= mode & ~S_IFMT;
617
618 inode->i_mode &= S_IFMT;
619 inode->i_mode |= mode & ~S_IFMT;
620 }
621 633
622 /* 634 /*
623 * Change file access or modified times. 635 * Change file access or modified times.
@@ -714,9 +726,8 @@ xfs_setattr_size(
714 return XFS_ERROR(error); 726 return XFS_ERROR(error);
715 727
716 ASSERT(S_ISREG(ip->i_d.di_mode)); 728 ASSERT(S_ISREG(ip->i_d.di_mode));
717 ASSERT((mask & (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET| 729 ASSERT((mask & (ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET|
718 ATTR_MTIME_SET|ATTR_KILL_SUID|ATTR_KILL_SGID| 730 ATTR_MTIME_SET|ATTR_KILL_PRIV|ATTR_TIMES_SET)) == 0);
719 ATTR_KILL_PRIV|ATTR_TIMES_SET)) == 0);
720 731
721 if (!(flags & XFS_ATTR_NOLOCK)) { 732 if (!(flags & XFS_ATTR_NOLOCK)) {
722 lock_flags |= XFS_IOLOCK_EXCL; 733 lock_flags |= XFS_IOLOCK_EXCL;
@@ -860,6 +871,12 @@ xfs_setattr_size(
860 xfs_inode_clear_eofblocks_tag(ip); 871 xfs_inode_clear_eofblocks_tag(ip);
861 } 872 }
862 873
874 /*
875 * Change file access modes.
876 */
877 if (mask & ATTR_MODE)
878 xfs_setattr_mode(tp, ip, iattr);
879
863 if (mask & ATTR_CTIME) { 880 if (mask & ATTR_CTIME) {
864 inode->i_ctime = iattr->ia_ctime; 881 inode->i_ctime = iattr->ia_ctime;
865 ip->i_d.di_ctime.t_sec = iattr->ia_ctime.tv_sec; 882 ip->i_d.di_ctime.t_sec = iattr->ia_ctime.tv_sec;
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 93f03ec17eec..d9e4d3c3991a 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -2097,6 +2097,17 @@ xlog_recover_do_reg_buffer(
2097 ((uint)bit << XFS_BLF_SHIFT) + (nbits << XFS_BLF_SHIFT)); 2097 ((uint)bit << XFS_BLF_SHIFT) + (nbits << XFS_BLF_SHIFT));
2098 2098
2099 /* 2099 /*
2100 * The dirty regions logged in the buffer, even though
2101 * contiguous, may span multiple chunks. This is because the
2102 * dirty region may span a physical page boundary in a buffer
2103 * and hence be split into two separate vectors for writing into
2104 * the log. Hence we need to trim nbits back to the length of
2105 * the current region being copied out of the log.
2106 */
2107 if (item->ri_buf[i].i_len < (nbits << XFS_BLF_SHIFT))
2108 nbits = item->ri_buf[i].i_len >> XFS_BLF_SHIFT;
2109
2110 /*
2100 * Do a sanity check if this is a dquot buffer. Just checking 2111 * Do a sanity check if this is a dquot buffer. Just checking
2101 * the first dquot in the buffer should do. XXXThis is 2112 * the first dquot in the buffer should do. XXXThis is
2102 * probably a good thing to do for other buf types also. 2113 * probably a good thing to do for other buf types also.
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index c41190cad6e9..6cdf6ffc36a1 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -489,31 +489,36 @@ xfs_qm_scall_setqlim(
489 if ((newlim->d_fieldmask & XFS_DQ_MASK) == 0) 489 if ((newlim->d_fieldmask & XFS_DQ_MASK) == 0)
490 return 0; 490 return 0;
491 491
492 tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SETQLIM);
493 error = xfs_trans_reserve(tp, 0, XFS_QM_SETQLIM_LOG_RES(mp),
494 0, 0, XFS_DEFAULT_LOG_COUNT);
495 if (error) {
496 xfs_trans_cancel(tp, 0);
497 return (error);
498 }
499
500 /* 492 /*
501 * We don't want to race with a quotaoff so take the quotaoff lock. 493 * We don't want to race with a quotaoff so take the quotaoff lock.
502 * (We don't hold an inode lock, so there's nothing else to stop 494 * We don't hold an inode lock, so there's nothing else to stop
503 * a quotaoff from happening). (XXXThis doesn't currently happen 495 * a quotaoff from happening.
504 * because we take the vfslock before calling xfs_qm_sysent).
505 */ 496 */
506 mutex_lock(&q->qi_quotaofflock); 497 mutex_lock(&q->qi_quotaofflock);
507 498
508 /* 499 /*
509 * Get the dquot (locked), and join it to the transaction. 500 * Get the dquot (locked) before we start, as we need to do a
510 * Allocate the dquot if this doesn't exist. 501 * transaction to allocate it if it doesn't exist. Once we have the
502 * dquot, unlock it so we can start the next transaction safely. We hold
503 * a reference to the dquot, so it's safe to do this unlock/lock without
504 * it being reclaimed in the mean time.
511 */ 505 */
512 if ((error = xfs_qm_dqget(mp, NULL, id, type, XFS_QMOPT_DQALLOC, &dqp))) { 506 error = xfs_qm_dqget(mp, NULL, id, type, XFS_QMOPT_DQALLOC, &dqp);
513 xfs_trans_cancel(tp, XFS_TRANS_ABORT); 507 if (error) {
514 ASSERT(error != ENOENT); 508 ASSERT(error != ENOENT);
515 goto out_unlock; 509 goto out_unlock;
516 } 510 }
511 xfs_dqunlock(dqp);
512
513 tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SETQLIM);
514 error = xfs_trans_reserve(tp, 0, XFS_QM_SETQLIM_LOG_RES(mp),
515 0, 0, XFS_DEFAULT_LOG_COUNT);
516 if (error) {
517 xfs_trans_cancel(tp, 0);
518 goto out_rele;
519 }
520
521 xfs_dqlock(dqp);
517 xfs_trans_dqjoin(tp, dqp); 522 xfs_trans_dqjoin(tp, dqp);
518 ddq = &dqp->q_core; 523 ddq = &dqp->q_core;
519 524
@@ -621,9 +626,10 @@ xfs_qm_scall_setqlim(
621 xfs_trans_log_dquot(tp, dqp); 626 xfs_trans_log_dquot(tp, dqp);
622 627
623 error = xfs_trans_commit(tp, 0); 628 error = xfs_trans_commit(tp, 0);
624 xfs_qm_dqrele(dqp);
625 629
626 out_unlock: 630out_rele:
631 xfs_qm_dqrele(dqp);
632out_unlock:
627 mutex_unlock(&q->qi_quotaofflock); 633 mutex_unlock(&q->qi_quotaofflock);
628 return error; 634 return error;
629} 635}
diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
index 5f234389327c..195a403e1522 100644
--- a/fs/xfs/xfs_symlink.c
+++ b/fs/xfs/xfs_symlink.c
@@ -56,16 +56,9 @@ xfs_symlink_blocks(
56 struct xfs_mount *mp, 56 struct xfs_mount *mp,
57 int pathlen) 57 int pathlen)
58{ 58{
59 int fsblocks = 0; 59 int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
60 int len = pathlen;
61 60
62 do { 61 return (pathlen + buflen - 1) / buflen;
63 fsblocks++;
64 len -= XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
65 } while (len > 0);
66
67 ASSERT(fsblocks <= XFS_SYMLINK_MAPS);
68 return fsblocks;
69} 62}
70 63
71static int 64static int
@@ -405,7 +398,7 @@ xfs_symlink(
405 if (pathlen <= XFS_LITINO(mp, dp->i_d.di_version)) 398 if (pathlen <= XFS_LITINO(mp, dp->i_d.di_version))
406 fs_blocks = 0; 399 fs_blocks = 0;
407 else 400 else
408 fs_blocks = XFS_B_TO_FSB(mp, pathlen); 401 fs_blocks = xfs_symlink_blocks(mp, pathlen);
409 resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks); 402 resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks);
410 error = xfs_trans_reserve(tp, resblks, XFS_SYMLINK_LOG_RES(mp), 0, 403 error = xfs_trans_reserve(tp, resblks, XFS_SYMLINK_LOG_RES(mp), 0,
411 XFS_TRANS_PERM_LOG_RES, XFS_SYMLINK_LOG_COUNT); 404 XFS_TRANS_PERM_LOG_RES, XFS_SYMLINK_LOG_COUNT);
@@ -512,7 +505,7 @@ xfs_symlink(
512 cur_chunk = target_path; 505 cur_chunk = target_path;
513 offset = 0; 506 offset = 0;
514 for (n = 0; n < nmaps; n++) { 507 for (n = 0; n < nmaps; n++) {
515 char *buf; 508 char *buf;
516 509
517 d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); 510 d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
518 byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); 511 byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
@@ -525,9 +518,7 @@ xfs_symlink(
525 bp->b_ops = &xfs_symlink_buf_ops; 518 bp->b_ops = &xfs_symlink_buf_ops;
526 519
527 byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt); 520 byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
528 if (pathlen < byte_cnt) { 521 byte_cnt = min(byte_cnt, pathlen);
529 byte_cnt = pathlen;
530 }
531 522
532 buf = bp->b_addr; 523 buf = bp->b_addr;
533 buf += xfs_symlink_hdr_set(mp, ip->i_ino, offset, 524 buf += xfs_symlink_hdr_set(mp, ip->i_ino, offset,
@@ -542,6 +533,7 @@ xfs_symlink(
542 xfs_trans_log_buf(tp, bp, 0, (buf + byte_cnt - 1) - 533 xfs_trans_log_buf(tp, bp, 0, (buf + byte_cnt - 1) -
543 (char *)bp->b_addr); 534 (char *)bp->b_addr);
544 } 535 }
536 ASSERT(pathlen == 0);
545 } 537 }
546 538
547 /* 539 /*