diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-05-01 12:11:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-05-01 12:11:45 -0400 |
commit | f2125992e7cb25ece668cb7af2bd8433715827d1 (patch) | |
tree | b77642b52ae91c6bb0c6a932e0339361af9a5d86 | |
parent | fff75eb2a08c2ac96404a2d79685668f3cf5a7a3 (diff) | |
parent | 7b38460dc8e4eafba06c78f8e37099d3b34d473c (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.c | 9 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_bmap.c | 4 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_inode_buf.c | 21 | ||||
-rw-r--r-- | fs/xfs/xfs_file.c | 14 |
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 | } |