qemu/tests/virtio-9p-test.c
<<
>>
Prefs
   1/*
   2 * QTest testcase for VirtIO 9P
   3 *
   4 * Copyright (c) 2014 SUSE LINUX Products GmbH
   5 *
   6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   7 * See the COPYING file in the top-level directory.
   8 */
   9
  10#include "qemu/osdep.h"
  11#include "libqtest-single.h"
  12#include "qemu/module.h"
  13#include "hw/9pfs/9p.h"
  14#include "hw/9pfs/9p-synth.h"
  15#include "libqos/virtio-9p.h"
  16#include "libqos/qgraph.h"
  17
  18#define QVIRTIO_9P_TIMEOUT_US (10 * 1000 * 1000)
  19static QGuestAllocator *alloc;
  20
  21static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc)
  22{
  23    QVirtio9P *v9p = obj;
  24    alloc = t_alloc;
  25    size_t tag_len = qvirtio_config_readw(v9p->vdev, 0);
  26    char *tag;
  27    int i;
  28
  29    g_assert_cmpint(tag_len, ==, strlen(MOUNT_TAG));
  30
  31    tag = g_malloc(tag_len);
  32    for (i = 0; i < tag_len; i++) {
  33        tag[i] = qvirtio_config_readb(v9p->vdev, i + 2);
  34    }
  35    g_assert_cmpmem(tag, tag_len, MOUNT_TAG, tag_len);
  36    g_free(tag);
  37}
  38
  39#define P9_MAX_SIZE 4096 /* Max size of a T-message or R-message */
  40
  41typedef struct {
  42    QTestState *qts;
  43    QVirtio9P *v9p;
  44    uint16_t tag;
  45    uint64_t t_msg;
  46    uint32_t t_size;
  47    uint64_t r_msg;
  48    /* No r_size, it is hardcoded to P9_MAX_SIZE */
  49    size_t t_off;
  50    size_t r_off;
  51    uint32_t free_head;
  52} P9Req;
  53
  54static void v9fs_memwrite(P9Req *req, const void *addr, size_t len)
  55{
  56    qtest_memwrite(req->qts, req->t_msg + req->t_off, addr, len);
  57    req->t_off += len;
  58}
  59
  60static void v9fs_memskip(P9Req *req, size_t len)
  61{
  62    req->r_off += len;
  63}
  64
  65static void v9fs_memread(P9Req *req, void *addr, size_t len)
  66{
  67    qtest_memread(req->qts, req->r_msg + req->r_off, addr, len);
  68    req->r_off += len;
  69}
  70
  71static void v9fs_uint16_write(P9Req *req, uint16_t val)
  72{
  73    uint16_t le_val = cpu_to_le16(val);
  74
  75    v9fs_memwrite(req, &le_val, 2);
  76}
  77
  78static void v9fs_uint16_read(P9Req *req, uint16_t *val)
  79{
  80    v9fs_memread(req, val, 2);
  81    le16_to_cpus(val);
  82}
  83
  84static void v9fs_uint32_write(P9Req *req, uint32_t val)
  85{
  86    uint32_t le_val = cpu_to_le32(val);
  87
  88    v9fs_memwrite(req, &le_val, 4);
  89}
  90
  91static void v9fs_uint64_write(P9Req *req, uint64_t val)
  92{
  93    uint64_t le_val = cpu_to_le64(val);
  94
  95    v9fs_memwrite(req, &le_val, 8);
  96}
  97
  98static void v9fs_uint32_read(P9Req *req, uint32_t *val)
  99{
 100    v9fs_memread(req, val, 4);
 101    le32_to_cpus(val);
 102}
 103
 104/* len[2] string[len] */
 105static uint16_t v9fs_string_size(const char *string)
 106{
 107    size_t len = strlen(string);
 108
 109    g_assert_cmpint(len, <=, UINT16_MAX - 2);
 110
 111    return 2 + len;
 112}
 113
 114static void v9fs_string_write(P9Req *req, const char *string)
 115{
 116    int len = strlen(string);
 117
 118    g_assert_cmpint(len, <=, UINT16_MAX);
 119
 120    v9fs_uint16_write(req, (uint16_t) len);
 121    v9fs_memwrite(req, string, len);
 122}
 123
 124static void v9fs_string_read(P9Req *req, uint16_t *len, char **string)
 125{
 126    uint16_t local_len;
 127
 128    v9fs_uint16_read(req, &local_len);
 129    if (len) {
 130        *len = local_len;
 131    }
 132    if (string) {
 133        *string = g_malloc(local_len);
 134        v9fs_memread(req, *string, local_len);
 135    } else {
 136        v9fs_memskip(req, local_len);
 137    }
 138}
 139
 140 typedef struct {
 141    uint32_t size;
 142    uint8_t id;
 143    uint16_t tag;
 144} QEMU_PACKED P9Hdr;
 145
 146static P9Req *v9fs_req_init(QVirtio9P *v9p, uint32_t size, uint8_t id,
 147                            uint16_t tag)
 148{
 149    P9Req *req = g_new0(P9Req, 1);
 150    uint32_t total_size = 7; /* 9P header has well-known size of 7 bytes */
 151    P9Hdr hdr = {
 152        .id = id,
 153        .tag = cpu_to_le16(tag)
 154    };
 155
 156    g_assert_cmpint(total_size, <=, UINT32_MAX - size);
 157    total_size += size;
 158    hdr.size = cpu_to_le32(total_size);
 159
 160    g_assert_cmpint(total_size, <=, P9_MAX_SIZE);
 161
 162    req->qts = global_qtest;
 163    req->v9p = v9p;
 164    req->t_size = total_size;
 165    req->t_msg = guest_alloc(alloc, req->t_size);
 166    v9fs_memwrite(req, &hdr, 7);
 167    req->tag = tag;
 168    return req;
 169}
 170
 171static void v9fs_req_send(P9Req *req)
 172{
 173    QVirtio9P *v9p = req->v9p;
 174
 175    req->r_msg = guest_alloc(alloc, P9_MAX_SIZE);
 176    req->free_head = qvirtqueue_add(req->qts, v9p->vq, req->t_msg, req->t_size,
 177                                    false, true);
 178    qvirtqueue_add(req->qts, v9p->vq, req->r_msg, P9_MAX_SIZE, true, false);
 179    qvirtqueue_kick(req->qts, v9p->vdev, v9p->vq, req->free_head);
 180    req->t_off = 0;
 181}
 182
 183static const char *rmessage_name(uint8_t id)
 184{
 185    return
 186        id == P9_RLERROR ? "RLERROR" :
 187        id == P9_RVERSION ? "RVERSION" :
 188        id == P9_RATTACH ? "RATTACH" :
 189        id == P9_RWALK ? "RWALK" :
 190        id == P9_RLOPEN ? "RLOPEN" :
 191        id == P9_RWRITE ? "RWRITE" :
 192        id == P9_RFLUSH ? "RFLUSH" :
 193        "<unknown>";
 194}
 195
 196static void v9fs_req_wait_for_reply(P9Req *req, uint32_t *len)
 197{
 198    QVirtio9P *v9p = req->v9p;
 199
 200    qvirtio_wait_used_elem(req->qts, v9p->vdev, v9p->vq, req->free_head, len,
 201                           QVIRTIO_9P_TIMEOUT_US);
 202}
 203
 204static void v9fs_req_recv(P9Req *req, uint8_t id)
 205{
 206    P9Hdr hdr;
 207
 208    v9fs_memread(req, &hdr, 7);
 209    hdr.size = ldl_le_p(&hdr.size);
 210    hdr.tag = lduw_le_p(&hdr.tag);
 211
 212    g_assert_cmpint(hdr.size, >=, 7);
 213    g_assert_cmpint(hdr.size, <=, P9_MAX_SIZE);
 214    g_assert_cmpint(hdr.tag, ==, req->tag);
 215
 216    if (hdr.id != id) {
 217        g_printerr("Received response %d (%s) instead of %d (%s)\n",
 218                   hdr.id, rmessage_name(hdr.id), id, rmessage_name(id));
 219
 220        if (hdr.id == P9_RLERROR) {
 221            uint32_t err;
 222            v9fs_uint32_read(req, &err);
 223            g_printerr("Rlerror has errno %d (%s)\n", err, strerror(err));
 224        }
 225    }
 226    g_assert_cmpint(hdr.id, ==, id);
 227}
 228
 229static void v9fs_req_free(P9Req *req)
 230{
 231    guest_free(alloc, req->t_msg);
 232    guest_free(alloc, req->r_msg);
 233    g_free(req);
 234}
 235
 236/* size[4] Rlerror tag[2] ecode[4] */
 237static void v9fs_rlerror(P9Req *req, uint32_t *err)
 238{
 239    v9fs_req_recv(req, P9_RLERROR);
 240    v9fs_uint32_read(req, err);
 241    v9fs_req_free(req);
 242}
 243
 244/* size[4] Tversion tag[2] msize[4] version[s] */
 245static P9Req *v9fs_tversion(QVirtio9P *v9p, uint32_t msize, const char *version,
 246                            uint16_t tag)
 247{
 248    P9Req *req;
 249    uint32_t body_size = 4;
 250    uint16_t string_size = v9fs_string_size(version);
 251
 252    g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
 253    body_size += string_size;
 254    req = v9fs_req_init(v9p, body_size, P9_TVERSION, tag);
 255
 256    v9fs_uint32_write(req, msize);
 257    v9fs_string_write(req, version);
 258    v9fs_req_send(req);
 259    return req;
 260}
 261
 262/* size[4] Rversion tag[2] msize[4] version[s] */
 263static void v9fs_rversion(P9Req *req, uint16_t *len, char **version)
 264{
 265    uint32_t msize;
 266
 267    v9fs_req_recv(req, P9_RVERSION);
 268    v9fs_uint32_read(req, &msize);
 269
 270    g_assert_cmpint(msize, ==, P9_MAX_SIZE);
 271
 272    if (len || version) {
 273        v9fs_string_read(req, len, version);
 274    }
 275
 276    v9fs_req_free(req);
 277}
 278
 279/* size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s] n_uname[4] */
 280static P9Req *v9fs_tattach(QVirtio9P *v9p, uint32_t fid, uint32_t n_uname,
 281                           uint16_t tag)
 282{
 283    const char *uname = ""; /* ignored by QEMU */
 284    const char *aname = ""; /* ignored by QEMU */
 285    P9Req *req = v9fs_req_init(v9p, 4 + 4 + 2 + 2 + 4, P9_TATTACH, tag);
 286
 287    v9fs_uint32_write(req, fid);
 288    v9fs_uint32_write(req, P9_NOFID);
 289    v9fs_string_write(req, uname);
 290    v9fs_string_write(req, aname);
 291    v9fs_uint32_write(req, n_uname);
 292    v9fs_req_send(req);
 293    return req;
 294}
 295
 296typedef char v9fs_qid[13];
 297
 298/* size[4] Rattach tag[2] qid[13] */
 299static void v9fs_rattach(P9Req *req, v9fs_qid *qid)
 300{
 301    v9fs_req_recv(req, P9_RATTACH);
 302    if (qid) {
 303        v9fs_memread(req, qid, 13);
 304    }
 305    v9fs_req_free(req);
 306}
 307
 308/* size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s]) */
 309static P9Req *v9fs_twalk(QVirtio9P *v9p, uint32_t fid, uint32_t newfid,
 310                         uint16_t nwname, char *const wnames[], uint16_t tag)
 311{
 312    P9Req *req;
 313    int i;
 314    uint32_t body_size = 4 + 4 + 2;
 315
 316    for (i = 0; i < nwname; i++) {
 317        uint16_t wname_size = v9fs_string_size(wnames[i]);
 318
 319        g_assert_cmpint(body_size, <=, UINT32_MAX - wname_size);
 320        body_size += wname_size;
 321    }
 322    req = v9fs_req_init(v9p,  body_size, P9_TWALK, tag);
 323    v9fs_uint32_write(req, fid);
 324    v9fs_uint32_write(req, newfid);
 325    v9fs_uint16_write(req, nwname);
 326    for (i = 0; i < nwname; i++) {
 327        v9fs_string_write(req, wnames[i]);
 328    }
 329    v9fs_req_send(req);
 330    return req;
 331}
 332
 333/* size[4] Rwalk tag[2] nwqid[2] nwqid*(wqid[13]) */
 334static void v9fs_rwalk(P9Req *req, uint16_t *nwqid, v9fs_qid **wqid)
 335{
 336    uint16_t local_nwqid;
 337
 338    v9fs_req_recv(req, P9_RWALK);
 339    v9fs_uint16_read(req, &local_nwqid);
 340    if (nwqid) {
 341        *nwqid = local_nwqid;
 342    }
 343    if (wqid) {
 344        *wqid = g_malloc(local_nwqid * 13);
 345        v9fs_memread(req, *wqid, local_nwqid * 13);
 346    }
 347    v9fs_req_free(req);
 348}
 349
 350/* size[4] Tlopen tag[2] fid[4] flags[4] */
 351static P9Req *v9fs_tlopen(QVirtio9P *v9p, uint32_t fid, uint32_t flags,
 352                          uint16_t tag)
 353{
 354    P9Req *req;
 355
 356    req = v9fs_req_init(v9p,  4 + 4, P9_TLOPEN, tag);
 357    v9fs_uint32_write(req, fid);
 358    v9fs_uint32_write(req, flags);
 359    v9fs_req_send(req);
 360    return req;
 361}
 362
 363/* size[4] Rlopen tag[2] qid[13] iounit[4] */
 364static void v9fs_rlopen(P9Req *req, v9fs_qid *qid, uint32_t *iounit)
 365{
 366    v9fs_req_recv(req, P9_RLOPEN);
 367    if (qid) {
 368        v9fs_memread(req, qid, 13);
 369    } else {
 370        v9fs_memskip(req, 13);
 371    }
 372    if (iounit) {
 373        v9fs_uint32_read(req, iounit);
 374    }
 375    v9fs_req_free(req);
 376}
 377
 378/* size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count] */
 379static P9Req *v9fs_twrite(QVirtio9P *v9p, uint32_t fid, uint64_t offset,
 380                          uint32_t count, const void *data, uint16_t tag)
 381{
 382    P9Req *req;
 383    uint32_t body_size = 4 + 8 + 4;
 384
 385    g_assert_cmpint(body_size, <=, UINT32_MAX - count);
 386    body_size += count;
 387    req = v9fs_req_init(v9p,  body_size, P9_TWRITE, tag);
 388    v9fs_uint32_write(req, fid);
 389    v9fs_uint64_write(req, offset);
 390    v9fs_uint32_write(req, count);
 391    v9fs_memwrite(req, data, count);
 392    v9fs_req_send(req);
 393    return req;
 394}
 395
 396/* size[4] Rwrite tag[2] count[4] */
 397static void v9fs_rwrite(P9Req *req, uint32_t *count)
 398{
 399    v9fs_req_recv(req, P9_RWRITE);
 400    if (count) {
 401        v9fs_uint32_read(req, count);
 402    }
 403    v9fs_req_free(req);
 404}
 405
 406/* size[4] Tflush tag[2] oldtag[2] */
 407static P9Req *v9fs_tflush(QVirtio9P *v9p, uint16_t oldtag, uint16_t tag)
 408{
 409    P9Req *req;
 410
 411    req = v9fs_req_init(v9p,  2, P9_TFLUSH, tag);
 412    v9fs_uint32_write(req, oldtag);
 413    v9fs_req_send(req);
 414    return req;
 415}
 416
 417/* size[4] Rflush tag[2] */
 418static void v9fs_rflush(P9Req *req)
 419{
 420    v9fs_req_recv(req, P9_RFLUSH);
 421    v9fs_req_free(req);
 422}
 423
 424static void fs_version(void *obj, void *data, QGuestAllocator *t_alloc)
 425{
 426    QVirtio9P *v9p = obj;
 427    alloc = t_alloc;
 428    const char *version = "9P2000.L";
 429    uint16_t server_len;
 430    char *server_version;
 431    P9Req *req;
 432
 433    req = v9fs_tversion(v9p, P9_MAX_SIZE, version, P9_NOTAG);
 434    v9fs_req_wait_for_reply(req, NULL);
 435    v9fs_rversion(req, &server_len, &server_version);
 436
 437    g_assert_cmpmem(server_version, server_len, version, strlen(version));
 438
 439    g_free(server_version);
 440}
 441
 442static void fs_attach(void *obj, void *data, QGuestAllocator *t_alloc)
 443{
 444    QVirtio9P *v9p = obj;
 445    alloc = t_alloc;
 446    P9Req *req;
 447
 448    fs_version(v9p, NULL, t_alloc);
 449    req = v9fs_tattach(v9p, 0, getuid(), 0);
 450    v9fs_req_wait_for_reply(req, NULL);
 451    v9fs_rattach(req, NULL);
 452}
 453
 454static void fs_walk(void *obj, void *data, QGuestAllocator *t_alloc)
 455{
 456    QVirtio9P *v9p = obj;
 457    alloc = t_alloc;
 458    char *wnames[P9_MAXWELEM];
 459    uint16_t nwqid;
 460    v9fs_qid *wqid;
 461    int i;
 462    P9Req *req;
 463
 464    for (i = 0; i < P9_MAXWELEM; i++) {
 465        wnames[i] = g_strdup_printf(QTEST_V9FS_SYNTH_WALK_FILE, i);
 466    }
 467
 468    fs_attach(v9p, NULL, t_alloc);
 469    req = v9fs_twalk(v9p, 0, 1, P9_MAXWELEM, wnames, 0);
 470    v9fs_req_wait_for_reply(req, NULL);
 471    v9fs_rwalk(req, &nwqid, &wqid);
 472
 473    g_assert_cmpint(nwqid, ==, P9_MAXWELEM);
 474
 475    for (i = 0; i < P9_MAXWELEM; i++) {
 476        g_free(wnames[i]);
 477    }
 478
 479    g_free(wqid);
 480}
 481
 482static void fs_walk_no_slash(void *obj, void *data, QGuestAllocator *t_alloc)
 483{
 484    QVirtio9P *v9p = obj;
 485    alloc = t_alloc;
 486    char *const wnames[] = { g_strdup(" /") };
 487    P9Req *req;
 488    uint32_t err;
 489
 490    fs_attach(v9p, NULL, t_alloc);
 491    req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
 492    v9fs_req_wait_for_reply(req, NULL);
 493    v9fs_rlerror(req, &err);
 494
 495    g_assert_cmpint(err, ==, ENOENT);
 496
 497    g_free(wnames[0]);
 498}
 499
 500static void fs_walk_dotdot(void *obj, void *data, QGuestAllocator *t_alloc)
 501{
 502    QVirtio9P *v9p = obj;
 503    alloc = t_alloc;
 504    char *const wnames[] = { g_strdup("..") };
 505    v9fs_qid root_qid, *wqid;
 506    P9Req *req;
 507
 508    fs_version(v9p, NULL, t_alloc);
 509    req = v9fs_tattach(v9p, 0, getuid(), 0);
 510    v9fs_req_wait_for_reply(req, NULL);
 511    v9fs_rattach(req, &root_qid);
 512
 513    req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
 514    v9fs_req_wait_for_reply(req, NULL);
 515    v9fs_rwalk(req, NULL, &wqid); /* We now we'll get one qid */
 516
 517    g_assert_cmpmem(&root_qid, 13, wqid[0], 13);
 518
 519    g_free(wqid);
 520    g_free(wnames[0]);
 521}
 522
 523static void fs_lopen(void *obj, void *data, QGuestAllocator *t_alloc)
 524{
 525    QVirtio9P *v9p = obj;
 526    alloc = t_alloc;
 527    char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_LOPEN_FILE) };
 528    P9Req *req;
 529
 530    fs_attach(v9p, NULL, t_alloc);
 531    req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
 532    v9fs_req_wait_for_reply(req, NULL);
 533    v9fs_rwalk(req, NULL, NULL);
 534
 535    req = v9fs_tlopen(v9p, 1, O_WRONLY, 0);
 536    v9fs_req_wait_for_reply(req, NULL);
 537    v9fs_rlopen(req, NULL, NULL);
 538
 539    g_free(wnames[0]);
 540}
 541
 542static void fs_write(void *obj, void *data, QGuestAllocator *t_alloc)
 543{
 544    QVirtio9P *v9p = obj;
 545    alloc = t_alloc;
 546    static const uint32_t write_count = P9_MAX_SIZE / 2;
 547    char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_WRITE_FILE) };
 548    char *buf = g_malloc0(write_count);
 549    uint32_t count;
 550    P9Req *req;
 551
 552    fs_attach(v9p, NULL, t_alloc);
 553    req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
 554    v9fs_req_wait_for_reply(req, NULL);
 555    v9fs_rwalk(req, NULL, NULL);
 556
 557    req = v9fs_tlopen(v9p, 1, O_WRONLY, 0);
 558    v9fs_req_wait_for_reply(req, NULL);
 559    v9fs_rlopen(req, NULL, NULL);
 560
 561    req = v9fs_twrite(v9p, 1, 0, write_count, buf, 0);
 562    v9fs_req_wait_for_reply(req, NULL);
 563    v9fs_rwrite(req, &count);
 564    g_assert_cmpint(count, ==, write_count);
 565
 566    g_free(buf);
 567    g_free(wnames[0]);
 568}
 569
 570static void fs_flush_success(void *obj, void *data, QGuestAllocator *t_alloc)
 571{
 572    QVirtio9P *v9p = obj;
 573    alloc = t_alloc;
 574    char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_FLUSH_FILE) };
 575    P9Req *req, *flush_req;
 576    uint32_t reply_len;
 577    uint8_t should_block;
 578
 579    fs_attach(v9p, NULL, t_alloc);
 580    req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
 581    v9fs_req_wait_for_reply(req, NULL);
 582    v9fs_rwalk(req, NULL, NULL);
 583
 584    req = v9fs_tlopen(v9p, 1, O_WRONLY, 0);
 585    v9fs_req_wait_for_reply(req, NULL);
 586    v9fs_rlopen(req, NULL, NULL);
 587
 588    /* This will cause the 9p server to try to write data to the backend,
 589     * until the write request gets cancelled.
 590     */
 591    should_block = 1;
 592    req = v9fs_twrite(v9p, 1, 0, sizeof(should_block), &should_block, 0);
 593
 594    flush_req = v9fs_tflush(v9p, req->tag, 1);
 595
 596    /* The write request is supposed to be flushed: the server should just
 597     * mark the write request as used and reply to the flush request.
 598     */
 599    v9fs_req_wait_for_reply(req, &reply_len);
 600    g_assert_cmpint(reply_len, ==, 0);
 601    v9fs_req_free(req);
 602    v9fs_rflush(flush_req);
 603
 604    g_free(wnames[0]);
 605}
 606
 607static void fs_flush_ignored(void *obj, void *data, QGuestAllocator *t_alloc)
 608{
 609    QVirtio9P *v9p = obj;
 610    alloc = t_alloc;
 611    char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_FLUSH_FILE) };
 612    P9Req *req, *flush_req;
 613    uint32_t count;
 614    uint8_t should_block;
 615
 616    fs_attach(v9p, NULL, t_alloc);
 617    req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0);
 618    v9fs_req_wait_for_reply(req, NULL);
 619    v9fs_rwalk(req, NULL, NULL);
 620
 621    req = v9fs_tlopen(v9p, 1, O_WRONLY, 0);
 622    v9fs_req_wait_for_reply(req, NULL);
 623    v9fs_rlopen(req, NULL, NULL);
 624
 625    /* This will cause the write request to complete right away, before it
 626     * could be actually cancelled.
 627     */
 628    should_block = 0;
 629    req = v9fs_twrite(v9p, 1, 0, sizeof(should_block), &should_block, 0);
 630
 631    flush_req = v9fs_tflush(v9p, req->tag, 1);
 632
 633    /* The write request is supposed to complete. The server should
 634     * reply to the write request and the flush request.
 635     */
 636    v9fs_req_wait_for_reply(req, NULL);
 637    v9fs_rwrite(req, &count);
 638    g_assert_cmpint(count, ==, sizeof(should_block));
 639    v9fs_rflush(flush_req);
 640
 641    g_free(wnames[0]);
 642}
 643
 644static void register_virtio_9p_test(void)
 645{
 646    qos_add_test("config", "virtio-9p", pci_config, NULL);
 647    qos_add_test("fs/version/basic", "virtio-9p", fs_version, NULL);
 648    qos_add_test("fs/attach/basic", "virtio-9p", fs_attach, NULL);
 649    qos_add_test("fs/walk/basic", "virtio-9p", fs_walk, NULL);
 650    qos_add_test("fs/walk/no_slash", "virtio-9p", fs_walk_no_slash,
 651                 NULL);
 652    qos_add_test("fs/walk/dotdot_from_root", "virtio-9p",
 653                 fs_walk_dotdot, NULL);
 654    qos_add_test("fs/lopen/basic", "virtio-9p", fs_lopen, NULL);
 655    qos_add_test("fs/write/basic", "virtio-9p", fs_write, NULL);
 656    qos_add_test("fs/flush/success", "virtio-9p", fs_flush_success,
 657                 NULL);
 658    qos_add_test("fs/flush/ignored", "virtio-9p", fs_flush_ignored,
 659                 NULL);
 660}
 661
 662libqos_init(register_virtio_9p_test);
 663