Skip to content

Commit b718402

Browse files
committed
Refactor decryption to use a read lock during operation
1 parent d660aa9 commit b718402

File tree

8 files changed

+120
-52
lines changed

8 files changed

+120
-52
lines changed

src/dbus/pool/pool_3_9/methods.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,12 +201,25 @@ pub async fn decrypt_pool_method(
201201
.get_mut_pool(PoolIdentifier::Uuid(pool_uuid))
202202
.await
203203
.ok_or_else(|| StratisError::Msg(format!("No pool associated with uuid {pool_uuid}")));
204+
let cloned_engine = Arc::clone(engine);
204205
match tokio::task::spawn_blocking(move || {
205206
let mut guard = guard_res?;
206207

207-
let (name, _, pool) = guard.as_mut_tuple();
208-
209-
handle_action!(pool.decrypt_pool(&name, pool_uuid))
208+
handle_action!(match guard.decrypt_pool_idem_check(pool_uuid) {
209+
Ok(DeleteAction::Identity) => Ok(DeleteAction::Identity),
210+
Ok(DeleteAction::Deleted(d)) => {
211+
let guard = guard.downgrade();
212+
guard
213+
.do_decrypt_pool(pool_uuid)
214+
.and_then(|_| {
215+
let mut guard = block_on(cloned_engine.upgrade_pool(guard));
216+
let (name, _, _) = guard.as_mut_tuple();
217+
guard.finish_decrypt_pool(pool_uuid, &name)
218+
})
219+
.map(|_| DeleteAction::Deleted(d))
220+
}
221+
Err(e) => Err(e),
222+
})
210223
})
211224
.await
212225
{

src/engine/engine.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -441,13 +441,21 @@ pub trait Pool: Debug + Send + Sync {
441441
pool_uuid: PoolUuid,
442442
) -> StratisResult<ReencryptedDevice>;
443443

444-
/// Decrypt an encrypted pool.
445-
fn decrypt_pool(
444+
/// Check idempotence of a pool decrypt command.
445+
///
446+
/// This method does not require interior mutability, but a write lock is required
447+
/// to ensure that no other decryption operations have already started.
448+
fn decrypt_pool_idem_check(
446449
&mut self,
447-
name: &Name,
448450
pool_uuid: PoolUuid,
449451
) -> StratisResult<DeleteAction<EncryptedDevice>>;
450452

453+
/// Decrypt an encrypted pool.
454+
fn do_decrypt_pool(&self, pool_uuid: PoolUuid) -> StratisResult<()>;
455+
456+
/// Finish pool decryption operation.
457+
fn finish_decrypt_pool(&mut self, pool_uuid: PoolUuid, name: &Name) -> StratisResult<()>;
458+
451459
/// Return the metadata that would be written if metadata were written.
452460
fn current_metadata(&self, pool_name: &Name) -> StratisResult<String>;
453461

src/engine/sim_engine/pool.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,20 +1018,27 @@ impl Pool for SimPool {
10181018
Ok(ReencryptedDevice(pool_uuid))
10191019
}
10201020

1021-
fn decrypt_pool(
1021+
fn decrypt_pool_idem_check(
10221022
&mut self,
1023-
_: &Name,
10241023
pool_uuid: PoolUuid,
10251024
) -> StratisResult<DeleteAction<EncryptedDevice>> {
10261025
if self.encryption_info.is_none() {
10271026
Ok(DeleteAction::Identity)
10281027
} else {
1029-
self.encryption_info = None;
1030-
self.last_reencrypt = None;
10311028
Ok(DeleteAction::Deleted(EncryptedDevice(pool_uuid)))
10321029
}
10331030
}
10341031

1032+
fn do_decrypt_pool(&self, _: PoolUuid) -> StratisResult<()> {
1033+
Ok(())
1034+
}
1035+
1036+
fn finish_decrypt_pool(&mut self, _: PoolUuid, _: &Name) -> StratisResult<()> {
1037+
self.encryption_info = None;
1038+
self.last_reencrypt = None;
1039+
Ok(())
1040+
}
1041+
10351042
fn current_metadata(&self, pool_name: &Name) -> StratisResult<String> {
10361043
serde_json::to_string(&self.record(pool_name)).map_err(|e| e.into())
10371044
}

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

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,12 +1381,13 @@ impl Backstore {
13811381
Ok(())
13821382
}
13831383

1384-
pub fn decrypt(&mut self, pool_uuid: PoolUuid) -> StratisResult<()> {
1384+
pub fn do_decrypt(&self, pool_uuid: PoolUuid) -> StratisResult<()> {
13851385
let handle = self
13861386
.cap_device
13871387
.enc
1388-
.take()
1388+
.as_ref()
13891389
.ok_or_else(|| StratisError::Msg("Pool is not encrypted".to_string()))?
1390+
.as_ref()
13901391
.right()
13911392
.ok_or_else(|| {
13921393
StratisError::Msg("No space has been allocated from the backstore".to_string())
@@ -1398,6 +1399,25 @@ impl Backstore {
13981399
Ok(())
13991400
}
14001401

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

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -893,11 +893,12 @@ impl CryptHandle {
893893
}
894894

895895
/// Decrypt the crypt device for an encrypted pool.
896-
pub fn decrypt(self, pool_uuid: PoolUuid) -> StratisResult<()> {
896+
pub fn decrypt(&self, pool_uuid: PoolUuid) -> StratisResult<()> {
897897
let activation_name = format_crypt_backstore_name(&pool_uuid);
898898
let mut device = acquire_crypt_device(self.luks2_device_path())?;
899899
let (keyslot, key) = get_passphrase(&mut device, self.encryption_info())?
900900
.either(|(keyslot, _, key)| (keyslot, key), |tup| tup);
901+
901902
device.reencrypt_handle().reencrypt_init_by_passphrase(
902903
Some(&activation_name.to_string()),
903904
key.as_ref(),

src/engine/strat_engine/pool/dispatch.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -410,14 +410,27 @@ impl Pool for AnyPool {
410410
}
411411
}
412412

413-
fn decrypt_pool(
413+
fn decrypt_pool_idem_check(
414414
&mut self,
415-
name: &Name,
416415
pool_uuid: PoolUuid,
417416
) -> StratisResult<DeleteAction<EncryptedDevice>> {
418417
match self {
419-
AnyPool::V1(p) => p.decrypt_pool(name, pool_uuid),
420-
AnyPool::V2(p) => p.decrypt_pool(name, pool_uuid),
418+
AnyPool::V1(p) => p.decrypt_pool_idem_check(pool_uuid),
419+
AnyPool::V2(p) => p.decrypt_pool_idem_check(pool_uuid),
420+
}
421+
}
422+
423+
fn do_decrypt_pool(&self, pool_uuid: PoolUuid) -> StratisResult<()> {
424+
match self {
425+
AnyPool::V1(p) => p.do_decrypt_pool(pool_uuid),
426+
AnyPool::V2(p) => p.do_decrypt_pool(pool_uuid),
427+
}
428+
}
429+
430+
fn finish_decrypt_pool(&mut self, pool_uuid: PoolUuid, name: &Name) -> StratisResult<()> {
431+
match self {
432+
AnyPool::V1(p) => p.finish_decrypt_pool(pool_uuid, name),
433+
AnyPool::V2(p) => p.finish_decrypt_pool(pool_uuid, name),
421434
}
422435
}
423436

src/engine/strat_engine/pool/v1.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,16 +1390,30 @@ impl Pool for StratPool {
13901390
Ok(ReencryptedDevice(pool_uuid))
13911391
}
13921392

1393-
fn decrypt_pool(
1393+
#[pool_mutating_action("NoRequests")]
1394+
fn decrypt_pool_idem_check(
13941395
&mut self,
1395-
_: &Name,
13961396
_: PoolUuid,
13971397
) -> StratisResult<DeleteAction<EncryptedDevice>> {
13981398
Err(StratisError::Msg(
13991399
"Decrypting an encrypted device is only supported in V2 of the metadata".to_string(),
14001400
))
14011401
}
14021402

1403+
#[pool_mutating_action("NoRequests")]
1404+
fn do_decrypt_pool(&self, _: PoolUuid) -> StratisResult<()> {
1405+
Err(StratisError::Msg(
1406+
"Decrypting an encrypted device is only supported in V2 of the metadata".to_string(),
1407+
))
1408+
}
1409+
1410+
#[pool_mutating_action("NoRequests")]
1411+
fn finish_decrypt_pool(&mut self, _: PoolUuid, _: &Name) -> StratisResult<()> {
1412+
Err(StratisError::Msg(
1413+
"Decrypting an encrypted device is only supported in V2 of the metadata".to_string(),
1414+
))
1415+
}
1416+
14031417
fn current_metadata(&self, pool_name: &Name) -> StratisResult<String> {
14041418
serde_json::to_string(&self.record(pool_name)).map_err(|e| e.into())
14051419
}

src/engine/strat_engine/pool/v2.rs

Lines changed: 25 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,41 +1277,32 @@ impl Pool for StratPool {
12771277
}
12781278

12791279
#[pool_mutating_action("NoRequests")]
1280-
fn decrypt_pool(
1280+
fn decrypt_pool_idem_check(
12811281
&mut self,
1282-
name: &Name,
12831282
pool_uuid: PoolUuid,
12841283
) -> StratisResult<DeleteAction<EncryptedDevice>> {
1285-
let offset = DEFAULT_CRYPT_DATA_OFFSET_V2;
1286-
let direction = OffsetDirection::Forwards;
12871284
match self.backstore.encryption_info() {
12881285
None => Ok(DeleteAction::Identity),
1289-
Some(_) => {
1290-
match self.backstore.decrypt(pool_uuid) {
1291-
Ok(_) => {
1292-
self.last_reencrypt = None;
1293-
}
1294-
Err(e) => return Err(e),
1295-
}
1296-
self.thin_pool.suspend()?;
1297-
let set_device_res = self.thin_pool.set_device(
1298-
self.backstore.device().expect(
1299-
"Since thin pool exists, space must have been allocated \
1300-
from the backstore, so backstore must have a cap device",
1301-
),
1302-
offset,
1303-
direction,
1304-
);
1305-
self.thin_pool.resume()?;
1306-
self.backstore.shift_alloc_offset(offset, direction);
1307-
let metadata_res = self.write_metadata(name);
1308-
let _ = set_device_res?;
1309-
metadata_res?;
1310-
Ok(DeleteAction::Deleted(EncryptedDevice(pool_uuid)))
1311-
}
1286+
Some(_) => Ok(DeleteAction::Deleted(EncryptedDevice(pool_uuid))),
13121287
}
13131288
}
13141289

1290+
#[pool_mutating_action("NoRequests")]
1291+
fn do_decrypt_pool(&self, pool_uuid: PoolUuid) -> StratisResult<()> {
1292+
self.backstore.do_decrypt(pool_uuid)
1293+
}
1294+
1295+
#[pool_mutating_action("NoRequests")]
1296+
fn finish_decrypt_pool(&mut self, pool_uuid: PoolUuid, name: &Name) -> StratisResult<()> {
1297+
let offset = DEFAULT_CRYPT_DATA_OFFSET_V2;
1298+
let direction = OffsetDirection::Forwards;
1299+
self.backstore
1300+
.finish_decrypt(pool_uuid, &mut self.thin_pool, offset, direction)?;
1301+
self.last_reencrypt = None;
1302+
self.write_metadata(name)?;
1303+
Ok(())
1304+
}
1305+
13151306
fn current_metadata(&self, pool_name: &Name) -> StratisResult<String> {
13161307
serde_json::to_string(&self.record(pool_name)).map_err(|e| e.into())
13171308
}
@@ -2382,12 +2373,13 @@ mod tests {
23822373
.unwrap();
23832374

23842375
{
2385-
let mut handle =
2386-
test_async!(engine.get_mut_pool(PoolIdentifier::Uuid(pool_uuid))).unwrap();
2387-
let (name, _, pool) = handle.as_mut_tuple();
2388-
assert!(pool.is_encrypted());
2389-
pool.decrypt_pool(&name, pool_uuid).unwrap();
2390-
assert!(!pool.is_encrypted());
2376+
let handle = test_async!(engine.get_pool(PoolIdentifier::Uuid(pool_uuid))).unwrap();
2377+
assert!(handle.is_encrypted());
2378+
handle.do_decrypt_pool(pool_uuid).unwrap();
2379+
let (name, _, _) = handle.as_tuple();
2380+
let mut handle = test_async!(engine.upgrade_pool(handle.into_dyn()));
2381+
handle.finish_decrypt_pool(pool_uuid, &name).unwrap();
2382+
assert!(!handle.is_encrypted());
23912383
}
23922384

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

0 commit comments

Comments
 (0)