#ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include "zvfs_hook_seek.h" #include "zvfs_hook_init.h" #include "zvfs_hook_reentrant.h" #include "fs/zvfs.h" #include "fs/zvfs_open_file.h" #include "fs/zvfs_inode.h" #include "fs/zvfs_path_entry.h" #include "spdk_engine/io_engine.h" #include #include #include /* FALLOC_FL_* */ #include #include /* ------------------------------------------------------------------ */ /* lseek / lseek64 */ /* ------------------------------------------------------------------ */ off_t lseek(int fd, off_t offset, int whence) { ZVFS_HOOK_ENTER(); struct zvfs_open_file *of = NULL; if (!ZVFS_IN_HOOK()) { pthread_mutex_lock(&g_fs.fd_mu); of = openfile_lookup(fd); pthread_mutex_unlock(&g_fs.fd_mu); } if (!of) { off_t r = real_lseek(fd, offset, whence); ZVFS_HOOK_LEAVE(); return r; } zvfs_ensure_init(); /* * O_APPEND fd 的 lseek:POSIX 允许 lseek,但下次 write 时 * 仍会从文件末尾写。lseek 只影响 read 的位置。 * 我们照常更新 of->offset。 */ pthread_mutex_lock(&of->inode->mu); /* SEEK_END 需读 logical_size */ uint64_t new_off = openfile_seek(of, (int64_t)offset, whence); pthread_mutex_unlock(&of->inode->mu); if (new_off == (uint64_t)-1) { ZVFS_HOOK_LEAVE(); return (off_t)-1; } ZVFS_HOOK_LEAVE(); return (off_t)new_off; } off_t lseek64(int fd, off_t offset, int whence) { return lseek(fd, offset, whence); } /* ------------------------------------------------------------------ */ /* 内部:按 inode 指针做 truncate(path / fd 路径共用) */ /* ------------------------------------------------------------------ */ /* * zvfs_truncate_by_inode - 对有 handle 的 openfile 做 truncate。 * 找到任意一个打开该 inode 的 openfile 取其 handle。 */ static int zvfs_truncate_inode_with_handle(struct zvfs_inode *inode, int real_fd, uint64_t new_size) { /* 在 fd_table 里找一个指向该 inode 的 openfile 取 handle */ struct zvfs_blob_handle *handle = NULL; pthread_mutex_lock(&g_fs.fd_mu); struct zvfs_open_file *of, *tmp; HASH_ITER(hh, g_fs.fd_table, of, tmp) { (void)tmp; if (of->inode == inode) { handle = of->handle; break; } } pthread_mutex_unlock(&g_fs.fd_mu); pthread_mutex_lock(&inode->mu); uint64_t old_size = inode->logical_size; pthread_mutex_unlock(&inode->mu); if (new_size != old_size && handle) { if (blob_resize(handle, new_size) < 0) { errno = EIO; return -1; } } else if (new_size != old_size && !handle) { /* * 文件未被打开:需要临时 blob_open。 * 这种情况下 truncate(path, ...) 被调用但文件没有 fd。 */ handle = blob_open(inode->blob_id); if (!handle) { errno = EIO; return -1; } int rc = blob_resize(handle, new_size); blob_close(handle); if (rc < 0) { errno = EIO; return -1; } } pthread_mutex_lock(&inode->mu); inode_update_size(inode, real_fd, new_size); pthread_mutex_unlock(&inode->mu); return 0; } /* ------------------------------------------------------------------ */ /* ftruncate / ftruncate64 */ /* ------------------------------------------------------------------ */ int ftruncate(int fd, off_t length) { ZVFS_HOOK_ENTER(); struct zvfs_open_file *of = NULL; if (!ZVFS_IN_HOOK()) { pthread_mutex_lock(&g_fs.fd_mu); of = openfile_lookup(fd); pthread_mutex_unlock(&g_fs.fd_mu); } if (!of) { int r = real_ftruncate(fd, length); ZVFS_HOOK_LEAVE(); return r; } zvfs_ensure_init(); if (length < 0) { errno = EINVAL; ZVFS_HOOK_LEAVE(); return -1; } int r = zvfs_truncate_inode_with_handle(of->inode, fd, (uint64_t)length); ZVFS_HOOK_LEAVE(); return r; } int ftruncate64(int fd, off_t length) { return ftruncate(fd, length); } /* ------------------------------------------------------------------ */ /* truncate / truncate64(按路径) */ /* ------------------------------------------------------------------ */ int truncate(const char *path, off_t length) { ZVFS_HOOK_ENTER(); if (ZVFS_IN_HOOK() || !zvfs_is_zvfs_path(path)) { int r = real_truncate(path, length); ZVFS_HOOK_LEAVE(); return r; } zvfs_ensure_init(); if (length < 0) { errno = EINVAL; ZVFS_HOOK_LEAVE(); return -1; } /* 查 path_cache 拿 inode */ pthread_mutex_lock(&g_fs.path_mu); struct zvfs_path_entry *pe = path_cache_lookup(path); struct zvfs_inode *inode = pe ? pe->inode : NULL; pthread_mutex_unlock(&g_fs.path_mu); if (!inode) { /* * inode 不在缓存:文件存在于 FS 但从未被 open。 * 需要读 xattr 拿 blob_id,临时构建 inode。 * 最简单的做法:先 real_open,再走 zvfs 路径,再 real_close。 * 这里直接调 real_truncate 改 st_size,但 blob 不会被截断。 * * 更正确的做法:open + ftruncate + close。 * 调用方通常不会在 file 未被打开的情况下做 truncate, * 所以这里先报 ENOENT(找不到 zvfs inode)作为安全兜底。 */ errno = ENOENT; ZVFS_HOOK_LEAVE(); return -1; } int r = zvfs_truncate_inode_with_handle(inode, -1, (uint64_t)length); /* 同步真实文件 st_size(real_truncate 更新磁盘元数据) */ if (r == 0) real_truncate(path, length); ZVFS_HOOK_LEAVE(); return r; } int truncate64(const char *path, off_t length) { return truncate(path, length); } /* ------------------------------------------------------------------ */ /* fallocate */ /* ------------------------------------------------------------------ */ int fallocate(int fd, int mode, off_t offset, off_t len) { ZVFS_HOOK_ENTER(); struct zvfs_open_file *of = NULL; if (!ZVFS_IN_HOOK()) { pthread_mutex_lock(&g_fs.fd_mu); of = openfile_lookup(fd); pthread_mutex_unlock(&g_fs.fd_mu); } if (!of) { int r = real_fallocate(fd, mode, offset, len); ZVFS_HOOK_LEAVE(); return r; } zvfs_ensure_init(); if (offset < 0 || len <= 0) { errno = EINVAL; ZVFS_HOOK_LEAVE(); return -1; } /* FALLOC_FL_PUNCH_HOLE:打孔,暂不支持 */ if (mode & FALLOC_FL_PUNCH_HOLE) { errno = ENOTSUP; ZVFS_HOOK_LEAVE(); return -1; } /* FALLOC_FL_KEEP_SIZE:预分配但不改变文件逻辑大小,直接返回 0 */ if (mode & FALLOC_FL_KEEP_SIZE) { ZVFS_HOOK_LEAVE(); return 0; } /* * 普通 fallocate(mode == 0): * 确保 [offset, offset+len) 范围内的空间被"分配"。 * zvfs 的语义:把 logical_size 扩展到 max(logical_size, offset+len)。 * 不提前 blob_resize,因为 SPDK cluster 按写入时分配更高效。 */ uint64_t new_end = (uint64_t)offset + (uint64_t)len; pthread_mutex_lock(&of->inode->mu); if (new_end > of->inode->logical_size) inode_update_size(of->inode, fd, new_end); pthread_mutex_unlock(&of->inode->mu); ZVFS_HOOK_LEAVE(); return 0; } /* ------------------------------------------------------------------ */ /* posix_fallocate */ /* ------------------------------------------------------------------ */ int posix_fallocate(int fd, off_t offset, off_t len) { ZVFS_HOOK_ENTER(); struct zvfs_open_file *of = NULL; if (!ZVFS_IN_HOOK()) { pthread_mutex_lock(&g_fs.fd_mu); of = openfile_lookup(fd); pthread_mutex_unlock(&g_fs.fd_mu); } if (!of) { int r = real_posix_fallocate(fd, offset, len); ZVFS_HOOK_LEAVE(); return r; } zvfs_ensure_init(); /* * posix_fallocate 不接受 mode 参数,语义等价于 fallocate(fd, 0, ...)。 * 注意:posix_fallocate 出错时返回错误码(正值),不设置 errno。 */ if (offset < 0 || len <= 0) { ZVFS_HOOK_LEAVE(); return EINVAL; } uint64_t new_end = (uint64_t)offset + (uint64_t)len; pthread_mutex_lock(&of->inode->mu); if (new_end > of->inode->logical_size) inode_update_size(of->inode, fd, new_end); pthread_mutex_unlock(&of->inode->mu); ZVFS_HOOK_LEAVE(); return 0; }