Skip to content

Commit fca0e39

Browse files
committed
Merge tag 'xfs-4.15-fixes-8' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
Pull xfs fixes from Darrick Wong: "Here are some XFS fixes for 4.15-rc5. Apologies for the unusually large number of patches this late, but I wanted to make sure the corruption fixes were really ready to go. Changes since last update: - Fix a locking problem during xattr block conversion that could lead to the log checkpointing thread to try to write an incomplete buffer to disk, which leads to a corruption shutdown - Fix a null pointer dereference when removing delayed allocation extents - Remove post-eof speculative allocations when reflinking a block past current inode size so that we don't just leave them there and assert on inode reclaim - Relax an assert which didn't accurately reflect the way locking works and would trigger under heavy io load - Avoid infinite loop when cancelling copy on write extents after a writeback failure - Try to avoid copy on write transaction reservation overflows when remapping after a successful write - Fix various problems with the copy-on-write reservation automatic garbage collection not being cleaned up properly during a ro remount - Fix problems with rmap log items being processed in the wrong order, leading to corruption shutdowns - Fix problems with EFI recovery wherein the "remove any rmapping if present" mechanism wasn't actually doing anything, which would lead to corruption problems later when the extent is reallocated, leading to multiple rmaps for the same extent" * tag 'xfs-4.15-fixes-8' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: xfs: only skip rmap owner checks for unknown-owner rmap removal xfs: always honor OWN_UNKNOWN rmap removal requests xfs: queue deferred rmap ops for cow staging extent alloc/free in the right order xfs: set cowblocks tag for direct cow writes too xfs: remove leftover CoW reservations when remounting ro xfs: don't be so eager to clear the cowblocks tag on truncate xfs: track cowblocks separately in i_flags xfs: allow CoW remap transactions to use reserve blocks xfs: avoid infinite loop when cancelling CoW blocks after writeback failure xfs: relax is_reflink_inode assert in xfs_reflink_find_cow_mapping xfs: remove dest file's post-eof preallocations before reflinking xfs: move xfs_iext_insert tracepoint to report useful information xfs: account for null transactions in bunmapi xfs: hold xfs_buf locked between shortform->leaf conversion and the addition of an attribute xfs: add the ability to join a held buffer to a defer_ops
2 parents 0fc0f18 + 68c58e9 commit fca0e39

19 files changed

+258
-97
lines changed

