13ef7ff83SDavid Woodhouse /* 23ef7ff83SDavid Woodhouse * QEMU XenStore XsNode testing 33ef7ff83SDavid Woodhouse * 43ef7ff83SDavid Woodhouse * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. 53ef7ff83SDavid Woodhouse 63ef7ff83SDavid Woodhouse * This work is licensed under the terms of the GNU GPL, version 2 or later. 73ef7ff83SDavid Woodhouse * See the COPYING file in the top-level directory. 83ef7ff83SDavid Woodhouse */ 93ef7ff83SDavid Woodhouse 103ef7ff83SDavid Woodhouse #include "qemu/osdep.h" 113ef7ff83SDavid Woodhouse #include "qapi/error.h" 123ef7ff83SDavid Woodhouse #include "qemu/module.h" 133ef7ff83SDavid Woodhouse 143ef7ff83SDavid Woodhouse static int nr_xs_nodes; 153ef7ff83SDavid Woodhouse static GList *xs_node_list; 163ef7ff83SDavid Woodhouse 173ef7ff83SDavid Woodhouse #define XS_NODE_UNIT_TEST 183ef7ff83SDavid Woodhouse 193ef7ff83SDavid Woodhouse /* 203ef7ff83SDavid Woodhouse * We don't need the core Xen definitions. And we *do* want to be able 213ef7ff83SDavid Woodhouse * to run the unit tests even on architectures that Xen doesn't support 223ef7ff83SDavid Woodhouse * (because life's too short to bother doing otherwise, and test coverage 233ef7ff83SDavid Woodhouse * doesn't hurt). 243ef7ff83SDavid Woodhouse */ 253ef7ff83SDavid Woodhouse #define __XEN_PUBLIC_XEN_H__ 26*15e283c5SDavid Woodhouse typedef unsigned long xen_pfn_t; 273ef7ff83SDavid Woodhouse 283ef7ff83SDavid Woodhouse #include "hw/i386/kvm/xenstore_impl.c" 293ef7ff83SDavid Woodhouse 303ef7ff83SDavid Woodhouse #define DOMID_QEMU 0 313ef7ff83SDavid Woodhouse #define DOMID_GUEST 1 323ef7ff83SDavid Woodhouse 33766804b1SDavid Woodhouse static void dump_ref(const char *name, XsNode *n, int indent) 34766804b1SDavid Woodhouse { 35766804b1SDavid Woodhouse int i; 36766804b1SDavid Woodhouse 37766804b1SDavid Woodhouse if (!indent && name) { 38766804b1SDavid Woodhouse printf("%s:\n", name); 39766804b1SDavid Woodhouse } 40766804b1SDavid Woodhouse 41766804b1SDavid Woodhouse for (i = 0; i < indent; i++) { 42766804b1SDavid Woodhouse printf(" "); 43766804b1SDavid Woodhouse } 44766804b1SDavid Woodhouse 45766804b1SDavid Woodhouse printf("->%p(%d, '%s'): '%.*s'%s%s\n", n, n->ref, n->name, 46766804b1SDavid Woodhouse (int)(n->content ? n->content->len : strlen("<empty>")), 47766804b1SDavid Woodhouse n->content ? (char *)n->content->data : "<empty>", 48766804b1SDavid Woodhouse n->modified_in_tx ? " MODIFIED" : "", 49766804b1SDavid Woodhouse n->deleted_in_tx ? " DELETED" : ""); 50766804b1SDavid Woodhouse 51766804b1SDavid Woodhouse if (n->children) { 52766804b1SDavid Woodhouse g_hash_table_foreach(n->children, (void *)dump_ref, 53766804b1SDavid Woodhouse GINT_TO_POINTER(indent + 2)); 54766804b1SDavid Woodhouse } 55766804b1SDavid Woodhouse } 56766804b1SDavid Woodhouse 573ef7ff83SDavid Woodhouse /* This doesn't happen in qemu but we want to make valgrind happy */ 58766804b1SDavid Woodhouse static void xs_impl_delete(XenstoreImplState *s, bool last) 593ef7ff83SDavid Woodhouse { 603ef7ff83SDavid Woodhouse int err; 613ef7ff83SDavid Woodhouse 626e133009SDavid Woodhouse xs_impl_reset_watches(s, DOMID_GUEST); 636e133009SDavid Woodhouse g_assert(!s->nr_domu_watches); 646e133009SDavid Woodhouse 653ef7ff83SDavid Woodhouse err = xs_impl_rm(s, DOMID_QEMU, XBT_NULL, "/local"); 663ef7ff83SDavid Woodhouse g_assert(!err); 673ef7ff83SDavid Woodhouse g_assert(s->nr_nodes == 1); 683ef7ff83SDavid Woodhouse 696e133009SDavid Woodhouse g_hash_table_unref(s->watches); 707248b87cSDavid Woodhouse g_hash_table_unref(s->transactions); 713ef7ff83SDavid Woodhouse xs_node_unref(s->root); 723ef7ff83SDavid Woodhouse g_free(s); 733ef7ff83SDavid Woodhouse 74766804b1SDavid Woodhouse if (!last) { 75766804b1SDavid Woodhouse return; 76766804b1SDavid Woodhouse } 77766804b1SDavid Woodhouse 783ef7ff83SDavid Woodhouse if (xs_node_list) { 793ef7ff83SDavid Woodhouse GList *l; 803ef7ff83SDavid Woodhouse for (l = xs_node_list; l; l = l->next) { 813ef7ff83SDavid Woodhouse XsNode *n = l->data; 823ef7ff83SDavid Woodhouse printf("Remaining node at %p name %s ref %u\n", n, n->name, 833ef7ff83SDavid Woodhouse n->ref); 843ef7ff83SDavid Woodhouse } 853ef7ff83SDavid Woodhouse } 863ef7ff83SDavid Woodhouse g_assert(!nr_xs_nodes); 873ef7ff83SDavid Woodhouse } 883ef7ff83SDavid Woodhouse 89766804b1SDavid Woodhouse struct compare_walk { 90766804b1SDavid Woodhouse char path[XENSTORE_ABS_PATH_MAX + 1]; 91766804b1SDavid Woodhouse XsNode *parent_2; 92766804b1SDavid Woodhouse bool compare_ok; 93766804b1SDavid Woodhouse }; 94766804b1SDavid Woodhouse 95766804b1SDavid Woodhouse 96766804b1SDavid Woodhouse static bool compare_perms(GList *p1, GList *p2) 97766804b1SDavid Woodhouse { 98766804b1SDavid Woodhouse while (p1) { 99766804b1SDavid Woodhouse if (!p2 || g_strcmp0(p1->data, p2->data)) { 100766804b1SDavid Woodhouse return false; 101766804b1SDavid Woodhouse } 102766804b1SDavid Woodhouse p1 = p1->next; 103766804b1SDavid Woodhouse p2 = p2->next; 104766804b1SDavid Woodhouse } 105766804b1SDavid Woodhouse return (p2 == NULL); 106766804b1SDavid Woodhouse } 107766804b1SDavid Woodhouse 108766804b1SDavid Woodhouse static bool compare_content(GByteArray *c1, GByteArray *c2) 109766804b1SDavid Woodhouse { 110766804b1SDavid Woodhouse size_t len1 = 0, len2 = 0; 111766804b1SDavid Woodhouse 112766804b1SDavid Woodhouse if (c1) { 113766804b1SDavid Woodhouse len1 = c1->len; 114766804b1SDavid Woodhouse } 115766804b1SDavid Woodhouse if (c2) { 116766804b1SDavid Woodhouse len2 = c2->len; 117766804b1SDavid Woodhouse } 118766804b1SDavid Woodhouse if (len1 != len2) { 119766804b1SDavid Woodhouse return false; 120766804b1SDavid Woodhouse } 121766804b1SDavid Woodhouse 122766804b1SDavid Woodhouse if (!len1) { 123766804b1SDavid Woodhouse return true; 124766804b1SDavid Woodhouse } 125766804b1SDavid Woodhouse 126766804b1SDavid Woodhouse return !memcmp(c1->data, c2->data, len1); 127766804b1SDavid Woodhouse } 128766804b1SDavid Woodhouse 129766804b1SDavid Woodhouse static void compare_child(gpointer, gpointer, gpointer); 130766804b1SDavid Woodhouse 131766804b1SDavid Woodhouse static void compare_nodes(struct compare_walk *cw, XsNode *n1, XsNode *n2) 132766804b1SDavid Woodhouse { 133766804b1SDavid Woodhouse int nr_children1 = 0, nr_children2 = 0; 134766804b1SDavid Woodhouse 135766804b1SDavid Woodhouse if (n1->children) { 136766804b1SDavid Woodhouse nr_children1 = g_hash_table_size(n1->children); 137766804b1SDavid Woodhouse } 138766804b1SDavid Woodhouse if (n2->children) { 139766804b1SDavid Woodhouse nr_children2 = g_hash_table_size(n2->children); 140766804b1SDavid Woodhouse } 141766804b1SDavid Woodhouse 142766804b1SDavid Woodhouse if (n1->ref != n2->ref || 143766804b1SDavid Woodhouse n1->deleted_in_tx != n2->deleted_in_tx || 144766804b1SDavid Woodhouse n1->modified_in_tx != n2->modified_in_tx || 145766804b1SDavid Woodhouse !compare_perms(n1->perms, n2->perms) || 146766804b1SDavid Woodhouse !compare_content(n1->content, n2->content) || 147766804b1SDavid Woodhouse nr_children1 != nr_children2) { 148766804b1SDavid Woodhouse cw->compare_ok = false; 149766804b1SDavid Woodhouse printf("Compare failure on '%s'\n", cw->path); 150766804b1SDavid Woodhouse } 151766804b1SDavid Woodhouse 152766804b1SDavid Woodhouse if (nr_children1) { 153766804b1SDavid Woodhouse XsNode *oldparent = cw->parent_2; 154766804b1SDavid Woodhouse cw->parent_2 = n2; 155766804b1SDavid Woodhouse g_hash_table_foreach(n1->children, compare_child, cw); 156766804b1SDavid Woodhouse 157766804b1SDavid Woodhouse cw->parent_2 = oldparent; 158766804b1SDavid Woodhouse } 159766804b1SDavid Woodhouse } 160766804b1SDavid Woodhouse 161766804b1SDavid Woodhouse static void compare_child(gpointer key, gpointer val, gpointer opaque) 162766804b1SDavid Woodhouse { 163766804b1SDavid Woodhouse struct compare_walk *cw = opaque; 164766804b1SDavid Woodhouse char *childname = key; 165766804b1SDavid Woodhouse XsNode *child1 = val; 166766804b1SDavid Woodhouse XsNode *child2 = g_hash_table_lookup(cw->parent_2->children, childname); 167766804b1SDavid Woodhouse int pathlen = strlen(cw->path); 168766804b1SDavid Woodhouse 169766804b1SDavid Woodhouse if (!child2) { 170766804b1SDavid Woodhouse cw->compare_ok = false; 171766804b1SDavid Woodhouse printf("Child '%s' does not exist under '%s'\n", childname, cw->path); 172766804b1SDavid Woodhouse return; 173766804b1SDavid Woodhouse } 174766804b1SDavid Woodhouse 175766804b1SDavid Woodhouse strncat(cw->path, "/", sizeof(cw->path) - 1); 176766804b1SDavid Woodhouse strncat(cw->path, childname, sizeof(cw->path) - 1); 177766804b1SDavid Woodhouse 178766804b1SDavid Woodhouse compare_nodes(cw, child1, child2); 179766804b1SDavid Woodhouse cw->path[pathlen] = '\0'; 180766804b1SDavid Woodhouse } 181766804b1SDavid Woodhouse 182766804b1SDavid Woodhouse static bool compare_trees(XsNode *n1, XsNode *n2) 183766804b1SDavid Woodhouse { 184766804b1SDavid Woodhouse struct compare_walk cw; 185766804b1SDavid Woodhouse 186766804b1SDavid Woodhouse cw.path[0] = '\0'; 187766804b1SDavid Woodhouse cw.parent_2 = n2; 188766804b1SDavid Woodhouse cw.compare_ok = true; 189766804b1SDavid Woodhouse 190766804b1SDavid Woodhouse if (!n1 || !n2) { 191766804b1SDavid Woodhouse return false; 192766804b1SDavid Woodhouse } 193766804b1SDavid Woodhouse 194766804b1SDavid Woodhouse compare_nodes(&cw, n1, n2); 195766804b1SDavid Woodhouse return cw.compare_ok; 196766804b1SDavid Woodhouse } 197766804b1SDavid Woodhouse 198766804b1SDavid Woodhouse static void compare_tx(gpointer key, gpointer val, gpointer opaque) 199766804b1SDavid Woodhouse { 200766804b1SDavid Woodhouse XenstoreImplState *s2 = opaque; 201766804b1SDavid Woodhouse XsTransaction *t1 = val, *t2; 202766804b1SDavid Woodhouse unsigned int tx_id = GPOINTER_TO_INT(key); 203766804b1SDavid Woodhouse 204766804b1SDavid Woodhouse t2 = g_hash_table_lookup(s2->transactions, key); 205766804b1SDavid Woodhouse g_assert(t2); 206766804b1SDavid Woodhouse 207766804b1SDavid Woodhouse g_assert(t1->tx_id == tx_id); 208766804b1SDavid Woodhouse g_assert(t2->tx_id == tx_id); 209766804b1SDavid Woodhouse g_assert(t1->base_tx == t2->base_tx); 210766804b1SDavid Woodhouse g_assert(t1->dom_id == t2->dom_id); 211766804b1SDavid Woodhouse if (!compare_trees(t1->root, t2->root)) { 212766804b1SDavid Woodhouse printf("Comparison failure in TX %u after serdes:\n", tx_id); 213766804b1SDavid Woodhouse dump_ref("Original", t1->root, 0); 214766804b1SDavid Woodhouse dump_ref("Deserialised", t2->root, 0); 215766804b1SDavid Woodhouse g_assert(0); 216766804b1SDavid Woodhouse } 217766804b1SDavid Woodhouse g_assert(t1->nr_nodes == t2->nr_nodes); 218766804b1SDavid Woodhouse } 219766804b1SDavid Woodhouse 2203ef7ff83SDavid Woodhouse static int write_str(XenstoreImplState *s, unsigned int dom_id, 2213ef7ff83SDavid Woodhouse unsigned int tx_id, const char *path, 2223ef7ff83SDavid Woodhouse const char *content) 2233ef7ff83SDavid Woodhouse { 2243ef7ff83SDavid Woodhouse GByteArray *d = g_byte_array_new(); 2253ef7ff83SDavid Woodhouse int err; 2263ef7ff83SDavid Woodhouse 2273ef7ff83SDavid Woodhouse g_byte_array_append(d, (void *)content, strlen(content)); 2283ef7ff83SDavid Woodhouse err = xs_impl_write(s, dom_id, tx_id, path, d); 2293ef7ff83SDavid Woodhouse g_byte_array_unref(d); 2303ef7ff83SDavid Woodhouse return err; 2313ef7ff83SDavid Woodhouse } 2323ef7ff83SDavid Woodhouse 2336e133009SDavid Woodhouse static void watch_cb(void *_str, const char *path, const char *token) 2346e133009SDavid Woodhouse { 2356e133009SDavid Woodhouse GString *str = _str; 2366e133009SDavid Woodhouse 2376e133009SDavid Woodhouse g_string_append(str, path); 2386e133009SDavid Woodhouse g_string_append(str, token); 2396e133009SDavid Woodhouse } 2406e133009SDavid Woodhouse 241766804b1SDavid Woodhouse static void check_serdes(XenstoreImplState *s) 242766804b1SDavid Woodhouse { 243766804b1SDavid Woodhouse XenstoreImplState *s2 = xs_impl_create(DOMID_GUEST); 244766804b1SDavid Woodhouse GByteArray *bytes = xs_impl_serialize(s); 245766804b1SDavid Woodhouse int nr_transactions1, nr_transactions2; 246766804b1SDavid Woodhouse int ret; 247766804b1SDavid Woodhouse 248766804b1SDavid Woodhouse ret = xs_impl_deserialize(s2, bytes, DOMID_GUEST, watch_cb, NULL); 249766804b1SDavid Woodhouse g_assert(!ret); 250766804b1SDavid Woodhouse 251766804b1SDavid Woodhouse g_byte_array_unref(bytes); 252766804b1SDavid Woodhouse 253766804b1SDavid Woodhouse g_assert(s->last_tx == s2->last_tx); 254766804b1SDavid Woodhouse g_assert(s->root_tx == s2->root_tx); 255766804b1SDavid Woodhouse 256766804b1SDavid Woodhouse if (!compare_trees(s->root, s2->root)) { 257766804b1SDavid Woodhouse printf("Comparison failure in main tree after serdes:\n"); 258766804b1SDavid Woodhouse dump_ref("Original", s->root, 0); 259766804b1SDavid Woodhouse dump_ref("Deserialised", s2->root, 0); 260766804b1SDavid Woodhouse g_assert(0); 261766804b1SDavid Woodhouse } 262766804b1SDavid Woodhouse 263766804b1SDavid Woodhouse nr_transactions1 = g_hash_table_size(s->transactions); 264766804b1SDavid Woodhouse nr_transactions2 = g_hash_table_size(s2->transactions); 265766804b1SDavid Woodhouse g_assert(nr_transactions1 == nr_transactions2); 266766804b1SDavid Woodhouse 267766804b1SDavid Woodhouse g_hash_table_foreach(s->transactions, compare_tx, s2); 268766804b1SDavid Woodhouse 269766804b1SDavid Woodhouse g_assert(s->nr_domu_watches == s2->nr_domu_watches); 270766804b1SDavid Woodhouse g_assert(s->nr_domu_transactions == s2->nr_domu_transactions); 271766804b1SDavid Woodhouse g_assert(s->nr_nodes == s2->nr_nodes); 272766804b1SDavid Woodhouse xs_impl_delete(s2, false); 273766804b1SDavid Woodhouse } 274766804b1SDavid Woodhouse 2753ef7ff83SDavid Woodhouse static XenstoreImplState *setup(void) 2763ef7ff83SDavid Woodhouse { 277be1934dfSPaul Durrant XenstoreImplState *s = xs_impl_create(DOMID_GUEST); 2783ef7ff83SDavid Woodhouse char *abspath; 279be1934dfSPaul Durrant GList *perms; 2803ef7ff83SDavid Woodhouse int err; 2813ef7ff83SDavid Woodhouse 2823ef7ff83SDavid Woodhouse abspath = g_strdup_printf("/local/domain/%u", DOMID_GUEST); 2833ef7ff83SDavid Woodhouse 2843ef7ff83SDavid Woodhouse err = write_str(s, DOMID_QEMU, XBT_NULL, abspath, ""); 2853ef7ff83SDavid Woodhouse g_assert(!err); 2866e133009SDavid Woodhouse g_assert(s->nr_nodes == 4); 2873ef7ff83SDavid Woodhouse 288be1934dfSPaul Durrant perms = g_list_append(NULL, g_strdup_printf("n%u", DOMID_QEMU)); 289be1934dfSPaul Durrant perms = g_list_append(perms, g_strdup_printf("r%u", DOMID_GUEST)); 290be1934dfSPaul Durrant 291be1934dfSPaul Durrant err = xs_impl_set_perms(s, DOMID_QEMU, XBT_NULL, abspath, perms); 292be1934dfSPaul Durrant g_assert(!err); 293be1934dfSPaul Durrant 294be1934dfSPaul Durrant g_list_free_full(perms, g_free); 2953ef7ff83SDavid Woodhouse g_free(abspath); 2963ef7ff83SDavid Woodhouse 2973ef7ff83SDavid Woodhouse abspath = g_strdup_printf("/local/domain/%u/some", DOMID_GUEST); 2983ef7ff83SDavid Woodhouse 2993ef7ff83SDavid Woodhouse err = write_str(s, DOMID_QEMU, XBT_NULL, abspath, ""); 3003ef7ff83SDavid Woodhouse g_assert(!err); 3013ef7ff83SDavid Woodhouse g_assert(s->nr_nodes == 5); 3023ef7ff83SDavid Woodhouse 303be1934dfSPaul Durrant perms = g_list_append(NULL, g_strdup_printf("n%u", DOMID_GUEST)); 304be1934dfSPaul Durrant 305be1934dfSPaul Durrant err = xs_impl_set_perms(s, DOMID_QEMU, XBT_NULL, abspath, perms); 306be1934dfSPaul Durrant g_assert(!err); 307be1934dfSPaul Durrant 308be1934dfSPaul Durrant g_list_free_full(perms, g_free); 3093ef7ff83SDavid Woodhouse g_free(abspath); 3103ef7ff83SDavid Woodhouse 3113ef7ff83SDavid Woodhouse return s; 3123ef7ff83SDavid Woodhouse } 3133ef7ff83SDavid Woodhouse 3143ef7ff83SDavid Woodhouse static void test_xs_node_simple(void) 3153ef7ff83SDavid Woodhouse { 3163ef7ff83SDavid Woodhouse GByteArray *data = g_byte_array_new(); 3173ef7ff83SDavid Woodhouse XenstoreImplState *s = setup(); 3186e133009SDavid Woodhouse GString *guest_watches = g_string_new(NULL); 3196e133009SDavid Woodhouse GString *qemu_watches = g_string_new(NULL); 3203ef7ff83SDavid Woodhouse GList *items = NULL; 3213ef7ff83SDavid Woodhouse XsNode *old_root; 3223ef7ff83SDavid Woodhouse uint64_t gencnt; 3233ef7ff83SDavid Woodhouse int err; 3243ef7ff83SDavid Woodhouse 3253ef7ff83SDavid Woodhouse g_assert(s); 3263ef7ff83SDavid Woodhouse 3276e133009SDavid Woodhouse err = xs_impl_watch(s, DOMID_GUEST, "some", "guestwatch", 3286e133009SDavid Woodhouse watch_cb, guest_watches); 3296e133009SDavid Woodhouse g_assert(!err); 3306e133009SDavid Woodhouse g_assert(guest_watches->len == strlen("someguestwatch")); 3316e133009SDavid Woodhouse g_assert(!strcmp(guest_watches->str, "someguestwatch")); 3326e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 3336e133009SDavid Woodhouse 3346e133009SDavid Woodhouse err = xs_impl_watch(s, 0, "/local/domain/1/some", "qemuwatch", 3356e133009SDavid Woodhouse watch_cb, qemu_watches); 3366e133009SDavid Woodhouse g_assert(!err); 3376e133009SDavid Woodhouse g_assert(qemu_watches->len == strlen("/local/domain/1/someqemuwatch")); 3386e133009SDavid Woodhouse g_assert(!strcmp(qemu_watches->str, "/local/domain/1/someqemuwatch")); 3396e133009SDavid Woodhouse g_string_truncate(qemu_watches, 0); 3406e133009SDavid Woodhouse 3413ef7ff83SDavid Woodhouse /* Read gives ENOENT when it should */ 3423ef7ff83SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "foo", data); 3433ef7ff83SDavid Woodhouse g_assert(err == ENOENT); 3443ef7ff83SDavid Woodhouse 3453ef7ff83SDavid Woodhouse /* Write works */ 3463ef7ff83SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/relative/path", 3473ef7ff83SDavid Woodhouse "something"); 3483ef7ff83SDavid Woodhouse g_assert(s->nr_nodes == 7); 3493ef7ff83SDavid Woodhouse g_assert(!err); 3506e133009SDavid Woodhouse g_assert(!strcmp(guest_watches->str, 3516e133009SDavid Woodhouse "some/relative/pathguestwatch")); 3526e133009SDavid Woodhouse g_assert(!strcmp(qemu_watches->str, 3536e133009SDavid Woodhouse "/local/domain/1/some/relative/pathqemuwatch")); 3546e133009SDavid Woodhouse 3556e133009SDavid Woodhouse g_string_truncate(qemu_watches, 0); 3566e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 3576e133009SDavid Woodhouse xs_impl_reset_watches(s, 0); 3583ef7ff83SDavid Woodhouse 3593ef7ff83SDavid Woodhouse /* Read gives back what we wrote */ 3603ef7ff83SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative/path", data); 3613ef7ff83SDavid Woodhouse g_assert(!err); 3623ef7ff83SDavid Woodhouse g_assert(data->len == strlen("something")); 3633ef7ff83SDavid Woodhouse g_assert(!memcmp(data->data, "something", data->len)); 3643ef7ff83SDavid Woodhouse 3653ef7ff83SDavid Woodhouse /* Even if we use an abolute path */ 3663ef7ff83SDavid Woodhouse g_byte_array_set_size(data, 0); 3673ef7ff83SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, 3683ef7ff83SDavid Woodhouse "/local/domain/1/some/relative/path", data); 3693ef7ff83SDavid Woodhouse g_assert(!err); 3703ef7ff83SDavid Woodhouse g_assert(data->len == strlen("something")); 3713ef7ff83SDavid Woodhouse 3726e133009SDavid Woodhouse g_assert(!qemu_watches->len); 3736e133009SDavid Woodhouse g_assert(!guest_watches->len); 3743ef7ff83SDavid Woodhouse /* Keep a copy, to force COW mode */ 3753ef7ff83SDavid Woodhouse old_root = xs_node_ref(s->root); 3763ef7ff83SDavid Woodhouse 377be1934dfSPaul Durrant /* Write somewhere we aren't allowed, in COW mode */ 378be1934dfSPaul Durrant err = write_str(s, DOMID_GUEST, XBT_NULL, "/local/domain/badplace", 379be1934dfSPaul Durrant "moredata"); 380be1934dfSPaul Durrant g_assert(err == EACCES); 381be1934dfSPaul Durrant g_assert(s->nr_nodes == 7); 382be1934dfSPaul Durrant 3833ef7ff83SDavid Woodhouse /* Write works again */ 3843ef7ff83SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, 3853ef7ff83SDavid Woodhouse "/local/domain/1/some/relative/path2", 3863ef7ff83SDavid Woodhouse "something else"); 3873ef7ff83SDavid Woodhouse g_assert(!err); 3883ef7ff83SDavid Woodhouse g_assert(s->nr_nodes == 8); 3896e133009SDavid Woodhouse g_assert(!qemu_watches->len); 3906e133009SDavid Woodhouse g_assert(!strcmp(guest_watches->str, "some/relative/path2guestwatch")); 3916e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 3923ef7ff83SDavid Woodhouse 3933ef7ff83SDavid Woodhouse /* Overwrite an existing node */ 3943ef7ff83SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/relative/path", 3953ef7ff83SDavid Woodhouse "another thing"); 3963ef7ff83SDavid Woodhouse g_assert(!err); 3973ef7ff83SDavid Woodhouse g_assert(s->nr_nodes == 8); 3986e133009SDavid Woodhouse g_assert(!qemu_watches->len); 3996e133009SDavid Woodhouse g_assert(!strcmp(guest_watches->str, "some/relative/pathguestwatch")); 4006e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 4013ef7ff83SDavid Woodhouse 4023ef7ff83SDavid Woodhouse /* We can list the two files we wrote */ 4033ef7ff83SDavid Woodhouse err = xs_impl_directory(s, DOMID_GUEST, XBT_NULL, "some/relative", &gencnt, 4043ef7ff83SDavid Woodhouse &items); 4053ef7ff83SDavid Woodhouse g_assert(!err); 4063ef7ff83SDavid Woodhouse g_assert(items); 4073ef7ff83SDavid Woodhouse g_assert(gencnt == 2); 4083ef7ff83SDavid Woodhouse g_assert(!strcmp(items->data, "path")); 4093ef7ff83SDavid Woodhouse g_assert(items->next); 4103ef7ff83SDavid Woodhouse g_assert(!strcmp(items->next->data, "path2")); 4113ef7ff83SDavid Woodhouse g_assert(!items->next->next); 4123ef7ff83SDavid Woodhouse g_list_free_full(items, g_free); 4133ef7ff83SDavid Woodhouse 4146e133009SDavid Woodhouse err = xs_impl_unwatch(s, DOMID_GUEST, "some", "guestwatch", 4156e133009SDavid Woodhouse watch_cb, guest_watches); 4166e133009SDavid Woodhouse g_assert(!err); 4176e133009SDavid Woodhouse 4186e133009SDavid Woodhouse err = xs_impl_unwatch(s, DOMID_GUEST, "some", "guestwatch", 4196e133009SDavid Woodhouse watch_cb, guest_watches); 4206e133009SDavid Woodhouse g_assert(err == ENOENT); 4216e133009SDavid Woodhouse 4226e133009SDavid Woodhouse err = xs_impl_watch(s, DOMID_GUEST, "some/relative/path2", "watchp2", 4236e133009SDavid Woodhouse watch_cb, guest_watches); 4246e133009SDavid Woodhouse g_assert(!err); 4256e133009SDavid Woodhouse g_assert(guest_watches->len == strlen("some/relative/path2watchp2")); 4266e133009SDavid Woodhouse g_assert(!strcmp(guest_watches->str, "some/relative/path2watchp2")); 4276e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 4286e133009SDavid Woodhouse 4296e133009SDavid Woodhouse err = xs_impl_watch(s, DOMID_GUEST, "/local/domain/1/some/relative", 4306e133009SDavid Woodhouse "watchrel", watch_cb, guest_watches); 4316e133009SDavid Woodhouse g_assert(!err); 4326e133009SDavid Woodhouse g_assert(guest_watches->len == 4336e133009SDavid Woodhouse strlen("/local/domain/1/some/relativewatchrel")); 4346e133009SDavid Woodhouse g_assert(!strcmp(guest_watches->str, 4356e133009SDavid Woodhouse "/local/domain/1/some/relativewatchrel")); 4366e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 4376e133009SDavid Woodhouse 4383ef7ff83SDavid Woodhouse /* Write somewhere else which already existed */ 4393ef7ff83SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/relative", "moredata"); 4403ef7ff83SDavid Woodhouse g_assert(!err); 4416e133009SDavid Woodhouse g_assert(s->nr_nodes == 8); 4426e133009SDavid Woodhouse 443be1934dfSPaul Durrant /* Write somewhere we aren't allowed */ 444be1934dfSPaul Durrant err = write_str(s, DOMID_GUEST, XBT_NULL, "/local/domain/badplace", 445be1934dfSPaul Durrant "moredata"); 446be1934dfSPaul Durrant g_assert(err == EACCES); 447be1934dfSPaul Durrant 4486e133009SDavid Woodhouse g_assert(!strcmp(guest_watches->str, 4496e133009SDavid Woodhouse "/local/domain/1/some/relativewatchrel")); 4506e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 4513ef7ff83SDavid Woodhouse 4523ef7ff83SDavid Woodhouse g_byte_array_set_size(data, 0); 4533ef7ff83SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative", data); 4543ef7ff83SDavid Woodhouse g_assert(!err); 4553ef7ff83SDavid Woodhouse g_assert(data->len == strlen("moredata")); 4563ef7ff83SDavid Woodhouse g_assert(!memcmp(data->data, "moredata", data->len)); 4573ef7ff83SDavid Woodhouse 4583ef7ff83SDavid Woodhouse /* Overwrite existing data */ 4593ef7ff83SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/relative", "otherdata"); 4603ef7ff83SDavid Woodhouse g_assert(!err); 4616e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 4623ef7ff83SDavid Woodhouse 4633ef7ff83SDavid Woodhouse g_byte_array_set_size(data, 0); 4643ef7ff83SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative", data); 4653ef7ff83SDavid Woodhouse g_assert(!err); 4663ef7ff83SDavid Woodhouse g_assert(data->len == strlen("otherdata")); 4673ef7ff83SDavid Woodhouse g_assert(!memcmp(data->data, "otherdata", data->len)); 4683ef7ff83SDavid Woodhouse 4693ef7ff83SDavid Woodhouse /* Remove the subtree */ 4703ef7ff83SDavid Woodhouse err = xs_impl_rm(s, DOMID_GUEST, XBT_NULL, "some/relative"); 4713ef7ff83SDavid Woodhouse g_assert(!err); 4723ef7ff83SDavid Woodhouse g_assert(s->nr_nodes == 5); 4733ef7ff83SDavid Woodhouse 4746e133009SDavid Woodhouse /* Each watch fires with the least specific relevant path */ 4756e133009SDavid Woodhouse g_assert(strstr(guest_watches->str, 4766e133009SDavid Woodhouse "some/relative/path2watchp2")); 4776e133009SDavid Woodhouse g_assert(strstr(guest_watches->str, 4786e133009SDavid Woodhouse "/local/domain/1/some/relativewatchrel")); 4796e133009SDavid Woodhouse g_string_truncate(guest_watches, 0); 4806e133009SDavid Woodhouse 4813ef7ff83SDavid Woodhouse g_byte_array_set_size(data, 0); 4823ef7ff83SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative", data); 4833ef7ff83SDavid Woodhouse g_assert(err == ENOENT); 4843ef7ff83SDavid Woodhouse g_byte_array_unref(data); 4853ef7ff83SDavid Woodhouse 4866e133009SDavid Woodhouse xs_impl_reset_watches(s, DOMID_GUEST); 4876e133009SDavid Woodhouse g_string_free(qemu_watches, true); 4886e133009SDavid Woodhouse g_string_free(guest_watches, true); 4893ef7ff83SDavid Woodhouse xs_node_unref(old_root); 490766804b1SDavid Woodhouse xs_impl_delete(s, true); 4913ef7ff83SDavid Woodhouse } 4923ef7ff83SDavid Woodhouse 4933ef7ff83SDavid Woodhouse 4947248b87cSDavid Woodhouse static void do_test_xs_node_tx(bool fail, bool commit) 4957248b87cSDavid Woodhouse { 4967248b87cSDavid Woodhouse XenstoreImplState *s = setup(); 4977248b87cSDavid Woodhouse GString *watches = g_string_new(NULL); 4987248b87cSDavid Woodhouse GByteArray *data = g_byte_array_new(); 4997248b87cSDavid Woodhouse unsigned int tx_id = XBT_NULL; 5007248b87cSDavid Woodhouse int err; 5017248b87cSDavid Woodhouse 5027248b87cSDavid Woodhouse g_assert(s); 5037248b87cSDavid Woodhouse 5047248b87cSDavid Woodhouse /* Set a watch */ 5057248b87cSDavid Woodhouse err = xs_impl_watch(s, DOMID_GUEST, "some", "watch", 5067248b87cSDavid Woodhouse watch_cb, watches); 5077248b87cSDavid Woodhouse g_assert(!err); 5087248b87cSDavid Woodhouse g_assert(watches->len == strlen("somewatch")); 5097248b87cSDavid Woodhouse g_assert(!strcmp(watches->str, "somewatch")); 5107248b87cSDavid Woodhouse g_string_truncate(watches, 0); 5117248b87cSDavid Woodhouse 5127248b87cSDavid Woodhouse /* Write something */ 5137248b87cSDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/relative/path", 5147248b87cSDavid Woodhouse "something"); 5157248b87cSDavid Woodhouse g_assert(s->nr_nodes == 7); 5167248b87cSDavid Woodhouse g_assert(!err); 5177248b87cSDavid Woodhouse g_assert(!strcmp(watches->str, 5187248b87cSDavid Woodhouse "some/relative/pathwatch")); 5197248b87cSDavid Woodhouse g_string_truncate(watches, 0); 5207248b87cSDavid Woodhouse 5217248b87cSDavid Woodhouse /* Create a transaction */ 5227248b87cSDavid Woodhouse err = xs_impl_transaction_start(s, DOMID_GUEST, &tx_id); 5237248b87cSDavid Woodhouse g_assert(!err); 5247248b87cSDavid Woodhouse 5257248b87cSDavid Woodhouse if (fail) { 5267248b87cSDavid Woodhouse /* Write something else in the root */ 5277248b87cSDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/relative/path", 5287248b87cSDavid Woodhouse "another thing"); 5297248b87cSDavid Woodhouse g_assert(!err); 5307248b87cSDavid Woodhouse g_assert(s->nr_nodes == 7); 5317248b87cSDavid Woodhouse g_assert(!strcmp(watches->str, 5327248b87cSDavid Woodhouse "some/relative/pathwatch")); 5337248b87cSDavid Woodhouse g_string_truncate(watches, 0); 5347248b87cSDavid Woodhouse } 5357248b87cSDavid Woodhouse 5367248b87cSDavid Woodhouse g_assert(!watches->len); 5377248b87cSDavid Woodhouse 5387248b87cSDavid Woodhouse /* Perform a write in the transaction */ 5397248b87cSDavid Woodhouse err = write_str(s, DOMID_GUEST, tx_id, "some/relative/path", 5407248b87cSDavid Woodhouse "something else"); 5417248b87cSDavid Woodhouse g_assert(!err); 5427248b87cSDavid Woodhouse g_assert(s->nr_nodes == 7); 5437248b87cSDavid Woodhouse g_assert(!watches->len); 5447248b87cSDavid Woodhouse 5457248b87cSDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative/path", data); 5467248b87cSDavid Woodhouse g_assert(!err); 5477248b87cSDavid Woodhouse if (fail) { 5487248b87cSDavid Woodhouse g_assert(data->len == strlen("another thing")); 5497248b87cSDavid Woodhouse g_assert(!memcmp(data->data, "another thing", data->len)); 5507248b87cSDavid Woodhouse } else { 5517248b87cSDavid Woodhouse g_assert(data->len == strlen("something")); 5527248b87cSDavid Woodhouse g_assert(!memcmp(data->data, "something", data->len)); 5537248b87cSDavid Woodhouse } 5547248b87cSDavid Woodhouse g_byte_array_set_size(data, 0); 5557248b87cSDavid Woodhouse 5567248b87cSDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, tx_id, "some/relative/path", data); 5577248b87cSDavid Woodhouse g_assert(!err); 5587248b87cSDavid Woodhouse g_assert(data->len == strlen("something else")); 5597248b87cSDavid Woodhouse g_assert(!memcmp(data->data, "something else", data->len)); 5607248b87cSDavid Woodhouse g_byte_array_set_size(data, 0); 5617248b87cSDavid Woodhouse 562766804b1SDavid Woodhouse check_serdes(s); 563766804b1SDavid Woodhouse 5647248b87cSDavid Woodhouse /* Attempt to commit the transaction */ 5657248b87cSDavid Woodhouse err = xs_impl_transaction_end(s, DOMID_GUEST, tx_id, commit); 5667248b87cSDavid Woodhouse if (commit && fail) { 5677248b87cSDavid Woodhouse g_assert(err == EAGAIN); 5687248b87cSDavid Woodhouse } else { 5697248b87cSDavid Woodhouse g_assert(!err); 5707248b87cSDavid Woodhouse } 5717cabbdb7SDavid Woodhouse if (commit && !fail) { 5727cabbdb7SDavid Woodhouse g_assert(!strcmp(watches->str, 5737cabbdb7SDavid Woodhouse "some/relative/pathwatch")); 5747cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 5757cabbdb7SDavid Woodhouse } else { 5767248b87cSDavid Woodhouse g_assert(!watches->len); 5777cabbdb7SDavid Woodhouse } 5787248b87cSDavid Woodhouse g_assert(s->nr_nodes == 7); 5797248b87cSDavid Woodhouse 580766804b1SDavid Woodhouse check_serdes(s); 581766804b1SDavid Woodhouse 5827248b87cSDavid Woodhouse err = xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", 5837248b87cSDavid Woodhouse watch_cb, watches); 5847248b87cSDavid Woodhouse g_assert(!err); 5857248b87cSDavid Woodhouse 5867248b87cSDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/relative/path", data); 5877248b87cSDavid Woodhouse g_assert(!err); 5887248b87cSDavid Woodhouse if (fail) { 5897248b87cSDavid Woodhouse g_assert(data->len == strlen("another thing")); 5907248b87cSDavid Woodhouse g_assert(!memcmp(data->data, "another thing", data->len)); 5917248b87cSDavid Woodhouse } else if (commit) { 5927248b87cSDavid Woodhouse g_assert(data->len == strlen("something else")); 5937248b87cSDavid Woodhouse g_assert(!memcmp(data->data, "something else", data->len)); 5947248b87cSDavid Woodhouse } else { 5957248b87cSDavid Woodhouse g_assert(data->len == strlen("something")); 5967248b87cSDavid Woodhouse g_assert(!memcmp(data->data, "something", data->len)); 5977248b87cSDavid Woodhouse } 5987248b87cSDavid Woodhouse g_byte_array_unref(data); 5997248b87cSDavid Woodhouse g_string_free(watches, true); 600766804b1SDavid Woodhouse xs_impl_delete(s, true); 6017248b87cSDavid Woodhouse } 6027248b87cSDavid Woodhouse 6037248b87cSDavid Woodhouse static void test_xs_node_tx_fail(void) 6047248b87cSDavid Woodhouse { 6057248b87cSDavid Woodhouse do_test_xs_node_tx(true, true); 6067248b87cSDavid Woodhouse } 6077248b87cSDavid Woodhouse 6087248b87cSDavid Woodhouse static void test_xs_node_tx_abort(void) 6097248b87cSDavid Woodhouse { 6107248b87cSDavid Woodhouse do_test_xs_node_tx(false, false); 6117248b87cSDavid Woodhouse do_test_xs_node_tx(true, false); 6127248b87cSDavid Woodhouse } 6137248b87cSDavid Woodhouse static void test_xs_node_tx_succeed(void) 6147248b87cSDavid Woodhouse { 6157248b87cSDavid Woodhouse do_test_xs_node_tx(false, true); 6167248b87cSDavid Woodhouse } 6177248b87cSDavid Woodhouse 6187cabbdb7SDavid Woodhouse static void test_xs_node_tx_rm(void) 6197cabbdb7SDavid Woodhouse { 6207cabbdb7SDavid Woodhouse XenstoreImplState *s = setup(); 6217cabbdb7SDavid Woodhouse GString *watches = g_string_new(NULL); 6227cabbdb7SDavid Woodhouse GByteArray *data = g_byte_array_new(); 6237cabbdb7SDavid Woodhouse unsigned int tx_id = XBT_NULL; 6247cabbdb7SDavid Woodhouse int err; 6257cabbdb7SDavid Woodhouse 6267cabbdb7SDavid Woodhouse g_assert(s); 6277cabbdb7SDavid Woodhouse 6287cabbdb7SDavid Woodhouse /* Set a watch */ 6297cabbdb7SDavid Woodhouse err = xs_impl_watch(s, DOMID_GUEST, "some", "watch", 6307cabbdb7SDavid Woodhouse watch_cb, watches); 6317cabbdb7SDavid Woodhouse g_assert(!err); 6327cabbdb7SDavid Woodhouse g_assert(watches->len == strlen("somewatch")); 6337cabbdb7SDavid Woodhouse g_assert(!strcmp(watches->str, "somewatch")); 6347cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 6357cabbdb7SDavid Woodhouse 6367cabbdb7SDavid Woodhouse /* Write something */ 6377cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/path", 6387cabbdb7SDavid Woodhouse "something"); 6397cabbdb7SDavid Woodhouse g_assert(!err); 6407cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 9); 6417cabbdb7SDavid Woodhouse g_assert(!strcmp(watches->str, 6427cabbdb7SDavid Woodhouse "some/deep/dark/relative/pathwatch")); 6437cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 6447cabbdb7SDavid Woodhouse 6457cabbdb7SDavid Woodhouse /* Create a transaction */ 6467cabbdb7SDavid Woodhouse err = xs_impl_transaction_start(s, DOMID_GUEST, &tx_id); 6477cabbdb7SDavid Woodhouse g_assert(!err); 6487cabbdb7SDavid Woodhouse 6497cabbdb7SDavid Woodhouse /* Delete the tree in the transaction */ 6507cabbdb7SDavid Woodhouse err = xs_impl_rm(s, DOMID_GUEST, tx_id, "some/deep/dark"); 6517cabbdb7SDavid Woodhouse g_assert(!err); 6527cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 9); 6537cabbdb7SDavid Woodhouse g_assert(!watches->len); 6547cabbdb7SDavid Woodhouse 6557cabbdb7SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/path", 6567cabbdb7SDavid Woodhouse data); 6577cabbdb7SDavid Woodhouse g_assert(!err); 6587cabbdb7SDavid Woodhouse g_assert(data->len == strlen("something")); 6597cabbdb7SDavid Woodhouse g_assert(!memcmp(data->data, "something", data->len)); 6607cabbdb7SDavid Woodhouse g_byte_array_set_size(data, 0); 6617cabbdb7SDavid Woodhouse 662766804b1SDavid Woodhouse check_serdes(s); 663766804b1SDavid Woodhouse 6647cabbdb7SDavid Woodhouse /* Commit the transaction */ 6657cabbdb7SDavid Woodhouse err = xs_impl_transaction_end(s, DOMID_GUEST, tx_id, true); 6667cabbdb7SDavid Woodhouse g_assert(!err); 6677cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 6); 6687cabbdb7SDavid Woodhouse 6697cabbdb7SDavid Woodhouse g_assert(!strcmp(watches->str, "some/deep/darkwatch")); 6707cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 6717cabbdb7SDavid Woodhouse 6727cabbdb7SDavid Woodhouse /* Now the node is gone */ 6737cabbdb7SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/path", 6747cabbdb7SDavid Woodhouse data); 6757cabbdb7SDavid Woodhouse g_assert(err == ENOENT); 6767cabbdb7SDavid Woodhouse g_byte_array_unref(data); 6777cabbdb7SDavid Woodhouse 6787cabbdb7SDavid Woodhouse err = xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", 6797cabbdb7SDavid Woodhouse watch_cb, watches); 6807cabbdb7SDavid Woodhouse g_assert(!err); 6817cabbdb7SDavid Woodhouse 6827cabbdb7SDavid Woodhouse g_string_free(watches, true); 683766804b1SDavid Woodhouse xs_impl_delete(s, true); 6847cabbdb7SDavid Woodhouse } 6857cabbdb7SDavid Woodhouse 6867cabbdb7SDavid Woodhouse static void test_xs_node_tx_resurrect(void) 6877cabbdb7SDavid Woodhouse { 6887cabbdb7SDavid Woodhouse XenstoreImplState *s = setup(); 6897cabbdb7SDavid Woodhouse GString *watches = g_string_new(NULL); 6907cabbdb7SDavid Woodhouse GByteArray *data = g_byte_array_new(); 6917cabbdb7SDavid Woodhouse unsigned int tx_id = XBT_NULL; 6927cabbdb7SDavid Woodhouse int err; 6937cabbdb7SDavid Woodhouse 6947cabbdb7SDavid Woodhouse g_assert(s); 6957cabbdb7SDavid Woodhouse 6967cabbdb7SDavid Woodhouse /* Write something */ 6977cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/path", 6987cabbdb7SDavid Woodhouse "something"); 6997cabbdb7SDavid Woodhouse g_assert(!err); 7007cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 9); 7017cabbdb7SDavid Woodhouse 702766804b1SDavid Woodhouse /* Another node to remain shared */ 703766804b1SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/place/safe", "keepme"); 704766804b1SDavid Woodhouse g_assert(!err); 705766804b1SDavid Woodhouse g_assert(s->nr_nodes == 11); 706766804b1SDavid Woodhouse 7077cabbdb7SDavid Woodhouse /* This node will be wiped and resurrected */ 7087cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark", 7097cabbdb7SDavid Woodhouse "foo"); 7107cabbdb7SDavid Woodhouse g_assert(!err); 711766804b1SDavid Woodhouse g_assert(s->nr_nodes == 11); 7127cabbdb7SDavid Woodhouse 7137cabbdb7SDavid Woodhouse /* Set a watch */ 7147cabbdb7SDavid Woodhouse err = xs_impl_watch(s, DOMID_GUEST, "some", "watch", 7157cabbdb7SDavid Woodhouse watch_cb, watches); 7167cabbdb7SDavid Woodhouse g_assert(!err); 7177cabbdb7SDavid Woodhouse g_assert(watches->len == strlen("somewatch")); 7187cabbdb7SDavid Woodhouse g_assert(!strcmp(watches->str, "somewatch")); 7197cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 7207cabbdb7SDavid Woodhouse 7217cabbdb7SDavid Woodhouse /* Create a transaction */ 7227cabbdb7SDavid Woodhouse err = xs_impl_transaction_start(s, DOMID_GUEST, &tx_id); 7237cabbdb7SDavid Woodhouse g_assert(!err); 7247cabbdb7SDavid Woodhouse 7257cabbdb7SDavid Woodhouse /* Delete the tree in the transaction */ 7267cabbdb7SDavid Woodhouse err = xs_impl_rm(s, DOMID_GUEST, tx_id, "some/deep"); 7277cabbdb7SDavid Woodhouse g_assert(!err); 728766804b1SDavid Woodhouse g_assert(s->nr_nodes == 11); 7297cabbdb7SDavid Woodhouse g_assert(!watches->len); 7307cabbdb7SDavid Woodhouse 7317cabbdb7SDavid Woodhouse /* Resurrect part of it */ 7327cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, tx_id, "some/deep/dark/different/path", 7337cabbdb7SDavid Woodhouse "something"); 7347cabbdb7SDavid Woodhouse g_assert(!err); 735766804b1SDavid Woodhouse g_assert(s->nr_nodes == 11); 736766804b1SDavid Woodhouse 737766804b1SDavid Woodhouse check_serdes(s); 7387cabbdb7SDavid Woodhouse 7397cabbdb7SDavid Woodhouse /* Commit the transaction */ 7407cabbdb7SDavid Woodhouse err = xs_impl_transaction_end(s, DOMID_GUEST, tx_id, true); 7417cabbdb7SDavid Woodhouse g_assert(!err); 742766804b1SDavid Woodhouse g_assert(s->nr_nodes == 11); 743766804b1SDavid Woodhouse 744766804b1SDavid Woodhouse check_serdes(s); 7457cabbdb7SDavid Woodhouse 7467cabbdb7SDavid Woodhouse /* lost data */ 7477cabbdb7SDavid Woodhouse g_assert(strstr(watches->str, "some/deep/dark/different/pathwatch")); 7487cabbdb7SDavid Woodhouse /* topmost deleted */ 7497cabbdb7SDavid Woodhouse g_assert(strstr(watches->str, "some/deep/dark/relativewatch")); 7507cabbdb7SDavid Woodhouse /* lost data */ 7517cabbdb7SDavid Woodhouse g_assert(strstr(watches->str, "some/deep/darkwatch")); 7527cabbdb7SDavid Woodhouse 7537cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 7547cabbdb7SDavid Woodhouse 7557cabbdb7SDavid Woodhouse /* Now the node is gone */ 7567cabbdb7SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/path", 7577cabbdb7SDavid Woodhouse data); 7587cabbdb7SDavid Woodhouse g_assert(err == ENOENT); 7597cabbdb7SDavid Woodhouse g_byte_array_unref(data); 7607cabbdb7SDavid Woodhouse 761766804b1SDavid Woodhouse check_serdes(s); 762766804b1SDavid Woodhouse 7637cabbdb7SDavid Woodhouse err = xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", 7647cabbdb7SDavid Woodhouse watch_cb, watches); 7657cabbdb7SDavid Woodhouse g_assert(!err); 7667cabbdb7SDavid Woodhouse 7677cabbdb7SDavid Woodhouse g_string_free(watches, true); 768766804b1SDavid Woodhouse xs_impl_delete(s, true); 7697cabbdb7SDavid Woodhouse } 7707cabbdb7SDavid Woodhouse 7717cabbdb7SDavid Woodhouse static void test_xs_node_tx_resurrect2(void) 7727cabbdb7SDavid Woodhouse { 7737cabbdb7SDavid Woodhouse XenstoreImplState *s = setup(); 7747cabbdb7SDavid Woodhouse GString *watches = g_string_new(NULL); 7757cabbdb7SDavid Woodhouse GByteArray *data = g_byte_array_new(); 7767cabbdb7SDavid Woodhouse unsigned int tx_id = XBT_NULL; 7777cabbdb7SDavid Woodhouse int err; 7787cabbdb7SDavid Woodhouse 7797cabbdb7SDavid Woodhouse g_assert(s); 7807cabbdb7SDavid Woodhouse 7817cabbdb7SDavid Woodhouse /* Write something */ 7827cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/path", 7837cabbdb7SDavid Woodhouse "something"); 7847cabbdb7SDavid Woodhouse g_assert(!err); 7857cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 9); 7867cabbdb7SDavid Woodhouse 7877cabbdb7SDavid Woodhouse /* Another node to remain shared */ 7887cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/place/safe", "keepme"); 7897cabbdb7SDavid Woodhouse g_assert(!err); 7907cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 11); 7917cabbdb7SDavid Woodhouse 7927cabbdb7SDavid Woodhouse /* This node will be wiped and resurrected */ 7937cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, XBT_NULL, "some/deep/dark", 7947cabbdb7SDavid Woodhouse "foo"); 7957cabbdb7SDavid Woodhouse g_assert(!err); 7967cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 11); 7977cabbdb7SDavid Woodhouse 7987cabbdb7SDavid Woodhouse /* Set a watch */ 7997cabbdb7SDavid Woodhouse err = xs_impl_watch(s, DOMID_GUEST, "some", "watch", 8007cabbdb7SDavid Woodhouse watch_cb, watches); 8017cabbdb7SDavid Woodhouse g_assert(!err); 8027cabbdb7SDavid Woodhouse g_assert(watches->len == strlen("somewatch")); 8037cabbdb7SDavid Woodhouse g_assert(!strcmp(watches->str, "somewatch")); 8047cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 8057cabbdb7SDavid Woodhouse 8067cabbdb7SDavid Woodhouse /* Create a transaction */ 8077cabbdb7SDavid Woodhouse err = xs_impl_transaction_start(s, DOMID_GUEST, &tx_id); 8087cabbdb7SDavid Woodhouse g_assert(!err); 8097cabbdb7SDavid Woodhouse 8107cabbdb7SDavid Woodhouse /* Delete the tree in the transaction */ 8117cabbdb7SDavid Woodhouse err = xs_impl_rm(s, DOMID_GUEST, tx_id, "some/deep"); 8127cabbdb7SDavid Woodhouse g_assert(!err); 8137cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 11); 8147cabbdb7SDavid Woodhouse g_assert(!watches->len); 8157cabbdb7SDavid Woodhouse 8167cabbdb7SDavid Woodhouse /* Resurrect part of it */ 8177cabbdb7SDavid Woodhouse err = write_str(s, DOMID_GUEST, tx_id, "some/deep/dark/relative/path", 8187cabbdb7SDavid Woodhouse "something"); 8197cabbdb7SDavid Woodhouse g_assert(!err); 8207cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 11); 8217cabbdb7SDavid Woodhouse 822766804b1SDavid Woodhouse check_serdes(s); 823766804b1SDavid Woodhouse 8247cabbdb7SDavid Woodhouse /* Commit the transaction */ 8257cabbdb7SDavid Woodhouse err = xs_impl_transaction_end(s, DOMID_GUEST, tx_id, true); 8267cabbdb7SDavid Woodhouse g_assert(!err); 8277cabbdb7SDavid Woodhouse g_assert(s->nr_nodes == 11); 8287cabbdb7SDavid Woodhouse 829766804b1SDavid Woodhouse check_serdes(s); 830766804b1SDavid Woodhouse 8317cabbdb7SDavid Woodhouse /* lost data */ 8327cabbdb7SDavid Woodhouse g_assert(strstr(watches->str, "some/deep/dark/relative/pathwatch")); 8337cabbdb7SDavid Woodhouse /* lost data */ 8347cabbdb7SDavid Woodhouse g_assert(strstr(watches->str, "some/deep/darkwatch")); 8357cabbdb7SDavid Woodhouse 8367cabbdb7SDavid Woodhouse g_string_truncate(watches, 0); 8377cabbdb7SDavid Woodhouse 8387cabbdb7SDavid Woodhouse /* Now the node is gone */ 8397cabbdb7SDavid Woodhouse err = xs_impl_read(s, DOMID_GUEST, XBT_NULL, "some/deep/dark/relative/path", 8407cabbdb7SDavid Woodhouse data); 8417cabbdb7SDavid Woodhouse g_assert(!err); 8427cabbdb7SDavid Woodhouse g_assert(data->len == strlen("something")); 8437cabbdb7SDavid Woodhouse g_assert(!memcmp(data->data, "something", data->len)); 8447cabbdb7SDavid Woodhouse 8457cabbdb7SDavid Woodhouse g_byte_array_unref(data); 8467cabbdb7SDavid Woodhouse 847766804b1SDavid Woodhouse check_serdes(s); 848766804b1SDavid Woodhouse 8497cabbdb7SDavid Woodhouse err = xs_impl_unwatch(s, DOMID_GUEST, "some", "watch", 8507cabbdb7SDavid Woodhouse watch_cb, watches); 8517cabbdb7SDavid Woodhouse g_assert(!err); 8527cabbdb7SDavid Woodhouse 8537cabbdb7SDavid Woodhouse g_string_free(watches, true); 854766804b1SDavid Woodhouse xs_impl_delete(s, true); 8557cabbdb7SDavid Woodhouse } 8567cabbdb7SDavid Woodhouse 8573ef7ff83SDavid Woodhouse int main(int argc, char **argv) 8583ef7ff83SDavid Woodhouse { 8593ef7ff83SDavid Woodhouse g_test_init(&argc, &argv, NULL); 8603ef7ff83SDavid Woodhouse module_call_init(MODULE_INIT_QOM); 8613ef7ff83SDavid Woodhouse 8623ef7ff83SDavid Woodhouse g_test_add_func("/xs_node/simple", test_xs_node_simple); 8637248b87cSDavid Woodhouse g_test_add_func("/xs_node/tx_abort", test_xs_node_tx_abort); 8647248b87cSDavid Woodhouse g_test_add_func("/xs_node/tx_fail", test_xs_node_tx_fail); 8657248b87cSDavid Woodhouse g_test_add_func("/xs_node/tx_succeed", test_xs_node_tx_succeed); 8667cabbdb7SDavid Woodhouse g_test_add_func("/xs_node/tx_rm", test_xs_node_tx_rm); 8677cabbdb7SDavid Woodhouse g_test_add_func("/xs_node/tx_resurrect", test_xs_node_tx_resurrect); 8687cabbdb7SDavid Woodhouse g_test_add_func("/xs_node/tx_resurrect2", test_xs_node_tx_resurrect2); 8693ef7ff83SDavid Woodhouse 8703ef7ff83SDavid Woodhouse return g_test_run(); 8713ef7ff83SDavid Woodhouse } 872