Skip to content

Commit 3279987

Browse files
committed
fix: use auto-detected sector size for blockdev
This fixes the behaviour where we pass 512 as sector size if the disk uri doesn't contain blk_size parameter. This causes pool creation failure if the underlying disk has a different sector size e.g. 4096. Instead of passing 512, we now pass 0 which lets spdk detect the device's sector size and use that value. Signed-off-by: Diwakar Sharma <diwakar.sharma@datacore.com>
1 parent 6b4def0 commit 3279987

File tree

7 files changed

+147
-7
lines changed

7 files changed

+147
-7
lines changed

io-engine-tests/src/lib.rs

+22
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,28 @@ pub fn truncate_file_bytes(path: &str, size: u64) {
188188
assert!(output.status.success());
189189
}
190190

191+
/// Automatically assign a loopdev to path
192+
pub fn setup_loopdev_file(path: &str, sector_size: Option<u64>) -> String {
193+
let log_sec = sector_size.unwrap_or(512);
194+
195+
let output = Command::new("losetup")
196+
.args(["-f", "--show", "-b", &format!("{log_sec}"), path])
197+
.output()
198+
.expect("failed exec losetup");
199+
assert!(output.status.success());
200+
// return the assigned loop device
201+
String::from_utf8(output.stdout).unwrap().trim().to_string()
202+
}
203+
204+
/// Detach the provided loop device.
205+
pub fn detach_loopdev(dev: &str) {
206+
let output = Command::new("losetup")
207+
.args(["-d", dev])
208+
.output()
209+
.expect("failed exec losetup");
210+
assert!(output.status.success());
211+
}
212+
191213
pub fn fscheck(device: &str) {
192214
let output = Command::new("fsck")
193215
.args([device, "-n"])

io-engine/src/bdev/aio.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,13 @@ use url::Url;
1414
use spdk_rs::libspdk::{bdev_aio_delete, create_aio_bdev};
1515

1616
use crate::{
17-
bdev::{dev::reject_unknown_parameters, util::uri, CreateDestroy, GetName},
17+
bdev::{
18+
dev::reject_unknown_parameters,
19+
path_is_blockdev,
20+
util::uri,
21+
CreateDestroy,
22+
GetName,
23+
},
1824
bdev_api::{self, BdevError},
1925
core::{UntypedBdev, VerboseError},
2026
ffihelper::{cb_arg, done_errno_cb, ErrnoResult},
@@ -47,6 +53,7 @@ impl TryFrom<&Url> for Aio {
4753
});
4854
}
4955

56+
let path_is_blockdev = path_is_blockdev(url.path());
5057
let mut parameters: HashMap<String, String> =
5158
url.query_pairs().into_owned().collect();
5259

@@ -58,7 +65,13 @@ impl TryFrom<&Url> for Aio {
5865
value: value.clone(),
5966
})?
6067
}
61-
None => 512,
68+
None => {
69+
if path_is_blockdev {
70+
0
71+
} else {
72+
512
73+
}
74+
}
6275
};
6376

6477
let uuid = uri::uuid(parameters.remove("uuid")).context(

io-engine/src/bdev/mod.rs

+26
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ use async_trait::async_trait;
22

33
pub use dev::{device_create, device_destroy, device_lookup, device_open};
44
pub use device::{bdev_event_callback, bdev_io_ctx_pool_init, SpdkBlockDevice};
5+
use libc::{stat, S_IFBLK, S_IFMT};
56
pub use nexus::{Nexus, NexusInfo, NexusState};
67
pub use nvmx::{
78
nvme_io_ctx_pool_init,
89
NvmeController,
910
NvmeControllerState,
1011
NVME_CONTROLLERS,
1112
};
13+
use std::ffi::CString;
1214

1315
mod aio;
1416
pub(crate) mod dev;
@@ -48,6 +50,30 @@ pub trait GetName {
4850
fn get_name(&self) -> String;
4951
}
5052

53+
/// Check if the path indicates a blockdev, or a regular file. It will be
54+
/// helpful for cases where we use a regular file e.g. a tmpfs file, as a pool
55+
/// backend. XXX: If we can't clearly determine if a path is blockdev(error
56+
/// conditions), we return false today so that caller side can decide what to
57+
/// do.
58+
pub fn path_is_blockdev(path: &str) -> bool {
59+
// Create a mutable stat struct
60+
let mut stat_result: stat = unsafe { std::mem::zeroed() };
61+
let path_cstring = match CString::new(path) {
62+
Ok(cstr) => cstr,
63+
Err(_e) => return false,
64+
};
65+
66+
// Call the stat system call
67+
let stat_ret =
68+
unsafe { stat(path_cstring.as_ptr(), &mut stat_result as *mut stat) };
69+
70+
if stat_ret == 0 {
71+
// Check if it's a block device
72+
stat_result.st_mode & S_IFMT == S_IFBLK
73+
} else {
74+
false
75+
}
76+
}
5177
/// Exposes functionality to prepare for persisting reservations in the event
5278
/// of a power loss.
5379
/// This can be implemented by each resource that deals with persistent nvme

io-engine/src/bdev/nvmx/qpair.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ use spdk_rs::libspdk::{
2222
spdk_nvme_qpair_set_abort_dnr,
2323
};
2424

25+
use std::mem::zeroed;
2526
#[cfg(feature = "spdk-async-qpair-connect")]
2627
use std::{os::raw::c_void, time::Duration};
27-
use std::mem::zeroed;
2828

2929
#[cfg(feature = "spdk-async-qpair-connect")]
3030
use spdk_rs::{

io-engine/src/bdev/uring.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@ use url::Url;
88
use spdk_rs::libspdk::{create_uring_bdev, delete_uring_bdev};
99

1010
use crate::{
11-
bdev::{dev::reject_unknown_parameters, util::uri, CreateDestroy, GetName},
11+
bdev::{
12+
dev::reject_unknown_parameters,
13+
path_is_blockdev,
14+
util::uri,
15+
CreateDestroy,
16+
GetName,
17+
},
1218
bdev_api::{self, BdevError},
1319
core::UntypedBdev,
1420
ffihelper::{cb_arg, done_errno_cb, ErrnoResult},
@@ -36,6 +42,7 @@ impl TryFrom<&Url> for Uring {
3642
});
3743
}
3844

45+
let path_is_blockdev = path_is_blockdev(url.path());
3946
let mut parameters: HashMap<String, String> =
4047
url.query_pairs().into_owned().collect();
4148

@@ -47,7 +54,13 @@ impl TryFrom<&Url> for Uring {
4754
value: value.clone(),
4855
})?
4956
}
50-
None => 512,
57+
None => {
58+
if path_is_blockdev {
59+
0
60+
} else {
61+
512
62+
}
63+
}
5164
};
5265

