Files
zvfs/zvfs_hook.c

359 lines
9.3 KiB
C
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 <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 blobopen 时不 resizewrite 时按需扩容 */
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;
}