diff --git a/.codex b/.codex new file mode 100644 index 0000000..e69de29 diff --git a/src/daemon/spdk_engine.c b/src/daemon/spdk_engine.c index 390156d..7fd6259 100644 --- a/src/daemon/spdk_engine.c +++ b/src/daemon/spdk_engine.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -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) { diff --git a/src/daemon/spdk_engine.h b/src/daemon/spdk_engine.h index 7920e8f..c7bab2f 100644 --- a/src/daemon/spdk_engine.h +++ b/src/daemon/spdk_engine.h @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -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); diff --git a/src/daemon/spdk_engine_wrapper.c b/src/daemon/spdk_engine_wrapper.c index be78f53..9d80d83 100644 --- a/src/daemon/spdk_engine_wrapper.c +++ b/src/daemon/spdk_engine_wrapper.c @@ -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: diff --git a/src/daemon/zvfs_daemon b/src/daemon/zvfs_daemon index b224b1e..990e85b 100755 Binary files a/src/daemon/zvfs_daemon and b/src/daemon/zvfs_daemon differ diff --git a/src/fs/zvfs_open_file.c b/src/fs/zvfs_open_file.c index f328e63..8e454e9 100644 --- a/src/fs/zvfs_open_file.c +++ b/src/fs/zvfs_open_file.c @@ -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; -} diff --git a/src/fs/zvfs_open_file.h b/src/fs/zvfs_open_file.h index 7b2fd98..a03fbc8 100644 --- a/src/fs/zvfs_open_file.h +++ b/src/fs/zvfs_open_file.h @@ -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__ diff --git a/src/hook/zvfs_hook_fcntl.c b/src/hook/zvfs_hook_fcntl.c index 475b419..b926314 100644 --- a/src/hook/zvfs_hook_fcntl.c +++ b/src/hook/zvfs_hook_fcntl.c @@ -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; diff --git a/src/hook/zvfs_hook_fcntl.h b/src/hook/zvfs_hook_fcntl.h index 28594b3..aabccfe 100644 --- a/src/hook/zvfs_hook_fcntl.h +++ b/src/hook/zvfs_hook_fcntl.h @@ -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_flags(FD_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 */ @@ -24,4 +24,4 @@ int fcntl(int fd, int cmd, ...); int fcntl64(int fd, int cmd, ...); int ioctl(int fd, unsigned long request, ...); -#endif // __ZVFS_HOOK_FCNTL_H__ \ No newline at end of file +#endif // __ZVFS_HOOK_FCNTL_H__ diff --git a/src/hook/zvfs_hook_fd.c b/src/hook/zvfs_hook_fd.c index 706bd30..12ec052 100644 --- a/src/hook/zvfs_hook_fd.c +++ b/src/hook/zvfs_hook_fd.c @@ -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; diff --git a/src/hook/zvfs_hook_rw.c b/src/hook/zvfs_hook_rw.c index 3c20b6a..326c2dc 100644 --- a/src/hook/zvfs_hook_rw.c +++ b/src/hook/zvfs_hook_rw.c @@ -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) /* flags(RWF_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; diff --git a/src/hook/zvfs_hook_rw.h b/src/hook/zvfs_hook_rw.h index 9a7a586..435bca3 100644 --- a/src/hook/zvfs_hook_rw.h +++ b/src/hook/zvfs_hook_rw.h @@ -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,合并结果。 diff --git a/src/hook/zvfs_hook_seek.c b/src/hook/zvfs_hook_seek.c index d600b65..b70ee8e 100644 --- a/src/hook/zvfs_hook_seek.c +++ b/src/hook/zvfs_hook_seek.c @@ -40,16 +40,12 @@ lseek(int fd, off_t offset, int whence) 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_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; } diff --git a/src/hook/zvfs_hook_seek.h b/src/hook/zvfs_hook_seek.h index 5aa9819..fdf6661 100644 --- a/src/hook/zvfs_hook_seek.h +++ b/src/hook/zvfs_hook_seek.h @@ -5,7 +5,7 @@ #include /* - * lseek:更新 of->offset(非 O_APPEND fd)。 + * lseek:更新 daemon handle 上的共享 offset。 * * truncate / ftruncate: * 更新 inode->logical_size,同步 st_size(ftruncate 到真实 fd), @@ -30,4 +30,4 @@ int ftruncate64(int fd, off_t length); int fallocate(int fd, int mode, off_t offset, off_t len); int posix_fallocate(int fd, off_t offset, off_t len); -#endif // __ZVFS_HOOK_SEEK_H__ \ No newline at end of file +#endif // __ZVFS_HOOK_SEEK_H__ diff --git a/src/proto/ipc_proto.c b/src/proto/ipc_proto.c index 3d3a617..9f30f2e 100644 --- a/src/proto/ipc_proto.c +++ b/src/proto/ipc_proto.c @@ -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; diff --git a/src/proto/ipc_proto.h b/src/proto/ipc_proto.h index a7eeedb..ebd0792 100644 --- a/src/proto/ipc_proto.h +++ b/src/proto/ipc_proto.h @@ -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); diff --git a/src/spdk_engine/io_engine.c b/src/spdk_engine/io_engine.c index 5689166..d99f575 100644 --- a/src/spdk_engine/io_engine.c +++ b/src/spdk_engine/io_engine.c @@ -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; +} diff --git a/src/spdk_engine/io_engine.h b/src/spdk_engine/io_engine.h index 8fbcece..24d4346 100644 --- a/src/spdk_engine/io_engine.h +++ b/src/spdk_engine/io_engine.h @@ -3,19 +3,27 @@ #include #include +#include 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__ diff --git a/tests/hook_test/hook_api_test.c b/tests/hook_test/hook_api_test.c index 84e8a8e..4ea95e0 100644 --- a/tests/hook_test/hook_api_test.c +++ b/tests/hook_test/hook_api_test.c @@ -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));