zvfs: 完成open/close/read/write/unlink的hook动态库代码编写、编译与简单功能测试。
This commit is contained in:
171
zvfs_hook.c
171
zvfs_hook.c
@@ -1,5 +1,8 @@
|
||||
#include "zvfs.h"
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <dlfcn.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
@@ -8,6 +11,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "zvfs.h"
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 全局状态 */
|
||||
@@ -15,13 +19,42 @@
|
||||
|
||||
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 1000
|
||||
#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 */
|
||||
@@ -36,7 +69,7 @@ static const char *META_FILE = "/home/lian/share/10.1-spdk/zvfs/zvfs_meta.txt";
|
||||
*/
|
||||
|
||||
static int meta_load(zvfs_t *fs) {
|
||||
int fd = open(META_FILE, O_RDONLY);
|
||||
int fd = real_open_fn(META_FILE, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
/* 文件不存在,当作空目录 */
|
||||
fs->dirent_count = 0;
|
||||
@@ -45,7 +78,7 @@ static int meta_load(zvfs_t *fs) {
|
||||
|
||||
/* 一次性读进来 */
|
||||
char buf[4096] = {0};
|
||||
ssize_t n = read(fd, buf, sizeof(buf) - 1);
|
||||
ssize_t n = real_read_fn(fd, buf, sizeof(buf) - 1);
|
||||
close(fd);
|
||||
if (n <= 0) return 0;
|
||||
|
||||
@@ -65,7 +98,7 @@ static int meta_load(zvfs_t *fs) {
|
||||
zvfs_dirent_t *d = calloc(1, sizeof(zvfs_dirent_t));
|
||||
if (!d) break;
|
||||
|
||||
int ret = sscanf(line, "%255s %"PRIu64" %"PRIu64" %"PRIu32,
|
||||
int ret = sscanf(line, "%255s %"PRIu64" %"PRIu64" %"PRIu64,
|
||||
d->filename,
|
||||
&d->blob_id,
|
||||
&d->file_size,
|
||||
@@ -85,7 +118,7 @@ static int meta_load(zvfs_t *fs) {
|
||||
}
|
||||
|
||||
static int meta_save(zvfs_t *fs) {
|
||||
int fd = open(META_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
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++) {
|
||||
@@ -93,12 +126,12 @@ static int meta_save(zvfs_t *fs) {
|
||||
if (!d || !d->is_valid) continue;
|
||||
|
||||
char line[512];
|
||||
int len = snprintf(line, sizeof(line), "%s %"PRIu64" %"PRIu64" %"PRIu32"\n",
|
||||
int len = snprintf(line, sizeof(line), "%s %"PRIu64" %"PRIu64" %"PRIu64"\n",
|
||||
d->filename, d->blob_id, d->file_size, d->allocated_clusters);
|
||||
write(fd, line, len);
|
||||
real_write_fn(fd, line, len);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
real_close_fn(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -106,6 +139,13 @@ static int meta_save(zvfs_t *fs) {
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 初始化(第一次 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;
|
||||
@@ -123,10 +163,13 @@ static int zvfs_ensure_mounted(void) {
|
||||
}
|
||||
|
||||
/* 初始化 SPDK 环境并 mount */
|
||||
if (zvfs_env_setup() != 0) {
|
||||
free(g_fs);
|
||||
g_fs = NULL;
|
||||
return -1;
|
||||
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)) {
|
||||
@@ -136,6 +179,8 @@ static int zvfs_ensure_mounted(void) {
|
||||
}
|
||||
|
||||
g_mounted = true;
|
||||
atexit(zvfs_atexit);
|
||||
SPDK_NOTICELOG("mount\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -164,6 +209,7 @@ static zvfs_dirent_t *dirent_alloc(const char *filename) {
|
||||
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;
|
||||
@@ -202,11 +248,25 @@ static zvfs_file_t *fd_lookup(int pseudo_fd) {
|
||||
return g_fs->fd_table[idx];
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* POSIX hook */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* POSIX hook: open */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
int zvfs_open_hook(const char *path, int flags, ...) {
|
||||
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) {
|
||||
@@ -229,6 +289,7 @@ int zvfs_open_hook(const char *path, int flags, ...) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
meta_save(g_fs);
|
||||
}
|
||||
|
||||
/* 创建 file 句柄 */
|
||||
@@ -246,13 +307,14 @@ int zvfs_open_hook(const char *path, int flags, ...) {
|
||||
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 */
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -279,7 +341,11 @@ int zvfs_open_hook(const char *path, int flags, ...) {
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* POSIX hook: read */
|
||||
/* ------------------------------------------------------------------ */
|
||||
ssize_t zvfs_read_hook(int fd, void *buf, size_t count) {
|
||||
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;
|
||||
@@ -299,7 +365,11 @@ ssize_t zvfs_read_hook(int fd, void *buf, size_t count) {
|
||||
/* POSIX hook: write */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
ssize_t zvfs_write_hook(int fd, const void *buf, size_t count) {
|
||||
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;
|
||||
@@ -314,7 +384,11 @@ ssize_t zvfs_write_hook(int fd, const void *buf, size_t count) {
|
||||
/* POSIX hook: close */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
int zvfs_close_hook(int fd) {
|
||||
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;
|
||||
@@ -334,25 +408,64 @@ int zvfs_close_hook(int fd) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* 如果没有任何打开的文件了,保存元数据并 unmount */
|
||||
if (g_fs->openfd_count == 0) {
|
||||
meta_save(g_fs);
|
||||
zvfs_umount(g_fs);
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* POSIX hook: unlink */
|
||||
/* ------------------------------------------------------------------ */
|
||||
int unlink(const char *name) {
|
||||
if (!is_zvfs_path(name)) {
|
||||
return real_unlink_fn(name);
|
||||
}
|
||||
|
||||
/* 释放所有 dirent */
|
||||
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++) {
|
||||
free(g_fs->dirents[i]);
|
||||
g_fs->dirents[i] = NULL;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
free(g_fs);
|
||||
g_fs = NULL;
|
||||
g_mounted = false;
|
||||
meta_save(g_fs);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user