]>
Commit | Line | Data |
---|---|---|
bc50ad75 | 1 | // SPDX-License-Identifier: GPL-2.0 |
b9e03857 TT |
2 | /* |
3 | * fault injection support for nvme. | |
4 | * | |
5 | * Copyright (c) 2018, Oracle and/or its affiliates | |
b9e03857 TT |
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_ns *ns) | |
19 | { | |
20 | struct dentry *dir, *parent; | |
21 | char *name = ns->disk->disk_name; | |
22 | struct nvme_fault_inject *fault_inj = &ns->fault_inject; | |
23 | struct fault_attr *attr = &fault_inj->attr; | |
24 | ||
25 | /* set default fault injection attribute */ | |
26 | if (fail_request) | |
27 | setup_fault_attr(&fail_default_attr, fail_request); | |
28 | ||
29 | /* create debugfs directory and attribute */ | |
30 | parent = debugfs_create_dir(name, NULL); | |
31 | if (!parent) { | |
32 | pr_warn("%s: failed to create debugfs directory\n", name); | |
33 | return; | |
34 | } | |
35 | ||
36 | *attr = fail_default_attr; | |
37 | dir = fault_create_debugfs_attr("fault_inject", parent, attr); | |
38 | if (IS_ERR(dir)) { | |
39 | pr_warn("%s: failed to create debugfs attr\n", name); | |
40 | debugfs_remove_recursive(parent); | |
41 | return; | |
42 | } | |
43 | ns->fault_inject.parent = parent; | |
44 | ||
45 | /* create debugfs for status code and dont_retry */ | |
46 | fault_inj->status = NVME_SC_INVALID_OPCODE; | |
47 | fault_inj->dont_retry = true; | |
48 | debugfs_create_x16("status", 0600, dir, &fault_inj->status); | |
49 | debugfs_create_bool("dont_retry", 0600, dir, &fault_inj->dont_retry); | |
50 | } | |
51 | ||
52 | void nvme_fault_inject_fini(struct nvme_ns *ns) | |
53 | { | |
54 | /* remove debugfs directories */ | |
55 | debugfs_remove_recursive(ns->fault_inject.parent); | |
56 | } | |
57 | ||
58 | void nvme_should_fail(struct request *req) | |
59 | { | |
60 | struct gendisk *disk = req->rq_disk; | |
61 | struct nvme_ns *ns = NULL; | |
62 | u16 status; | |
63 | ||
64 | /* | |
65 | * make sure this request is coming from a valid namespace | |
66 | */ | |
67 | if (!disk) | |
68 | return; | |
69 | ||
70 | ns = disk->private_data; | |
71 | if (ns && should_fail(&ns->fault_inject.attr, 1)) { | |
72 | /* inject status code and DNR bit */ | |
73 | status = ns->fault_inject.status; | |
74 | if (ns->fault_inject.dont_retry) | |
75 | status |= NVME_SC_DNR; | |
76 | nvme_req(req)->status = status; | |
77 | } | |
78 | } | |
79 | EXPORT_SYMBOL_GPL(nvme_should_fail); |