diff options
Diffstat (limited to 'tests/qtest/virtio-9p-test.c')
| -rw-r--r-- | tests/qtest/virtio-9p-test.c | 1301 |
1 files changed, 209 insertions, 1092 deletions
diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c index 25305a4cf7..65e69491e5 100644 --- a/tests/qtest/virtio-9p-test.c +++ b/tests/qtest/virtio-9p-test.c @@ -13,76 +13,27 @@ */ #include "qemu/osdep.h" -#include "libqtest-single.h" #include "qemu/module.h" -#include "hw/9pfs/9p.h" -#include "hw/9pfs/9p-synth.h" -#include "libqos/virtio-9p.h" -#include "libqos/qgraph.h" - -#define QVIRTIO_9P_TIMEOUT_US (10 * 1000 * 1000) -static QGuestAllocator *alloc; - -/* - * Used to auto generate new fids. Start with arbitrary high value to avoid - * collision with hard coded fids in basic test code. - */ -static uint32_t fid_generator = 1000; - -static uint32_t genfid(void) -{ - return fid_generator++; -} - -/** - * Splits the @a in string by @a delim into individual (non empty) strings - * and outputs them to @a out. The output array @a out is NULL terminated. - * - * Output array @a out must be freed by calling split_free(). - * - * @returns number of individual elements in output array @a out (without the - * final NULL terminating element) - */ -static int split(const char *in, const char *delim, char ***out) -{ - int n = 0, i = 0; - char *tmp, *p; - - tmp = g_strdup(in); - for (p = strtok(tmp, delim); p != NULL; p = strtok(NULL, delim)) { - if (strlen(p) > 0) { - ++n; - } - } - g_free(tmp); - - *out = g_new0(char *, n + 1); /* last element NULL delimiter */ - - tmp = g_strdup(in); - for (p = strtok(tmp, delim); p != NULL; p = strtok(NULL, delim)) { - if (strlen(p) > 0) { - (*out)[i++] = g_strdup(p); - } - } - g_free(tmp); - - return n; -} - -static void split_free(char ***out) -{ - int i; - for (i = 0; (*out)[i]; ++i) { - g_free((*out)[i]); - } - g_free(*out); - *out = NULL; -} +#include "libqos/virtio-9p-client.h" + +#define twalk(...) v9fs_twalk((TWalkOpt) __VA_ARGS__) +#define tversion(...) v9fs_tversion((TVersionOpt) __VA_ARGS__) +#define tattach(...) v9fs_tattach((TAttachOpt) __VA_ARGS__) +#define tgetattr(...) v9fs_tgetattr((TGetAttrOpt) __VA_ARGS__) +#define treaddir(...) v9fs_treaddir((TReadDirOpt) __VA_ARGS__) +#define tlopen(...) v9fs_tlopen((TLOpenOpt) __VA_ARGS__) +#define twrite(...) v9fs_twrite((TWriteOpt) __VA_ARGS__) +#define tflush(...) v9fs_tflush((TFlushOpt) __VA_ARGS__) +#define tmkdir(...) v9fs_tmkdir((TMkdirOpt) __VA_ARGS__) +#define tlcreate(...) v9fs_tlcreate((TlcreateOpt) __VA_ARGS__) +#define tsymlink(...) v9fs_tsymlink((TsymlinkOpt) __VA_ARGS__) +#define tlink(...) v9fs_tlink((TlinkOpt) __VA_ARGS__) +#define tunlinkat(...) v9fs_tunlinkat((TunlinkatOpt) __VA_ARGS__) static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); size_t tag_len = qvirtio_config_readw(v9p->vdev, 0); g_autofree char *tag = NULL; int i; @@ -96,670 +47,43 @@ static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc) g_assert_cmpmem(tag, tag_len, MOUNT_TAG, tag_len); } -#define P9_MAX_SIZE 4096 /* Max size of a T-message or R-message */ - -typedef struct { - QTestState *qts; - QVirtio9P *v9p; - uint16_t tag; - uint64_t t_msg; - uint32_t t_size; - uint64_t r_msg; - /* No r_size, it is hardcoded to P9_MAX_SIZE */ - size_t t_off; - size_t r_off; - uint32_t free_head; -} P9Req; - -static void v9fs_memwrite(P9Req *req, const void *addr, size_t len) -{ - qtest_memwrite(req->qts, req->t_msg + req->t_off, addr, len); - req->t_off += len; -} - -static void v9fs_memskip(P9Req *req, size_t len) -{ - req->r_off += len; -} - -static void v9fs_memread(P9Req *req, void *addr, size_t len) -{ - qtest_memread(req->qts, req->r_msg + req->r_off, addr, len); - req->r_off += len; -} - -static void v9fs_uint8_read(P9Req *req, uint8_t *val) -{ - v9fs_memread(req, val, 1); -} - -static void v9fs_uint16_write(P9Req *req, uint16_t val) -{ - uint16_t le_val = cpu_to_le16(val); - - v9fs_memwrite(req, &le_val, 2); -} - -static void v9fs_uint16_read(P9Req *req, uint16_t *val) -{ - v9fs_memread(req, val, 2); - le16_to_cpus(val); -} - -static void v9fs_uint32_write(P9Req *req, uint32_t val) -{ - uint32_t le_val = cpu_to_le32(val); - - v9fs_memwrite(req, &le_val, 4); -} - -static void v9fs_uint64_write(P9Req *req, uint64_t val) -{ - uint64_t le_val = cpu_to_le64(val); - - v9fs_memwrite(req, &le_val, 8); -} - -static void v9fs_uint32_read(P9Req *req, uint32_t *val) -{ - v9fs_memread(req, val, 4); - le32_to_cpus(val); -} - -static void v9fs_uint64_read(P9Req *req, uint64_t *val) -{ - v9fs_memread(req, val, 8); - le64_to_cpus(val); -} - -/* len[2] string[len] */ -static uint16_t v9fs_string_size(const char *string) -{ - size_t len = strlen(string); - - g_assert_cmpint(len, <=, UINT16_MAX - 2); - - return 2 + len; -} - -static void v9fs_string_write(P9Req *req, const char *string) -{ - int len = strlen(string); - - g_assert_cmpint(len, <=, UINT16_MAX); - - v9fs_uint16_write(req, (uint16_t) len); - v9fs_memwrite(req, string, len); -} - -static void v9fs_string_read(P9Req *req, uint16_t *len, char **string) -{ - uint16_t local_len; - - v9fs_uint16_read(req, &local_len); - if (len) { - *len = local_len; - } - if (string) { - *string = g_malloc(local_len + 1); - v9fs_memread(req, *string, local_len); - (*string)[local_len] = 0; - } else { - v9fs_memskip(req, local_len); - } -} - - typedef struct { - uint32_t size; - uint8_t id; - uint16_t tag; -} QEMU_PACKED P9Hdr; - -static P9Req *v9fs_req_init(QVirtio9P *v9p, uint32_t size, uint8_t id, - uint16_t tag) -{ - P9Req *req = g_new0(P9Req, 1); - uint32_t total_size = 7; /* 9P header has well-known size of 7 bytes */ - P9Hdr hdr = { - .id = id, - .tag = cpu_to_le16(tag) - }; - - g_assert_cmpint(total_size, <=, UINT32_MAX - size); - total_size += size; - hdr.size = cpu_to_le32(total_size); - - g_assert_cmpint(total_size, <=, P9_MAX_SIZE); - - req->qts = global_qtest; - req->v9p = v9p; - req->t_size = total_size; - req->t_msg = guest_alloc(alloc, req->t_size); - v9fs_memwrite(req, &hdr, 7); - req->tag = tag; - return req; -} - -static void v9fs_req_send(P9Req *req) -{ - QVirtio9P *v9p = req->v9p; - - req->r_msg = guest_alloc(alloc, P9_MAX_SIZE); - req->free_head = qvirtqueue_add(req->qts, v9p->vq, req->t_msg, req->t_size, - false, true); - qvirtqueue_add(req->qts, v9p->vq, req->r_msg, P9_MAX_SIZE, true, false); - qvirtqueue_kick(req->qts, v9p->vdev, v9p->vq, req->free_head); - req->t_off = 0; -} - -static const char *rmessage_name(uint8_t id) -{ - return - id == P9_RLERROR ? "RLERROR" : - id == P9_RVERSION ? "RVERSION" : - id == P9_RATTACH ? "RATTACH" : - id == P9_RWALK ? "RWALK" : - id == P9_RLOPEN ? "RLOPEN" : - id == P9_RWRITE ? "RWRITE" : - id == P9_RMKDIR ? "RMKDIR" : - id == P9_RLCREATE ? "RLCREATE" : - id == P9_RSYMLINK ? "RSYMLINK" : - id == P9_RLINK ? "RLINK" : - id == P9_RUNLINKAT ? "RUNLINKAT" : - id == P9_RFLUSH ? "RFLUSH" : - id == P9_RREADDIR ? "READDIR" : - "<unknown>"; -} - -static void v9fs_req_wait_for_reply(P9Req *req, uint32_t *len) -{ - QVirtio9P *v9p = req->v9p; - - qvirtio_wait_used_elem(req->qts, v9p->vdev, v9p->vq, req->free_head, len, - QVIRTIO_9P_TIMEOUT_US); -} - -static void v9fs_req_recv(P9Req *req, uint8_t id) -{ - P9Hdr hdr; - - v9fs_memread(req, &hdr, 7); - hdr.size = ldl_le_p(&hdr.size); - hdr.tag = lduw_le_p(&hdr.tag); - - g_assert_cmpint(hdr.size, >=, 7); - g_assert_cmpint(hdr.size, <=, P9_MAX_SIZE); - g_assert_cmpint(hdr.tag, ==, req->tag); - - if (hdr.id != id) { - g_printerr("Received response %d (%s) instead of %d (%s)\n", - hdr.id, rmessage_name(hdr.id), id, rmessage_name(id)); - - if (hdr.id == P9_RLERROR) { - uint32_t err; - v9fs_uint32_read(req, &err); - g_printerr("Rlerror has errno %d (%s)\n", err, strerror(err)); - } - } - g_assert_cmpint(hdr.id, ==, id); -} - -static void v9fs_req_free(P9Req *req) -{ - guest_free(alloc, req->t_msg); - guest_free(alloc, req->r_msg); - g_free(req); -} - -/* size[4] Rlerror tag[2] ecode[4] */ -static void v9fs_rlerror(P9Req *req, uint32_t *err) -{ - v9fs_req_recv(req, P9_RLERROR); - v9fs_uint32_read(req, err); - v9fs_req_free(req); -} - -/* size[4] Tversion tag[2] msize[4] version[s] */ -static P9Req *v9fs_tversion(QVirtio9P *v9p, uint32_t msize, const char *version, - uint16_t tag) -{ - P9Req *req; - uint32_t body_size = 4; - uint16_t string_size = v9fs_string_size(version); - - g_assert_cmpint(body_size, <=, UINT32_MAX - string_size); - body_size += string_size; - req = v9fs_req_init(v9p, body_size, P9_TVERSION, tag); - - v9fs_uint32_write(req, msize); - v9fs_string_write(req, version); - v9fs_req_send(req); - return req; -} - -/* size[4] Rversion tag[2] msize[4] version[s] */ -static void v9fs_rversion(P9Req *req, uint16_t *len, char **version) -{ - uint32_t msize; - - v9fs_req_recv(req, P9_RVERSION); - v9fs_uint32_read(req, &msize); - - g_assert_cmpint(msize, ==, P9_MAX_SIZE); - - if (len || version) { - v9fs_string_read(req, len, version); - } - - v9fs_req_free(req); -} - -/* size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s] n_uname[4] */ -static P9Req *v9fs_tattach(QVirtio9P *v9p, uint32_t fid, uint32_t n_uname, - uint16_t tag) -{ - const char *uname = ""; /* ignored by QEMU */ - const char *aname = ""; /* ignored by QEMU */ - P9Req *req = v9fs_req_init(v9p, 4 + 4 + 2 + 2 + 4, P9_TATTACH, tag); - - v9fs_uint32_write(req, fid); - v9fs_uint32_write(req, P9_NOFID); - v9fs_string_write(req, uname); - v9fs_string_write(req, aname); - v9fs_uint32_write(req, n_uname); - v9fs_req_send(req); - return req; -} - -/* type[1] version[4] path[8] */ -typedef char v9fs_qid[13]; - static inline bool is_same_qid(v9fs_qid a, v9fs_qid b) { /* don't compare QID version for checking for file ID equalness */ return a[0] == b[0] && memcmp(&a[5], &b[5], 8) == 0; } -/* size[4] Rattach tag[2] qid[13] */ -static void v9fs_rattach(P9Req *req, v9fs_qid *qid) -{ - v9fs_req_recv(req, P9_RATTACH); - if (qid) { - v9fs_memread(req, qid, 13); - } - v9fs_req_free(req); -} - -/* size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s]) */ -static P9Req *v9fs_twalk(QVirtio9P *v9p, uint32_t fid, uint32_t newfid, - uint16_t nwname, char *const wnames[], uint16_t tag) -{ - P9Req *req; - int i; - uint32_t body_size = 4 + 4 + 2; - - for (i = 0; i < nwname; i++) { - uint16_t wname_size = v9fs_string_size(wnames[i]); - - g_assert_cmpint(body_size, <=, UINT32_MAX - wname_size); - body_size += wname_size; - } - req = v9fs_req_init(v9p, body_size, P9_TWALK, tag); - v9fs_uint32_write(req, fid); - v9fs_uint32_write(req, newfid); - v9fs_uint16_write(req, nwname); - for (i = 0; i < nwname; i++) { - v9fs_string_write(req, wnames[i]); - } - v9fs_req_send(req); - return req; -} - -/* size[4] Rwalk tag[2] nwqid[2] nwqid*(wqid[13]) */ -static void v9fs_rwalk(P9Req *req, uint16_t *nwqid, v9fs_qid **wqid) -{ - uint16_t local_nwqid; - - v9fs_req_recv(req, P9_RWALK); - v9fs_uint16_read(req, &local_nwqid); - if (nwqid) { - *nwqid = local_nwqid; - } - if (wqid) { - *wqid = g_malloc(local_nwqid * 13); - v9fs_memread(req, *wqid, local_nwqid * 13); - } - v9fs_req_free(req); -} - -/* size[4] Tgetattr tag[2] fid[4] request_mask[8] */ -static P9Req *v9fs_tgetattr(QVirtio9P *v9p, uint32_t fid, uint64_t request_mask, - uint16_t tag) -{ - P9Req *req; - - req = v9fs_req_init(v9p, 4 + 8, P9_TGETATTR, tag); - v9fs_uint32_write(req, fid); - v9fs_uint64_write(req, request_mask); - v9fs_req_send(req); - return req; -} - -typedef struct v9fs_attr { - uint64_t valid; - v9fs_qid qid; - uint32_t mode; - uint32_t uid; - uint32_t gid; - uint64_t nlink; - uint64_t rdev; - uint64_t size; - uint64_t blksize; - uint64_t blocks; - uint64_t atime_sec; - uint64_t atime_nsec; - uint64_t mtime_sec; - uint64_t mtime_nsec; - uint64_t ctime_sec; - uint64_t ctime_nsec; - uint64_t btime_sec; - uint64_t btime_nsec; - uint64_t gen; - uint64_t data_version; -} v9fs_attr; - -#define P9_GETATTR_BASIC 0x000007ffULL /* Mask for fields up to BLOCKS */ - -/* - * size[4] Rgetattr tag[2] valid[8] qid[13] mode[4] uid[4] gid[4] nlink[8] - * rdev[8] size[8] blksize[8] blocks[8] - * atime_sec[8] atime_nsec[8] mtime_sec[8] mtime_nsec[8] - * ctime_sec[8] ctime_nsec[8] btime_sec[8] btime_nsec[8] - * gen[8] data_version[8] - */ -static void v9fs_rgetattr(P9Req *req, v9fs_attr *attr) -{ - v9fs_req_recv(req, P9_RGETATTR); - - v9fs_uint64_read(req, &attr->valid); - v9fs_memread(req, &attr->qid, 13); - v9fs_uint32_read(req, &attr->mode); - v9fs_uint32_read(req, &attr->uid); - v9fs_uint32_read(req, &attr->gid); - v9fs_uint64_read(req, &attr->nlink); - v9fs_uint64_read(req, &attr->rdev); - v9fs_uint64_read(req, &attr->size); - v9fs_uint64_read(req, &attr->blksize); - v9fs_uint64_read(req, &attr->blocks); - v9fs_uint64_read(req, &attr->atime_sec); - v9fs_uint64_read(req, &attr->atime_nsec); - v9fs_uint64_read(req, &attr->mtime_sec); - v9fs_uint64_read(req, &attr->mtime_nsec); - v9fs_uint64_read(req, &attr->ctime_sec); - v9fs_uint64_read(req, &attr->ctime_nsec); - v9fs_uint64_read(req, &attr->btime_sec); - v9fs_uint64_read(req, &attr->btime_nsec); - v9fs_uint64_read(req, &attr->gen); - v9fs_uint64_read(req, &attr->data_version); - - v9fs_req_free(req); -} - -/* size[4] Treaddir tag[2] fid[4] offset[8] count[4] */ -static P9Req *v9fs_treaddir(QVirtio9P *v9p, uint32_t fid, uint64_t offset, - uint32_t count, uint16_t tag) -{ - P9Req *req; - - req = v9fs_req_init(v9p, 4 + 8 + 4, P9_TREADDIR, tag); - v9fs_uint32_write(req, fid); - v9fs_uint64_write(req, offset); - v9fs_uint32_write(req, count); - v9fs_req_send(req); - return req; -} - -struct V9fsDirent { - v9fs_qid qid; - uint64_t offset; - uint8_t type; - char *name; - struct V9fsDirent *next; -}; - -/* size[4] Rreaddir tag[2] count[4] data[count] */ -static void v9fs_rreaddir(P9Req *req, uint32_t *count, uint32_t *nentries, - struct V9fsDirent **entries) -{ - uint32_t local_count; - struct V9fsDirent *e = NULL; - uint16_t slen; - uint32_t n = 0; - - v9fs_req_recv(req, P9_RREADDIR); - v9fs_uint32_read(req, &local_count); - - if (count) { - *count = local_count; - } - - for (int32_t togo = (int32_t)local_count; - togo >= 13 + 8 + 1 + 2; - togo -= 13 + 8 + 1 + 2 + slen, ++n) - { - if (!e) { - e = g_new(struct V9fsDirent, 1); - if (entries) { - *entries = e; - } - } else { - e = e->next = g_new(struct V9fsDirent, 1); - } - e->next = NULL; - /* qid[13] offset[8] type[1] name[s] */ - v9fs_memread(req, &e->qid, 13); - v9fs_uint64_read(req, &e->offset); - v9fs_uint8_read(req, &e->type); - v9fs_string_read(req, &slen, &e->name); - } - - if (nentries) { - *nentries = n; - } - - v9fs_req_free(req); -} - -static void v9fs_free_dirents(struct V9fsDirent *e) -{ - struct V9fsDirent *next = NULL; - - for (; e; e = next) { - next = e->next; - g_free(e->name); - g_free(e); - } -} - -/* size[4] Tlopen tag[2] fid[4] flags[4] */ -static P9Req *v9fs_tlopen(QVirtio9P *v9p, uint32_t fid, uint32_t flags, - uint16_t tag) -{ - P9Req *req; - - req = v9fs_req_init(v9p, 4 + 4, P9_TLOPEN, tag); - v9fs_uint32_write(req, fid); - v9fs_uint32_write(req, flags); - v9fs_req_send(req); - return req; -} - -/* size[4] Rlopen tag[2] qid[13] iounit[4] */ -static void v9fs_rlopen(P9Req *req, v9fs_qid *qid, uint32_t *iounit) -{ - v9fs_req_recv(req, P9_RLOPEN); - if (qid) { - v9fs_memread(req, qid, 13); - } else { - v9fs_memskip(req, 13); - } - if (iounit) { - v9fs_uint32_read(req, iounit); - } - v9fs_req_free(req); -} - -/* size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count] */ -static P9Req *v9fs_twrite(QVirtio9P *v9p, uint32_t fid, uint64_t offset, - uint32_t count, const void *data, uint16_t tag) -{ - P9Req *req; - uint32_t body_size = 4 + 8 + 4; - - g_assert_cmpint(body_size, <=, UINT32_MAX - count); - body_size += count; - req = v9fs_req_init(v9p, body_size, P9_TWRITE, tag); - v9fs_uint32_write(req, fid); - v9fs_uint64_write(req, offset); - v9fs_uint32_write(req, count); - v9fs_memwrite(req, data, count); - v9fs_req_send(req); - return req; -} - -/* size[4] Rwrite tag[2] count[4] */ -static void v9fs_rwrite(P9Req *req, uint32_t *count) -{ - v9fs_req_recv(req, P9_RWRITE); - if (count) { - v9fs_uint32_read(req, count); - } - v9fs_req_free(req); -} - -/* size[4] Tflush tag[2] oldtag[2] */ -static P9Req *v9fs_tflush(QVirtio9P *v9p, uint16_t oldtag, uint16_t tag) -{ - P9Req *req; - - req = v9fs_req_init(v9p, 2, P9_TFLUSH, tag); - v9fs_uint32_write(req, oldtag); - v9fs_req_send(req); - return req; -} - -/* size[4] Rflush tag[2] */ -static void v9fs_rflush(P9Req *req) -{ - v9fs_req_recv(req, P9_RFLUSH); - v9fs_req_free(req); -} - -static void do_version(QVirtio9P *v9p) -{ - const char *version = "9P2000.L"; - uint16_t server_len; - g_autofree char *server_version = NULL; - P9Req *req; - - req = v9fs_tversion(v9p, P9_MAX_SIZE, version, P9_NOTAG); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rversion(req, &server_len, &server_version); - - g_assert_cmpmem(server_version, server_len, version, strlen(version)); -} - -/* - * utility function: walk to requested dir and return fid for that dir and - * the QIDs of server response - */ -static uint32_t do_walk_rqids(QVirtio9P *v9p, const char *path, uint16_t *nwqid, - v9fs_qid **wqid) -{ - char **wnames; - P9Req *req; - const uint32_t fid = genfid(); - - int nwnames = split(path, "/", &wnames); - - req = v9fs_twalk(v9p, 0, fid, nwnames, wnames, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rwalk(req, nwqid, wqid); - - split_free(&wnames); - return fid; -} - -/* utility function: walk to requested dir and return fid for that dir */ -static uint32_t do_walk(QVirtio9P *v9p, const char *path) -{ - return do_walk_rqids(v9p, path, NULL, NULL); -} - -/* utility function: walk to requested dir and expect passed error response */ -static void do_walk_expect_error(QVirtio9P *v9p, const char *path, uint32_t err) -{ - char **wnames; - P9Req *req; - uint32_t _err; - const uint32_t fid = genfid(); - - int nwnames = split(path, "/", &wnames); - - req = v9fs_twalk(v9p, 0, fid, nwnames, wnames, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rlerror(req, &_err); - - g_assert_cmpint(_err, ==, err); - - split_free(&wnames); -} - static void fs_version(void *obj, void *data, QGuestAllocator *t_alloc) { - alloc = t_alloc; - do_version(obj); -} - -static void do_attach_rqid(QVirtio9P *v9p, v9fs_qid *qid) -{ - P9Req *req; - - do_version(v9p); - req = v9fs_tattach(v9p, 0, getuid(), 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rattach(req, qid); -} - -static void do_attach(QVirtio9P *v9p) -{ - do_attach_rqid(v9p, NULL); + v9fs_set_allocator(t_alloc); + tversion({ .client = obj }); } static void fs_attach(void *obj, void *data, QGuestAllocator *t_alloc) { - alloc = t_alloc; - do_attach(obj); + v9fs_set_allocator(t_alloc); + tattach({ .client = obj }); } static void fs_walk(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); char *wnames[P9_MAXWELEM]; uint16_t nwqid; g_autofree v9fs_qid *wqid = NULL; int i; - P9Req *req; for (i = 0; i < P9_MAXWELEM; i++) { wnames[i] = g_strdup_printf(QTEST_V9FS_SYNTH_WALK_FILE, i); } - do_attach(v9p); - req = v9fs_twalk(v9p, 0, 1, P9_MAXWELEM, wnames, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rwalk(req, &nwqid, &wqid); + tattach({ .client = v9p }); + twalk({ + .client = v9p, .fid = 0, .newfid = 1, + .nwname = P9_MAXWELEM, .wnames = wnames, + .rwalk = { .nwqid = &nwqid, .wqid = &wqid } + }); g_assert_cmpint(nwqid, ==, P9_MAXWELEM); @@ -778,192 +102,37 @@ static bool fs_dirents_contain_name(struct V9fsDirent *e, const char* name) return false; } -/* size[4] Tmkdir tag[2] dfid[4] name[s] mode[4] gid[4] */ -static P9Req *v9fs_tmkdir(QVirtio9P *v9p, uint32_t dfid, const char *name, - uint32_t mode, uint32_t gid, uint16_t tag) -{ - P9Req *req; - - uint32_t body_size = 4 + 4 + 4; - uint16_t string_size = v9fs_string_size(name); - - g_assert_cmpint(body_size, <=, UINT32_MAX - string_size); - body_size += string_size; - - req = v9fs_req_init(v9p, body_size, P9_TMKDIR, tag); - v9fs_uint32_write(req, dfid); - v9fs_string_write(req, name); - v9fs_uint32_write(req, mode); - v9fs_uint32_write(req, gid); - v9fs_req_send(req); - return req; -} - -/* size[4] Rmkdir tag[2] qid[13] */ -static void v9fs_rmkdir(P9Req *req, v9fs_qid *qid) -{ - v9fs_req_recv(req, P9_RMKDIR); - if (qid) { - v9fs_memread(req, qid, 13); - } else { - v9fs_memskip(req, 13); - } - v9fs_req_free(req); -} - -/* size[4] Tlcreate tag[2] fid[4] name[s] flags[4] mode[4] gid[4] */ -static P9Req *v9fs_tlcreate(QVirtio9P *v9p, uint32_t fid, const char *name, - uint32_t flags, uint32_t mode, uint32_t gid, - uint16_t tag) -{ - P9Req *req; - - uint32_t body_size = 4 + 4 + 4 + 4; - uint16_t string_size = v9fs_string_size(name); - - g_assert_cmpint(body_size, <=, UINT32_MAX - string_size); - body_size += string_size; - - req = v9fs_req_init(v9p, body_size, P9_TLCREATE, tag); - v9fs_uint32_write(req, fid); - v9fs_string_write(req, name); - v9fs_uint32_write(req, flags); - v9fs_uint32_write(req, mode); - v9fs_uint32_write(req, gid); - v9fs_req_send(req); - return req; -} - -/* size[4] Rlcreate tag[2] qid[13] iounit[4] */ -static void v9fs_rlcreate(P9Req *req, v9fs_qid *qid, uint32_t *iounit) -{ - v9fs_req_recv(req, P9_RLCREATE); - if (qid) { - v9fs_memread(req, qid, 13); - } else { - v9fs_memskip(req, 13); - } - if (iounit) { - v9fs_uint32_read(req, iounit); - } - v9fs_req_free(req); -} - -/* size[4] Tsymlink tag[2] fid[4] name[s] symtgt[s] gid[4] */ -static P9Req *v9fs_tsymlink(QVirtio9P *v9p, uint32_t fid, const char *name, - const char *symtgt, uint32_t gid, uint16_t tag) -{ - P9Req *req; - - uint32_t body_size = 4 + 4; - uint16_t string_size = v9fs_string_size(name) + v9fs_string_size(symtgt); - - g_assert_cmpint(body_size, <=, UINT32_MAX - string_size); - body_size += string_size; - - req = v9fs_req_init(v9p, body_size, P9_TSYMLINK, tag); - v9fs_uint32_write(req, fid); - v9fs_string_write(req, name); - v9fs_string_write(req, symtgt); - v9fs_uint32_write(req, gid); - v9fs_req_send(req); - return req; -} - -/* size[4] Rsymlink tag[2] qid[13] */ -static void v9fs_rsymlink(P9Req *req, v9fs_qid *qid) -{ - v9fs_req_recv(req, P9_RSYMLINK); - if (qid) { - v9fs_memread(req, qid, 13); - } else { - v9fs_memskip(req, 13); - } - v9fs_req_free(req); -} - -/* size[4] Tlink tag[2] dfid[4] fid[4] name[s] */ -static P9Req *v9fs_tlink(QVirtio9P *v9p, uint32_t dfid, uint32_t fid, - const char *name, uint16_t tag) -{ - P9Req *req; - - uint32_t body_size = 4 + 4; - uint16_t string_size = v9fs_string_size(name); - - g_assert_cmpint(body_size, <=, UINT32_MAX - string_size); - body_size += string_size; - - req = v9fs_req_init(v9p, body_size, P9_TLINK, tag); - v9fs_uint32_write(req, dfid); - v9fs_uint32_write(req, fid); - v9fs_string_write(req, name); - v9fs_req_send(req); - return req; -} - -/* size[4] Rlink tag[2] */ -static void v9fs_rlink(P9Req *req) -{ - v9fs_req_recv(req, P9_RLINK); - v9fs_req_free(req); -} - -/* size[4] Tunlinkat tag[2] dirfd[4] name[s] flags[4] */ -static P9Req *v9fs_tunlinkat(QVirtio9P *v9p, uint32_t dirfd, const char *name, - uint32_t flags, uint16_t tag) -{ - P9Req *req; - - uint32_t body_size = 4 + 4; - uint16_t string_size = v9fs_string_size(name); - - g_assert_cmpint(body_size, <=, UINT32_MAX - string_size); - body_size += string_size; - - req = v9fs_req_init(v9p, body_size, P9_TUNLINKAT, tag); - v9fs_uint32_write(req, dirfd); - v9fs_string_write(req, name); - v9fs_uint32_write(req, flags); - v9fs_req_send(req); - return req; -} - -/* size[4] Runlinkat tag[2] */ -static void v9fs_runlinkat(P9Req *req) -{ - v9fs_req_recv(req, P9_RUNLINKAT); - v9fs_req_free(req); -} - /* basic readdir test where reply fits into a single response message */ static void fs_readdir(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; - char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_READDIR_DIR) }; + v9fs_set_allocator(t_alloc); + char *wnames[] = { g_strdup(QTEST_V9FS_SYNTH_READDIR_DIR) }; uint16_t nqid; v9fs_qid qid; uint32_t count, nentries; struct V9fsDirent *entries = NULL; - P9Req *req; - do_attach(v9p); - req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rwalk(req, &nqid, NULL); + tattach({ .client = v9p }); + twalk({ + .client = v9p, .fid = 0, .newfid = 1, + .nwname = 1, .wnames = wnames, .rwalk.nwqid = &nqid + }); g_assert_cmpint(nqid, ==, 1); - req = v9fs_tlopen(v9p, 1, O_DIRECTORY, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rlopen(req, &qid, NULL); + tlopen({ + .client = v9p, .fid = 1, .flags = O_DIRECTORY, .rlopen.qid = &qid + }); /* * submit count = msize - 11, because 11 is the header size of Rreaddir */ - req = v9fs_treaddir(v9p, 1, 0, P9_MAX_SIZE - 11, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rreaddir(req, &count, &nentries, &entries); + treaddir({ + .client = v9p, .fid = 1, .offset = 0, .count = P9_MAX_SIZE - 11, + .rreaddir = { + .count = &count, .nentries = &nentries, .entries = &entries + } + }); /* * Assuming msize (P9_MAX_SIZE) is large enough so we can retrieve all @@ -993,16 +162,15 @@ static void fs_readdir(void *obj, void *data, QGuestAllocator *t_alloc) /* readdir test where overall request is split over several messages */ static void do_readdir_split(QVirtio9P *v9p, uint32_t count) { - char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_READDIR_DIR) }; + char *wnames[] = { g_strdup(QTEST_V9FS_SYNTH_READDIR_DIR) }; uint16_t nqid; v9fs_qid qid; uint32_t nentries, npartialentries; struct V9fsDirent *entries, *tail, *partialentries; - P9Req *req; int fid; uint64_t offset; - do_attach(v9p); + tattach({ .client = v9p }); fid = 1; offset = 0; @@ -1010,14 +178,15 @@ static void do_readdir_split(QVirtio9P *v9p, uint32_t count) nentries = 0; tail = NULL; - req = v9fs_twalk(v9p, 0, fid, 1, wnames, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rwalk(req, &nqid, NULL); + twalk({ + .client = v9p, .fid = 0, .newfid = fid, + .nwname = 1, .wnames = wnames, .rwalk.nwqid = &nqid + }); g_assert_cmpint(nqid, ==, 1); - req = v9fs_tlopen(v9p, fid, O_DIRECTORY, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rlopen(req, &qid, NULL); + tlopen({ + .client = v9p, .fid = fid, .flags = O_DIRECTORY, .rlopen.qid = &qid + }); /* * send as many Treaddir requests as required to get all directory @@ -1027,9 +196,13 @@ static void do_readdir_split(QVirtio9P *v9p, uint32_t count) npartialentries = 0; partialentries = NULL; - req = v9fs_treaddir(v9p, fid, offset, count, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rreaddir(req, &count, &npartialentries, &partialentries); + treaddir({ + .client = v9p, .fid = fid, .offset = offset, .count = count, + .rreaddir = { + .count = &count, .nentries = &npartialentries, + .entries = &partialentries + } + }); if (npartialentries > 0 && partialentries) { if (!entries) { entries = partialentries; @@ -1073,17 +246,14 @@ static void do_readdir_split(QVirtio9P *v9p, uint32_t count) static void fs_walk_no_slash(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; - char *const wnames[] = { g_strdup(" /") }; - P9Req *req; - uint32_t err; + v9fs_set_allocator(t_alloc); + char *wnames[] = { g_strdup(" /") }; - do_attach(v9p); - req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rlerror(req, &err); - - g_assert_cmpint(err, ==, ENOENT); + tattach({ .client = v9p }); + twalk({ + .client = v9p, .fid = 0, .newfid = 1, .nwname = 1, .wnames = wnames, + .expectErr = ENOENT + }); g_free(wnames[0]); } @@ -1091,32 +261,34 @@ static void fs_walk_no_slash(void *obj, void *data, QGuestAllocator *t_alloc) static void fs_walk_nonexistent(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); - do_attach(v9p); + tattach({ .client = v9p }); /* * The 9p2000 protocol spec says: "If the first element cannot be walked * for any reason, Rerror is returned." */ - do_walk_expect_error(v9p, "non-existent", ENOENT); + twalk({ .client = v9p, .path = "non-existent", .expectErr = ENOENT }); } static void fs_walk_2nd_nonexistent(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); v9fs_qid root_qid; uint16_t nwqid; - uint32_t fid, err; - P9Req *req; + uint32_t fid; g_autofree v9fs_qid *wqid = NULL; g_autofree char *path = g_strdup_printf( QTEST_V9FS_SYNTH_WALK_FILE "/non-existent", 0 ); - do_attach_rqid(v9p, &root_qid); - fid = do_walk_rqids(v9p, path, &nwqid, &wqid); + tattach({ .client = v9p, .rattach.qid = &root_qid }); + fid = twalk({ + .client = v9p, .path = path, + .rwalk = { .nwqid = &nwqid, .wqid = &wqid } + }).newfid; /* * The 9p2000 protocol spec says: "nwqid is therefore either nwname or the * index of the first elementwise walk that failed." @@ -1127,37 +299,38 @@ static void fs_walk_2nd_nonexistent(void *obj, void *data, g_assert(wqid && wqid[0] && !is_same_qid(root_qid, wqid[0])); /* expect fid being unaffected by walk above */ - req = v9fs_tgetattr(v9p, fid, P9_GETATTR_BASIC, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rlerror(req, &err); - - g_assert_cmpint(err, ==, ENOENT); + tgetattr({ + .client = v9p, .fid = fid, .request_mask = P9_GETATTR_BASIC, + .expectErr = ENOENT + }); } static void fs_walk_none(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); v9fs_qid root_qid; g_autofree v9fs_qid *wqid = NULL; - P9Req *req; struct v9fs_attr attr; - do_version(v9p); - req = v9fs_tattach(v9p, 0, getuid(), 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rattach(req, &root_qid); + tversion({ .client = v9p }); + tattach({ + .client = v9p, .fid = 0, .n_uname = getuid(), + .rattach.qid = &root_qid + }); - req = v9fs_twalk(v9p, 0, 1, 0, NULL, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rwalk(req, NULL, &wqid); + twalk({ + .client = v9p, .fid = 0, .newfid = 1, .nwname = 0, .wnames = NULL, + .rwalk.wqid = &wqid + }); /* special case: no QID is returned if nwname=0 was sent */ g_assert(wqid == NULL); - req = v9fs_tgetattr(v9p, 1, P9_GETATTR_BASIC, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rgetattr(req, &attr); + tgetattr({ + .client = v9p, .fid = 1, .request_mask = P9_GETATTR_BASIC, + .rgetattr.attr = &attr + }); g_assert(is_same_qid(root_qid, attr.qid)); } @@ -1165,20 +338,21 @@ static void fs_walk_none(void *obj, void *data, QGuestAllocator *t_alloc) static void fs_walk_dotdot(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; - char *const wnames[] = { g_strdup("..") }; + v9fs_set_allocator(t_alloc); + char *wnames[] = { g_strdup("..") }; v9fs_qid root_qid; g_autofree v9fs_qid *wqid = NULL; - P9Req *req; - do_version(v9p); - req = v9fs_tattach(v9p, 0, getuid(), 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rattach(req, &root_qid); + tversion({ .client = v9p }); + tattach({ + .client = v9p, .fid = 0, .n_uname = getuid(), + .rattach.qid = &root_qid + }); - req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rwalk(req, NULL, &wqid); /* We now we'll get one qid */ + twalk({ + .client = v9p, .fid = 0, .newfid = 1, .nwname = 1, .wnames = wnames, + .rwalk.wqid = &wqid /* We now we'll get one qid */ + }); g_assert_cmpmem(&root_qid, 13, wqid[0], 13); @@ -1188,18 +362,15 @@ static void fs_walk_dotdot(void *obj, void *data, QGuestAllocator *t_alloc) static void fs_lopen(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; - char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_LOPEN_FILE) }; - P9Req *req; + v9fs_set_allocator(t_alloc); + char *wnames[] = { g_strdup(QTEST_V9FS_SYNTH_LOPEN_FILE) }; - do_attach(v9p); - req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rwalk(req, NULL, NULL); + tattach({ .client = v9p }); + twalk({ + .client = v9p, .fid = 0, .newfid = 1, .nwname = 1, .wnames = wnames + }); - req = v9fs_tlopen(v9p, 1, O_WRONLY, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rlopen(req, NULL, NULL); + tlopen({ .client = v9p, .fid = 1, .flags = O_WRONLY }); g_free(wnames[0]); } @@ -1207,25 +378,23 @@ static void fs_lopen(void *obj, void *data, QGuestAllocator *t_alloc) static void fs_write(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); static const uint32_t write_count = P9_MAX_SIZE / 2; - char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_WRITE_FILE) }; + char *wnames[] = { g_strdup(QTEST_V9FS_SYNTH_WRITE_FILE) }; g_autofree char *buf = g_malloc0(write_count); uint32_t count; - P9Req *req; - do_attach(v9p); - req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rwalk(req, NULL, NULL); + tattach({ .client = v9p }); + twalk({ + .client = v9p, .fid = 0, .newfid = 1, .nwname = 1, .wnames = wnames + }); - req = v9fs_tlopen(v9p, 1, O_WRONLY, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rlopen(req, NULL, NULL); + tlopen({ .client = v9p, .fid = 1, .flags = O_WRONLY }); - req = v9fs_twrite(v9p, 1, 0, write_count, buf, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rwrite(req, &count); + count = twrite({ + .client = v9p, .fid = 1, .offset = 0, .count = write_count, + .data = buf + }).count; g_assert_cmpint(count, ==, write_count); g_free(wnames[0]); @@ -1234,28 +403,32 @@ static void fs_write(void *obj, void *data, QGuestAllocator *t_alloc) static void fs_flush_success(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; - char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_FLUSH_FILE) }; + v9fs_set_allocator(t_alloc); + char *wnames[] = { g_strdup(QTEST_V9FS_SYNTH_FLUSH_FILE) }; P9Req *req, *flush_req; uint32_t reply_len; uint8_t should_block; - do_attach(v9p); - req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rwalk(req, NULL, NULL); + tattach({ .client = v9p }); + twalk({ + .client = v9p, .fid = 0, .newfid = 1, .nwname = 1, .wnames = wnames + }); - req = v9fs_tlopen(v9p, 1, O_WRONLY, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rlopen(req, NULL, NULL); + tlopen({ .client = v9p, .fid = 1, .flags = O_WRONLY }); /* This will cause the 9p server to try to write data to the backend, * until the write request gets cancelled. */ should_block = 1; - req = v9fs_twrite(v9p, 1, 0, sizeof(should_block), &should_block, 0); + req = twrite({ + .client = v9p, .fid = 1, .offset = 0, + .count = sizeof(should_block), .data = &should_block, + .requestOnly = true + }).req; - flush_req = v9fs_tflush(v9p, req->tag, 1); + flush_req = tflush({ + .client = v9p, .oldtag = req->tag, .tag = 1, .requestOnly = true + }).req; /* The write request is supposed to be flushed: the server should just * mark the write request as used and reply to the flush request. @@ -1271,28 +444,32 @@ static void fs_flush_success(void *obj, void *data, QGuestAllocator *t_alloc) static void fs_flush_ignored(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; - char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_FLUSH_FILE) }; + v9fs_set_allocator(t_alloc); + char *wnames[] = { g_strdup(QTEST_V9FS_SYNTH_FLUSH_FILE) }; P9Req *req, *flush_req; uint32_t count; uint8_t should_block; - do_attach(v9p); - req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rwalk(req, NULL, NULL); + tattach({ .client = v9p }); + twalk({ + .client = v9p, .fid = 0, .newfid = 1, .nwname = 1, .wnames = wnames + }); - req = v9fs_tlopen(v9p, 1, O_WRONLY, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rlopen(req, NULL, NULL); + tlopen({ .client = v9p, .fid = 1, .flags = O_WRONLY }); /* This will cause the write request to complete right away, before it * could be actually cancelled. */ should_block = 0; - req = v9fs_twrite(v9p, 1, 0, sizeof(should_block), &should_block, 0); + req = twrite({ + .client = v9p, .fid = 1, .offset = 0, + .count = sizeof(should_block), .data = &should_block, + .requestOnly = true + }).req; - flush_req = v9fs_tflush(v9p, req->tag, 1); + flush_req = tflush({ + .client = v9p, .oldtag = req->tag, .tag = 1, .requestOnly = true + }).req; /* The write request is supposed to complete. The server should * reply to the write request and the flush request. @@ -1305,99 +482,24 @@ static void fs_flush_ignored(void *obj, void *data, QGuestAllocator *t_alloc) g_free(wnames[0]); } -static void do_mkdir(QVirtio9P *v9p, const char *path, const char *cname) -{ - g_autofree char *name = g_strdup(cname); - uint32_t fid; - P9Req *req; - - fid = do_walk(v9p, path); - - req = v9fs_tmkdir(v9p, fid, name, 0750, 0, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rmkdir(req, NULL); -} - -/* create a regular file with Tlcreate and return file's fid */ -static uint32_t do_lcreate(QVirtio9P *v9p, const char *path, - const char *cname) -{ - g_autofree char *name = g_strdup(cname); - uint32_t fid; - P9Req *req; - - fid = do_walk(v9p, path); - - req = v9fs_tlcreate(v9p, fid, name, 0, 0750, 0, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rlcreate(req, NULL, NULL); - - return fid; -} - -/* create symlink named @a clink in directory @a path pointing to @a to */ -static void do_symlink(QVirtio9P *v9p, const char *path, const char *clink, - const char *to) -{ - g_autofree char *name = g_strdup(clink); - g_autofree char *dst = g_strdup(to); - uint32_t fid; - P9Req *req; - - fid = do_walk(v9p, path); - - req = v9fs_tsymlink(v9p, fid, name, dst, 0, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rsymlink(req, NULL); -} - -/* create a hard link named @a clink in directory @a path pointing to @a to */ -static void do_hardlink(QVirtio9P *v9p, const char *path, const char *clink, - const char *to) -{ - uint32_t dfid, fid; - P9Req *req; - - dfid = do_walk(v9p, path); - fid = do_walk(v9p, to); - - req = v9fs_tlink(v9p, dfid, fid, clink, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_rlink(req); -} - -static void do_unlinkat(QVirtio9P *v9p, const char *atpath, const char *rpath, - uint32_t flags) -{ - g_autofree char *name = g_strdup(rpath); - uint32_t fid; - P9Req *req; - - fid = do_walk(v9p, atpath); - - req = v9fs_tunlinkat(v9p, fid, name, flags, 0); - v9fs_req_wait_for_reply(req, NULL); - v9fs_runlinkat(req); -} - static void fs_readdir_split_128(void *obj, void *data, QGuestAllocator *t_alloc) { - alloc = t_alloc; + v9fs_set_allocator(t_alloc); do_readdir_split(obj, 128); } static void fs_readdir_split_256(void *obj, void *data, QGuestAllocator *t_alloc) { - alloc = t_alloc; + v9fs_set_allocator(t_alloc); do_readdir_split(obj, 256); } static void fs_readdir_split_512(void *obj, void *data, QGuestAllocator *t_alloc) { - alloc = t_alloc; + v9fs_set_allocator(t_alloc); do_readdir_split(obj, 512); } @@ -1407,15 +509,15 @@ static void fs_readdir_split_512(void *obj, void *data, static void fs_create_dir(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); struct stat st; g_autofree char *root_path = virtio_9p_test_path(""); g_autofree char *new_dir = virtio_9p_test_path("01"); g_assert(root_path != NULL); - do_attach(v9p); - do_mkdir(v9p, "/", "01"); + tattach({ .client = v9p }); + tmkdir({ .client = v9p, .atPath = "/", .name = "01" }); /* check if created directory really exists now ... */ g_assert(stat(new_dir, &st) == 0); @@ -1426,22 +528,25 @@ static void fs_create_dir(void *obj, void *data, QGuestAllocator *t_alloc) static void fs_unlinkat_dir(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); struct stat st; g_autofree char *root_path = virtio_9p_test_path(""); g_autofree char *new_dir = virtio_9p_test_path("02"); g_assert(root_path != NULL); - do_attach(v9p); - do_mkdir(v9p, "/", "02"); + tattach({ .client = v9p }); + tmkdir({ .client = v9p, .atPath = "/", .name = "02" }); /* check if created directory really exists now ... */ g_assert(stat(new_dir, &st) == 0); /* ... and is actually a directory */ g_assert((st.st_mode & S_IFMT) == S_IFDIR); - do_unlinkat(v9p, "/", "02", P9_DOTL_AT_REMOVEDIR); + tunlinkat({ + .client = v9p, .atPath = "/", .name = "02", + .flags = P9_DOTL_AT_REMOVEDIR + }); /* directory should be gone now */ g_assert(stat(new_dir, &st) != 0); } @@ -1449,13 +554,13 @@ static void fs_unlinkat_dir(void *obj, void *data, QGuestAllocator *t_alloc) static void fs_create_file(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); struct stat st; g_autofree char *new_file = virtio_9p_test_path("03/1st_file"); - do_attach(v9p); - do_mkdir(v9p, "/", "03"); - do_lcreate(v9p, "03", "1st_file"); + tattach({ .client = v9p }); + tmkdir({ .client = v9p, .atPath = "/", .name = "03" }); + tlcreate({ .client = v9p, .atPath = "03", .name = "1st_file" }); /* check if created file exists now ... */ g_assert(stat(new_file, &st) == 0); @@ -1466,20 +571,20 @@ static void fs_create_file(void *obj, void *data, QGuestAllocator *t_alloc) static void fs_unlinkat_file(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); struct stat st; g_autofree char *new_file = virtio_9p_test_path("04/doa_file"); - do_attach(v9p); - do_mkdir(v9p, "/", "04"); - do_lcreate(v9p, "04", "doa_file"); + tattach({ .client = v9p }); + tmkdir({ .client = v9p, .atPath = "/", .name = "04" }); + tlcreate({ .client = v9p, .atPath = "04", .name = "doa_file" }); /* check if created file exists now ... */ g_assert(stat(new_file, &st) == 0); /* ... and is a regular file */ g_assert((st.st_mode & S_IFMT) == S_IFREG); - do_unlinkat(v9p, "04", "doa_file", 0); + tunlinkat({ .client = v9p, .atPath = "04", .name = "doa_file" }); /* file should be gone now */ g_assert(stat(new_file, &st) != 0); } @@ -1487,18 +592,21 @@ static void fs_unlinkat_file(void *obj, void *data, QGuestAllocator *t_alloc) static void fs_symlink_file(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); struct stat st; g_autofree char *real_file = virtio_9p_test_path("05/real_file"); g_autofree char *symlink_file = virtio_9p_test_path("05/symlink_file"); - do_attach(v9p); - do_mkdir(v9p, "/", "05"); - do_lcreate(v9p, "05", "real_file"); + tattach({ .client = v9p }); + tmkdir({ .client = v9p, .atPath = "/", .name = "05" }); + tlcreate({ .client = v9p, .atPath = "05", .name = "real_file" }); g_assert(stat(real_file, &st) == 0); g_assert((st.st_mode & S_IFMT) == S_IFREG); - do_symlink(v9p, "05", "symlink_file", "real_file"); + tsymlink({ + .client = v9p, .atPath = "05", .name = "symlink_file", + .symtgt = "real_file" + }); /* check if created link exists now */ g_assert(stat(symlink_file, &st) == 0); @@ -1508,21 +616,24 @@ static void fs_unlinkat_symlink(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); struct stat st; g_autofree char *real_file = virtio_9p_test_path("06/real_file"); g_autofree char *symlink_file = virtio_9p_test_path("06/symlink_file"); - do_attach(v9p); - do_mkdir(v9p, "/", "06"); - do_lcreate(v9p, "06", "real_file"); + tattach({ .client = v9p }); + tmkdir({ .client = v9p, .atPath = "/", .name = "06" }); + tlcreate({ .client = v9p, .atPath = "06", .name = "real_file" }); g_assert(stat(real_file, &st) == 0); g_assert((st.st_mode & S_IFMT) == S_IFREG); - do_symlink(v9p, "06", "symlink_file", "real_file"); + tsymlink({ + .client = v9p, .atPath = "06", .name = "symlink_file", + .symtgt = "real_file" + }); g_assert(stat(symlink_file, &st) == 0); - do_unlinkat(v9p, "06", "symlink_file", 0); + tunlinkat({ .client = v9p, .atPath = "06", .name = "symlink_file" }); /* symlink should be gone now */ g_assert(stat(symlink_file, &st) != 0); } @@ -1530,18 +641,21 @@ static void fs_unlinkat_symlink(void *obj, void *data, static void fs_hardlink_file(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); struct stat st_real, st_link; g_autofree char *real_file = virtio_9p_test_path("07/real_file"); g_autofree char *hardlink_file = virtio_9p_test_path("07/hardlink_file"); - do_attach(v9p); - do_mkdir(v9p, "/", "07"); - do_lcreate(v9p, "07", "real_file"); + tattach({ .client = v9p }); + tmkdir({ .client = v9p, .atPath = "/", .name = "07" }); + tlcreate({ .client = v9p, .atPath = "07", .name = "real_file" }); g_assert(stat(real_file, &st_real) == 0); g_assert((st_real.st_mode & S_IFMT) == S_IFREG); - do_hardlink(v9p, "07", "hardlink_file", "07/real_file"); + tlink({ + .client = v9p, .atPath = "07", .name = "hardlink_file", + .toPath = "07/real_file" + }); /* check if link exists now ... */ g_assert(stat(hardlink_file, &st_link) == 0); @@ -1555,21 +669,24 @@ static void fs_unlinkat_hardlink(void *obj, void *data, QGuestAllocator *t_alloc) { QVirtio9P *v9p = obj; - alloc = t_alloc; + v9fs_set_allocator(t_alloc); struct stat st_real, st_link; g_autofree char *real_file = virtio_9p_test_path("08/real_file"); g_autofree char *hardlink_file = virtio_9p_test_path("08/hardlink_file"); - do_attach(v9p); - do_mkdir(v9p, "/", "08"); - do_lcreate(v9p, "08", "real_file"); + tattach({ .client = v9p }); + tmkdir({ .client = v9p, .atPath = "/", .name = "08" }); + tlcreate({ .client = v9p, .atPath = "08", .name = "real_file" }); g_assert(stat(real_file, &st_real) == 0); g_assert((st_real.st_mode & S_IFMT) == S_IFREG); - do_hardlink(v9p, "08", "hardlink_file", "08/real_file"); + tlink({ + .client = v9p, .atPath = "08", .name = "hardlink_file", + .toPath = "08/real_file" + }); g_assert(stat(hardlink_file, &st_link) == 0); - do_unlinkat(v9p, "08", "hardlink_file", 0); + tunlinkat({ .client = v9p, .atPath = "08", .name = "hardlink_file" }); /* symlink should be gone now */ g_assert(stat(hardlink_file, &st_link) != 0); /* and old file should still exist */ |