zvfs: 性能测试

This commit is contained in:
2026-02-24 16:01:29 +00:00
parent 6f8f2148c3
commit 8d1d9506cd
7 changed files with 779 additions and 48 deletions

134
zvfs.c
View File

@@ -4,6 +4,10 @@
#undef SPDK_DEBUGLOG
#define SPDK_DEBUGLOG(...) do {} while(0)
#define ZVFS_BDEV "Nvme0n1"
#ifndef ZVFS_BDEV
#define ZVFS_BDEV "Malloc0"
#endif
struct spdk_thread *global_thread = NULL;
const char *json_file = "/home/lian/share/10.1-spdk/zvfs/zvfs.json";
@@ -114,18 +118,29 @@ bool waiter(struct spdk_thread *thread, spdk_msg_fn start_fn, void *ctx, bool *f
/* MOUNT */
/* ================================================================== */
void zvfs_do_mount(void *arg) {
zvfs_t *fs = (zvfs_t*)arg;
struct spdk_bs_dev *bs_dev = NULL;
int rc = spdk_bdev_create_bs_dev_ext("Malloc0", zvfs_spdk_bdev_event_cb, NULL, &bs_dev);
// SPDK_DEBUGLOG("=== Listing ALL bdevs after JSON load ===\n");
// struct spdk_bdev *bdev = spdk_bdev_first();
// while (bdev) {
// SPDK_DEBUGLOG("Found bdev: [%s] product: %s\n",
// spdk_bdev_get_name(bdev),
// spdk_bdev_get_product_name(bdev));
// bdev = spdk_bdev_next(bdev);
// }
// SPDK_DEBUGLOG("---------------------------------\n");
// SPDK_DEBUGLOG("Trying to open: %s\n", ZVFS_BDEV);
int rc = spdk_bdev_create_bs_dev_ext(ZVFS_BDEV, zvfs_spdk_bdev_event_cb, NULL, &bs_dev);
if (rc != 0) {
spdk_app_stop(0);
SPDK_ERRLOG("=== bdev_open FAILED rc=%d (probably still not registered) ===\n", rc);
fs->finished = true;
spdk_app_stop(-1);
return;
}
fs->bs_dev = bs_dev;
// spdk_bs_init(bs_dev, NULL, zvfs_spdk_bs_init_cb, fs);
spdk_bs_load(bs_dev, NULL, zvfs_spdk_bs_load_cb, fs);
}
@@ -136,7 +151,7 @@ void zvfs_spdk_bs_load_cb(void *arg, struct spdk_blob_store *bs, int bserrno) {
SPDK_DEBUGLOG("load failed, new device, re-create bs_dev and init\n");
struct spdk_bs_dev *bs_dev = NULL;
int rc = spdk_bdev_create_bs_dev_ext("Malloc0", zvfs_spdk_bdev_event_cb, NULL, &bs_dev);
int rc = spdk_bdev_create_bs_dev_ext(ZVFS_BDEV, zvfs_spdk_bdev_event_cb, NULL, &bs_dev);
if (rc != 0) {
SPDK_ERRLOG("re-create bs_dev failed\n");
spdk_app_stop(-1);
@@ -150,7 +165,8 @@ void zvfs_spdk_bs_load_cb(void *arg, struct spdk_blob_store *bs, int bserrno) {
uint64_t io_unit_size = spdk_bs_get_io_unit_size(bs);
SPDK_DEBUGLOG("io_unit_size : %"PRIu64"\n", io_unit_size);
SPDK_NOTICELOG("io_unit_size=%lu\n", io_unit_size);
fs->io_unit_size = io_unit_size;
fs->bs = bs;
fs->channel = spdk_bs_alloc_io_channel(fs->bs);
@@ -167,6 +183,7 @@ void zvfs_spdk_bs_init_cb(void *arg, struct spdk_blob_store *bs, int bserrno) {
uint64_t io_unit_size = spdk_bs_get_io_unit_size(bs);
SPDK_DEBUGLOG("io_unit_size : %"PRIu64"\n", io_unit_size);
SPDK_NOTICELOG("io_unit_size=%lu\n", io_unit_size);
fs->io_unit_size = io_unit_size;
fs->bs = bs;
@@ -370,17 +387,38 @@ void zvfs_do_write(void *arg) {
return;
}
/*
* 先把涉及的扇区读出read 完成后在 preread_cb 里 patch 数据再写。
* 注意:把用户数据暂存在 file->write_buf / write_count
* 或者借用 file->io_countio_count 不变)。
* 这里我们把用户数据已经由上层调用者拷贝到了 write_staging_buf
*/
/* 不管是否需要扩容,先 preread */
spdk_blob_io_read(file->blob, file->fs->channel,
file->dma_buf,
lba, lba_count,
zvfs_spdk_blob_write_preread_cb, file);
file->aligned = (file->current_offset % io_unit == 0) &&
(file->io_count % io_unit == 0);
// static uint64_t aligned_count = 0;
// static uint64_t unaligned_count = 0;
// if (aligned) {
// aligned_count++;
// } else {
// unaligned_count++;
// }
// if ((aligned_count + unaligned_count) % 1000 == 0) {
// printf("aligned=%lu unaligned=%lu\n", aligned_count, unaligned_count);
// }
if (file->aligned) {
/* 直接把用户数据拷到 dma_buf跳过 preread */
memcpy(file->dma_buf, file->write_staging_buf, file->io_count);
/* 直接进 preread_cb 的后半段逻辑(扩容判断+写) */
zvfs_spdk_blob_write_preread_cb(file, 0);
} else {
/*
* 先把涉及的扇区读出read 完成后在 preread_cb 里 patch 数据再写。
* 注意:把用户数据暂存在 file->write_buf / write_count
* 或者借用 file->io_countio_count 不变)。
* 这里我们把用户数据已经由上层调用者拷贝到了 write_staging_buf
*/
/* 不管是否需要扩容,先 preread */
spdk_blob_io_read(file->blob, file->fs->channel,
file->dma_buf,
lba, lba_count,
zvfs_spdk_blob_write_preread_cb, file);
}
}
/* Step 2 : preread 完成patch dma_buf然后决定是否扩容 */
@@ -393,11 +431,15 @@ void zvfs_spdk_blob_write_preread_cb(void *arg, int bserrno){
SPDK_DEBUGLOG("preread error %d (may be uninitialized, continue)\n", bserrno);
}
/* patch把用户数据覆写到 dma_buf 的正确偏移处 */
uint64_t page_off = file->current_offset % file->fs->io_unit_size;
memcpy((uint8_t *)file->dma_buf + page_off,
file->write_staging_buf,
file->io_count);
/* 只有非对齐情况才需要 patch对齐情况下数据已经在 dma_buf 里了do_write 里拷好的)*/
uint64_t io_unit = file->fs->io_unit_size;
if (!file->aligned) {
uint64_t page_off = file->current_offset % io_unit;
memcpy((uint8_t *)file->dma_buf + page_off,
file->write_staging_buf,
file->io_count);
}
/* 判断是否需要扩容 */
uint64_t end_byte = file->current_offset + file->io_count;
@@ -547,7 +589,6 @@ void zvfs_spdk_bs_unload_cb(void *arg, int bserrno) {
// setup
// zvfs.json
int zvfs_env_setup(void) {
struct spdk_env_opts opts;
spdk_env_opts_init(&opts);
@@ -572,10 +613,26 @@ int zvfs_env_setup(void) {
spdk_set_thread(global_thread);
bool done = false;
waiter(global_thread, zvfs_json_load_fn, &done, &done);
SPDK_DEBUGLOG("zvfs_env_setup complete\n");
int retry = 0;
while (retry < 200) { // 最多等 20 秒
spdk_thread_poll(global_thread, 0, 0);
if (spdk_bdev_get_by_name(ZVFS_BDEV) != NULL) {
SPDK_DEBUGLOG("bdev %s ready!\n", ZVFS_BDEV);
break;
}
usleep(100 * 1000); // 100ms
retry++;
}
if (spdk_bdev_get_by_name(ZVFS_BDEV) == NULL) {
SPDK_ERRLOG("bdev %s not found after 20s timeout!\n", ZVFS_BDEV);
return -1;
}
SPDK_DEBUGLOG("zvfs_env_setup complete\n");
return 0;
}
@@ -586,9 +643,12 @@ void zvfs_json_load_fn(void *arg) {
}
void json_app_load_done(int rc, void *ctx) {
bool *done = ctx;
*done = true;
SPDK_DEBUGLOG("json_app_load_done\n");
bool *done = ctx;
if (rc != 0) {
SPDK_ERRLOG("JSON config load FAILED! rc=%d\n", rc);
}
// 不要 sleep直接标记完成让外部 waiter 去轮询
*done = true;
}
@@ -600,14 +660,14 @@ void json_app_load_done(int rc, void *ctx) {
int zvfs_mount(struct zvfs_s *fs) {
fs->finished = false;
bool ok = waiter(global_thread, zvfs_do_mount, fs, &fs->finished);
SPDK_DEBUGLOG("mount finished\n");
if(!ok) SPDK_ERRLOG("mount result: ok=%d\n", ok);
return ok;
}
// unload
int zvfs_umount(struct zvfs_s *fs) {
fs->finished = false;
bool ok = waiter(global_thread, zvfs_do_umount, fs, &fs->finished);
SPDK_DEBUGLOG("umount finished\n");
if(!ok) SPDK_ERRLOG("umount result: ok=%d\n", ok);
return ok;
}
// file
@@ -615,14 +675,14 @@ int zvfs_umount(struct zvfs_s *fs) {
int zvfs_create(struct zvfs_file_s *file) {
file->finished = false;
bool ok = waiter(global_thread, zvfs_do_create, file, &file->finished);
SPDK_DEBUGLOG("create finished\n");
if(!ok) SPDK_ERRLOG("create result: ok=%d\n", ok);
return ok;
}
// open
int zvfs_open(struct zvfs_file_s *file) {
file->finished = false;
bool ok = waiter(global_thread, zvfs_do_open, file, &file->finished);
SPDK_DEBUGLOG("open finished\n");
if(!ok) SPDK_ERRLOG("open result: ok=%d\n", ok);
return ok;
}
// read
@@ -632,6 +692,7 @@ int zvfs_read(struct zvfs_file_s *file, uint8_t *buffer, size_t count) {
file->finished = false;
bool ok = waiter(global_thread, zvfs_do_read, file, &file->finished);
if(!ok) SPDK_ERRLOG("read result: ok=%d\n", ok);
if (!ok || file->actual_io_count == 0) return -1;
/*
@@ -649,7 +710,6 @@ int zvfs_read(struct zvfs_file_s *file, uint8_t *buffer, size_t count) {
(uint8_t *)file->dma_buf + page_off,
file->actual_io_count);
SPDK_DEBUGLOG("read finished\n");
return (int)file->actual_io_count;
}
// write
@@ -659,21 +719,21 @@ int zvfs_write(struct zvfs_file_s *file, const uint8_t *buffer, size_t count) {
file->finished = false;
bool ok = waiter(global_thread, zvfs_do_write, file, &file->finished);
SPDK_DEBUGLOG("write finished\n");
if(!ok) SPDK_ERRLOG("write result: ok=%d\n", ok);
return ok ? (int)count : -1;
}
// close
int zvfs_close(struct zvfs_file_s *file) {
file->finished = false;
bool ok = waiter(global_thread, zvfs_do_close, file, &file->finished);
SPDK_DEBUGLOG("close finished\n");
if(!ok) SPDK_ERRLOG("close result: ok=%d\n", ok);
return ok;
}
// delete
int zvfs_delete(struct zvfs_file_s *file) {
file->finished = false;
bool ok = waiter(global_thread, zvfs_do_delete, file, &file->finished);
SPDK_DEBUGLOG("delete finished\n");
if(!ok) SPDK_ERRLOG("delete result: ok=%d\n", ok);
return ok;
}