From 8c52f78fc55c09d78327e5be822b0e131d1be33d Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Wed, 1 Mar 2006 18:33:36 +0100 Subject: [PATCH 01/12] Disallow cmpxchg8b ptwr emulation for non-pae. Also a few cleanups. Signed-off-by: Keir Fraser --- xen/arch/x86/mm.c | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 1e29ce5d2d..05d7704211 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -507,10 +507,9 @@ get_page_from_l2e( rc = get_page_and_type_from_pagenr( l2e_get_pfn(l2e), PGT_l1_page_table | vaddr, d); -#if CONFIG_PAGING_LEVELS == 2 - if ( unlikely(!rc) ) + if ( (CONFIG_PAGING_LEVELS == 2) && unlikely(!rc) ) rc = get_linear_pagetable(l2e, pfn, d); -#endif + return rc; } @@ -539,10 +538,10 @@ get_page_from_l3e( rc = get_page_and_type_from_pagenr( l3e_get_pfn(l3e), PGT_l2_page_table | vaddr, d); -#if CONFIG_PAGING_LEVELS == 3 - if ( unlikely(!rc) ) + + if ( (CONFIG_PAGING_LEVELS == 3) && unlikely(!rc) ) rc = get_linear_pagetable(l3e, pfn, d); -#endif + return rc; } #endif /* 3 level */ @@ -3187,8 +3186,8 @@ static int ptwr_emulated_update( ptwr_flush(d, PTWR_PT_INACTIVE); /* Read the PTE that maps the page being updated. */ - if (__copy_from_user(&pte, &linear_pg_table[l1_linear_offset(addr)], - sizeof(pte))) + if ( __copy_from_user(&pte, &linear_pg_table[l1_linear_offset(addr)], + sizeof(pte)) ) { MEM_LOG("ptwr_emulate: Cannot read thru linear_pg_table"); return X86EMUL_UNHANDLEABLE; @@ -3198,15 +3197,10 @@ static int ptwr_emulated_update( page = mfn_to_page(pfn); /* We are looking only for read-only mappings of p.t. pages. */ - if ( ((l1e_get_flags(pte) & (_PAGE_RW|_PAGE_PRESENT)) != _PAGE_PRESENT) || - ((page->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table) || - (page_get_owner(page) != d) ) - { - MEM_LOG("ptwr_emulate: Page is mistyped or bad pte " - "(%lx, %" PRtype_info ")", - l1e_get_pfn(pte), page->u.inuse.type_info); - return X86EMUL_UNHANDLEABLE; - } + ASSERT((l1e_get_flags(pte) & (_PAGE_RW|_PAGE_PRESENT)) == _PAGE_PRESENT); + ASSERT((page->u.inuse.type_info & PGT_type_mask) == PGT_l1_page_table); + ASSERT((page->u.inuse.type_info & PGT_count_mask) != 0); + ASSERT(page_get_owner(page) == d); /* Check the new PTE. */ nl1e = l1e_from_intpte(val); @@ -3266,8 +3260,11 @@ static int ptwr_emulated_cmpxchg8b( unsigned long new, unsigned long new_hi) { - return ptwr_emulated_update( - addr, ((u64)old_hi << 32) | old, ((u64)new_hi << 32) | new, 8, 1); + if ( CONFIG_PAGING_LEVELS == 2 ) + return X86EMUL_UNHANDLEABLE; + else + return ptwr_emulated_update( + addr, ((u64)old_hi << 32) | old, ((u64)new_hi << 32) | new, 8, 1); } static struct x86_mem_emulator ptwr_mem_emulator = { From 71a0b53a1ad36ccca3b83baf2047817efaf9e27d Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Wed, 1 Mar 2006 18:34:06 +0100 Subject: [PATCH 02/12] map_domain_page() now handles running on idle page tables. Signed-off-by: Keir Fraser --- xen/arch/x86/x86_32/domain_page.c | 46 +++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/xen/arch/x86/x86_32/domain_page.c b/xen/arch/x86/x86_32/domain_page.c index 222e813693..f3125bd1d3 100644 --- a/xen/arch/x86/x86_32/domain_page.c +++ b/xen/arch/x86/x86_32/domain_page.c @@ -11,15 +11,40 @@ #include #include #include +#include #include #include #include +static inline struct vcpu *mapcache_current_vcpu(void) +{ + struct vcpu *v; + + /* In the common case we use the mapcache of the running VCPU. */ + v = current; + + /* + * If guest_table is NULL, and we are running a paravirtualised guest, + * then it means we are running on the idle domain's page table and must + * therefore use its mapcache. + */ + if ( unlikely(!pagetable_get_pfn(v->arch.guest_table)) && !HVM_DOMAIN(v) ) + { + /* If we really are idling, perform lazy context switch now. */ + if ( (v = idle_vcpu[smp_processor_id()]) == current ) + __sync_lazy_execstate(); + /* We must now be running on the idle page table. */ + ASSERT(read_cr3() == __pa(idle_pg_table)); + } + + return v; +} + void *map_domain_page(unsigned long pfn) { unsigned long va; - unsigned int idx, i, vcpu = current->vcpu_id; - struct domain *d; + unsigned int idx, i, vcpu; + struct vcpu *v; struct mapcache *cache; struct vcpu_maphash_entry *hashent; @@ -27,12 +52,10 @@ void *map_domain_page(unsigned long pfn) perfc_incrc(map_domain_page_count); - /* If we are the idle domain, ensure that we run on our own page tables. */ - d = current->domain; - if ( unlikely(is_idle_domain(d)) ) - __sync_lazy_execstate(); + v = mapcache_current_vcpu(); - cache = &d->arch.mapcache; + vcpu = v->vcpu_id; + cache = &v->domain->arch.mapcache; hashent = &cache->vcpu_maphash[vcpu].hash[MAPHASH_HASHFN(pfn)]; if ( hashent->pfn == pfn ) @@ -93,7 +116,8 @@ void *map_domain_page(unsigned long pfn) void unmap_domain_page(void *va) { unsigned int idx; - struct mapcache *cache = ¤t->domain->arch.mapcache; + struct vcpu *v; + struct mapcache *cache; unsigned long pfn; struct vcpu_maphash_entry *hashent; @@ -102,9 +126,13 @@ void unmap_domain_page(void *va) ASSERT((void *)MAPCACHE_VIRT_START <= va); ASSERT(va < (void *)MAPCACHE_VIRT_END); + v = mapcache_current_vcpu(); + + cache = &v->domain->arch.mapcache; + idx = ((unsigned long)va - MAPCACHE_VIRT_START) >> PAGE_SHIFT; pfn = l1e_get_pfn(cache->l1tab[idx]); - hashent = &cache->vcpu_maphash[current->vcpu_id].hash[MAPHASH_HASHFN(pfn)]; + hashent = &cache->vcpu_maphash[v->vcpu_id].hash[MAPHASH_HASHFN(pfn)]; if ( hashent->idx == idx ) { From 2c1a8a16e5aa28973e0b41ba6a00a9b414125990 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Wed, 1 Mar 2006 23:35:55 +0100 Subject: [PATCH 03/12] Revert two uses of CONFIG_PAGING_LEVELS to CPP rather than C predicate. Fixes PAE and 64-bit builds. Signed-off-by: Keir Fraser --- xen/arch/x86/mm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 05d7704211..60a324cf79 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -506,10 +506,10 @@ get_page_from_l2e( vaddr <<= PGT_va_shift; rc = get_page_and_type_from_pagenr( l2e_get_pfn(l2e), PGT_l1_page_table | vaddr, d); - - if ( (CONFIG_PAGING_LEVELS == 2) && unlikely(!rc) ) +#if CONFIG_PAGING_LEVELS == 2 + if ( unlikely(!rc) ) rc = get_linear_pagetable(l2e, pfn, d); - +#endif return rc; } @@ -538,10 +538,10 @@ get_page_from_l3e( rc = get_page_and_type_from_pagenr( l3e_get_pfn(l3e), PGT_l2_page_table | vaddr, d); - - if ( (CONFIG_PAGING_LEVELS == 3) && unlikely(!rc) ) +#if CONFIG_PAGING_LEVELS == 3 + if ( unlikely(!rc) ) rc = get_linear_pagetable(l3e, pfn, d); - +#endif return rc; } #endif /* 3 level */ From 7595516fa02e169c47e554eb5c16fccf99883604 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Wed, 1 Mar 2006 23:38:18 +0100 Subject: [PATCH 04/12] Clean up SVM 32-bit exits.S file (remove all tsc/fpu). Signed-off-by: Tom Woller --- xen/arch/x86/hvm/svm/x86_32/exits.S | 57 ----------------------------- 1 file changed, 57 deletions(-) diff --git a/xen/arch/x86/hvm/svm/x86_32/exits.S b/xen/arch/x86/hvm/svm/x86_32/exits.S index 7c6147269a..4325b1443d 100644 --- a/xen/arch/x86/hvm/svm/x86_32/exits.S +++ b/xen/arch/x86/hvm/svm/x86_32/exits.S @@ -88,9 +88,6 @@ #define STGI .byte 0x0F,0x01,0xDC #define CLGI .byte 0x0F,0x01,0xDD -#define DO_TSC_OFFSET 0 -#define DO_FPUSAVE 0 - ENTRY(svm_asm_do_launch) sti CLGI @@ -101,36 +98,6 @@ ENTRY(svm_asm_do_launch) movl VCPU_svm_hsa_pa(%ebx), %eax VMSAVE -#if DO_FPUSAVE - mov %cr0, %eax - push %eax - clts - lea VCPU_arch_guest_fpu_ctxt(%ebx), %eax - fxrstor (%eax) - pop %eax - mov %eax, %cr0 -#endif - -#if (DO_TSC_OFFSET) - pushl %edx /* eax and edx get trashed by rdtsc */ - pushl %eax - rdtsc - subl VCPU_svm_vmexit_tsc(%ebx),%eax /* tsc's from */ - sbbl VCPU_svm_vmexit_tsc+4(%ebx),%edx /* last #VMEXIT? */ - subl %eax,VMCB_tsc_offset(%ecx) /* subtract from running TSC_OFFSET */ - sbbl %edx,VMCB_tsc_offset+4(%ecx) - subl $20000,VMCB_tsc_offset(%ecx) /* fudge factor for VMXXX calls */ - sbbl $0,VMCB_tsc_offset+4(%ecx) - - /* - * TODO: may need to add a kludge factor to account for all the cycles - * burned in VMLOAD, VMSAVE, VMRUN... - */ - - popl %eax - popl %edx - #endif - movl VCPU_svm_vmcb_pa(%ebx), %eax popl %ebx popl %ecx @@ -150,31 +117,7 @@ ENTRY(svm_asm_do_launch) VMSAVE /* eax is the only register we're allowed to touch here... */ -#if DO_FPUSAVE - mov %cr0, %eax - push %eax - clts GET_CURRENT(%eax) - lea VCPU_arch_guest_fpu_ctxt(%eax), %eax - fxsave (%eax) - fnclex - pop %eax - mov %eax, %cr0 -#endif - - GET_CURRENT(%eax) - -#if (DO_TSC_OFFSET) - pushl %edx - pushl %ebx - movl %eax,%ebx - rdtsc - movl %eax,VCPU_svm_vmexit_tsc(%ebx) - movl %edx,VCPU_svm_vmexit_tsc+4(%ebx) - movl %ebx,%eax - popl %ebx - popl %edx -#endif movl VCPU_svm_hsa_pa(%eax), %eax VMLOAD From 4a8c3511f17ffca649784faa659d7745d10c21c6 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Wed, 1 Mar 2006 23:39:43 +0100 Subject: [PATCH 05/12] Add SVM 32bit msr support (combined both 32bit with 64bit functions) and enable vlapic for 64bit. Signed-off-by: Tom Woller --- xen/arch/x86/hvm/svm/svm.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 345aca07d6..0b2a6765f1 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -247,6 +247,7 @@ void svm_load_msrs(void) void svm_restore_msrs(struct vcpu *v) { } +#endif #define IS_CANO_ADDRESS(add) 1 @@ -297,8 +298,13 @@ static inline int long_mode_do_msr_read(struct cpu_user_regs *regs) return 0; } +#ifdef __x86_64__ HVM_DBG_LOG(DBG_LEVEL_2, "mode_do_msr_read: msr_content: %lx\n", msr_content); +#else + HVM_DBG_LOG(DBG_LEVEL_2, "mode_do_msr_read: msr_content: %llx\n", + msr_content); +#endif regs->eax = msr_content & 0xffffffff; regs->edx = msr_content >> 32; @@ -311,12 +317,18 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs) struct vcpu *vc = current; struct vmcb_struct *vmcb = vc->arch.hvm_svm.vmcb; +#ifdef __x86_64__ HVM_DBG_LOG(DBG_LEVEL_1, "mode_do_msr_write msr %lx msr_content %lx\n", regs->ecx, msr_content); +#else + HVM_DBG_LOG(DBG_LEVEL_1, "mode_do_msr_write msr %x msr_content %llx\n", + regs->ecx, msr_content); +#endif switch (regs->ecx) { case MSR_EFER: +#ifdef __x86_64__ if ((msr_content & EFER_LME) ^ test_bit(SVM_CPU_STATE_LME_ENABLED, &vc->arch.hvm_svm.cpu_state)) { @@ -337,6 +349,7 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs) if ((msr_content ^ vmcb->efer) & EFER_LME) msr_content &= ~EFER_LME; /* No update for LME/LMA since it have no effect */ +#endif vmcb->efer = msr_content | EFER_SVME; break; @@ -383,18 +396,6 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs) return 1; } -#else -static inline int long_mode_do_msr_read(struct cpu_user_regs *regs) -{ - return 0; -} - -static inline int long_mode_do_msr_write(struct cpu_user_regs *regs) -{ - return 0; -} -#endif - void svm_store_cpu_guest_ctrl_regs(struct vcpu *v, unsigned long crs[8]) { struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; @@ -937,10 +938,8 @@ static void svm_vmexit_do_cpuid(struct vmcb_struct *vmcb, unsigned long input, if (input == 1) { -#ifndef __x86_64__ if ( hvm_apic_support(v->domain) && !vlapic_global_enabled((VLAPIC(v))) ) -#endif clear_bit(X86_FEATURE_APIC, &edx); #if CONFIG_PAGING_LEVELS < 3 From af77e81a1ca6ff7566310ccc017b110e04d59de2 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Wed, 1 Mar 2006 23:41:43 +0100 Subject: [PATCH 06/12] Fix problems with HVM PAE guests with >4GB memory. Signed-off-by: Xiaohui Xin Signed-off-by: Jun Nakajima --- xen/arch/x86/shadow.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xen/arch/x86/shadow.c b/xen/arch/x86/shadow.c index 410dc5812f..6ed126eb96 100644 --- a/xen/arch/x86/shadow.c +++ b/xen/arch/x86/shadow.c @@ -279,8 +279,8 @@ alloc_shadow_page(struct domain *d, psh_type == PGT_l4_shadow ) /* allocated for PAE PDP page */ page = alloc_domheap_pages(NULL, 0, ALLOC_DOM_DMA); else if ( d->arch.ops->guest_paging_levels == PAGING_L3 && - psh_type == PGT_l3_shadow ) /* allocated for PAE PDP page */ - page = alloc_domheap_pages(NULL, 0, ALLOC_DOM_DMA); + (psh_type == PGT_l3_shadow || psh_type == PGT_l4_shadow) ) + page = alloc_domheap_pages(NULL, 0, ALLOC_DOM_DMA); /* allocated for PAE PDP page */ else page = alloc_domheap_page(NULL); #endif From 4749c682b0e652d9dfa831eeb7ad7eafbed218eb Mon Sep 17 00:00:00 2001 From: "emellor@leeni.uk.xensource.com" Date: Thu, 2 Mar 2006 01:59:28 +0100 Subject: [PATCH 07/12] Avoid a race between Xend removing the vm entries corresponding to a domain, and the hotplug scripts checking whether that domain is still alive. This triggers the "xenstore-read: couldn't read path /local/domain/107/vm" message in /var/log/xen-hotplug.log, followed by "Device XYZ is mounted in a guest domain and so cannot be mounted now". Closes bug #514. Signed-off-by: Ewan Mellor --- tools/examples/block | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/examples/block b/tools/examples/block index b6a374c3c4..e73ab9c8bf 100644 --- a/tools/examples/block +++ b/tools/examples/block @@ -129,7 +129,14 @@ check_sharing() same_vm() { local otherdom="$1" - local othervm=$(xenstore-read "/local/domain/$otherdom/vm") + # Note that othervm can be MISSING here, because Xend will be racing with + # the hotplug scripts -- the entries in /local/domain can be removed by + # Xend before the hotplug scripts have removed the entry in + # /local/domain/0/backend/. In this case, we want to pretend that the + # VM is the same as FRONTEND_UUID, because that way the 'sharing' will be + # allowed. + local othervm=$(xenstore_read_default "/local/domain/$otherdom/vm" \ + "$FRONTEND_UUID") [ "$FRONTEND_UUID" == "$othervm" ] } From 8920f45cc8bbbad7fdf478673f8119adda58cfa0 Mon Sep 17 00:00:00 2001 From: "emellor@leeni.uk.xensource.com" Date: Thu, 2 Mar 2006 02:01:17 +0100 Subject: [PATCH 08/12] Silence the messages that are emitted when removing nodes that already have been removed. This is fine, in a cleanup script. Signed-off-by: Ewan Mellor --- tools/examples/xen-hotplug-cleanup | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/examples/xen-hotplug-cleanup b/tools/examples/xen-hotplug-cleanup index 4e9c0ca735..6356a91892 100644 --- a/tools/examples/xen-hotplug-cleanup +++ b/tools/examples/xen-hotplug-cleanup @@ -12,10 +12,11 @@ dir=$(dirname "$0") claim_lock "block" # remove device frontend store entries -xenstore-rm -t $(xenstore-read "$XENBUS_PATH/frontend") || true +xenstore-rm -t \ + $(xenstore-read "$XENBUS_PATH/frontend" 2>/dev/null) 2>/dev/null || true # remove device backend store entries -xenstore-rm -t "$XENBUS_PATH" || true -xenstore-rm -t "error/$XENBUS_PATH" || true +xenstore-rm -t "$XENBUS_PATH" 2>/dev/null || true +xenstore-rm -t "error/$XENBUS_PATH" 2>/dev/null || true release_lock "block" From 06d17943f0cd4f1386e2dfbfbffa3e29bd458b10 Mon Sep 17 00:00:00 2001 From: "emellor@leeni.uk.xensource.com" Date: Thu, 2 Mar 2006 02:09:23 +0100 Subject: [PATCH 09/12] Added a basic integrity checker, and some basic ability to recover from store corruption, rather than just spewing error messages and exiting. Added a xenstore-control executable, which sends commands to xenstored. Currently, the only command is 'check', which triggers an integrity check. (The integrity check is also triggered whenever a corrupted store is detected). Signed-off-by: Ewan Mellor --- .hgignore | 1 + tools/xenstore/Makefile | 18 +++- tools/xenstore/xenstore_control.c | 28 +++++ tools/xenstore/xenstored_core.c | 171 ++++++++++++++++++++++-------- tools/xenstore/xenstored_core.h | 4 - 5 files changed, 169 insertions(+), 53 deletions(-) create mode 100644 tools/xenstore/xenstore_control.c diff --git a/.hgignore b/.hgignore index 1d6138311f..3e0b2e8974 100644 --- a/.hgignore +++ b/.hgignore @@ -166,6 +166,7 @@ ^tools/xenstore/xenstore-read$ ^tools/xenstore/xenstore-rm$ ^tools/xenstore/xenstore-write$ +^tools/xenstore/xenstore-control$ ^tools/xenstore/xenstore-ls$ ^tools/xenstore/xenstored$ ^tools/xenstore/xenstored_test$ diff --git a/tools/xenstore/Makefile b/tools/xenstore/Makefile index a6ba3ee2dc..ea50b86acc 100644 --- a/tools/xenstore/Makefile +++ b/tools/xenstore/Makefile @@ -27,7 +27,10 @@ CLIENTS := xenstore-exists xenstore-list xenstore-read xenstore-rm CLIENTS += xenstore-write CLIENTS_OBJS := $(patsubst xenstore-%,xenstore_%.o,$(CLIENTS)) -all: libxenstore.so xenstored $(CLIENTS) xs_tdb_dump xenstore-ls +all: libxenstore.so xenstored $(CLIENTS) xs_tdb_dump xenstore-control xenstore-ls + +test_interleaved_transactions: test_interleaved_transactions.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -L. -lxenstore -o $@ testcode: xs_test xenstored_test xs_random @@ -35,13 +38,16 @@ xenstored: xenstored_core.o xenstored_watch.o xenstored_domain.o xenstored_trans $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -lxenctrl -o $@ $(CLIENTS): xenstore-%: xenstore_%.o libxenstore.so - $(LINK.o) $< $(LOADLIBES) $(LDLIBS) -lxenctrl -L. -lxenstore -o $@ + $(LINK.o) $< $(LOADLIBES) $(LDLIBS) -L. -lxenstore -o $@ $(CLIENTS_OBJS): xenstore_%.o: xenstore_client.c $(COMPILE.c) -DCLIENT_$(*F) -o $@ $< +xenstore-control: xenstore_control.o libxenstore.so + $(LINK.o) $< $(LOADLIBES) $(LDLIBS) -L. -lxenstore -o $@ + xenstore-ls: xsls.o libxenstore.so - $(LINK.o) $< $(LOADLIBES) $(LDLIBS) -lxenctrl -L. -lxenstore -o $@ + $(LINK.o) $< $(LOADLIBES) $(LDLIBS) -L. -lxenstore -o $@ xenstored_test: xenstored_core_test.o xenstored_watch_test.o xenstored_domain_test.o xenstored_transaction_test.o xs_lib.o talloc_test.o fake_libxc.o utils.o tdb.o $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ @@ -77,7 +83,8 @@ libxenstore.so: xs.opic xs_lib.opic clean: testsuite-clean rm -f *.o *.opic *.so rm -f xenstored xs_random xs_stress xs_crashme - rm -f xs_test xenstored_test xs_tdb_dump xenstore-ls $(CLIENTS) + rm -f xs_test xenstored_test xs_tdb_dump xenstore-control xenstore-ls + rm -f $(CLIENTS) $(RM) $(PROG_DEP) print-dir: @@ -129,7 +136,7 @@ TAGS: tarball: clean cd .. && tar -c -j -v -h -f xenstore.tar.bz2 xenstore/ -install: libxenstore.so xenstored xenstore-ls $(CLIENTS) +install: all $(INSTALL_DIR) -p $(DESTDIR)/var/run/xenstored $(INSTALL_DIR) -p $(DESTDIR)/var/lib/xenstored $(INSTALL_DIR) -p $(DESTDIR)/usr/bin @@ -137,6 +144,7 @@ install: libxenstore.so xenstored xenstore-ls $(CLIENTS) $(INSTALL_DIR) -p $(DESTDIR)/usr/include $(INSTALL_PROG) xenstored $(DESTDIR)/usr/sbin $(INSTALL_PROG) $(CLIENTS) $(DESTDIR)/usr/bin + $(INSTALL_PROG) xenstore-control $(DESTDIR)/usr/bin $(INSTALL_PROG) xenstore-ls $(DESTDIR)/usr/bin $(INSTALL_DIR) -p $(DESTDIR)/usr/$(LIBDIR) $(INSTALL_DATA) libxenstore.so $(DESTDIR)/usr/$(LIBDIR) diff --git a/tools/xenstore/xenstore_control.c b/tools/xenstore/xenstore_control.c new file mode 100644 index 0000000000..80685c59d7 --- /dev/null +++ b/tools/xenstore/xenstore_control.c @@ -0,0 +1,28 @@ +#include +#include +#include + +#include "xs.h" + + +int main(int argc, char **argv) +{ + if (argc < 2 || + strcmp(argv[1], "check")) + { + fprintf(stderr, + "Usage:\n" + "\n" + " %s check\n" + "\n", argv[0]); + return 2; + } + + struct xs_handle * xsh = xs_daemon_open(); + + xs_debug_command(xsh, argv[1], NULL, 0); + + xs_daemon_close(xsh); + + return 0; +} diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c index f9629626d9..a88d09efa7 100644 --- a/tools/xenstore/xenstored_core.c +++ b/tools/xenstore/xenstored_core.c @@ -60,6 +60,18 @@ static int reopen_log_pipe[2]; static char *tracefile = NULL; static TDB_CONTEXT *tdb_ctx; +static void corrupt(struct connection *conn, const char *fmt, ...); +static void check_store(); + +#define log(...) \ + do { \ + char *s = talloc_asprintf(NULL, __VA_ARGS__); \ + trace("%s\n", s); \ + syslog(LOG_ERR, "%s", s); \ + talloc_free(s); \ + } while (0) + + #ifdef TESTING static bool failtest = false; @@ -104,33 +116,6 @@ int test_mkdir(const char *dir, int perms) #include "xenstored_test.h" -/* FIXME: Ideally, this should never be called. Some can be eliminated. */ -/* Something is horribly wrong: shutdown immediately. */ -void __attribute__((noreturn)) corrupt(struct connection *conn, - const char *fmt, ...) -{ - va_list arglist; - char *str; - int saved_errno = errno; - - va_start(arglist, fmt); - str = talloc_vasprintf(NULL, fmt, arglist); - va_end(arglist); - - trace("xenstored corruption: connection id %i: err %s: %s", - conn ? (int)conn->id : -1, strerror(saved_errno), str); - eprintf("xenstored corruption: connection id %i: err %s: %s", - conn ? (int)conn->id : -1, strerror(saved_errno), str); -#ifdef TESTING - /* Allow them to attach debugger. */ - sleep(30); -#endif - syslog(LOG_DAEMON, - "xenstored corruption: connection id %i: err %s: %s", - conn ? (int)conn->id : -1, strerror(saved_errno), str); - _exit(2); -} - TDB_CONTEXT *tdb_context(struct connection *conn) { /* conn = NULL used in manual_node at setup. */ @@ -216,7 +201,8 @@ static void trace_io(const struct connection *conn, now = time(NULL); tm = localtime(&now); - trace("%s %p %02d:%02d:%02d %s (", prefix, conn, + trace("%s %p %p %04d%02d%02d %02d:%02d:%02d %s (", prefix, conn, + conn->transaction, tm->year + 1900, tm->mon + 1, tm->mday, tm->tm_hour, tm->tm_min, tm->tm_sec, sockmsg_string(data->hdr.msg.type)); @@ -837,8 +823,6 @@ static int destroy_node(void *_node) return 0; } -/* Be careful: create heirarchy, put entry in existing parent *last*. - * This helps fsck if we die during this. */ static struct node *create_node(struct connection *conn, const char *name, void *data, unsigned int datalen) @@ -939,8 +923,9 @@ static void delete_node(struct connection *conn, struct node *node) { unsigned int i; - /* Delete self, then delete children. If something goes wrong, - * consistency check will clean up this way. */ + /* Delete self, then delete children. If we crash, then the worst + that can happen is the children will continue to take up space, but + will otherwise be unreachable. */ delete_node_single(conn, node); /* Delete children, too. */ @@ -950,9 +935,14 @@ static void delete_node(struct connection *conn, struct node *node) child = read_node(conn, talloc_asprintf(node, "%s/%s", node->name, node->children + i)); - if (!child) - corrupt(conn, "No child '%s' found", child); - delete_node(conn, child); + if (child) { + delete_node(conn, child); + } + else { + trace("delete_node: No child '%s/%s' found!\n", + node->name, node->children + i); + /* Skip it, we've already deleted the parent. */ + } } } @@ -976,12 +966,15 @@ static bool delete_child(struct connection *conn, } } corrupt(conn, "Can't find child '%s' in %s", childname, node->name); + return false; } static int _rm(struct connection *conn, struct node *node, const char *name) { - /* Delete from parent first, then if something explodes fsck cleans. */ + /* Delete from parent first, then if we crash, the worst that can + happen is the child will continue to take up space, but will + otherwise be unreachable. */ struct node *parent = read_node(conn, get_parent(name)); if (!parent) { send_error(conn, EINVAL); @@ -1000,10 +993,11 @@ static int _rm(struct connection *conn, struct node *node, const char *name) static void internal_rm(const char *name) { - char *tname = talloc_strdup(talloc_autofree_context(), name); + char *tname = talloc_strdup(NULL, name); struct node *node = read_node(NULL, tname); if (node) _rm(NULL, node, tname); + talloc_free(tname); } @@ -1149,18 +1143,19 @@ static void process_message(struct connection *conn, struct buffered_data *in) case XS_DEBUG: if (streq(in->buffer, "print")) xprintf("debug: %s", in->buffer + get_string(in, 0)); + if (streq(in->buffer, "check")) + check_store(); #ifdef TESTING /* For testing, we allow them to set id. */ if (streq(in->buffer, "setid")) { conn->id = atoi(in->buffer + get_string(in, 0)); - send_ack(conn, XS_DEBUG); } else if (streq(in->buffer, "failtest")) { if (get_string(in, 0) < in->used) srandom(atoi(in->buffer + get_string(in, 0))); - send_ack(conn, XS_DEBUG); failtest = true; } #endif /* TESTING */ + send_ack(conn, XS_DEBUG); break; case XS_WATCH: @@ -1258,7 +1253,7 @@ static void handle_input(struct connection *conn) if (in->hdr.msg.len > PATH_MAX) { #ifndef TESTING - syslog(LOG_DAEMON, "Client tried to feed us %i", + syslog(LOG_ERR, "Client tried to feed us %i", in->hdr.msg.len); #endif goto bad_client; @@ -1425,10 +1420,16 @@ static void setup_structure(void) balloon driver will pick up stale entries. In the case of the balloon driver, this can be fatal. */ - char *tlocal = talloc_strdup(talloc_autofree_context(), - "/local"); + char *tlocal = talloc_strdup(NULL, "/local"); + + check_store(); + internal_rm("/local"); create_node(NULL, tlocal, NULL, 0); + + talloc_free(tlocal); + + check_store(); } else { tdb_ctx = tdb_open(tdbname, 7919, TDB_FLAGS, O_RDWR|O_CREAT, @@ -1439,11 +1440,93 @@ static void setup_structure(void) manual_node("/", "tool"); manual_node("/tool", "xenstored"); manual_node("/tool/xenstored", NULL); - } - /* FIXME: Fsck */ + check_store(); + } } +static char *child_name(const char *s1, const char *s2) +{ + if (strcmp(s1, "/")) { + return talloc_asprintf(NULL, "%s/%s", s1, s2); + } + else { + return talloc_asprintf(NULL, "/%s", s2); + } +} + +static void check_store_(const char *name) +{ + struct node *node = read_node(NULL, name); + + if (node) { + size_t i = 0; + + while (i < node->childlen) { + size_t childlen = strlen(node->children + i); + char * childname = child_name(node->name, + node->children + i); + struct node *childnode = read_node(NULL, childname); + + if (childnode) { + check_store_(childname); + i += childlen + 1; + } + else { + log("check_store: No child '%s' found!\n", + childname); + + memdel(node->children, i, childlen + 1, + node->childlen); + node->childlen -= childlen + 1; + write_node(NULL, node); + } + + talloc_free(childname); + } + } + else { + /* Impossible, because no database should ever be without the + root, and otherwise, we've just checked in our caller + (which made a recursive call to get here). */ + + log("check_store: No child '%s' found: impossible!", name); + } +} + + +static void check_store() +{ + char * root = talloc_strdup(NULL, "/"); + log("Checking store ..."); + check_store_(root); + log("Checking store complete."); + talloc_free(root); +} + + +/* Something is horribly wrong: check the store. */ +static void corrupt(struct connection *conn, const char *fmt, ...) +{ + va_list arglist; + char *str; + int saved_errno = errno; + + va_start(arglist, fmt); + str = talloc_vasprintf(NULL, fmt, arglist); + va_end(arglist); + + log("corruption detected by connection %i: err %s: %s", + conn ? (int)conn->id : -1, strerror(saved_errno), str); + +#ifdef TESTING + /* Allow them to attach debugger. */ + sleep(30); +#endif + check_store(); +} + + static void write_pidfile(const char *pidfile) { char buf[100]; diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h index da98a9211d..090f54a846 100644 --- a/tools/xenstore/xenstored_core.h +++ b/tools/xenstore/xenstored_core.h @@ -148,10 +148,6 @@ int destroy_tdb(void *_tdb); /* Replace the tdb: required for transaction code */ bool replace_tdb(const char *newname, TDB_CONTEXT *newtdb); -/* Fail due to excessive corruption, capitalist pigdogs! */ -void __attribute__((noreturn)) corrupt(struct connection *conn, - const char *fmt, ...); - struct connection *new_connection(connwritefn_t *write, connreadfn_t *read); From 03d3577c361217d3e875cd686fb0cf1fd21808ec Mon Sep 17 00:00:00 2001 From: "emellor@leeni.uk.xensource.com" Date: Thu, 2 Mar 2006 02:35:23 +0100 Subject: [PATCH 10/12] Fix printf. Signed-off-by: Ewan Mellor --- tools/xenstore/xenstored_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c index a88d09efa7..7c23e12c11 100644 --- a/tools/xenstore/xenstored_core.c +++ b/tools/xenstore/xenstored_core.c @@ -202,8 +202,8 @@ static void trace_io(const struct connection *conn, tm = localtime(&now); trace("%s %p %p %04d%02d%02d %02d:%02d:%02d %s (", prefix, conn, - conn->transaction, tm->year + 1900, tm->mon + 1, tm->mday, - tm->tm_hour, tm->tm_min, tm->tm_sec, + conn->transaction, tm->tm_year + 1900, tm->tm_mon + 1, + tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, sockmsg_string(data->hdr.msg.type)); for (i = 0; i < data->hdr.msg.len; i++) From dcb858b08945b5efc87c22eb356bc417514bd042 Mon Sep 17 00:00:00 2001 From: "vhanquez@kneesa.uk.xensource.com" Date: Thu, 2 Mar 2006 02:14:45 +0000 Subject: [PATCH 11/12] Removing out-of-date unused file. current code available in io/xs_wire.h Signed-off-by: Vincent Hanquez --- .../include/xen/public/xenstored.h | 89 ------------------- 1 file changed, 89 deletions(-) delete mode 100644 linux-2.6-xen-sparse/include/xen/public/xenstored.h diff --git a/linux-2.6-xen-sparse/include/xen/public/xenstored.h b/linux-2.6-xen-sparse/include/xen/public/xenstored.h deleted file mode 100644 index 3633e5eb74..0000000000 --- a/linux-2.6-xen-sparse/include/xen/public/xenstored.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Simple prototyle Xen Store Daemon providing simple tree-like database. - * Copyright (C) 2005 Rusty Russell IBM Corporation - * - * This file may be distributed separately from the Linux kernel, or - * incorporated into other software packages, subject to the following license: - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this source file (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#ifndef _XENSTORED_H -#define _XENSTORED_H - -enum xsd_sockmsg_type -{ - XS_DEBUG, - XS_SHUTDOWN, - XS_DIRECTORY, - XS_READ, - XS_GET_PERMS, - XS_WATCH, - XS_WATCH_ACK, - XS_UNWATCH, - XS_TRANSACTION_START, - XS_TRANSACTION_END, - XS_OP_READ_ONLY = XS_TRANSACTION_END, - XS_INTRODUCE, - XS_RELEASE, - XS_GET_DOMAIN_PATH, - XS_WRITE, - XS_MKDIR, - XS_RM, - XS_SET_PERMS, - XS_WATCH_EVENT, - XS_ERROR, -}; - -#define XS_WRITE_NONE "NONE" -#define XS_WRITE_CREATE "CREATE" -#define XS_WRITE_CREATE_EXCL "CREATE|EXCL" - -/* We hand errors as strings, for portability. */ -struct xsd_errors -{ - int errnum; - const char *errstring; -}; -#define XSD_ERROR(x) { x, #x } -static struct xsd_errors xsd_errors[] __attribute__((unused)) = { - XSD_ERROR(EINVAL), - XSD_ERROR(EACCES), - XSD_ERROR(EEXIST), - XSD_ERROR(EISDIR), - XSD_ERROR(ENOENT), - XSD_ERROR(ENOMEM), - XSD_ERROR(ENOSPC), - XSD_ERROR(EIO), - XSD_ERROR(ENOTEMPTY), - XSD_ERROR(ENOSYS), - XSD_ERROR(EROFS), - XSD_ERROR(EBUSY), - XSD_ERROR(EAGAIN), - XSD_ERROR(EISCONN), -}; -struct xsd_sockmsg -{ - u32 type; - u32 len; /* Length of data following this. */ - - /* Generally followed by nul-terminated string(s). */ -}; - -#endif /* _XENSTORED_H */ From 343da423ced783d9d666ae9f64e70e53258cb8f4 Mon Sep 17 00:00:00 2001 From: "emellor@leeni.uk.xensource.com" Date: Thu, 2 Mar 2006 03:21:17 +0100 Subject: [PATCH 12/12] Fix violation of C90 mixed-code-and-declarations restriction. Signed-off-by: Ewan Mellor --- tools/xenstore/xenstore_control.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/xenstore/xenstore_control.c b/tools/xenstore/xenstore_control.c index 80685c59d7..5433bfc811 100644 --- a/tools/xenstore/xenstore_control.c +++ b/tools/xenstore/xenstore_control.c @@ -7,6 +7,8 @@ int main(int argc, char **argv) { + struct xs_handle * xsh; + if (argc < 2 || strcmp(argv[1], "check")) { @@ -18,7 +20,7 @@ int main(int argc, char **argv) return 2; } - struct xs_handle * xsh = xs_daemon_open(); + xsh = xs_daemon_open(); xs_debug_command(xsh, argv[1], NULL, 0);