aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-07-28 17:29:48 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-28 17:29:48 -0400
commit19993e7378533d8d802d707be271074f2eb8e4fd (patch)
tree566d8b6b0c28f0f3315d6dfd22c5b3708faec5b7
parent8155469341a60ba7064d64b62bb32af5a901ccaf (diff)
parent5b094d6dac0451ad89b1dc088395c7b399b7e9e8 (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.c21
-rw-r--r--fs/xfs/libxfs/xfs_btree.c6
-rw-r--r--fs/xfs/libxfs/xfs_dir2_data.c4
-rw-r--r--fs/xfs/libxfs/xfs_refcount.c4
-rw-r--r--fs/xfs/xfs_qm.c3
-rw-r--r--fs/xfs/xfs_reflink.c4
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)