Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/block/rnull/configfs.rs
54339 views
1
// SPDX-License-Identifier: GPL-2.0
2
3
use super::{NullBlkDevice, THIS_MODULE};
4
use kernel::{
5
block::mq::gen_disk::{GenDisk, GenDiskBuilder},
6
configfs::{self, AttributeOperations},
7
configfs_attrs,
8
fmt::{self, Write as _},
9
new_mutex,
10
page::PAGE_SIZE,
11
prelude::*,
12
str::{kstrtobool_bytes, CString},
13
sync::Mutex,
14
};
15
16
pub(crate) fn subsystem() -> impl PinInit<kernel::configfs::Subsystem<Config>, Error> {
17
let item_type = configfs_attrs! {
18
container: configfs::Subsystem<Config>,
19
data: Config,
20
child: DeviceConfig,
21
attributes: [
22
features: 0,
23
],
24
};
25
26
kernel::configfs::Subsystem::new(c"rnull", item_type, try_pin_init!(Config {}))
27
}
28
29
#[pin_data]
30
pub(crate) struct Config {}
31
32
#[vtable]
33
impl AttributeOperations<0> for Config {
34
type Data = Config;
35
36
fn show(_this: &Config, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
37
let mut writer = kernel::str::Formatter::new(page);
38
writer.write_str("blocksize,size,rotational,irqmode\n")?;
39
Ok(writer.bytes_written())
40
}
41
}
42
43
#[vtable]
44
impl configfs::GroupOperations for Config {
45
type Child = DeviceConfig;
46
47
fn make_group(
48
&self,
49
name: &CStr,
50
) -> Result<impl PinInit<configfs::Group<DeviceConfig>, Error>> {
51
let item_type = configfs_attrs! {
52
container: configfs::Group<DeviceConfig>,
53
data: DeviceConfig,
54
attributes: [
55
// Named for compatibility with C null_blk
56
power: 0,
57
blocksize: 1,
58
rotational: 2,
59
size: 3,
60
irqmode: 4,
61
],
62
};
63
64
Ok(configfs::Group::new(
65
name.try_into()?,
66
item_type,
67
// TODO: cannot coerce new_mutex!() to impl PinInit<_, Error>, so put mutex inside
68
try_pin_init!( DeviceConfig {
69
data <- new_mutex!(DeviceConfigInner {
70
powered: false,
71
block_size: 4096,
72
rotational: false,
73
disk: None,
74
capacity_mib: 4096,
75
irq_mode: IRQMode::None,
76
name: name.try_into()?,
77
}),
78
}),
79
))
80
}
81
}
82
83
#[derive(Debug, Clone, Copy)]
84
pub(crate) enum IRQMode {
85
None,
86
Soft,
87
}
88
89
impl TryFrom<u8> for IRQMode {
90
type Error = kernel::error::Error;
91
92
fn try_from(value: u8) -> Result<Self> {
93
match value {
94
0 => Ok(Self::None),
95
1 => Ok(Self::Soft),
96
_ => Err(EINVAL),
97
}
98
}
99
}
100
101
impl fmt::Display for IRQMode {
102
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103
match self {
104
Self::None => f.write_str("0")?,
105
Self::Soft => f.write_str("1")?,
106
}
107
Ok(())
108
}
109
}
110
111
#[pin_data]
112
pub(crate) struct DeviceConfig {
113
#[pin]
114
data: Mutex<DeviceConfigInner>,
115
}
116
117
#[pin_data]
118
struct DeviceConfigInner {
119
powered: bool,
120
name: CString,
121
block_size: u32,
122
rotational: bool,
123
capacity_mib: u64,
124
irq_mode: IRQMode,
125
disk: Option<GenDisk<NullBlkDevice>>,
126
}
127
128
#[vtable]
129
impl configfs::AttributeOperations<0> for DeviceConfig {
130
type Data = DeviceConfig;
131
132
fn show(this: &DeviceConfig, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
133
let mut writer = kernel::str::Formatter::new(page);
134
135
if this.data.lock().powered {
136
writer.write_str("1\n")?;
137
} else {
138
writer.write_str("0\n")?;
139
}
140
141
Ok(writer.bytes_written())
142
}
143
144
fn store(this: &DeviceConfig, page: &[u8]) -> Result {
145
let power_op = kstrtobool_bytes(page)?;
146
let mut guard = this.data.lock();
147
148
if !guard.powered && power_op {
149
guard.disk = Some(NullBlkDevice::new(
150
&guard.name,
151
guard.block_size,
152
guard.rotational,
153
guard.capacity_mib,
154
guard.irq_mode,
155
)?);
156
guard.powered = true;
157
} else if guard.powered && !power_op {
158
drop(guard.disk.take());
159
guard.powered = false;
160
}
161
162
Ok(())
163
}
164
}
165
166
#[vtable]
167
impl configfs::AttributeOperations<1> for DeviceConfig {
168
type Data = DeviceConfig;
169
170
fn show(this: &DeviceConfig, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
171
let mut writer = kernel::str::Formatter::new(page);
172
writer.write_fmt(fmt!("{}\n", this.data.lock().block_size))?;
173
Ok(writer.bytes_written())
174
}
175
176
fn store(this: &DeviceConfig, page: &[u8]) -> Result {
177
if this.data.lock().powered {
178
return Err(EBUSY);
179
}
180
181
let text = core::str::from_utf8(page)?.trim();
182
let value = text.parse::<u32>().map_err(|_| EINVAL)?;
183
184
GenDiskBuilder::validate_block_size(value)?;
185
this.data.lock().block_size = value;
186
Ok(())
187
}
188
}
189
190
#[vtable]
191
impl configfs::AttributeOperations<2> for DeviceConfig {
192
type Data = DeviceConfig;
193
194
fn show(this: &DeviceConfig, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
195
let mut writer = kernel::str::Formatter::new(page);
196
197
if this.data.lock().rotational {
198
writer.write_str("1\n")?;
199
} else {
200
writer.write_str("0\n")?;
201
}
202
203
Ok(writer.bytes_written())
204
}
205
206
fn store(this: &DeviceConfig, page: &[u8]) -> Result {
207
if this.data.lock().powered {
208
return Err(EBUSY);
209
}
210
211
this.data.lock().rotational = kstrtobool_bytes(page)?;
212
213
Ok(())
214
}
215
}
216
217
#[vtable]
218
impl configfs::AttributeOperations<3> for DeviceConfig {
219
type Data = DeviceConfig;
220
221
fn show(this: &DeviceConfig, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
222
let mut writer = kernel::str::Formatter::new(page);
223
writer.write_fmt(fmt!("{}\n", this.data.lock().capacity_mib))?;
224
Ok(writer.bytes_written())
225
}
226
227
fn store(this: &DeviceConfig, page: &[u8]) -> Result {
228
if this.data.lock().powered {
229
return Err(EBUSY);
230
}
231
232
let text = core::str::from_utf8(page)?.trim();
233
let value = text.parse::<u64>().map_err(|_| EINVAL)?;
234
235
this.data.lock().capacity_mib = value;
236
Ok(())
237
}
238
}
239
240
#[vtable]
241
impl configfs::AttributeOperations<4> for DeviceConfig {
242
type Data = DeviceConfig;
243
244
fn show(this: &DeviceConfig, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
245
let mut writer = kernel::str::Formatter::new(page);
246
writer.write_fmt(fmt!("{}\n", this.data.lock().irq_mode))?;
247
Ok(writer.bytes_written())
248
}
249
250
fn store(this: &DeviceConfig, page: &[u8]) -> Result {
251
if this.data.lock().powered {
252
return Err(EBUSY);
253
}
254
255
let text = core::str::from_utf8(page)?.trim();
256
let value = text.parse::<u8>().map_err(|_| EINVAL)?;
257
258
this.data.lock().irq_mode = IRQMode::try_from(value)?;
259
Ok(())
260
}
261
}
262
263