@@ -24,7 +24,7 @@ use spdk_rs::{
2424 accel_dpdk_cryptodev_enable, accel_dpdk_cryptodev_set_driver, create_crypto_disk,
2525 create_crypto_opts_by_name, delete_crypto_disk, spdk_accel_assign_opc,
2626 spdk_accel_crypto_key, spdk_accel_crypto_key_create, spdk_accel_crypto_key_create_param,
27- spdk_accel_crypto_key_get,
27+ spdk_accel_crypto_key_destroy , spdk_accel_crypto_key_get,
2828 } ,
2929} ;
3030use std:: {
@@ -38,6 +38,91 @@ use crate::{
3838 ffihelper:: { cb_arg, pair, FfiResult } ,
3939} ;
4040
41+ use once_cell:: sync:: Lazy ;
42+ use std:: {
43+ collections:: { HashMap , HashSet } ,
44+ sync:: RwLock ,
45+ } ;
46+
47+ /// Global synchronized HashMap (Crypto Key -> Set of crypto vbdevs).
48+ /// Since this doesn't lie in IO path, not using per-bucket locks in hashmap.
49+ static KEY_CRYPTO_VBDEV_MAP : Lazy < RwLock < HashMap < String , HashSet < String > > > > =
50+ Lazy :: new ( || RwLock :: new ( HashMap :: new ( ) ) ) ;
51+
52+ /// Adds a dependency ('crypto_vbdev_name' uses 'key_name')
53+ fn add_key_user (
54+ key_params : & EncryptionKey ,
55+ crypto_vbdev_name : String ,
56+ ) -> Result < * mut spdk_accel_crypto_key , BdevError > {
57+ let mut map = KEY_CRYPTO_VBDEV_MAP . write ( ) . unwrap ( ) ;
58+
59+ // Create the key first.
60+ let key = create_crypto_key ( key_params) ?;
61+
62+ map. entry ( key_params. key_name . clone ( ) )
63+ . or_default ( )
64+ . insert ( crypto_vbdev_name) ;
65+ Ok ( key)
66+ }
67+
68+ /// Removes a dependency ('crypto_vbdev_name' stops using 'key_name')
69+ fn remove_key_user ( key_name : & str , crypto_vbdev_name : String ) {
70+ let mut map = KEY_CRYPTO_VBDEV_MAP . write ( ) . unwrap ( ) ;
71+ if let Some ( users) = map. get_mut ( key_name) {
72+ users. remove ( & crypto_vbdev_name) ;
73+ // Clean up empty sets immediately
74+ if users. is_empty ( ) {
75+ // delete the key in spdk.
76+ unsafe {
77+ let key = spdk_accel_crypto_key_get (
78+ key_name. to_string ( ) . into_cstring ( ) . as_ptr ( ) as * mut c_char
79+ ) ;
80+ if key. is_null ( ) {
81+ warn ! ( "Non-existent key in SPDK." ) ;
82+ } else {
83+ let err = spdk_accel_crypto_key_destroy ( key) ;
84+ if err != 0 {
85+ error ! ( "Failed to destroy spdk accel crypto key: {err}" ) ;
86+ // Return and don't remove from the map yet.
87+ return ;
88+ }
89+ }
90+ }
91+ map. remove ( key_name) ;
92+ }
93+ }
94+ }
95+
96+ /// Gets all crypto vbdev names using a given key_name.
97+ fn get_users_of ( key_name : & str ) -> Option < HashSet < String > > {
98+ let map = KEY_CRYPTO_VBDEV_MAP . read ( ) . unwrap ( ) ;
99+ // Clone or return ref perhaps?
100+ map. get ( key_name) . cloned ( )
101+ }
102+
103+ /// Reverse lookup: O(n * m)
104+ /// Finds which hash key contains a particular crypto vbdev name (scans the map). Should be
105+ /// ok to bear this cost as there won't be exhorbitant number of pool or keys per io-engine.
106+ fn find_key_for_crypto_vbdev ( crypto_vbdev_name : & str ) -> Option < String > {
107+ let map = KEY_CRYPTO_VBDEV_MAP . read ( ) . unwrap ( ) ;
108+ map. iter ( ) . find_map ( |( key, users) | {
109+ if users. contains ( crypto_vbdev_name) {
110+ Some ( key. to_owned ( ) )
111+ } else {
112+ None
113+ }
114+ } )
115+ }
116+
117+ /// Purges all key entries that have no crypto vbdev users left. This will not be usually
118+ /// needed because remove call is taking care of deleting the key entry upon removal of
119+ /// last crypto vbdev user.
120+ #[ allow( dead_code) ]
121+ fn purge_empty_keys ( ) {
122+ let mut map = KEY_CRYPTO_VBDEV_MAP . write ( ) . unwrap ( ) ;
123+ map. retain ( |_, users| !users. is_empty ( ) ) ;
124+ }
125+
41126/// Representation of a crypto vbdev to be created in SPDK.
42127/// TODO: Currently we don't fit crypto vbdev into the uri based bdev management
43128/// as the information required to completely setup the crypto vbdev isn't part of the uri,
@@ -200,6 +285,12 @@ fn create_crypto_key(key_params: &EncryptionKey) -> Result<*mut spdk_accel_crypt
200285 } ;
201286
202287 unsafe {
288+ // Check if the key with this name exists. If it does, then we reuse that.
289+ let existing_key = spdk_accel_crypto_key_get ( create_key_params. key_name ) ;
290+ if !existing_key. is_null ( ) {
291+ info ! ( "Key {:?} exists already, reusing it." , key_params. key_name) ;
292+ return Ok ( existing_key) ;
293+ } ;
203294 let ret = spdk_accel_crypto_key_create ( & create_key_params) ;
204295 if ret != 0 {
205296 Err ( BdevError :: CreateBdevFailed {
@@ -222,7 +313,10 @@ extern "C" fn crypto_vbdev_op_cb(arg: *mut std::os::raw::c_void, errno: i32) {
222313}
223314
224315/// Destroy a crypto vbdev.
225- pub async fn destroy_crypto_vbdev ( vbdev_name : String ) -> Result < ( ) , BdevError > {
316+ pub async fn destroy_crypto_vbdev (
317+ vbdev_name : String ,
318+ key_name : Option < String > ,
319+ ) -> Result < ( ) , BdevError > {
226320 let ( s, r) = pair :: < i32 > ( ) ;
227321 unsafe {
228322 delete_crypto_disk (
@@ -232,14 +326,34 @@ pub async fn destroy_crypto_vbdev(vbdev_name: String) -> Result<(), BdevError> {
232326 ) ;
233327 }
234328
235- r. await
329+ let ret = r
330+ . await
236331 . expect ( "callback gone while deleting crypto disk" )
237332 . to_result ( |e| BdevError :: DestroyBdevFailed {
238333 source : Errno :: from_raw ( e) ,
239334 name : vbdev_name. to_string ( ) ,
240- } ) ?;
335+ } ) ;
336+ if let Err ( e) = ret {
337+ match e {
338+ BdevError :: BdevNotFound { .. } => { }
339+ _else => return Err ( _else) ,
340+ }
341+ }
241342
242343 info ! ( "crypto vbdev {vbdev_name} destroyed successfully" ) ;
344+
345+ let key_name = match key_name. or_else ( || find_key_for_crypto_vbdev ( & vbdev_name) ) {
346+ Some ( k) => k,
347+ None => {
348+ warn ! ( "Mapped key not found for {vbdev_name}" ) ;
349+ return Ok ( ( ) ) ;
350+ }
351+ } ;
352+
353+ remove_key_user ( key_name. as_str ( ) , vbdev_name) ;
354+ if let Some ( users) = get_users_of ( key_name. as_str ( ) ) {
355+ trace ! ( "[remove] Remaining key users {key_name}: {users:?}" ) ;
356+ }
243357 Ok ( ( ) )
244358}
245359/// The primary function to create a crypto vbdev in spdk.
@@ -248,29 +362,35 @@ pub fn create_crypto_vbdev_on_base_bdev(
248362 base_bdev_name : & str ,
249363 key_params : & EncryptionKey ,
250364) -> Result < ( ) , BdevError > {
251- // Create the key.
252- let key = create_crypto_key ( key_params) ?;
365+ // Create the key and add to the map.
366+ let key = add_key_user ( key_params, crypto_vbdev_name. to_string ( ) ) ?;
367+ if let Some ( users) = get_users_of ( key_params. key_name . as_str ( ) ) {
368+ trace ! (
369+ "[add] updated key users {:?}: {users:?}" ,
370+ key_params. key_name
371+ ) ;
372+ }
253373
254374 // Setup the crypto opts using the key now.
255375 let crypto_opts_ptr = unsafe {
256376 create_crypto_opts_by_name (
257377 crypto_vbdev_name. into_cstring ( ) . as_ptr ( ) as * mut c_char ,
258378 base_bdev_name. into_cstring ( ) . as_ptr ( ) as * mut c_char ,
259379 key,
260- true ,
380+ false ,
261381 )
262382 } ;
263383
264384 // Now create the crypto vbdev.
265385 let ret = unsafe { create_crypto_disk ( crypto_opts_ptr) } ;
266386
267387 if ret != 0 {
268- Err ( BdevError :: CreateBdevFailed {
388+ return Err ( BdevError :: CreateBdevFailed {
269389 source : Errno :: from_raw ( ret) ,
270390 name : crypto_vbdev_name. to_string ( ) ,
271- } )
272- } else {
273- info ! ( "crypto vbdev {crypto_vbdev_name} created on base bdev {base_bdev_name}" ) ;
274- Ok ( ( ) )
391+ } ) ;
275392 }
393+ info ! ( "crypto vbdev {crypto_vbdev_name} created on base bdev {base_bdev_name}" ) ;
394+
395+ Ok ( ( ) )
276396}
0 commit comments