359 lines
9.3 KiB
C
359 lines
9.3 KiB
C
#include "zvfs.h"
|
||
|
||
#include <sys/types.h>
|
||
#include <sys/stat.h>
|
||
#include <fcntl.h>
|
||
#include <unistd.h>
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
#include <errno.h>
|
||
|
||
/* ------------------------------------------------------------------ */
|
||
/* 全局状态 */
|
||
/* ------------------------------------------------------------------ */
|
||
|
||
static zvfs_t *g_fs = NULL; /* 全局文件系统,NULL 表示未初始化 */
|
||
static bool g_mounted = false;
|
||
|
||
/* 元数据文件路径 */
|
||
static const char *META_FILE = "/home/lian/share/10.1-spdk/zvfs/zvfs_meta.txt";
|
||
|
||
/* 伪 fd 起始值,避免和真实 fd 冲突 */
|
||
#define FD_BASE 1000
|
||
|
||
|
||
/* ------------------------------------------------------------------ */
|
||
/* 元数据文件 I/O */
|
||
/* ------------------------------------------------------------------ */
|
||
|
||
/*
|
||
* 格式:每行一条记录,字段用空格分隔
|
||
* filename blob_id file_size allocated_clusters
|
||
*
|
||
* 例:
|
||
* hello.txt 4294967296 26 1
|
||
*/
|
||
|
||
static int meta_load(zvfs_t *fs) {
|
||
int fd = open(META_FILE, O_RDONLY);
|
||
if (fd < 0) {
|
||
/* 文件不存在,当作空目录 */
|
||
fs->dirent_count = 0;
|
||
return 0;
|
||
}
|
||
|
||
/* 一次性读进来 */
|
||
char buf[4096] = {0};
|
||
ssize_t n = read(fd, buf, sizeof(buf) - 1);
|
||
close(fd);
|
||
if (n <= 0) return 0;
|
||
|
||
char *line = buf;
|
||
while (*line) {
|
||
/* 找行尾 */
|
||
char *nl = strchr(line, '\n');
|
||
if (nl) *nl = '\0';
|
||
|
||
if (*line == '\0') {
|
||
line = nl ? nl + 1 : line + strlen(line);
|
||
continue;
|
||
}
|
||
|
||
if (fs->dirent_count >= ZVFS_MAX_FILES) break;
|
||
|
||
zvfs_dirent_t *d = calloc(1, sizeof(zvfs_dirent_t));
|
||
if (!d) break;
|
||
|
||
int ret = sscanf(line, "%255s %"PRIu64" %"PRIu64" %"PRIu32,
|
||
d->filename,
|
||
&d->blob_id,
|
||
&d->file_size,
|
||
&d->allocated_clusters);
|
||
if (ret == 4) {
|
||
d->is_valid = true;
|
||
d->open_count = 0;
|
||
fs->dirents[fs->dirent_count++] = d;
|
||
} else {
|
||
free(d);
|
||
}
|
||
|
||
line = nl ? nl + 1 : line + strlen(line);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int meta_save(zvfs_t *fs) {
|
||
int fd = open(META_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||
if (fd < 0) return -1;
|
||
|
||
for (uint32_t i = 0; i < fs->dirent_count; i++) {
|
||
zvfs_dirent_t *d = fs->dirents[i];
|
||
if (!d || !d->is_valid) continue;
|
||
|
||
char line[512];
|
||
int len = snprintf(line, sizeof(line), "%s %"PRIu64" %"PRIu64" %"PRIu32"\n",
|
||
d->filename, d->blob_id, d->file_size, d->allocated_clusters);
|
||
write(fd, line, len);
|
||
}
|
||
|
||
close(fd);
|
||
return 0;
|
||
}
|
||
|
||
|
||
/* ------------------------------------------------------------------ */
|
||
/* 初始化(第一次 open 时调用) */
|
||
/* ------------------------------------------------------------------ */
|
||
|
||
static int zvfs_ensure_mounted(void) {
|
||
if (g_mounted) return 0;
|
||
|
||
g_fs = calloc(1, sizeof(zvfs_t));
|
||
if (!g_fs) return -1;
|
||
|
||
g_fs->fd_base = FD_BASE;
|
||
|
||
/* 加载元数据 */
|
||
if (meta_load(g_fs) != 0) {
|
||
free(g_fs);
|
||
g_fs = NULL;
|
||
return -1;
|
||
}
|
||
|
||
/* 初始化 SPDK 环境并 mount */
|
||
if (zvfs_env_setup() != 0) {
|
||
free(g_fs);
|
||
g_fs = NULL;
|
||
return -1;
|
||
}
|
||
|
||
if (!zvfs_mount(g_fs)) {
|
||
free(g_fs);
|
||
g_fs = NULL;
|
||
return -1;
|
||
}
|
||
|
||
g_mounted = true;
|
||
return 0;
|
||
}
|
||
|
||
|
||
/* ------------------------------------------------------------------ */
|
||
/* 目录查找 / 分配 */
|
||
/* ------------------------------------------------------------------ */
|
||
|
||
static zvfs_dirent_t *dirent_find(const char *filename) {
|
||
for (uint32_t i = 0; i < g_fs->dirent_count; i++) {
|
||
zvfs_dirent_t *d = g_fs->dirents[i];
|
||
if (d && d->is_valid && strcmp(d->filename, filename) == 0)
|
||
return d;
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
static zvfs_dirent_t *dirent_alloc(const char *filename) {
|
||
if (g_fs->dirent_count >= ZVFS_MAX_FILES) return NULL;
|
||
|
||
zvfs_dirent_t *d = calloc(1, sizeof(zvfs_dirent_t));
|
||
if (!d) return NULL;
|
||
|
||
strncpy(d->filename, filename, sizeof(d->filename) - 1);
|
||
d->is_valid = true;
|
||
d->open_count = 0;
|
||
d->file_size = 0;
|
||
d->allocated_clusters = 0;
|
||
|
||
g_fs->dirents[g_fs->dirent_count++] = d;
|
||
return d;
|
||
}
|
||
|
||
|
||
/* ------------------------------------------------------------------ */
|
||
/* fd 表管理 */
|
||
/* ------------------------------------------------------------------ */
|
||
|
||
/* 分配一个空闲 slot,返回伪 fd;失败返回 -1 */
|
||
static int fd_alloc(zvfs_file_t *file) {
|
||
for (int i = 0; i < ZVFS_MAX_FD; i++) {
|
||
if (g_fs->fd_table[i] == NULL) {
|
||
g_fs->fd_table[i] = file;
|
||
file->pseudo_fd = FD_BASE + i;
|
||
g_fs->openfd_count++;
|
||
return file->pseudo_fd;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
/* 释放 slot */
|
||
static void fd_free(int pseudo_fd) {
|
||
int idx = pseudo_fd - FD_BASE;
|
||
if (idx < 0 || idx >= ZVFS_MAX_FD) return;
|
||
g_fs->fd_table[idx] = NULL;
|
||
g_fs->openfd_count--;
|
||
}
|
||
|
||
/* 通过伪 fd 查找 file */
|
||
static zvfs_file_t *fd_lookup(int pseudo_fd) {
|
||
int idx = pseudo_fd - FD_BASE;
|
||
if (idx < 0 || idx >= ZVFS_MAX_FD) return NULL;
|
||
return g_fs->fd_table[idx];
|
||
}
|
||
|
||
/* ------------------------------------------------------------------ */
|
||
/* POSIX hook: open */
|
||
/* ------------------------------------------------------------------ */
|
||
|
||
int zvfs_open_hook(const char *path, int flags, ...) {
|
||
|
||
/* 确保 fs 已经 mount */
|
||
if (zvfs_ensure_mounted() != 0) {
|
||
errno = EIO;
|
||
return -1;
|
||
}
|
||
|
||
/* 查找 dirent */
|
||
zvfs_dirent_t *dirent = dirent_find(path);
|
||
|
||
if (!dirent) {
|
||
/* 文件不存在 */
|
||
if (!(flags & O_CREAT)) {
|
||
errno = ENOENT;
|
||
return -1;
|
||
}
|
||
/* 新建 dirent */
|
||
dirent = dirent_alloc(path);
|
||
if (!dirent) {
|
||
errno = ENOMEM;
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
/* 创建 file 句柄 */
|
||
zvfs_file_t *file = calloc(1, sizeof(zvfs_file_t));
|
||
if (!file) {
|
||
errno = ENOMEM;
|
||
return -1;
|
||
}
|
||
|
||
file->fs = g_fs;
|
||
file->dirent = dirent;
|
||
file->flags = flags;
|
||
file->current_offset = 0;
|
||
|
||
int ok;
|
||
if (dirent->blob_id == 0) {
|
||
/* 新文件:create blob,open 时不 resize,write 时按需扩容 */
|
||
file->blob_id = 0;
|
||
ok = zvfs_create(file); /* 内部 create → open → (no resize) → alloc dma_buf */
|
||
/* 把新分配的 blob_id 写回 dirent */
|
||
dirent->blob_id = file->blob_id;
|
||
} else {
|
||
/* 已有文件:直接 open 已有 blob */
|
||
file->blob_id = dirent->blob_id;
|
||
ok = zvfs_open(file);
|
||
}
|
||
|
||
if (!ok) {
|
||
free(file);
|
||
errno = EIO;
|
||
return -1;
|
||
}
|
||
|
||
/* 分配伪 fd */
|
||
int fd = fd_alloc(file);
|
||
if (fd < 0) {
|
||
zvfs_close(file);
|
||
free(file);
|
||
errno = EMFILE;
|
||
return -1;
|
||
}
|
||
|
||
dirent->open_count++;
|
||
return fd;
|
||
}
|
||
|
||
|
||
/* ------------------------------------------------------------------ */
|
||
/* POSIX hook: read */
|
||
/* ------------------------------------------------------------------ */
|
||
ssize_t zvfs_read_hook(int fd, void *buf, size_t count) {
|
||
zvfs_file_t *file = fd_lookup(fd);
|
||
if (!file) {
|
||
errno = EBADF;
|
||
return -1;
|
||
}
|
||
|
||
if (!(file->flags & O_RDWR) && (file->flags & O_WRONLY)) {
|
||
errno = EBADF;
|
||
return -1;
|
||
}
|
||
|
||
return zvfs_read(file, (uint8_t *)buf, count);
|
||
}
|
||
|
||
|
||
/* ------------------------------------------------------------------ */
|
||
/* POSIX hook: write */
|
||
/* ------------------------------------------------------------------ */
|
||
|
||
ssize_t zvfs_write_hook(int fd, const void *buf, size_t count) {
|
||
zvfs_file_t *file = fd_lookup(fd);
|
||
if (!file) {
|
||
errno = EBADF;
|
||
return -1;
|
||
}
|
||
|
||
return zvfs_write(file, (const uint8_t *)buf, count);
|
||
}
|
||
|
||
|
||
/* ------------------------------------------------------------------ */
|
||
/* POSIX hook: close */
|
||
/* ------------------------------------------------------------------ */
|
||
|
||
int zvfs_close_hook(int fd) {
|
||
zvfs_file_t *file = fd_lookup(fd);
|
||
if (!file) {
|
||
errno = EBADF;
|
||
return -1;
|
||
}
|
||
|
||
zvfs_dirent_t *dirent = file->dirent;
|
||
|
||
/* 关闭 blob */
|
||
zvfs_close(file);
|
||
|
||
/* 释放 fd slot */
|
||
fd_free(fd);
|
||
|
||
/* 更新引用计数 */
|
||
if (dirent) {
|
||
dirent->open_count--;
|
||
if(dirent->open_count == 0 && !dirent->is_valid){
|
||
zvfs_delete(file);
|
||
}
|
||
}
|
||
|
||
free(file);
|
||
|
||
/* 如果没有任何打开的文件了,保存元数据并 unmount */
|
||
if (g_fs->openfd_count == 0) {
|
||
meta_save(g_fs);
|
||
zvfs_umount(g_fs);
|
||
|
||
/* 释放所有 dirent */
|
||
for (uint32_t i = 0; i < g_fs->dirent_count; i++) {
|
||
free(g_fs->dirents[i]);
|
||
g_fs->dirents[i] = NULL;
|
||
}
|
||
|
||
free(g_fs);
|
||
g_fs = NULL;
|
||
g_mounted = false;
|
||
}
|
||
|
||
return 0;
|
||
} |