Commit | Line | Data |
---|---|---|
3bd94003 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
784aae73 MB |
2 | /* |
3 | * Copyright (C) 2008 Red Hat, Inc. All rights reserved. | |
4 | * | |
5 | * This file is released under the GPL. | |
6 | */ | |
7 | ||
8 | #include <linux/sysfs.h> | |
9 | #include <linux/dm-ioctl.h> | |
4cc96131 MS |
10 | #include "dm-core.h" |
11 | #include "dm-rq.h" | |
784aae73 MB |
12 | |
13 | struct dm_sysfs_attr { | |
14 | struct attribute attr; | |
02f10ba1 HM |
15 | ssize_t (*show)(struct mapped_device *md, char *p); |
16 | ssize_t (*store)(struct mapped_device *md, const char *p, size_t count); | |
784aae73 MB |
17 | }; |
18 | ||
19 | #define DM_ATTR_RO(_name) \ | |
20 | struct dm_sysfs_attr dm_attr_##_name = \ | |
6a808034 | 21 | __ATTR(_name, 0444, dm_attr_##_name##_show, NULL) |
784aae73 MB |
22 | |
23 | static ssize_t dm_attr_show(struct kobject *kobj, struct attribute *attr, | |
24 | char *page) | |
25 | { | |
26 | struct dm_sysfs_attr *dm_attr; | |
27 | struct mapped_device *md; | |
28 | ssize_t ret; | |
29 | ||
30 | dm_attr = container_of(attr, struct dm_sysfs_attr, attr); | |
31 | if (!dm_attr->show) | |
32 | return -EIO; | |
33 | ||
34 | md = dm_get_from_kobject(kobj); | |
35 | if (!md) | |
36 | return -EINVAL; | |
37 | ||
38 | ret = dm_attr->show(md, page); | |
39 | dm_put(md); | |
40 | ||
41 | return ret; | |
42 | } | |
43 | ||
b898320d MS |
44 | #define DM_ATTR_RW(_name) \ |
45 | struct dm_sysfs_attr dm_attr_##_name = \ | |
6a808034 | 46 | __ATTR(_name, 0644, dm_attr_##_name##_show, dm_attr_##_name##_store) |
b898320d MS |
47 | |
48 | static ssize_t dm_attr_store(struct kobject *kobj, struct attribute *attr, | |
49 | const char *page, size_t count) | |
50 | { | |
51 | struct dm_sysfs_attr *dm_attr; | |
52 | struct mapped_device *md; | |
53 | ssize_t ret; | |
54 | ||
55 | dm_attr = container_of(attr, struct dm_sysfs_attr, attr); | |
56 | if (!dm_attr->store) | |
57 | return -EIO; | |
58 | ||
59 | md = dm_get_from_kobject(kobj); | |
60 | if (!md) | |
61 | return -EINVAL; | |
62 | ||
63 | ret = dm_attr->store(md, page, count); | |
64 | dm_put(md); | |
65 | ||
66 | return ret; | |
67 | } | |
68 | ||
784aae73 MB |
69 | static ssize_t dm_attr_name_show(struct mapped_device *md, char *buf) |
70 | { | |
71 | if (dm_copy_name_and_uuid(md, buf, NULL)) | |
72 | return -EIO; | |
73 | ||
74 | strcat(buf, "\n"); | |
75 | return strlen(buf); | |
76 | } | |
77 | ||
78 | static ssize_t dm_attr_uuid_show(struct mapped_device *md, char *buf) | |
79 | { | |
80 | if (dm_copy_name_and_uuid(md, NULL, buf)) | |
81 | return -EIO; | |
82 | ||
83 | strcat(buf, "\n"); | |
84 | return strlen(buf); | |
85 | } | |
86 | ||
486d220f PR |
87 | static ssize_t dm_attr_suspended_show(struct mapped_device *md, char *buf) |
88 | { | |
4f186f8b | 89 | sprintf(buf, "%d\n", dm_suspended_md(md)); |
486d220f PR |
90 | |
91 | return strlen(buf); | |
92 | } | |
93 | ||
17e149b8 MS |
94 | static ssize_t dm_attr_use_blk_mq_show(struct mapped_device *md, char *buf) |
95 | { | |
6a23e05c JA |
96 | /* Purely for userspace compatibility */ |
97 | sprintf(buf, "%d\n", true); | |
17e149b8 MS |
98 | |
99 | return strlen(buf); | |
100 | } | |
101 | ||
784aae73 MB |
102 | static DM_ATTR_RO(name); |
103 | static DM_ATTR_RO(uuid); | |
486d220f | 104 | static DM_ATTR_RO(suspended); |
17e149b8 | 105 | static DM_ATTR_RO(use_blk_mq); |
0ce65797 | 106 | static DM_ATTR_RW(rq_based_seq_io_merge_deadline); |
784aae73 MB |
107 | |
108 | static struct attribute *dm_attrs[] = { | |
109 | &dm_attr_name.attr, | |
110 | &dm_attr_uuid.attr, | |
486d220f | 111 | &dm_attr_suspended.attr, |
17e149b8 | 112 | &dm_attr_use_blk_mq.attr, |
0ce65797 | 113 | &dm_attr_rq_based_seq_io_merge_deadline.attr, |
784aae73 MB |
114 | NULL, |
115 | }; | |
eaac0b59 | 116 | ATTRIBUTE_GROUPS(dm); |
784aae73 | 117 | |
52cf25d0 | 118 | static const struct sysfs_ops dm_sysfs_ops = { |
784aae73 | 119 | .show = dm_attr_show, |
b898320d | 120 | .store = dm_attr_store, |
784aae73 MB |
121 | }; |
122 | ||
b0bbd86a | 123 | static const struct kobj_type dm_ktype = { |
784aae73 | 124 | .sysfs_ops = &dm_sysfs_ops, |
eaac0b59 | 125 | .default_groups = dm_groups, |
be35f486 | 126 | .release = dm_kobject_release, |
784aae73 MB |
127 | }; |
128 | ||
129 | /* | |
130 | * Initialize kobj | |
131 | * because nobody using md yet, no need to call explicit dm_get/put | |
132 | */ | |
133 | int dm_sysfs_init(struct mapped_device *md) | |
134 | { | |
135 | return kobject_init_and_add(dm_kobject(md), &dm_ktype, | |
136 | &disk_to_dev(dm_disk(md))->kobj, | |
137 | "%s", "dm"); | |
138 | } | |
139 | ||
140 | /* | |
141 | * Remove kobj, called after all references removed | |
142 | */ | |
143 | void dm_sysfs_exit(struct mapped_device *md) | |
144 | { | |
be35f486 | 145 | struct kobject *kobj = dm_kobject(md); |
0ef0b471 | 146 | |
be35f486 MP |
147 | kobject_put(kobj); |
148 | wait_for_completion(dm_get_completion_from_kobject(kobj)); | |
784aae73 | 149 | } |