Skip to content

Commit 97a2e29

Browse files
feat(pool-expand): add logic to derive md_resv_ratio from absolute size
Signed-off-by: Abhilash Shetty <[email protected]>
1 parent 0da7949 commit 97a2e29

File tree

12 files changed

+76
-52
lines changed

12 files changed

+76
-52
lines changed

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
[submodule "utils/dependencies"]
66
path = utils/dependencies
77
url = ../mayastor-dependencies.git
8-
branch = pool_grow_changes
8+
branch = develop

io-engine-tests/src/pool.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -212,20 +212,17 @@ impl PoolBuilderRpc {
212212
.map(|r| r.into_inner())
213213
}
214214

215-
pub async fn grow(&mut self) -> Result<(Pool, Pool), Status> {
215+
pub async fn grow(&mut self) -> Result<Pool, Status> {
216216
self.rpc()
217217
.lock()
218218
.await
219219
.pool
220-
.grow_pool(GrowPoolRequest {
220+
.grow_pool_v2(GrowPoolRequest {
221221
name: self.name(),
222222
uuid: Some(self.uuid()),
223223
})
224224
.await
225-
.map(|r| {
226-
let t = r.into_inner();
227-
(t.previous_pool.unwrap(), t.current_pool.unwrap())
228-
})
225+
.map(|r| (r.into_inner()))
229226
}
230227

231228
pub async fn get_pool(&self) -> Result<Pool, Status> {

io-engine/src/bin/io-engine-client/v1/pool_cli.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ pub fn subcommands() -> Command {
185185
);
186186

187187
let expand = Command::new("expand")
188-
.about("Expand a storage pool to fill the entire underlying device")
188+
.about("Expand a storage pool to span the entire underlying device")
189189
.arg(
190190
Arg::new("name")
191191
.required(true)
@@ -569,6 +569,13 @@ async fn expand(mut ctx: Context, matches: &ArgMatches) -> crate::Result<()> {
569569
.await
570570
.context(GrpcStatus)?;
571571

572+
if list_response.get_ref().pools.is_empty() {
573+
return Err(ClientError::GrpcStatus {
574+
source: Status::not_found(format!("Pool {name} not found")),
575+
backtrace: None,
576+
});
577+
}
578+
572579
let pool = &list_response.get_ref().pools[0];
573580
let previous_capacity = pool.capacity;
574581

io-engine/src/grpc/v0/mayastor_grpc.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,7 @@ impl From<LvsError> for tonic::Status {
250250
LvsError::SetProperty { .. } => Status::data_loss(e.to_string()),
251251
LvsError::WipeFailed { source } => source.into(),
252252
LvsError::ResourceLockFailed { .. } => Status::aborted(e.to_string()),
253-
LvsError::MaxExpansionFactorFormat { .. } => Status::invalid_argument(e.to_string()),
254-
LvsError::MaxExpansionFactorParse { .. } => Status::invalid_argument(e.to_string()),
253+
LvsError::MaxExpansionParse { .. } => Status::invalid_argument(e.to_string()),
255254
_ => Status::internal(e.verbose()),
256255
}
257256
}

io-engine/src/grpc/v1/pool.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use std::{
2424
ops::Deref,
2525
panic::AssertUnwindSafe,
2626
};
27-
use tonic::{Request, Status};
27+
use tonic::{Code, Request, Status};
2828

2929
pub type PoolCreateEncryptionParams = create_pool_request::Encryption;
3030
pub type PoolImportEncryptionParams = import_pool_request::Encryption;
@@ -448,7 +448,7 @@ impl From<&dyn PoolOps> for Pool {
448448
disk_capacity: value.disk_capacity(),
449449
md_info: value.md_props().map(|md| md.into()),
450450
encrypted: Some(value.encrypted()),
451-
max_expandable_size: Some(value.max_expandable_size()),
451+
max_expandable_size: value.max_expandable_size(),
452452
}
453453
}
454454
}
@@ -711,7 +711,10 @@ impl PoolRpc for PoolService {
711711
}
712712

713713
async fn grow_pool(&self, _request: Request<GrowPoolRequest>) -> GrpcResult<GrowPoolResponse> {
714-
unimplemented!()
714+
Err(Status::new(
715+
Code::Unimplemented,
716+
"grow_pool is deprecated. Please use grow_pool_v2",
717+
))
715718
}
716719

717720
#[named]

io-engine/src/lvm/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,8 +326,8 @@ impl IPoolProps for VolumeGroup {
326326
false
327327
}
328328

329-
fn max_expandable_size(&self) -> u64 {
330-
0
329+
fn max_expandable_size(&self) -> Option<u64> {
330+
None
331331
}
332332
}
333333

io-engine/src/lvs/lvs_error.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -262,13 +262,9 @@ pub enum LvsError {
262262
ResourceLockFailed {
263263
msg: String,
264264
},
265-
#[snafu(display("Failed to parse factor {} into float", factor))]
266-
MaxExpansionFactorParse {
267-
factor: String,
268-
},
269-
#[snafu(display("Max growth factor {} does not end with x", factor))]
270-
MaxExpansionFactorFormat {
271-
factor: String,
265+
#[snafu(display("{msg}"))]
266+
MaxExpansionParse {
267+
msg: String,
272268
},
273269
}
274270

@@ -305,8 +301,7 @@ impl ToErrno for LvsError {
305301
Self::CloneConfigFailed { .. } => Errno::EINVAL,
306302
Self::WipeFailed { .. } => Errno::EINVAL,
307303
Self::ResourceLockFailed { .. } => Errno::EBUSY,
308-
Self::MaxExpansionFactorParse { .. } => Errno::EINVAL,
309-
Self::MaxExpansionFactorFormat { .. } => Errno::EINVAL,
304+
Self::MaxExpansionParse { .. } => Errno::EINVAL,
310305
}
311306
}
312307
}

io-engine/src/lvs/lvs_store.rs

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use core::f64;
2-
use std::{convert::TryFrom, fmt::Debug, os::raw::c_void, pin::Pin, ptr::NonNull};
2+
use std::{convert::TryFrom, fmt::Debug, os::raw::c_void, pin::Pin, ptr::NonNull, str::FromStr};
33

44
use byte_unit::Byte;
55
use events_api::event::EventAction;
@@ -210,9 +210,9 @@ impl Lvs {
210210
}
211211

212212
/// Size upto which blobstore can be expanded.
213-
pub fn max_expandable_size(&self) -> u64 {
213+
pub fn max_expandable_size(&self) -> Option<u64> {
214214
// TODO: Use spdk function when changes gets merged.
215-
0
215+
Some(0)
216216
}
217217

218218
/// returns the UUID of the lvs
@@ -422,21 +422,37 @@ impl Lvs {
422422
}
423423
}
424424

425-
/// Converts floating point metadata reservation ratio into SPDK's format.
426-
fn mdp_ratio(args: &PoolArgs) -> Result<u32, LvsError> {
427-
if let Some(mut h) = args.md_args.as_ref().and_then(|p| p.max_expansion.clone()) {
428-
if h.ends_with("x") {
429-
let _ = h.pop();
430-
let factor_parsed = h
431-
.parse::<f64>()
432-
.map_err(|_| LvsError::MaxExpansionFactorParse { factor: h })?;
433-
Ok((factor_parsed * 100.0) as u32)
434-
} else {
435-
Err(LvsError::MaxExpansionFactorFormat { factor: h })
436-
}
425+
/// Derive num_md_pages_per_cluster_ratio from max_expansion which can be a factor or absolute size.
426+
fn md_resv_ratio(args: &PoolArgs, capacity: u64) -> Result<u32, LvsError> {
427+
let param = match args.md_args.as_ref().and_then(|p| p.max_expansion.clone()) {
428+
Some(p) => p,
429+
None => return Ok(100),
430+
};
431+
let factor = if let Some(stripped) = param.strip_suffix('x') {
432+
stripped
433+
.parse::<f64>()
434+
.map_err(|error| LvsError::MaxExpansionParse {
435+
msg: format!(
436+
"Failed to parse factor max_expansion {stripped} as float: {error}"
437+
),
438+
})?
439+
} else if param.ends_with('B') {
440+
let expand_bytes =
441+
Byte::from_str(&param).map_err(|error| LvsError::MaxExpansionParse {
442+
msg: format!("Failed to parse max_expansion {param} as bytes: {error}"),
443+
})?;
444+
expand_bytes.as_u64() as f64 / capacity as f64
437445
} else {
438-
Ok(0)
439-
}
446+
return Err(LvsError::MaxExpansionParse {
447+
msg: format!("Max expansion factor {param} does not end with x or B"),
448+
});
449+
};
450+
// The Blobstore ensures that we have enough pages in used_cluster_mask to track the current device size.
451+
// So, If maxExpansion results is < 1x it still shouldn't matter. Its same as having
452+
// default reservation. However, it does impact how many md pages per cluster are reserved.
453+
// For ex. if the factor turns out to be 0.5 then blobstore reserves 1 page per 2 clusters.
454+
// So lets ensures that we pass at least default reservation.
455+
Ok((factor.max(1.0) * 100.0) as u32)
440456
}
441457

442458
/// Creates a pool on base bdev.
@@ -450,7 +466,7 @@ impl Lvs {
450466
let bdev_name = if let Some(ref c) = args.crypto_vbdev_name {
451467
c.clone().into_cstring()
452468
} else {
453-
bdev.into_cstring()
469+
bdev.clone().into_cstring()
454470
};
455471

456472
let cluster_size = if let Some(cluster_size) = args.cluster_size {
@@ -474,9 +490,14 @@ impl Lvs {
474490
msg: format!("{cluster_size}, larger than max limit {MAX_CLUSTER_SIZE}"),
475491
});
476492
}
477-
478-
let mdp_ratio = Self::mdp_ratio(&args)?;
479-
493+
let bdev = UntypedBdev::lookup_by_name(&bdev).ok_or(LvsError::InvalidBdev {
494+
source: BdevError::BdevNotFound {
495+
name: bdev.to_string(),
496+
},
497+
name: bdev.to_string(),
498+
})?;
499+
let bdev_capacity = bdev.num_blocks() * bdev.block_len() as u64;
500+
let mdp_ratio = Self::md_resv_ratio(&args, bdev_capacity)?;
480501
let (sender, receiver) = pair::<ErrnoResult<Lvs>>();
481502
unsafe {
482503
if let Some(uuid) = &args.uuid {

io-engine/src/lvs/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ impl IPoolProps for Lvs {
232232
self.encrypted()
233233
}
234234

235-
fn max_expandable_size(&self) -> u64 {
235+
fn max_expandable_size(&self) -> Option<u64> {
236236
self.max_expandable_size()
237237
}
238238
}

io-engine/src/pool_backend.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ pub trait IPoolProps {
234234
fn committed(&self) -> u64;
235235
fn md_props(&self) -> Option<PoolMetadataInfo>;
236236
fn encrypted(&self) -> bool;
237-
fn max_expandable_size(&self) -> u64;
237+
fn max_expandable_size(&self) -> Option<u64>;
238238
}
239239

240240
/// A pool factory helper.

0 commit comments

Comments
 (0)