Files
zvfs/zvfs/zvfs.c

1136 lines
32 KiB
C
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "zvfs.h"
#include <errno.h>
#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/zvfs.json";
// mount
void zvfs_do_mount(void *arg);
void zvfs_spdk_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx);
void zvfs_spdk_bs_load_cb(void *arg, struct spdk_blob_store *bs, int bserrno);
void zvfs_spdk_bs_init_cb(void *arg, struct spdk_blob_store *bs, int bserrno);
// create
void zvfs_do_create(void *arg);
void zvfs_spdk_bs_create_blob_cb(void *arg, spdk_blob_id blobid, int bserrno);
void zvfs_spdk_bs_open_blob_cb(void *arg, struct spdk_blob *blb, int bserrno);
void zvfs_spdk_blob_resize_cb(void *arg, int bserrno);
void zvfs_spdk_blob_sync_cb(void *arg, int bserrno);
// open
void zvfs_do_open(void *arg);
void zvfs_spdk_bs_open_blob_cb2(void *arg, struct spdk_blob *blb, int bserrno);
// read
void zvfs_do_read(void *arg);
void zvfs_spdk_blob_read_cb(void *arg, int bserrno);
// write
void zvfs_do_write(void *arg);
void zvfs_do_write_io(zvfs_io_req_t *req);
void zvfs_spdk_blob_write_preread_cb(void *arg, int bserrno);
void zvfs_spdk_blob_write_resize_cb(void *arg, int bserrno);
void zvfs_spdk_blob_write_sync_cb(void *arg, int bserrno);
void zvfs_spdk_blob_write_cb(void *arg, int bserrno);
// close
void zvfs_do_close(void *arg);
void zvfs_spdk_blob_close_cb(void *arg, int bserrno);
void zvfs_spdk_blob_open_fail_close_cb(void *arg, int bserrno);
// delete
void zvfs_do_delete(void *arg);
void zvfs_spdk_blob_delete_cb(void *arg, int bserrno);
// setup
void zvfs_json_load_fn(void *arg);
void json_app_load_done(int rc, void *ctx);
// unmount
void zvfs_do_umount(void *arg);
void zvfs_spdk_bs_unload_cb(void *arg, int bserrno);
static int zvfs_submit_io_req(zvfs_io_req_t *req, spdk_msg_fn submit_fn, const char *op_name);
static int zvfs_pread_internal(zvfs_io_req_t *req);
static int zvfs_pwrite_internal(zvfs_io_req_t *req);
/* ================================================================== */
/* HELPER */
/* ================================================================== */
static uint64_t zvfs_need_clusters(zvfs_t *fs, uint64_t end_byte) {
uint64_t cluster_size = spdk_bs_get_cluster_size(fs->bs);
return (end_byte + cluster_size - 1) / cluster_size;
}
/* ---------- 辅助:计算本次 IO 涉及的 LBA 范围 ---------- */
static void calc_lba_range(zvfs_io_req_t *req)
{
uint64_t io_unit = req->file->fs->io_unit_size;
uint64_t off = req->offset;
uint64_t cnt = req->len;
req->lba = off / io_unit;
req->page_off = off % io_unit;
req->lba_count = (req->page_off + cnt + io_unit - 1) / io_unit;
}
/* ---------- 确保 dma_buf 足够大 ---------- */
static int ensure_dma_buf(zvfs_file_t *file, uint64_t need_bytes)
{
if (file->dma_buf && file->dma_buf_size >= need_bytes) return 0;
if (file->dma_buf) spdk_free(file->dma_buf);
file->dma_buf = spdk_malloc(need_bytes, 0x1000, NULL,
SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
if (!file->dma_buf) { file->dma_buf_size = 0; return -1; }
file->dma_buf_size = need_bytes;
return 0;
}
static inline int zvfs_err_from_bserrno(int bserrno)
{
return bserrno != 0 ? bserrno : -EIO;
}
// waiter
bool waiter(struct spdk_thread *thread, spdk_msg_fn start_fn, void *ctx, bool *finished) {
if (thread == NULL || start_fn == NULL || finished == NULL) {
return false;
}
spdk_thread_send_msg(thread, start_fn, ctx);
int waiter_count = 0;
do {
spdk_thread_poll(thread, 0, 0);
waiter_count ++;
} while(!(*finished) && waiter_count < WAITER_MAX_TIME);
if (!(*finished) && waiter_count >= WAITER_MAX_TIME) {
return false; // timeout
}
return true;
}
static int zvfs_submit_io_req(zvfs_io_req_t *req, spdk_msg_fn submit_fn, const char *op_name)
{
if (req == NULL || submit_fn == NULL || global_thread == NULL) {
return -1;
}
req->op_errno = 0;
req->result = 0;
req->finished = false;
if (req->file != NULL) {
req->file->op_errno = 0;
}
bool ok = waiter(global_thread, submit_fn, req, &req->finished);
if (!ok) {
SPDK_ERRLOG("%s result: ok=%d\n", op_name, ok);
if (req->file != NULL) {
req->file->op_errno = -EIO;
}
return -1;
}
if (req->op_errno != 0) {
if (req->file != NULL) {
req->file->op_errno = req->op_errno;
}
return -1;
}
return (int)req->result;
}
static int zvfs_pread_internal(zvfs_io_req_t *req)
{
return zvfs_submit_io_req(req, zvfs_do_read, "pread");
}
static int zvfs_pwrite_internal(zvfs_io_req_t *req)
{
return zvfs_submit_io_req(req, zvfs_do_write, "pwrite");
}
/* ================================================================== */
/* MOUNT */
/* ================================================================== */
void zvfs_do_mount(void *arg) {
zvfs_t *fs = (zvfs_t*)arg;
struct spdk_bs_dev *bs_dev = NULL;
if (fs == NULL) {
return;
}
fs->op_errno = 0;
// 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_ERRLOG("=== bdev_open FAILED rc=%d (probably still not registered) ===\n", rc);
fs->op_errno = rc;
fs->finished = true;
return;
}
fs->bs_dev = bs_dev;
fs->bs_dev_owned = true;
spdk_bs_load(bs_dev, NULL, zvfs_spdk_bs_load_cb, fs);
fs->bs_dev_owned = false;
}
void zvfs_spdk_bs_load_cb(void *arg, struct spdk_blob_store *bs, int bserrno) {
zvfs_t *fs = (zvfs_t*)arg;
if (fs == NULL) {
return;
}
if (bserrno == 0 && bs == NULL) {
fs->op_errno = -EIO;
fs->finished = true;
return;
}
if (bserrno != 0) {
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(ZVFS_BDEV, zvfs_spdk_bdev_event_cb, NULL, &bs_dev);
if (rc != 0) {
SPDK_ERRLOG("re-create bs_dev failed\n");
fs->op_errno = rc;
fs->finished = true;
return;
}
fs->bs_dev = bs_dev;
fs->bs_dev_owned = true;
spdk_bs_init(fs->bs_dev, NULL, zvfs_spdk_bs_init_cb, fs);
fs->bs_dev_owned = false;
return;
}
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);
if (fs->channel == NULL) {
fs->op_errno = -ENOMEM;
fs->finished = true;
return ;
}
fs->finished = true;
}
void zvfs_spdk_bs_init_cb(void *arg, struct spdk_blob_store *bs, int bserrno) {
zvfs_t *fs = (zvfs_t*)arg;
if (fs == NULL) {
return;
}
if (bserrno != 0 || bs == NULL) {
fs->op_errno = zvfs_err_from_bserrno(bserrno);
fs->finished = true;
return;
}
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);
if (fs->channel == NULL) {
fs->op_errno = -ENOMEM;
fs->finished = true;
return ;
}
fs->finished = true;
}
void zvfs_spdk_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
void *event_ctx) {
}
/* ================================================================== */
/* CREATE */
/* ================================================================== */
void zvfs_do_create(void *arg) {
zvfs_file_t *file = (zvfs_file_t *)arg;
if (file == NULL || file->fs == NULL || file->fs->bs == NULL) {
if (file != NULL) {
file->op_errno = -EINVAL;
file->finished = true;
}
return;
}
file->op_errno = 0;
spdk_bs_create_blob(file->fs->bs, zvfs_spdk_bs_create_blob_cb, file);
}
void zvfs_spdk_bs_create_blob_cb(void *arg, spdk_blob_id blobid, int bserrno) {
zvfs_file_t *file = (zvfs_file_t *)arg;
if (file == NULL) {
return;
}
if (bserrno != 0) {
file->op_errno = zvfs_err_from_bserrno(bserrno);
file->finished = true;
return;
}
file->blob_id = blobid;
SPDK_DEBUGLOG("create blobid : %"PRIu64"\n", blobid);
spdk_bs_open_blob(file->fs->bs, blobid, zvfs_spdk_bs_open_blob_cb, file);
}
void zvfs_spdk_bs_open_blob_cb(void *arg, struct spdk_blob *blb, int bserrno) {
zvfs_file_t *file = (zvfs_file_t *)arg;
if (bserrno) {
SPDK_ERRLOG("load blob error: %d\n", bserrno);
file->op_errno = zvfs_err_from_bserrno(bserrno);
file->finished = true;
return;
}
if (blb == NULL) {
file->op_errno = -EIO;
file->finished = true;
return;
}
file->blob = blb;
uint64_t free_cluster = spdk_bs_free_cluster_count(file->fs->bs);
if(free_cluster == 0){
SPDK_ERRLOG("no free cluster: %d\n", bserrno);
file->op_errno = -ENOSPC;
file->finished = true;
return ;
}
spdk_blob_resize(blb, 1, zvfs_spdk_blob_resize_cb, file);
}
void zvfs_spdk_blob_resize_cb(void *arg, int bserrno) {
zvfs_file_t *file = (zvfs_file_t *)arg;
if (file == NULL) {
return;
}
if (bserrno != 0) {
file->op_errno = zvfs_err_from_bserrno(bserrno);
file->finished = true;
return;
}
uint64_t total = spdk_blob_get_num_clusters(file->blob);
SPDK_DEBUGLOG("resize blob :%"PRIu64"\n", total);
if (file->dirent) {
file->dirent->allocated_clusters = total;
}
spdk_blob_sync_md(file->blob, zvfs_spdk_blob_sync_cb, file);
}
void zvfs_spdk_blob_sync_cb(void *arg, int bserrno) {
zvfs_file_t *file = (zvfs_file_t *)arg;
if (file == NULL) {
return;
}
if (bserrno != 0) {
file->op_errno = zvfs_err_from_bserrno(bserrno);
file->finished = true;
return;
}
file->dma_buf = spdk_malloc(BUFFER_SIZE, 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
if (file->dma_buf == NULL) {
SPDK_ERRLOG("spdk_malloc failed\n");
file->op_errno = -ENOMEM;
spdk_blob_close(file->blob, zvfs_spdk_blob_open_fail_close_cb, file);
return ;
}
file->dma_buf_size = BUFFER_SIZE;
file->finished = true;
}
/* ================================================================== */
/* OPEN */
/* ================================================================== */
void zvfs_do_open(void *arg) {
zvfs_file_t *file = (zvfs_file_t *)arg;
if (file == NULL || file->fs == NULL || file->fs->bs == NULL) {
if (file != NULL) {
file->op_errno = -EINVAL;
file->finished = true;
}
return;
}
file->op_errno = 0;
spdk_bs_open_blob(file->fs->bs, file->blob_id, zvfs_spdk_bs_open_blob_cb2, file);
}
void zvfs_spdk_bs_open_blob_cb2(void *arg, struct spdk_blob *blb, int bserrno) {
zvfs_file_t *file = (zvfs_file_t *)arg;
if (bserrno) {
SPDK_ERRLOG("load blob error: %d\n", bserrno);
file->op_errno = zvfs_err_from_bserrno(bserrno);
file->finished = true;
return;
}
if (blb == NULL) {
file->op_errno = -EIO;
file->finished = true;
return;
}
file->blob = blb;
file->dma_buf = spdk_malloc(BUFFER_SIZE, 0x1000, NULL,
SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
if (!file->dma_buf) {
SPDK_ERRLOG("spdk_malloc failed\n");
file->op_errno = -ENOMEM;
spdk_blob_close(file->blob, zvfs_spdk_blob_open_fail_close_cb, file);
return;
}
file->dma_buf_size = BUFFER_SIZE;
file->finished = true;
}
/* ================================================================== */
/* READ */
/* ================================================================== */
void zvfs_do_read(void *arg) {
zvfs_io_req_t *req = (zvfs_io_req_t *)arg;
zvfs_file_t *file = req ? req->file : NULL;
if (req == NULL || file == NULL || file->fs == NULL || file->blob == NULL ||
file->fs->channel == NULL || req->buf == NULL) {
if (req != NULL) {
req->op_errno = -EINVAL;
req->result = 0;
req->finished = true;
}
return;
}
req->op_errno = 0;
if (req->len == 0) {
req->result = 0;
req->finished = true;
return;
}
uint64_t io_unit = file->fs->io_unit_size;
if (io_unit == 0) {
req->op_errno = -EIO;
req->result = 0;
req->finished = true;
return;
}
uint64_t file_sz = file->dirent ? file->dirent->file_size : 0;
if (req->offset >= file_sz) {
SPDK_DEBUGLOG("read: EOF\n");
req->result = 0;
req->finished = true;
return;
}
if (req->offset + req->len > file_sz) {
req->len = file_sz - req->offset;
}
req->result = req->len;
calc_lba_range(req);
uint64_t buf_need = req->lba_count * io_unit;
if (ensure_dma_buf(file, buf_need) != 0) {
SPDK_ERRLOG("ensure_dma_buf failed\n");
req->op_errno = -ENOMEM;
req->result = 0;
req->finished = true;
return;
}
spdk_blob_io_read(file->blob, file->fs->channel,
file->dma_buf,
req->lba, req->lba_count,
zvfs_spdk_blob_read_cb, req);
}
void zvfs_spdk_blob_read_cb(void *arg, int bserrno) {
zvfs_io_req_t *req = (zvfs_io_req_t *)arg;
zvfs_file_t *file = req ? req->file : NULL;
if (req == NULL || file == NULL) {
return;
}
if (bserrno) {
SPDK_ERRLOG("blob_read error: %d\n", bserrno);
req->op_errno = zvfs_err_from_bserrno(bserrno);
req->result = 0;
req->finished = true;
return;
}
memcpy(req->buf,
(uint8_t *)file->dma_buf + req->page_off,
req->result);
SPDK_DEBUGLOG("read complete, offset=%" PRIu64 " len=%zu\n", req->offset, req->result);
req->finished = true;
}
/* ================================================================== */
/* WRITE */
/* ================================================================== */
/**
* 1. write 的 callback 链
* zvfs_do_write
* └─→ 先用 spdk_blob_io_read 读出覆盖范围内的扇区
* └─→ zvfs_spdk_blob_write_preread_cb
* (在 dma_buf 里 patch 新数据)
* ├─(需扩容)─→ spdk_blob_resize
* │ └─→ zvfs_spdk_blob_write_resize_cb
* │ └─→ spdk_blob_sync_md
* │ └─→ zvfs_spdk_blob_write_sync_cb
* │ └─→ zvfs_do_write_io
* │ └─→ zvfs_spdk_blob_write_cb
* └─(不需扩容)─→ zvfs_do_write_io
* └─→ zvfs_spdk_blob_write_cb
*/
/* Step 1 : 进入 write先把覆盖范围内的扇区读出来read-modify-write) */
void zvfs_do_write(void *arg) {
zvfs_io_req_t *req = (zvfs_io_req_t *)arg;
zvfs_file_t *file = req ? req->file : NULL;
if (req == NULL || file == NULL || file->fs == NULL || file->blob == NULL ||
file->fs->channel == NULL) {
if (req != NULL) {
req->op_errno = -EINVAL;
req->finished = true;
}
return;
}
if (req->buf == NULL && req->len != 0) {
req->op_errno = -EINVAL;
req->finished = true;
return;
}
if (req->len == 0) {
req->result = 0;
req->finished = true;
return;
}
req->op_errno = 0;
uint64_t io_unit = file->fs->io_unit_size;
if (io_unit == 0) {
req->op_errno = -EIO;
req->finished = true;
return;
}
calc_lba_range(req);
uint64_t buf_need = req->lba_count * io_unit;
if (ensure_dma_buf(file, buf_need) != 0) {
SPDK_ERRLOG("ensure_dma_buf failed\n");
req->op_errno = -ENOMEM;
req->finished = true;
return;
}
req->aligned = (req->offset % io_unit == 0) &&
(req->len % io_unit == 0);
if (req->aligned) {
memcpy(file->dma_buf, req->buf, req->len);
zvfs_spdk_blob_write_preread_cb(req, 0);
} else {
spdk_blob_io_read(file->blob, file->fs->channel,
file->dma_buf,
req->lba, req->lba_count,
zvfs_spdk_blob_write_preread_cb, req);
}
}
/* Step 2 : preread 完成patch dma_buf然后决定是否扩容 */
void zvfs_spdk_blob_write_preread_cb(void *arg, int bserrno){
zvfs_io_req_t *req = (zvfs_io_req_t *)arg;
zvfs_file_t *file = req ? req->file : NULL;
if (req == NULL || file == NULL) {
return;
}
uint64_t io_unit = file->fs->io_unit_size;
if (io_unit == 0) {
req->op_errno = -EIO;
req->finished = true;
return;
}
/* preread 失败也没关系——如果是新分配区域全零即可,
这里仍然继续SPDK 对未写过的区域返回全零)。*/
if (bserrno) {
SPDK_DEBUGLOG("preread error %d (may be uninitialized, continue)\n", bserrno);
memset(file->dma_buf, 0, req->lba_count * io_unit);
}
/* 只有非对齐情况才需要 patch对齐情况下数据已经在 dma_buf 里了do_write 里拷好的)*/
if (!req->aligned) {
memcpy((uint8_t *)file->dma_buf + req->page_off,
req->buf,
req->len);
}
/*
* 稀疏写语义:当写偏移超过旧 EOF 时gap 区间应当读为 0。
* 这里至少把本次覆盖到的页内 gap 清零,避免把底层旧数据带入新文件逻辑范围。
*/
uint64_t old_eof = file->dirent ? file->dirent->file_size : 0;
if (req->offset > old_eof) {
uint64_t page_start = req->lba * io_unit;
uint64_t page_end = page_start + req->lba_count * io_unit;
uint64_t zero_start = old_eof > page_start ? old_eof : page_start;
uint64_t zero_end = req->offset < page_end ? req->offset : page_end;
if (zero_end > zero_start) {
memset((uint8_t *)file->dma_buf + (zero_start - page_start), 0,
zero_end - zero_start);
}
}
/* 判断是否需要扩容 */
uint64_t end_byte = req->offset + req->len;
uint64_t need_clusters = zvfs_need_clusters(file->fs, end_byte);
uint64_t cur_clusters = file->dirent ? file->dirent->allocated_clusters
: spdk_blob_get_num_clusters(file->blob);
if (need_clusters > cur_clusters) {
uint64_t free_clusters = spdk_bs_free_cluster_count(file->fs->bs);
if (need_clusters - cur_clusters > free_clusters) {
SPDK_ERRLOG("no free clusters\n");
req->op_errno = -ENOSPC;
req->finished = true;
return;
}
spdk_blob_resize(file->blob, need_clusters,
zvfs_spdk_blob_write_resize_cb, req);
} else {
zvfs_do_write_io(req);
}
}
/* Step 3a : resize 完成 → sync */
void zvfs_spdk_blob_write_resize_cb(void *arg, int bserrno) {
zvfs_io_req_t *req = (zvfs_io_req_t *)arg;
zvfs_file_t *file = req ? req->file : NULL;
if (req == NULL || file == NULL) {
return;
}
if (bserrno) {
SPDK_ERRLOG("write resize error: %d\n", bserrno);
req->op_errno = zvfs_err_from_bserrno(bserrno);
req->finished = true;
return;
}
spdk_blob_sync_md(file->blob, zvfs_spdk_blob_write_sync_cb, req);
}
/* Step 3b : sync 完成 → 真正写 */
void zvfs_spdk_blob_write_sync_cb(void *arg, int bserrno) {
zvfs_io_req_t *req = (zvfs_io_req_t *)arg;
zvfs_file_t *file = req ? req->file : NULL;
if (req == NULL || file == NULL) {
return;
}
if (bserrno) {
SPDK_ERRLOG("write sync error: %d\n", bserrno);
req->op_errno = zvfs_err_from_bserrno(bserrno);
req->finished = true;
return;
}
if (file->dirent) {
file->dirent->allocated_clusters =
(uint32_t)spdk_blob_get_num_clusters(file->blob);
}
zvfs_do_write_io(req);
}
/* Step 4 : 实际写入dma_buf 已经是 patch 后的整扇区数据) */
void zvfs_do_write_io(zvfs_io_req_t *req) {
zvfs_file_t *file = req ? req->file : NULL;
if (req == NULL || file == NULL || file->fs == NULL) {
return;
}
uint64_t io_unit_size = file->fs->io_unit_size;
if (io_unit_size == 0) {
req->op_errno = -EIO;
req->finished = true;
return;
}
uint64_t lba_count = (req->page_off + req->len + io_unit_size - 1) / io_unit_size;
spdk_blob_io_write(file->blob, file->fs->channel,
file->dma_buf,
req->lba, lba_count,
zvfs_spdk_blob_write_cb, req);
}
/* Step 5 : 写完成 */
void zvfs_spdk_blob_write_cb(void *arg, int bserrno) {
zvfs_io_req_t *req = (zvfs_io_req_t *)arg;
zvfs_file_t *file = req ? req->file : NULL;
if (req == NULL || file == NULL) {
return;
}
if (bserrno) {
SPDK_ERRLOG("blob_write error: %d\n", bserrno);
req->op_errno = zvfs_err_from_bserrno(bserrno);
req->finished = true;
return;
}
uint64_t new_end = req->offset + req->len;
if (file->dirent && new_end > file->dirent->file_size) {
file->dirent->file_size = new_end;
}
req->result = req->len;
SPDK_DEBUGLOG("write complete, offset=%" PRIu64 " len=%zu\n", req->offset, req->result);
req->finished = true;
}
/* ================================================================== */
/* CLOSE */
/* ================================================================== */
void zvfs_do_close(void *arg) {
zvfs_file_t *file = (zvfs_file_t *)arg;
if (file == NULL) {
return;
}
file->op_errno = 0;
if (file->blob == NULL) {
file->finished = true;
return;
}
spdk_blob_close(file->blob, zvfs_spdk_blob_close_cb, file);
}
void zvfs_spdk_blob_open_fail_close_cb(void *arg, int bserrno)
{
zvfs_file_t *file = (zvfs_file_t *)arg;
if (file == NULL) {
return;
}
if (bserrno) {
SPDK_ERRLOG("blob_close after open/create failure error: %d\n", bserrno);
if (file->op_errno == 0) {
file->op_errno = zvfs_err_from_bserrno(bserrno);
}
}
file->blob = NULL;
file->finished = true;
}
void zvfs_spdk_blob_close_cb(void *arg, int bserrno) {
zvfs_file_t *file = (zvfs_file_t *)arg;
if (bserrno) {
SPDK_ERRLOG("blob_close error: %d\n", bserrno);
file->op_errno = zvfs_err_from_bserrno(bserrno);
}
spdk_free(file->dma_buf);
file->dma_buf = NULL;
file->blob = NULL;
file->current_offset = 0;
file->finished = true;
}
/* ================================================================== */
/* DELETE */
/* ================================================================== */
void zvfs_do_delete(void *arg) {
zvfs_file_t *file = (zvfs_file_t *)arg;
if (file == NULL || file->fs == NULL || file->fs->bs == NULL) {
if (file != NULL) {
file->op_errno = -EINVAL;
file->finished = true;
}
return;
}
file->op_errno = 0;
spdk_bs_delete_blob(file->fs->bs, file->blob_id, zvfs_spdk_blob_delete_cb, file);
}
void zvfs_spdk_blob_delete_cb(void *arg, int bserrno) {
zvfs_file_t *file = (zvfs_file_t *)arg;
if (bserrno) {
SPDK_ERRLOG("blob_delete error: %d\n", bserrno);
file->op_errno = zvfs_err_from_bserrno(bserrno);
}
file->finished = true;
}
/* ================================================================== */
/* UNMOUNT */
/* ================================================================== */
void zvfs_do_umount(void *arg) {
zvfs_t *fs = (zvfs_t *)arg;
if (fs == NULL) {
return;
}
fs->op_errno = 0;
if (fs->bs) {
if (fs->channel) {
spdk_bs_free_io_channel(fs->channel);
fs->channel = NULL;
}
spdk_bs_unload(fs->bs, zvfs_spdk_bs_unload_cb, fs);
return;
}
if (fs->bs_dev && fs->bs_dev_owned) {
fs->bs_dev->destroy(fs->bs_dev);
fs->bs_dev = NULL;
fs->bs_dev_owned = false;
}
fs->finished = true;
}
void zvfs_spdk_bs_unload_cb(void *arg, int bserrno) {
zvfs_t *fs = (zvfs_t *)arg;
if (fs == NULL) {
return;
}
if (bserrno != 0) {
fs->op_errno = zvfs_err_from_bserrno(bserrno);
}
fs->bs = NULL;
fs->bs_dev = NULL;
fs->bs_dev_owned = false;
fs->finished = true;
}
// setup
// zvfs.json
int zvfs_env_setup(void) {
struct spdk_env_opts opts;
spdk_env_opts_init(&opts);
opts.name = "zvfs";
int rc = spdk_env_init(&opts);
if (rc != 0) {
return -1;
}
spdk_log_set_print_level(SPDK_LOG_ERROR);
spdk_log_set_level(SPDK_LOG_NOTICE);
spdk_log_open(NULL);
int rc2 = spdk_thread_lib_init(NULL, 0);
if (rc2 != 0) {
SPDK_ERRLOG("spdk_thread_lib_init failed\n");
return -1;
}
global_thread = spdk_thread_create("global", NULL);
if (global_thread == NULL) {
SPDK_ERRLOG("spdk_thread_create failed\n");
return -1;
}
spdk_set_thread(global_thread);
bool done = false;
if (!waiter(global_thread, zvfs_json_load_fn, &done, &done) || !done) {
SPDK_ERRLOG("json load waiter timeout\n");
return -1;
}
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;
}
void zvfs_json_load_fn(void *arg) {
spdk_subsystem_init_from_json_config(json_file, SPDK_DEFAULT_RPC_ADDR, json_app_load_done,
arg, true);
}
void json_app_load_done(int rc, void *ctx) {
bool *done = ctx;
if (rc != 0) {
SPDK_ERRLOG("JSON config load FAILED! rc=%d\n", rc);
}
// 不要 sleep直接标记完成让外部 waiter 去轮询
*done = true;
}
// filesystem
// load
int zvfs_mount(struct zvfs_s *fs) {
if (fs == NULL || global_thread == NULL) {
return 0;
}
fs->op_errno = 0;
fs->finished = false;
bool ok = waiter(global_thread, zvfs_do_mount, fs, &fs->finished);
if(!ok) SPDK_ERRLOG("mount result: ok=%d\n", ok);
return ok && fs->op_errno == 0;
}
// unload
int zvfs_umount(struct zvfs_s *fs) {
if (fs == NULL || global_thread == NULL) {
return 0;
}
fs->op_errno = 0;
fs->finished = false;
bool ok = waiter(global_thread, zvfs_do_umount, fs, &fs->finished);
if(!ok) SPDK_ERRLOG("umount result: ok=%d\n", ok);
return ok && fs->op_errno == 0;
}
// file
// create
int zvfs_create(struct zvfs_file_s *file) {
if (file == NULL || global_thread == NULL) {
return 0;
}
file->op_errno = 0;
file->finished = false;
bool ok = waiter(global_thread, zvfs_do_create, file, &file->finished);
if(!ok) SPDK_ERRLOG("create result: ok=%d\n", ok);
return ok && file->op_errno == 0;
}
// open
int zvfs_open(struct zvfs_file_s *file) {
if (file == NULL || global_thread == NULL) {
return 0;
}
file->op_errno = 0;
file->finished = false;
bool ok = waiter(global_thread, zvfs_do_open, file, &file->finished);
if(!ok) SPDK_ERRLOG("open result: ok=%d\n", ok);
return ok && file->op_errno == 0;
}
// read
int zvfs_read(struct zvfs_file_s *file, uint8_t *buffer, size_t count) {
if (file == NULL || buffer == NULL || global_thread == NULL) {
return -1;
}
if (count == 0) {
return 0;
}
zvfs_io_req_t req = {
.file = file,
.op = ZVFS_IO_READ,
.buf = buffer,
.len = count,
.offset = file->current_offset,
.flags = 0,
};
int rc = zvfs_pread_internal(&req);
if (rc > 0) {
file->current_offset += (uint64_t)rc;
}
return rc;
}
// write
int zvfs_write(struct zvfs_file_s *file, const uint8_t *buffer, size_t count) {
if (file == NULL || global_thread == NULL) {
return -1;
}
zvfs_io_req_t req = {
.file = file,
.op = ZVFS_IO_WRITE,
.buf = (uint8_t *)buffer,
.len = count,
.offset = file->current_offset,
.flags = 0,
};
int rc = zvfs_pwrite_internal(&req);
if (rc > 0) {
file->current_offset += (uint64_t)rc;
}
return rc;
}
int zvfs_pread(struct zvfs_file_s *file, uint8_t *buffer, size_t count, uint64_t offset)
{
if (file == NULL || buffer == NULL || global_thread == NULL) {
return -1;
}
if (count == 0) {
return 0;
}
zvfs_io_req_t req = {
.file = file,
.op = ZVFS_IO_READ,
.buf = buffer,
.len = count,
.offset = offset,
.flags = 0,
};
return zvfs_pread_internal(&req);
}
int zvfs_pwrite(struct zvfs_file_s *file, const uint8_t *buffer, size_t count, uint64_t offset)
{
if (file == NULL || global_thread == NULL) {
return -1;
}
zvfs_io_req_t req = {
.file = file,
.op = ZVFS_IO_WRITE,
.buf = (uint8_t *)buffer,
.len = count,
.offset = offset,
.flags = 0,
};
return zvfs_pwrite_internal(&req);
}
// close
int zvfs_close(struct zvfs_file_s *file) {
if (file == NULL || global_thread == NULL) {
return 0;
}
file->op_errno = 0;
file->finished = false;
bool ok = waiter(global_thread, zvfs_do_close, file, &file->finished);
if(!ok) SPDK_ERRLOG("close result: ok=%d\n", ok);
return ok && file->op_errno == 0;
}
// delete
int zvfs_delete(struct zvfs_file_s *file) {
if (file == NULL || global_thread == NULL) {
return 0;
}
file->op_errno = 0;
file->finished = false;
bool ok = waiter(global_thread, zvfs_do_delete, file, &file->finished);
if(!ok) SPDK_ERRLOG("delete result: ok=%d\n", ok);
return ok && file->op_errno == 0;
}
// int main(int argc, char *argv[]) {
// if (zvfs_env_setup()) {
// return -1;
// }
// SPDK_NOTICELOG("zvfs_env_setup success\n");
// SPDK_NOTICELOG("\n\n zvfs mount start \n\n");
// zvfs_t *fs = calloc(1, sizeof(zvfs_t));
// zvfs_mount(fs);
// SPDK_NOTICELOG("\n\n zvfs open start \n\n");
// zvfs_file_t *file = calloc(1, sizeof(zvfs_file_t));
// file->fs = fs;
// zvfs_dirent_t *dirent = calloc(1, sizeof(zvfs_dirent_t));
// file->dirent = dirent;
// zvfs_create(file);
// SPDK_NOTICELOG("\n\n zvfs write start \n\n");
// char *buffer = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// zvfs_write(file, buffer, strlen(buffer));
// char *buffer2 = "abcdefghijklmnopqrstuvwxyz";
// zvfs_write(file, buffer2, strlen(buffer2));
// SPDK_NOTICELOG("\n\n zvfs read start \n\n");
// file->current_offset = 0;
// char rbuffer[BUFFER_SIZE] = {0};
// int n = zvfs_read(file, rbuffer, BUFFER_SIZE);
// SPDK_NOTICELOG("READ BUFFER:%d, %s\n", n, rbuffer);
// SPDK_NOTICELOG("\n\n zvfs close start \n\n");
// zvfs_close(file);
// SPDK_NOTICELOG("\n\n zvfs delete start \n\n");
// zvfs_delete(file);
// free(dirent);
// free(file);
// SPDK_NOTICELOG("\n\n zvfs umount start \n\n");
// zvfs_umount(fs);
// free(fs);
// }