1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * fault injection support for nvme. |
4 | * |
5 | * Copyright (c) 2018, Oracle and/or its affiliates |
6 | */ |
7 | |
8 | #include <linux/moduleparam.h> |
9 | #include "nvme.h" |
10 | |
11 | static DECLARE_FAULT_ATTR(fail_default_attr); |
12 | /* optional fault injection attributes boot time option: |
13 | * nvme_core.fail_request=<interval>,<probability>,<space>,<times> |
14 | */ |
15 | static char *fail_request; |
16 | module_param(fail_request, charp, 0000); |
17 | |
18 | void nvme_fault_inject_init(struct nvme_fault_inject *fault_inj, |
19 | const char *dev_name) |
20 | { |
21 | struct dentry *dir, *parent; |
22 | struct fault_attr *attr = &fault_inj->attr; |
23 | |
24 | /* set default fault injection attribute */ |
25 | if (fail_request) |
26 | setup_fault_attr(attr: &fail_default_attr, str: fail_request); |
27 | |
28 | /* create debugfs directory and attribute */ |
29 | parent = debugfs_create_dir(name: dev_name, NULL); |
30 | if (IS_ERR(ptr: parent)) { |
31 | pr_warn("%s: failed to create debugfs directory\n" , dev_name); |
32 | return; |
33 | } |
34 | |
35 | *attr = fail_default_attr; |
36 | dir = fault_create_debugfs_attr(name: "fault_inject" , parent, attr); |
37 | if (IS_ERR(ptr: dir)) { |
38 | pr_warn("%s: failed to create debugfs attr\n" , dev_name); |
39 | debugfs_remove_recursive(dentry: parent); |
40 | return; |
41 | } |
42 | fault_inj->parent = parent; |
43 | |
44 | /* create debugfs for status code and dont_retry */ |
45 | fault_inj->status = NVME_SC_INVALID_OPCODE; |
46 | fault_inj->dont_retry = true; |
47 | debugfs_create_x16(name: "status" , mode: 0600, parent: dir, value: &fault_inj->status); |
48 | debugfs_create_bool(name: "dont_retry" , mode: 0600, parent: dir, value: &fault_inj->dont_retry); |
49 | } |
50 | |
51 | void nvme_fault_inject_fini(struct nvme_fault_inject *fault_inject) |
52 | { |
53 | /* remove debugfs directories */ |
54 | debugfs_remove_recursive(dentry: fault_inject->parent); |
55 | } |
56 | |
57 | void nvme_should_fail(struct request *req) |
58 | { |
59 | struct gendisk *disk = req->q->disk; |
60 | struct nvme_fault_inject *fault_inject = NULL; |
61 | u16 status; |
62 | |
63 | if (disk) { |
64 | struct nvme_ns *ns = disk->private_data; |
65 | |
66 | if (ns) |
67 | fault_inject = &ns->fault_inject; |
68 | else |
69 | WARN_ONCE(1, "No namespace found for request\n" ); |
70 | } else { |
71 | fault_inject = &nvme_req(req)->ctrl->fault_inject; |
72 | } |
73 | |
74 | if (fault_inject && should_fail(attr: &fault_inject->attr, size: 1)) { |
75 | /* inject status code and DNR bit */ |
76 | status = fault_inject->status; |
77 | if (fault_inject->dont_retry) |
78 | status |= NVME_SC_DNR; |
79 | nvme_req(req)->status = status; |
80 | } |
81 | } |
82 | EXPORT_SYMBOL_GPL(nvme_should_fail); |
83 | |