Skip to content

Commit cd14f15

Browse files
author
Darrick J. Wong
committed
Merge tag 'iomap-write-race-testing-6.2_2022-11-30' of git://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux into xfs-6.2-mergeC
xfs: add knobs for testing iomap write race fixes This series is a followup to Dave Chinner's series entitled "xfs, iomap: fix data corruption due to stale cached iomaps". The two patches here add debugging knobs to introduce artificial delays into the pagecache write and writeback code to facilitate testing of the iomap invalidation code. New tracepoints are also introduced so that fstests can look for the invalidations. Signed-off-by: Darrick J. Wong <[email protected]> * tag 'iomap-write-race-testing-6.2_2022-11-30' of git://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux: xfs: add debug knob to slow down write for fun xfs: add debug knob to slow down writeback for fun
2 parents 7dd7380 + 254e345 commit cd14f15

File tree

7 files changed

+149
-5
lines changed

7 files changed

+149
-5
lines changed

fs/xfs/libxfs/xfs_errortag.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@
6161
#define XFS_ERRTAG_LARP 39
6262
#define XFS_ERRTAG_DA_LEAF_SPLIT 40
6363
#define XFS_ERRTAG_ATTR_LEAF_TO_NODE 41
64-
#define XFS_ERRTAG_MAX 42
64+
#define XFS_ERRTAG_WB_DELAY_MS 42
65+
#define XFS_ERRTAG_WRITE_DELAY_MS 43
66+
#define XFS_ERRTAG_MAX 44
6567

6668
/*
6769
* Random factors for above tags, 1 means always, 2 means 1/2 time, etc.
@@ -107,5 +109,7 @@
107109
#define XFS_RANDOM_LARP 1
108110
#define XFS_RANDOM_DA_LEAF_SPLIT 1
109111
#define XFS_RANDOM_ATTR_LEAF_TO_NODE 1
112+
#define XFS_RANDOM_WB_DELAY_MS 3000
113+
#define XFS_RANDOM_WRITE_DELAY_MS 3000
110114

111115
#endif /* __XFS_ERRORTAG_H_ */

fs/xfs/xfs_aops.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include "xfs_bmap.h"
1818
#include "xfs_bmap_util.h"
1919
#include "xfs_reflink.h"
20+
#include "xfs_errortag.h"
21+
#include "xfs_error.h"
2022

2123
struct xfs_writepage_ctx {
2224
struct iomap_writepage_ctx ctx;
@@ -217,11 +219,17 @@ xfs_imap_valid(
217219
* checked (and found nothing at this offset) could have added
218220
* overlapping blocks.
219221
*/
220-
if (XFS_WPC(wpc)->data_seq != READ_ONCE(ip->i_df.if_seq))
222+
if (XFS_WPC(wpc)->data_seq != READ_ONCE(ip->i_df.if_seq)) {
223+
trace_xfs_wb_data_iomap_invalid(ip, &wpc->iomap,
224+
XFS_WPC(wpc)->data_seq, XFS_DATA_FORK);
221225
return false;
226+
}
222227
if (xfs_inode_has_cow_data(ip) &&
223-
XFS_WPC(wpc)->cow_seq != READ_ONCE(ip->i_cowfp->if_seq))
228+
XFS_WPC(wpc)->cow_seq != READ_ONCE(ip->i_cowfp->if_seq)) {
229+
trace_xfs_wb_cow_iomap_invalid(ip, &wpc->iomap,
230+
XFS_WPC(wpc)->cow_seq, XFS_COW_FORK);
224231
return false;
232+
}
225233
return true;
226234
}
227235

