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

block: null_blk: make fault-injection dynamically configurable per device

The null_blk driver has multiple driver-specific fault injection
mechanisms. Each fault injection configuration can only be specified by a
module parameter and cannot be reconfigured without reloading the driver.
Also, each configuration is common to all devices and is initialized every
time a new device is added.

This change adds the following subdirectories for each null_blk device.

/sys/kernel/config/nullb/<disk>/timeout_inject
/sys/kernel/config/nullb/<disk>/requeue_inject
/sys/kernel/config/nullb/<disk>/init_hctx_fault_inject

Each fault injection attribute can be dynamically set per device by a
corresponding file in these directories.

Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Link: https://lore.kernel.org/r/20230327143733.14599-3-akinobu.mita@gmail.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Akinobu Mita and committed by
Jens Axboe
bb4c19e0 4668c7a2

+87 -23
+8
Documentation/fault-injection/fault-injection.rst
··· 52 52 status code is NVME_SC_INVALID_OPCODE with no retry. The status code and 53 53 retry flag can be set via the debugfs. 54 54 55 + - Null test block driver fault injection 56 + 57 + inject IO timeouts by setting config items under 58 + /sys/kernel/config/nullb/<disk>/timeout_inject, 59 + inject requeue requests by setting config items under 60 + /sys/kernel/config/nullb/<disk>/requeue_inject, and 61 + inject init_hctx() errors by setting config items under 62 + /sys/kernel/config/nullb/<disk>/init_hctx_fault_inject. 55 63 56 64 Configure fault-injection capabilities behavior 57 65 -----------------------------------------------
+1 -1
drivers/block/null_blk/Kconfig
··· 9 9 10 10 config BLK_DEV_NULL_BLK_FAULT_INJECTION 11 11 bool "Support fault injection for Null test block driver" 12 - depends on BLK_DEV_NULL_BLK && FAULT_INJECTION 12 + depends on BLK_DEV_NULL_BLK && FAULT_INJECTION_CONFIGFS
+72 -21
drivers/block/null_blk/main.c
··· 250 250 251 251 static inline struct nullb_device *to_nullb_device(struct config_item *item) 252 252 { 253 - return item ? container_of(item, struct nullb_device, item) : NULL; 253 + return item ? container_of(to_config_group(item), struct nullb_device, group) : NULL; 254 254 } 255 255 256 256 static inline ssize_t nullb_device_uint_attr_show(unsigned int val, char *page) ··· 593 593 .ct_owner = THIS_MODULE, 594 594 }; 595 595 596 + #ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION 597 + 598 + static void nullb_add_fault_config(struct nullb_device *dev) 599 + { 600 + fault_config_init(&dev->timeout_config, "timeout_inject"); 601 + fault_config_init(&dev->requeue_config, "requeue_inject"); 602 + fault_config_init(&dev->init_hctx_fault_config, "init_hctx_fault_inject"); 603 + 604 + configfs_add_default_group(&dev->timeout_config.group, &dev->group); 605 + configfs_add_default_group(&dev->requeue_config.group, &dev->group); 606 + configfs_add_default_group(&dev->init_hctx_fault_config.group, &dev->group); 607 + } 608 + 609 + #else 610 + 611 + static void nullb_add_fault_config(struct nullb_device *dev) 612 + { 613 + } 614 + 615 + #endif 616 + 596 617 static struct 597 - config_item *nullb_group_make_item(struct config_group *group, const char *name) 618 + config_group *nullb_group_make_group(struct config_group *group, const char *name) 598 619 { 599 620 struct nullb_device *dev; 600 621 ··· 626 605 if (!dev) 627 606 return ERR_PTR(-ENOMEM); 628 607 629 - config_item_init_type_name(&dev->item, name, &nullb_device_type); 608 + config_group_init_type_name(&dev->group, name, &nullb_device_type); 609 + nullb_add_fault_config(dev); 630 610 631 - return &dev->item; 611 + return &dev->group; 632 612 } 633 613 634 614 static void ··· 667 645 }; 668 646 669 647 static struct configfs_group_operations nullb_group_ops = { 670 - .make_item = nullb_group_make_item, 648 + .make_group = nullb_group_make_group, 671 649 .drop_item = nullb_group_drop_item, 672 650 }; 673 651 ··· 698 676 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 699 677 if (!dev) 700 678 return NULL; 679 + 680 + #ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION 681 + dev->timeout_config.attr = null_timeout_attr; 682 + dev->requeue_config.attr = null_requeue_attr; 683 + dev->init_hctx_fault_config.attr = null_init_hctx_attr; 684 + #endif 685 + 701 686 INIT_RADIX_TREE(&dev->data, GFP_ATOMIC); 702 687 INIT_RADIX_TREE(&dev->cache, GFP_ATOMIC); 703 688 if (badblocks_init(&dev->badblocks, 0)) { ··· 1544 1515 null_handle_cmd(alloc_cmd(nq, bio), sector, nr_sectors, bio_op(bio)); 1545 1516 } 1546 1517 1518 + #ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION 1519 + 1547 1520 static bool should_timeout_request(struct request *rq) 1548 1521 { 1549 - #ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION 1550 - if (g_timeout_str[0]) 1551 - return should_fail(&null_timeout_attr, 1); 1552 - #endif 1522 + struct nullb_cmd *cmd = blk_mq_rq_to_pdu(rq); 1523 + struct nullb_device *dev = cmd->nq->dev; 1524 + 1525 + return should_fail(&dev->timeout_config.attr, 1); 1526 + } 1527 + 1528 + static bool should_requeue_request(struct request *rq) 1529 + { 1530 + struct nullb_cmd *cmd = blk_mq_rq_to_pdu(rq); 1531 + struct nullb_device *dev = cmd->nq->dev; 1532 + 1533 + return should_fail(&dev->requeue_config.attr, 1); 1534 + } 1535 + 1536 + static bool should_init_hctx_fail(struct nullb_device *dev) 1537 + { 1538 + return should_fail(&dev->init_hctx_fault_config.attr, 1); 1539 + } 1540 + 1541 + #else 1542 + 1543 + static bool should_timeout_request(struct request *rq) 1544 + { 1553 1545 return false; 1554 1546 } 1555 1547 1556 1548 static bool should_requeue_request(struct request *rq) 1557 1549 { 1558 - #ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION 1559 - if (g_requeue_str[0]) 1560 - return should_fail(&null_requeue_attr, 1); 1561 - #endif 1562 1550 return false; 1563 1551 } 1552 + 1553 + static bool should_init_hctx_fail(struct nullb_device *dev) 1554 + { 1555 + return false; 1556 + } 1557 + 1558 + #endif 1564 1559 1565 1560 static void null_map_queues(struct blk_mq_tag_set *set) 1566 1561 { ··· 1782 1729 struct nullb *nullb = hctx->queue->queuedata; 1783 1730 struct nullb_queue *nq; 1784 1731 1785 - #ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION 1786 - if (g_init_hctx_str[0] && should_fail(&null_init_hctx_attr, 1)) 1732 + if (should_init_hctx_fail(nullb->dev)) 1787 1733 return -EFAULT; 1788 - #endif 1789 1734 1790 1735 nq = &nullb->queues[hctx_idx]; 1791 1736 hctx->driver_data = nq; ··· 2103 2052 if (rv) 2104 2053 goto out_cleanup_queues; 2105 2054 2106 - if (!null_setup_fault()) 2107 - goto out_cleanup_tags; 2108 - 2109 2055 nullb->tag_set->timeout = 5 * HZ; 2110 2056 nullb->disk = blk_mq_alloc_disk(nullb->tag_set, nullb); 2111 2057 if (IS_ERR(nullb->disk)) { ··· 2164 2116 2165 2117 null_config_discard(nullb); 2166 2118 2167 - if (config_item_name(&dev->item)) { 2119 + if (config_item_name(&dev->group.cg_item)) { 2168 2120 /* Use configfs dir name as the device name */ 2169 2121 snprintf(nullb->disk_name, sizeof(nullb->disk_name), 2170 - "%s", config_item_name(&dev->item)); 2122 + "%s", config_item_name(&dev->group.cg_item)); 2171 2123 } else { 2172 2124 sprintf(nullb->disk_name, "nullb%d", nullb->index); 2173 2125 } ··· 2266 2218 pr_err("invalid home_node value\n"); 2267 2219 g_home_node = NUMA_NO_NODE; 2268 2220 } 2221 + 2222 + if (!null_setup_fault()) 2223 + return -EINVAL; 2269 2224 2270 2225 if (g_queue_mode == NULL_Q_RQ) { 2271 2226 pr_err("legacy IO path is no longer available\n");
+6 -1
drivers/block/null_blk/null_blk.h
··· 69 69 70 70 struct nullb_device { 71 71 struct nullb *nullb; 72 - struct config_item item; 72 + struct config_group group; 73 + #ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION 74 + struct fault_config timeout_config; 75 + struct fault_config requeue_config; 76 + struct fault_config init_hctx_fault_config; 77 + #endif 73 78 struct radix_tree_root data; /* data stored in the disk */ 74 79 struct radix_tree_root cache; /* disk cache data */ 75 80 unsigned long flags; /* device flags */