aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-05-01 12:11:45 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-05-01 12:11:45 -0400
commitf2125992e7cb25ece668cb7af2bd8433715827d1 (patch)
treeb77642b52ae91c6bb0c6a932e0339361af9a5d86
parentfff75eb2a08c2ac96404a2d79685668f3cf5a7a3 (diff)
parent7b38460dc8e4eafba06c78f8e37099d3b34d473c (diff)
Merge tag 'xfs-4.17-fixes-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
Pull xfs fixes from Darrick Wong: "Here are a few more bug fixes for xfs for 4.17-rc4. Most of them are fixes for bad behavior. This series has been run through a full xfstests run during LSF and through a quick xfstests run against this morning's master, with no major failures reported. Summary: - Enhance inode fork verifiers to prevent loading of corrupted metadata. - Fix a crash when we try to convert extents format inodes to btree format, we run out of space, but forget to revert the in-core state changes. - Fix file size checks when doing INSERT_RANGE that could cause files to end up negative size if there previously was an extent mapped at s_maxbytes. - Fix a bug when doing a remove-then-add ATTR_REPLACE xattr update where we forget to clear ATTR_REPLACE after the remove, which causes the attr to be lost and the fs to shut down due to (what it thinks is) inconsistent in-core state" * tag 'xfs-4.17-fixes-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: xfs: don't fail when converting shortform attr to long form during ATTR_REPLACE xfs: prevent creating negative-sized file via INSERT_RANGE xfs: set format back to extents if xfs_bmap_extents_to_btree xfs: enhance dinode verifier
-rw-r--r--fs/xfs/libxfs/xfs_attr.c9
-rw-r--r--fs/xfs/libxfs/xfs_bmap.c4
-rw-r--r--fs/xfs/libxfs/xfs_inode_buf.c21
-rw-r--r--fs/xfs/xfs_file.c14
4 files changed, 42 insertions, 6 deletions
diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index ce4a34a2751d..35a124400d60 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -511,7 +511,14 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
511 if (args->flags & ATTR_CREATE) 511 if (args->flags & ATTR_CREATE)
512 return retval; 512 return retval;
513 retval = xfs_attr_shortform_remove(args); 513 retval = xfs_attr_shortform_remove(args);
514 ASSERT(retval == 0); 514 if (retval)
515 return retval;
516 /*
517 * Since we have removed the old attr, clear ATTR_REPLACE so
518 * that the leaf format add routine won't trip over the attr
519 * not being around.
520 */
521 args->flags &= ~ATTR_REPLACE;
515 } 522 }
516 523
517 if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX || 524 if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index 6a7c2f03ea11..040eeda8426f 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -725,12 +725,16 @@ xfs_bmap_extents_to_btree(
725 *logflagsp = 0; 725 *logflagsp = 0;
726 if ((error = xfs_alloc_vextent(&args))) { 726 if ((error = xfs_alloc_vextent(&args))) {
727 xfs_iroot_realloc(ip, -1, whichfork); 727 xfs_iroot_realloc(ip, -1, whichfork);
728 ASSERT(ifp->if_broot == NULL);
729 XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS);
728 xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); 730 xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
729 return error; 731 return error;
730 } 732 }
731 733
732 if (WARN_ON_ONCE(args.fsbno == NULLFSBLOCK)) { 734 if (WARN_ON_ONCE(args.fsbno == NULLFSBLOCK)) {
733 xfs_iroot_realloc(ip, -1, whichfork); 735 xfs_iroot_realloc(ip, -1, whichfork);
736 ASSERT(ifp->if_broot == NULL);
737 XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS);
734 xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); 738 xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
735 return -ENOSPC; 739 return -ENOSPC;
736 } 740 }
diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
index ef68b1de006a..1201107eabc6 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.c
+++ b/fs/xfs/libxfs/xfs_inode_buf.c
@@ -466,6 +466,8 @@ xfs_dinode_verify(
466 return __this_address; 466 return __this_address;
467 if (di_size > XFS_DFORK_DSIZE(dip, mp)) 467 if (di_size > XFS_DFORK_DSIZE(dip, mp))
468 return __this_address; 468 return __this_address;
469 if (dip->di_nextents)
470 return __this_address;
469 /* fall through */ 471 /* fall through */
470 case XFS_DINODE_FMT_EXTENTS: 472 case XFS_DINODE_FMT_EXTENTS:
471 case XFS_DINODE_FMT_BTREE: 473 case XFS_DINODE_FMT_BTREE:
@@ -484,12 +486,31 @@ xfs_dinode_verify(
484 if (XFS_DFORK_Q(dip)) { 486 if (XFS_DFORK_Q(dip)) {
485 switch (dip->di_aformat) { 487 switch (dip->di_aformat) {
486 case XFS_DINODE_FMT_LOCAL: 488 case XFS_DINODE_FMT_LOCAL:
489 if (dip->di_anextents)
490 return __this_address;
491 /* fall through */
487 case XFS_DINODE_FMT_EXTENTS: 492 case XFS_DINODE_FMT_EXTENTS:
488 case XFS_DINODE_FMT_BTREE: 493 case XFS_DINODE_FMT_BTREE:
489 break; 494 break;
490 default: 495 default:
491 return __this_address; 496 return __this_address;
492 } 497 }
498 } else {
499 /*
500 * If there is no fork offset, this may be a freshly-made inode
501 * in a new disk cluster, in which case di_aformat is zeroed.
502 * Otherwise, such an inode must be in EXTENTS format; this goes
503 * for freed inodes as well.
504 */
505 switch (dip->di_aformat) {
506 case 0:
507 case XFS_DINODE_FMT_EXTENTS:
508 break;
509 default:
510 return __this_address;
511 }
512 if (dip->di_anextents)
513 return __this_address;
493 } 514 }
494 515
495 /* only version 3 or greater inodes are extensively verified here */ 516 /* only version 3 or greater inodes are extensively verified here */
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 299aee4b7b0b..eed073cc4778 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -778,22 +778,26 @@ xfs_file_fallocate(
778 if (error) 778 if (error)
779 goto out_unlock; 779 goto out_unlock;
780 } else if (mode & FALLOC_FL_INSERT_RANGE) { 780 } else if (mode & FALLOC_FL_INSERT_RANGE) {
781 unsigned int blksize_mask = i_blocksize(inode) - 1; 781 unsigned int blksize_mask = i_blocksize(inode) - 1;
782 loff_t isize = i_size_read(inode);
782 783
783 new_size = i_size_read(inode) + len;
784 if (offset & blksize_mask || len & blksize_mask) { 784 if (offset & blksize_mask || len & blksize_mask) {
785 error = -EINVAL; 785 error = -EINVAL;
786 goto out_unlock; 786 goto out_unlock;
787 } 787 }
788 788
789 /* check the new inode size does not wrap through zero */ 789 /*
790 if (new_size > inode->i_sb->s_maxbytes) { 790 * New inode size must not exceed ->s_maxbytes, accounting for
791 * possible signed overflow.
792 */
793 if (inode->i_sb->s_maxbytes - isize < len) {
791 error = -EFBIG; 794 error = -EFBIG;
792 goto out_unlock; 795 goto out_unlock;
793 } 796 }
797 new_size = isize + len;
794 798
795 /* Offset should be less than i_size */ 799 /* Offset should be less than i_size */
796 if (offset >= i_size_read(inode)) { 800 if (offset >= isize) {
797 error = -EINVAL; 801 error = -EINVAL;
798 goto out_unlock; 802 goto out_unlock;
799 } 803 }