diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-28 17:29:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-28 17:29:48 -0400 |
commit | 19993e7378533d8d802d707be271074f2eb8e4fd (patch) | |
tree | 566d8b6b0c28f0f3315d6dfd22c5b3708faec5b7 | |
parent | 8155469341a60ba7064d64b62bb32af5a901ccaf (diff) | |
parent | 5b094d6dac0451ad89b1dc088395c7b399b7e9e8 (diff) |
Merge tag 'xfs-4.13-fixes-2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
Pull xfs fixes from Darrick Wong:
- fix firstfsb variables that we left uninitialized, which could lead
to locking problems.
- check for NULL metadata buffer pointers before using them.
- don't allow btree cursor manipulation if the btree block is corrupt.
Better to just shut down.
- fix infinite loop problems in quotacheck.
- fix buffer overrun when validating directory blocks.
- fix deadlock problem in bunmapi.
* tag 'xfs-4.13-fixes-2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux:
xfs: fix multi-AG deadlock in xfs_bunmapi
xfs: check that dir block entries don't off the end of the buffer
xfs: fix quotacheck dquot id overflow infinite loop
xfs: check _alloc_read_agf buffer pointer before using
xfs: set firstfsb to NULLFSBLOCK before feeding it to _bmapi_write
xfs: check _btree_check_block value
-rw-r--r-- | fs/xfs/libxfs/xfs_bmap.c | 21 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_btree.c | 6 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_dir2_data.c | 4 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_refcount.c | 4 | ||||
-rw-r--r-- | fs/xfs/xfs_qm.c | 3 | ||||
-rw-r--r-- | fs/xfs/xfs_reflink.c | 4 |
6 files changed, 39 insertions, 3 deletions
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 0a9880777c9c..c09c16b1ad3b 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c | |||
@@ -5435,6 +5435,7 @@ __xfs_bunmapi( | |||
5435 | xfs_fsblock_t sum; | 5435 | xfs_fsblock_t sum; |
5436 | xfs_filblks_t len = *rlen; /* length to unmap in file */ | 5436 | xfs_filblks_t len = *rlen; /* length to unmap in file */ |
5437 | xfs_fileoff_t max_len; | 5437 | xfs_fileoff_t max_len; |
5438 | xfs_agnumber_t prev_agno = NULLAGNUMBER, agno; | ||
5438 | 5439 | ||
5439 | trace_xfs_bunmap(ip, bno, len, flags, _RET_IP_); | 5440 | trace_xfs_bunmap(ip, bno, len, flags, _RET_IP_); |
5440 | 5441 | ||
@@ -5534,6 +5535,17 @@ __xfs_bunmapi( | |||
5534 | */ | 5535 | */ |
5535 | del = got; | 5536 | del = got; |
5536 | wasdel = isnullstartblock(del.br_startblock); | 5537 | wasdel = isnullstartblock(del.br_startblock); |
5538 | |||
5539 | /* | ||
5540 | * Make sure we don't touch multiple AGF headers out of order | ||
5541 | * in a single transaction, as that could cause AB-BA deadlocks. | ||
5542 | */ | ||
5543 | if (!wasdel) { | ||
5544 | agno = XFS_FSB_TO_AGNO(mp, del.br_startblock); | ||
5545 | if (prev_agno != NULLAGNUMBER && prev_agno > agno) | ||
5546 | break; | ||
5547 | prev_agno = agno; | ||
5548 | } | ||
5537 | if (got.br_startoff < start) { | 5549 | if (got.br_startoff < start) { |
5538 | del.br_startoff = start; | 5550 | del.br_startoff = start; |
5539 | del.br_blockcount -= start - got.br_startoff; | 5551 | del.br_blockcount -= start - got.br_startoff; |
@@ -6499,6 +6511,15 @@ xfs_bmap_finish_one( | |||
6499 | xfs_fsblock_t firstfsb; | 6511 | xfs_fsblock_t firstfsb; |
6500 | int error = 0; | 6512 | int error = 0; |
6501 | 6513 | ||
6514 | /* | ||
6515 | * firstfsb is tied to the transaction lifetime and is used to | ||
6516 | * ensure correct AG locking order and schedule work item | ||
6517 | * continuations. XFS_BUI_MAX_FAST_EXTENTS (== 1) restricts us | ||
6518 | * to only making one bmap call per transaction, so it should | ||
6519 | * be safe to have it as a local variable here. | ||
6520 | */ | ||
6521 | firstfsb = NULLFSBLOCK; | ||
6522 | |||
6502 | trace_xfs_bmap_deferred(tp->t_mountp, | 6523 | trace_xfs_bmap_deferred(tp->t_mountp, |
6503 | XFS_FSB_TO_AGNO(tp->t_mountp, startblock), type, | 6524 | XFS_FSB_TO_AGNO(tp->t_mountp, startblock), type, |
6504 | XFS_FSB_TO_AGBNO(tp->t_mountp, startblock), | 6525 | XFS_FSB_TO_AGBNO(tp->t_mountp, startblock), |
diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c index 4da85fff69ad..e0bcc4a59efd 100644 --- a/fs/xfs/libxfs/xfs_btree.c +++ b/fs/xfs/libxfs/xfs_btree.c | |||
@@ -728,7 +728,8 @@ xfs_btree_firstrec( | |||
728 | * Get the block pointer for this level. | 728 | * Get the block pointer for this level. |
729 | */ | 729 | */ |
730 | block = xfs_btree_get_block(cur, level, &bp); | 730 | block = xfs_btree_get_block(cur, level, &bp); |
731 | xfs_btree_check_block(cur, block, level, bp); | 731 | if (xfs_btree_check_block(cur, block, level, bp)) |
732 | return 0; | ||
732 | /* | 733 | /* |
733 | * It's empty, there is no such record. | 734 | * It's empty, there is no such record. |
734 | */ | 735 | */ |
@@ -757,7 +758,8 @@ xfs_btree_lastrec( | |||
757 | * Get the block pointer for this level. | 758 | * Get the block pointer for this level. |
758 | */ | 759 | */ |
759 | block = xfs_btree_get_block(cur, level, &bp); | 760 | block = xfs_btree_get_block(cur, level, &bp); |
760 | xfs_btree_check_block(cur, block, level, bp); | 761 | if (xfs_btree_check_block(cur, block, level, bp)) |
762 | return 0; | ||
761 | /* | 763 | /* |
762 | * It's empty, there is no such record. | 764 | * It's empty, there is no such record. |
763 | */ | 765 | */ |
diff --git a/fs/xfs/libxfs/xfs_dir2_data.c b/fs/xfs/libxfs/xfs_dir2_data.c index d478065b9544..8727a43115ef 100644 --- a/fs/xfs/libxfs/xfs_dir2_data.c +++ b/fs/xfs/libxfs/xfs_dir2_data.c | |||
@@ -136,6 +136,8 @@ __xfs_dir3_data_check( | |||
136 | */ | 136 | */ |
137 | if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { | 137 | if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { |
138 | XFS_WANT_CORRUPTED_RETURN(mp, lastfree == 0); | 138 | XFS_WANT_CORRUPTED_RETURN(mp, lastfree == 0); |
139 | XFS_WANT_CORRUPTED_RETURN(mp, endp >= | ||
140 | p + be16_to_cpu(dup->length)); | ||
139 | XFS_WANT_CORRUPTED_RETURN(mp, | 141 | XFS_WANT_CORRUPTED_RETURN(mp, |
140 | be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) == | 142 | be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) == |
141 | (char *)dup - (char *)hdr); | 143 | (char *)dup - (char *)hdr); |
@@ -164,6 +166,8 @@ __xfs_dir3_data_check( | |||
164 | XFS_WANT_CORRUPTED_RETURN(mp, dep->namelen != 0); | 166 | XFS_WANT_CORRUPTED_RETURN(mp, dep->namelen != 0); |
165 | XFS_WANT_CORRUPTED_RETURN(mp, | 167 | XFS_WANT_CORRUPTED_RETURN(mp, |
166 | !xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber))); | 168 | !xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber))); |
169 | XFS_WANT_CORRUPTED_RETURN(mp, endp >= | ||
170 | p + ops->data_entsize(dep->namelen)); | ||
167 | XFS_WANT_CORRUPTED_RETURN(mp, | 171 | XFS_WANT_CORRUPTED_RETURN(mp, |
168 | be16_to_cpu(*ops->data_entry_tag_p(dep)) == | 172 | be16_to_cpu(*ops->data_entry_tag_p(dep)) == |
169 | (char *)dep - (char *)hdr); | 173 | (char *)dep - (char *)hdr); |
diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c index 900ea231f9a3..45b1c3b4e047 100644 --- a/fs/xfs/libxfs/xfs_refcount.c +++ b/fs/xfs/libxfs/xfs_refcount.c | |||
@@ -1638,6 +1638,10 @@ xfs_refcount_recover_cow_leftovers( | |||
1638 | error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp); | 1638 | error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp); |
1639 | if (error) | 1639 | if (error) |
1640 | goto out_trans; | 1640 | goto out_trans; |
1641 | if (!agbp) { | ||
1642 | error = -ENOMEM; | ||
1643 | goto out_trans; | ||
1644 | } | ||
1641 | cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL); | 1645 | cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL); |
1642 | 1646 | ||
1643 | /* Find all the leftover CoW staging extents. */ | 1647 | /* Find all the leftover CoW staging extents. */ |
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index 6ce948c436d5..15751dc2a27d 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c | |||
@@ -111,6 +111,9 @@ restart: | |||
111 | skipped = 0; | 111 | skipped = 0; |
112 | break; | 112 | break; |
113 | } | 113 | } |
114 | /* we're done if id overflows back to zero */ | ||
115 | if (!next_index) | ||
116 | break; | ||
114 | } | 117 | } |
115 | 118 | ||
116 | if (skipped) { | 119 | if (skipped) { |
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index ab2270a87196..f45fbf0db9bb 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c | |||
@@ -170,6 +170,8 @@ xfs_reflink_find_shared( | |||
170 | error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp); | 170 | error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp); |
171 | if (error) | 171 | if (error) |
172 | return error; | 172 | return error; |
173 | if (!agbp) | ||
174 | return -ENOMEM; | ||
173 | 175 | ||
174 | cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL); | 176 | cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL); |
175 | 177 | ||
@@ -329,7 +331,7 @@ xfs_reflink_convert_cow_extent( | |||
329 | xfs_filblks_t count_fsb, | 331 | xfs_filblks_t count_fsb, |
330 | struct xfs_defer_ops *dfops) | 332 | struct xfs_defer_ops *dfops) |
331 | { | 333 | { |
332 | xfs_fsblock_t first_block; | 334 | xfs_fsblock_t first_block = NULLFSBLOCK; |
333 | int nimaps = 1; | 335 | int nimaps = 1; |
334 | 336 | ||
335 | if (imap->br_state == XFS_EXT_NORM) | 337 | if (imap->br_state == XFS_EXT_NORM) |