sysfs_class/
block.rs

1use crate::SysClass;
2use std::io::Result;
3use std::path::{Path, PathBuf};
4
5pub type SlaveIter = Box<dyn Iterator<Item = Result<PathBuf>>>;
6
7/// A block device in /sys/class/block
8#[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    /// Logical devices have their parent device(s) listed here.
54    ///
55    /// For example:
56    ///
57    /// - dm-4 has a slave of dm-0
58    /// - dm-0 has a slave of sda3
59    /// - sda3 does not have any slaves
60    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    // Base properties
75
76    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    // bdi
115
116    // device
117
118    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    // holders
131
132    // integrity
133
134    // power
135
136    // trace
137
138    // queue
139
140    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    // method!("queue/scheduler", queue_scheduler parse_file u64);
195    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    // queue/iosched
224
225    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}