1use crate::SysClass;
2use std::io::Result;
3use std::path::{Path, PathBuf};
4
5pub type SlaveIter = Box<dyn Iterator<Item = Result<PathBuf>>>;
6
7#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
9pub struct Block {
10 path: PathBuf,
11}
12
13impl SysClass for Block {
14 fn class() -> &'static str {
15 "block"
16 }
17
18 unsafe fn from_path_unchecked(path: PathBuf) -> Self {
19 Self { path }
20 }
21
22 fn path(&self) -> &Path {
23 &self.path
24 }
25}
26
27impl Block {
28 pub fn has_device(&self) -> bool {
29 self.path.join("device").exists()
30 }
31
32 pub fn children(&self) -> Result<Vec<Self>> {
33 let mut children = Block::all()?
34 .into_iter()
35 .filter(|x| {
36 x.parent_device()
37 .map_or(false, |parent| parent.path() == self.path)
38 })
39 .collect::<Vec<_>>();
40 children.sort_unstable();
41 Ok(children)
42 }
43
44 pub fn parent_device(&self) -> Option<Block> {
45 self.partition().ok().and_then(|partition| {
46 let path = self.path().to_str()?;
47 let pos = path.len() - partition as usize / 10 - 1;
48 let path = Path::new(path.split_at(pos).0).to_path_buf();
49 Some(unsafe { Block::from_path_unchecked(path) })
50 })
51 }
52
53 pub fn slaves(&self) -> Option<Result<SlaveIter>> {
61 let slaves_path = self.path.join("slaves");
62 if slaves_path.exists() {
63 let res: Result<SlaveIter> = match slaves_path.read_dir() {
64 Ok(iter) => Ok(Box::new(iter.map(|entry| Ok(entry?.path())))),
65 Err(why) => Err(why),
66 };
67
68 Some(res)
69 } else {
70 None
71 }
72 }
73
74 method!(alignment_offset parse_file u64);
77
78 method!(capability parse_file u8);
79
80 method!(dev read_file String);
81
82 method!(discard_alignment parse_file u64);
83
84 method!(events parse_file u64);
85
86 method!(events_async parse_file u64);
87
88 method!(events_poll_msecs parse_file u64);
89
90 method!(ext_range parse_file u64);
91
92 method!(hidden parse_file u8);
93
94 method!(inflight read_file String);
95
96 method!(partition parse_file u8);
97
98 method!(range parse_file u64);
99
100 method!(removable parse_file u8);
101
102 method!(ro parse_file u8);
103
104 method!(size parse_file u64);
105
106 method!(start parse_file u64);
107
108 method!(stat parse_file u8);
109
110 method!(subsystem parse_file u8);
111
112 method!(uevent read_file String);
113
114 method!("device/device_blocked", device_blocked parse_file u8);
119
120 method!("device/device_busy", device_busy parse_file u8);
121
122 method!("device/model", device_model read_file String);
123
124 method!("device/rev", device_rev read_file String);
125
126 method!("device/state", device_state read_file String);
127
128 method!("device/vendor", device_vendor read_file String);
129
130 method!("queue/add_random", queue_add_random parse_file u64);
141
142 method!("queue/chunk_sectors", queue_chunk_sectors parse_file u64);
143
144 method!("queue/dax", queue_dax parse_file u64);
145
146 method!("queue/discard_granularity", queue_discard_granularity parse_file u64);
147
148 method!("queue/discard_max_bytes", queue_discard_max_bytes parse_file u64);
149
150 method!("queue/discard_max_hw_bytes", queue_discard_max_hw_bytes parse_file u64);
151
152 method!("queue/discard_zeroes_data", queue_discard_zeroes_data parse_file u64);
153
154 method!("queue/fua", queue_fua parse_file u64);
155
156 method!("queue/hw_sector_size", queue_hw_sector_size parse_file u64);
157
158 method!("queue/io_poll", queue_io_poll parse_file u64);
159
160 method!("queue/io_poll_delay", queue_io_poll_delay parse_file u64);
161
162 method!("queue/iostats", queue_iostats parse_file u64);
163
164 method!("queue/logical_block_size", queue_logical_block_size parse_file u64);
165
166 method!("queue/max_discard_segments", queue_max_discard_segments parse_file u64);
167
168 method!("queue/max_hw_sectors_kb", queue_max_hw_sectors_kb parse_file u64);
169
170 method!("queue/max_integrity_segments", queue_max_integrity_segments parse_file u64);
171
172 method!("queue/max_sectors_kb", queue_max_sectors_kb parse_file u64);
173
174 method!("queue/max_segment_size", queue_max_segment_size parse_file u64);
175
176 method!("queue/max_segments", queue_max_segments parse_file u64);
177
178 method!("queue/minimum_io_size", queue_minimum_io_size parse_file u64);
179
180 method!("queue/nomerges", queue_nomerges parse_file u64);
181
182 method!("queue/nr_requests", queue_nr_requests parse_file u64);
183
184 method!("queue/optimal_io_size", queue_optimal_io_size parse_file u64);
185
186 method!("queue/physical_block_size", queue_physical_block_size parse_file u64);
187
188 method!("queue/read_ahead_kb", queue_read_ahead_kb parse_file u64);
189
190 method!("queue/rotational", queue_rotational parse_file u8);
191
192 method!("queue/rq_affinity", queue_rq_affinity parse_file u64);
193
194 pub fn queue_scheduler(&self) -> Result<BlockScheduler> {
196 let mut active = 0;
197 let mut schedules = Vec::new();
198 for schedule in self.read_file("queue/scheduler")?.split_whitespace() {
199 let schedule = if schedule.starts_with('[') {
200 active = schedules.len();
201 &schedule[1..schedule.len() - 1]
202 } else {
203 schedule
204 };
205
206 schedules.push(schedule.to_owned());
207 }
208
209 Ok(BlockScheduler {
210 active: active as u8,
211 schedules,
212 })
213 }
214
215 method!("queue/write_cache", queue_write_cache read_file String);
216
217 method!("queue/write_same_max_bytes", queue_write_same_max_bytes parse_file u64);
218
219 method!("queue/write_zeroes_max_bytes", queue_write_zeroes_max_bytes parse_file u64);
220
221 method!("queue/zoned", queue_zoned read_file String);
222
223 method!("queue/iosched/back_seek_max", queue_iosched_back_seek_max parse_file u64);
226
227 method!("queue/iosched/back_seek_penalty", queue_iosched_back_seek_penalty parse_file u64);
228
229 method!("queue/iosched/fifo_expire_async", queue_iosched_fifo_expire_async parse_file u64);
230
231 method!("queue/iosched/fifo_expire_sync", queue_iosched_fifo_expire_sync parse_file u64);
232
233 method!("queue/iosched/group_idle", queue_iosched_group_idle parse_file u64);
234
235 method!("queue/iosched/group_idle_us", queue_iosched_group_idle_us parse_file u64);
236
237 method!("queue/iosched/low_latency", queue_iosched_low_latency parse_file u8);
238
239 method!("queue/iosched/quantum", queue_iosched_quantum parse_file u64);
240
241 method!("queue/iosched/slice_async", queue_iosched_slice_async parse_file u64);
242
243 method!("queue/iosched/slice_async_rq", queue_iosched_slice_async_rq parse_file u64);
244
245 method!("queue/iosched/slice_async_us", queue_iosched_slice_async_us parse_file u64);
246
247 method!("queue/iosched/slice_idle", queue_iosched_slice_idle parse_file u8);
248
249 method!("queue/iosched/slice_idle_us", queue_iosched_slice_idle_us parse_file u64);
250
251 method!("queue/iosched/slice_sync", queue_iosched_slice_sync parse_file u64);
252
253 method!("queue/iosched/slice_sync_us", queue_iosched_slice_sync_us parse_file u64);
254
255 method!("queue/iosched/target_latency", queue_iosched_target_latency parse_file u64);
256
257 method!("queue/iosched/target_latency_us", queue_iosched_target_latency_us parse_file u64);
258}
259
260pub struct BlockScheduler {
261 schedules: Vec<String>,
262 active: u8,
263}
264
265impl BlockScheduler {
266 pub fn active(&self) -> &str {
267 &self.schedules[self.active as usize]
268 }
269
270 pub fn schedulers(&self) -> &[String] {
271 &self.schedules
272 }
273}