Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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
745b3f76d1c8 ("xfs: maintain a sequence count for inode fork
manipulations").

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Dave Chinner <dchinner@redhat.com>

+90 -3
+3 -1
fs/xfs/libxfs/xfs_errortag.h
··· 61 61 #define XFS_ERRTAG_LARP 39 62 62 #define XFS_ERRTAG_DA_LEAF_SPLIT 40 63 63 #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 65 66 66 67 /* 67 68 * Random factors for above tags, 1 means always, 2 means 1/2 time, etc. ··· 108 107 #define XFS_RANDOM_LARP 1 109 108 #define XFS_RANDOM_DA_LEAF_SPLIT 1 110 109 #define XFS_RANDOM_ATTR_LEAF_TO_NODE 1 110 + #define XFS_RANDOM_WB_DELAY_MS 3000 111 111 112 112 #endif /* __XFS_ERRORTAG_H_ */
+12 -2
fs/xfs/xfs_aops.c
··· 17 17 #include "xfs_bmap.h" 18 18 #include "xfs_bmap_util.h" 19 19 #include "xfs_reflink.h" 20 + #include "xfs_errortag.h" 21 + #include "xfs_error.h" 20 22 21 23 struct xfs_writepage_ctx { 22 24 struct iomap_writepage_ctx ctx; ··· 219 217 * checked (and found nothing at this offset) could have added 220 218 * overlapping blocks. 221 219 */ 222 - if (XFS_WPC(wpc)->data_seq != READ_ONCE(ip->i_df.if_seq)) 220 + if (XFS_WPC(wpc)->data_seq != READ_ONCE(ip->i_df.if_seq)) { 221 + trace_xfs_wb_data_iomap_invalid(ip, &wpc->iomap, 222 + XFS_WPC(wpc)->data_seq, XFS_DATA_FORK); 223 223 return false; 224 + } 224 225 if (xfs_inode_has_cow_data(ip) && 225 - XFS_WPC(wpc)->cow_seq != READ_ONCE(ip->i_cowfp->if_seq)) 226 + XFS_WPC(wpc)->cow_seq != READ_ONCE(ip->i_cowfp->if_seq)) { 227 + trace_xfs_wb_cow_iomap_invalid(ip, &wpc->iomap, 228 + XFS_WPC(wpc)->cow_seq, XFS_COW_FORK); 226 229 return false; 230 + } 227 231 return true; 228 232 } 229 233 ··· 292 284 293 285 if (xfs_is_shutdown(mp)) 294 286 return -EIO; 287 + 288 + XFS_ERRORTAG_DELAY(mp, XFS_ERRTAG_WB_DELAY_MS); 295 289 296 290 /* 297 291 * COW fork blocks can overlap data fork blocks even if the blocks
+16
fs/xfs/xfs_error.c
··· 60 60 XFS_RANDOM_LARP, 61 61 XFS_RANDOM_DA_LEAF_SPLIT, 62 62 XFS_RANDOM_ATTR_LEAF_TO_NODE, 63 + XFS_RANDOM_WB_DELAY_MS, 63 64 }; 64 65 65 66 struct xfs_errortag_attr { ··· 176 175 XFS_ERRORTAG_ATTR_RW(larp, XFS_ERRTAG_LARP); 177 176 XFS_ERRORTAG_ATTR_RW(da_leaf_split, XFS_ERRTAG_DA_LEAF_SPLIT); 178 177 XFS_ERRORTAG_ATTR_RW(attr_leaf_to_node, XFS_ERRTAG_ATTR_LEAF_TO_NODE); 178 + XFS_ERRORTAG_ATTR_RW(wb_delay_ms, XFS_ERRTAG_WB_DELAY_MS); 179 179 180 180 static struct attribute *xfs_errortag_attrs[] = { 181 181 XFS_ERRORTAG_ATTR_LIST(noerror), ··· 220 218 XFS_ERRORTAG_ATTR_LIST(larp), 221 219 XFS_ERRORTAG_ATTR_LIST(da_leaf_split), 222 220 XFS_ERRORTAG_ATTR_LIST(attr_leaf_to_node), 221 + XFS_ERRORTAG_ATTR_LIST(wb_delay_ms), 223 222 NULL, 224 223 }; 225 224 ATTRIBUTE_GROUPS(xfs_errortag); ··· 268 265 if (error_tag == XFS_ERRTAG_DROP_WRITES) 269 266 return false; 270 267 return true; 268 + } 269 + 270 + bool 271 + xfs_errortag_enabled( 272 + struct xfs_mount *mp, 273 + unsigned int tag) 274 + { 275 + if (!mp->m_errortag) 276 + return false; 277 + if (!xfs_errortag_valid(tag)) 278 + return false; 279 + 280 + return mp->m_errortag[tag] != 0; 271 281 } 272 282 273 283 bool
+13
fs/xfs/xfs_error.h
··· 45 45 const char *file, int line, unsigned int error_tag); 46 46 #define XFS_TEST_ERROR(expr, mp, tag) \ 47 47 ((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) 48 60 49 61 extern int xfs_errortag_get(struct xfs_mount *mp, unsigned int error_tag); 50 62 extern int xfs_errortag_set(struct xfs_mount *mp, unsigned int error_tag, ··· 67 55 #define xfs_errortag_init(mp) (0) 68 56 #define xfs_errortag_del(mp) 69 57 #define XFS_TEST_ERROR(expr, mp, tag) (expr) 58 + #define XFS_ERRORTAG_DELAY(mp, tag) ((void)0) 70 59 #define xfs_errortag_set(mp, tag, val) (ENOSYS) 71 60 #define xfs_errortag_add(mp, tag) (ENOSYS) 72 61 #define xfs_errortag_clearall(mp) (ENOSYS)
+2
fs/xfs/xfs_trace.c
··· 34 34 #include "xfs_ag.h" 35 35 #include "xfs_ag_resv.h" 36 36 #include "xfs_error.h" 37 + #include <linux/iomap.h> 38 + #include "xfs_iomap.h" 37 39 38 40 /* 39 41 * We include this last to have the helpers above available for the trace
+44
fs/xfs/xfs_trace.h
··· 3352 3352 TP_PROTO(struct xfs_inode *ip, struct xfs_bmbt_irec *irec), \ 3353 3353 TP_ARGS(ip, irec)) 3354 3354 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 + 3355 3399 /* refcount/reflink tracepoint definitions */ 3356 3400 3357 3401 /* reflink tracepoints */