@@ -285,6 +293,8 @@ xfs_map_blocks(
285293
if (xfs_is_shutdown(mp))
286294
return -EIO;
287295

296+
XFS_ERRORTAG_DELAY(mp, XFS_ERRTAG_WB_DELAY_MS);
297+
288298
/*
289299
* COW fork blocks can overlap data fork blocks even if the blocks
290300
* aren't shared. COW I/O always takes precedent, so we must always

fs/xfs/xfs_error.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ static unsigned int xfs_errortag_random_default[] = {
6060
XFS_RANDOM_LARP,
6161
XFS_RANDOM_DA_LEAF_SPLIT,
6262
XFS_RANDOM_ATTR_LEAF_TO_NODE,
63+
XFS_RANDOM_WB_DELAY_MS,
64+
XFS_RANDOM_WRITE_DELAY_MS,
6365
};
6466

6567
struct xfs_errortag_attr {
@@ -175,6 +177,8 @@ XFS_ERRORTAG_ATTR_RW(ag_resv_fail, XFS_ERRTAG_AG_RESV_FAIL);
175177
XFS_ERRORTAG_ATTR_RW(larp, XFS_ERRTAG_LARP);
176178
XFS_ERRORTAG_ATTR_RW(da_leaf_split, XFS_ERRTAG_DA_LEAF_SPLIT);
177179
XFS_ERRORTAG_ATTR_RW(attr_leaf_to_node, XFS_ERRTAG_ATTR_LEAF_TO_NODE);
180+
XFS_ERRORTAG_ATTR_RW(wb_delay_ms, XFS_ERRTAG_WB_DELAY_MS);
181+
XFS_ERRORTAG_ATTR_RW(write_delay_ms, XFS_ERRTAG_WRITE_DELAY_MS);
178182

179183
static struct attribute *xfs_errortag_attrs[] = {
180184
XFS_ERRORTAG_ATTR_LIST(noerror),
@@ -218,6 +222,8 @@ static struct attribute *xfs_errortag_attrs[] = {
218222
XFS_ERRORTAG_ATTR_LIST(larp),
219223
XFS_ERRORTAG_ATTR_LIST(da_leaf_split),
220224
XFS_ERRORTAG_ATTR_LIST(attr_leaf_to_node),
225+
XFS_ERRORTAG_ATTR_LIST(wb_delay_ms),
226+
XFS_ERRORTAG_ATTR_LIST(write_delay_ms),
221227
NULL,
222228
};
223229
ATTRIBUTE_GROUPS(xfs_errortag);
@@ -267,6 +273,19 @@ xfs_errortag_valid(
267273
return true;
268274
}
269275

276+
bool
277+
xfs_errortag_enabled(
278+
struct xfs_mount *mp,
279+
unsigned int tag)
280+
{
281+
if (!mp->m_errortag)
282+
return false;
283+
if (!xfs_errortag_valid(tag))
284+
return false;
285+
286+
return mp->m_errortag[tag] != 0;
287+
}
288+
270289
bool
271290
xfs_errortag_test(
272291
struct xfs_mount *mp,

fs/xfs/xfs_error.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,18 @@ extern bool xfs_errortag_test(struct xfs_mount *mp, const char *expression,
4545
const char *file, int line, unsigned int error_tag);
4646
#define XFS_TEST_ERROR(expr, mp, tag) \
4747
((expr) || xfs_errortag_test((mp), #expr, __FILE__, __LINE__, (tag)))
48+
bool xfs_errortag_enabled(struct xfs_mount *mp, unsigned int tag);
49+
#define XFS_ERRORTAG_DELAY(mp, tag) \
50+
do { \
51+
might_sleep(); \
52+
if (!xfs_errortag_enabled((mp), (tag))) \
53+
break; \
54+
xfs_warn_ratelimited((mp), \
55+
"Injecting %ums delay at file %s, line %d, on filesystem \"%s\"", \
56+
(mp)->m_errortag[(tag)], __FILE__, __LINE__, \
57+
(mp)->m_super->s_id); \
58+
mdelay((mp)->m_errortag[(tag)]); \
59+
} while (0)
4860

4961
extern int xfs_errortag_get(struct xfs_mount *mp, unsigned int error_tag);
5062
extern int xfs_errortag_set(struct xfs_mount *mp, unsigned int error_tag,
@@ -55,6 +67,7 @@ extern int xfs_errortag_clearall(struct xfs_mount *mp);
5567
#define xfs_errortag_init(mp) (0)
5668
#define xfs_errortag_del(mp)
5769
#define XFS_TEST_ERROR(expr, mp, tag) (expr)
70+
#define XFS_ERRORTAG_DELAY(mp, tag) ((void)0)
5871
#define xfs_errortag_set(mp, tag, val) (ENOSYS)
5972
#define xfs_errortag_add(mp, tag) (ENOSYS)
6073
#define xfs_errortag_clearall(mp) (ENOSYS)

fs/xfs/xfs_iomap.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
#include "xfs_dquot_item.h"
2828
#include "xfs_dquot.h"
2929
#include "xfs_reflink.h"
30+
#include "xfs_error.h"
31+
#include "xfs_errortag.h"
3032

3133
#define XFS_ALLOC_ALIGN(mp, off) \
3234
(((off) >> mp->m_allocsize_log) << mp->m_allocsize_log)
@@ -71,8 +73,16 @@ xfs_iomap_valid(
7173
struct inode *inode,
7274
const struct iomap *iomap)
7375
{
74-
return iomap->validity_cookie ==
75-
xfs_iomap_inode_sequence(XFS_I(inode), iomap->flags);
76+
struct xfs_inode *ip = XFS_I(inode);
77+
78+
if (iomap->validity_cookie !=
79+
xfs_iomap_inode_sequence(ip, iomap->flags)) {
80+
trace_xfs_iomap_invalid(ip, iomap);
81+
return false;
82+
}
83+
84+
XFS_ERRORTAG_DELAY(ip->i_mount, XFS_ERRTAG_WRITE_DELAY_MS);
85+
return true;
7686
}
7787

7888
const struct iomap_page_ops xfs_iomap_page_ops = {

fs/xfs/xfs_trace.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
#include "xfs_ag.h"
3535
#include "xfs_ag_resv.h"
3636
#include "xfs_error.h"
37+
#include <linux/iomap.h>
38+
#include "xfs_iomap.h"
3739

3840
/*
3941
* We include this last to have the helpers above available for the trace

fs/xfs/xfs_trace.h

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3352,6 +3352,92 @@ DEFINE_EVENT(xfs_inode_irec_class, name, \
33523352
TP_PROTO(struct xfs_inode *ip, struct xfs_bmbt_irec *irec), \
33533353
TP_ARGS(ip, irec))
33543354

3355+
/* inode iomap invalidation events */
3356+
DECLARE_EVENT_CLASS(xfs_wb_invalid_class,
3357+
TP_PROTO(struct xfs_inode *ip, const struct iomap *iomap, unsigned int wpcseq, int whichfork),
3358+
TP_ARGS(ip, iomap, wpcseq, whichfork),
3359+
TP_STRUCT__entry(
3360+
__field(dev_t, dev)
3361+
__field(xfs_ino_t, ino)
3362+
__field(u64, addr)
3363+
__field(loff_t, pos)
3364+
__field(u64, len)
3365+
__field(u16, type)
3366+
__field(u16, flags)
3367+
__field(u32, wpcseq)
3368+
__field(u32, forkseq)
3369+
),
3370+
TP_fast_assign(
3371+
__entry->dev = VFS_I(ip)->i_sb->s_dev;
3372+
__entry->ino = ip->i_ino;
3373+
__entry->addr = iomap->addr;
3374+
__entry->pos = iomap->offset;
3375+
__entry->len = iomap->length;
3376+
__entry->type = iomap->type;
3377+
__entry->flags = iomap->flags;
3378+
__entry->wpcseq = wpcseq;
3379+
__entry->forkseq = READ_ONCE(xfs_ifork_ptr(ip, whichfork)->if_seq);
3380+
),
3381+
TP_printk("dev %d:%d ino 0x%llx pos 0x%llx addr 0x%llx bytecount 0x%llx type 0x%x flags 0x%x wpcseq 0x%x forkseq 0x%x",
3382+
MAJOR(__entry->dev), MINOR(__entry->dev),
3383+
__entry->ino,
3384+
__entry->pos,
3385+
__entry->addr,
3386+
__entry->len,
3387+
__entry->type,
3388+
__entry->flags,
3389+
__entry->wpcseq,
3390+
__entry->forkseq)
3391+
);
3392+
#define DEFINE_WB_INVALID_EVENT(name) \
3393+
DEFINE_EVENT(xfs_wb_invalid_class, name, \
3394+
TP_PROTO(struct xfs_inode *ip, const struct iomap *iomap, unsigned int wpcseq, int whichfork), \
3395+
TP_ARGS(ip, iomap, wpcseq, whichfork))
3396+
DEFINE_WB_INVALID_EVENT(xfs_wb_cow_iomap_invalid);
3397+
DEFINE_WB_INVALID_EVENT(xfs_wb_data_iomap_invalid);
3398+
3399+
DECLARE_EVENT_CLASS(xfs_iomap_invalid_class,
3400+
TP_PROTO(struct xfs_inode *ip, const struct iomap *iomap),
3401+
TP_ARGS(ip, iomap),
3402+
TP_STRUCT__entry(
3403+
__field(dev_t, dev)
3404+
__field(xfs_ino_t, ino)
3405+
__field(u64, addr)
3406+
__field(loff_t, pos)
3407+
__field(u64, len)
3408+
__field(u64, validity_cookie)
3409+
__field(u64, inodeseq)
3410+
__field(u16, type)
3411+
__field(u16, flags)
3412+
),
3413+
TP_fast_assign(
3414+
__entry->dev = VFS_I(ip)->i_sb->s_dev;
3415+
__entry->ino = ip->i_ino;
3416+
__entry->addr = iomap->addr;
3417+
__entry->pos = iomap->offset;
3418+
__entry->len = iomap->length;
3419+
__entry->validity_cookie = iomap->validity_cookie;
3420+
__entry->type = iomap->type;
3421+
__entry->flags = iomap->flags;
3422+
__entry->inodeseq = xfs_iomap_inode_sequence(ip, iomap->flags);
3423+
),
3424+
TP_printk("dev %d:%d ino 0x%llx pos 0x%llx addr 0x%llx bytecount 0x%llx type 0x%x flags 0x%x validity_cookie 0x%llx inodeseq 0x%llx",
3425+
MAJOR(__entry->dev), MINOR(__entry->dev),
3426+
__entry->ino,
3427+
__entry->pos,
3428+
__entry->addr,
3429+
__entry->len,
3430+
__entry->type,
3431+
__entry->flags,
3432+
__entry->validity_cookie,
3433+
__entry->inodeseq)
3434+
);
3435+
#define DEFINE_IOMAP_INVALID_EVENT(name) \
3436+
DEFINE_EVENT(xfs_iomap_invalid_class, name, \
3437+
TP_PROTO(struct xfs_inode *ip, const struct iomap *iomap), \
3438+
TP_ARGS(ip, iomap))
3439+
DEFINE_IOMAP_INVALID_EVENT(xfs_iomap_invalid);
3440+
33553441
/* refcount/reflink tracepoint definitions */
33563442

33573443
/* reflink tracepoints */

0 commit comments

Comments
 (0)