Skip to content

Commit 48961b2

Browse files
committed
Refactor decryption to use a read lock during operation
1 parent e3d4954 commit 48961b2

File tree

8 files changed

+130
-75
lines changed

8 files changed

+130
-75
lines changed

src/dbus_api/pool/pool_3_9/methods.rs

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::{
1313
types::{DbusErrorEnum, EncryptionInfos, TData, OK_STRING},
1414
util::{engine_to_dbus_err_tuple, get_next_arg, tuple_to_option},
1515
},
16-
engine::{CreateAction, InputEncryptionInfo, KeyDescription},
16+
engine::{CreateAction, DeleteAction, InputEncryptionInfo, KeyDescription},
1717
stratis::StratisError,
1818
};
1919

@@ -90,7 +90,8 @@ pub fn encrypt_pool(m: &MethodInfo<'_, MTSync<TData>, TData>) -> MethodResult {
9090

9191
// Check if operation is idempotent and complete all operations before handling result
9292
let create_result = handle_action!(
93-
read_guard.encrypt_pool_idem_check()
93+
read_guard
94+
.encrypt_pool_idem_check()
9495
.and_then(|action| match action {
9596
CreateAction::Identity => Ok(action),
9697
CreateAction::Created(_) => {
@@ -117,9 +118,11 @@ pub fn encrypt_pool(m: &MethodInfo<'_, MTSync<TData>, TData>) -> MethodResult {
117118
);
118119

119120
let msg = match create_result {
120-
Ok(CreateAction::Identity) => {
121-
return_message.append3(default_return, DbusErrorEnum::OK as u16, OK_STRING.to_string())
122-
}
121+
Ok(CreateAction::Identity) => return_message.append3(
122+
default_return,
123+
DbusErrorEnum::OK as u16,
124+
OK_STRING.to_string(),
125+
),
123126
Ok(CreateAction::Created(_)) => {
124127
let guard = get_pool!(dbus_context.engine; pool_uuid; default_return; return_message);
125128
let encryption_info = match guard.encryption_info().clone() {
@@ -218,22 +221,40 @@ pub fn decrypt_pool(m: &MethodInfo<'_, MTSync<TData>, TData>) -> MethodResult {
218221
return_message
219222
);
220223

221-
let mut guard = get_mut_pool!(dbus_context.engine; pool_uuid; default_return; return_message);
222-
let (name, uuid, pool) = guard.as_mut_tuple();
224+
let guard = get_pool!(dbus_context.engine; pool_uuid; default_return; return_message);
223225

224-
let result = handle_action!(
225-
pool.decrypt_pool(&name, uuid),
226+
let result = match handle_action!(
227+
guard.decrypt_pool_idem_check(),
226228
dbus_context,
227229
pool_path.get_name()
228-
);
230+
) {
231+
Ok(DeleteAction::Identity) => Ok(DeleteAction::Identity),
232+
Ok(DeleteAction::Deleted(d)) => {
233+
match guard.do_decrypt_pool(pool_uuid).and_then(|_| {
234+
let mut guard = block_on(dbus_context.engine.upgrade_pool(guard));
235+
let (name, _, _) = guard.as_mut_tuple();
236+
guard.finish_decrypt_pool(pool_uuid, &name)
237+
}) {
238+
Ok(_) => Ok(DeleteAction::Deleted(d)),
239+
Err(e) => Err(e),
240+
}
241+
}
242+
Err(e) => Err(e),
243+
};
229244
let msg = match result {
230-
Ok(_) => {
245+
Ok(DeleteAction::Deleted(_)) => {
246+
let guard = get_pool!(dbus_context.engine; pool_uuid; default_return; return_message);
231247
dbus_context.push_pool_key_desc_change(pool_path.get_name(), None);
232248
dbus_context.push_pool_clevis_info_change(pool_path.get_name(), None);
233249
dbus_context.push_pool_encryption_status_change(pool_path.get_name(), false);
234-
dbus_context.push_pool_last_reencrypt_timestamp(object_path, pool.last_reencrypt());
250+
dbus_context.push_pool_last_reencrypt_timestamp(object_path, guard.last_reencrypt());
235251
return_message.append3(true, DbusErrorEnum::OK as u16, OK_STRING.to_string())
236252
}
253+
Ok(DeleteAction::Identity) => return_message.append3(
254+
default_return,
255+
DbusErrorEnum::OK as u16,
256+
OK_STRING.to_string(),
257+
),
237258
Err(err) => {
238259
let (rc, rs) = engine_to_dbus_err_tuple(&err);
239260
return_message.append3(default_return, rc, rs)

src/engine/engine.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -433,12 +433,14 @@ pub trait Pool: Debug + Send + Sync {
433433
/// Finish reencryption of an encrypted pool.
434434
fn finish_reencrypt_pool(&mut self, name: &Name) -> StratisResult<ReencryptedDevice>;
435435

436+
/// Check idempotence of a pool decrypt command.
437+
fn decrypt_pool_idem_check(&self) -> StratisResult<DeleteAction<EncryptedDevice>>;
438+
436439
/// Decrypt an encrypted pool.
437-
fn decrypt_pool(
438-
&mut self,
439-
name: &Name,
440-
pool_uuid: PoolUuid,
441-
) -> StratisResult<DeleteAction<EncryptedDevice>>;
440+
fn do_decrypt_pool(&self, pool_uuid: PoolUuid) -> StratisResult<()>;
441+
442+
/// Finish pool decryption operation.
443+
fn finish_decrypt_pool(&mut self, pool_uuid: PoolUuid, name: &Name) -> StratisResult<()>;
442444

443445
/// Return the metadata that would be written if metadata were written.
444446
fn current_metadata(&self, pool_name: &Name) -> StratisResult<String>;

src/engine/sim_engine/pool.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -975,20 +975,24 @@ impl Pool for SimPool {
975975
Ok(ReencryptedDevice)
976976
}
977977

978-
fn decrypt_pool(
979-
&mut self,
980-
_: &Name,
981-
_: PoolUuid,
982-
) -> StratisResult<DeleteAction<EncryptedDevice>> {
978+
fn decrypt_pool_idem_check(&self) -> StratisResult<DeleteAction<EncryptedDevice>> {
983979
if self.encryption_info.is_none() {
984980
Ok(DeleteAction::Identity)
985981
} else {
986-
self.encryption_info = None;
987-
self.last_reencrypt = None;
988982
Ok(DeleteAction::Deleted(EncryptedDevice))
989983
}
990984
}
991985

986+
fn do_decrypt_pool(&self, _: PoolUuid) -> StratisResult<()> {
987+
Ok(())
988+
}
989+
990+
fn finish_decrypt_pool(&mut self, _: PoolUuid, _: &Name) -> StratisResult<()> {
991+
self.encryption_info = None;
992+
self.last_reencrypt = None;
993+
Ok(())
994+
}
995+
992996
fn current_metadata(&self, pool_name: &Name) -> StratisResult<String> {
993997
serde_json::to_string(&self.record(pool_name)).map_err(|e| e.into())
994998
}

src/engine/strat_engine/backstore/backstore/v2.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,12 +1377,13 @@ impl Backstore {
13771377
Ok(())
13781378
}
13791379

1380-
pub fn decrypt(&mut self, pool_uuid: PoolUuid) -> StratisResult<()> {
1380+
pub fn do_decrypt(&self, pool_uuid: PoolUuid) -> StratisResult<()> {
13811381
let handle = self
13821382
.cap_device
13831383
.enc
1384-
.take()
1384+
.as_ref()
13851385
.ok_or_else(|| StratisError::Msg("Pool is not encrypted".to_string()))?
1386+
.as_ref()
13861387
.right()
13871388
.ok_or_else(|| {
13881389
StratisError::Msg("No space has been allocated from the backstore".to_string())
@@ -1394,6 +1395,25 @@ impl Backstore {
13941395
Ok(())
13951396
}
13961397

1398+
pub fn finish_decrypt(
1399+
&mut self,
1400+
pool_uuid: PoolUuid,
1401+
thinpool: &mut ThinPool<Self>,
1402+
offset: Sectors,
1403+
direction: OffsetDirection,
1404+
) -> StratisResult<()> {
1405+
thinpool.suspend()?;
1406+
self.shift_alloc_offset(offset, direction);
1407+
let (dm_name, _) = format_backstore_ids(pool_uuid, CacheRole::Cache);
1408+
let set_device_res =
1409+
get_devno_from_path(&PathBuf::from(DEVICEMAPPER_PATH).join(dm_name.to_string()))
1410+
.and_then(|devno| thinpool.set_device(devno, offset, direction));
1411+
thinpool.resume()?;
1412+
set_device_res?;
1413+
self.cap_device.enc = None;
1414+
Ok(())
1415+
}
1416+
13971417
/// A summary of block sizes
13981418
pub fn block_size_summary(&self, tier: BlockDevTier) -> Option<BlockSizeSummary> {
13991419
match tier {

src/engine/strat_engine/crypt/handle/v2.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -885,11 +885,12 @@ impl CryptHandle {
885885
}
886886

887887
/// Decrypt the crypt device for an encrypted pool.
888-
pub fn decrypt(self, pool_uuid: PoolUuid) -> StratisResult<()> {
888+
pub fn decrypt(&self, pool_uuid: PoolUuid) -> StratisResult<()> {
889889
let activation_name = format_crypt_backstore_name(&pool_uuid);
890890
let mut device = acquire_crypt_device(self.luks2_device_path())?;
891891
let (keyslot, key) = get_passphrase(&mut device, self.encryption_info())?
892892
.either(|(keyslot, _, key)| (keyslot, key), |tup| tup);
893+
893894
device.reencrypt_handle().reencrypt_init_by_passphrase(
894895
Some(&activation_name.to_string()),
895896
key.as_ref(),

src/engine/strat_engine/pool/dispatch.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -409,14 +409,24 @@ impl Pool for AnyPool {
409409
}
410410
}
411411

412-
fn decrypt_pool(
413-
&mut self,
414-
name: &Name,
415-
pool_uuid: PoolUuid,
416-
) -> StratisResult<DeleteAction<EncryptedDevice>> {
412+
fn decrypt_pool_idem_check(&self) -> StratisResult<DeleteAction<EncryptedDevice>> {
413+
match self {
414+
AnyPool::V1(p) => p.decrypt_pool_idem_check(),
415+
AnyPool::V2(p) => p.decrypt_pool_idem_check(),
416+
}
417+
}
418+
419+
fn do_decrypt_pool(&self, pool_uuid: PoolUuid) -> StratisResult<()> {
420+
match self {
421+
AnyPool::V1(p) => p.do_decrypt_pool(pool_uuid),
422+
AnyPool::V2(p) => p.do_decrypt_pool(pool_uuid),
423+
}
424+
}
425+
426+
fn finish_decrypt_pool(&mut self, pool_uuid: PoolUuid, name: &Name) -> StratisResult<()> {
417427
match self {
418-
AnyPool::V1(p) => p.decrypt_pool(name, pool_uuid),
419-
AnyPool::V2(p) => p.decrypt_pool(name, pool_uuid),
428+
AnyPool::V1(p) => p.finish_decrypt_pool(pool_uuid, name),
429+
AnyPool::V2(p) => p.finish_decrypt_pool(pool_uuid, name),
420430
}
421431
}
422432

src/engine/strat_engine/pool/v1.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,11 +1389,19 @@ impl Pool for StratPool {
13891389
Ok(ReencryptedDevice)
13901390
}
13911391

1392-
fn decrypt_pool(
1393-
&mut self,
1394-
_: &Name,
1395-
_: PoolUuid,
1396-
) -> StratisResult<DeleteAction<EncryptedDevice>> {
1392+
fn decrypt_pool_idem_check(&self) -> StratisResult<DeleteAction<EncryptedDevice>> {
1393+
Err(StratisError::Msg(
1394+
"Decrypting an encrypted device is only supported in V2 of the metadata".to_string(),
1395+
))
1396+
}
1397+
1398+
fn do_decrypt_pool(&self, _: PoolUuid) -> StratisResult<()> {
1399+
Err(StratisError::Msg(
1400+
"Decrypting an encrypted device is only supported in V2 of the metadata".to_string(),
1401+
))
1402+
}
1403+
1404+
fn finish_decrypt_pool(&mut self, _: PoolUuid, _: &Name) -> StratisResult<()> {
13971405
Err(StratisError::Msg(
13981406
"Decrypting an encrypted device is only supported in V2 of the metadata".to_string(),
13991407
))

src/engine/strat_engine/pool/v2.rs

Lines changed: 25 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,41 +1270,29 @@ impl Pool for StratPool {
12701270
}
12711271

12721272
#[pool_mutating_action("NoRequests")]
1273-
fn decrypt_pool(
1274-
&mut self,
1275-
name: &Name,
1276-
pool_uuid: PoolUuid,
1277-
) -> StratisResult<DeleteAction<EncryptedDevice>> {
1278-
let offset = DEFAULT_CRYPT_DATA_OFFSET_V2;
1279-
let direction = OffsetDirection::Forwards;
1273+
fn decrypt_pool_idem_check(&self) -> StratisResult<DeleteAction<EncryptedDevice>> {
12801274
match self.backstore.encryption_info() {
12811275
None => Ok(DeleteAction::Identity),
1282-
Some(_) => {
1283-
match self.backstore.decrypt(pool_uuid) {
1284-
Ok(_) => {
1285-
self.last_reencrypt = None;
1286-
}
1287-
Err(e) => return Err(e),
1288-
}
1289-
self.thin_pool.suspend()?;
1290-
self.backstore.shift_alloc_offset(offset, direction);
1291-
let set_device_res = self.thin_pool.set_device(
1292-
self.backstore.device().expect(
1293-
"Since thin pool exists, space must have been allocated \
1294-
from the backstore, so backstore must have a cap device",
1295-
),
1296-
offset,
1297-
direction,
1298-
);
1299-
self.thin_pool.resume()?;
1300-
let metadata_res = self.write_metadata(name);
1301-
let _ = set_device_res?;
1302-
metadata_res?;
1303-
Ok(DeleteAction::Deleted(EncryptedDevice))
1304-
}
1276+
Some(_) => Ok(DeleteAction::Deleted(EncryptedDevice)),
13051277
}
13061278
}
13071279

1280+
#[pool_mutating_action("NoRequests")]
1281+
fn do_decrypt_pool(&self, pool_uuid: PoolUuid) -> StratisResult<()> {
1282+
self.backstore.do_decrypt(pool_uuid)
1283+
}
1284+
1285+
#[pool_mutating_action("NoRequests")]
1286+
fn finish_decrypt_pool(&mut self, pool_uuid: PoolUuid, name: &Name) -> StratisResult<()> {
1287+
let offset = DEFAULT_CRYPT_DATA_OFFSET_V2;
1288+
let direction = OffsetDirection::Forwards;
1289+
self.backstore
1290+
.finish_decrypt(pool_uuid, &mut self.thin_pool, offset, direction)?;
1291+
self.last_reencrypt = None;
1292+
self.write_metadata(name)?;
1293+
Ok(())
1294+
}
1295+
13081296
fn current_metadata(&self, pool_name: &Name) -> StratisResult<String> {
13091297
serde_json::to_string(&self.record(pool_name)).map_err(|e| e.into())
13101298
}
@@ -2368,12 +2356,13 @@ mod tests {
23682356
.unwrap();
23692357

23702358
{
2371-
let mut handle =
2372-
test_async!(engine.get_mut_pool(PoolIdentifier::Uuid(pool_uuid))).unwrap();
2373-
let (name, _, pool) = handle.as_mut_tuple();
2374-
assert!(pool.is_encrypted());
2375-
pool.decrypt_pool(&name, pool_uuid).unwrap();
2376-
assert!(!pool.is_encrypted());
2359+
let handle = test_async!(engine.get_pool(PoolIdentifier::Uuid(pool_uuid))).unwrap();
2360+
assert!(handle.is_encrypted());
2361+
handle.do_decrypt_pool(pool_uuid).unwrap();
2362+
let (name, _, _) = handle.as_tuple();
2363+
let mut handle = test_async!(engine.upgrade_pool(handle.into_dyn()));
2364+
handle.finish_decrypt_pool(pool_uuid, &name).unwrap();
2365+
assert!(!handle.is_encrypted());
23772366
}
23782367

23792368
test_async!(engine.stop_pool(PoolIdentifier::Uuid(pool_uuid), true)).unwrap();

0 commit comments

Comments
 (0)