/* lib9p/tests/test_server/fs_flush.c - flush-* API endpoints * * Copyright (C) 2024-2025 Luke T. Shumaker * SPDX-License-Identifier: AGPL-3.0-or-later */ #include #define IMPLEMENTATION_FOR_LIB9P_SRV_H YES /* for ctx->flush_ch */ #include "fs_flush.h" LO_IMPLEMENTATION_C(lib9p_srv_file, struct flush_file, flush_file, static); struct flush_fio { struct flush_file *parent; }; LO_IMPLEMENTATION_H(lib9p_srv_fio, struct flush_fio, flush_fio); LO_IMPLEMENTATION_C(lib9p_srv_fio, struct flush_fio, flush_fio, static); /* srv_file *******************************************************************/ static void flush_file_free(struct flush_file *self) { assert(self); } static struct lib9p_qid flush_file_qid(struct flush_file *self) { assert(self); return (struct lib9p_qid){ .type = LIB9P_QT_FILE, .vers = 1, .path = self->pathnum, }; } static struct lib9p_srv_stat flush_file_stat(struct flush_file *self, struct lib9p_srv_ctx *ctx) { assert(self); assert(ctx); return (struct lib9p_srv_stat){ .qid = flush_file_qid(self), .mode = 0444, .atime_sec = UTIL9P_ATIME, .mtime_sec = UTIL9P_MTIME, .size = 6, .name = lib9p_str(self->name), .owner_uid = { .name = lib9p_str("root"), .num = 0 }, .owner_gid = { .name = lib9p_str("root"), .num = 0 }, .last_modifier_uid = { .name = lib9p_str("root"), .num = 0 }, .extension = lib9p_str(NULL), }; } static void flush_file_wstat(struct flush_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat) { assert(self); assert(ctx); lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "cannot wstat API file"); } static void flush_file_remove(struct flush_file *self, struct lib9p_srv_ctx *ctx) { assert(self); assert(ctx); lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_EROFS, "cannot remove API file"); } LIB9P_SRV_NOTDIR(struct flush_file, flush_file) static lo_interface lib9p_srv_fio flush_file_fopen(struct flush_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) { assert(self); assert(ctx); struct flush_fio *ret = heap_alloc(1, struct flush_fio); ret->parent = self; return lo_box_flush_fio_as_lib9p_srv_fio(ret); } /* srv_fio ********************************************************************/ static void flush_fio_iofree(struct flush_fio *self) { assert(self); free(self); } static struct lib9p_qid flush_fio_qid(struct flush_fio *self) { assert(self); return flush_file_qid(self->parent); } static uint32_t flush_fio_iounit(struct flush_fio *self) { assert(self); return 0; } static uint32_t flush_fio_pwrite(struct flush_fio *LM_UNUSED(self), struct lib9p_srv_ctx *LM_UNUSED(ctx), void *LM_UNUSED(buf), uint32_t LM_UNUSED(byte_count), uint64_t LM_UNUSED(offset)) { assert_notreached("not writable"); } static void flush_fio_pread(struct flush_fio *self, struct lib9p_srv_ctx *ctx, uint32_t byte_count, uint64_t LM_UNUSED(byte_offset), struct iovec *ret) { assert(self); assert(ctx); assert(ret); /* Wait for first Tflush */ while (!lib9p_srv_flush_requested(ctx)) cr_yield(); /* Wait for the specified number of Tflush (may be higher *or* * lower than 1; lower would mean that the first Tflush needs * to be flushed itself). */ while (cr_chan_num_waiters(&ctx->flush_ch) != self->parent->flush_cnt) cr_yield(); /* Return */ switch (self->parent->flush_behavior) { case FLUSH_READ: *ret = (struct iovec){ .iov_base = "Sloth\n", .iov_len = 6 < byte_count ? 6 : byte_count, }; break; case FLUSH_ERROR: lib9p_srv_acknowledge_flush(ctx); lib9p_error(&ctx->basectx, LIB9P_ERRNO_L_ECANCELED, "request canceled by flush"); break; case FLUSH_SILENT: lib9p_srv_acknowledge_flush(ctx); break; } cr_yield(); }