Skip to content

Commit b8f1fa2

Browse files
committed
Merge tag 'xfs-6.7-fixes-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
Pull xfs fixes from Chandan Babu: - Fix deadlock arising due to intent items in AIL not being cleared when log recovery fails - Fix stale data exposure bug when remapping COW fork extents to data fork - Fix deadlock when data device flush fails - Fix AGFL minimum size calculation - Select DEBUG_FS instead of XFS_DEBUG when XFS_ONLINE_SCRUB_STATS is selected - Fix corruption of log inode's extent count field when NREXT64 feature is enabled * tag 'xfs-6.7-fixes-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: xfs: recovery should not clear di_flushiter unconditionally xfs: inode recovery does not validate the recovered inode xfs: fix again select in kconfig XFS_ONLINE_SCRUB_STATS xfs: fix internal error from AGFL exhaustion xfs: up(ic_sema) if flushing data device fails xfs: only remap the written blocks in xfs_reflink_end_cow_extent XFS: Update MAINTAINERS to catch all XFS documentation xfs: abort intent items when recovery intents fail xfs: factor out xfs_defer_pending_abort
2 parents bb28378 + 7930d9e commit b8f1fa2

File tree

10 files changed

+92
-45
lines changed

10 files changed

+92
-45
lines changed

MAINTAINERS

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23882,8 +23882,7 @@ T: git git://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git
2388223882
P: Documentation/filesystems/xfs-maintainer-entry-profile.rst
2388323883
F: Documentation/ABI/testing/sysfs-fs-xfs
2388423884
F: Documentation/admin-guide/xfs.rst
23885-
F: Documentation/filesystems/xfs-delayed-logging-design.rst
23886-
F: Documentation/filesystems/xfs-self-describing-metadata.rst
23885+
F: Documentation/filesystems/xfs-*
2388723886
F: fs/xfs/
2388823887
F: include/uapi/linux/dqblk_xfs.h
2388923888
F: include/uapi/linux/fsmap.h

fs/xfs/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ config XFS_ONLINE_SCRUB_STATS
147147
bool "XFS online metadata check usage data collection"
148148
default y
149149
depends on XFS_ONLINE_SCRUB
150-
select XFS_DEBUG
150+
select DEBUG_FS
151151
help
152152
If you say Y here, the kernel will gather usage data about
153153
the online metadata check subsystem. This includes the number

fs/xfs/libxfs/xfs_alloc.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2275,16 +2275,37 @@ xfs_alloc_min_freelist(
22752275

22762276
ASSERT(mp->m_alloc_maxlevels > 0);
22772277

2278+
/*
2279+
* For a btree shorter than the maximum height, the worst case is that
2280+
* every level gets split and a new level is added, then while inserting
2281+
* another entry to refill the AGFL, every level under the old root gets
2282+
* split again. This is:
2283+
*
2284+
* (full height split reservation) + (AGFL refill split height)
2285+
* = (current height + 1) + (current height - 1)
2286+
* = (new height) + (new height - 2)
2287+
* = 2 * new height - 2
2288+
*
2289+
* For a btree of maximum height, the worst case is that every level
2290+
* under the root gets split, then while inserting another entry to
2291+
* refill the AGFL, every level under the root gets split again. This is
2292+
* also:
2293+
*
2294+
* 2 * (current height - 1)
2295+
* = 2 * (new height - 1)
2296+
* = 2 * new height - 2
2297+
*/
2298+
22782299
/* space needed by-bno freespace btree */
22792300
min_free = min_t(unsigned int, levels[XFS_BTNUM_BNOi] + 1,
2280-
mp->m_alloc_maxlevels);
2301+
mp->m_alloc_maxlevels) * 2 - 2;
22812302
/* space needed by-size freespace btree */
22822303
min_free += min_t(unsigned int, levels[XFS_BTNUM_CNTi] + 1,
2283-
mp->m_alloc_maxlevels);
2304+
mp->m_alloc_maxlevels) * 2 - 2;
22842305
/* space needed reverse mapping used space btree */
22852306
if (xfs_has_rmapbt(mp))
22862307
min_free += min_t(unsigned int, levels[XFS_BTNUM_RMAPi] + 1,
2287-
mp->m_rmap_maxlevels);
2308+
mp->m_rmap_maxlevels) * 2 - 2;
22882309

22892310
return min_free;
22902311
}

fs/xfs/libxfs/xfs_defer.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -245,28 +245,35 @@ xfs_defer_create_intents(
245245
return ret;
246246
}
247247

