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