Skip to content

Commit 9fbb3a4

Browse files
mayastor-borsabhilashshetty04
andcommitted
Merge #1897
1897: do bdev rescan before calling lvs grow function r=abhilashshetty04 a=abhilashshetty04 This PR does `bdev_aio_rescan` before calling grow function. Also some changes in error handling which will help in control plane logic. Co-authored-by: Abhilash Shetty <[email protected]>
2 parents 8407c80 + 01fb76e commit 9fbb3a4

File tree

5 files changed

+87
-11
lines changed

5 files changed

+87
-11
lines changed

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,26 @@ impl From<LvsError> for tonic::Status {
251251
LvsError::WipeFailed { source } => source.into(),
252252
LvsError::ResourceLockFailed { .. } => Status::aborted(e.to_string()),
253253
LvsError::MaxExpansionParse { .. } => Status::invalid_argument(e.to_string()),
254+
LvsError::BdevRescanFailed { .. } => {
255+
let mut status = Status::failed_precondition(e.to_string());
256+
status.metadata_mut().insert(
257+
"bdev_rescan_failed",
258+
tonic::metadata::MetadataValue::from(0),
259+
);
260+
status
261+
}
262+
LvsError::BdevNotExtended { .. } => {
263+
let mut status = Status::failed_precondition(e.to_string());
264+
status
265+
.metadata_mut()
266+
.insert("bdev_not_extended", tonic::metadata::MetadataValue::from(0));
267+
status
268+
}
269+
LvsError::Grow { source, .. } => match source.to_errno() {
270+
Errno::ENOMEM => Status::resource_exhausted(e.to_string()),
271+
Errno::ENOSPC => Status::out_of_range(e.to_string()),
272+
_ => Status::internal(e.to_string()),
273+
},
254274
_ => Status::internal(e.verbose()),
255275
}
256276
}

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -724,11 +724,9 @@ impl PoolRpc for PoolService {
724724
async move {
725725
crate::spdk_submit!(async move {
726726
info!("{:?}", request.get_ref());
727-
728727
let pool = GrpcPoolFactory::finder(request.into_inner()).await?;
729728
pool.grow().await?;
730729
let current_pool = Pool::from(pool.as_ops());
731-
732730
Ok(current_pool)
733731
})
734732
},

io-engine/src/lvs/lvs_error.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,15 @@ pub enum LvsError {
266266
MaxExpansionParse {
267267
msg: String,
268268
},
269+
#[snafu(display("{source}, Failed to rescan bdev {name}"))]
270+
BdevRescanFailed {
271+
source: BsError,
272+
name: String,
273+
},
274+
#[snafu(display("Failed to extend pool bdev: {name}"))]
275+
BdevNotExtended {
276+
name: String,
277+
},
269278
}
270279

271280
/// Map CoreError to errno code.
@@ -302,6 +311,8 @@ impl ToErrno for LvsError {
302311
Self::WipeFailed { .. } => Errno::EINVAL,
303312
Self::ResourceLockFailed { .. } => Errno::EBUSY,
304313
Self::MaxExpansionParse { .. } => Errno::EINVAL,
314+
Self::BdevRescanFailed { source, .. } => source.to_errno(),
315+
Self::BdevNotExtended { .. } => Errno::EOPNOTSUPP,
305316
}
306317
}
307318
}

io-engine/src/lvs/lvs_store.rs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use nix::errno::Errno;
88
use pin_utils::core_reexport::fmt::Formatter;
99

