12d888c09SAndreas Färber /* 22d888c09SAndreas Färber * QTest testcase for VirtIO 9P 32d888c09SAndreas Färber * 42d888c09SAndreas Färber * Copyright (c) 2014 SUSE LINUX Products GmbH 52d888c09SAndreas Färber * 62d888c09SAndreas Färber * This work is licensed under the terms of the GNU GPL, version 2 or later. 72d888c09SAndreas Färber * See the COPYING file in the top-level directory. 82d888c09SAndreas Färber */ 92d888c09SAndreas Färber 106f569084SChristian Schoenebeck /* 116f569084SChristian Schoenebeck * Not so fast! You might want to read the 9p developer docs first: 126f569084SChristian Schoenebeck * https://wiki.qemu.org/Documentation/9p 136f569084SChristian Schoenebeck */ 146f569084SChristian Schoenebeck 15fbc04127SPeter Maydell #include "qemu/osdep.h" 160b8fa32fSMarkus Armbruster #include "qemu/module.h" 17684f9120SChristian Schoenebeck #include "libqos/virtio-9p-client.h" 1865b70fc7SGreg Kurz 19569f3b63SChristian Schoenebeck #define twalk(...) v9fs_twalk((TWalkOpt) __VA_ARGS__) 20bee8fda2SChristian Schoenebeck #define tversion(...) v9fs_tversion((TVersionOpt) __VA_ARGS__) 2174a160abSChristian Schoenebeck #define tattach(...) v9fs_tattach((TAttachOpt) __VA_ARGS__) 222af5be47SChristian Schoenebeck #define tgetattr(...) v9fs_tgetattr((TGetAttrOpt) __VA_ARGS__) 231ebacc40SChristian Schoenebeck #define treaddir(...) v9fs_treaddir((TReadDirOpt) __VA_ARGS__) 243878ce4cSChristian Schoenebeck #define tlopen(...) v9fs_tlopen((TLOpenOpt) __VA_ARGS__) 25ac9e4e61SChristian Schoenebeck #define twrite(...) v9fs_twrite((TWriteOpt) __VA_ARGS__) 26*d89146fdSChristian Schoenebeck #define tflush(...) v9fs_tflush((TFlushOpt) __VA_ARGS__) 27653daf38SChristian Schoenebeck 28dfbe8b43SEmanuele Giuseppe Esposito static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc) 29557a4cc0SGreg Kurz { 30dfbe8b43SEmanuele Giuseppe Esposito QVirtio9P *v9p = obj; 31684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 32dfbe8b43SEmanuele Giuseppe Esposito size_t tag_len = qvirtio_config_readw(v9p->vdev, 0); 3365ceee0aSChristian Schoenebeck g_autofree char *tag = NULL; 34557a4cc0SGreg Kurz int i; 35557a4cc0SGreg Kurz 36dfbe8b43SEmanuele Giuseppe Esposito g_assert_cmpint(tag_len, ==, strlen(MOUNT_TAG)); 37557a4cc0SGreg Kurz 38557a4cc0SGreg Kurz tag = g_malloc(tag_len); 39557a4cc0SGreg Kurz for (i = 0; i < tag_len; i++) { 40dfbe8b43SEmanuele Giuseppe Esposito tag[i] = qvirtio_config_readb(v9p->vdev, i + 2); 41557a4cc0SGreg Kurz } 42dfbe8b43SEmanuele Giuseppe Esposito g_assert_cmpmem(tag, tag_len, MOUNT_TAG, tag_len); 431211d81bSGreg Kurz } 44557a4cc0SGreg Kurz 45a6821b82SChristian Schoenebeck static inline bool is_same_qid(v9fs_qid a, v9fs_qid b) 46a6821b82SChristian Schoenebeck { 47a6821b82SChristian Schoenebeck /* don't compare QID version for checking for file ID equalness */ 48a6821b82SChristian Schoenebeck return a[0] == b[0] && memcmp(&a[5], &b[5], 8) == 0; 49a6821b82SChristian Schoenebeck } 50a6821b82SChristian Schoenebeck 511c450e6eSGreg Kurz static void fs_version(void *obj, void *data, QGuestAllocator *t_alloc) 521c450e6eSGreg Kurz { 53684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 54bee8fda2SChristian Schoenebeck tversion({ .client = obj }); 551c450e6eSGreg Kurz } 561c450e6eSGreg Kurz 573fe4baf4SGreg Kurz static void fs_attach(void *obj, void *data, QGuestAllocator *t_alloc) 583fe4baf4SGreg Kurz { 59684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 6074a160abSChristian Schoenebeck tattach({ .client = obj }); 613fe4baf4SGreg Kurz } 623fe4baf4SGreg Kurz 63dfbe8b43SEmanuele Giuseppe Esposito static void fs_walk(void *obj, void *data, QGuestAllocator *t_alloc) 6404b88c84SGreg Kurz { 65dfbe8b43SEmanuele Giuseppe Esposito QVirtio9P *v9p = obj; 66684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 672893ddd5SGreg Kurz char *wnames[P9_MAXWELEM]; 6804b88c84SGreg Kurz uint16_t nwqid; 6965ceee0aSChristian Schoenebeck g_autofree v9fs_qid *wqid = NULL; 7004b88c84SGreg Kurz int i; 7104b88c84SGreg Kurz 7204b88c84SGreg Kurz for (i = 0; i < P9_MAXWELEM; i++) { 732893ddd5SGreg Kurz wnames[i] = g_strdup_printf(QTEST_V9FS_SYNTH_WALK_FILE, i); 7404b88c84SGreg Kurz } 7504b88c84SGreg Kurz 7674a160abSChristian Schoenebeck tattach({ .client = v9p }); 773f3e9232SChristian Schoenebeck twalk({ 78569f3b63SChristian Schoenebeck .client = v9p, .fid = 0, .newfid = 1, 793f3e9232SChristian Schoenebeck .nwname = P9_MAXWELEM, .wnames = wnames, 803f3e9232SChristian Schoenebeck .rwalk = { .nwqid = &nwqid, .wqid = &wqid } 813f3e9232SChristian Schoenebeck }); 8204b88c84SGreg Kurz 8304b88c84SGreg Kurz g_assert_cmpint(nwqid, ==, P9_MAXWELEM); 8404b88c84SGreg Kurz 8504b88c84SGreg Kurz for (i = 0; i < P9_MAXWELEM; i++) { 8604b88c84SGreg Kurz g_free(wnames[i]); 8704b88c84SGreg Kurz } 8804b88c84SGreg Kurz } 8904b88c84SGreg Kurz 904829469fSChristian Schoenebeck static bool fs_dirents_contain_name(struct V9fsDirent *e, const char* name) 914829469fSChristian Schoenebeck { 924829469fSChristian Schoenebeck for (; e; e = e->next) { 934829469fSChristian Schoenebeck if (!strcmp(e->name, name)) { 944829469fSChristian Schoenebeck return true; 954829469fSChristian Schoenebeck } 964829469fSChristian Schoenebeck } 974829469fSChristian Schoenebeck return false; 984829469fSChristian Schoenebeck } 994829469fSChristian Schoenebeck 10046488b62SChristian Schoenebeck /* basic readdir test where reply fits into a single response message */ 1014829469fSChristian Schoenebeck static void fs_readdir(void *obj, void *data, QGuestAllocator *t_alloc) 1024829469fSChristian Schoenebeck { 1034829469fSChristian Schoenebeck QVirtio9P *v9p = obj; 104684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 105569f3b63SChristian Schoenebeck char *wnames[] = { g_strdup(QTEST_V9FS_SYNTH_READDIR_DIR) }; 1064829469fSChristian Schoenebeck uint16_t nqid; 1074829469fSChristian Schoenebeck v9fs_qid qid; 1084829469fSChristian Schoenebeck uint32_t count, nentries; 1094829469fSChristian Schoenebeck struct V9fsDirent *entries = NULL; 1104829469fSChristian Schoenebeck 11174a160abSChristian Schoenebeck tattach({ .client = v9p }); 1123f3e9232SChristian Schoenebeck twalk({ 113569f3b63SChristian Schoenebeck .client = v9p, .fid = 0, .newfid = 1, 1143f3e9232SChristian Schoenebeck .nwname = 1, .wnames = wnames, .rwalk.nwqid = &nqid 1153f3e9232SChristian Schoenebeck }); 1164829469fSChristian Schoenebeck g_assert_cmpint(nqid, ==, 1); 1174829469fSChristian Schoenebeck 1180e4c4ff0SChristian Schoenebeck tlopen({ 1190e4c4ff0SChristian Schoenebeck .client = v9p, .fid = 1, .flags = O_DIRECTORY, .rlopen.qid = &qid 1200e4c4ff0SChristian Schoenebeck }); 1214829469fSChristian Schoenebeck 1224829469fSChristian Schoenebeck /* 1234829469fSChristian Schoenebeck * submit count = msize - 11, because 11 is the header size of Rreaddir 1244829469fSChristian Schoenebeck */ 125a9a53769SChristian Schoenebeck treaddir({ 1261ebacc40SChristian Schoenebeck .client = v9p, .fid = 1, .offset = 0, .count = P9_MAX_SIZE - 11, 127a9a53769SChristian Schoenebeck .rreaddir = { 128a9a53769SChristian Schoenebeck .count = &count, .nentries = &nentries, .entries = &entries 129a9a53769SChristian Schoenebeck } 130a9a53769SChristian Schoenebeck }); 1314829469fSChristian Schoenebeck 1324829469fSChristian Schoenebeck /* 1334829469fSChristian Schoenebeck * Assuming msize (P9_MAX_SIZE) is large enough so we can retrieve all 1344829469fSChristian Schoenebeck * dir entries with only one readdir request. 1354829469fSChristian Schoenebeck */ 1364829469fSChristian Schoenebeck g_assert_cmpint( 1374829469fSChristian Schoenebeck nentries, ==, 1384829469fSChristian Schoenebeck QTEST_V9FS_SYNTH_READDIR_NFILES + 2 /* "." and ".." */ 1394829469fSChristian Schoenebeck ); 1404829469fSChristian Schoenebeck 1414829469fSChristian Schoenebeck /* 1424829469fSChristian Schoenebeck * Check all file names exist in returned entries, ignore their order 1434829469fSChristian Schoenebeck * though. 1444829469fSChristian Schoenebeck */ 1454829469fSChristian Schoenebeck g_assert_cmpint(fs_dirents_contain_name(entries, "."), ==, true); 1464829469fSChristian Schoenebeck g_assert_cmpint(fs_dirents_contain_name(entries, ".."), ==, true); 1474829469fSChristian Schoenebeck for (int i = 0; i < QTEST_V9FS_SYNTH_READDIR_NFILES; ++i) { 14865ceee0aSChristian Schoenebeck g_autofree char *name = 14965ceee0aSChristian Schoenebeck g_strdup_printf(QTEST_V9FS_SYNTH_READDIR_FILE, i); 1504829469fSChristian Schoenebeck g_assert_cmpint(fs_dirents_contain_name(entries, name), ==, true); 1514829469fSChristian Schoenebeck } 1524829469fSChristian Schoenebeck 1534829469fSChristian Schoenebeck v9fs_free_dirents(entries); 1544829469fSChristian Schoenebeck g_free(wnames[0]); 1554829469fSChristian Schoenebeck } 1564829469fSChristian Schoenebeck 15746488b62SChristian Schoenebeck /* readdir test where overall request is split over several messages */ 1581d98613dSGreg Kurz static void do_readdir_split(QVirtio9P *v9p, uint32_t count) 15946488b62SChristian Schoenebeck { 160569f3b63SChristian Schoenebeck char *wnames[] = { g_strdup(QTEST_V9FS_SYNTH_READDIR_DIR) }; 16146488b62SChristian Schoenebeck uint16_t nqid; 16246488b62SChristian Schoenebeck v9fs_qid qid; 16346488b62SChristian Schoenebeck uint32_t nentries, npartialentries; 16446488b62SChristian Schoenebeck struct V9fsDirent *entries, *tail, *partialentries; 16546488b62SChristian Schoenebeck int fid; 16646488b62SChristian Schoenebeck uint64_t offset; 16746488b62SChristian Schoenebeck 16874a160abSChristian Schoenebeck tattach({ .client = v9p }); 16946488b62SChristian Schoenebeck 17046488b62SChristian Schoenebeck fid = 1; 17146488b62SChristian Schoenebeck offset = 0; 17246488b62SChristian Schoenebeck entries = NULL; 17346488b62SChristian Schoenebeck nentries = 0; 17446488b62SChristian Schoenebeck tail = NULL; 17546488b62SChristian Schoenebeck 1763f3e9232SChristian Schoenebeck twalk({ 177569f3b63SChristian Schoenebeck .client = v9p, .fid = 0, .newfid = fid, 1783f3e9232SChristian Schoenebeck .nwname = 1, .wnames = wnames, .rwalk.nwqid = &nqid 1793f3e9232SChristian Schoenebeck }); 18046488b62SChristian Schoenebeck g_assert_cmpint(nqid, ==, 1); 18146488b62SChristian Schoenebeck 1820e4c4ff0SChristian Schoenebeck tlopen({ 1830e4c4ff0SChristian Schoenebeck .client = v9p, .fid = fid, .flags = O_DIRECTORY, .rlopen.qid = &qid 1840e4c4ff0SChristian Schoenebeck }); 18546488b62SChristian Schoenebeck 18646488b62SChristian Schoenebeck /* 18746488b62SChristian Schoenebeck * send as many Treaddir requests as required to get all directory 18846488b62SChristian Schoenebeck * entries 18946488b62SChristian Schoenebeck */ 19046488b62SChristian Schoenebeck while (true) { 19146488b62SChristian Schoenebeck npartialentries = 0; 19246488b62SChristian Schoenebeck partialentries = NULL; 19346488b62SChristian Schoenebeck 194a9a53769SChristian Schoenebeck treaddir({ 1951ebacc40SChristian Schoenebeck .client = v9p, .fid = fid, .offset = offset, .count = count, 196a9a53769SChristian Schoenebeck .rreaddir = { 197a9a53769SChristian Schoenebeck .count = &count, .nentries = &npartialentries, 198a9a53769SChristian Schoenebeck .entries = &partialentries 199a9a53769SChristian Schoenebeck } 200a9a53769SChristian Schoenebeck }); 20146488b62SChristian Schoenebeck if (npartialentries > 0 && partialentries) { 20246488b62SChristian Schoenebeck if (!entries) { 20346488b62SChristian Schoenebeck entries = partialentries; 20446488b62SChristian Schoenebeck nentries = npartialentries; 20546488b62SChristian Schoenebeck tail = partialentries; 20646488b62SChristian Schoenebeck } else { 20746488b62SChristian Schoenebeck tail->next = partialentries; 20846488b62SChristian Schoenebeck nentries += npartialentries; 20946488b62SChristian Schoenebeck } 21046488b62SChristian Schoenebeck while (tail->next) { 21146488b62SChristian Schoenebeck tail = tail->next; 21246488b62SChristian Schoenebeck } 21346488b62SChristian Schoenebeck offset = tail->offset; 21446488b62SChristian Schoenebeck } else { 21546488b62SChristian Schoenebeck break; 21646488b62SChristian Schoenebeck } 21746488b62SChristian Schoenebeck } 21846488b62SChristian Schoenebeck 21946488b62SChristian Schoenebeck g_assert_cmpint( 22046488b62SChristian Schoenebeck nentries, ==, 22146488b62SChristian Schoenebeck QTEST_V9FS_SYNTH_READDIR_NFILES + 2 /* "." and ".." */ 22246488b62SChristian Schoenebeck ); 22346488b62SChristian Schoenebeck 22446488b62SChristian Schoenebeck /* 22546488b62SChristian Schoenebeck * Check all file names exist in returned entries, ignore their order 22646488b62SChristian Schoenebeck * though. 22746488b62SChristian Schoenebeck */ 22846488b62SChristian Schoenebeck g_assert_cmpint(fs_dirents_contain_name(entries, "."), ==, true); 22946488b62SChristian Schoenebeck g_assert_cmpint(fs_dirents_contain_name(entries, ".."), ==, true); 23046488b62SChristian Schoenebeck for (int i = 0; i < QTEST_V9FS_SYNTH_READDIR_NFILES; ++i) { 23146488b62SChristian Schoenebeck char *name = g_strdup_printf(QTEST_V9FS_SYNTH_READDIR_FILE, i); 23246488b62SChristian Schoenebeck g_assert_cmpint(fs_dirents_contain_name(entries, name), ==, true); 23346488b62SChristian Schoenebeck g_free(name); 23446488b62SChristian Schoenebeck } 23546488b62SChristian Schoenebeck 23646488b62SChristian Schoenebeck v9fs_free_dirents(entries); 23746488b62SChristian Schoenebeck 23846488b62SChristian Schoenebeck g_free(wnames[0]); 23946488b62SChristian Schoenebeck } 24046488b62SChristian Schoenebeck 241dfbe8b43SEmanuele Giuseppe Esposito static void fs_walk_no_slash(void *obj, void *data, QGuestAllocator *t_alloc) 242ba0d1037SGreg Kurz { 243dfbe8b43SEmanuele Giuseppe Esposito QVirtio9P *v9p = obj; 244684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 245569f3b63SChristian Schoenebeck char *wnames[] = { g_strdup(" /") }; 246ba0d1037SGreg Kurz 24774a160abSChristian Schoenebeck tattach({ .client = v9p }); 2483f3e9232SChristian Schoenebeck twalk({ 249569f3b63SChristian Schoenebeck .client = v9p, .fid = 0, .newfid = 1, .nwname = 1, .wnames = wnames, 2503f3e9232SChristian Schoenebeck .expectErr = ENOENT 2513f3e9232SChristian Schoenebeck }); 252ba0d1037SGreg Kurz 253ba0d1037SGreg Kurz g_free(wnames[0]); 254ba0d1037SGreg Kurz } 255ba0d1037SGreg Kurz 2569472a689SChristian Schoenebeck static void fs_walk_nonexistent(void *obj, void *data, QGuestAllocator *t_alloc) 2579472a689SChristian Schoenebeck { 2589472a689SChristian Schoenebeck QVirtio9P *v9p = obj; 259684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 2609472a689SChristian Schoenebeck 26174a160abSChristian Schoenebeck tattach({ .client = v9p }); 26215fbff48SChristian Schoenebeck /* 26315fbff48SChristian Schoenebeck * The 9p2000 protocol spec says: "If the first element cannot be walked 26415fbff48SChristian Schoenebeck * for any reason, Rerror is returned." 26515fbff48SChristian Schoenebeck */ 266569f3b63SChristian Schoenebeck twalk({ .client = v9p, .path = "non-existent", .expectErr = ENOENT }); 2679472a689SChristian Schoenebeck } 2689472a689SChristian Schoenebeck 26915fbff48SChristian Schoenebeck static void fs_walk_2nd_nonexistent(void *obj, void *data, 27015fbff48SChristian Schoenebeck QGuestAllocator *t_alloc) 27115fbff48SChristian Schoenebeck { 27215fbff48SChristian Schoenebeck QVirtio9P *v9p = obj; 273684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 2740e43495dSChristian Schoenebeck v9fs_qid root_qid; 27515fbff48SChristian Schoenebeck uint16_t nwqid; 27628c73670SChristian Schoenebeck uint32_t fid; 27715fbff48SChristian Schoenebeck g_autofree v9fs_qid *wqid = NULL; 27815fbff48SChristian Schoenebeck g_autofree char *path = g_strdup_printf( 27915fbff48SChristian Schoenebeck QTEST_V9FS_SYNTH_WALK_FILE "/non-existent", 0 28015fbff48SChristian Schoenebeck ); 28115fbff48SChristian Schoenebeck 28274a160abSChristian Schoenebeck tattach({ .client = v9p, .rattach.qid = &root_qid }); 283569f3b63SChristian Schoenebeck fid = twalk({ 284569f3b63SChristian Schoenebeck .client = v9p, .path = path, 2853f3e9232SChristian Schoenebeck .rwalk = { .nwqid = &nwqid, .wqid = &wqid } 286569f3b63SChristian Schoenebeck }).newfid; 28715fbff48SChristian Schoenebeck /* 28815fbff48SChristian Schoenebeck * The 9p2000 protocol spec says: "nwqid is therefore either nwname or the 28915fbff48SChristian Schoenebeck * index of the first elementwise walk that failed." 29015fbff48SChristian Schoenebeck */ 29115fbff48SChristian Schoenebeck assert(nwqid == 1); 2920e43495dSChristian Schoenebeck 2930e43495dSChristian Schoenebeck /* returned QID wqid[0] is file ID of 1st subdir */ 2940e43495dSChristian Schoenebeck g_assert(wqid && wqid[0] && !is_same_qid(root_qid, wqid[0])); 2950e43495dSChristian Schoenebeck 2960e43495dSChristian Schoenebeck /* expect fid being unaffected by walk above */ 29728c73670SChristian Schoenebeck tgetattr({ 2982af5be47SChristian Schoenebeck .client = v9p, .fid = fid, .request_mask = P9_GETATTR_BASIC, 29928c73670SChristian Schoenebeck .expectErr = ENOENT 30028c73670SChristian Schoenebeck }); 30115fbff48SChristian Schoenebeck } 30215fbff48SChristian Schoenebeck 303c1668948SChristian Schoenebeck static void fs_walk_none(void *obj, void *data, QGuestAllocator *t_alloc) 304c1668948SChristian Schoenebeck { 305c1668948SChristian Schoenebeck QVirtio9P *v9p = obj; 306684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 307c1668948SChristian Schoenebeck v9fs_qid root_qid; 308c1668948SChristian Schoenebeck g_autofree v9fs_qid *wqid = NULL; 309a6821b82SChristian Schoenebeck struct v9fs_attr attr; 310c1668948SChristian Schoenebeck 311bee8fda2SChristian Schoenebeck tversion({ .client = v9p }); 3121125ddf6SChristian Schoenebeck tattach({ 3131125ddf6SChristian Schoenebeck .client = v9p, .fid = 0, .n_uname = getuid(), 3141125ddf6SChristian Schoenebeck .rattach.qid = &root_qid 3151125ddf6SChristian Schoenebeck }); 316c1668948SChristian Schoenebeck 3173f3e9232SChristian Schoenebeck twalk({ 318569f3b63SChristian Schoenebeck .client = v9p, .fid = 0, .newfid = 1, .nwname = 0, .wnames = NULL, 3193f3e9232SChristian Schoenebeck .rwalk.wqid = &wqid 3203f3e9232SChristian Schoenebeck }); 321c1668948SChristian Schoenebeck 322c1668948SChristian Schoenebeck /* special case: no QID is returned if nwname=0 was sent */ 323c1668948SChristian Schoenebeck g_assert(wqid == NULL); 324a6821b82SChristian Schoenebeck 32528c73670SChristian Schoenebeck tgetattr({ 3262af5be47SChristian Schoenebeck .client = v9p, .fid = 1, .request_mask = P9_GETATTR_BASIC, 32728c73670SChristian Schoenebeck .rgetattr.attr = &attr 32828c73670SChristian Schoenebeck }); 329a6821b82SChristian Schoenebeck 330a6821b82SChristian Schoenebeck g_assert(is_same_qid(root_qid, attr.qid)); 331c1668948SChristian Schoenebeck } 332c1668948SChristian Schoenebeck 333dfbe8b43SEmanuele Giuseppe Esposito static void fs_walk_dotdot(void *obj, void *data, QGuestAllocator *t_alloc) 334a37c0702SGreg Kurz { 335dfbe8b43SEmanuele Giuseppe Esposito QVirtio9P *v9p = obj; 336684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 337569f3b63SChristian Schoenebeck char *wnames[] = { g_strdup("..") }; 33865ceee0aSChristian Schoenebeck v9fs_qid root_qid; 33965ceee0aSChristian Schoenebeck g_autofree v9fs_qid *wqid = NULL; 340a37c0702SGreg Kurz 341bee8fda2SChristian Schoenebeck tversion({ .client = v9p }); 3421125ddf6SChristian Schoenebeck tattach({ 3431125ddf6SChristian Schoenebeck .client = v9p, .fid = 0, .n_uname = getuid(), 3441125ddf6SChristian Schoenebeck .rattach.qid = &root_qid 3451125ddf6SChristian Schoenebeck }); 346a37c0702SGreg Kurz 3473f3e9232SChristian Schoenebeck twalk({ 348569f3b63SChristian Schoenebeck .client = v9p, .fid = 0, .newfid = 1, .nwname = 1, .wnames = wnames, 3493f3e9232SChristian Schoenebeck .rwalk.wqid = &wqid /* We now we'll get one qid */ 3503f3e9232SChristian Schoenebeck }); 351a37c0702SGreg Kurz 352a37c0702SGreg Kurz g_assert_cmpmem(&root_qid, 13, wqid[0], 13); 353a37c0702SGreg Kurz 354a37c0702SGreg Kurz g_free(wnames[0]); 355a37c0702SGreg Kurz } 356a37c0702SGreg Kurz 357dfbe8b43SEmanuele Giuseppe Esposito static void fs_lopen(void *obj, void *data, QGuestAllocator *t_alloc) 35882469aaeSGreg Kurz { 359dfbe8b43SEmanuele Giuseppe Esposito QVirtio9P *v9p = obj; 360684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 361569f3b63SChristian Schoenebeck char *wnames[] = { g_strdup(QTEST_V9FS_SYNTH_LOPEN_FILE) }; 36282469aaeSGreg Kurz 36374a160abSChristian Schoenebeck tattach({ .client = v9p }); 3643f3e9232SChristian Schoenebeck twalk({ 3653f3e9232SChristian Schoenebeck .client = v9p, .fid = 0, .newfid = 1, .nwname = 1, .wnames = wnames 3663f3e9232SChristian Schoenebeck }); 36782469aaeSGreg Kurz 3680e4c4ff0SChristian Schoenebeck tlopen({ .client = v9p, .fid = 1, .flags = O_WRONLY }); 36982469aaeSGreg Kurz 37082469aaeSGreg Kurz g_free(wnames[0]); 37182469aaeSGreg Kurz } 37282469aaeSGreg Kurz 373dfbe8b43SEmanuele Giuseppe Esposito static void fs_write(void *obj, void *data, QGuestAllocator *t_alloc) 374354b86f8SGreg Kurz { 375dfbe8b43SEmanuele Giuseppe Esposito QVirtio9P *v9p = obj; 376684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 377354b86f8SGreg Kurz static const uint32_t write_count = P9_MAX_SIZE / 2; 378569f3b63SChristian Schoenebeck char *wnames[] = { g_strdup(QTEST_V9FS_SYNTH_WRITE_FILE) }; 37965ceee0aSChristian Schoenebeck g_autofree char *buf = g_malloc0(write_count); 380354b86f8SGreg Kurz uint32_t count; 381354b86f8SGreg Kurz 38274a160abSChristian Schoenebeck tattach({ .client = v9p }); 3833f3e9232SChristian Schoenebeck twalk({ 3843f3e9232SChristian Schoenebeck .client = v9p, .fid = 0, .newfid = 1, .nwname = 1, .wnames = wnames 3853f3e9232SChristian Schoenebeck }); 386354b86f8SGreg Kurz 3870e4c4ff0SChristian Schoenebeck tlopen({ .client = v9p, .fid = 1, .flags = O_WRONLY }); 388354b86f8SGreg Kurz 389bb286ff8SChristian Schoenebeck count = twrite({ 390ac9e4e61SChristian Schoenebeck .client = v9p, .fid = 1, .offset = 0, .count = write_count, 391bb286ff8SChristian Schoenebeck .data = buf 392bb286ff8SChristian Schoenebeck }).count; 393354b86f8SGreg Kurz g_assert_cmpint(count, ==, write_count); 394354b86f8SGreg Kurz 395354b86f8SGreg Kurz g_free(wnames[0]); 396354b86f8SGreg Kurz } 397354b86f8SGreg Kurz 398dfbe8b43SEmanuele Giuseppe Esposito static void fs_flush_success(void *obj, void *data, QGuestAllocator *t_alloc) 399357e2f7fSGreg Kurz { 400dfbe8b43SEmanuele Giuseppe Esposito QVirtio9P *v9p = obj; 401684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 402569f3b63SChristian Schoenebeck char *wnames[] = { g_strdup(QTEST_V9FS_SYNTH_FLUSH_FILE) }; 403357e2f7fSGreg Kurz P9Req *req, *flush_req; 404357e2f7fSGreg Kurz uint32_t reply_len; 405357e2f7fSGreg Kurz uint8_t should_block; 406357e2f7fSGreg Kurz 40774a160abSChristian Schoenebeck tattach({ .client = v9p }); 4083f3e9232SChristian Schoenebeck twalk({ 4093f3e9232SChristian Schoenebeck .client = v9p, .fid = 0, .newfid = 1, .nwname = 1, .wnames = wnames 4103f3e9232SChristian Schoenebeck }); 411357e2f7fSGreg Kurz 4120e4c4ff0SChristian Schoenebeck tlopen({ .client = v9p, .fid = 1, .flags = O_WRONLY }); 413357e2f7fSGreg Kurz 414357e2f7fSGreg Kurz /* This will cause the 9p server to try to write data to the backend, 415357e2f7fSGreg Kurz * until the write request gets cancelled. 416357e2f7fSGreg Kurz */ 417357e2f7fSGreg Kurz should_block = 1; 418ac9e4e61SChristian Schoenebeck req = twrite({ 419ac9e4e61SChristian Schoenebeck .client = v9p, .fid = 1, .offset = 0, 420ac9e4e61SChristian Schoenebeck .count = sizeof(should_block), .data = &should_block, 421ac9e4e61SChristian Schoenebeck .requestOnly = true 422ac9e4e61SChristian Schoenebeck }).req; 423357e2f7fSGreg Kurz 424*d89146fdSChristian Schoenebeck flush_req = tflush({ 425*d89146fdSChristian Schoenebeck .client = v9p, .oldtag = req->tag, .tag = 1, .requestOnly = true 426*d89146fdSChristian Schoenebeck }).req; 427357e2f7fSGreg Kurz 428357e2f7fSGreg Kurz /* The write request is supposed to be flushed: the server should just 429357e2f7fSGreg Kurz * mark the write request as used and reply to the flush request. 430357e2f7fSGreg Kurz */ 431357e2f7fSGreg Kurz v9fs_req_wait_for_reply(req, &reply_len); 432357e2f7fSGreg Kurz g_assert_cmpint(reply_len, ==, 0); 433357e2f7fSGreg Kurz v9fs_req_free(req); 434357e2f7fSGreg Kurz v9fs_rflush(flush_req); 435357e2f7fSGreg Kurz 436357e2f7fSGreg Kurz g_free(wnames[0]); 437357e2f7fSGreg Kurz } 438357e2f7fSGreg Kurz 439dfbe8b43SEmanuele Giuseppe Esposito static void fs_flush_ignored(void *obj, void *data, QGuestAllocator *t_alloc) 440357e2f7fSGreg Kurz { 441dfbe8b43SEmanuele Giuseppe Esposito QVirtio9P *v9p = obj; 442684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 443569f3b63SChristian Schoenebeck char *wnames[] = { g_strdup(QTEST_V9FS_SYNTH_FLUSH_FILE) }; 444357e2f7fSGreg Kurz P9Req *req, *flush_req; 445357e2f7fSGreg Kurz uint32_t count; 446357e2f7fSGreg Kurz uint8_t should_block; 447357e2f7fSGreg Kurz 44874a160abSChristian Schoenebeck tattach({ .client = v9p }); 4493f3e9232SChristian Schoenebeck twalk({ 4503f3e9232SChristian Schoenebeck .client = v9p, .fid = 0, .newfid = 1, .nwname = 1, .wnames = wnames 4513f3e9232SChristian Schoenebeck }); 452357e2f7fSGreg Kurz 4530e4c4ff0SChristian Schoenebeck tlopen({ .client = v9p, .fid = 1, .flags = O_WRONLY }); 454357e2f7fSGreg Kurz 455357e2f7fSGreg Kurz /* This will cause the write request to complete right away, before it 456357e2f7fSGreg Kurz * could be actually cancelled. 457357e2f7fSGreg Kurz */ 458357e2f7fSGreg Kurz should_block = 0; 459ac9e4e61SChristian Schoenebeck req = twrite({ 460ac9e4e61SChristian Schoenebeck .client = v9p, .fid = 1, .offset = 0, 461ac9e4e61SChristian Schoenebeck .count = sizeof(should_block), .data = &should_block, 462ac9e4e61SChristian Schoenebeck .requestOnly = true 463ac9e4e61SChristian Schoenebeck }).req; 464357e2f7fSGreg Kurz 465*d89146fdSChristian Schoenebeck flush_req = tflush({ 466*d89146fdSChristian Schoenebeck .client = v9p, .oldtag = req->tag, .tag = 1, .requestOnly = true 467*d89146fdSChristian Schoenebeck }).req; 468357e2f7fSGreg Kurz 469357e2f7fSGreg Kurz /* The write request is supposed to complete. The server should 470357e2f7fSGreg Kurz * reply to the write request and the flush request. 471357e2f7fSGreg Kurz */ 472357e2f7fSGreg Kurz v9fs_req_wait_for_reply(req, NULL); 473357e2f7fSGreg Kurz v9fs_rwrite(req, &count); 474357e2f7fSGreg Kurz g_assert_cmpint(count, ==, sizeof(should_block)); 475357e2f7fSGreg Kurz v9fs_rflush(flush_req); 476357e2f7fSGreg Kurz 477357e2f7fSGreg Kurz g_free(wnames[0]); 478357e2f7fSGreg Kurz } 479357e2f7fSGreg Kurz 480c1934f63SGreg Kurz static void do_mkdir(QVirtio9P *v9p, const char *path, const char *cname) 481653daf38SChristian Schoenebeck { 48265ceee0aSChristian Schoenebeck g_autofree char *name = g_strdup(cname); 48320018805SChristian Schoenebeck uint32_t fid; 484653daf38SChristian Schoenebeck P9Req *req; 485653daf38SChristian Schoenebeck 486569f3b63SChristian Schoenebeck fid = twalk({ .client = v9p, .path = path }).newfid; 487653daf38SChristian Schoenebeck 488653daf38SChristian Schoenebeck req = v9fs_tmkdir(v9p, fid, name, 0750, 0, 0); 489653daf38SChristian Schoenebeck v9fs_req_wait_for_reply(req, NULL); 490653daf38SChristian Schoenebeck v9fs_rmkdir(req, NULL); 491653daf38SChristian Schoenebeck } 492653daf38SChristian Schoenebeck 493b09dbfddSChristian Schoenebeck /* create a regular file with Tlcreate and return file's fid */ 494b09dbfddSChristian Schoenebeck static uint32_t do_lcreate(QVirtio9P *v9p, const char *path, 495b09dbfddSChristian Schoenebeck const char *cname) 496b09dbfddSChristian Schoenebeck { 49765ceee0aSChristian Schoenebeck g_autofree char *name = g_strdup(cname); 498b09dbfddSChristian Schoenebeck uint32_t fid; 499b09dbfddSChristian Schoenebeck P9Req *req; 500b09dbfddSChristian Schoenebeck 501569f3b63SChristian Schoenebeck fid = twalk({ .client = v9p, .path = path }).newfid; 502b09dbfddSChristian Schoenebeck 503b09dbfddSChristian Schoenebeck req = v9fs_tlcreate(v9p, fid, name, 0, 0750, 0, 0); 504b09dbfddSChristian Schoenebeck v9fs_req_wait_for_reply(req, NULL); 505b09dbfddSChristian Schoenebeck v9fs_rlcreate(req, NULL, NULL); 506b09dbfddSChristian Schoenebeck 507b09dbfddSChristian Schoenebeck return fid; 508b09dbfddSChristian Schoenebeck } 509b09dbfddSChristian Schoenebeck 51059ff563dSChristian Schoenebeck /* create symlink named @a clink in directory @a path pointing to @a to */ 51159ff563dSChristian Schoenebeck static void do_symlink(QVirtio9P *v9p, const char *path, const char *clink, 51259ff563dSChristian Schoenebeck const char *to) 51359ff563dSChristian Schoenebeck { 51465ceee0aSChristian Schoenebeck g_autofree char *name = g_strdup(clink); 51565ceee0aSChristian Schoenebeck g_autofree char *dst = g_strdup(to); 51659ff563dSChristian Schoenebeck uint32_t fid; 51759ff563dSChristian Schoenebeck P9Req *req; 51859ff563dSChristian Schoenebeck 519569f3b63SChristian Schoenebeck fid = twalk({ .client = v9p, .path = path }).newfid; 52059ff563dSChristian Schoenebeck 52159ff563dSChristian Schoenebeck req = v9fs_tsymlink(v9p, fid, name, dst, 0, 0); 52259ff563dSChristian Schoenebeck v9fs_req_wait_for_reply(req, NULL); 52359ff563dSChristian Schoenebeck v9fs_rsymlink(req, NULL); 52459ff563dSChristian Schoenebeck } 52559ff563dSChristian Schoenebeck 52664e3d403SChristian Schoenebeck /* create a hard link named @a clink in directory @a path pointing to @a to */ 52764e3d403SChristian Schoenebeck static void do_hardlink(QVirtio9P *v9p, const char *path, const char *clink, 52864e3d403SChristian Schoenebeck const char *to) 52964e3d403SChristian Schoenebeck { 53064e3d403SChristian Schoenebeck uint32_t dfid, fid; 53164e3d403SChristian Schoenebeck P9Req *req; 53264e3d403SChristian Schoenebeck 533569f3b63SChristian Schoenebeck dfid = twalk({ .client = v9p, .path = path }).newfid; 534569f3b63SChristian Schoenebeck fid = twalk({ .client = v9p, .path = to }).newfid; 53564e3d403SChristian Schoenebeck 53664e3d403SChristian Schoenebeck req = v9fs_tlink(v9p, dfid, fid, clink, 0); 53764e3d403SChristian Schoenebeck v9fs_req_wait_for_reply(req, NULL); 53864e3d403SChristian Schoenebeck v9fs_rlink(req); 53964e3d403SChristian Schoenebeck } 54064e3d403SChristian Schoenebeck 541b37d62d6SChristian Schoenebeck static void do_unlinkat(QVirtio9P *v9p, const char *atpath, const char *rpath, 542b37d62d6SChristian Schoenebeck uint32_t flags) 543b37d62d6SChristian Schoenebeck { 54465ceee0aSChristian Schoenebeck g_autofree char *name = g_strdup(rpath); 545b37d62d6SChristian Schoenebeck uint32_t fid; 546b37d62d6SChristian Schoenebeck P9Req *req; 547b37d62d6SChristian Schoenebeck 548569f3b63SChristian Schoenebeck fid = twalk({ .client = v9p, .path = atpath }).newfid; 549b37d62d6SChristian Schoenebeck 550b37d62d6SChristian Schoenebeck req = v9fs_tunlinkat(v9p, fid, name, flags, 0); 551b37d62d6SChristian Schoenebeck v9fs_req_wait_for_reply(req, NULL); 552b37d62d6SChristian Schoenebeck v9fs_runlinkat(req); 553b37d62d6SChristian Schoenebeck } 554b37d62d6SChristian Schoenebeck 55546488b62SChristian Schoenebeck static void fs_readdir_split_128(void *obj, void *data, 55646488b62SChristian Schoenebeck QGuestAllocator *t_alloc) 55746488b62SChristian Schoenebeck { 558684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 5591d98613dSGreg Kurz do_readdir_split(obj, 128); 56046488b62SChristian Schoenebeck } 56146488b62SChristian Schoenebeck 56246488b62SChristian Schoenebeck static void fs_readdir_split_256(void *obj, void *data, 56346488b62SChristian Schoenebeck QGuestAllocator *t_alloc) 56446488b62SChristian Schoenebeck { 565684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 5661d98613dSGreg Kurz do_readdir_split(obj, 256); 56746488b62SChristian Schoenebeck } 56846488b62SChristian Schoenebeck 56946488b62SChristian Schoenebeck static void fs_readdir_split_512(void *obj, void *data, 57046488b62SChristian Schoenebeck QGuestAllocator *t_alloc) 57146488b62SChristian Schoenebeck { 572684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 5731d98613dSGreg Kurz do_readdir_split(obj, 512); 57446488b62SChristian Schoenebeck } 57546488b62SChristian Schoenebeck 576653daf38SChristian Schoenebeck 577653daf38SChristian Schoenebeck /* tests using the 9pfs 'local' fs driver */ 578653daf38SChristian Schoenebeck 579653daf38SChristian Schoenebeck static void fs_create_dir(void *obj, void *data, QGuestAllocator *t_alloc) 580653daf38SChristian Schoenebeck { 581653daf38SChristian Schoenebeck QVirtio9P *v9p = obj; 582684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 583653daf38SChristian Schoenebeck struct stat st; 58465ceee0aSChristian Schoenebeck g_autofree char *root_path = virtio_9p_test_path(""); 58565ceee0aSChristian Schoenebeck g_autofree char *new_dir = virtio_9p_test_path("01"); 586653daf38SChristian Schoenebeck 587653daf38SChristian Schoenebeck g_assert(root_path != NULL); 588653daf38SChristian Schoenebeck 58974a160abSChristian Schoenebeck tattach({ .client = v9p }); 590c1934f63SGreg Kurz do_mkdir(v9p, "/", "01"); 591653daf38SChristian Schoenebeck 592653daf38SChristian Schoenebeck /* check if created directory really exists now ... */ 593653daf38SChristian Schoenebeck g_assert(stat(new_dir, &st) == 0); 594653daf38SChristian Schoenebeck /* ... and is actually a directory */ 595653daf38SChristian Schoenebeck g_assert((st.st_mode & S_IFMT) == S_IFDIR); 596653daf38SChristian Schoenebeck } 597653daf38SChristian Schoenebeck 598b37d62d6SChristian Schoenebeck static void fs_unlinkat_dir(void *obj, void *data, QGuestAllocator *t_alloc) 599b37d62d6SChristian Schoenebeck { 600b37d62d6SChristian Schoenebeck QVirtio9P *v9p = obj; 601684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 602b37d62d6SChristian Schoenebeck struct stat st; 60365ceee0aSChristian Schoenebeck g_autofree char *root_path = virtio_9p_test_path(""); 60465ceee0aSChristian Schoenebeck g_autofree char *new_dir = virtio_9p_test_path("02"); 605b37d62d6SChristian Schoenebeck 606b37d62d6SChristian Schoenebeck g_assert(root_path != NULL); 607b37d62d6SChristian Schoenebeck 60874a160abSChristian Schoenebeck tattach({ .client = v9p }); 609b37d62d6SChristian Schoenebeck do_mkdir(v9p, "/", "02"); 610b37d62d6SChristian Schoenebeck 611b37d62d6SChristian Schoenebeck /* check if created directory really exists now ... */ 612b37d62d6SChristian Schoenebeck g_assert(stat(new_dir, &st) == 0); 613b37d62d6SChristian Schoenebeck /* ... and is actually a directory */ 614b37d62d6SChristian Schoenebeck g_assert((st.st_mode & S_IFMT) == S_IFDIR); 615b37d62d6SChristian Schoenebeck 616d3671fd9SWill Cohen do_unlinkat(v9p, "/", "02", P9_DOTL_AT_REMOVEDIR); 617b37d62d6SChristian Schoenebeck /* directory should be gone now */ 618b37d62d6SChristian Schoenebeck g_assert(stat(new_dir, &st) != 0); 619b37d62d6SChristian Schoenebeck } 620b37d62d6SChristian Schoenebeck 621b09dbfddSChristian Schoenebeck static void fs_create_file(void *obj, void *data, QGuestAllocator *t_alloc) 622b09dbfddSChristian Schoenebeck { 623b09dbfddSChristian Schoenebeck QVirtio9P *v9p = obj; 624684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 625b09dbfddSChristian Schoenebeck struct stat st; 62665ceee0aSChristian Schoenebeck g_autofree char *new_file = virtio_9p_test_path("03/1st_file"); 627b09dbfddSChristian Schoenebeck 62874a160abSChristian Schoenebeck tattach({ .client = v9p }); 629b09dbfddSChristian Schoenebeck do_mkdir(v9p, "/", "03"); 630b09dbfddSChristian Schoenebeck do_lcreate(v9p, "03", "1st_file"); 631b09dbfddSChristian Schoenebeck 632b09dbfddSChristian Schoenebeck /* check if created file exists now ... */ 633b09dbfddSChristian Schoenebeck g_assert(stat(new_file, &st) == 0); 634b09dbfddSChristian Schoenebeck /* ... and is a regular file */ 635b09dbfddSChristian Schoenebeck g_assert((st.st_mode & S_IFMT) == S_IFREG); 636b09dbfddSChristian Schoenebeck } 637b09dbfddSChristian Schoenebeck 638472c18b8SChristian Schoenebeck static void fs_unlinkat_file(void *obj, void *data, QGuestAllocator *t_alloc) 639472c18b8SChristian Schoenebeck { 640472c18b8SChristian Schoenebeck QVirtio9P *v9p = obj; 641684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 642472c18b8SChristian Schoenebeck struct stat st; 64365ceee0aSChristian Schoenebeck g_autofree char *new_file = virtio_9p_test_path("04/doa_file"); 644472c18b8SChristian Schoenebeck 64574a160abSChristian Schoenebeck tattach({ .client = v9p }); 646472c18b8SChristian Schoenebeck do_mkdir(v9p, "/", "04"); 647472c18b8SChristian Schoenebeck do_lcreate(v9p, "04", "doa_file"); 648472c18b8SChristian Schoenebeck 649472c18b8SChristian Schoenebeck /* check if created file exists now ... */ 650472c18b8SChristian Schoenebeck g_assert(stat(new_file, &st) == 0); 651472c18b8SChristian Schoenebeck /* ... and is a regular file */ 652472c18b8SChristian Schoenebeck g_assert((st.st_mode & S_IFMT) == S_IFREG); 653472c18b8SChristian Schoenebeck 654472c18b8SChristian Schoenebeck do_unlinkat(v9p, "04", "doa_file", 0); 655472c18b8SChristian Schoenebeck /* file should be gone now */ 656472c18b8SChristian Schoenebeck g_assert(stat(new_file, &st) != 0); 657472c18b8SChristian Schoenebeck } 658472c18b8SChristian Schoenebeck 65959ff563dSChristian Schoenebeck static void fs_symlink_file(void *obj, void *data, QGuestAllocator *t_alloc) 66059ff563dSChristian Schoenebeck { 66159ff563dSChristian Schoenebeck QVirtio9P *v9p = obj; 662684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 66359ff563dSChristian Schoenebeck struct stat st; 66465ceee0aSChristian Schoenebeck g_autofree char *real_file = virtio_9p_test_path("05/real_file"); 66565ceee0aSChristian Schoenebeck g_autofree char *symlink_file = virtio_9p_test_path("05/symlink_file"); 66659ff563dSChristian Schoenebeck 66774a160abSChristian Schoenebeck tattach({ .client = v9p }); 66859ff563dSChristian Schoenebeck do_mkdir(v9p, "/", "05"); 66959ff563dSChristian Schoenebeck do_lcreate(v9p, "05", "real_file"); 67059ff563dSChristian Schoenebeck g_assert(stat(real_file, &st) == 0); 67159ff563dSChristian Schoenebeck g_assert((st.st_mode & S_IFMT) == S_IFREG); 67259ff563dSChristian Schoenebeck 67359ff563dSChristian Schoenebeck do_symlink(v9p, "05", "symlink_file", "real_file"); 67459ff563dSChristian Schoenebeck 67559ff563dSChristian Schoenebeck /* check if created link exists now */ 67659ff563dSChristian Schoenebeck g_assert(stat(symlink_file, &st) == 0); 67759ff563dSChristian Schoenebeck } 67859ff563dSChristian Schoenebeck 6795b28ab8bSChristian Schoenebeck static void fs_unlinkat_symlink(void *obj, void *data, 6805b28ab8bSChristian Schoenebeck QGuestAllocator *t_alloc) 6815b28ab8bSChristian Schoenebeck { 6825b28ab8bSChristian Schoenebeck QVirtio9P *v9p = obj; 683684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 6845b28ab8bSChristian Schoenebeck struct stat st; 68565ceee0aSChristian Schoenebeck g_autofree char *real_file = virtio_9p_test_path("06/real_file"); 68665ceee0aSChristian Schoenebeck g_autofree char *symlink_file = virtio_9p_test_path("06/symlink_file"); 6875b28ab8bSChristian Schoenebeck 68874a160abSChristian Schoenebeck tattach({ .client = v9p }); 6895b28ab8bSChristian Schoenebeck do_mkdir(v9p, "/", "06"); 6905b28ab8bSChristian Schoenebeck do_lcreate(v9p, "06", "real_file"); 6915b28ab8bSChristian Schoenebeck g_assert(stat(real_file, &st) == 0); 6925b28ab8bSChristian Schoenebeck g_assert((st.st_mode & S_IFMT) == S_IFREG); 6935b28ab8bSChristian Schoenebeck 6945b28ab8bSChristian Schoenebeck do_symlink(v9p, "06", "symlink_file", "real_file"); 6955b28ab8bSChristian Schoenebeck g_assert(stat(symlink_file, &st) == 0); 6965b28ab8bSChristian Schoenebeck 6975b28ab8bSChristian Schoenebeck do_unlinkat(v9p, "06", "symlink_file", 0); 6985b28ab8bSChristian Schoenebeck /* symlink should be gone now */ 6995b28ab8bSChristian Schoenebeck g_assert(stat(symlink_file, &st) != 0); 7005b28ab8bSChristian Schoenebeck } 7015b28ab8bSChristian Schoenebeck 70264e3d403SChristian Schoenebeck static void fs_hardlink_file(void *obj, void *data, QGuestAllocator *t_alloc) 70364e3d403SChristian Schoenebeck { 70464e3d403SChristian Schoenebeck QVirtio9P *v9p = obj; 705684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 70664e3d403SChristian Schoenebeck struct stat st_real, st_link; 70765ceee0aSChristian Schoenebeck g_autofree char *real_file = virtio_9p_test_path("07/real_file"); 70865ceee0aSChristian Schoenebeck g_autofree char *hardlink_file = virtio_9p_test_path("07/hardlink_file"); 70964e3d403SChristian Schoenebeck 71074a160abSChristian Schoenebeck tattach({ .client = v9p }); 71164e3d403SChristian Schoenebeck do_mkdir(v9p, "/", "07"); 71264e3d403SChristian Schoenebeck do_lcreate(v9p, "07", "real_file"); 71364e3d403SChristian Schoenebeck g_assert(stat(real_file, &st_real) == 0); 71464e3d403SChristian Schoenebeck g_assert((st_real.st_mode & S_IFMT) == S_IFREG); 71564e3d403SChristian Schoenebeck 71664e3d403SChristian Schoenebeck do_hardlink(v9p, "07", "hardlink_file", "07/real_file"); 71764e3d403SChristian Schoenebeck 71864e3d403SChristian Schoenebeck /* check if link exists now ... */ 71964e3d403SChristian Schoenebeck g_assert(stat(hardlink_file, &st_link) == 0); 72064e3d403SChristian Schoenebeck /* ... and it's a hard link, right? */ 72164e3d403SChristian Schoenebeck g_assert((st_link.st_mode & S_IFMT) == S_IFREG); 72264e3d403SChristian Schoenebeck g_assert(st_link.st_dev == st_real.st_dev); 72364e3d403SChristian Schoenebeck g_assert(st_link.st_ino == st_real.st_ino); 72464e3d403SChristian Schoenebeck } 72564e3d403SChristian Schoenebeck 7264d0746e2SChristian Schoenebeck static void fs_unlinkat_hardlink(void *obj, void *data, 7274d0746e2SChristian Schoenebeck QGuestAllocator *t_alloc) 7284d0746e2SChristian Schoenebeck { 7294d0746e2SChristian Schoenebeck QVirtio9P *v9p = obj; 730684f9120SChristian Schoenebeck v9fs_set_allocator(t_alloc); 7314d0746e2SChristian Schoenebeck struct stat st_real, st_link; 73265ceee0aSChristian Schoenebeck g_autofree char *real_file = virtio_9p_test_path("08/real_file"); 73365ceee0aSChristian Schoenebeck g_autofree char *hardlink_file = virtio_9p_test_path("08/hardlink_file"); 7344d0746e2SChristian Schoenebeck 73574a160abSChristian Schoenebeck tattach({ .client = v9p }); 7364d0746e2SChristian Schoenebeck do_mkdir(v9p, "/", "08"); 7374d0746e2SChristian Schoenebeck do_lcreate(v9p, "08", "real_file"); 7384d0746e2SChristian Schoenebeck g_assert(stat(real_file, &st_real) == 0); 7394d0746e2SChristian Schoenebeck g_assert((st_real.st_mode & S_IFMT) == S_IFREG); 7404d0746e2SChristian Schoenebeck 7414d0746e2SChristian Schoenebeck do_hardlink(v9p, "08", "hardlink_file", "08/real_file"); 7424d0746e2SChristian Schoenebeck g_assert(stat(hardlink_file, &st_link) == 0); 7434d0746e2SChristian Schoenebeck 7444d0746e2SChristian Schoenebeck do_unlinkat(v9p, "08", "hardlink_file", 0); 7454d0746e2SChristian Schoenebeck /* symlink should be gone now */ 7464d0746e2SChristian Schoenebeck g_assert(stat(hardlink_file, &st_link) != 0); 7474d0746e2SChristian Schoenebeck /* and old file should still exist */ 7484d0746e2SChristian Schoenebeck g_assert(stat(real_file, &st_real) == 0); 7494d0746e2SChristian Schoenebeck } 7504d0746e2SChristian Schoenebeck 7513a565c64SChristian Schoenebeck static void *assign_9p_local_driver(GString *cmd_line, void *arg) 7523a565c64SChristian Schoenebeck { 7533a565c64SChristian Schoenebeck virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr"); 7543a565c64SChristian Schoenebeck return arg; 7553a565c64SChristian Schoenebeck } 7563a565c64SChristian Schoenebeck 757dfbe8b43SEmanuele Giuseppe Esposito static void register_virtio_9p_test(void) 7581211d81bSGreg Kurz { 7593a565c64SChristian Schoenebeck 7603a565c64SChristian Schoenebeck QOSGraphTestOptions opts = { 7613a565c64SChristian Schoenebeck }; 7623a565c64SChristian Schoenebeck 7633a565c64SChristian Schoenebeck /* 9pfs test cases using the 'synth' filesystem driver */ 7643a565c64SChristian Schoenebeck qos_add_test("synth/config", "virtio-9p", pci_config, &opts); 7653a565c64SChristian Schoenebeck qos_add_test("synth/version/basic", "virtio-9p", fs_version, &opts); 7663a565c64SChristian Schoenebeck qos_add_test("synth/attach/basic", "virtio-9p", fs_attach, &opts); 7673a565c64SChristian Schoenebeck qos_add_test("synth/walk/basic", "virtio-9p", fs_walk, &opts); 768eefd2394SChristian Schoenebeck qos_add_test("synth/walk/no_slash", "virtio-9p", fs_walk_no_slash, 7693a565c64SChristian Schoenebeck &opts); 770c1668948SChristian Schoenebeck qos_add_test("synth/walk/none", "virtio-9p", fs_walk_none, &opts); 771eefd2394SChristian Schoenebeck qos_add_test("synth/walk/dotdot_from_root", "virtio-9p", 7723a565c64SChristian Schoenebeck fs_walk_dotdot, &opts); 7739472a689SChristian Schoenebeck qos_add_test("synth/walk/non_existent", "virtio-9p", fs_walk_nonexistent, 7749472a689SChristian Schoenebeck &opts); 77515fbff48SChristian Schoenebeck qos_add_test("synth/walk/2nd_non_existent", "virtio-9p", 77615fbff48SChristian Schoenebeck fs_walk_2nd_nonexistent, &opts); 7773a565c64SChristian Schoenebeck qos_add_test("synth/lopen/basic", "virtio-9p", fs_lopen, &opts); 7783a565c64SChristian Schoenebeck qos_add_test("synth/write/basic", "virtio-9p", fs_write, &opts); 779eefd2394SChristian Schoenebeck qos_add_test("synth/flush/success", "virtio-9p", fs_flush_success, 7803a565c64SChristian Schoenebeck &opts); 781eefd2394SChristian Schoenebeck qos_add_test("synth/flush/ignored", "virtio-9p", fs_flush_ignored, 7823a565c64SChristian Schoenebeck &opts); 7833a565c64SChristian Schoenebeck qos_add_test("synth/readdir/basic", "virtio-9p", fs_readdir, &opts); 784eefd2394SChristian Schoenebeck qos_add_test("synth/readdir/split_512", "virtio-9p", 7853a565c64SChristian Schoenebeck fs_readdir_split_512, &opts); 786eefd2394SChristian Schoenebeck qos_add_test("synth/readdir/split_256", "virtio-9p", 7873a565c64SChristian Schoenebeck fs_readdir_split_256, &opts); 788eefd2394SChristian Schoenebeck qos_add_test("synth/readdir/split_128", "virtio-9p", 7893a565c64SChristian Schoenebeck fs_readdir_split_128, &opts); 7903a565c64SChristian Schoenebeck 7913a565c64SChristian Schoenebeck 7923a565c64SChristian Schoenebeck /* 9pfs test cases using the 'local' filesystem driver */ 793558f5c42SGreg Kurz 794558f5c42SGreg Kurz /* 795558f5c42SGreg Kurz * XXX: Until we are sure that these tests can run everywhere, 796558f5c42SGreg Kurz * keep them as "slow" so that they aren't run with "make check". 797558f5c42SGreg Kurz */ 798558f5c42SGreg Kurz if (!g_test_slow()) { 799558f5c42SGreg Kurz return; 800558f5c42SGreg Kurz } 801558f5c42SGreg Kurz 8023a565c64SChristian Schoenebeck opts.before = assign_9p_local_driver; 8033a565c64SChristian Schoenebeck qos_add_test("local/config", "virtio-9p", pci_config, &opts); 804653daf38SChristian Schoenebeck qos_add_test("local/create_dir", "virtio-9p", fs_create_dir, &opts); 805b37d62d6SChristian Schoenebeck qos_add_test("local/unlinkat_dir", "virtio-9p", fs_unlinkat_dir, &opts); 806b09dbfddSChristian Schoenebeck qos_add_test("local/create_file", "virtio-9p", fs_create_file, &opts); 807472c18b8SChristian Schoenebeck qos_add_test("local/unlinkat_file", "virtio-9p", fs_unlinkat_file, &opts); 80859ff563dSChristian Schoenebeck qos_add_test("local/symlink_file", "virtio-9p", fs_symlink_file, &opts); 8095b28ab8bSChristian Schoenebeck qos_add_test("local/unlinkat_symlink", "virtio-9p", fs_unlinkat_symlink, 8105b28ab8bSChristian Schoenebeck &opts); 81164e3d403SChristian Schoenebeck qos_add_test("local/hardlink_file", "virtio-9p", fs_hardlink_file, &opts); 8124d0746e2SChristian Schoenebeck qos_add_test("local/unlinkat_hardlink", "virtio-9p", fs_unlinkat_hardlink, 8134d0746e2SChristian Schoenebeck &opts); 8141211d81bSGreg Kurz } 8151211d81bSGreg Kurz 816dfbe8b43SEmanuele Giuseppe Esposito libqos_init(register_virtio_9p_test); 817136b7af2SChristian Schoenebeck 818136b7af2SChristian Schoenebeck static void __attribute__((constructor)) construct_9p_test(void) 819136b7af2SChristian Schoenebeck { 820136b7af2SChristian Schoenebeck /* make sure test dir for the 'local' tests exists */ 821136b7af2SChristian Schoenebeck virtio_9p_create_local_test_dir(); 822136b7af2SChristian Schoenebeck } 823136b7af2SChristian Schoenebeck 824136b7af2SChristian Schoenebeck static void __attribute__((destructor)) destruct_9p_test(void) 825136b7af2SChristian Schoenebeck { 826136b7af2SChristian Schoenebeck /* remove previously created test dir when test suite completed */ 827136b7af2SChristian Schoenebeck virtio_9p_remove_local_test_dir(); 828136b7af2SChristian Schoenebeck } 829