5366
let uuid = uri::uuid(parameters.remove("uuid")).context(

io-engine/src/core/env.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use spdk_rs::{
2727
libspdk::{
2828
spdk_app_shutdown_cb,
2929
spdk_env_dpdk_post_init,
30+
spdk_env_dpdk_rte_eal_init,
3031
spdk_env_fini,
3132
spdk_log_close,
3233
spdk_log_level,
@@ -43,7 +44,6 @@ use spdk_rs::{
4344
spdk_thread_lib_fini,
4445
spdk_thread_send_critical_msg,
4546
spdk_trace_cleanup,
46-
spdk_env_dpdk_rte_eal_init,
4747
SPDK_LOG_DEBUG,
4848
SPDK_LOG_INFO,
4949
SPDK_RPC_RUNTIME,

io-engine/tests/lvs_pool.rs

+67-1
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,22 @@ pub mod common;
1818

1919
static DISKNAME1: &str = "/tmp/disk1.img";
2020
static DISKNAME2: &str = "/tmp/disk2.img";
21+
static DISKNAME3: &str = "/tmp/disk3.img";
2122

2223
#[tokio::test]
2324
async fn lvs_pool_test() {
24-
common::delete_file(&[DISKNAME1.into(), DISKNAME2.into()]);
25+
common::delete_file(&[
26+
DISKNAME1.into(),
27+
DISKNAME2.into(),
28+
DISKNAME3.into(),
29+
]);
2530
common::truncate_file(DISKNAME1, 128 * 1024);
2631
common::truncate_file(DISKNAME2, 128 * 1024);
32+
common::truncate_file(DISKNAME3, 128 * 1024);
33+
34+
//setup disk3 via loop device using a sector size of 4096.
35+
let ldev = common::setup_loopdev_file(DISKNAME3, Some(4096));
36+
2737
let args = MayastorCliArgs {
2838
reactor_mask: "0x3".into(),
2939
..Default::default()
@@ -336,6 +346,60 @@ async fn lvs_pool_test() {
336346
})
337347
.await;
338348

349+
let pool_dev_aio = ldev.clone();
350+
// should succeed to create an aio bdev pool on a loop blockdev of 4096
351+
// bytes sector size.
352+
ms.spawn(async move {
353+
Lvs::create_or_import(PoolArgs {
354+
name: "tpool_4k_aio".into(),
355+
disks: vec![format!("aio://{pool_dev_aio}")],
356+
uuid: None,
357+
cluster_size: None,
358+
backend: PoolBackend::Lvs,
359+
})
360+
.await
361+
.unwrap();
362+
})
363+
.await;
364+
365+
// should be able to find our new LVS created on loopdev, and subsequently
366+
// destroy it.
367+
ms.spawn(async {
368+
let pool = Lvs::lookup("tpool_4k_aio").unwrap();
369+
assert_eq!(pool.name(), "tpool_4k_aio");
370+
assert_eq!(pool.used(), 0);
371+
dbg!(pool.uuid());
372+
pool.destroy().await.unwrap();
373+
})
374+
.await;
375+
376+
let pool_dev_uring = ldev.clone();
377+
// should succeed to create an uring pool on a loop blockdev of 4096 bytes
378+
// sector size.
379+
ms.spawn(async move {
380+
Lvs::create_or_import(PoolArgs {
381+
name: "tpool_4k_uring".into(),
382+
disks: vec![format!("uring://{pool_dev_uring}")],
383+
uuid: None,
384+
cluster_size: None,
385+
backend: PoolBackend::Lvs,
386+
})
387+
.await
388+
.unwrap();
389+
})
390+
.await;
391+
392+
// should be able to find our new LVS created on loopdev, and subsequently
393+
// destroy it.
394+
ms.spawn(async {
395+
let pool = Lvs::lookup("tpool_4k_uring").unwrap();
396+
assert_eq!(pool.name(), "tpool_4k_uring");
397+
assert_eq!(pool.used(), 0);
398+
dbg!(pool.uuid());
399+
pool.destroy().await.unwrap();
400+
})
401+
.await;
402+
339403
// validate the expected state of mayastor
340404
ms.spawn(async {
341405
// no shares left except for the discovery controller
@@ -381,4 +445,6 @@ async fn lvs_pool_test() {
381445
.await;
382446

383447
common::delete_file(&[DISKNAME2.into()]);
448+
common::detach_loopdev(ldev.as_str());
449+
common::delete_file(&[DISKNAME3.into()]);
384450
}

0 commit comments

Comments
 (0)