bugfix: OFD:FLAGS

This commit is contained in:
2026-04-14 07:40:56 +00:00
parent ea64511f95
commit 15d6a90e2f
19 changed files with 1030 additions and 160 deletions

0
.codex Normal file
View File

View File

@@ -14,6 +14,7 @@
#include <spdk/blob_bdev.h>
#include <spdk/thread.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
#include <time.h>
@@ -133,6 +134,31 @@ static void push_err_resp(struct zvfs_req *req, int status) {
zvfs_conn_submit_resp(resp);
}
static uint32_t handle_status_flags_from_open_flags(uint32_t open_flags) {
const uint32_t keep_mask = O_ACCMODE | O_APPEND | O_NONBLOCK | O_ASYNC;
return open_flags & keep_mask;
}
static int handle_state_init(struct zvfs_blob_handle *handle, uint32_t open_flags) {
if (!handle) {
return -EINVAL;
}
handle->current_offset = 0;
handle->status_flags = handle_status_flags_from_open_flags(open_flags);
if (pthread_mutex_init(&handle->state_mu, NULL) != 0) {
return -errno;
}
return 0;
}
static void handle_state_destroy(struct zvfs_blob_handle *handle) {
if (!handle) {
return;
}
pthread_mutex_destroy(&handle->state_mu);
}
/** ===========================================================
* bdev / blobstore 初始化(仅在 md 线程上执行)
* 初始化阶段使用同步等待是必要的,因为此时还没有其他线程可以 poll
@@ -631,6 +657,13 @@ static void create_sync_cb(void *arg, int bserrno) {
handle->blob_id = cctx->blob_id;
handle->blob = cctx->blob;
atomic_init(&handle->ref_count, 1);
if (handle_state_init(handle, cctx->req->open_flags) != 0) {
spdk_blob_close(cctx->blob, blob_close_noop_cb, NULL);
free(handle);
push_err_resp(cctx->req, -ENOMEM);
free(cctx);
return;
}
/* 构造响应 */
struct zvfs_resp *resp = calloc(1, sizeof(*resp));
@@ -688,6 +721,13 @@ static void blob_open_done_cb(void *arg, struct spdk_blob *blob, int bserrno) {
handle->blob_id = octx->req->blob_id;
handle->blob = blob;
atomic_init(&handle->ref_count, 1);
if (handle_state_init(handle, octx->req->open_flags) != 0) {
spdk_blob_close(blob, blob_close_noop_cb, NULL);
free(handle);
push_err_resp(octx->req, -ENOMEM);
free(octx);
return;
}
struct zvfs_resp *resp = calloc(1, sizeof(*resp));
if (!resp) {
@@ -733,6 +773,93 @@ int blob_open(struct zvfs_req *req) {
return 0;
}
static int prepare_shared_read(struct zvfs_req *req, struct zvfs_blob_handle *handle) {
uint64_t logical_size;
uint64_t cur;
uint64_t remaining;
uint64_t actual_len;
if ((req->write_flags & ZVFS_RW_F_USE_HANDLE_POS) == 0) {
return 0;
}
logical_size = req->offset;
pthread_mutex_lock(&handle->state_mu);
cur = handle->current_offset;
if (cur >= logical_size) {
actual_len = 0;
} else {
remaining = logical_size - cur;
actual_len = req->length;
if (actual_len > remaining) {
actual_len = remaining;
}
}
handle->current_offset = cur + actual_len;
pthread_mutex_unlock(&handle->state_mu);
req->offset = cur;
req->length = actual_len;
return 0;
}
static int prepare_shared_write(struct zvfs_req *req, struct zvfs_blob_handle *handle) {
uint64_t base_offset;
uint64_t logical_size;
uint64_t new_offset;
if ((req->write_flags & ZVFS_RW_F_USE_HANDLE_POS) == 0) {
return 0;
}
logical_size = req->offset;
pthread_mutex_lock(&handle->state_mu);
if ((handle->status_flags & O_APPEND) != 0) {
base_offset = logical_size;
} else {
base_offset = handle->current_offset;
}
if (__builtin_add_overflow(base_offset, req->length, &new_offset)) {
pthread_mutex_unlock(&handle->state_mu);
return -EOVERFLOW;
}
handle->current_offset = new_offset;
pthread_mutex_unlock(&handle->state_mu);
req->offset = base_offset;
return 0;
}
static int handle_seek_locked(struct zvfs_blob_handle *handle, int64_t offset, uint32_t whence,
uint64_t logical_size, uint64_t *new_offset_out) {
int64_t base;
int64_t new_offset;
switch (whence) {
case SEEK_SET:
base = 0;
break;
case SEEK_CUR:
base = (int64_t)handle->current_offset;
break;
case SEEK_END:
base = (int64_t)logical_size;
break;
default:
return -EINVAL;
}
if (__builtin_add_overflow(base, offset, &new_offset) || new_offset < 0) {
return -EINVAL;
}
handle->current_offset = (uint64_t)new_offset;
if (new_offset_out) {
*new_offset_out = (uint64_t)new_offset;
}
return 0;
}
/** ===========================================================
* blob_resize
* ============================================================ */
@@ -816,6 +943,7 @@ static void blob_close_done_cb(void *arg, int bserrno) {
struct close_ctx *cctx = arg;
if (bserrno == 0) {
engine_cache_remove((zvfs_handle_id_t)(uintptr_t)cctx->handle);
handle_state_destroy(cctx->handle);
free(cctx->handle);
}
@@ -871,6 +999,124 @@ int blob_close(struct zvfs_req *req) {
return 0;
}
int blob_seek(struct zvfs_req *req) {
struct zvfs_blob_handle *handle = req->handle;
struct zvfs_resp *resp;
int rc;
if (!handle) {
push_err_resp(req, -EINVAL);
return -EINVAL;
}
resp = calloc(1, sizeof(*resp));
if (!resp) {
push_err_resp(req, -ENOMEM);
return -ENOMEM;
}
pthread_mutex_lock(&handle->state_mu);
rc = handle_seek_locked(handle, req->seek_offset, req->seek_whence, req->size_hint, &resp->offset);
pthread_mutex_unlock(&handle->state_mu);
if (rc != 0) {
free(resp);
push_err_resp(req, rc);
return rc;
}
resp->opcode = req->opcode;
resp->status = 0;
resp->conn = req->conn;
free(req);
zvfs_conn_submit_resp(resp);
return 0;
}
int blob_get_pos(struct zvfs_req *req) {
struct zvfs_blob_handle *handle = req->handle;
struct zvfs_resp *resp;
if (!handle) {
push_err_resp(req, -EINVAL);
return -EINVAL;
}
resp = calloc(1, sizeof(*resp));
if (!resp) {
push_err_resp(req, -ENOMEM);
return -ENOMEM;
}
pthread_mutex_lock(&handle->state_mu);
resp->offset = handle->current_offset;
pthread_mutex_unlock(&handle->state_mu);
resp->opcode = req->opcode;
resp->status = 0;
resp->conn = req->conn;
free(req);
zvfs_conn_submit_resp(resp);
return 0;
}
int blob_get_flags(struct zvfs_req *req) {
struct zvfs_blob_handle *handle = req->handle;
struct zvfs_resp *resp;
if (!handle) {
push_err_resp(req, -EINVAL);
return -EINVAL;
}
resp = calloc(1, sizeof(*resp));
if (!resp) {
push_err_resp(req, -ENOMEM);
return -ENOMEM;
}
pthread_mutex_lock(&handle->state_mu);
resp->handle_flags = handle->status_flags;
pthread_mutex_unlock(&handle->state_mu);
resp->opcode = req->opcode;
resp->status = 0;
resp->conn = req->conn;
free(req);
zvfs_conn_submit_resp(resp);
return 0;
}
int blob_set_flags(struct zvfs_req *req) {
struct zvfs_blob_handle *handle = req->handle;
const uint32_t mutable_mask = O_APPEND | O_NONBLOCK | O_ASYNC;
uint32_t new_flags;
struct zvfs_resp *resp;
if (!handle) {
push_err_resp(req, -EINVAL);
return -EINVAL;
}
resp = calloc(1, sizeof(*resp));
if (!resp) {
push_err_resp(req, -ENOMEM);
return -ENOMEM;
}
pthread_mutex_lock(&handle->state_mu);
new_flags = handle->status_flags & ~mutable_mask;
new_flags |= req->handle_flags & mutable_mask;
handle->status_flags = new_flags;
pthread_mutex_unlock(&handle->state_mu);
resp->opcode = req->opcode;
resp->status = 0;
resp->conn = req->conn;
free(req);
zvfs_conn_submit_resp(resp);
return 0;
}
/** ===========================================================
* blob_delete
* ============================================================ */
@@ -1073,6 +1319,21 @@ static void do_blob_read(void *arg) {
int blob_read(struct zvfs_req *req) {
struct zvfs_blob_handle *handle = req->handle;
if (!handle || !req->data) { push_err_resp(req, -EINVAL); return -EINVAL; }
prepare_shared_read(req, handle);
if (req->length == 0) {
struct zvfs_resp *resp = calloc(1, sizeof(*resp));
if (!resp) { push_err_resp(req, -ENOMEM); return -ENOMEM; }
resp->opcode = req->opcode;
resp->status = 0;
resp->conn = req->conn;
resp->length = 0;
free(req->data);
req->data = NULL;
free(req);
zvfs_conn_submit_resp(resp);
return 0;
}
struct zvfs_io_thread *iot = pick_io_thread();
if (!iot || !iot->ready || !iot->channel) {
@@ -1236,6 +1497,13 @@ static void do_write_autogrow_resize(void *arg) {
int blob_write(struct zvfs_req *req) {
struct zvfs_blob_handle *handle = req->handle;
if (!handle || !req->data) { push_err_resp(req, -EINVAL); return -EINVAL; }
{
int rc = prepare_shared_write(req, handle);
if (rc != 0) {
push_err_resp(req, rc);
return rc;
}
}
struct zvfs_io_thread *iot = pick_io_thread();
if (!iot || !iot->ready || !iot->channel) {

View File

@@ -6,6 +6,7 @@
#include <stdint.h>
#include <sys/types.h>
#include <stdatomic.h>
#include <pthread.h>
#include <spdk/blob.h>
@@ -14,6 +15,9 @@ typedef struct zvfs_blob_handle {
spdk_blob_id blob_id;
struct spdk_blob *blob;
atomic_uint ref_count;
uint64_t current_offset;
uint32_t status_flags;
pthread_mutex_t state_mu;
} zvfs_blob_handle_t;
struct zvfs_io_thread {
@@ -76,6 +80,10 @@ int blob_resize(struct zvfs_req *req);
int blob_sync_md(struct zvfs_req *req);
int blob_close(struct zvfs_req *req);
int blob_delete(struct zvfs_req *req);
int blob_seek(struct zvfs_req *req);
int blob_get_pos(struct zvfs_req *req);
int blob_get_flags(struct zvfs_req *req);
int blob_set_flags(struct zvfs_req *req);
int blobstore_reset(struct zvfs_req *req);
bool io_engine_reset_in_progress(void);

View File

@@ -182,6 +182,26 @@ static int zvfs_add_ref_batch(struct zvfs_req *req) {
return 0;
}
static int zvfs_seek(struct zvfs_req *req) {
if (fill_handle(req, "zvfs_seek") != 0) return -EBADF;
return blob_seek(req);
}
static int zvfs_get_pos(struct zvfs_req *req) {
if (fill_handle(req, "zvfs_get_pos") != 0) return -EBADF;
return blob_get_pos(req);
}
static int zvfs_get_flags(struct zvfs_req *req) {
if (fill_handle(req, "zvfs_get_flags") != 0) return -EBADF;
return blob_get_flags(req);
}
static int zvfs_set_flags(struct zvfs_req *req) {
if (fill_handle(req, "zvfs_set_flags") != 0) return -EBADF;
return blob_set_flags(req);
}
static int zvfs_reset_blobstore(struct zvfs_req *req) {
return blobstore_reset(req);
}
@@ -214,6 +234,14 @@ int dispatch_to_worker(struct zvfs_req *req){
return zvfs_add_ref(req);
case ZVFS_OP_ADD_REF_BATCH:
return zvfs_add_ref_batch(req);
case ZVFS_OP_SEEK:
return zvfs_seek(req);
case ZVFS_OP_GET_POS:
return zvfs_get_pos(req);
case ZVFS_OP_GET_FLAGS:
return zvfs_get_flags(req);
case ZVFS_OP_SET_FLAGS:
return zvfs_set_flags(req);
case ZVFS_OP_RESET_BLOBSTORE:
return zvfs_reset_blobstore(req);
default:

Binary file not shown.

View File

@@ -14,7 +14,6 @@
struct zvfs_open_file *openfile_alloc(int fd,
struct zvfs_inode *inode,
int flags,
uint64_t handle_id)
{
struct zvfs_open_file *of = calloc(1, sizeof(*of));
@@ -24,9 +23,7 @@ struct zvfs_open_file *openfile_alloc(int fd,
of->fd = fd;
of->inode = inode;
of->handle_id = handle_id;
of->flags = flags;
of->fd_flags = 0;
of->offset = 0;
return of;
}
@@ -58,39 +55,3 @@ void openfile_remove(int fd)
if (of)
HASH_DEL(g_fs.fd_table, of);
}
/* ------------------------------------------------------------------ */
/* lseek (调用方持有 of->inode->mu */
/* ------------------------------------------------------------------ */
uint64_t openfile_seek(struct zvfs_open_file *of, int64_t offset, int whence)
{
int64_t new_off;
switch (whence) {
case SEEK_SET:
new_off = offset;
break;
case SEEK_CUR:
new_off = (int64_t)of->offset + offset;
break;
case SEEK_END:
/* logical_size 由调用方在持锁状态下保证可见 */
new_off = (int64_t)of->inode->logical_size + offset;
break;
default:
errno = EINVAL;
return (uint64_t)-1;
}
if (new_off < 0) {
errno = EINVAL;
return (uint64_t)-1;
}
of->offset = (uint64_t)new_off;
return of->offset;
}

View File

@@ -10,17 +10,14 @@ struct zvfs_open_file {
struct zvfs_inode *inode;
uint64_t handle_id;
int flags;
int fd_flags;
uint64_t offset; // 非 APPEND 模式的当前位置
UT_hash_handle hh;
};
// 分配 openfile不插入全局表
struct zvfs_open_file *openfile_alloc(int fd, struct zvfs_inode *inode,
int flags, uint64_t handle_id);
uint64_t handle_id);
// 释放内存
void openfile_free(struct zvfs_open_file *of);
@@ -34,8 +31,4 @@ struct zvfs_open_file *openfile_lookup(int fd);
// 从全局表移除(需持有 fd_mu不释放内存
void openfile_remove(int fd);
// lseek 语义:返回新 offset出错返回 (uint64_t)-1
// 需持有 of->inode->mu读 logical_size
uint64_t openfile_seek(struct zvfs_open_file *of, int64_t offset, int whence);
#endif // __ZVFS_OPEN_FILE_H__

View File

@@ -58,23 +58,32 @@ zvfs_fcntl_impl(int fd, int cmd, va_list ap)
switch (cmd) {
/* ---- 文件状态 flags ------------------------------------------ */
case F_GETFL:
return of->flags;
case F_GETFL: {
uint32_t flags = 0;
if (blob_get_flags(of->handle_id, &flags) < 0)
return -1;
return (int)flags;
}
case F_SETFL: {
int newfl = va_arg(ap, int);
uint32_t cur_flags = 0;
/*
* 只允许修改可变位O_APPEND、O_NONBLOCK、O_ASYNC。
* O_RDONLY / O_WRONLY / O_RDWR 是 open 时决定的,不能改。
* 同步给真实 fd保持内核状态一致影响 real_read/write
*/
int mutable_mask = O_APPEND | O_NONBLOCK | O_ASYNC;
of->flags = (of->flags & ~mutable_mask) | (newfl & mutable_mask);
if (blob_get_flags(of->handle_id, &cur_flags) < 0)
return -1;
cur_flags = (cur_flags & ~((uint32_t)mutable_mask)) | ((uint32_t)newfl & (uint32_t)mutable_mask);
if (blob_set_flags(of->handle_id, cur_flags) < 0)
return -1;
/*
* 也透传给真实 fd——虽然真实 fd 上的读写被我们拦截了,
* 但 O_NONBLOCK 可能影响 pipe / socket 等透传路径。
*/
real_fcntl(fd, F_SETFL, of->flags);
real_fcntl(fd, F_SETFL, (int)cur_flags);
return 0;
}
@@ -238,7 +247,8 @@ ioctl(int fd, unsigned long request, ...)
uint64_t size = of->inode->logical_size;
pthread_mutex_unlock(&of->inode->mu);
uint64_t off = of->offset;
uint64_t off = 0;
if (blob_get_pos(of->handle_id, &off) < 0) { ret = -1; break; }
int avail = (off < size) ? (int)(size - off) : 0;
if (arg) *(int *)arg = avail;
ret = 0;

View File

@@ -4,8 +4,8 @@
/*
* fcntl cmd 处理策略:
*
* F_GETFL → 返回 of->flags
* F_SETFL → 更新 of->flags只允许改 O_APPEND / O_NONBLOCK
* F_GETFL → 返回 daemon handle 上的共享 status flags
* F_SETFL → 更新 daemon handle 上的共享 status flags
* F_GETFD → 返回 of->fd_flags
* F_SETFD → 更新 of->fd_flagsFD_CLOEXEC
* F_DUPFD → 等价于 dup分配 >= arg 的最小可用 fd走 dup 路径
@@ -16,7 +16,7 @@
* 其他 cmd → 透传给 real_fcntl同时透传给内核保持真实 fd 状态同步)
*
* ioctl cmd 处理策略:
* FIONREAD → 返回 logical_size - cur_offset可读字节数
* FIONREAD → 返回 logical_size - daemon handle 当前 offset
* 其他 → 透传,或对 zvfs fd 返回 ENOTTY
*/

View File

@@ -241,7 +241,7 @@ zvfs_open_impl(int real_fd, const char *abspath, int flags, mode_t mode)
/* ---- 创建路径 -------------------------------------------- */
/* 1. 创建 blob */
if (blob_create(0, &blob_id, &handle_id) != 0) {
if (blob_create(0, flags, &blob_id, &handle_id) != 0) {
int saved = errno;
if (saved == 0) saved = EIO;
fprintf(stderr,
@@ -311,7 +311,7 @@ zvfs_open_impl(int real_fd, const char *abspath, int flags, mode_t mode)
(unsigned long)inode->blob_id);
/* path_cache 命中:直接用缓存的 inode重新 blob_open */
blob_id = inode->blob_id;
if (blob_open(blob_id, &handle_id) != 0) {
if (blob_open(blob_id, flags, &handle_id) != 0) {
if (errno == 0) errno = EIO;
zvfs_debug_open_log(abspath, NULL,
"open existing path_cache-hit blob_open fail errno=%d(%s)",
@@ -344,7 +344,7 @@ zvfs_open_impl(int real_fd, const char *abspath, int flags, mode_t mode)
zvfs_debug_open_log(abspath, NULL,
"open existing inode_table hit blob_id=%lu",
(unsigned long)blob_id);
if (blob_open(blob_id, &handle_id) != 0) {
if (blob_open(blob_id, flags, &handle_id) != 0) {
if (errno == 0) errno = EIO;
zvfs_debug_open_log(abspath, NULL,
"open existing inode_table-hit blob_open fail errno=%d(%s)",
@@ -381,7 +381,7 @@ zvfs_open_impl(int real_fd, const char *abspath, int flags, mode_t mode)
pthread_mutex_lock(&g_fs.path_mu);
path_cache_insert(abspath, inode);
pthread_mutex_unlock(&g_fs.path_mu);
if (blob_open(blob_id, &handle_id) != 0) {
if (blob_open(blob_id, flags, &handle_id) != 0) {
if (errno == 0) errno = EIO;
zvfs_debug_open_log(abspath, NULL,
"open existing new-inode blob_open fail errno=%d(%s)",
@@ -397,7 +397,7 @@ zvfs_open_impl(int real_fd, const char *abspath, int flags, mode_t mode)
}
/* ---- 分配 openfile插入 fd_table ---------------------------- */
struct zvfs_open_file *of = openfile_alloc(real_fd, inode, flags, handle_id);
struct zvfs_open_file *of = openfile_alloc(real_fd, inode, handle_id);
if (!of) { errno = ENOMEM; goto fail_handle; }
pthread_mutex_lock(&g_fs.fd_mu);
@@ -1150,7 +1150,7 @@ zvfs_dup_attach_newfd(int oldfd, int newfd, int new_fd_flags)
return -1;
}
new_of = openfile_alloc(newfd, old_of->inode, old_of->flags, old_of->handle_id);
new_of = openfile_alloc(newfd, old_of->inode, old_of->handle_id);
if (!new_of) {
saved = (errno != 0) ? errno : ENOMEM;
(void)blob_close(old_of->handle_id);
@@ -1159,7 +1159,6 @@ zvfs_dup_attach_newfd(int oldfd, int newfd, int new_fd_flags)
return -1;
}
new_of->offset = old_of->offset;
fd_flags = (new_fd_flags >= 0) ? new_fd_flags : old_of->fd_flags;
new_of->fd_flags = fd_flags;

View File

@@ -23,7 +23,7 @@
#define zvfs_debug_rw_log(...) ((void)0)
/* ------------------------------------------------------------------ */
/* 内部:单段 pread / pwrite不修改 of->offset */
/* 内部:单段 pread / pwrite不修改 daemon handle offset */
/* ------------------------------------------------------------------ */
/*
@@ -90,6 +90,52 @@ zvfs_pwrite_impl(struct zvfs_open_file *of,
return (ssize_t)count;
}
static ssize_t
zvfs_read_shared_impl(struct zvfs_open_file *of, void *buf, size_t count)
{
uint64_t size;
ssize_t nr;
pthread_mutex_lock(&of->inode->mu);
size = of->inode->logical_size;
pthread_mutex_unlock(&of->inode->mu);
nr = blob_read_shared(of->handle_id, size, buf, count);
if (nr < 0) {
errno = EIO;
return -1;
}
return nr;
}
static ssize_t
zvfs_write_shared_impl(struct zvfs_open_file *of, const void *buf, size_t count)
{
uint64_t logical_size;
uint64_t new_pos = 0;
if (count == 0)
return 0;
pthread_mutex_lock(&of->inode->mu);
logical_size = of->inode->logical_size;
pthread_mutex_unlock(&of->inode->mu);
if (blob_write_shared(of->handle_id, logical_size, buf, count, ZVFS_WRITE_F_AUTO_GROW) < 0)
return -1;
if (blob_get_pos(of->handle_id, &new_pos) < 0)
return -1;
pthread_mutex_lock(&of->inode->mu);
if (new_pos > of->inode->logical_size)
inode_update_size(of->inode, of->fd, new_pos);
pthread_mutex_unlock(&of->inode->mu);
return (ssize_t)count;
}
/* ------------------------------------------------------------------ */
/* 内部iov 合并辅助 */
/* ------------------------------------------------------------------ */
@@ -189,6 +235,63 @@ zvfs_iov_pwrite(struct zvfs_open_file *of,
return r;
}
static ssize_t
zvfs_iov_read_shared(struct zvfs_open_file *of, const struct iovec *iov, int iovcnt)
{
size_t total_len = iov_total_len(iov, iovcnt);
ssize_t nr;
size_t copied = 0;
char *tmp;
if (total_len == 0)
return 0;
tmp = malloc(total_len);
if (!tmp) { errno = ENOMEM; return -1; }
nr = zvfs_read_shared_impl(of, tmp, total_len);
if (nr <= 0) {
free(tmp);
return nr;
}
for (int i = 0; i < iovcnt && copied < (size_t)nr; i++) {
size_t seg = iov[i].iov_len;
if (seg == 0) continue;
if (copied + seg > (size_t)nr) seg = (size_t)nr - copied;
memcpy(iov[i].iov_base, tmp + copied, seg);
copied += seg;
}
free(tmp);
return nr;
}
static ssize_t
zvfs_iov_write_shared(struct zvfs_open_file *of, const struct iovec *iov, int iovcnt)
{
size_t total_len = iov_total_len(iov, iovcnt);
size_t pos = 0;
char *tmp;
ssize_t nr;
if (total_len == 0)
return 0;
tmp = malloc(total_len);
if (!tmp) { errno = ENOMEM; return -1; }
for (int i = 0; i < iovcnt; i++) {
if (iov[i].iov_len == 0) continue;
memcpy(tmp + pos, iov[i].iov_base, iov[i].iov_len);
pos += iov[i].iov_len;
}
nr = zvfs_write_shared_impl(of, tmp, total_len);
free(tmp);
return nr;
}
/* ------------------------------------------------------------------ */
/* 内部:取出 of处理重入/非 zvfs 判断 */
/* ------------------------------------------------------------------ */
@@ -237,9 +340,9 @@ zvfs_fread_impl(void *ptr, size_t size, size_t nmemb, FILE *stream, int unlocked
}
zvfs_debug_rw_log(fd,
"fread hooked unlocked=%d size=%zu nmemb=%zu offset=%lu handle_id=%lu logical_size=%lu target=%s",
"fread hooked unlocked=%d size=%zu nmemb=%zu handle_id=%lu logical_size=%lu target=%s",
unlocked, size, nmemb,
(unsigned long)of->offset, (unsigned long)of->handle_id,
(unsigned long)of->handle_id,
(unsigned long)zvfs_debug_logical_size(of),
zvfs_debug_fd_target(fd));
zvfs_ensure_init();
@@ -255,9 +358,7 @@ zvfs_fread_impl(void *ptr, size_t size, size_t nmemb, FILE *stream, int unlocked
}
size_t total = size * nmemb;
ssize_t n = zvfs_pread_impl(of, ptr, total, of->offset);
if (n > 0)
of->offset += (uint64_t)n;
ssize_t n = zvfs_read_shared_impl(of, ptr, total);
/* Keep stdio state machine consistent for callers that check feof/ferror. */
if (n < 0) {
@@ -266,9 +367,8 @@ zvfs_fread_impl(void *ptr, size_t size, size_t nmemb, FILE *stream, int unlocked
stream->_flags |= _IO_EOF_SEEN;
}
zvfs_debug_rw_log(fd,
"fread hooked ret_bytes=%zd ret_nmemb=%zu new_offset=%lu errno=%d(%s)",
"fread hooked ret_bytes=%zd ret_nmemb=%zu errno=%d(%s)",
n, (n <= 0) ? 0 : ((size_t)n / size),
(unsigned long)of->offset,
(n < 0) ? errno : 0, (n < 0) ? strerror(errno) : "OK");
ZVFS_HOOK_LEAVE();
return (n <= 0) ? 0 : ((size_t)n / size);
@@ -323,9 +423,15 @@ zvfs_vfscanf_impl(FILE *stream, const char *format, va_list ap, int use_isoc99)
return EOF;
}
uint64_t cur_off = of->offset;
uint64_t cur_off = 0;
uint64_t logical_size;
if (blob_get_pos(of->handle_id, &cur_off) < 0) {
stream->_flags |= _IO_ERR_SEEN;
ZVFS_HOOK_LEAVE();
return EOF;
}
pthread_mutex_lock(&of->inode->mu);
logical_size = of->inode->logical_size;
pthread_mutex_unlock(&of->inode->mu);
@@ -384,8 +490,14 @@ zvfs_vfscanf_impl(FILE *stream, const char *format, va_list ap, int use_isoc99)
ret = zvfs_vfscanf_passthrough(mem, format, ap, use_isoc99);
long consumed = ftell(mem);
if (consumed > 0) {
of->offset = cur_off + (uint64_t)consumed;
if (consumed > 0 &&
blob_seek(of->handle_id, (int64_t)(cur_off + (uint64_t)consumed), SEEK_SET,
logical_size, &cur_off) < 0) {
stream->_flags |= _IO_ERR_SEEN;
fclose(mem);
free(buf);
ZVFS_HOOK_LEAVE();
return EOF;
}
fclose(mem);
@@ -397,7 +509,7 @@ zvfs_vfscanf_impl(FILE *stream, const char *format, va_list ap, int use_isoc99)
zvfs_debug_rw_log(fd,
"fscanf hooked ret=%d consumed=%ld new_offset=%lu errno=%d(%s)",
ret, consumed, (unsigned long)of->offset, errno, strerror(errno));
ret, consumed, (unsigned long)cur_off, errno, strerror(errno));
ZVFS_HOOK_LEAVE();
return ret;
}
@@ -440,19 +552,17 @@ read(int fd, void *buf, size_t count)
}
zvfs_debug_rw_log(fd,
"read hooked count=%zu offset=%lu handle_id=%lu logical_size=%lu target=%s",
count, (unsigned long)of->offset,
"read hooked count=%zu handle_id=%lu logical_size=%lu target=%s",
count,
(unsigned long)of->handle_id,
(unsigned long)zvfs_debug_logical_size(of),
zvfs_debug_fd_target(fd));
zvfs_ensure_init();
ssize_t r = zvfs_pread_impl(of, buf, count, of->offset);
if (r > 0)
of->offset += (uint64_t)r;
ssize_t r = zvfs_read_shared_impl(of, buf, count);
zvfs_debug_rw_log(fd,
"read hooked ret=%zd new_offset=%lu errno=%d(%s)",
r, (unsigned long)of->offset,
"read hooked ret=%zd errno=%d(%s)",
r,
(r < 0) ? errno : 0, (r < 0) ? strerror(errno) : "OK");
ZVFS_HOOK_LEAVE();
@@ -577,9 +687,7 @@ readv(int fd, const struct iovec *iov, int iovcnt)
zvfs_ensure_init();
ssize_t r = zvfs_iov_pread(of, iov, iovcnt, of->offset);
if (r > 0)
of->offset += (uint64_t)r;
ssize_t r = zvfs_iov_read_shared(of, iov, iovcnt);
ZVFS_HOOK_LEAVE();
return r;
@@ -630,10 +738,9 @@ preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags)
* 忽略该 flag按普通 preadv 处理。
* RWF_HIPRI / RWF_DSYNC / RWF_SYNC同上忽略。
*/
uint64_t off = (offset == (off_t)-1) ? of->offset : (uint64_t)offset;
ssize_t r = zvfs_iov_pread(of, iov, iovcnt, off);
if (offset == (off_t)-1 && r > 0)
of->offset += (uint64_t)r;
ssize_t r = (offset == (off_t)-1)
? zvfs_iov_read_shared(of, iov, iovcnt)
: zvfs_iov_pread(of, iov, iovcnt, (uint64_t)offset);
ZVFS_HOOK_LEAVE();
return r;
@@ -657,28 +764,9 @@ write(int fd, const void *buf, size_t count)
zvfs_ensure_init();
uint64_t write_off;
if (of->flags & O_APPEND) {
/* O_APPEND每次写入位置 = 当前 logical_size。 */
pthread_mutex_lock(&of->inode->mu);
write_off = of->inode->logical_size; /* 重新取,防止 TOCTOU */
pthread_mutex_unlock(&of->inode->mu);
ssize_t r = zvfs_pwrite_impl(of, buf, count, write_off);
if (r > 0)
of->offset = write_off + (uint64_t)r;
ZVFS_HOOK_LEAVE();
return r;
} else {
write_off = of->offset;
ssize_t r = zvfs_pwrite_impl(of, buf, count, write_off);
if (r > 0)
of->offset += (uint64_t)r;
ZVFS_HOOK_LEAVE();
return r;
}
ssize_t r = zvfs_write_shared_impl(of, buf, count);
ZVFS_HOOK_LEAVE();
return r;
}
ssize_t __write(int fd, const void *buf, size_t count) { return write(fd, buf, count); }
@@ -733,20 +821,7 @@ writev(int fd, const struct iovec *iov, int iovcnt)
zvfs_ensure_init();
ssize_t r;
if (of->flags & O_APPEND) {
/* O_APPEND + writev以当前 logical_size 作为写入起点。 */
pthread_mutex_lock(&of->inode->mu);
uint64_t write_off = of->inode->logical_size;
pthread_mutex_unlock(&of->inode->mu);
r = zvfs_iov_pwrite(of, iov, iovcnt, write_off);
if (r > 0)
of->offset = write_off + (uint64_t)r;
} else {
r = zvfs_iov_pwrite(of, iov, iovcnt, of->offset);
if (r > 0) of->offset += (uint64_t)r;
}
ssize_t r = zvfs_iov_write_shared(of, iov, iovcnt);
ZVFS_HOOK_LEAVE();
return r;
@@ -794,11 +869,10 @@ pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags)
/* flagsRWF_SYNC/RWF_DSYNC/RWF_APPEND 等):
* zvfs 无缓冲区,所有写均同步落盘,忽略 flags。
* offset == -1使用并更新 of->offset。 */
uint64_t off = (offset == (off_t)-1) ? of->offset : (uint64_t)offset;
ssize_t r = zvfs_iov_pwrite(of, iov, iovcnt, off);
if (offset == (off_t)-1 && r > 0)
of->offset += (uint64_t)r;
* offset == -1使用并更新 daemon handle offset。 */
ssize_t r = (offset == (off_t)-1)
? zvfs_iov_write_shared(of, iov, iovcnt)
: zvfs_iov_pwrite(of, iov, iovcnt, (uint64_t)offset);
ZVFS_HOOK_LEAVE();
return r;

View File

@@ -14,9 +14,9 @@
* zvfs_pwrite_impl(fd, buf, count, offset)
*
* offset 语义:
* - pread/pwrite 系列:直接使用传入 offset不修改 of->offset
* - read/write 系列:使用 of->offset完成后更新
* - O_APPEND write 每次写前持 inode->mu 取 logical_size 作为 offset
* - pread/pwrite 系列:直接使用传入 offset不修改 daemon handle offset
* - read/write 系列:使用并更新 daemon handle offset
* - O_APPEND write 由 daemon handle 上的共享 status flags 决定
*
* iov 系列readv/writev/preadv/pwritev
* 展开 iovec 后逐段调用 pread/pwrite impl合并结果。

View File

@@ -40,16 +40,12 @@ lseek(int fd, off_t offset, int whence)
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_lock(&of->inode->mu);
uint64_t logical_size = of->inode->logical_size;
pthread_mutex_unlock(&of->inode->mu);
if (new_off == (uint64_t)-1) {
uint64_t new_off = 0;
if (blob_seek(of->handle_id, (int64_t)offset, whence, logical_size, &new_off) != 0) {
ZVFS_HOOK_LEAVE();
return (off_t)-1;
}
@@ -104,7 +100,7 @@ zvfs_truncate_inode_with_handle(struct zvfs_inode *inode,
* 这种情况下 truncate(path, ...) 被调用但文件没有 fd。
*/
uint64_t temp_handle_id = 0;
if (blob_open(inode->blob_id, &temp_handle_id) < 0) {
if (blob_open(inode->blob_id, O_RDWR, &temp_handle_id) < 0) {
errno = EIO;
return -1;
}

View File

@@ -5,7 +5,7 @@
#include <unistd.h>
/*
* lseek更新 of->offset非 O_APPEND fd
* lseek更新 daemon handle 上的共享 offset
*
* truncate / ftruncate
* 更新 inode->logical_size同步 st_sizeftruncate 到真实 fd

View File

@@ -39,6 +39,14 @@ static int read_s32(const uint8_t **p, size_t *remaining, int32_t *v) {
return read_bytes(p, remaining, v, sizeof(*v));
}
static int write_s64(uint8_t **p, size_t *remaining, int64_t v) {
return write_bytes(p, remaining, &v, sizeof(v));
}
static int read_s64(const uint8_t **p, size_t *remaining, int64_t *v) {
return read_bytes(p, remaining, v, sizeof(*v));
}
static int write_u64(uint8_t **p, size_t *remaining, uint64_t v) {
return write_bytes(p, remaining, &v, sizeof(v));
}
@@ -176,7 +184,8 @@ size_t zvfs_serialize_req_create(const struct zvfs_req_create_body *body, uint8_
if (!body || !buf) {
return 0;
}
if (write_u64(&p, &remaining, body->size_hint) != 0) {
if (write_u64(&p, &remaining, body->size_hint) != 0 ||
write_u32(&p, &remaining, body->open_flags) != 0) {
return 0;
}
return (size_t)(p - buf);
@@ -189,7 +198,8 @@ size_t zvfs_deserialize_req_create(const uint8_t *buf, size_t buf_len, struct zv
if (!body || !buf) {
return 0;
}
if (read_u64(&p, &remaining, &body->size_hint) != 0) {
if (read_u64(&p, &remaining, &body->size_hint) != 0 ||
read_u32(&p, &remaining, &body->open_flags) != 0) {
return 0;
}
return (size_t)(p - buf);
@@ -202,7 +212,8 @@ size_t zvfs_serialize_req_open(const struct zvfs_req_open_body *body, uint8_t *b
if (!body || !buf) {
return 0;
}
if (write_u64(&p, &remaining, body->blob_id) != 0) {
if (write_u64(&p, &remaining, body->blob_id) != 0 ||
write_u32(&p, &remaining, body->open_flags) != 0) {
return 0;
}
return (size_t)(p - buf);
@@ -215,7 +226,8 @@ size_t zvfs_deserialize_req_open(const uint8_t *buf, size_t buf_len, struct zvfs
if (!body || !buf) {
return 0;
}
if (read_u64(&p, &remaining, &body->blob_id) != 0) {
if (read_u64(&p, &remaining, &body->blob_id) != 0 ||
read_u32(&p, &remaining, &body->open_flags) != 0) {
return 0;
}
return (size_t)(p - buf);
@@ -230,7 +242,8 @@ size_t zvfs_serialize_req_read(const struct zvfs_req_read_body *body, uint8_t *b
}
if (write_u64(&p, &remaining, body->handle_id) != 0 ||
write_u64(&p, &remaining, body->offset) != 0 ||
write_u64(&p, &remaining, body->length) != 0) {
write_u64(&p, &remaining, body->length) != 0 ||
write_u32(&p, &remaining, body->flags) != 0) {
return 0;
}
return (size_t)(p - buf);
@@ -245,7 +258,8 @@ size_t zvfs_deserialize_req_read(const uint8_t *buf, size_t buf_len, struct zvfs
}
if (read_u64(&p, &remaining, &body->handle_id) != 0 ||
read_u64(&p, &remaining, &body->offset) != 0 ||
read_u64(&p, &remaining, &body->length) != 0) {
read_u64(&p, &remaining, &body->length) != 0 ||
read_u32(&p, &remaining, &body->flags) != 0) {
return 0;
}
return (size_t)(p - buf);
@@ -527,6 +541,106 @@ size_t zvfs_deserialize_req_add_ref_batch(const uint8_t *buf, size_t buf_len, st
return (size_t)(p - buf);
}
size_t zvfs_serialize_req_seek(const struct zvfs_req_seek_body *body, uint8_t *buf, size_t buf_len) {
uint8_t *p = buf;
size_t remaining = buf_len;
if (!body || !buf) {
return 0;
}
if (write_u64(&p, &remaining, body->handle_id) != 0 ||
write_s64(&p, &remaining, body->offset) != 0 ||
write_u32(&p, &remaining, body->whence) != 0 ||
write_u64(&p, &remaining, body->logical_size) != 0) {
return 0;
}
return (size_t)(p - buf);
}
size_t zvfs_deserialize_req_seek(const uint8_t *buf, size_t buf_len, struct zvfs_req_seek_body *body) {
const uint8_t *p = buf;
size_t remaining = buf_len;
if (!body || !buf) {
return 0;
}
if (read_u64(&p, &remaining, &body->handle_id) != 0 ||
read_s64(&p, &remaining, &body->offset) != 0 ||
read_u32(&p, &remaining, &body->whence) != 0 ||
read_u64(&p, &remaining, &body->logical_size) != 0) {
return 0;
}
return (size_t)(p - buf);
}
size_t zvfs_serialize_req_get_pos(const struct zvfs_req_get_pos_body *body, uint8_t *buf, size_t buf_len) {
uint8_t *p = buf;
size_t remaining = buf_len;
if (!body || !buf) {
return 0;
}
if (write_u64(&p, &remaining, body->handle_id) != 0) {
return 0;
}
return (size_t)(p - buf);
}
size_t zvfs_deserialize_req_get_pos(const uint8_t *buf, size_t buf_len, struct zvfs_req_get_pos_body *body) {
const uint8_t *p = buf;
size_t remaining = buf_len;
if (!body || !buf) {
return 0;
}
if (read_u64(&p, &remaining, &body->handle_id) != 0) {
return 0;
}
return (size_t)(p - buf);
}
size_t zvfs_serialize_req_get_flags(const struct zvfs_req_get_flags_body *body, uint8_t *buf, size_t buf_len) {
return zvfs_serialize_req_get_pos((const struct zvfs_req_get_pos_body *)body, buf, buf_len);
}
size_t zvfs_deserialize_req_get_flags(const uint8_t *buf, size_t buf_len, struct zvfs_req_get_flags_body *body) {
return zvfs_deserialize_req_get_pos(buf, buf_len, (struct zvfs_req_get_pos_body *)body);
}
size_t zvfs_serialize_req_set_flags(const struct zvfs_req_set_flags_body *body, uint8_t *buf, size_t buf_len) {
uint8_t *p = buf;
size_t remaining = buf_len;
if (!body || !buf) {
return 0;
}
if (write_u64(&p, &remaining, body->handle_id) != 0 ||
write_u32(&p, &remaining, body->flags) != 0) {
return 0;
}
return (size_t)(p - buf);
}
size_t zvfs_deserialize_req_set_flags(const uint8_t *buf, size_t buf_len, struct zvfs_req_set_flags_body *body) {
const uint8_t *p = buf;
size_t remaining = buf_len;
if (!body || !buf) {
return 0;
}
if (read_u64(&p, &remaining, &body->handle_id) != 0 ||
read_u32(&p, &remaining, &body->flags) != 0) {
return 0;
}
return (size_t)(p - buf);
}
/* -------------------- response body -------------------- */
size_t zvfs_serialize_resp_create(const struct zvfs_resp_create_body *body, uint8_t *buf, size_t buf_len) {
@@ -663,6 +777,72 @@ size_t zvfs_deserialize_resp_write(const uint8_t *buf, size_t buf_len, struct zv
return (size_t)(p - buf);
}
size_t zvfs_serialize_resp_seek(const struct zvfs_resp_seek_body *body, uint8_t *buf, size_t buf_len) {
uint8_t *p = buf;
size_t remaining = buf_len;
if (!body || !buf) {
return 0;
}
if (write_u64(&p, &remaining, body->offset) != 0) {
return 0;
}
return (size_t)(p - buf);
}
size_t zvfs_deserialize_resp_seek(const uint8_t *buf, size_t buf_len, struct zvfs_resp_seek_body *body) {
const uint8_t *p = buf;
size_t remaining = buf_len;
if (!body || !buf) {
return 0;
}
memset(body, 0, sizeof(*body));
if (read_u64(&p, &remaining, &body->offset) != 0) {
return 0;
}
return (size_t)(p - buf);
}
size_t zvfs_serialize_resp_get_pos(const struct zvfs_resp_get_pos_body *body, uint8_t *buf, size_t buf_len) {
return zvfs_serialize_resp_seek((const struct zvfs_resp_seek_body *)body, buf, buf_len);
}
size_t zvfs_deserialize_resp_get_pos(const uint8_t *buf, size_t buf_len, struct zvfs_resp_get_pos_body *body) {
return zvfs_deserialize_resp_seek(buf, buf_len, (struct zvfs_resp_seek_body *)body);
}
size_t zvfs_serialize_resp_get_flags(const struct zvfs_resp_get_flags_body *body, uint8_t *buf, size_t buf_len) {
uint8_t *p = buf;
size_t remaining = buf_len;
if (!body || !buf) {
return 0;
}
if (write_u32(&p, &remaining, body->flags) != 0) {
return 0;
}
return (size_t)(p - buf);
}
size_t zvfs_deserialize_resp_get_flags(const uint8_t *buf, size_t buf_len, struct zvfs_resp_get_flags_body *body) {
const uint8_t *p = buf;
size_t remaining = buf_len;
if (!body || !buf) {
return 0;
}
memset(body, 0, sizeof(*body));
if (read_u32(&p, &remaining, &body->flags) != 0) {
return 0;
}
return (size_t)(p - buf);
}
size_t zvfs_serialize_resp_resize(uint8_t *buf, size_t buf_len) {
(void)buf;
(void)buf_len;
@@ -741,13 +921,19 @@ size_t zvfs_serialize_req(struct zvfs_req *req, uint8_t *buf, size_t buf_len) {
switch (req->opcode) {
case ZVFS_OP_CREATE: {
struct zvfs_req_create_body body = { .size_hint = req->size_hint };
struct zvfs_req_create_body body = {
.size_hint = req->size_hint,
.open_flags = req->open_flags,
};
body_len = zvfs_serialize_req_create(&body, buf + ZVFS_REQ_HEADER_WIRE_SIZE,
buf_len - ZVFS_REQ_HEADER_WIRE_SIZE);
break;
}
case ZVFS_OP_OPEN: {
struct zvfs_req_open_body body = { .blob_id = req->blob_id };
struct zvfs_req_open_body body = {
.blob_id = req->blob_id,
.open_flags = req->open_flags,
};
body_len = zvfs_serialize_req_open(&body, buf + ZVFS_REQ_HEADER_WIRE_SIZE,
buf_len - ZVFS_REQ_HEADER_WIRE_SIZE);
break;
@@ -757,6 +943,7 @@ size_t zvfs_serialize_req(struct zvfs_req *req, uint8_t *buf, size_t buf_len) {
.handle_id = req->handle_id,
.offset = req->offset,
.length = req->length,
.flags = req->write_flags,
};
body_len = zvfs_serialize_req_read(&body, buf + ZVFS_REQ_HEADER_WIRE_SIZE,
buf_len - ZVFS_REQ_HEADER_WIRE_SIZE);
@@ -819,6 +1006,38 @@ size_t zvfs_serialize_req(struct zvfs_req *req, uint8_t *buf, size_t buf_len) {
buf_len - ZVFS_REQ_HEADER_WIRE_SIZE);
break;
}
case ZVFS_OP_SEEK: {
struct zvfs_req_seek_body body = {
.handle_id = req->handle_id,
.offset = req->seek_offset,
.whence = req->seek_whence,
.logical_size = req->size_hint,
};
body_len = zvfs_serialize_req_seek(&body, buf + ZVFS_REQ_HEADER_WIRE_SIZE,
buf_len - ZVFS_REQ_HEADER_WIRE_SIZE);
break;
}
case ZVFS_OP_GET_POS: {
struct zvfs_req_get_pos_body body = { .handle_id = req->handle_id };
body_len = zvfs_serialize_req_get_pos(&body, buf + ZVFS_REQ_HEADER_WIRE_SIZE,
buf_len - ZVFS_REQ_HEADER_WIRE_SIZE);
break;
}
case ZVFS_OP_GET_FLAGS: {
struct zvfs_req_get_flags_body body = { .handle_id = req->handle_id };
body_len = zvfs_serialize_req_get_flags(&body, buf + ZVFS_REQ_HEADER_WIRE_SIZE,
buf_len - ZVFS_REQ_HEADER_WIRE_SIZE);
break;
}
case ZVFS_OP_SET_FLAGS: {
struct zvfs_req_set_flags_body body = {
.handle_id = req->handle_id,
.flags = req->handle_flags,
};
body_len = zvfs_serialize_req_set_flags(&body, buf + ZVFS_REQ_HEADER_WIRE_SIZE,
buf_len - ZVFS_REQ_HEADER_WIRE_SIZE);
break;
}
case ZVFS_OP_RESET_BLOBSTORE:
body_len = 0;
break;
@@ -871,6 +1090,7 @@ size_t zvfs_deserialize_req(uint8_t *buf, size_t buf_len, struct zvfs_req *req)
consumed = zvfs_deserialize_req_create(payload, header.payload_len, &body);
if (consumed == header.payload_len) {
req->size_hint = body.size_hint;
req->open_flags = body.open_flags;
}
break;
}
@@ -879,6 +1099,7 @@ size_t zvfs_deserialize_req(uint8_t *buf, size_t buf_len, struct zvfs_req *req)
consumed = zvfs_deserialize_req_open(payload, header.payload_len, &body);
if (consumed == header.payload_len) {
req->blob_id = body.blob_id;
req->open_flags = body.open_flags;
}
break;
}
@@ -889,6 +1110,7 @@ size_t zvfs_deserialize_req(uint8_t *buf, size_t buf_len, struct zvfs_req *req)
req->handle_id = body.handle_id;
req->offset = body.offset;
req->length = body.length;
req->write_flags = body.flags;
req->data = malloc(req->length);
}
break;
@@ -956,6 +1178,42 @@ size_t zvfs_deserialize_req(uint8_t *buf, size_t buf_len, struct zvfs_req *req)
}
break;
}
case ZVFS_OP_SEEK: {
struct zvfs_req_seek_body body;
consumed = zvfs_deserialize_req_seek(payload, header.payload_len, &body);
if (consumed == header.payload_len) {
req->handle_id = body.handle_id;
req->seek_offset = body.offset;
req->seek_whence = body.whence;
req->size_hint = body.logical_size;
}
break;
}
case ZVFS_OP_GET_POS: {
struct zvfs_req_get_pos_body body;
consumed = zvfs_deserialize_req_get_pos(payload, header.payload_len, &body);
if (consumed == header.payload_len) {
req->handle_id = body.handle_id;
}
break;
}
case ZVFS_OP_GET_FLAGS: {
struct zvfs_req_get_flags_body body;
consumed = zvfs_deserialize_req_get_flags(payload, header.payload_len, &body);
if (consumed == header.payload_len) {
req->handle_id = body.handle_id;
}
break;
}
case ZVFS_OP_SET_FLAGS: {
struct zvfs_req_set_flags_body body;
consumed = zvfs_deserialize_req_set_flags(payload, header.payload_len, &body);
if (consumed == header.payload_len) {
req->handle_id = body.handle_id;
req->handle_flags = body.flags;
}
break;
}
case ZVFS_OP_RESET_BLOBSTORE:
if (header.payload_len != 0) {
return 0;
@@ -1032,6 +1290,24 @@ size_t zvfs_serialize_resp(struct zvfs_resp *resp, uint8_t *buf, size_t buf_len)
buf_len - ZVFS_RESP_HEADER_WIRE_SIZE);
break;
}
case ZVFS_OP_SEEK: {
struct zvfs_resp_seek_body body = { .offset = resp->offset };
body_len = zvfs_serialize_resp_seek(&body, buf + ZVFS_RESP_HEADER_WIRE_SIZE,
buf_len - ZVFS_RESP_HEADER_WIRE_SIZE);
break;
}
case ZVFS_OP_GET_POS: {
struct zvfs_resp_get_pos_body body = { .offset = resp->offset };
body_len = zvfs_serialize_resp_get_pos(&body, buf + ZVFS_RESP_HEADER_WIRE_SIZE,
buf_len - ZVFS_RESP_HEADER_WIRE_SIZE);
break;
}
case ZVFS_OP_GET_FLAGS: {
struct zvfs_resp_get_flags_body body = { .flags = resp->handle_flags };
body_len = zvfs_serialize_resp_get_flags(&body, buf + ZVFS_RESP_HEADER_WIRE_SIZE,
buf_len - ZVFS_RESP_HEADER_WIRE_SIZE);
break;
}
case ZVFS_OP_RESIZE:
body_len = 0;
break;
@@ -1048,6 +1324,7 @@ size_t zvfs_serialize_resp(struct zvfs_resp *resp, uint8_t *buf, size_t buf_len)
case ZVFS_OP_DELETE:
case ZVFS_OP_ADD_REF:
case ZVFS_OP_ADD_REF_BATCH:
case ZVFS_OP_SET_FLAGS:
case ZVFS_OP_RESET_BLOBSTORE:
body_len = 0;
break;
@@ -1055,7 +1332,10 @@ size_t zvfs_serialize_resp(struct zvfs_resp *resp, uint8_t *buf, size_t buf_len)
return 0;
}
if (resp->opcode <= ZVFS_OP_WRITE && body_len == 0) {
if ((resp->opcode <= ZVFS_OP_WRITE ||
resp->opcode == ZVFS_OP_SEEK ||
resp->opcode == ZVFS_OP_GET_POS ||
resp->opcode == ZVFS_OP_GET_FLAGS) && body_len == 0) {
return 0;
}
}
@@ -1142,6 +1422,30 @@ size_t zvfs_deserialize_resp(uint8_t *buf, size_t buf_len, struct zvfs_resp *res
}
break;
}
case ZVFS_OP_SEEK: {
struct zvfs_resp_seek_body body;
consumed = zvfs_deserialize_resp_seek(payload, header.payload_len, &body);
if (consumed == header.payload_len) {
resp->offset = body.offset;
}
break;
}
case ZVFS_OP_GET_POS: {
struct zvfs_resp_get_pos_body body;
consumed = zvfs_deserialize_resp_get_pos(payload, header.payload_len, &body);
if (consumed == header.payload_len) {
resp->offset = body.offset;
}
break;
}
case ZVFS_OP_GET_FLAGS: {
struct zvfs_resp_get_flags_body body;
consumed = zvfs_deserialize_resp_get_flags(payload, header.payload_len, &body);
if (consumed == header.payload_len) {
resp->handle_flags = body.flags;
}
break;
}
case ZVFS_OP_RESIZE:
if (header.payload_len != 0) {
return 0;
@@ -1160,6 +1464,7 @@ size_t zvfs_deserialize_resp(uint8_t *buf, size_t buf_len, struct zvfs_resp *res
case ZVFS_OP_DELETE:
case ZVFS_OP_ADD_REF:
case ZVFS_OP_ADD_REF_BATCH:
case ZVFS_OP_SET_FLAGS:
case ZVFS_OP_RESET_BLOBSTORE:
if (header.payload_len != 0) {
return 0;

View File

@@ -22,6 +22,10 @@ enum zvfs_opcode {
ZVFS_OP_DELETE,
ZVFS_OP_ADD_REF,
ZVFS_OP_ADD_REF_BATCH,
ZVFS_OP_SEEK,
ZVFS_OP_GET_POS,
ZVFS_OP_GET_FLAGS,
ZVFS_OP_SET_FLAGS,
ZVFS_OP_RESET_BLOBSTORE
};
@@ -58,6 +62,18 @@ inline const char* cast_opcode2string(uint32_t op){
case ZVFS_OP_ADD_REF_BATCH:
return "ADD_REF_BATCH";
break;
case ZVFS_OP_SEEK:
return "SEEK";
break;
case ZVFS_OP_GET_POS:
return "GET_POS";
break;
case ZVFS_OP_GET_FLAGS:
return "GET_FLAGS";
break;
case ZVFS_OP_SET_FLAGS:
return "SET_FLAGS";
break;
case ZVFS_OP_RESET_BLOBSTORE:
return "RESET_BLOBSTORE";
break;
@@ -68,6 +84,7 @@ inline const char* cast_opcode2string(uint32_t op){
}
#define ZVFS_WRITE_F_AUTO_GROW (1u << 0)
#define ZVFS_RW_F_USE_HANDLE_POS (1u << 1)
#define ZVFS_RESP_TRACE_F_VALID (1u << 0)
#define ZVFS_RESP_TRACE_F_PHASE1_VALID (1u << 1)
@@ -92,16 +109,19 @@ struct zvfs_resp_header {
struct zvfs_req_create_body {
uint64_t size_hint;
uint32_t open_flags;
};
struct zvfs_req_open_body {
uint64_t blob_id;
uint32_t open_flags;
};
struct zvfs_req_read_body {
uint64_t handle_id;
uint64_t offset;
uint64_t length;
uint32_t flags;
};
struct zvfs_req_write_body {
@@ -144,6 +164,26 @@ struct zvfs_req_add_ref_batch_body {
const struct zvfs_add_ref_item *items;
};
struct zvfs_req_seek_body {
uint64_t handle_id;
int64_t offset;
uint32_t whence;
uint64_t logical_size;
};
struct zvfs_req_get_pos_body {
uint64_t handle_id;
};
struct zvfs_req_get_flags_body {
uint64_t handle_id;
};
struct zvfs_req_set_flags_body {
uint64_t handle_id;
uint32_t flags;
};
/* -------------------- per-op response body -------------------- */
struct zvfs_resp_create_body {
@@ -183,6 +223,18 @@ struct zvfs_resp_sync_md_body {
struct zvfs_resp_trace trace;
};
struct zvfs_resp_seek_body {
uint64_t offset;
};
struct zvfs_resp_get_pos_body {
uint64_t offset;
};
struct zvfs_resp_get_flags_body {
uint32_t flags;
};
/* resize/sync_md/close/delete 成功时 body 为空 */
size_t zvfs_serialize_resp_resize(uint8_t *buf, size_t buf_len);
size_t zvfs_deserialize_resp_resize(const uint8_t *buf, size_t buf_len);
@@ -205,11 +257,15 @@ struct zvfs_req {
uint64_t offset;
uint64_t length;
uint32_t write_flags;
uint32_t open_flags;
uint32_t handle_flags;
void *data;
uint32_t ref_delta;
uint32_t add_ref_count;
struct zvfs_add_ref_item *add_ref_items;
int64_t seek_offset;
uint32_t seek_whence;
struct zvfs_conn *conn;
struct zvfs_blob_handle *handle;
@@ -225,12 +281,14 @@ struct zvfs_resp {
uint64_t blob_id;
uint64_t handle_id;
uint64_t size;
uint64_t offset;
uint64_t length;
void *data;
uint64_t bytes_written;
struct zvfs_resp_trace trace;
uint32_t handle_flags;
struct zvfs_conn *conn;
};
@@ -277,6 +335,18 @@ size_t zvfs_deserialize_req_add_ref(const uint8_t *buf, size_t buf_len, struct z
size_t zvfs_serialize_req_add_ref_batch(const struct zvfs_req_add_ref_batch_body *body, uint8_t *buf, size_t buf_len);
size_t zvfs_deserialize_req_add_ref_batch(const uint8_t *buf, size_t buf_len, struct zvfs_req_add_ref_batch_body *body);
size_t zvfs_serialize_req_seek(const struct zvfs_req_seek_body *body, uint8_t *buf, size_t buf_len);
size_t zvfs_deserialize_req_seek(const uint8_t *buf, size_t buf_len, struct zvfs_req_seek_body *body);
size_t zvfs_serialize_req_get_pos(const struct zvfs_req_get_pos_body *body, uint8_t *buf, size_t buf_len);
size_t zvfs_deserialize_req_get_pos(const uint8_t *buf, size_t buf_len, struct zvfs_req_get_pos_body *body);
size_t zvfs_serialize_req_get_flags(const struct zvfs_req_get_flags_body *body, uint8_t *buf, size_t buf_len);
size_t zvfs_deserialize_req_get_flags(const uint8_t *buf, size_t buf_len, struct zvfs_req_get_flags_body *body);
size_t zvfs_serialize_req_set_flags(const struct zvfs_req_set_flags_body *body, uint8_t *buf, size_t buf_len);
size_t zvfs_deserialize_req_set_flags(const uint8_t *buf, size_t buf_len, struct zvfs_req_set_flags_body *body);
/* -------------------- response body 序列化/反序列化 -------------------- */
size_t zvfs_serialize_resp_create(const struct zvfs_resp_create_body *body, uint8_t *buf, size_t buf_len);
@@ -291,6 +361,15 @@ size_t zvfs_deserialize_resp_read(const uint8_t *buf, size_t buf_len, struct zvf
size_t zvfs_serialize_resp_write(const struct zvfs_resp_write_body *body, uint8_t *buf, size_t buf_len);
size_t zvfs_deserialize_resp_write(const uint8_t *buf, size_t buf_len, struct zvfs_resp_write_body *body);
size_t zvfs_serialize_resp_seek(const struct zvfs_resp_seek_body *body, uint8_t *buf, size_t buf_len);
size_t zvfs_deserialize_resp_seek(const uint8_t *buf, size_t buf_len, struct zvfs_resp_seek_body *body);
size_t zvfs_serialize_resp_get_pos(const struct zvfs_resp_get_pos_body *body, uint8_t *buf, size_t buf_len);
size_t zvfs_deserialize_resp_get_pos(const uint8_t *buf, size_t buf_len, struct zvfs_resp_get_pos_body *body);
size_t zvfs_serialize_resp_get_flags(const struct zvfs_resp_get_flags_body *body, uint8_t *buf, size_t buf_len);
size_t zvfs_deserialize_resp_get_flags(const uint8_t *buf, size_t buf_len, struct zvfs_resp_get_flags_body *body);
/* -------------------- 兼容封装 -------------------- */
size_t zvfs_serialize_req(struct zvfs_req *req, uint8_t *buf, size_t buf_len);

View File

@@ -475,7 +475,7 @@ int io_engine_init(void) {
return 0;
}
int blob_create(uint64_t size_hint, uint64_t *blob_id_out, uint64_t *handle_id_out) {
int blob_create(uint64_t size_hint, int open_flags, uint64_t *blob_id_out, uint64_t *handle_id_out) {
if (!blob_id_out || !handle_id_out) {
errno = EINVAL;
return -1;
@@ -485,6 +485,7 @@ int blob_create(uint64_t size_hint, uint64_t *blob_id_out, uint64_t *handle_id_o
memset(&req, 0, sizeof(req));
req.opcode = ZVFS_OP_CREATE;
req.size_hint = size_hint;
req.open_flags = (uint32_t)open_flags;
struct zvfs_resp resp;
memset(&resp, 0, sizeof(resp));
@@ -502,7 +503,7 @@ int blob_create(uint64_t size_hint, uint64_t *blob_id_out, uint64_t *handle_id_o
return 0;
}
int blob_open(uint64_t blob_id, uint64_t *handle_id_out) {
int blob_open(uint64_t blob_id, int open_flags, uint64_t *handle_id_out) {
if (!handle_id_out) {
errno = EINVAL;
return -1;
@@ -512,6 +513,7 @@ int blob_open(uint64_t blob_id, uint64_t *handle_id_out) {
memset(&req, 0, sizeof(req));
req.opcode = ZVFS_OP_OPEN;
req.blob_id = blob_id;
req.open_flags = (uint32_t)open_flags;
struct zvfs_resp resp;
memset(&resp, 0, sizeof(resp));
@@ -571,7 +573,12 @@ int blob_write(uint64_t handle_id, uint64_t offset, const void *buf, size_t len)
return blob_write_ex(handle_id, offset, buf, len, 0);
}
int blob_read(uint64_t handle_id, uint64_t offset, void *buf, size_t len) {
int blob_write_shared(uint64_t handle_id, uint64_t logical_size, const void *buf, size_t len, uint32_t write_flags) {
return blob_write_ex(handle_id, logical_size, buf, len,
write_flags | ZVFS_RW_F_USE_HANDLE_POS);
}
ssize_t blob_read_ex(uint64_t handle_id, uint64_t offset, void *buf, size_t len, uint32_t read_flags) {
if (len == 0) {
return 0;
}
@@ -586,6 +593,7 @@ int blob_read(uint64_t handle_id, uint64_t offset, void *buf, size_t len) {
req.handle_id = handle_id;
req.offset = offset;
req.length = (uint64_t)len;
req.write_flags = read_flags;
struct zvfs_resp resp;
memset(&resp, 0, sizeof(resp));
@@ -594,7 +602,7 @@ int blob_read(uint64_t handle_id, uint64_t offset, void *buf, size_t len) {
return -1;
}
if (!resp.data || resp.length != (uint64_t)len) {
if (!resp.data && resp.length != 0) {
if (resp.data) {
free(resp.data);
}
@@ -602,11 +610,35 @@ int blob_read(uint64_t handle_id, uint64_t offset, void *buf, size_t len) {
return -1;
}
memcpy(buf, resp.data, len);
if (resp.length > len) {
free(resp.data);
errno = EPROTO;
return -1;
}
if (resp.length > 0) {
memcpy(buf, resp.data, (size_t)resp.length);
}
free(resp.data);
return (ssize_t)resp.length;
}
int blob_read(uint64_t handle_id, uint64_t offset, void *buf, size_t len) {
ssize_t nr = blob_read_ex(handle_id, offset, buf, len, 0);
if (nr < 0) {
return -1;
}
if ((size_t)nr != len) {
errno = EPROTO;
return -1;
}
return 0;
}
ssize_t blob_read_shared(uint64_t handle_id, uint64_t logical_size, void *buf, size_t len) {
return blob_read_ex(handle_id, logical_size, buf, len, ZVFS_RW_F_USE_HANDLE_POS);
}
int blob_resize(uint64_t handle_id, uint64_t new_size) {
if (handle_id == 0) {
errno = EINVAL;
@@ -769,3 +801,106 @@ int blob_add_ref_batch(const uint64_t *handle_ids, const uint32_t *ref_deltas, u
}
return 0;
}
int blob_seek(uint64_t handle_id, int64_t offset, int whence, uint64_t logical_size, uint64_t *new_offset_out) {
if (handle_id == 0 || !new_offset_out) {
errno = EINVAL;
return -1;
}
struct zvfs_req req;
memset(&req, 0, sizeof(req));
req.opcode = ZVFS_OP_SEEK;
req.handle_id = handle_id;
req.seek_offset = offset;
req.seek_whence = (uint32_t)whence;
req.size_hint = logical_size;
struct zvfs_resp resp;
memset(&resp, 0, sizeof(resp));
if (ipc_do_req(&req, &resp) != 0) {
return -1;
}
*new_offset_out = resp.offset;
if (resp.data) {
free(resp.data);
}
return 0;
}
int blob_get_pos(uint64_t handle_id, uint64_t *offset_out) {
if (handle_id == 0 || !offset_out) {
errno = EINVAL;
return -1;
}
struct zvfs_req req;
memset(&req, 0, sizeof(req));
req.opcode = ZVFS_OP_GET_POS;
req.handle_id = handle_id;
struct zvfs_resp resp;
memset(&resp, 0, sizeof(resp));
if (ipc_do_req(&req, &resp) != 0) {
return -1;
}
*offset_out = resp.offset;
if (resp.data) {
free(resp.data);
}
return 0;
}
int blob_get_flags(uint64_t handle_id, uint32_t *flags_out) {
if (handle_id == 0 || !flags_out) {
errno = EINVAL;
return -1;
}
struct zvfs_req req;
memset(&req, 0, sizeof(req));
req.opcode = ZVFS_OP_GET_FLAGS;
req.handle_id = handle_id;
struct zvfs_resp resp;
memset(&resp, 0, sizeof(resp));
if (ipc_do_req(&req, &resp) != 0) {
return -1;
}
*flags_out = resp.handle_flags;
if (resp.data) {
free(resp.data);
}
return 0;
}
int blob_set_flags(uint64_t handle_id, uint32_t flags) {
if (handle_id == 0) {
errno = EINVAL;
return -1;
}
struct zvfs_req req;
memset(&req, 0, sizeof(req));
req.opcode = ZVFS_OP_SET_FLAGS;
req.handle_id = handle_id;
req.handle_flags = flags;
struct zvfs_resp resp;
memset(&resp, 0, sizeof(resp));
if (ipc_do_req(&req, &resp) != 0) {
return -1;
}
if (resp.data) {
free(resp.data);
}
return 0;
}

View File

@@ -3,19 +3,27 @@
#include <stdint.h>
#include <stddef.h>
#include <sys/types.h>
int io_engine_init(void);
int blob_create(uint64_t size_hint, uint64_t *blob_id_out, uint64_t *handle_id_out);
int blob_open(uint64_t blob_id, uint64_t *handle_id_out);
int blob_create(uint64_t size_hint, int open_flags, uint64_t *blob_id_out, uint64_t *handle_id_out);
int blob_open(uint64_t blob_id, int open_flags, uint64_t *handle_id_out);
int blob_write_ex(uint64_t handle_id, uint64_t offset, const void *buf, size_t len, uint32_t write_flags);
int blob_write(uint64_t handle_id, uint64_t offset, const void *buf, size_t len);
int blob_write_shared(uint64_t handle_id, uint64_t logical_size, const void *buf, size_t len, uint32_t write_flags);
ssize_t blob_read_ex(uint64_t handle_id, uint64_t offset, void *buf, size_t len, uint32_t read_flags);
int blob_read(uint64_t handle_id, uint64_t offset, void *buf, size_t len);
ssize_t blob_read_shared(uint64_t handle_id, uint64_t logical_size, void *buf, size_t len);
int blob_resize(uint64_t handle_id, uint64_t new_size);
int blob_sync_md(uint64_t handle_id);
int blob_close(uint64_t handle_id);
int blob_delete(uint64_t blob_id);
int blob_add_ref(uint64_t handle_id, uint32_t ref_delta);
int blob_add_ref_batch(const uint64_t *handle_ids, const uint32_t *ref_deltas, uint32_t count);
int blob_seek(uint64_t handle_id, int64_t offset, int whence, uint64_t logical_size, uint64_t *new_offset_out);
int blob_get_pos(uint64_t handle_id, uint64_t *offset_out);
int blob_get_flags(uint64_t handle_id, uint32_t *flags_out);
int blob_set_flags(uint64_t handle_id, uint32_t flags);
#endif // __ZVFS_IO_ENGINE_H__

View File

@@ -177,6 +177,12 @@ test_dup_fcntl_ioctl(const char *workdir)
int file_flags_after = fcntl(fd, F_GETFL);
ASSERT_SYS_OK(file_flags_after);
ASSERT_TRUE((file_flags_after & O_APPEND) != 0, "O_APPEND should be set");
if (dup_supported) {
int file_flags_dup = fcntl(fd2, F_GETFL);
ASSERT_SYS_OK(file_flags_dup);
ASSERT_TRUE((file_flags_dup & O_APPEND) != 0,
"dup should share status flags like O_APPEND");
}
int avail = -1;
ASSERT_SYS_OK(ioctl(dup_supported ? fd2 : fd, FIONREAD, &avail));