Files
zvfs/src/hook/zvfs_hook_seek.c
2026-03-09 07:53:06 +00:00

302 lines
8.7 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 "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 <errno.h>
#include <fcntl.h>
#include <linux/falloc.h> /* FALLOC_FL_* */
#include <pthread.h>
#include <stdint.h>
/* ------------------------------------------------------------------ */
/* 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 的 lseekPOSIX 允许 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 指针做 truncatepath / 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_sizereal_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;
}
/*
* 普通 fallocatemode == 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;
}