Skip to content

Commit d660aa9

Browse files
committed
Refactor encryption to use a read lock during operation
1 parent de4e1d0 commit d660aa9

File tree

9 files changed

+171
-61
lines changed

9 files changed

+171
-61
lines changed

src/dbus/pool/pool_3_9/methods.rs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ use crate::{
2020
},
2121
},
2222
engine::{
23-
CreateAction, DeleteAction, Engine, InputEncryptionInfo, KeyDescription, Lockable,
24-
PoolIdentifier, PoolUuid,
23+
CreateAction, DeleteAction, EncryptedDevice, Engine, InputEncryptionInfo, KeyDescription,
24+
Lockable, PoolIdentifier, PoolUuid,
2525
},
2626
stratis::StratisError,
2727
};
@@ -86,12 +86,27 @@ pub async fn encrypt_pool_method(
8686
.get_mut_pool(PoolIdentifier::Uuid(pool_uuid))
8787
.await
8888
.ok_or_else(|| StratisError::Msg(format!("No pool associated with uuid {pool_uuid}")));
89+
let cloned_engine = Arc::clone(engine);
8990
match tokio::task::spawn_blocking(move || {
9091
let mut guard = guard_res?;
9192

92-
let (name, _, pool) = guard.as_mut_tuple();
93-
94-
handle_action!(pool.encrypt_pool(&name, pool_uuid, &iei))
93+
handle_action!(guard
94+
.start_encrypt_pool(pool_uuid, &iei)
95+
.and_then(|action| match action {
96+
CreateAction::Identity => Ok(CreateAction::Identity),
97+
CreateAction::Created((sector_size, key_info)) => {
98+
let guard = guard.downgrade();
99+
guard
100+
.do_encrypt_pool(pool_uuid, sector_size, key_info)
101+
.map(|_| guard)
102+
.and_then(|guard| {
103+
let mut guard = block_on(cloned_engine.upgrade_pool(guard));
104+
let (name, _, _) = guard.as_mut_tuple();
105+
guard.finish_encrypt_pool(&name, pool_uuid)
106+
})
107+
.map(|_| CreateAction::Created(EncryptedDevice(pool_uuid)))
108+
}
109+
}))
95110
})
96111
.await
97112
{

src/engine/engine.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -402,13 +402,23 @@ pub trait Pool: Debug + Send + Sync {
402402
limit: Option<Bytes>,
403403
) -> StratisResult<PropChangeAction<Option<Sectors>>>;
404404

405-
/// Encrypted an unencrypted pool.
406-
fn encrypt_pool(
405+
/// Setup pool encryption operation and check for idempotence.
406+
fn start_encrypt_pool(
407407
&mut self,
408-
name: &Name,
409408
pool_uuid: PoolUuid,
410409
encryption_info: &InputEncryptionInfo,
411-
) -> StratisResult<CreateAction<EncryptedDevice>>;
410+
) -> StratisResult<CreateAction<(u32, (u32, SizedKeyMemory))>>;
411+
412+
/// Encrypt an unencrypted pool.
413+
fn do_encrypt_pool(
414+
&self,
415+
pool_uuid: PoolUuid,
416+
sector_size: u32,
417+
key_info: (u32, SizedKeyMemory),
418+
) -> StratisResult<()>;
419+
420+
/// Update internal data structures with the result of the encryption operation.
421+
fn finish_encrypt_pool(&mut self, name: &Name, pool_uuid: PoolUuid) -> StratisResult<()>;
412422

413423
/// Start reencryption of an encrypted pool.
414424
///

src/engine/mod.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ pub use self::{
2020
},
2121
types::{
2222
ActionAvailability, BlockDevTier, ClevisInfo, CreateAction, DeleteAction, DevUuid, Diff,
23-
EncryptionInfo, EngineAction, Features, FilesystemUuid, GrowAction, InputEncryptionInfo,
24-
IntegritySpec, IntegrityTagSpec, KeyDescription, Lockable, LockedPoolInfo, LockedPoolsInfo,
25-
MappingCreateAction, MappingDeleteAction, MaybeInconsistent, Name, OptionalTokenSlotInput,
26-
PoolDiff, PoolEncryptionInfo, PoolIdentifier, PoolUuid, PropChangeAction, RenameAction,
27-
ReportType, SetCreateAction, SetDeleteAction, SetUnlockAction, StartAction, StopAction,
28-
StoppedPoolInfo, StoppedPoolsInfo, StratBlockDevDiff, StratFilesystemDiff, StratPoolDiff,
23+
EncryptedDevice, EncryptionInfo, EngineAction, Features, FilesystemUuid, GrowAction,
24+
InputEncryptionInfo, IntegritySpec, IntegrityTagSpec, KeyDescription, Lockable,
25+
LockedPoolInfo, LockedPoolsInfo, MappingCreateAction, MappingDeleteAction,
26+
MaybeInconsistent, Name, OptionalTokenSlotInput, PoolDiff, PoolEncryptionInfo,
27+
PoolIdentifier, PoolUuid, PropChangeAction, RenameAction, ReportType, SetCreateAction,
28+
SetDeleteAction, SetUnlockAction, StartAction, StopAction, StoppedPoolInfo,
29+
StoppedPoolsInfo, StratBlockDevDiff, StratFilesystemDiff, StratPoolDiff,
2930
StratSigblockVersion, StratisUuid, ThinPoolDiff, ToDisplay, TokenUnlockMethod,
3031
UdevEngineEvent, UnlockMethod, ValidatedIntegritySpec, DEFAULT_INTEGRITY_JOURNAL_SIZE,
3132
DEFAULT_INTEGRITY_TAG_SPEC,

src/engine/sim_engine/pool.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use itertools::Itertools;
1414
use serde_json::{Map, Value};
1515

1616
use devicemapper::{Bytes, Sectors, IEC};
17+
use libcryptsetup_rs::SafeMemHandle;
1718

1819
use crate::{
1920
engine::{
@@ -966,20 +967,30 @@ impl Pool for SimPool {
966967
}
967968
}
968969

969-
fn encrypt_pool(
970+
fn start_encrypt_pool(
970971
&mut self,
971-
_: &Name,
972-
pool_uuid: PoolUuid,
972+
_: PoolUuid,
973973
enc: &InputEncryptionInfo,
974-
) -> StratisResult<CreateAction<EncryptedDevice>> {
974+
) -> StratisResult<CreateAction<(u32, (u32, SizedKeyMemory))>> {
975975
if self.encryption_info.is_some() {
976976
Ok(CreateAction::Identity)
977977
} else {
978978
self.encryption_info = convert_encryption_info(Some(enc), None)?;
979-
Ok(CreateAction::Created(EncryptedDevice(pool_uuid)))
979+
Ok(CreateAction::Created((
980+
0,
981+
(0, SizedKeyMemory::new(SafeMemHandle::alloc(1)?, 0)),
982+
)))
980983
}
981984
}
982985

986+
fn do_encrypt_pool(&self, _: PoolUuid, _: u32, _: (u32, SizedKeyMemory)) -> StratisResult<()> {
987+
Ok(())
988+
}
989+
990+
fn finish_encrypt_pool(&mut self, _: &Name, _: PoolUuid) -> StratisResult<()> {
991+
Ok(())
992+
}
993+
983994
fn start_reencrypt_pool(&mut self) -> StratisResult<Vec<(u32, SizedKeyMemory, u32)>> {
984995
if self.encryption_info.is_none() {
985996
Err(StratisError::Msg(

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

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,17 +1291,17 @@ impl Backstore {
12911291
self.data_tier.grow(dev)
12921292
}
12931293

1294-
pub fn encrypt(
1294+
pub fn prepare_encrypt(
12951295
&mut self,
12961296
pool_uuid: PoolUuid,
12971297
thinpool: &mut ThinPool<Self>,
12981298
offset: Sectors,
12991299
offset_direction: OffsetDirection,
13001300
encryption_info: &InputEncryptionInfo,
1301-
) -> StratisResult<()> {
1301+
) -> StratisResult<(u32, (u32, SizedKeyMemory))> {
13021302
let (dm_name, _) = format_backstore_ids(pool_uuid, CacheRole::Cache);
13031303
let unencrypted_path = PathBuf::from(DEVICEMAPPER_PATH).join(dm_name.to_string());
1304-
let (mut device, sector_size, key_info) =
1304+
let (sector_size, key_info) =
13051305
CryptHandle::setup_encrypt(pool_uuid, thinpool, &unencrypted_path, encryption_info)?;
13061306

13071307
thinpool.suspend()?;
@@ -1314,14 +1314,23 @@ impl Backstore {
13141314
self.shift_alloc_offset(offset, offset_direction);
13151315
set_device_res?;
13161316

1317-
let handle = CryptHandle::do_encrypt(
1318-
&mut device,
1319-
&unencrypted_path,
1320-
pool_uuid,
1321-
sector_size,
1322-
key_info,
1323-
)?;
1317+
Ok((sector_size, key_info))
1318+
}
1319+
1320+
pub fn do_encrypt(
1321+
pool_uuid: PoolUuid,
1322+
sector_size: u32,
1323+
key_info: (u32, SizedKeyMemory),
1324+
) -> StratisResult<()> {
1325+
let (dm_name, _) = format_backstore_ids(pool_uuid, CacheRole::Cache);
1326+
let unencrypted_path = PathBuf::from(DEVICEMAPPER_PATH).join(dm_name.to_string());
1327+
CryptHandle::do_encrypt(&unencrypted_path, pool_uuid, sector_size, key_info)
1328+
}
13241329

1330+
pub fn finish_encrypt(&mut self, pool_uuid: PoolUuid) -> StratisResult<()> {
1331+
let (dm_name, _) = format_backstore_ids(pool_uuid, CacheRole::Cache);
1332+
let unencrypted_path = PathBuf::from(DEVICEMAPPER_PATH).join(dm_name.to_string());
1333+
let handle = CryptHandle::finish_encrypt(&unencrypted_path, pool_uuid)?;
13251334
self.cap_device.enc = Some(Either::Right(handle));
13261335
Ok(())
13271336
}

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,7 @@ impl CryptHandle {
726726
thinpool: &ThinPool<v2::Backstore>,
727727
unencrypted_path: &Path,
728728
encryption_info: &InputEncryptionInfo,
729-
) -> StratisResult<(CryptDevice, u32, (u32, SizedKeyMemory))> {
729+
) -> StratisResult<(u32, (u32, SizedKeyMemory))> {
730730
let mut tmp_file = tempfile::NamedTempFile::new()?;
731731
tmp_file
732732
.as_file_mut()
@@ -804,7 +804,7 @@ impl CryptHandle {
804804
CryptActivate::SHARED,
805805
)?;
806806

807-
Ok((device, sector_size, (keyslot, key)))
807+
Ok((sector_size, (keyslot, key)))
808808
}
809809

810810
/// Perform the online encryption operation that was set up.
@@ -813,12 +813,12 @@ impl CryptHandle {
813813
/// Precondition: crypt device was already added as the backing device for the thin pool
814814
/// failure to do so will result in corruption
815815
pub fn do_encrypt(
816-
device: &mut CryptDevice,
817816
unencrypted_path: &Path,
818817
pool_uuid: PoolUuid,
819818
sector_size: u32,
820819
key_info: (u32, SizedKeyMemory),
821-
) -> StratisResult<Self> {
820+
) -> StratisResult<()> {
821+
let mut device = acquire_crypt_device(unencrypted_path)?;
822822
let activation_name = &format_crypt_backstore_name(&pool_uuid).to_string();
823823
let (keyslot, key) = key_info;
824824
device.reencrypt_handle().reencrypt_init_by_passphrase(
@@ -850,7 +850,16 @@ impl CryptHandle {
850850
)?;
851851
info!("Starting encryption operation on pool with UUID {pool_uuid}; may take a while");
852852
device.reencrypt_handle().reencrypt2::<()>(None, None)?;
853+
Ok(())
854+
}
853855

856+
/// Generate the CryptHandle from the LUKS2 device path.
857+
///
858+
/// Precondition: LUKS2 device path was fully encrypted successfully
859+
pub fn finish_encrypt(
860+
unencrypted_path: &Path,
861+
pool_uuid: PoolUuid,
862+
) -> StratisResult<CryptHandle> {
854863
CryptHandle::setup(unencrypted_path, pool_uuid, TokenUnlockMethod::Any, None)
855864
.map(|h| h.expect("should have crypt device after online encrypt"))
856865
}

src/engine/strat_engine/pool/dispatch.rs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -351,15 +351,33 @@ impl Pool for AnyPool {
351351
}
352352
}
353353

354-
fn encrypt_pool(
354+
fn start_encrypt_pool(
355355
&mut self,
356-
name: &Name,
357356
pool_uuid: PoolUuid,
358357
encryption_info: &InputEncryptionInfo,
359-
) -> StratisResult<CreateAction<EncryptedDevice>> {
358+
) -> StratisResult<CreateAction<(u32, (u32, SizedKeyMemory))>> {
359+
match self {
360+
AnyPool::V1(p) => p.start_encrypt_pool(pool_uuid, encryption_info),
361+
AnyPool::V2(p) => p.start_encrypt_pool(pool_uuid, encryption_info),
362+
}
363+
}
364+
365+
fn do_encrypt_pool(
366+
&self,
367+
pool_uuid: PoolUuid,
368+
sector_size: u32,
369+
key_info: (u32, SizedKeyMemory),
370+
) -> StratisResult<()> {
371+
match self {
372+
AnyPool::V1(p) => p.do_encrypt_pool(pool_uuid, sector_size, key_info),
373+
AnyPool::V2(p) => p.do_encrypt_pool(pool_uuid, sector_size, key_info),
374+
}
375+
}
376+
377+
fn finish_encrypt_pool(&mut self, name: &Name, pool_uuid: PoolUuid) -> StratisResult<()> {
360378
match self {
361-
AnyPool::V1(p) => p.encrypt_pool(name, pool_uuid, encryption_info),
362-
AnyPool::V2(p) => p.encrypt_pool(name, pool_uuid, encryption_info),
379+
AnyPool::V1(p) => p.finish_encrypt_pool(name, pool_uuid),
380+
AnyPool::V2(p) => p.finish_encrypt_pool(name, pool_uuid),
363381
}
364382
}
365383

src/engine/strat_engine/pool/v1.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,12 +1340,26 @@ impl Pool for StratPool {
13401340
}
13411341
}
13421342

1343-
fn encrypt_pool(
1343+
#[pool_mutating_action("NoRequests")]
1344+
fn start_encrypt_pool(
13441345
&mut self,
1345-
_: &Name,
13461346
_: PoolUuid,
13471347
_: &InputEncryptionInfo,
1348-
) -> StratisResult<CreateAction<EncryptedDevice>> {
1348+
) -> StratisResult<CreateAction<(u32, (u32, SizedKeyMemory))>> {
1349+
Err(StratisError::Msg(
1350+
"Encrypting an unencrypted device is only supported in V2 of the metadata".to_string(),
1351+
))
1352+
}
1353+
1354+
#[pool_mutating_action("NoRequests")]
1355+
fn do_encrypt_pool(&self, _: PoolUuid, _: u32, _: (u32, SizedKeyMemory)) -> StratisResult<()> {
1356+
Err(StratisError::Msg(
1357+
"Encrypting an unencrypted device is only supported in V2 of the metadata".to_string(),
1358+
))
1359+
}
1360+
1361+
#[pool_mutating_action("NoRequests")]
1362+
fn finish_encrypt_pool(&mut self, _: &Name, _: PoolUuid) -> StratisResult<()> {
13491363
Err(StratisError::Msg(
13501364
"Encrypting an unencrypted device is only supported in V2 of the metadata".to_string(),
13511365
))

src/engine/strat_engine/pool/v2.rs

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,30 +1211,46 @@ impl Pool for StratPool {
12111211
}
12121212

12131213
#[pool_mutating_action("NoRequests")]
1214-
fn encrypt_pool(
1214+
fn start_encrypt_pool(
12151215
&mut self,
1216-
name: &Name,
12171216
pool_uuid: PoolUuid,
12181217
encryption_info: &InputEncryptionInfo,
1219-
) -> StratisResult<CreateAction<EncryptedDevice>> {
1220-
let offset = DEFAULT_CRYPT_DATA_OFFSET_V2;
1221-
let direction = OffsetDirection::Backwards;
1218+
) -> StratisResult<CreateAction<(u32, (u32, SizedKeyMemory))>> {
12221219
match self.backstore.encryption_info() {
12231220
Some(_) => Ok(CreateAction::Identity),
12241221
None => {
1225-
self.backstore.encrypt(
1226-
pool_uuid,
1227-
&mut self.thin_pool,
1228-
offset,
1229-
direction,
1230-
encryption_info,
1231-
)?;
1232-
self.write_metadata(name)?;
1233-
Ok(CreateAction::Created(EncryptedDevice(pool_uuid)))
1222+
let offset = DEFAULT_CRYPT_DATA_OFFSET_V2;
1223+
let direction = OffsetDirection::Backwards;
1224+
self.backstore
1225+
.prepare_encrypt(
1226+
pool_uuid,
1227+
&mut self.thin_pool,
1228+
offset,
1229+
direction,
1230+
encryption_info,
1231+
)
1232+
.map(CreateAction::Created)
12341233
}
12351234
}
12361235
}
12371236

1237+
#[pool_mutating_action("NoRequests")]
1238+
fn do_encrypt_pool(
1239+
&self,
1240+
pool_uuid: PoolUuid,
1241+
sector_size: u32,
1242+
key_info: (u32, SizedKeyMemory),
1243+
) -> StratisResult<()> {
1244+
Backstore::do_encrypt(pool_uuid, sector_size, key_info)
1245+
}
1246+
1247+
#[pool_mutating_action("NoRequests")]
1248+
fn finish_encrypt_pool(&mut self, name: &Name, pool_uuid: PoolUuid) -> StratisResult<()> {
1249+
self.backstore.finish_encrypt(pool_uuid)?;
1250+
self.write_metadata(name)?;
1251+
Ok(())
1252+
}
1253+
12381254
#[pool_mutating_action("NoRequests")]
12391255
fn start_reencrypt_pool(&mut self) -> StratisResult<Vec<(u32, SizedKeyMemory, u32)>> {
12401256
self.backstore.prepare_reencrypt()
@@ -2195,10 +2211,8 @@ mod tests {
21952211
{
21962212
let mut handle =
21972213
test_async!(engine.get_mut_pool(PoolIdentifier::Uuid(pool_uuid))).unwrap();
2198-
let (name, _, pool) = handle.as_mut_tuple();
2199-
assert!(!pool.is_encrypted());
2200-
pool.encrypt_pool(
2201-
&name,
2214+
assert!(!handle.is_encrypted());
2215+
let (sector_size, key_info) = handle.start_encrypt_pool(
22022216
pool_uuid,
22032217
&InputEncryptionInfo::new(
22042218
vec![(None, key_desc.to_owned())],
@@ -2216,8 +2230,17 @@ mod tests {
22162230
.unwrap()
22172231
.unwrap(),
22182232
)
2233+
.unwrap()
2234+
.changed()
22192235
.unwrap();
2220-
assert!(pool.is_encrypted());
2236+
let handle = handle.downgrade();
2237+
handle
2238+
.do_encrypt_pool(pool_uuid, sector_size, key_info)
2239+
.unwrap();
2240+
let mut handle = test_async!(engine.upgrade_pool(handle.into_dyn()));
2241+
let (name, _, _) = handle.as_mut_tuple();
2242+
handle.finish_encrypt_pool(&name, pool_uuid).unwrap();
2243+
assert!(handle.is_encrypted());
22212244
}
22222245

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

0 commit comments

Comments
 (0)