Skip to content

Commit 19993e7

Browse files
committed
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
2 parents 8155469 + 5b094d6 commit 19993e7

File tree

6 files changed

+39
-3
lines changed

6 files changed

+39
-3
lines changed

fs/xfs/libxfs/xfs_bmap.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5435,6 +5435,7 @@ __xfs_bunmapi(
54355435
xfs_fsblock_t sum;
54365436
xfs_filblks_t len = *rlen; /* length to unmap in file */
54375437
xfs_fileoff_t max_len;
5438+
xfs_agnumber_t prev_agno = NULLAGNUMBER, agno;
54385439

54395440
trace_xfs_bunmap(ip, bno, len, flags, _RET_IP_);
54405441

@@ -5534,6 +5535,17 @@ __xfs_bunmapi(
55345535
*/
55355536
del = got;
55365537
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+
}
55375549
if (got.br_startoff < start) {
55385550
del.br_startoff = start;
55395551
del.br_blockcount -= start - got.br_startoff;
@@ -6499,6 +6511,15 @@ xfs_bmap_finish_one(
64996511
xfs_fsblock_t firstfsb;
65006512
int error = 0;
65016513

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+
65026523
trace_xfs_bmap_deferred(tp->t_mountp,
65036524
XFS_FSB_TO_AGNO(tp->t_mountp, startblock), type,
65046525
XFS_FSB_TO_AGBNO(tp->t_mountp, startblock),

fs/xfs/libxfs/xfs_btree.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,8 @@ xfs_btree_firstrec(
728728
* Get the block pointer for this level.
729729
*/
730730
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;
732733
/*
733734
* It's empty, there is no such record.
734735
*/
@@ -757,7 +758,8 @@ xfs_btree_lastrec(
757758
* Get the block pointer for this level.
758759
*/
759760
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;
761763
/*
762764
* It's empty, there is no such record.
763765
*/

fs/xfs/libxfs/xfs_dir2_data.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ __xfs_dir3_data_check(
136136
*/
137137
if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
138138
XFS_WANT_CORRUPTED_RETURN(mp, lastfree == 0);
139+
XFS_WANT_CORRUPTED_RETURN(mp, endp >=
140+
p + be16_to_cpu(dup->length));
139141
XFS_WANT_CORRUPTED_RETURN(mp,
140142
be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) ==
141143
(char *)dup - (char *)hdr);
@@ -164,6 +166,8 @@ __xfs_dir3_data_check(
164166
XFS_WANT_CORRUPTED_RETURN(mp, dep->namelen != 0);
165167
XFS_WANT_CORRUPTED_RETURN(mp,
166168
!xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber)));
169+
XFS_WANT_CORRUPTED_RETURN(mp, endp >=
170+
p + ops->data_entsize(dep->namelen));
167171
XFS_WANT_CORRUPTED_RETURN(mp,
168172
be16_to_cpu(*ops->data_entry_tag_p(dep)) ==
169173
(char *)dep - (char *)hdr);

fs/xfs/libxfs/xfs_refcount.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1638,6 +1638,10 @@ xfs_refcount_recover_cow_leftovers(
16381638
error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
16391639
if (error)
16401640
goto out_trans;
1641+
if (!agbp) {
1642+
error = -ENOMEM;
1643+
goto out_trans;
1644+
}
16411645
cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
16421646

16431647
/* Find all the leftover CoW staging extents. */

fs/xfs/xfs_qm.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ xfs_qm_dquot_walk(
111111
skipped = 0;
112112
break;
113113
}
114+
/* we're done if id overflows back to zero */
115+
if (!next_index)
116+
break;
114117
}
115118

116119
if (skipped) {

fs/xfs/xfs_reflink.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ xfs_reflink_find_shared(
170170
error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
171171
if (error)
172172
return error;
173+
if (!agbp)
174+
return -ENOMEM;
173175

174176
cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
175177

@@ -329,7 +331,7 @@ xfs_reflink_convert_cow_extent(
329331
xfs_filblks_t count_fsb,
330332
struct xfs_defer_ops *dfops)
331333
{
332-
xfs_fsblock_t first_block;
334+
xfs_fsblock_t first_block = NULLFSBLOCK;
333335
int nimaps = 1;
334336

335337
if (imap->br_state == XFS_EXT_NORM)

0 commit comments

Comments
 (0)