rebuild
This commit is contained in:
301
src/hook/zvfs_hook_seek.c
Normal file
301
src/hook/zvfs_hook_seek.c
Normal file
@@ -0,0 +1,301 @@
|
||||
#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 的 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;
|
||||
}
|
||||
Reference in New Issue
Block a user