Skip to content

Commit c2beff9

Browse files
author
Darrick J. Wong
committed
xfs: add debug knob to slow down writeback for fun
Add a new error injection knob so that we can arbitrarily slow down writeback to test for race conditions and aberrant reclaim behavior if the writeback mechanisms are slow to issue writeback. This will enable functional testing for the ifork sequence counters introduced in commit 745b3f7 ("xfs: maintain a sequence count for inode fork manipulations"). Signed-off-by: Darrick J. Wong <[email protected]> Reviewed-by: Dave Chinner <[email protected]>
1 parent 7dd7380 commit c2beff9

File tree

6 files changed

+90
-3
lines changed

6 files changed

+90
-3
lines changed

fs/xfs/libxfs/xfs_errortag.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@
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_MAX 43
6566

6667
/*
6768
* Random factors for above tags, 1 means always, 2 means 1/2 time, etc.
@@ -107,5 +108,6 @@
107108
#define XFS_RANDOM_LARP 1
108109
#define XFS_RANDOM_DA_LEAF_SPLIT 1
109110
#define XFS_RANDOM_ATTR_LEAF_TO_NODE 1
111+
#define XFS_RANDOM_WB_DELAY_MS 3000
110112

111113
#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: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ 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,
6364
};
6465

6566
struct xfs_errortag_attr {
@@ -175,6 +176,7 @@ XFS_ERRORTAG_ATTR_RW(ag_resv_fail, XFS_ERRTAG_AG_RESV_FAIL);
175176
XFS_ERRORTAG_ATTR_RW(larp, XFS_ERRTAG_LARP);
176177
XFS_ERRORTAG_ATTR_RW(da_leaf_split, XFS_ERRTAG_DA_LEAF_SPLIT);
177178
XFS_ERRORTAG_ATTR_RW(attr_leaf_to_node, XFS_ERRTAG_ATTR_LEAF_TO_NODE);
179+
XFS_ERRORTAG_ATTR_RW(wb_delay_ms, XFS_ERRTAG_WB_DELAY_MS);
178180

179181
static struct attribute *xfs_errortag_attrs[] = {
180182
XFS_ERRORTAG_ATTR_LIST(noerror),
@@ -218,6 +220,7 @@ static struct attribute *xfs_errortag_attrs[] = {
218220
XFS_ERRORTAG_ATTR_LIST(larp),
219221
XFS_ERRORTAG_ATTR_LIST(da_leaf_split),
220222
XFS_ERRORTAG_ATTR_LIST(attr_leaf_to_node),
223+
XFS_ERRORTAG_ATTR_LIST(wb_delay_ms),
221224
NULL,
222225
};
223226
ATTRIBUTE_GROUPS(xfs_errortag);
@@ -267,6 +270,19 @@ xfs_errortag_valid(
267270
return true;
268271
}
269272

273+
bool
274+
xfs_errortag_enabled(
275+
struct xfs_mount *mp,
276+
unsigned int tag)
277+
{
278+
if (!mp->m_errortag)
279+
return false;
280+
if (!xfs_errortag_valid(tag))
281+
return false;
282+
283+
return mp->m_errortag[tag] != 0;
284+
}
285+
270286
bool
271287
xfs_errortag_test(
272288
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_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: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3352,6 +3352,50 @@ 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+
33553399
/* refcount/reflink tracepoint definitions */
33563400

33573401
/* reflink tracepoints */

0 commit comments

Comments
 (0)