Commit d8dd401709 for qemu.org
commit d8dd4017095383bd4b14a7ee8151248f6902eb72
Author: Christian Schoenebeck <qemu_oss@crudebyte.com>
Date: Wed Oct 7 12:27:55 2026 +0200
tests/9p-client: add Tcreate / Rcreate test client functions
Add v9fs_tcreate() and v9fs_rcreate() functions to the 9p test
client for the legacy 9p2000(.u) Tcreate request type.
This is a preparatory patch, these functions will be used by the
subsequently added 9p race test.
Link: https://lore.kernel.org/qemu-devel/532fed8595419fd57ec7d24dc5dbcbd8b1190e80.1791368962.git.qemu_oss@crudebyte.com
Signed-off-by: Christian Schoenebeck <qemu_oss@crudebyte.com>
diff --git a/tests/qtest/libqos/virtio-9p-client.c b/tests/qtest/libqos/virtio-9p-client.c
index 4a3fc1511b..ce67a4b8c5 100644
--- a/tests/qtest/libqos/virtio-9p-client.c
+++ b/tests/qtest/libqos/virtio-9p-client.c
@@ -1365,3 +1365,63 @@ void v9fs_rstat(P9Req *req, v9fs_stat *stat)
v9fs_req_free(req);
}
+
+/* size[4] Tcreate tag[2] fid[4] name[s] perm[4] mode[1] extension[s] */
+TCreateRes v9fs_tcreate(TCreateOpt opt)
+{
+ P9Req *req;
+ uint8_t mode = opt.mode;
+ uint32_t body_size = 4 + 4 + 1;
+ uint16_t string_size;
+
+ g_assert(opt.client);
+ /* expecting either Rcreate or an error response, but obviously not both */
+ g_assert(!opt.expectErr || !(opt.rcreate.qid || opt.rcreate.iounit));
+
+ if (!opt.perm) {
+ opt.perm = 0644;
+ }
+ if (!opt.extension) {
+ opt.extension = "";
+ }
+
+ string_size = v9fs_string_size(opt.name) +
+ v9fs_string_size(opt.extension);
+ g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
+ body_size += string_size;
+
+ req = v9fs_req_init(opt.client, body_size, P9_TCREATE, opt.tag);
+ v9fs_uint32_write(req, opt.fid);
+ v9fs_string_write(req, opt.name);
+ v9fs_uint32_write(req, opt.perm);
+ v9fs_memwrite(req, &mode, 1);
+ v9fs_string_write(req, opt.extension);
+ v9fs_req_send(req);
+
+ if (!opt.requestOnly) {
+ v9fs_req_wait_for_reply(req, NULL);
+ if (opt.expectErr) {
+ v9fs_req_check_err(req, opt.expectErr);
+ } else {
+ v9fs_rcreate(req, opt.rcreate.qid, opt.rcreate.iounit);
+ }
+ req = NULL; /* request was freed */
+ }
+
+ return (TCreateRes) { .req = req };
+}
+
+/* size[4] Rcreate tag[2] qid[13] iounit[4] */
+void v9fs_rcreate(P9Req *req, v9fs_qid *qid, uint32_t *iounit)
+{
+ v9fs_req_recv(req, P9_RCREATE);
+ if (qid) {
+ v9fs_memread(req, qid, 13);
+ } else {
+ v9fs_memskip(req, 13);
+ }
+ if (iounit) {
+ v9fs_uint32_read(req, iounit);
+ }
+ v9fs_req_free(req);
+}
diff --git a/tests/qtest/libqos/virtio-9p-client.h b/tests/qtest/libqos/virtio-9p-client.h
index f604cc0ee5..88e0f41ff0 100644
--- a/tests/qtest/libqos/virtio-9p-client.h
+++ b/tests/qtest/libqos/virtio-9p-client.h
@@ -372,6 +372,54 @@ typedef struct TMkdirRes {
P9Req *req;
} TMkdirRes;
+/* create directory */
+#define P9_CREATE_PERM_DMDIR 0x80000000
+
+/* options for 'Tcreate' 9p request (legacy 9p2000.u) */
+typedef struct TCreateOpt {
+ /* 9P client being used (mandatory) */
+ QVirtio9P *client;
+ /* user supplied tag number being returned with response (optional) */
+ uint16_t tag;
+ /* file ID of the directory the new file shall be created in (required) */
+ uint32_t fid;
+ /* name of the new file (required) */
+ const char *name;
+ /*
+ * Create mode bits (including file type bits):
+ * e.g. 0644 for a regular file,
+ * or P9_CREATE_PERM_DMDIR | 0755 for a directory
+ * (optional)
+ */
+ uint32_t perm;
+ /*
+ * Open mode byte:
+ * OREAD (0), OWRITE (1), ORDWR (2), OEXEC(3), OTRUNC(0x10), ORCLOSE(0x40)
+ * (optional)
+ */
+ uint8_t mode;
+ /*
+ * Extension data for special files (e.g. symlink target), empty for
+ * regular files. (optional)
+ */
+ const char *extension;
+ /* data being received from 9p server as 'Rcreate' response (optional) */
+ struct {
+ v9fs_qid *qid;
+ uint32_t *iounit;
+ } rcreate;
+ /* only send Tcreate request but not wait for a reply? (optional) */
+ bool requestOnly;
+ /* do we expect an error response, if yes which error code? (optional) */
+ uint32_t expectErr;
+} TCreateOpt;
+
+/* result of 'Tcreate' 9p request */
+typedef struct TCreateRes {
+ /* if requestOnly was set: request object for further processing */
+ P9Req *req;
+} TCreateRes;
+
/* options for 'Tlcreate' 9p request */
typedef struct TlcreateOpt {
/* 9P client being used (mandatory) */
@@ -666,6 +714,8 @@ TFlushRes v9fs_tflush(TFlushOpt);
void v9fs_rflush(P9Req *req);
TMkdirRes v9fs_tmkdir(TMkdirOpt);
void v9fs_rmkdir(P9Req *req, v9fs_qid *qid);
+TCreateRes v9fs_tcreate(TCreateOpt opt);
+void v9fs_rcreate(P9Req *req, v9fs_qid *qid, uint32_t *iounit);
TlcreateRes v9fs_tlcreate(TlcreateOpt);
void v9fs_rlcreate(P9Req *req, v9fs_qid *qid, uint32_t *iounit);
TsymlinkRes v9fs_tsymlink(TsymlinkOpt);