diff options
-rwxr-xr-x | build-aux/valgrind | 1 | ||||
-rw-r--r-- | lib9p/tests/test_server/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib9p/tests/test_server/fs_slowread.c | 101 | ||||
-rw-r--r-- | lib9p/tests/test_server/fs_slowread.h | 22 | ||||
-rw-r--r-- | lib9p/tests/test_server/main.c | 5 | ||||
-rwxr-xr-x | lib9p/tests/testclient-p9p | 4 | ||||
-rw-r--r-- | lib9p/tests/testclient-p9p.explog | 20 | ||||
-rw-r--r-- | lib9p/tests/testclient-sess.c | 31 | ||||
-rw-r--r-- | lib9p/tests/testclient-sess.explog | 32 |
9 files changed, 205 insertions, 12 deletions
diff --git a/build-aux/valgrind b/build-aux/valgrind index 728faca..7ad2712 100755 --- a/build-aux/valgrind +++ b/build-aux/valgrind @@ -6,6 +6,7 @@ exec \ valgrind \ + --fair-sched=yes \ --error-exitcode=2 \ --leak-check=full \ --show-leak-kinds=all \ diff --git a/lib9p/tests/test_server/CMakeLists.txt b/lib9p/tests/test_server/CMakeLists.txt index 19c8edb..eb16165 100644 --- a/lib9p/tests/test_server/CMakeLists.txt +++ b/lib9p/tests/test_server/CMakeLists.txt @@ -10,6 +10,7 @@ if (PICO_PLATFORM STREQUAL "host") add_library(test_server_objs OBJECT main.c fs_shutdown.c + fs_slowread.c ) target_include_directories(test_server_objs PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/config) target_include_directories(test_server_objs PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/lib9p/tests/test_server/fs_slowread.c b/lib9p/tests/test_server/fs_slowread.c new file mode 100644 index 0000000..520edd2 --- /dev/null +++ b/lib9p/tests/test_server/fs_slowread.c @@ -0,0 +1,101 @@ +/* lib9p/tests/test_server/fs_slowread.c - slowread API endpoint + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include "fs_slowread.h" + +LO_IMPLEMENTATION_C(lib9p_srv_file, struct slowread_file, slowread_file, static); + +LO_IMPLEMENTATION_H(lib9p_srv_fio, struct slowread_file, slowread_file); +LO_IMPLEMENTATION_C(lib9p_srv_fio, struct slowread_file, slowread_file, static); + +/* srv_file *******************************************************************/ + +static void slowread_file_free(struct slowread_file *self) { + assert(self); +} +static struct lib9p_qid slowread_file_qid(struct slowread_file *self) { + assert(self); + return (struct lib9p_qid){ + .type = LIB9P_QT_FILE, + .vers = 1, + .path = self->pathnum, + }; +} + +static struct lib9p_stat slowread_file_stat(struct slowread_file *self, struct lib9p_srv_ctx *ctx) { + assert(self); + assert(ctx); + return (struct lib9p_stat){ + .kern_type = 0, + .kern_dev = 0, + .file_qid = slowread_file_qid(self), + .file_mode = 0444, + .file_atime = UTIL9P_ATIME, + .file_mtime = UTIL9P_MTIME, + .file_size = 6, + .file_name = lib9p_str(self->name), + .file_owner_uid = lib9p_str("root"), + .file_owner_gid = lib9p_str("root"), + .file_last_modified_uid = lib9p_str("root"), + .file_extension = lib9p_str(NULL), + .file_owner_n_uid = 0, + .file_owner_n_gid = 0, + .file_last_modified_n_uid = 0, + }; +} +static void slowread_file_wstat(struct slowread_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_stat) { + assert(self); + assert(ctx); + lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot wstat API file"); +} +static void slowread_file_remove(struct slowread_file *self, struct lib9p_srv_ctx *ctx) { + assert(self); + assert(ctx); + lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot remove API file"); +} + +LIB9P_SRV_NOTDIR(struct slowread_file, slowread_file) + +static lo_interface lib9p_srv_fio slowread_file_fopen(struct slowread_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) { + assert(self); + assert(ctx); + return lo_box_slowread_file_as_lib9p_srv_fio(self); +} + +/* srv_fio ********************************************************************/ + +static void slowread_file_iofree(struct slowread_file *self) { + assert(self); +} + +static uint32_t slowread_file_iounit(struct slowread_file *self) { + assert(self); + return 0; +} + +static uint32_t slowread_file_pwrite(struct slowread_file *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 slowread_file_pread(struct slowread_file *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); + + while (!lib9p_srv_flush_requested(ctx)) + cr_yield(); + if (self->flushable) + lib9p_srv_acknowledge_flush(ctx); + else + *ret = (struct iovec){ + .iov_base = "Sloth\n", + .iov_len = 6 < byte_count ? 6 : byte_count, + }; +} diff --git a/lib9p/tests/test_server/fs_slowread.h b/lib9p/tests/test_server/fs_slowread.h new file mode 100644 index 0000000..ef4b65f --- /dev/null +++ b/lib9p/tests/test_server/fs_slowread.h @@ -0,0 +1,22 @@ +/* lib9p/tests/test_server/fs_slowread.h - slowread API endpoint + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIB9P_TESTS_TEST_SERVER_FS_SLOWREAD_H_ +#define _LIB9P_TESTS_TEST_SERVER_FS_SLOWREAD_H_ + +#include <util9p/static.h> +#include <libhw/host_net.h> + +struct slowread_file { + char *name; + uint64_t pathnum; + + bool flushable; +}; +LO_IMPLEMENTATION_H(lib9p_srv_file, struct slowread_file, slowread_file); +#define lo_box_slowread_file_as_lib9p_srv_file(obj) util9p_box(slowread_file, obj) + +#endif /* _LIB9P_TESTS_TEST_SERVER_FS_SLOWREAD_H_ */ diff --git a/lib9p/tests/test_server/main.c b/lib9p/tests/test_server/main.c index 01a1738..e5e54e9 100644 --- a/lib9p/tests/test_server/main.c +++ b/lib9p/tests/test_server/main.c @@ -20,6 +20,7 @@ #include "static.h" #include "fs_shutdown.h" +#include "fs_slowread.h" /* configuration **************************************************************/ @@ -74,6 +75,10 @@ struct lib9p_srv_file root = API_FILE("shutdown", shutdown, .listeners = globals.listeners, .nlisteners = LM_ARRAY_LEN(globals.listeners)), + API_FILE("slowread", slowread, + .flushable = false), + API_FILE("slowread-flushable", slowread, + .flushable = true), ); static lo_interface lib9p_srv_file get_root(struct lib9p_srv_ctx *LM_UNUSED(ctx), struct lib9p_s LM_UNUSED(treename)) { diff --git a/lib9p/tests/testclient-p9p b/lib9p/tests/testclient-p9p index 5e4c2c8..55ca069 100755 --- a/lib9p/tests/testclient-p9p +++ b/lib9p/tests/testclient-p9p @@ -25,7 +25,9 @@ out=$("${client[@]}" ls -l '') expect_lines \ 'd-r-xr-xr-x M 0 root root 0 Oct 7 2024 Documentation' \ '--r--r--r-- M 0 root root 166 Oct 7 2024 README.md' \ - '---w--w--w- M 0 root root 0 Oct 7 2024 shutdown' + '---w--w--w- M 0 root root 0 Oct 7 2024 shutdown' \ + '--r--r--r-- M 0 root root 6 Oct 7 2024 slowread' \ + '--r--r--r-- M 0 root root 6 Oct 7 2024 slowread-flushable' out=$("${client[@]}" ls -l 'Documentation/') expect_lines \ diff --git a/lib9p/tests/testclient-p9p.explog b/lib9p/tests/testclient-p9p.explog index c9c3f55..7874de4 100644 --- a/lib9p/tests/testclient-p9p.explog +++ b/lib9p/tests/testclient-p9p.explog @@ -7,20 +7,20 @@ > Tauth { tag=0 afid=0 uname="lukeshu" aname="" n_uid=0 } < Rerror { tag=0 errstr="authentication not required" errnum=95 } > Tattach { tag=0 fid=0 afid=NOFID uname="lukeshu" aname="" n_uid=0 } -< Rattach { tag=0 qid={ type=(DIR) vers=1 path=5 } } +< Rattach { tag=0 qid={ type=(DIR) vers=1 path=7 } } > Twalk { tag=0 fid=0 newfid=1 nwname=0 wname=[ ] } < Rwalk { tag=0 nwqid=0 wqid=[ ] } > Tstat { tag=0 fid=1 } -< Rstat { tag=0 stat={ kern_type=0 kern_dev=0 file_qid={ type=(DIR) vers=1 path=5 } file_mode=(DIR|0555) file_atime=1728337905 file_mtime=1728337904 file_size=0 file_name="" file_owner_uid="root" file_owner_gid="root" file_last_modified_uid="root" file_extension="" file_owner_n_uid=0 file_owner_n_gid=0 file_last_modified_n_uid=0 } } +< Rstat { tag=0 stat={ kern_type=0 kern_dev=0 file_qid={ type=(DIR) vers=1 path=7 } file_mode=(DIR|0555) file_atime=1728337905 file_mtime=1728337904 file_size=0 file_name="" file_owner_uid="root" file_owner_gid="root" file_last_modified_uid="root" file_extension="" file_owner_n_uid=0 file_owner_n_gid=0 file_last_modified_n_uid=0 } } > Tclunk { tag=0 fid=1 } < Rclunk { tag=0 } > Twalk { tag=0 fid=0 newfid=1 nwname=0 wname=[ ] } < Rwalk { tag=0 nwqid=0 wqid=[ ] } > Topen { tag=0 fid=1 mode=(MODE_READ) } -< Ropen { tag=0 qid={ type=(DIR) vers=1 path=5 } iounit=0 } +< Ropen { tag=0 qid={ type=(DIR) vers=1 path=7 } iounit=0 } > Tread { tag=0 fid=1 offset=0 count=4096 } -< Rread { tag=0 count=213 data=<bytedata> } -> Tread { tag=0 fid=1 offset=213 count=4096 } +< Rread { tag=0 count=361 data=<bytedata> } +> Tread { tag=0 fid=1 offset=361 count=4096 } < Rread { tag=0 count=0 data="" } > Tclunk { tag=0 fid=1 } < Rclunk { tag=0 } @@ -29,7 +29,7 @@ > Tauth { tag=0 afid=0 uname="lukeshu" aname="" n_uid=0 } < Rerror { tag=0 errstr="authentication not required" errnum=95 } > Tattach { tag=0 fid=0 afid=NOFID uname="lukeshu" aname="" n_uid=0 } -< Rattach { tag=0 qid={ type=(DIR) vers=1 path=5 } } +< Rattach { tag=0 qid={ type=(DIR) vers=1 path=7 } } > Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=["Documentation" ] } < Rwalk { tag=0 nwqid=1 wqid=[{ type=(DIR) vers=1 path=2 } ] } > Tstat { tag=0 fid=1 } @@ -51,7 +51,7 @@ > Tauth { tag=0 afid=0 uname="lukeshu" aname="" n_uid=0 } < Rerror { tag=0 errstr="authentication not required" errnum=95 } > Tattach { tag=0 fid=0 afid=NOFID uname="lukeshu" aname="" n_uid=0 } -< Rattach { tag=0 qid={ type=(DIR) vers=1 path=5 } } +< Rattach { tag=0 qid={ type=(DIR) vers=1 path=7 } } > Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=["README.md" ] } < Rwalk { tag=0 nwqid=1 wqid=[{ type=(0) vers=1 path=3 } ] } > Topen { tag=0 fid=1 mode=(MODE_READ) } @@ -67,7 +67,7 @@ > Tauth { tag=0 afid=0 uname="lukeshu" aname="" n_uid=0 } < Rerror { tag=0 errstr="authentication not required" errnum=95 } > Tattach { tag=0 fid=0 afid=NOFID uname="lukeshu" aname="" n_uid=0 } -< Rattach { tag=0 qid={ type=(DIR) vers=1 path=5 } } +< Rattach { tag=0 qid={ type=(DIR) vers=1 path=7 } } > Twalk { tag=0 fid=0 newfid=1 nwname=2 wname=["Documentation", "x" ] } < Rwalk { tag=0 nwqid=2 wqid=[{ type=(DIR) vers=1 path=2 }, { type=(0) vers=1 path=1 } ] } > Topen { tag=0 fid=1 mode=(MODE_READ) } @@ -83,7 +83,7 @@ > Tauth { tag=0 afid=0 uname="lukeshu" aname="" n_uid=0 } < Rerror { tag=0 errstr="authentication not required" errnum=95 } > Tattach { tag=0 fid=0 afid=NOFID uname="lukeshu" aname="" n_uid=0 } -< Rattach { tag=0 qid={ type=(DIR) vers=1 path=5 } } +< Rattach { tag=0 qid={ type=(DIR) vers=1 path=7 } } > Twalk { tag=0 fid=0 newfid=1 nwname=2 wname=["Documentation", "x" ] } < Rwalk { tag=0 nwqid=2 wqid=[{ type=(DIR) vers=1 path=2 }, { type=(0) vers=1 path=1 } ] } > Tstat { tag=0 fid=1 } @@ -95,7 +95,7 @@ > Tauth { tag=0 afid=0 uname="lukeshu" aname="" n_uid=0 } < Rerror { tag=0 errstr="authentication not required" errnum=95 } > Tattach { tag=0 fid=0 afid=NOFID uname="lukeshu" aname="" n_uid=0 } -< Rattach { tag=0 qid={ type=(DIR) vers=1 path=5 } } +< Rattach { tag=0 qid={ type=(DIR) vers=1 path=7 } } > Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=["shutdown" ] } < Rwalk { tag=0 nwqid=1 wqid=[{ type=(0) vers=1 path=4 } ] } > Topen { tag=0 fid=1 mode=(TRUNC|MODE_WRITE) } diff --git a/lib9p/tests/testclient-sess.c b/lib9p/tests/testclient-sess.c index 54b8722..423dc2c 100644 --- a/lib9p/tests/testclient-sess.c +++ b/lib9p/tests/testclient-sess.c @@ -96,6 +96,37 @@ int main(int argc, char *argv[]) { recv9p(); /* Rversion */ ctx.version = LIB9P_VER_9P2000_u; + /* main session *******************************************************/ + send9p(Tversion, .tag=0, .max_msg_size=(8*1024), .version=lib9p_str("9P2000")); + recv9p(); /* Rversion */ + ctx.version = LIB9P_VER_9P2000; + send9p(Tattach, .tag=0, .fid=0, .afid=LIB9P_FID_NOFID, .uname=lib9p_str("nobody"), .aname=lib9p_str("")); + recv9p(); /* Rattach */ + + /* flush, but original response comes back first */ + wname[0] = lib9p_str("slowread"); send9p(Twalk, .tag=0, .fid=0, .newfid=1, .nwname=1, .wname=wname); + recv9p(); /* Rwalk */ + send9p(Topen, .tag=0, .fid=1, .mode=LIB9P_O_MODE_READ); + recv9p(); /* Ropen */ + send9p(Tread, .tag=1, .fid=1, .offset=0, .count=6); + send9p(Tflush, .tag=2, .oldtag=1); + recv9p(); /* Rread */ + recv9p(); /* Rflush */ + + /* flush, original request is aborted with error */ + wname[0] = lib9p_str("slowread-flushable"); send9p(Twalk, .tag=1, .fid=0, .newfid=2, .nwname=1, .wname=wname); + recv9p(); /* Rwalk */ + send9p(Topen, .tag=0, .fid=2, .mode=LIB9P_O_MODE_READ); + recv9p(); /* Ropen */ + send9p(Tread, .tag=1, .fid=2, .offset=0, .count=6); + send9p(Tflush, .tag=2, .oldtag=1); + recv9p(); /* Rerror */ + recv9p(); /* Rflush */ + + /* flush, unknown tag */ + send9p(Tflush, .tag=0, .oldtag=99); + recv9p(); /* Rflush */ + /* shutdown ***********************************************************/ send9p(Tversion, .tag=0, .max_msg_size=(8*1024), .version=lib9p_str("9P2000")); recv9p(); /* Rversion */ diff --git a/lib9p/tests/testclient-sess.explog b/lib9p/tests/testclient-sess.explog index 4932553..e086341 100644 --- a/lib9p/tests/testclient-sess.explog +++ b/lib9p/tests/testclient-sess.explog @@ -15,11 +15,41 @@ > Tversion { tag=0 max_msg_size=57 version="9P2000.u" } < Rversion { tag=0 max_msg_size=57 version="9P2000.u" } +# main session ################################################################# +> Tversion { tag=0 max_msg_size=8192 version="9P2000" } +< Rversion { tag=0 max_msg_size=4120 version="9P2000" } +> Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" n_uid=0 } +< Rattach { tag=0 qid={ type=(DIR) vers=1 path=7 } } + +# flush, but original response comes back first +> Twalk { tag=0 fid=0 newfid=1 nwname=1 wname=["slowread" ] } +< Rwalk { tag=0 nwqid=1 wqid=[{ type=(0) vers=1 path=5 } ] } +> Topen { tag=0 fid=1 mode=(MODE_READ) } +< Ropen { tag=0 qid={ type=(0) vers=1 path=5 } iounit=0 } +> Tread { tag=1 fid=1 offset=0 count=6 } +> Tflush { tag=2 oldtag=1 } +< Rread { tag=1 count=6 data="Sloth\n" } +< Rflush { tag=2 } + +# flush, succeeds +> Twalk { tag=1 fid=0 newfid=2 nwname=1 wname=["slowread-flushable" ] } +< Rwalk { tag=1 nwqid=1 wqid=[{ type=(0) vers=1 path=6 } ] } +> Topen { tag=0 fid=2 mode=(MODE_READ) } +< Ropen { tag=0 qid={ type=(0) vers=1 path=6 } iounit=0 } +> Tread { tag=1 fid=2 offset=0 count=6 } +> Tflush { tag=2 oldtag=1 } +< Rflush { tag=2 } +< Rerror { tag=1 errstr="request canceled by flush" errnum=125 } + +# flush, unknown tag +> Tflush { tag=0 oldtag=99 } +< Rflush { tag=0 } + # shutdown ##################################################################### > Tversion { tag=0 max_msg_size=8192 version="9P2000" } < Rversion { tag=0 max_msg_size=4120 version="9P2000" } > Tattach { tag=0 fid=0 afid=NOFID uname="nobody" aname="" n_uid=0 } -< Rattach { tag=0 qid={ type=(DIR) vers=1 path=5 } } +< Rattach { tag=0 qid={ type=(DIR) vers=1 path=7 } } > Twalk { tag=0 fid=0 newfid=0 nwname=1 wname=["shutdown" ] } < Rwalk { tag=0 nwqid=1 wqid=[{ type=(0) vers=1 path=4 } ] } > Topen { tag=0 fid=0 mode=(MODE_WRITE) } |