Files
zvfs/zvfs_hook.c

472 lines
13 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.
#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 blobopen 时不 resizewrite 时按需扩容 */
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;
}