1010
use spdk_rs::libspdk::{
11-
spdk_bdev_update_bs_blockcnt, spdk_blob_store, spdk_bs_free_cluster_count,
11+
bdev_aio_rescan, spdk_bdev_update_bs_blockcnt, spdk_blob_store, spdk_bs_free_cluster_count,
1212
spdk_bs_get_cluster_size, spdk_bs_get_md_len, spdk_bs_get_page_size, spdk_bs_get_used_md,
1313
spdk_bs_total_data_cluster_count, spdk_lvol, spdk_lvol_opts, spdk_lvol_opts_init,
1414
spdk_lvol_store, spdk_lvs_grow_live, vbdev_get_lvol_store_by_name,
@@ -874,11 +874,40 @@ impl Lvs {
874874
Ok(())
875875
}
876876

877-
/// Grows the online (live) pool.
877+
/// Rescans the bdev and triggers live LVS grow i.e. without closing the blobs and unloading the blobstore.
878878
#[tracing::instrument(level = "debug", err)]
879879
pub async fn grow(&self) -> Result<(), LvsError> {
880880
info!("{self:?}: growing lvs...");
881881

882+
let cname = self.base_bdev().name().into_cstring();
883+
let uri_str = &self.base_bdev().bdev_uri_str().unwrap_or_default();
884+
let url = Url::parse(uri_str).map_err(|source| LvsError::InvalidBdev {
885+
source: BdevError::UriParseFailed {
886+
source,
887+
uri: uri_str.to_string(),
888+
},
889+
name: self.name().to_string(),
890+
})?;
891+
if url.scheme() != "malloc" {
892+
info!(
893+
"Attempting to rescan bdev {:?} part of lvs {:?}, uri {:?}",
894+
self.base_bdev().name(),
895+
self.name(),
896+
self.base_bdev().bdev_uri_str().unwrap_or_default()
897+
);
898+
899+
let errno = unsafe { bdev_aio_rescan(cname.as_ptr() as *mut std::os::raw::c_char) };
900+
901+
if errno != 0 {
902+
return Err(LvsError::BdevRescanFailed {
903+
source: BsError::from_i32(errno),
904+
name: self.base_bdev().name().to_string(),
905+
});
906+
}
907+
}
908+
909+
let capacity_before_grow = self.capacity();
910+
882911
let (s, r) = pair::<i32>();
883912

884913
unsafe {
@@ -898,6 +927,12 @@ impl Lvs {
898927
name: self.name().to_string(),
899928
})?;
900929

930+
if self.capacity() == capacity_before_grow {
931+
return Err(LvsError::BdevNotExtended {
932+
name: self.base_bdev().name().to_string(),
933+
});
934+
}
935+
901936
info!("{self:?}: lvs has been grown successfully");
902937

903938
Ok(())

io-engine/tests/lvs_grow.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ impl From<Pool> for TestPoolStats {
8282
/// Grow test interface.
8383
#[async_trait(?Send)]
8484
trait GrowTest {
85+
fn is_malloc(&self) -> bool;
8586
async fn create_pool(&mut self) -> TestPoolStats;
8687
async fn pool_stats(&self) -> TestPoolStats;
8788
async fn grow_pool(&mut self) -> (TestPoolStats, TestPoolStats);
@@ -107,19 +108,22 @@ async fn test_grow(create: impl Future<Output = Box<dyn GrowTest>>) {
107108
// Pool capacity must not change, disk capacity must reflect disk size
108109
// change.
109110
let after_dev_grow = gt.pool_stats().await;
111+
if gt.is_malloc() {
112+
assert_eq!(after_dev_grow.disk_capacity, new_dev_cap);
113+
} else {
114+
assert!(after_dev_grow.disk_capacity < new_dev_cap)
115+
}
110116
assert_eq!(after_dev_grow.capacity, initial.capacity);
111-
assert_eq!(after_dev_grow.disk_capacity, new_dev_cap);
112117

113118
// Grow the pool.
114119
let (before_pool_grow, after_pool_grow) = gt.grow_pool().await;
115120
assert_eq!(before_pool_grow.capacity, initial.capacity);
116-
assert_eq!(before_pool_grow.disk_capacity, new_dev_cap);
117121

118122
// Pool must have grown.
119123
assert!(after_pool_grow.capacity > before_pool_grow.capacity);
120124

121125
// New pool capacity must be close to the disk capacity.
122-
assert!(after_pool_grow.capacity <= after_pool_grow.disk_capacity);
126+
assert!(after_pool_grow.capacity < after_pool_grow.disk_capacity);
123127
assert!(after_pool_grow.capacity_approx_matches());
124128
}
125129

@@ -194,6 +198,10 @@ async fn lvs_grow_ms_malloc() {
194198
.await;
195199
self.device_size().await
196200
}
201+
202+
fn is_malloc(&self) -> bool {
203+
true
204+
}
197205
}
198206

199207
test_grow(async { Box::new(GrowTestMsMalloc {}) as Box<dyn GrowTest> }).await;
@@ -268,6 +276,10 @@ async fn lvs_grow_api_malloc() {
268276
let bdev = create_bdev(self.ms.clone(), BDEV_URI_RESIZE).await.unwrap();
269277
bdev.num_blocks * bdev.blk_size as u64
270278
}
279+
280+
fn is_malloc(&self) -> bool {
281+
true
282+
}
271283
}
272284

273285
test_grow(async { Box::new(GrowTestApiMalloc::new().await) as Box<dyn GrowTest> }).await;
@@ -279,7 +291,6 @@ async fn lvs_grow_api_aio() {
279291
const DISK_NAME: &str = "/tmp/disk1.img";
280292
const BDEV_NAME: &str = "/host/tmp/disk1.img";
281293
const BDEV_URI: &str = "aio:///host/tmp/disk1.img?blk_size=512";
282-
const BDEV_URI_RESCAN: &str = "aio:///host/tmp/disk1.img?blk_size=512&rescan";
283294
const POOL_NAME: &str = "pool0";
284295
const POOL_UUID: &str = "40baf8b5-6256-4f29-b073-61ebf67d9b91";
285296

@@ -347,10 +358,11 @@ async fn lvs_grow_api_aio() {
347358
async fn grow_device(&mut self) -> u64 {
348359
// Resize bdev's backing file.
349360
common::truncate_file(DISK_NAME, 128 * 1024);
361+
self.device_size().await + (128 * 1024)
362+
}
350363

351-
// Rescan AIO bdev (re-read its size from the backing media).
352-
let bdev = create_bdev(self.ms.clone(), BDEV_URI_RESCAN).await.unwrap();
353-
bdev.num_blocks * bdev.blk_size as u64
364+
fn is_malloc(&self) -> bool {
365+
false
354366
}
355367
}
356368

0 commit comments

Comments
 (0)