1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
use std::fmt;
use std::path::PathBuf;
use consts::{DmFlags, DM_SUSPEND};
use deviceinfo::DeviceInfo;
use dm::{DM, DevId};
use result::{DmResult, DmError, InternalError};
use thinpooldev::ThinPoolDev;
use types::TargetLine;
use types::Sectors;
pub struct ThinDev {
dev_info: DeviceInfo,
thin_id: u32,
size: Sectors,
thinpool_dstr: String,
}
impl fmt::Debug for ThinDev {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}", self.name())
}
}
#[derive(Debug, Clone, Copy)]
pub enum ThinStatus {
Good((Sectors, Sectors)),
Fail,
}
impl ThinDev {
pub fn new(name: &str,
dm: &DM,
thin_pool: &ThinPoolDev,
thin_id: u32,
length: Sectors)
-> DmResult<ThinDev> {
try!(thin_pool.message(dm, &format!("create_thin {}", thin_id)));
try!(dm.device_create(name, None, DmFlags::empty()));
let id = &DevId::Name(name);
let thin_pool_dstr = thin_pool.dstr();
let di = try!(dm.table_load(&id, &ThinDev::dm_table(&thin_pool_dstr, thin_id, length)));
try!(dm.device_suspend(id, DmFlags::empty()));
DM::wait_for_dm();
Ok(ThinDev {
dev_info: di,
thin_id: thin_id,
size: length,
thinpool_dstr: thin_pool_dstr,
})
}
fn dm_table(thin_pool_dstr: &str, thin_id: u32, length: Sectors) -> Vec<TargetLine> {
let params = format!("{} {}", thin_pool_dstr, thin_id);
vec![(0u64, *length, "thin".to_owned(), params)]
}
pub fn name(&self) -> &str {
self.dev_info.name()
}
pub fn dstr(&self) -> String {
self.dev_info.device().dstr()
}
pub fn size(&self) -> Sectors {
self.size
}
pub fn id(&self) -> u32 {
self.thin_id
}
pub fn devnode(&self) -> DmResult<PathBuf> {
self.dev_info
.device()
.devnode()
.ok_or(DmError::Dm(InternalError("No path associated with dev_info".into())))
}
pub fn status(&self, dm: &DM) -> DmResult<ThinStatus> {
let (_, mut status) = try!(dm.table_status(&DevId::Name(&self.dev_info.name()),
DmFlags::empty()));
assert!(status.len() == 1,
"Kernel must return 1 line from thin status");
let status_line = status.pop().expect("assertion above holds").3;
if status_line.starts_with("Fail") {
return Ok(ThinStatus::Fail);
}
let status_vals = status_line.split(' ').collect::<Vec<_>>();
assert!(status_vals.len() >= 2,
"Kernel must return at least 2 values from thin pool status");
Ok(ThinStatus::Good((Sectors(status_vals[0]
.parse::<u64>()
.expect("mapped sector count value must be valid")),
Sectors(status_vals[1]
.parse::<u64>()
.expect("highest mapped sector value must be valid")))))
}
pub fn extend(&mut self, dm: &DM, sectors: Sectors) -> DmResult<()> {
self.size = self.size + sectors;
let id = &DevId::Name(&self.dev_info.name());
try!(dm.table_load(id,
&ThinDev::dm_table(&self.thinpool_dstr, self.thin_id, self.size)));
try!(dm.device_suspend(id, DM_SUSPEND));
try!(dm.device_suspend(id, DmFlags::empty()));
Ok(())
}
pub fn teardown(self, dm: &DM) -> DmResult<()> {
try!(dm.device_remove(&DevId::Name(self.name()), DmFlags::empty()));
Ok(())
}
}