472 lines
13 KiB
C
472 lines
13 KiB
C
|
||
#ifndef _GNU_SOURCE
|
||
#define _GNU_SOURCE
|
||
#endif
|
||
#include <dlfcn.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>
|
||
#include "zvfs.h"
|
||
|
||
/* ------------------------------------------------------------------ */
|
||
/* 全局状态 */
|
||
/* ------------------------------------------------------------------ */
|
||
|
||
static zvfs_t *g_fs = NULL; /* 全局文件系统,NULL 表示未初始化 */
|
||
static bool g_mounted = false;
|
||
static bool g_env_init = false;
|
||
|
||
|
||
/* 元数据文件路径 */
|
||
static const char *META_FILE = "/home/lian/share/10.1-spdk/zvfs/zvfs_meta.txt";
|
||
|
||
/* 伪 fd 起始值,避免和真实 fd 冲突 */
|
||
#define FD_BASE 10000
|
||
|
||
/* 只拦截以 /zvfs 开头的路径 */
|
||
#define ZVFS_PATH_PREFIX "/zvfs"
|
||
|
||
static int (*real_open_fn) (const char*, int, ...) = NULL;
|
||
static ssize_t (*real_read_fn) (int, void*, size_t) = NULL;
|
||
static ssize_t (*real_write_fn)(int, const void*, size_t) = NULL;
|
||
static int (*real_close_fn)(int) = NULL;
|
||
static int (*real_unlink_fn)(const char *name) = NULL;
|
||
|
||
__attribute__((constructor))
|
||
static void zvfs_preload_init(void) {
|
||
real_open_fn = dlsym(RTLD_NEXT, "open");
|
||
real_read_fn = dlsym(RTLD_NEXT, "read");
|
||
real_write_fn = dlsym(RTLD_NEXT, "write");
|
||
real_close_fn = dlsym(RTLD_NEXT, "close");
|
||
real_unlink_fn= dlsym(RTLD_NEXT, "unlink");
|
||
}
|
||
|
||
/* 判断路径是否由我们接管 */
|
||
static inline bool is_zvfs_path(const char *path) {
|
||
return path && strncmp(path, ZVFS_PATH_PREFIX, sizeof(ZVFS_PATH_PREFIX) - 1) == 0;
|
||
}
|
||
|
||
/* 判断 fd 是否是我们的伪 fd */
|
||
static inline bool is_zvfs_fd(int fd) {
|
||
return fd >= FD_BASE && fd < FD_BASE + ZVFS_MAX_FD;
|
||
}
|
||
|
||
/* ------------------------------------------------------------------ */
|
||
/* 元数据文件 I/O */
|
||
/* ------------------------------------------------------------------ */
|
||
|
||
/*
|
||
* 格式:每行一条记录,字段用空格分隔
|
||
* filename blob_id file_size allocated_clusters
|
||
*
|
||
* 例:
|
||
* hello.txt 4294967296 26 1
|
||
*/
|
||
|
||
static int meta_load(zvfs_t *fs) {
|
||
int fd = real_open_fn(META_FILE, O_RDONLY);
|
||
if (fd < 0) {
|
||
/* 文件不存在,当作空目录 */
|
||
fs->dirent_count = 0;
|
||
return 0;
|
||
}
|
||
|
||
/* 一次性读进来 */
|
||
char buf[4096] = {0};
|
||
ssize_t n = real_read_fn(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" %"PRIu64,
|
||
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 = real_open_fn (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" %"PRIu64"\n",
|
||
d->filename, d->blob_id, d->file_size, d->allocated_clusters);
|
||
real_write_fn(fd, line, len);
|
||
}
|
||
|
||
real_close_fn(fd);
|
||
return 0;
|
||
}
|
||
|
||
|
||
/* ------------------------------------------------------------------ */
|
||
/* 初始化(第一次 open 时调用) */
|
||
/* ------------------------------------------------------------------ */
|
||
// 退出的时候调用 save 和 unmount
|
||
static void zvfs_atexit(void) {
|
||
if (!g_mounted || !g_fs) return;
|
||
SPDK_NOTICELOG("umount\n");
|
||
meta_save(g_fs);
|
||
zvfs_umount(g_fs);
|
||
}
|
||
|
||
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 (!g_env_init) {
|
||
if( zvfs_env_setup() != 0) {
|
||
free(g_fs);
|
||
g_fs = NULL;
|
||
return -1;
|
||
}
|
||
g_env_init = true;
|
||
}
|
||
|
||
if (!zvfs_mount(g_fs)) {
|
||
free(g_fs);
|
||
g_fs = NULL;
|
||
return -1;
|
||
}
|
||
|
||
g_mounted = true;
|
||
atexit(zvfs_atexit);
|
||
SPDK_NOTICELOG("mount\n");
|
||
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;
|
||
d->blob_id = 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 */
|
||
/* ------------------------------------------------------------------ */
|
||
|
||
/* ------------------------------------------------------------------ */
|
||
/* POSIX hook: open */
|
||
/* ------------------------------------------------------------------ */
|
||
|
||
int open(const char *path, int flags, ...) {
|
||
if (!is_zvfs_path(path)) {
|
||
mode_t mode = 0;
|
||
if (flags & O_CREAT) {
|
||
va_list ap;
|
||
va_start(ap, flags);
|
||
mode = va_arg(ap, mode_t);
|
||
va_end(ap);
|
||
}
|
||
return real_open_fn(path, flags, mode);
|
||
}
|
||
|
||
/* 确保 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;
|
||
}
|
||
meta_save(g_fs);
|
||
}
|
||
|
||
/* 创建 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 时按需扩容 */
|
||
ok = zvfs_create(file); /* 内部 create → open → resize → alloc dma_buf */
|
||
SPDK_DEBUGLOG("create: %ld\n", file->blob_id);
|
||
/* 把新分配的 blob_id 写回 dirent */
|
||
dirent->blob_id = file->blob_id;
|
||
} else {
|
||
/* 已有文件:直接 open 已有 blob */
|
||
file->blob_id = dirent->blob_id;
|
||
SPDK_DEBUGLOG("open: %ld\n", file->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 read(int fd, void *buf, size_t count) {
|
||
if (!is_zvfs_fd(fd)) {
|
||
return real_read_fn(fd, buf, 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 write(int fd, const void *buf, size_t count) {
|
||
if (!is_zvfs_fd(fd)) {
|
||
return real_write_fn(fd, buf, 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 close(int fd) {
|
||
if (!is_zvfs_fd(fd)) {
|
||
return real_close_fn(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);
|
||
/* 从 dirents 数组中移除 */
|
||
for (uint32_t i = 0; i < g_fs->dirent_count; i++) {
|
||
if (g_fs->dirents[i] == dirent) {
|
||
free(dirent);
|
||
g_fs->dirents[i] = g_fs->dirents[--g_fs->dirent_count];
|
||
g_fs->dirents[g_fs->dirent_count] = NULL;
|
||
break;
|
||
}
|
||
}
|
||
meta_save(g_fs);
|
||
}
|
||
}
|
||
|
||
free(file);
|
||
return 0;
|
||
}
|
||
|
||
/* ------------------------------------------------------------------ */
|
||
/* POSIX hook: unlink */
|
||
/* ------------------------------------------------------------------ */
|
||
int unlink(const char *name) {
|
||
if (!is_zvfs_path(name)) {
|
||
return real_unlink_fn(name);
|
||
}
|
||
|
||
if (zvfs_ensure_mounted() != 0) {
|
||
errno = EIO;
|
||
return -1;
|
||
}
|
||
|
||
zvfs_dirent_t *dirent = dirent_find(name);
|
||
if (!dirent) {
|
||
errno = ENOENT;
|
||
return -1;
|
||
}
|
||
|
||
if (dirent->open_count > 0) {
|
||
/* 还有人打开着,延迟删除:标记无效,等最后一次 close 时再 delete blob */
|
||
dirent->is_valid = false;
|
||
} else {
|
||
/* 没人打开,直接删除 blob */
|
||
zvfs_file_t tmp = {0};
|
||
tmp.fs = g_fs;
|
||
tmp.dirent = dirent;
|
||
tmp.blob_id = dirent->blob_id;
|
||
zvfs_delete(&tmp);
|
||
|
||
/* 从 dirents 数组中移除 */
|
||
for (uint32_t i = 0; i < g_fs->dirent_count; i++) {
|
||
if (g_fs->dirents[i] == dirent) {
|
||
free(dirent);
|
||
g_fs->dirents[i] = g_fs->dirents[--g_fs->dirent_count];
|
||
g_fs->dirents[g_fs->dirent_count] = NULL;
|
||
break;
|
||
}
|
||
}
|
||
|
||
meta_save(g_fs);
|
||
}
|
||
|
||
return 0;
|
||
} |