fs/xfs/libxfs/xfs_alloc.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,7 @@ xfs_alloc_ag_vextent(
702702
ASSERT(args->agbno % args->alignment == 0);
703703

704704
/* if not file data, insert new block into the reverse map btree */
705-
if (args->oinfo.oi_owner != XFS_RMAP_OWN_UNKNOWN) {
705+
if (!xfs_rmap_should_skip_owner_update(&args->oinfo)) {
706706
error = xfs_rmap_alloc(args->tp, args->agbp, args->agno,
707707
args->agbno, args->len, &args->oinfo);
708708
if (error)
@@ -1682,7 +1682,7 @@ xfs_free_ag_extent(
16821682
bno_cur = cnt_cur = NULL;
16831683
mp = tp->t_mountp;
16841684

1685-
if (oinfo->oi_owner != XFS_RMAP_OWN_UNKNOWN) {
1685+
if (!xfs_rmap_should_skip_owner_update(oinfo)) {
16861686
error = xfs_rmap_free(tp, agbp, agno, bno, len, oinfo);
16871687
if (error)
16881688
goto error0;

fs/xfs/libxfs/xfs_attr.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ xfs_attr_set(
212212
int flags)
213213
{
214214
struct xfs_mount *mp = dp->i_mount;
215+
struct xfs_buf *leaf_bp = NULL;
215216
struct xfs_da_args args;
216217
struct xfs_defer_ops dfops;
217218
struct xfs_trans_res tres;
@@ -327,23 +328,31 @@ xfs_attr_set(
327328
* GROT: another possible req'mt for a double-split btree op.
328329
*/
329330
xfs_defer_init(args.dfops, args.firstblock);
330-
error = xfs_attr_shortform_to_leaf(&args);
331+
error = xfs_attr_shortform_to_leaf(&args, &leaf_bp);
331332
if (error)
332333
goto out_defer_cancel;
334+
/*
335+
* Prevent the leaf buffer from being unlocked so that a
336+
* concurrent AIL push cannot grab the half-baked leaf
337+
* buffer and run into problems with the write verifier.
338+
*/
339+
xfs_trans_bhold(args.trans, leaf_bp);
340+
xfs_defer_bjoin(args.dfops, leaf_bp);
333341
xfs_defer_ijoin(args.dfops, dp);
334342
error = xfs_defer_finish(&args.trans, args.dfops);
335343
if (error)
336344
goto out_defer_cancel;
337345

338346
/*
339347
* Commit the leaf transformation. We'll need another (linked)
340-
* transaction to add the new attribute to the leaf.
348+
* transaction to add the new attribute to the leaf, which
349+
* means that we have to hold & join the leaf buffer here too.
341350
*/
342-
343351
error = xfs_trans_roll_inode(&args.trans, dp);
344352
if (error)
345353
goto out;
346-
354+
xfs_trans_bjoin(args.trans, leaf_bp);
355+
leaf_bp = NULL;
347356
}
348357

349358
if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
@@ -374,8 +383,9 @@ xfs_attr_set(
374383

375384
out_defer_cancel:
376385
xfs_defer_cancel(&dfops);
377-
args.trans = NULL;
378386
out:
387+
if (leaf_bp)
388+
xfs_trans_brelse(args.trans, leaf_bp);
379389
if (args.trans)
380390
xfs_trans_cancel(args.trans);
381391
xfs_iunlock(dp, XFS_ILOCK_EXCL);

fs/xfs/libxfs/xfs_attr_leaf.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -735,10 +735,13 @@ xfs_attr_shortform_getvalue(xfs_da_args_t *args)
735735
}
736736

737737
/*
738-
* Convert from using the shortform to the leaf.
738+
* Convert from using the shortform to the leaf. On success, return the
739+
* buffer so that we can keep it locked until we're totally done with it.
739740
*/
740741
int
741-
xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
742+
xfs_attr_shortform_to_leaf(
743+
struct xfs_da_args *args,
744+
struct xfs_buf **leaf_bp)
742745
{
743746
xfs_inode_t *dp;
744747
xfs_attr_shortform_t *sf;
@@ -818,7 +821,7 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
818821
sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
819822
}
820823
error = 0;
821-
824+
*leaf_bp = bp;
822825
out:
823826
kmem_free(tmpbuffer);
824827
return error;

fs/xfs/libxfs/xfs_attr_leaf.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ void xfs_attr_shortform_create(struct xfs_da_args *args);
4848
void xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff);
4949
int xfs_attr_shortform_lookup(struct xfs_da_args *args);
5050
int xfs_attr_shortform_getvalue(struct xfs_da_args *args);
51-
int xfs_attr_shortform_to_leaf(struct xfs_da_args *args);
51+
int xfs_attr_shortform_to_leaf(struct xfs_da_args *args,
52+
struct xfs_buf **leaf_bp);
5253
int xfs_attr_shortform_remove(struct xfs_da_args *args);
5354
int xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp);
5455
int xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes);

fs/xfs/libxfs/xfs_bmap.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5136,7 +5136,7 @@ __xfs_bunmapi(
51365136
* blowing out the transaction with a mix of EFIs and reflink
51375137
* adjustments.
51385138
*/
5139-
if (xfs_is_reflink_inode(ip) && whichfork == XFS_DATA_FORK)
5139+
if (tp && xfs_is_reflink_inode(ip) && whichfork == XFS_DATA_FORK)
51405140
max_len = min(len, xfs_refcount_max_unmap(tp->t_log_res));
51415141
else
51425142
max_len = len;

fs/xfs/libxfs/xfs_defer.c

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,10 @@ xfs_defer_trans_roll(
249249
for (i = 0; i < XFS_DEFER_OPS_NR_INODES && dop->dop_inodes[i]; i++)
250250
xfs_trans_log_inode(*tp, dop->dop_inodes[i], XFS_ILOG_CORE);
251251

252+
/* Hold the (previously bjoin'd) buffer locked across the roll. */
253+
for (i = 0; i < XFS_DEFER_OPS_NR_BUFS && dop->dop_bufs[i]; i++)
254+
xfs_trans_dirty_buf(*tp, dop->dop_bufs[i]);
255+
252256
trace_xfs_defer_trans_roll((*tp)->t_mountp, dop);
253257

254258
/* Roll the transaction. */
@@ -264,6 +268,12 @@ xfs_defer_trans_roll(
264268
for (i = 0; i < XFS_DEFER_OPS_NR_INODES && dop->dop_inodes[i]; i++)
265269
xfs_trans_ijoin(*tp, dop->dop_inodes[i], 0);
266270

271+
/* Rejoin the buffers and dirty them so the log moves forward. */
272+
for (i = 0; i < XFS_DEFER_OPS_NR_BUFS && dop->dop_bufs[i]; i++) {
273+
xfs_trans_bjoin(*tp, dop->dop_bufs[i]);
274+
xfs_trans_bhold(*tp, dop->dop_bufs[i]);
275+
}
276+
267277
return error;
268278
}
269279

@@ -295,6 +305,31 @@ xfs_defer_ijoin(
295305
}
296306
}
297307

308+
ASSERT(0);
309+
return -EFSCORRUPTED;
310+
}
311+
312+
/*
313+
* Add this buffer to the deferred op. Each joined buffer is relogged
314+
* each time we roll the transaction.
315+
*/
316+
int
317+
xfs_defer_bjoin(
318+
struct xfs_defer_ops *dop,
319+
struct xfs_buf *bp)
320+
{
321+
int i;
322+
323+
for (i = 0; i < XFS_DEFER_OPS_NR_BUFS; i++) {
324+
if (dop->dop_bufs[i] == bp)
325+
return 0;
326+
else if (dop->dop_bufs[i] == NULL) {
327+
dop->dop_bufs[i] = bp;
328+
return 0;
329+
}
330+
}
331+
332+
ASSERT(0);
298333
return -EFSCORRUPTED;
299334
}
300335

@@ -493,9 +528,7 @@ xfs_defer_init(
493528
struct xfs_defer_ops *dop,
494529
xfs_fsblock_t *fbp)
495530
{
496-
dop->dop_committed = false;
497-
dop->dop_low = false;
498-
memset(&dop->dop_inodes, 0, sizeof(dop->dop_inodes));
531+
memset(dop, 0, sizeof(struct xfs_defer_ops));
499532
*fbp = NULLFSBLOCK;
500533
INIT_LIST_HEAD(&dop->dop_intake);
501534
INIT_LIST_HEAD(&dop->dop_pending);

fs/xfs/libxfs/xfs_defer.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,17 @@ enum xfs_defer_ops_type {
5959
};
6060

6161
#define XFS_DEFER_OPS_NR_INODES 2 /* join up to two inodes */
62+
#define XFS_DEFER_OPS_NR_BUFS 2 /* join up to two buffers */
6263

6364
struct xfs_defer_ops {
6465
bool dop_committed; /* did any trans commit? */
6566
bool dop_low; /* alloc in low mode */
6667
struct list_head dop_intake; /* unlogged pending work */
6768
struct list_head dop_pending; /* logged pending work */
6869

69-
/* relog these inodes with each roll */
70+
/* relog these with each roll */
7071
struct xfs_inode *dop_inodes[XFS_DEFER_OPS_NR_INODES];
72+
struct xfs_buf *dop_bufs[XFS_DEFER_OPS_NR_BUFS];
7173
};
7274

7375
void xfs_defer_add(struct xfs_defer_ops *dop, enum xfs_defer_ops_type type,
@@ -77,6 +79,7 @@ void xfs_defer_cancel(struct xfs_defer_ops *dop);
7779
void xfs_defer_init(struct xfs_defer_ops *dop, xfs_fsblock_t *fbp);
7880
bool xfs_defer_has_unfinished_work(struct xfs_defer_ops *dop);
7981
int xfs_defer_ijoin(struct xfs_defer_ops *dop, struct xfs_inode *ip);
82+
int xfs_defer_bjoin(struct xfs_defer_ops *dop, struct xfs_buf *bp);
8083

8184
/* Description of a deferred type. */
8285
struct xfs_defer_op_type {

fs/xfs/libxfs/xfs_iext_tree.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -632,8 +632,6 @@ xfs_iext_insert(
632632
struct xfs_iext_leaf *new = NULL;
633633
int nr_entries, i;
634634

635-
trace_xfs_iext_insert(ip, cur, state, _RET_IP_);
636-
637635
if (ifp->if_height == 0)
638636
xfs_iext_alloc_root(ifp, cur);
639637
else if (ifp->if_height == 1)
@@ -661,6 +659,8 @@ xfs_iext_insert(
661659
xfs_iext_set(cur_rec(cur), irec);
662660
ifp->if_bytes += sizeof(struct xfs_iext_rec);
663661

662+
trace_xfs_iext_insert(ip, cur, state, _RET_IP_);
663+
664664
if (new)
665665
xfs_iext_insert_node(ifp, xfs_iext_leaf_key(new, 0), new, 2);
666666
}

fs/xfs/libxfs/xfs_refcount.c

Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1488,27 +1488,12 @@ __xfs_refcount_cow_alloc(
14881488
xfs_extlen_t aglen,
14891489
struct xfs_defer_ops *dfops)
14901490
{
1491-
int error;
1492-
14931491
trace_xfs_refcount_cow_increase(rcur->bc_mp, rcur->bc_private.a.agno,
14941492
agbno, aglen);
14951493

14961494
/* Add refcount btree reservation */
1497-
error = xfs_refcount_adjust_cow(rcur, agbno, aglen,
1495+
return xfs_refcount_adjust_cow(rcur, agbno, aglen,
14981496
XFS_REFCOUNT_ADJUST_COW_ALLOC, dfops);
1499-
if (error)
1500-
return error;
1501-
1502-
/* Add rmap entry */
1503-
if (xfs_sb_version_hasrmapbt(&rcur->bc_mp->m_sb)) {
1504-
error = xfs_rmap_alloc_extent(rcur->bc_mp, dfops,
1505-
rcur->bc_private.a.agno,
1506-
agbno, aglen, XFS_RMAP_OWN_COW);
1507-
if (error)
1508-
return error;
1509-
}
1510-
1511-
return error;
15121497
}
15131498

15141499
/*
@@ -1521,27 +1506,12 @@ __xfs_refcount_cow_free(
15211506
xfs_extlen_t aglen,
15221507
struct xfs_defer_ops *dfops)
15231508
{
1524-
int error;
1525-
15261509
trace_xfs_refcount_cow_decrease(rcur->bc_mp, rcur->bc_private.a.agno,
15271510
agbno, aglen);
15281511

15291512
/* Remove refcount btree reservation */
1530-
error = xfs_refcount_adjust_cow(rcur, agbno, aglen,
1513+
return xfs_refcount_adjust_cow(rcur, agbno, aglen,
15311514
XFS_REFCOUNT_ADJUST_COW_FREE, dfops);
1532-
if (error)
1533-
return error;
1534-
1535-
/* Remove rmap entry */
1536-
if (xfs_sb_version_hasrmapbt(&rcur->bc_mp->m_sb)) {
1537-
error = xfs_rmap_free_extent(rcur->bc_mp, dfops,
1538-
rcur->bc_private.a.agno,
1539-
agbno, aglen, XFS_RMAP_OWN_COW);
1540-
if (error)
1541-
return error;
1542-
}
1543-
1544-
return error;
15451515
}
15461516

15471517
/* Record a CoW staging extent in the refcount btree. */
@@ -1552,11 +1522,19 @@ xfs_refcount_alloc_cow_extent(
15521522
xfs_fsblock_t fsb,
15531523
xfs_extlen_t len)
15541524
{
1525+
int error;
1526+
15551527
if (!xfs_sb_version_hasreflink(&mp->m_sb))
15561528
return 0;
15571529

1558-
return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_ALLOC_COW,
1530+
error = __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_ALLOC_COW,
15591531
fsb, len);
1532+
if (error)
1533+
return error;
1534+
1535+
/* Add rmap entry */
1536+
return xfs_rmap_alloc_extent(mp, dfops, XFS_FSB_TO_AGNO(mp, fsb),
1537+
XFS_FSB_TO_AGBNO(mp, fsb), len, XFS_RMAP_OWN_COW);
15601538
}
15611539

15621540
/* Forget a CoW staging event in the refcount btree. */
@@ -1567,9 +1545,17 @@ xfs_refcount_free_cow_extent(
15671545
xfs_fsblock_t fsb,
15681546
xfs_extlen_t len)
15691547
{
1548+
int error;
1549+
15701550
if (!xfs_sb_version_hasreflink(&mp->m_sb))
15711551
return 0;
15721552

1553+
/* Remove rmap entry */
1554+
error = xfs_rmap_free_extent(mp, dfops, XFS_FSB_TO_AGNO(mp, fsb),
1555+
XFS_FSB_TO_AGBNO(mp, fsb), len, XFS_RMAP_OWN_COW);
1556+
if (error)
1557+
return error;
1558+
15731559
return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_FREE_COW,
15741560
fsb, len);
15751561
}

0 commit comments

Comments
 (0)