#ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #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; static off_t (*real_lseek_fn)(int fd, off_t offset, int whence) = 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"); real_lseek_fn = dlsym(RTLD_NEXT, "lseek"); } /* 判断路径是否由我们接管 */ 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)) { zvfs_umount(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 */ /* ------------------------------------------------------------------ */ /** * O_RDONLY * O_WRONLY * O_RDWR * O_CREAT */ 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; } /* ------------------------------------------------------------------ */ /* POSIX hook: unlink */ /* ------------------------------------------------------------------ */ /** * SEEK_SET * SEEK_CUR * SEEK_END */ off_t lseek(int fd, off_t offset, int whence){ if (!is_zvfs_fd(fd)) { return real_lseek_fn(fd, offset, whence); } zvfs_file_t *file = fd_lookup(fd); if (!file) { errno = EBADF; return -1; } off_t new_offset; uint64_t file_size = file->dirent ? file->dirent->file_size : 0; switch (whence) { case SEEK_SET: new_offset = offset; break; case SEEK_CUR: new_offset = (off_t)file->current_offset + offset; break; case SEEK_END: new_offset = (off_t)file_size + offset; break; default: errno = EINVAL; return -1; } if (new_offset < 0) { errno = EINVAL; return -1; } file->current_offset = (uint64_t)new_offset; return new_offset; }