248-
/* Abort all the intents that were committed. */
249248
STATIC void
250-
xfs_defer_trans_abort(
251-
struct xfs_trans *tp,
252-
struct list_head *dop_pending)
249+
xfs_defer_pending_abort(
250+
struct xfs_mount *mp,
251+
struct list_head *dop_list)
253252
{
254253
struct xfs_defer_pending *dfp;
255254
const struct xfs_defer_op_type *ops;
256255

257-
trace_xfs_defer_trans_abort(tp, _RET_IP_);
258-
259256
/* Abort intent items that don't have a done item. */
260-
list_for_each_entry(dfp, dop_pending, dfp_list) {
257+
list_for_each_entry(dfp, dop_list, dfp_list) {
261258
ops = defer_op_types[dfp->dfp_type];
262-
trace_xfs_defer_pending_abort(tp->t_mountp, dfp);
259+
trace_xfs_defer_pending_abort(mp, dfp);
263260
if (dfp->dfp_intent && !dfp->dfp_done) {
264261
ops->abort_intent(dfp->dfp_intent);
265262
dfp->dfp_intent = NULL;
266263
}
267264
}
268265
}
269266

267+
/* Abort all the intents that were committed. */
268+
STATIC void
269+
xfs_defer_trans_abort(
270+
struct xfs_trans *tp,
271+
struct list_head *dop_pending)
272+
{
273+
trace_xfs_defer_trans_abort(tp, _RET_IP_);
274+
xfs_defer_pending_abort(tp->t_mountp, dop_pending);
275+
}
276+
270277
/*
271278
* Capture resources that the caller said not to release ("held") when the
272279
* transaction commits. Caller is responsible for zero-initializing @dres.
@@ -756,12 +763,13 @@ xfs_defer_ops_capture(
756763

757764
/* Release all resources that we used to capture deferred ops. */
758765
void
759-
xfs_defer_ops_capture_free(
766+
xfs_defer_ops_capture_abort(
760767
struct xfs_mount *mp,
761768
struct xfs_defer_capture *dfc)
762769
{
763770
unsigned short i;
764771

772+
xfs_defer_pending_abort(mp, &dfc->dfc_dfops);
765773
xfs_defer_cancel_list(mp, &dfc->dfc_dfops);
766774

767775
for (i = 0; i < dfc->dfc_held.dr_bufs; i++)
@@ -802,7 +810,7 @@ xfs_defer_ops_capture_and_commit(
802810
/* Commit the transaction and add the capture structure to the list. */
803811
error = xfs_trans_commit(tp);
804812
if (error) {
805-
xfs_defer_ops_capture_free(mp, dfc);
813+
xfs_defer_ops_capture_abort(mp, dfc);
806814
return error;
807815
}
808816

fs/xfs/libxfs/xfs_defer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ int xfs_defer_ops_capture_and_commit(struct xfs_trans *tp,
121121
struct list_head *capture_list);
122122
void xfs_defer_ops_continue(struct xfs_defer_capture *d, struct xfs_trans *tp,
123123
struct xfs_defer_resources *dres);
124-
void xfs_defer_ops_capture_free(struct xfs_mount *mp,
124+
void xfs_defer_ops_capture_abort(struct xfs_mount *mp,
125125
struct xfs_defer_capture *d);
126126
void xfs_defer_resources_rele(struct xfs_defer_resources *dres);
127127

fs/xfs/libxfs/xfs_inode_buf.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,9 @@ xfs_dinode_verify(
510510
if (mode && nextents + naextents > nblocks)
511511
return __this_address;
512512

513+
if (nextents + naextents == 0 && nblocks != 0)
514+
return __this_address;
515+
513516
if (S_ISDIR(mode) && nextents > mp->m_dir_geo->max_extents)
514517
return __this_address;
515518

fs/xfs/xfs_inode_item_recover.c

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ xlog_recover_inode_commit_pass2(
286286
struct xfs_log_dinode *ldip;
287287
uint isize;
288288
int need_free = 0;
289+
xfs_failaddr_t fa;
289290

290291
if (item->ri_buf[0].i_len == sizeof(struct xfs_inode_log_format)) {
291292
in_f = item->ri_buf[0].i_addr;
@@ -369,24 +370,26 @@ xlog_recover_inode_commit_pass2(
369370
* superblock flag to determine whether we need to look at di_flushiter
370371
* to skip replay when the on disk inode is newer than the log one
371372
*/
372-
if (!xfs_has_v3inodes(mp) &&
373-
ldip->di_flushiter < be16_to_cpu(dip->di_flushiter)) {
374-
/*
375-
* Deal with the wrap case, DI_MAX_FLUSH is less
376-
* than smaller numbers
377-
*/
378-
if (be16_to_cpu(dip->di_flushiter) == DI_MAX_FLUSH &&
379-
ldip->di_flushiter < (DI_MAX_FLUSH >> 1)) {
380-
/* do nothing */
381-
} else {
382-
trace_xfs_log_recover_inode_skip(log, in_f);
383-
error = 0;
384-
goto out_release;
373+
if (!xfs_has_v3inodes(mp)) {
374+
if (ldip->di_flushiter < be16_to_cpu(dip->di_flushiter)) {
375+
/*
376+
* Deal with the wrap case, DI_MAX_FLUSH is less
377+
* than smaller numbers
378+
*/
379+
if (be16_to_cpu(dip->di_flushiter) == DI_MAX_FLUSH &&
380+
ldip->di_flushiter < (DI_MAX_FLUSH >> 1)) {
381+
/* do nothing */
382+
} else {
383+
trace_xfs_log_recover_inode_skip(log, in_f);
384+
error = 0;
385+
goto out_release;
386+
}
385387
}
388+
389+
/* Take the opportunity to reset the flush iteration count */
390+
ldip->di_flushiter = 0;
386391
}
387392

388-
/* Take the opportunity to reset the flush iteration count */
389-
ldip->di_flushiter = 0;
390393

391394
if (unlikely(S_ISREG(ldip->di_mode))) {
392395
if ((ldip->di_format != XFS_DINODE_FMT_EXTENTS) &&
@@ -528,8 +531,19 @@ xlog_recover_inode_commit_pass2(
528531
(dip->di_mode != 0))
529532
error = xfs_recover_inode_owner_change(mp, dip, in_f,
530533
buffer_list);
531-
/* re-generate the checksum. */
534+
/* re-generate the checksum and validate the recovered inode. */
532535
xfs_dinode_calc_crc(log->l_mp, dip);
536+
fa = xfs_dinode_verify(log->l_mp, in_f->ilf_ino, dip);
537+
if (fa) {
538+
XFS_CORRUPTION_ERROR(
539+
"Bad dinode after recovery",
540+
XFS_ERRLEVEL_LOW, mp, dip, sizeof(*dip));
541+
xfs_alert(mp,
542+
"Metadata corruption detected at %pS, inode 0x%llx",
543+
fa, in_f->ilf_ino);
544+
error = -EFSCORRUPTED;
545+
goto out_release;
546+
}
533547

534548
ASSERT(bp->b_mount == mp);
535549
bp->b_flags |= _XBF_LOGRECOVERY;

fs/xfs/xfs_log.c

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1893,9 +1893,7 @@ xlog_write_iclog(
18931893
* the buffer manually, the code needs to be kept in sync
18941894
* with the I/O completion path.
18951895
*/
1896-
xlog_state_done_syncing(iclog);
1897-
up(&iclog->ic_sema);
1898-
return;
1896+
goto sync;
18991897
}
19001898

19011899
/*
@@ -1925,20 +1923,17 @@ xlog_write_iclog(
19251923
* avoid shutdown re-entering this path and erroring out again.
19261924
*/
19271925
if (log->l_targ != log->l_mp->m_ddev_targp &&
1928-
blkdev_issue_flush(log->l_mp->m_ddev_targp->bt_bdev)) {
1929-
xlog_force_shutdown(log, SHUTDOWN_LOG_IO_ERROR);
1930-
return;
1931-
}
1926+
blkdev_issue_flush(log->l_mp->m_ddev_targp->bt_bdev))
1927+
goto shutdown;
19321928
}
19331929
if (iclog->ic_flags & XLOG_ICL_NEED_FUA)
19341930
iclog->ic_bio.bi_opf |= REQ_FUA;
19351931

19361932
iclog->ic_flags &= ~(XLOG_ICL_NEED_FLUSH | XLOG_ICL_NEED_FUA);
19371933

1938-
if (xlog_map_iclog_data(&iclog->ic_bio, iclog->ic_data, count)) {
1939-
xlog_force_shutdown(log, SHUTDOWN_LOG_IO_ERROR);
1940-
return;
1941-
}
1934+
if (xlog_map_iclog_data(&iclog->ic_bio, iclog->ic_data, count))
1935+
goto shutdown;
1936+
19421937
if (is_vmalloc_addr(iclog->ic_data))
19431938
flush_kernel_vmap_range(iclog->ic_data, count);
19441939

@@ -1959,6 +1954,12 @@ xlog_write_iclog(
19591954
}
19601955

19611956
submit_bio(&iclog->ic_bio);
1957+
return;
1958+
shutdown:
1959+
xlog_force_shutdown(log, SHUTDOWN_LOG_IO_ERROR);
1960+
sync:
1961+
xlog_state_done_syncing(iclog);
1962+
up(&iclog->ic_sema);
19621963
}
19631964

19641965
/*

fs/xfs/xfs_log_recover.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2511,7 +2511,7 @@ xlog_abort_defer_ops(
25112511

25122512
list_for_each_entry_safe(dfc, next, capture_list, dfc_list) {
25132513
list_del_init(&dfc->dfc_list);
2514-
xfs_defer_ops_capture_free(mp, dfc);
2514+
xfs_defer_ops_capture_abort(mp, dfc);
25152515
}
25162516
}
25172517

fs/xfs/xfs_reflink.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,7 @@ xfs_reflink_end_cow_extent(
784784
}
785785
}
786786
del = got;
787+
xfs_trim_extent(&del, *offset_fsb, end_fsb - *offset_fsb);
787788

788789
/* Grab the corresponding mapping in the data fork. */
789790
nmaps = 1;

0 commit comments

Comments
 (0)