xfs: add log item pinning error injection tag
authorBrian Foster <bfoster@redhat.com>
Wed, 9 Aug 2017 01:21:52 +0000 (18:21 -0700)
committerDarrick J. Wong <darrick.wong@oracle.com>
Tue, 22 Aug 2017 16:22:24 +0000 (09:22 -0700)
Add an error injection tag to force log items in the AIL to the
pinned state. This option can be used by test infrastructure to
induce head behind tail conditions. Specifically, this is intended
to be used by xfstests to reproduce log recovery problems after
failed/corrupted log writes overwrite the last good tail LSN in the
log.

When enabled, AIL push attempts see log items in the AIL in the
pinned state. This stalls metadata writeback and thus prevents the
current tail of the log from moving forward. When disabled,
subsequent AIL pushes observe the log items in their appropriate
state and filesystem operation continues as normal.

Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
fs/xfs/xfs_error.c
fs/xfs/xfs_error.h
fs/xfs/xfs_trans_ail.c

index 2f4feb959bfb46812678b65e262270b2fc55842a..bd786a9ac2c38879cf6e94ad660cd1bda19873c5 100644 (file)
@@ -57,6 +57,7 @@ static unsigned int xfs_errortag_random_default[] = {
        XFS_RANDOM_AG_RESV_CRITICAL,
        XFS_RANDOM_DROP_WRITES,
        XFS_RANDOM_LOG_BAD_CRC,
+       XFS_RANDOM_LOG_ITEM_PIN,
 };
 
 struct xfs_errortag_attr {
@@ -161,6 +162,7 @@ XFS_ERRORTAG_ATTR_RW(bmap_finish_one,       XFS_ERRTAG_BMAP_FINISH_ONE);
 XFS_ERRORTAG_ATTR_RW(ag_resv_critical, XFS_ERRTAG_AG_RESV_CRITICAL);
 XFS_ERRORTAG_ATTR_RW(drop_writes,      XFS_ERRTAG_DROP_WRITES);
 XFS_ERRORTAG_ATTR_RW(log_bad_crc,      XFS_ERRTAG_LOG_BAD_CRC);
+XFS_ERRORTAG_ATTR_RW(log_item_pin,     XFS_ERRTAG_LOG_ITEM_PIN);
 
 static struct attribute *xfs_errortag_attrs[] = {
        XFS_ERRORTAG_ATTR_LIST(noerror),
@@ -193,6 +195,7 @@ static struct attribute *xfs_errortag_attrs[] = {
        XFS_ERRORTAG_ATTR_LIST(ag_resv_critical),
        XFS_ERRORTAG_ATTR_LIST(drop_writes),
        XFS_ERRORTAG_ATTR_LIST(log_bad_crc),
+       XFS_ERRORTAG_ATTR_LIST(log_item_pin),
        NULL,
 };
 
index 7577be5f09bc04fa6522baaccf8de6af879efd77..7c4bef3bddb7504d0c06dd27479fc5b6dfa9f1c5 100644 (file)
@@ -106,7 +106,8 @@ extern void xfs_verifier_error(struct xfs_buf *bp);
  */
 #define XFS_ERRTAG_DROP_WRITES                         28
 #define XFS_ERRTAG_LOG_BAD_CRC                         29
-#define XFS_ERRTAG_MAX                                 30
+#define XFS_ERRTAG_LOG_ITEM_PIN                                30
+#define XFS_ERRTAG_MAX                                 31
 
 /*
  * Random factors for above tags, 1 means always, 2 means 1/2 time, etc.
@@ -141,6 +142,7 @@ extern void xfs_verifier_error(struct xfs_buf *bp);
 #define XFS_RANDOM_AG_RESV_CRITICAL                    4
 #define XFS_RANDOM_DROP_WRITES                         1
 #define XFS_RANDOM_LOG_BAD_CRC                         1
+#define XFS_RANDOM_LOG_ITEM_PIN                                1
 
 #ifdef DEBUG
 extern int xfs_errortag_init(struct xfs_mount *mp);
index 70f5ab01732360450a3f1c95e23b74c829db2672..354368a906e593c9e1e3a268c38919bbb5a20ab7 100644 (file)
@@ -325,6 +325,21 @@ xfs_ail_delete(
        xfs_trans_ail_cursor_clear(ailp, lip);
 }
 
+static inline uint
+xfsaild_push_item(
+       struct xfs_ail          *ailp,
+       struct xfs_log_item     *lip)
+{
+       /*
+        * If log item pinning is enabled, skip the push and track the item as
+        * pinned. This can help induce head-behind-tail conditions.
+        */
+       if (XFS_TEST_ERROR(false, ailp->xa_mount, XFS_ERRTAG_LOG_ITEM_PIN))
+               return XFS_ITEM_PINNED;
+
+       return lip->li_ops->iop_push(lip, &ailp->xa_buf_list);
+}
+
 static long
 xfsaild_push(
        struct xfs_ail          *ailp)
@@ -382,7 +397,7 @@ xfsaild_push(
                 * rely on the AIL cursor implementation to be able to deal with
                 * the dropped lock.
                 */
-               lock_result = lip->li_ops->iop_push(lip, &ailp->xa_buf_list);
+               lock_result = xfsaild_push_item(ailp, lip);
                switch (lock_result) {
                case XFS_ITEM_SUCCESS:
                        XFS_STATS_INC(mp, xs_push_ail_success);