From 571c447f7e4d3cbb9a8e4c5c0e83240a83b4e074 Mon Sep 17 00:00:00 2001 From: "ach61@arcadians.cl.cam.ac.uk" Date: Mon, 13 Jun 2005 14:19:41 +0000 Subject: [PATCH 01/25] bitkeeper revision 1.1713.1.3 (42ad95fdAjhhuDM4A-oDzz_3fc_elA) export evtchn irq symbols --- linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c b/linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c index 4e8db3e003..7019e33687 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c +++ b/linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c @@ -47,6 +47,8 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) EXPORT_SYMBOL(force_evtchn_callback); EXPORT_SYMBOL(evtchn_do_upcall); +EXPORT_SYMBOL(bind_evtchn_to_irq); +EXPORT_SYMBOL(unbind_evtchn_from_irq); #endif /* From 4def5ac864f2736b780010ccf931b3c57f676a9e Mon Sep 17 00:00:00 2001 From: "vh249@arcadians.cl.cam.ac.uk" Date: Mon, 13 Jun 2005 15:39:51 +0000 Subject: [PATCH 02/25] bitkeeper revision 1.1713.1.4 (42ada8c7SOk12pe5FJtQjpPwNus87g) fix x86-64 compilation with CONFIG_SMP Signed-off-by: Vincent Hanquez --- linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/entry.S | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/entry.S b/linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/entry.S index 3f28d0e04e..3b1504f58e 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/entry.S +++ b/linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/entry.S @@ -67,9 +67,9 @@ VGCF_IN_SYSCALL = (1<<8) #define preempt_disable(reg) incl TI_preempt_count(reg) #define preempt_enable(reg) decl TI_preempt_count(reg) #define XEN_LOCK_VCPU_INFO_SMP(reg) preempt_disable(%rbp) ; \ - movl TI_cpu(%rbp),reg ; \ + movq TI_cpu(%rbp),reg ; \ shl $sizeof_vcpu_shift,reg ; \ - addl HYPERVISOR_shared_info,reg + addq HYPERVISOR_shared_info,reg #define XEN_UNLOCK_VCPU_INFO_SMP(reg) preempt_enable(%rbp) #define XEN_UNLOCK_VCPU_INFO_SMP_fixup .byte 0xff,0xff,0xff #define Ux00 0xff @@ -80,7 +80,7 @@ VGCF_IN_SYSCALL = (1<<8) #define XEN_UNBLOCK_EVENTS(reg) XEN_LOCK_VCPU_INFO_SMP(reg) ; \ movb $0,evtchn_upcall_mask(reg) ; \ XEN_UNLOCK_VCPU_INFO_SMP(reg) -#define XEN_SAVE_UPCALL_MASK(reg,tmp,off) GET_THREAD_INFO(%ebp) ; \ +#define XEN_SAVE_UPCALL_MASK(reg,tmp,off) GET_THREAD_INFO(%rbp) ; \ XEN_LOCK_VCPU_INFO_SMP(reg) ; \ movb evtchn_upcall_mask(reg), tmp ; \ movb tmp, off(%rsp) ; \ From 16e23b02c2f1a7a8d7e5a7c37d717f436ae727d2 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 13 Jun 2005 22:48:36 +0000 Subject: [PATCH 03/25] bitkeeper revision 1.1713.1.5 (42ae0d44bPpuSBR0o475OuEOeDlNPg) Fix xs Python module for Python <2.3. Signed-off-by: Keir Fraser --- tools/python/xen/lowlevel/xs/xs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/python/xen/lowlevel/xs/xs.c b/tools/python/xen/lowlevel/xs/xs.c index 6ecddc6fd4..0da0fbcb3e 100644 --- a/tools/python/xen/lowlevel/xs/xs.c +++ b/tools/python/xen/lowlevel/xs/xs.c @@ -14,9 +14,9 @@ */ /* Needed for Python versions earlier than 2.3. */ -//#ifndef PyMODINIT_FUNC -//#define PyMODINIT_FUNC DL_EXPORT(void) -//#endif +#ifndef PyMODINIT_FUNC +#define PyMODINIT_FUNC DL_EXPORT(void) +#endif #define PYPKG "xen.lowlevel.xs" From 264c8b7aac4d2c7ab164b35faca8073c114a3174 Mon Sep 17 00:00:00 2001 From: "arun.sharma@intel.com[kaf24]" Date: Mon, 13 Jun 2005 22:49:32 +0000 Subject: [PATCH 04/25] bitkeeper revision 1.1713.1.6 (42ae0d7cI1fdGe88s6RyEx8d0oy2wg) [PATCH] x64-vmxassist-fix2.patch Fix 64 bit build. Tested the binary built on a 64 bit platform on a 32 bit platform. Signed-off-by: Arun Sharma --- tools/firmware/vmxassist/Makefile | 14 +++++++++++--- tools/firmware/vmxassist/head.S | 1 + tools/firmware/vmxassist/trap.S | 3 ++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/tools/firmware/vmxassist/Makefile b/tools/firmware/vmxassist/Makefile index 545acdf743..a9b142363c 100644 --- a/tools/firmware/vmxassist/Makefile +++ b/tools/firmware/vmxassist/Makefile @@ -18,6 +18,9 @@ # Place - Suite 330, Boston, MA 02111-1307 USA. # +XEN_ROOT = ../../.. +include $(XEN_ROOT)/tools/Rules.mk + # The emulator code lives in ROM space TEXTADDR=0x000D0000 DEFINES=-DDEBUG -DTEXTADDR=${TEXTADDR} @@ -32,19 +35,24 @@ CPP=cpp -P OBJCOPY=objcopy -p -O binary -R .note -R .comment -R .bss -S --gap-fill=0 CFLAGS=${DEFINES} -I. $(XENINC) -Wall -fno-builtin -O2 -msoft-float +ifeq ($(XEN_COMPILE_ARCH),x86_64) +CFLAGS += -m32 -march=i686 +LDFLAGS += -m elf_i386 +endif + OBJECTS = head.o trap.o vm86.o setup.o util.o all: vmxloader vmxloader: roms.h vmxloader.c - ${CC} ${DEFINES} -c vmxloader.c - $(CC) -o vmxloader.tmp -nostdlib -Wl,-N -Wl,-Ttext -Wl,0x100000 vmxloader.o + ${CC} ${CFLAGS} ${DEFINES} -c vmxloader.c + $(CC) -o vmxloader.tmp -m32 -nostdlib -Wl,-N -Wl,-Ttext -Wl,0x100000 vmxloader.o objcopy --change-addresses=0xC0000000 vmxloader.tmp vmxloader rm -f vmxloader.tmp vmxassist.bin: vmxassist.ld ${OBJECTS} ${CPP} ${DEFINES} vmxassist.ld > vmxassist.tmp - ${LD} -o vmxassist -nostdlib --fatal-warnings -N -T vmxassist.tmp ${OBJECTS} + ${LD} -o vmxassist ${LDFLAGS} -nostdlib --fatal-warnings -N -T vmxassist.tmp ${OBJECTS} nm -n vmxassist > vmxassist.sym ${OBJCOPY} vmxassist vmxassist.tmp dd if=vmxassist.tmp of=vmxassist.bin ibs=512 conv=sync diff --git a/tools/firmware/vmxassist/head.S b/tools/firmware/vmxassist/head.S index a657e64740..1541a1c8e9 100644 --- a/tools/firmware/vmxassist/head.S +++ b/tools/firmware/vmxassist/head.S @@ -106,6 +106,7 @@ rom_gdtr: * main and setup our own environment. */ .globl _start + .code32 _start: cli diff --git a/tools/firmware/vmxassist/trap.S b/tools/firmware/vmxassist/trap.S index a469f68fc8..e4294e88c2 100644 --- a/tools/firmware/vmxassist/trap.S +++ b/tools/firmware/vmxassist/trap.S @@ -20,7 +20,6 @@ #include "machine.h" #include "offsets.h" - /* * All processor exception/faults/interrupts end up here. * @@ -43,6 +42,7 @@ .endm .section .rodata + .code32 .align 4 .global trap_handlers trap_handlers: @@ -96,6 +96,7 @@ trap_handlers: TRAP_HANDLER 47, 0 /* irq 15 */ .text + .code32 .align 16 common_trap: /* common trap handler */ pushl %gs From 2d0fe9c80f2db0cce0318eb953a9ce732ba2b9b4 Mon Sep 17 00:00:00 2001 From: "chrisw@osdl.org[kaf24]" Date: Mon, 13 Jun 2005 22:51:02 +0000 Subject: [PATCH 05/25] bitkeeper revision 1.1713.1.7 (42ae0dd6jIaFvKcbyu8YLCgOrZScdg) [PATCH] [PATCH] fix x86_64 initrd support * Chris Wright (chrisw@osdl.org) wrote: Ugh, that one had some tab damage, here's the proper patch. -chris --- .../arch/xen/x86_64/kernel/setup.c | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/setup.c b/linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/setup.c index 8951d61c2a..72d4cd59e4 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/setup.c +++ b/linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/setup.c @@ -727,23 +727,20 @@ void __init setup_arch(char **cmdline_p) acpi_reserve_bootmem(); #endif #ifdef CONFIG_BLK_DEV_INITRD - if (xen_start_info.mod_start) { - if (LOADER_TYPE && INITRD_START) { - if (INITRD_START + INITRD_SIZE <= (end_pfn << PAGE_SHIFT)) { - /* reserve_bootmem_generic(INITRD_START, INITRD_SIZE); */ - initrd_start = INITRD_START + PAGE_OFFSET; - initrd_end = initrd_start+INITRD_SIZE; - initrd_below_start_ok = 1; - } - else { - printk(KERN_ERR "initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx)\ndisabling initrd\n", - (unsigned long)(INITRD_START + INITRD_SIZE), - (unsigned long)(end_pfn << PAGE_SHIFT)); - initrd_start = 0; - } - } - } + if (xen_start_info.mod_start) { + if (INITRD_START + INITRD_SIZE <= (end_pfn << PAGE_SHIFT)) { + /*reserve_bootmem_generic(INITRD_START, INITRD_SIZE);*/ + initrd_start = INITRD_START + PAGE_OFFSET; + initrd_end = initrd_start+INITRD_SIZE; + initrd_below_start_ok = 1; + } else { + printk(KERN_ERR "initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + (unsigned long)(INITRD_START + INITRD_SIZE), + (unsigned long)(end_pfn << PAGE_SHIFT)); + initrd_start = 0; + } + } #endif paging_init(); #ifdef CONFIG_X86_LOCAL_APIC From 0e6cf5a2afd0b58a6538a85c47430e78f313ef2d Mon Sep 17 00:00:00 2001 From: "arun.sharma@intel.com[kaf24]" Date: Tue, 14 Jun 2005 13:06:33 +0000 Subject: [PATCH 06/25] bitkeeper revision 1.1713.1.8 (42aed659DzIwFCeaK8Cxa8ZpzbHR-Q) [PATCH] 64-session-id.patch session_id is an opaque pointer, so should be wider on 64 bit platforms. Signed-off-by: Kevin Tian Signed-off-by: Arun Sharma --- tools/python/xen/lowlevel/xu/xu.c | 2 +- tools/xcs/xcs_proto.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/python/xen/lowlevel/xu/xu.c b/tools/python/xen/lowlevel/xu/xu.c index 65660ba6dc..cd616e75bc 100644 --- a/tools/python/xen/lowlevel/xu/xu.c +++ b/tools/python/xen/lowlevel/xu/xu.c @@ -72,7 +72,7 @@ static void set_cloexec(int fd) static int xcs_ctrl_fd = -1; /* control connection to the xcs server. */ static int xcs_data_fd = -1; /* data connection to the xcs server. */ -static u32 xcs_session_id = 0; +static unsigned long xcs_session_id = 0; static int xcs_ctrl_send(xcs_msg_t *msg); static int xcs_ctrl_read(xcs_msg_t *msg); diff --git a/tools/xcs/xcs_proto.h b/tools/xcs/xcs_proto.h index fa04621f40..7038467c90 100644 --- a/tools/xcs/xcs_proto.h +++ b/tools/xcs/xcs_proto.h @@ -40,7 +40,7 @@ #define TYPE_VIRQ 0xfffe typedef struct { - u32 session_id; + unsigned long session_id; } xcs_connect_msg_t; typedef struct { From 972a32cf6636266825d02a5730d81c339c14b659 Mon Sep 17 00:00:00 2001 From: "chrisw@osdl.org[kaf24]" Date: Tue, 14 Jun 2005 19:30:50 +0000 Subject: [PATCH 07/25] bitkeeper revision 1.1713.1.9 (42af306adOSGlJaEmolMoERc4oAXYg) [PATCH] x86_64 entry.S cleanup - take 3 This patch cleans up x86_64 entry.S. Namely, it updates the Xen relevant macros to be the simpler version that's found in i386. This means that: - XEN_[UN]BLOCK_EVENTS interface now takes care of dealing with SMP issues and is no longer conditionally defined - XEN_LOCKED_[UN]BLOCK_EVENTS is identical in both cases (SMP and UP) and no longer needs to be conditionally defined - XEN_[UN]LOCK_VPCU_INFO_SMP is dropped in favor of XEN_GET/PUT_VCPU_INFO This cleans up the code, minimizes the differences with i386 code, and lays the groundwork for SMP support (the real reason I did this ;-). It's booting, executing syscalls, taking interrupts, etc (it's what I'm using to send this e-mail). Signed-off-by: Chris Wright ===== linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/entry.S 1.10 vs edited ===== --- .../arch/xen/x86_64/kernel/entry.S | 75 +++++-------------- 1 file changed, 20 insertions(+), 55 deletions(-) diff --git a/linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/entry.S b/linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/entry.S index 3b1504f58e..e01fdd064a 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/entry.S +++ b/linux-2.6.11-xen-sparse/arch/xen/x86_64/kernel/entry.S @@ -63,42 +63,28 @@ VGCF_IN_SYSCALL = (1<<8) #define sizeof_vcpu_shift 3 #ifdef CONFIG_SMP -#define XEN_GET_VCPU_INFO(reg) -#define preempt_disable(reg) incl TI_preempt_count(reg) -#define preempt_enable(reg) decl TI_preempt_count(reg) -#define XEN_LOCK_VCPU_INFO_SMP(reg) preempt_disable(%rbp) ; \ - movq TI_cpu(%rbp),reg ; \ +#define preempt_disable(reg) incl threadinfo_preempt_count(reg) +#define preempt_enable(reg) decl threadinfo_preempt_count(reg) +#define XEN_GET_VCPU_INFO(reg) preempt_disable(%rbp) ; \ + movq %gs:pda_cpunumber,reg ; \ shl $sizeof_vcpu_shift,reg ; \ addq HYPERVISOR_shared_info,reg -#define XEN_UNLOCK_VCPU_INFO_SMP(reg) preempt_enable(%rbp) -#define XEN_UNLOCK_VCPU_INFO_SMP_fixup .byte 0xff,0xff,0xff -#define Ux00 0xff -#define XEN_LOCKED_BLOCK_EVENTS(reg) movb $1,evtchn_upcall_mask(reg) -#define XEN_BLOCK_EVENTS(reg) XEN_LOCK_VCPU_INFO_SMP(reg) ; \ - XEN_LOCKED_BLOCK_EVENTS(reg) ; \ - XEN_UNLOCK_VCPU_INFO_SMP(reg) -#define XEN_UNBLOCK_EVENTS(reg) XEN_LOCK_VCPU_INFO_SMP(reg) ; \ - movb $0,evtchn_upcall_mask(reg) ; \ - XEN_UNLOCK_VCPU_INFO_SMP(reg) -#define XEN_SAVE_UPCALL_MASK(reg,tmp,off) GET_THREAD_INFO(%rbp) ; \ - XEN_LOCK_VCPU_INFO_SMP(reg) ; \ - movb evtchn_upcall_mask(reg), tmp ; \ - movb tmp, off(%rsp) ; \ - XEN_UNLOCK_VCPU_INFO_SMP(reg) +#define XEN_PUT_VCPU_INFO(reg) preempt_enable(%rbp) ; \ +#define XEN_PUT_VCPU_INFO_fixup .byte 0xff,0xff,0xff #else #define XEN_GET_VCPU_INFO(reg) movq HYPERVISOR_shared_info,reg -#define XEN_LOCK_VCPU_INFO_SMP(reg) movq HYPERVISOR_shared_info,reg -#define XEN_UNLOCK_VCPU_INFO_SMP(reg) -#define XEN_UNLOCK_VCPU_INFO_SMP_fixup -#define Ux00 0x00 -#define XEN_LOCKED_BLOCK_EVENTS(reg) movb $1,evtchn_upcall_mask(reg) -#define XEN_BLOCK_EVENTS(reg) XEN_LOCKED_BLOCK_EVENTS(reg) -#define XEN_UNBLOCK_EVENTS(reg) movb $0,evtchn_upcall_mask(reg) -#define XEN_SAVE_UPCALL_MASK(reg,tmp,off) \ - movb evtchn_upcall_mask(reg), tmp; \ - movb tmp, off(%rsp) +#define XEN_PUT_VCPU_INFO(reg) +#define XEN_PUT_VCPU_INFO_fixup #endif +#define XEN_LOCKED_BLOCK_EVENTS(reg) movb $1,evtchn_upcall_mask(reg) +#define XEN_LOCKED_UNBLOCK_EVENTS(reg) movb $0,evtchn_upcall_mask(reg) +#define XEN_BLOCK_EVENTS(reg) XEN_GET_VCPU_INFO(reg) ; \ + XEN_LOCKED_BLOCK_EVENTS(reg) ; \ + XEN_PUT_VCPU_INFO(reg) +#define XEN_UNBLOCK_EVENTS(reg) XEN_GET_VCPU_INFO(reg) ; \ + XEN_LOCKED_UNBLOCK_EVENTS(reg) ; \ + XEN_PUT_VCPU_INFO(reg) #define XEN_TEST_PENDING(reg) testb $0xFF,evtchn_upcall_pending(reg) .code64 @@ -256,8 +242,6 @@ ENTRY(system_call) CFI_STARTPROC SAVE_ARGS -8,0 movq %rax,ORIG_RAX-ARGOFFSET(%rsp) - XEN_GET_VCPU_INFO(%r11) - XEN_SAVE_UPCALL_MASK(%r11,%cl,EVENT_MASK-ARGOFFSET) # saved %rcx XEN_UNBLOCK_EVENTS(%r11) GET_THREAD_INFO(%rcx) testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%rcx) @@ -277,7 +261,6 @@ ret_from_sys_call: /* edi: flagmask */ sysret_check: GET_THREAD_INFO(%rcx) - XEN_GET_VCPU_INFO(%rsi) XEN_BLOCK_EVENTS(%rsi) movl threadinfo_flags(%rcx),%edx andl %edi,%edx @@ -291,7 +274,6 @@ sysret_check: sysret_careful: bt $TIF_NEED_RESCHED,%edx jnc sysret_signal - XEN_GET_VCPU_INFO(%rsi) XEN_BLOCK_EVENTS(%rsi) pushq %rdi call schedule @@ -301,7 +283,6 @@ sysret_careful: /* Handle a signal */ sysret_signal: /* sti */ - XEN_GET_VCPU_INFO(%rsi) XEN_UNBLOCK_EVENTS(%rsi) testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx jz 1f @@ -345,7 +326,6 @@ badsys: * Has correct top of stack, but partial stack frame. */ ENTRY(int_ret_from_sys_call) - XEN_GET_VCPU_INFO(%rsi) XEN_BLOCK_EVENTS(%rsi) testb $3,CS-ARGOFFSET(%rsp) jnz 1f @@ -369,7 +349,6 @@ int_careful: bt $TIF_NEED_RESCHED,%edx jnc int_very_careful /* sti */ - XEN_GET_VCPU_INFO(%rsi) XEN_UNBLOCK_EVENTS(%rsi) pushq %rdi call schedule @@ -379,7 +358,6 @@ int_careful: /* handle signals and tracing -- both require a full stack frame */ int_very_careful: /* sti */ - XEN_GET_VCPU_INFO(%rsi) XEN_UNBLOCK_EVENTS(%rsi) SAVE_REST /* Check for syscall exit trace */ @@ -529,11 +507,11 @@ retint_check: retint_restore_args: movb EVENT_MASK-REST_SKIP(%rsp), %al notb %al # %al == ~saved_mask - XEN_LOCK_VCPU_INFO_SMP(%rsi) + XEN_GET_VCPU_INFO(%rsi) andb evtchn_upcall_mask(%rsi),%al andb $1,%al # %al == mask & ~saved_mask jnz restore_all_enable_events # != 0 => reenable event delivery - XEN_UNLOCK_VCPU_INFO_SMP(%rsi) + XEN_PUT_VCPU_INFO(%rsi) RESTORE_ARGS 0,8,0 testb $3,8(%rsp) # check CS @@ -548,13 +526,11 @@ user_mode: retint_careful: bt $TIF_NEED_RESCHED,%edx jnc retint_signal - XEN_GET_VCPU_INFO(%rsi) XEN_UNBLOCK_EVENTS(%rsi) /* sti */ pushq %rdi call schedule popq %rdi - XEN_GET_VCPU_INFO(%rsi) XEN_BLOCK_EVENTS(%rsi) GET_THREAD_INFO(%rcx) /* cli */ @@ -563,7 +539,6 @@ retint_careful: retint_signal: testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx jz retint_restore_args - XEN_GET_VCPU_INFO(%rsi) XEN_UNBLOCK_EVENTS(%rsi) SAVE_REST movq $-1,ORIG_RAX(%rsp) @@ -571,7 +546,6 @@ retint_signal: movq %rsp,%rdi # &pt_regs call do_notify_resume RESTORE_REST - XEN_GET_VCPU_INFO(%rsi) XEN_BLOCK_EVENTS(%rsi) movl $_TIF_NEED_RESCHED,%edi GET_THREAD_INFO(%rcx) @@ -590,10 +564,8 @@ retint_kernel: jc retint_restore_args movl $PREEMPT_ACTIVE,threadinfo_preempt_count(%rcx) /* sti */ - XEN_GET_VCPU_INFO(%rsi) XEN_UNBLOCK_EVENTS(%rsi) call schedule - XEN_GET_VCPU_INFO(%rsi) /* %esi can be different */ XEN_BLOCK_EVENTS(%rsi) /* cli */ GET_THREAD_INFO(%rcx) @@ -728,17 +700,10 @@ error_call_handler: movq %rsp,%rdi movq ORIG_RAX(%rsp),%rsi # get error code movq $-1,ORIG_RAX(%rsp) - leaq do_hypervisor_callback,%rcx - cmpq %rax,%rcx - je 0f # don't save event mask for callbacks - XEN_GET_VCPU_INFO(%r11) - XEN_SAVE_UPCALL_MASK(%r11,%cl,EVENT_MASK) -0: call *%rax error_exit: RESTORE_REST /* cli */ - XEN_GET_VCPU_INFO(%rsi) XEN_BLOCK_EVENTS(%rsi) GET_THREAD_INFO(%rcx) testb $3,CS-ARGOFFSET(%rsp) @@ -807,7 +772,7 @@ restore_all_enable_events: scrit: /**** START OF CRITICAL REGION ****/ XEN_TEST_PENDING(%rsi) jnz 14f # process more events if necessary... - XEN_UNLOCK_VCPU_INFO_SMP(%rsi) + XEN_PUT_VCPU_INFO(%rsi) RESTORE_ARGS 0,8,0 testb $3,8(%rsp) # check CS jnz crit_user_mode @@ -817,7 +782,7 @@ crit_user_mode: SWITCH_TO_USER 0 14: XEN_LOCKED_BLOCK_EVENTS(%rsi) - XEN_UNLOCK_VCPU_INFO_SMP(%rsi) + XEN_PUT_VCPU_INFO(%rsi) SAVE_REST movq %rsp,%rdi # set the argument again jmp 11b From f987bb10354f8846e115a20448db71dfbb298f90 Mon Sep 17 00:00:00 2001 From: "ach61@arcadians.cl.cam.ac.uk" Date: Wed, 15 Jun 2005 14:37:13 +0000 Subject: [PATCH 08/25] bitkeeper revision 1.1713.1.10 (42b03d19TAy64Sdjkm7M7nVoGNwCVw) readme for pdb 0.3 --- .rootkeys | 1 + tools/debugger/pdb/readme | 84 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 tools/debugger/pdb/readme diff --git a/.rootkeys b/.rootkeys index f8d113f0e6..b4448b79e7 100644 --- a/.rootkeys +++ b/.rootkeys @@ -542,6 +542,7 @@ 42a0c8dasiso9c-2sCvHBzP6YVjATA tools/debugger/pdb/evtchn.mli 42a0c8daXD_6Y62A_u5-PO_Klrhi0w tools/debugger/pdb/pdb_caml_xc.c 42a0c8danJXun9ay5SPBhhkKvuUPfg tools/debugger/pdb/pdb_xen.c +42b03d06llc_GE7fXGQ6-rYR4VFAcw tools/debugger/pdb/readme 42a0c8dbjK6Du89D2SUcxsuAdlUu3w tools/debugger/pdb/server.ml 401d7e160vaxMBAUSLSicuZ7AQjJ3w tools/examples/Makefile 401d7e16UgeqroJQTIhwkrDVkoWgZQ tools/examples/README diff --git a/tools/debugger/pdb/readme b/tools/debugger/pdb/readme new file mode 100644 index 0000000000..be1c44279e --- /dev/null +++ b/tools/debugger/pdb/readme @@ -0,0 +1,84 @@ + +PDB 0.3 +http://www.cl.cam.ac.uk/netos/pdb + +Alex Ho +June 2005 + + +This is the latest incarnation of the pervasive debugger. +PDB is a remote stub for GDB. Running as a user-space +application in domain 0, it can debug any other domain. + + ++------+ tcp/ip +-------+ +| GDB |--------------| PDB | ++------+ +-------+ +-------+ + | Dom 0 | | Dom U | + +-------+---+-------+ + | Xen | + +-------------------+ + +Installation + +- Install OCaml 3.08 in domain 0. + http://caml.inria.fr/download.en.html is a good place to start. + +- Build Xen with debugger support + make domu_debug=y xen + +- (optional) + Build the target domains with debugging symbols. + make CONFIG_DEBUG_INFO=true CONFIG_FRAME_POINTER=false linux-2.6-xenU-build + + You can also change linux-2.6.11-xenU/Makefile + CONFIG_CC_OPTIMIZE_FOR_SIZE from -O2 to -O + +- Build PDB + (cd tools/debugger/libxendebug; make install) + (cd tools/debugger/pdb; make) + +Usage + +- PDB does not currently support SMP. Please boot xen with "maxcpus=1" + +- Run PDB + domain-0.xeno# ./pdb + +- Run GDB + hostname% gdb /dist/install/boot/vmlinux-syms-2.6.11.11-xenU + + (gdb) target remote domain-0.xeno: + + At this point, you'll get an error message such as: + Remote debugging using domain-0.xeno:5000 + 0x00000000 in ?? () + warning: shared library handler failed to enable breakpoint + Although GDB is connected to PDB, PDB doesn't know which domain + you'd like to debug, so it's just feeding GDB a bunch of zeros. + + (gdb) maint packet x context = domain + + This tells PDB that we'd like to debug a particular domain & vcpu. + However, since we're sending the command directly to PDB, GDB doesn't + know that we now have a proper target. We can force GDB to invalidate + its register cache. This is optional; the next time the program + stops GDB will query for the registers automatically. + + (gdb) flushreg + + + the following gdb commands should work :) + + break + step, stepi + next, nexti + continue + print + + +To Do + +- watchpoints +- support for SMP +- support for user applications From c39f4a5931522c6fdea218d607d7f3953e1f934b Mon Sep 17 00:00:00 2001 From: "ach61@arcadians.cl.cam.ac.uk" Date: Wed, 15 Jun 2005 14:41:49 +0000 Subject: [PATCH 09/25] bitkeeper revision 1.1713.1.11 (42b03e2dFl47vRNjIHPpu-GWrag_zA) remove obsolete debugger documentation --- .rootkeys | 1 - docs/misc/XenDebugger-HOWTO | 304 ------------------------------------ 2 files changed, 305 deletions(-) delete mode 100644 docs/misc/XenDebugger-HOWTO diff --git a/.rootkeys b/.rootkeys index b4448b79e7..d53afebc33 100644 --- a/.rootkeys +++ b/.rootkeys @@ -17,7 +17,6 @@ 3f9e7d60PWZJeVh5xdnk0nLUdxlqEA docs/figs/xenlogo.eps 418a3248xjIqmNKo0v_XQSfAvlBGFw docs/html.sty 41c0c4116itF389v0CEWcmzue6zJkA docs/misc/VMX_changes.txt -4022a73cgxX1ryj1HgS-IwwB6NUi2A docs/misc/XenDebugger-HOWTO 412f4bd9sm5mCQ8BkrgKcAKZGadq7Q docs/misc/blkif-drivers-explained.txt 420b949cy9ZGzED74Fz_DaWlK7tT4g docs/misc/crashdb.txt 4251a1f82AexscYEiF4Iku8Gc_kWfQ docs/misc/grant-tables.txt diff --git a/docs/misc/XenDebugger-HOWTO b/docs/misc/XenDebugger-HOWTO deleted file mode 100644 index f4d2998b1a..0000000000 --- a/docs/misc/XenDebugger-HOWTO +++ /dev/null @@ -1,304 +0,0 @@ -Pervasive Debugging -=================== - -Alex Ho (alex.ho at cl.cam.ac.uk) - -Introduction ------------- - -The pervasive debugging project is leveraging Xen to -debug distributed systems. We have added a gdb stub -to Xen to allow for remote debugging of both Xen and -guest operating systems. More information about the -pervasive debugger is available at: http://www.cl.cam.ac.uk/netos/pdb - - -Implementation --------------- - -The gdb stub communicates with gdb running over a serial line. -The main entry point is pdb_handle_exception() which is invoked -from: pdb_key_pressed() ('D' on the console) - do_int3_exception() (interrupt 3: breakpoint exception) - do_debug() (interrupt 1: debug exception) - -This accepts characters from the serial port and passes gdb -commands to pdb_process_command() which implements the gdb stub -interface. This file draws heavily from the kgdb project and -sample gdbstub provided with gdb. - -The stub can examine registers, single step and continue, and -read and write memory (in Xen, a domain, or a Linux process' -address space). The debugger does not currently trace the -current process, so all bets are off if context switch occurs -in the domain. - - -Setup ------ - - +-------+ telnet +-----------+ serial +-------+ - | GDB |--------| nsplitd |--------| Xen | - +-------+ +-----------+ +-------+ - -To run pdb, Xen must be appropriately configured and -a suitable serial interface attached to the target machine. -GDB and nsplitd can run on the same machine. - -Xen Configuration - - Add the "pdb=xxx" option to your Xen boot command line - where xxx is one of the following values: - com1 gdb stub should communicate on com1 - com1H gdb stub should communicate on com1 (with high bit set) - com2 gdb stub should communicate on com2 - com2H gdb stub should communicate on com2 (with high bit set) - - Symbolic debugging infomration is quite helpful too: - xeno.bk/xen/arch/x86/Rules.mk - add -g to CFLAGS to compile Xen with symbols - xeno.bk/linux-2.4.27-xen-sparse/arch/xen/Makefile - add -g to CFLAGS to compile Linux with symbols - - You may also want to consider dedicating a register to the - frame pointer (disable the -fomit-frame-pointer compile flag). - - When booting Xen and domain 0, look for the console text - "pdb: pervasive debugger" just before DOM0 starts up. - -Serial Port Configuration - - pdb expects to communicate with gdb using the serial port. Since - this port is often shared with the machine's console output, pdb can - discriminate its communication by setting the high bit of each byte. - - A new tool has been added to the source tree which splits - the serial output from a remote machine into two streams: - one stream (without the high bit) is the console and - one stream (with the high bit stripped) is the pdb communication. - - See: xeno.bk/tools/misc/nsplitd - - nsplitd configuration - --------------------- - hostname$ more /etc/xinetd.d/nsplit - service nsplit1 - { - socket_type = stream - protocol = tcp - wait = no - user = wanda - server = /usr/sbin/in.nsplitd - server_args = serial.cl.cam.ac.uk:wcons00 - disable = no - only_from = 128.232.0.0/17 127.0.0.1 - } - - hostname$ egrep 'wcons00|nsplit1' /etc/services - wcons00 9600/tcp # Wanda remote console - nsplit1 12010/tcp # Nemesis console splitter ports. - - Note: nsplitd was originally written for the Nemesis project - at Cambridge. - - After nsplitd accepts a connection on (12010 in the above - example), it starts listening on port . Characters sent - to the will have the high bit set and vice versa for - characters received. - - You can connect to the nsplitd using - 'tools/misc/xencons ' - -GDB 6.0 - pdb has been tested with gdb 6.0. It should also work with - earlier versions. - - -Usage ------ - -1. Boot Xen and Linux -2. Interrupt Xen by pressing 'D' at the console - You should see the console message: - (XEN) pdb_handle_exception [0x88][0x101000:0xfc5e72ac] - At this point Xen is frozen and the pdb stub is waiting for gdb commands - on the serial line. -3. Attach with gdb - (gdb) file xeno.bk/xen/xen - Reading symbols from xeno.bk/xen/xen...done. - (gdb) target remote : /* contact nsplitd */ - Remote debugging using serial.srg:12131 - continue_cpu_idle_loop () at current.h:10 - warning: shared library handler failed to enable breakpoint - (gdb) break __enter_scheduler - Breakpoint 1 at 0xfc510a94: file schedule.c, line 330. - (gdb) cont - Continuing. - - Program received signal SIGTRAP, Trace/breakpoint trap. - __enter_scheduler () at schedule.c:330 - (gdb) step - (gdb) step - (gdb) print next /* the variable prev has been optimized away! */ - $1 = (struct task_struct *) 0x0 - (gdb) delete - Delete all breakpoints? (y or n) y -4. You can add additional symbols to gdb - (gdb) add-sym xeno.bk/linux-2.4.27-xen0/vmlinux - add symbol table from file "xeno.bk/linux-2.4.27-xen0/vmlinux" at - (y or n) y - Reading symbols from xeno.bk/linux-2.4.27-xen0/vmlinux...done. - (gdb) x/s cpu_vendor_names[0] - 0xc01530d2 : "Intel" - (gdb) break free_uid - Breakpoint 2 at 0xc0012250 - (gdb) cont - Continuing. /* run a command in domain 0 */ - - Program received signal SIGTRAP, Trace/breakpoint trap. - free_uid (up=0xbffff738) at user.c:77 - - (gdb) print *up - $2 = {__count = {counter = 0}, processes = {counter = 135190120}, files = { - counter = 0}, next = 0x395, pprev = 0xbffff878, uid = 134701041} - (gdb) finish - Run till exit from #0 free_uid (up=0xbffff738) at user.c:77 - - Program received signal SIGTRAP, Trace/breakpoint trap. - release_task (p=0xc2da0000) at exit.c:51 - (gdb) print *p - $3 = {state = 4, flags = 4, sigpending = 0, addr_limit = {seg = 3221225472}, - exec_domain = 0xc016a040, need_resched = 0, ptrace = 0, lock_depth = -1, - counter = 1, nice = 0, policy = 0, mm = 0x0, processor = 0, - cpus_runnable = 1, cpus_allowed = 4294967295, run_list = {next = 0x0, - prev = 0x0}, sleep_time = 18995, next_task = 0xc017c000, - prev_task = 0xc2f94000, active_mm = 0x0, local_pages = {next = 0xc2da0054, - prev = 0xc2da0054}, allocation_order = 0, nr_local_pages = 0, - ... -5. To resume Xen, enter the "continue" command to gdb. - This sends the packet $c#63 along the serial channel. - - (gdb) cont - Continuing. - -Debugging Multiple Domains & Processes --------------------------------------- - -pdb supports debugging multiple domains & processes. You can switch -between different domains and processes within domains and examine -variables in each. - -The pdb context identifies the current debug target. It is stored -in the xen variable pdb_ctx and defaults to xen. - - target pdb_ctx.domain pdb_ctx.process - ------ -------------- --------------- - xen -1 -1 - guest os 0,1,2,... -1 - process 0,1,2,... 0,1,2,... - -Unfortunately, gdb doesn't understand debugging multiple process -simultaneously (we're working on it), so at present you are limited -to just one set of symbols for symbolic debugging. When debugging -processes, pdb currently supports just Linux 2.4. - - define setup - file xeno-clone/xeno.bk/xen/xen - add-sym xeno-clone/xeno.bk/linux-2.4.27-xen0/vmlinux - add-sym ~ach61/a.out - end - - -1. Connect with gdb as before. A couple of Linux-specific - symbols need to be defined. - - (gdb) target remote : /* contact nsplitd */ - Remote debugging using serial.srg:12131 - continue_cpu_idle_loop () at current.h:10 - warning: shared library handler failed to enable breakpoint - (gdb) set pdb_pidhash_addr = &pidhash - (gdb) set pdb_init_task_union_addr = &init_task_union - -2. The pdb context defaults to Xen and we can read Xen's memory. - An attempt to access domain 0 memory fails. - - (gdb) print pdb_ctx - $1 = {valid = 0, domain = -1, process = -1, ptbr = 1052672} - (gdb) print hexchars - $2 = "0123456789abcdef" - (gdb) print cpu_vendor_names - Cannot access memory at address 0xc0191f80 - -3. Now we change to domain 0. In addition to changing pdb_ctx.domain, - we need to change pdb_ctx.valid to signal pdb of the change. - It is now possible to examine Xen and Linux memory. - - (gdb) set pdb_ctx.domain=0 - (gdb) set pdb_ctx.valid=1 - (gdb) print hexchars - $3 = "0123456789abcdef" - (gdb) print cpu_vendor_names - $4 = {0xc0158b46 "Intel", 0xc0158c37 "Cyrix", 0xc0158b55 "AMD", - 0xc0158c3d "UMC", 0xc0158c41 "NexGen", 0xc0158c48 "Centaur", - 0xc0158c50 "Rise", 0xc0158c55 "Transmeta"} - -4. Now change to a process within domain 0. Again, we need to - change pdb_ctx.valid in addition to pdb_ctx.process. - - (gdb) set pdb_ctx.process=962 - (gdb) set pdb_ctx.valid =1 - (gdb) print pdb_ctx - $1 = {valid = 0, domain = 0, process = 962, ptbr = 52998144} - (gdb) print aho_a - $2 = 20 - -5. Now we can read the same variable from another process running - the same executable in another domain. - - (gdb) set pdb_ctx.domain=1 - (gdb) set pdb_ctx.process=1210 - (gdb) set pdb_ctx.valid=1 - (gdb) print pdb_ctx - $3 = {valid = 0, domain = 1, process = 1210, ptbr = 70574080} - (gdb) print aho_a - $4 = 27 - - -Some Helpful .gdbinit Commands ------------------------------- - -define setup - file .../install/boot/xen-syms - add-sym .../install/boot/vmlinux-syms-2.4.27-xen0 - add-sym /homes/aho/a.out -end -document setup - load symbols for xen, xenolinux (dom 0), and "a.out" -end - -define setup-linux - set pdb_pidhash_addr = &pidhash - set pdb_init_task_union_addr = &init_task_union - - set task_struct_mm_offset = (void *)&(init_task_union.task.mm) - (void *)&(init_task_union.task) - set task_struct_next_task_offset = (void *)&(init_task_union.task.next_task) - (void *)&(init_task_union.task) - set task_struct_pid_offset = (void *)&(init_task_union.task.pid) - (void *)&(init_task_union.task) - set task_struct_pidhash_next_offset = (void *)&(init_task_union.task.pidhash_next) - (void *)&(init_task_union.task) - set task_struct_comm_offset = (void *)&(init_task_union.task.comm) - (void *)&(init_task_union.task) - set task_struct_comm_length = sizeof (init_task_union.task.comm) - - set mm_struct_pgd_offset = sizeof (struct vm_area_struct *) * 2 + sizeof (rb_root_t) -end -document setup-linux - define various xenolinux specific offsets and sizes in pdb -end - - - - -Changes -------- - -04.07.15 aho .gdbinit -04.02.05 aho creation -04.03.31 aho add description on debugging multiple domains From 7752c1a0368f1331775ff7ea5d1d6733da795ff0 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Thu, 16 Jun 2005 01:47:29 +0000 Subject: [PATCH 10/25] bitkeeper revision 1.1713.1.12 (42b0da31QIvTtfE2iHo4yER4A1GFIw) serial.c: Fix serial_getc locking. --- xen/drivers/char/serial.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c index bec789e084..ad5ad5cde0 100644 --- a/xen/drivers/char/serial.c +++ b/xen/drivers/char/serial.c @@ -176,11 +176,15 @@ char serial_getc(int handle) if ( port->rxbufp != port->rxbufc ) { c = port->rxbuf[MASK_SERIAL_RXBUF_IDX(port->rxbufc++)]; + spin_unlock_irqrestore(&port->lock, flags); break; } if ( port->driver->getc(port, &c) ) + { + spin_unlock_irqrestore(&port->lock, flags); break; + } spin_unlock_irqrestore(&port->lock, flags); From e7399d6ff4d5783837d1e83792cba7a2be41ece0 Mon Sep 17 00:00:00 2001 From: "sos22@douglas.cl.cam.ac.uk" Date: Thu, 16 Jun 2005 11:44:16 +0000 Subject: [PATCH 11/25] bitkeeper revision 1.1713.1.13 (42b16610ojQcHPRC6Ao_1CKXClza9A) Slightly disgusting hack to avoid using lots of lock instructions on a uniprocessor machine just because we happened to compile with CONFIG_SMP. Essentially, we make a big table of all of the instruction sequences which differ in ``easy'' ways between UP and SMP kernels, and then select which one to use at run time. Signed-off-by: Steven Smith --- .rootkeys | 1 + linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig | 13 + .../arch/xen/i386/kernel/Makefile | 1 + .../arch/xen/i386/kernel/smpboot.c | 17 + .../include/asm-xen/asm-i386/system.h | 57 +- patches/linux-2.6.11/smp-alts.patch | 554 ++++++++++++++++++ 6 files changed, 637 insertions(+), 6 deletions(-) create mode 100644 patches/linux-2.6.11/smp-alts.patch diff --git a/.rootkeys b/.rootkeys index d53afebc33..98804345ab 100644 --- a/.rootkeys +++ b/.rootkeys @@ -470,6 +470,7 @@ 428359d4b3fDYtazwXi4UUmSWaOUew patches/linux-2.6.11/linux-2.6.11.12.patch 4296fb998LGSWCcljGKbOCUv3h9uRQ patches/linux-2.6.11/net-csum.patch 429ae875I9ZrqrRDjGD34IC2kzDREw patches/linux-2.6.11/rcu-nohz.patch +42b165fcilFTNezi9NIsG2ecLZVU0w patches/linux-2.6.11/smp-alts.patch 429ba3007184K-y6WHQ6KgY65-lEIQ patches/linux-2.6.11/udp-frag.patch 424f001e_M1Tnxc52rDrmCLelnDWMQ patches/linux-2.6.11/x86_64-linux.patch 3f776bd1Hy9rn69ntXBhPReUFw9IEA tools/Makefile diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig b/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig index d1ffcb05d1..dec06cdfd1 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig @@ -372,6 +372,19 @@ config SMP If you don't know what to do here, say N. +config SMP_ALTERNATIVES + bool "SMP alternatives support (EXPERIMENTAL)" + depends on SMP && EXPERIMENTAL + help + Try to reduce the overhead of running an SMP kernel on a uniprocessor + host slightly by replacing certain key instruction sequences + according to whether we currently have more than one CPU available. + This should provide a noticeable boost to performance when + running SMP kernels on UP machines, and have negligible impact + when running on an true SMP host. + + If unsure, say N. + config NR_CPUS int "Maximum number of CPUs (2-255)" range 2 255 diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/Makefile b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/Makefile index 3f2fef4a94..6973df049f 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/Makefile +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/Makefile @@ -42,6 +42,7 @@ c-obj-$(CONFIG_ACPI_SRAT) += srat.o c-obj-$(CONFIG_HPET_TIMER) += time_hpet.o c-obj-$(CONFIG_EFI) += efi.o efi_stub.o c-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +c-obj-$(CONFIG_SMP_ALTERNATIVES)+= smpalts.o EXTRA_AFLAGS := -traditional diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c index a716095376..1956f9ceed 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c @@ -54,6 +54,8 @@ #include #include +#include + #ifndef CONFIG_X86_IO_APIC #define Dprintk(args...) #endif @@ -1186,6 +1188,10 @@ static void __init smp_boot_cpus(unsigned int max_cpus) if (max_cpus <= cpucount+1) continue; +#ifdef CONFIG_SMP_ALTERNATIVES + if (kicked == 1) + prepare_for_smp(); +#endif if (do_boot_cpu(cpu)) printk("CPU #%d not responding - cannot use it.\n", cpu); @@ -1301,6 +1307,11 @@ void __devinit smp_prepare_boot_cpu(void) /* must be called with the cpucontrol mutex held */ static int __devinit cpu_enable(unsigned int cpu) { +#ifdef CONFIG_SMP_ALTERNATIVES + if (num_online_cpus() == 1) + prepare_for_smp(); +#endif + /* get the target out of its holding state */ per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; wmb(); @@ -1340,6 +1351,12 @@ int __cpu_disable(void) fixup_irqs(map); /* It's now safe to remove this processor from the online map */ cpu_clear(cpu, cpu_online_map); + +#ifdef CONFIG_SMP_ALTERNATIVES + if (num_online_cpus() == 1) + unprepare_for_smp(); +#endif + return 0; } diff --git a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/system.h b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/system.h index 021acbd159..fcf9959526 100644 --- a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/system.h +++ b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/system.h @@ -8,6 +8,7 @@ #include #include #include +#include #ifdef __KERNEL__ @@ -251,19 +252,19 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, unsigned long prev; switch (size) { case 1: - __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2" + __asm__ __volatile__(LOCK "cmpxchgb %b1,%2" : "=a"(prev) : "q"(new), "m"(*__xg(ptr)), "0"(old) : "memory"); return prev; case 2: - __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2" + __asm__ __volatile__(LOCK "cmpxchgw %w1,%2" : "=a"(prev) : "q"(new), "m"(*__xg(ptr)), "0"(old) : "memory"); return prev; case 4: - __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2" + __asm__ __volatile__(LOCK "cmpxchgl %1,%2" : "=a"(prev) : "q"(new), "m"(*__xg(ptr)), "0"(old) : "memory"); @@ -427,11 +428,55 @@ struct alt_instr { #endif #ifdef CONFIG_SMP -#define smp_mb() mb() -#define smp_rmb() rmb() #define smp_wmb() wmb() -#define smp_read_barrier_depends() read_barrier_depends() +#if defined(CONFIG_SMP_ALTERNATIVES) && !defined(MODULE) +#define smp_alt_mb(instr) \ +__asm__ __volatile__("6667:\nnop\nnop\nnop\nnop\nnop\nnop\n6668:\n" \ + ".section __smp_alternatives,\"a\"\n" \ + ".long 6667b\n" \ + ".long 6673f\n" \ + ".previous\n" \ + ".section __smp_replacements,\"a\"\n" \ + "6673:.byte 6668b-6667b\n" \ + ".byte 6670f-6669f\n" \ + ".byte 6671f-6670f\n" \ + ".byte 0\n" \ + ".byte %c0\n" \ + "6669:lock;addl $0,0(%%esp)\n" \ + "6670:" instr "\n" \ + "6671:\n" \ + ".previous\n" \ + : \ + : "i" (X86_FEATURE_XMM2) \ + : "memory") +#define smp_rmb() smp_alt_mb("lfence") +#define smp_mb() smp_alt_mb("mfence") +#define set_mb(var, value) do { \ +unsigned long __set_mb_temp; \ +__asm__ __volatile__("6667:movl %1, %0\n6668:\n" \ + ".section __smp_alternatives,\"a\"\n" \ + ".long 6667b\n" \ + ".long 6673f\n" \ + ".previous\n" \ + ".section __smp_replacements,\"a\"\n" \ + "6673: .byte 6668b-6667b\n" \ + ".byte 6670f-6669f\n" \ + ".byte 0\n" \ + ".byte 6671f-6670f\n" \ + ".byte -1\n" \ + "6669: xchg %1, %0\n" \ + "6670:movl %1, %0\n" \ + "6671:\n" \ + ".previous\n" \ + : "=m" (var), "=r" (__set_mb_temp) \ + : "1" (value) \ + : "memory"); } while (0) +#else +#define smp_rmb() rmb() +#define smp_mb() mb() #define set_mb(var, value) do { xchg(&var, value); } while (0) +#endif +#define smp_read_barrier_depends() read_barrier_depends() #else #define smp_mb() barrier() #define smp_rmb() barrier() diff --git a/patches/linux-2.6.11/smp-alts.patch b/patches/linux-2.6.11/smp-alts.patch new file mode 100644 index 0000000000..db71ab1e56 --- /dev/null +++ b/patches/linux-2.6.11/smp-alts.patch @@ -0,0 +1,554 @@ +diff -Naur linux-2.6.11/arch/i386/Kconfig linux-2.6.11.post/arch/i386/Kconfig +--- linux-2.6.11/arch/i386/Kconfig 2005-03-02 07:37:49.000000000 +0000 ++++ linux-2.6.11.post/arch/i386/Kconfig 2005-06-10 13:42:35.000000000 +0100 +@@ -481,6 +481,19 @@ + + If you don't know what to do here, say N. + ++config SMP_ALTERNATIVES ++ bool "SMP alternatives support (EXPERIMENTAL)" ++ depends on SMP && EXPERIMENTAL ++ help ++ Try to reduce the overhead of running an SMP kernel on a uniprocessor ++ host slightly by replacing certain key instruction sequences ++ according to whether we currently have more than one CPU available. ++ This should provide a noticeable boost to performance when ++ running SMP kernels on UP machines, and have negligible impact ++ when running on an true SMP host. ++ ++ If unsure, say N. ++ + config NR_CPUS + int "Maximum number of CPUs (2-255)" + range 2 255 +diff -Naur linux-2.6.11/arch/i386/kernel/Makefile linux-2.6.11.post/arch/i386/kernel/Makefile +--- linux-2.6.11/arch/i386/kernel/Makefile 2005-03-02 07:37:49.000000000 +0000 ++++ linux-2.6.11.post/arch/i386/kernel/Makefile 2005-06-16 11:16:18.555332435 +0100 +@@ -32,6 +32,7 @@ + obj-$(CONFIG_HPET_TIMER) += time_hpet.o + obj-$(CONFIG_EFI) += efi.o efi_stub.o + obj-$(CONFIG_EARLY_PRINTK) += early_printk.o ++obj-$(CONFIG_SMP_ALTERNATIVES) += smpalts.o + + EXTRA_AFLAGS := -traditional + +diff -Naur linux-2.6.11/arch/i386/kernel/smpalts.c linux-2.6.11.post/arch/i386/kernel/smpalts.c +--- linux-2.6.11/arch/i386/kernel/smpalts.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.11.post/arch/i386/kernel/smpalts.c 2005-06-16 11:23:39.300902424 +0100 +@@ -0,0 +1,76 @@ ++#include ++#include ++#include ++#include ++#include ++ ++struct smp_replacement_record { ++ unsigned char targ_size; ++ unsigned char smp1_size; ++ unsigned char smp2_size; ++ unsigned char up_size; ++ unsigned char feature; ++ unsigned char data[0]; ++}; ++ ++struct smp_alternative_record { ++ void *targ_start; ++ struct smp_replacement_record *repl; ++}; ++ ++extern struct smp_alternative_record __start_smp_alternatives_table, ++ __stop_smp_alternatives_table; ++ ++void prepare_for_smp(void) ++{ ++ struct smp_alternative_record *r; ++ printk(KERN_INFO "Enabling SMP...\n"); ++ for (r = &__start_smp_alternatives_table; ++ r != &__stop_smp_alternatives_table; ++ r++) { ++ BUG_ON(r->repl->targ_size < r->repl->smp1_size); ++ BUG_ON(r->repl->targ_size < r->repl->smp2_size); ++ BUG_ON(r->repl->targ_size < r->repl->up_size); ++ if (r->repl->feature != (unsigned char)-1 && ++ boot_cpu_has(r->repl->feature)) { ++ memcpy(r->targ_start, ++ r->repl->data + r->repl->smp1_size, ++ r->repl->smp2_size); ++ memset(r->targ_start + r->repl->smp2_size, ++ 0x90, ++ r->repl->targ_size - r->repl->smp2_size); ++ } else { ++ memcpy(r->targ_start, ++ r->repl->data, ++ r->repl->smp1_size); ++ memset(r->targ_start + r->repl->smp1_size, ++ 0x90, ++ r->repl->targ_size - r->repl->smp1_size); ++ } ++ } ++ /* Paranoia */ ++ asm volatile ("jmp 1f\n1:"); ++ mb(); ++} ++ ++void unprepare_for_smp(void) ++{ ++ struct smp_alternative_record *r; ++ printk(KERN_INFO "Disabling SMP...\n"); ++ for (r = &__start_smp_alternatives_table; ++ r != &__stop_smp_alternatives_table; ++ r++) { ++ BUG_ON(r->repl->targ_size < r->repl->smp1_size); ++ BUG_ON(r->repl->targ_size < r->repl->smp2_size); ++ BUG_ON(r->repl->targ_size < r->repl->up_size); ++ memcpy(r->targ_start, ++ r->repl->data + r->repl->smp1_size + r->repl->smp2_size, ++ r->repl->up_size); ++ memset(r->targ_start + r->repl->up_size, ++ 0x90, ++ r->repl->targ_size - r->repl->up_size); ++ } ++ /* Paranoia */ ++ asm volatile ("jmp 1f\n1:"); ++ mb(); ++} +diff -Naur linux-2.6.11/arch/i386/kernel/smpboot.c linux-2.6.11.post/arch/i386/kernel/smpboot.c +--- linux-2.6.11/arch/i386/kernel/smpboot.c 2005-03-02 07:38:09.000000000 +0000 ++++ linux-2.6.11.post/arch/i386/kernel/smpboot.c 2005-06-16 11:17:09.287064617 +0100 +@@ -1003,6 +1003,11 @@ + if (max_cpus <= cpucount+1) + continue; + ++#ifdef CONFIG_SMP_ALTERNATIVES ++ if (kicked == 1) ++ prepare_for_smp(); ++#endif ++ + if (do_boot_cpu(apicid)) + printk("CPU #%d not responding - cannot use it.\n", + apicid); +@@ -1118,6 +1123,11 @@ + return -EIO; + } + ++#ifdef CONFIG_SMP_ALTERNATIVES ++ if (num_online_cpus() == 1) ++ prepare_for_smp(); ++#endif ++ + local_irq_enable(); + /* Unleash the CPU! */ + cpu_set(cpu, smp_commenced_mask); +diff -Naur linux-2.6.11/arch/i386/kernel/vmlinux.lds.S linux-2.6.11.post/arch/i386/kernel/vmlinux.lds.S +--- linux-2.6.11/arch/i386/kernel/vmlinux.lds.S 2005-03-02 07:38:37.000000000 +0000 ++++ linux-2.6.11.post/arch/i386/kernel/vmlinux.lds.S 2005-06-10 11:14:14.000000000 +0100 +@@ -30,6 +30,13 @@ + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + ++ . = ALIGN(16); ++ __start_smp_alternatives_table = .; ++ __smp_alternatives : { *(__smp_alternatives) } ++ __stop_smp_alternatives_table = .; ++ ++ __smp_replacements : { *(__smp_replacements) } ++ + RODATA + + /* writeable */ +diff -Naur linux-2.6.11/include/asm-i386/atomic.h linux-2.6.11.post/include/asm-i386/atomic.h +--- linux-2.6.11/include/asm-i386/atomic.h 2005-03-02 07:37:51.000000000 +0000 ++++ linux-2.6.11.post/include/asm-i386/atomic.h 2005-06-13 10:10:39.000000000 +0100 +@@ -4,18 +4,13 @@ + #include + #include + #include ++#include + + /* + * Atomic operations that C can't guarantee us. Useful for + * resource counting etc.. + */ + +-#ifdef CONFIG_SMP +-#define LOCK "lock ; " +-#else +-#define LOCK "" +-#endif +- + /* + * Make sure gcc doesn't try to be clever and move things around + * on us. We need to use _exactly_ the address the user gave us, +diff -Naur linux-2.6.11/include/asm-i386/bitops.h linux-2.6.11.post/include/asm-i386/bitops.h +--- linux-2.6.11/include/asm-i386/bitops.h 2005-03-02 07:38:12.000000000 +0000 ++++ linux-2.6.11.post/include/asm-i386/bitops.h 2005-06-13 10:11:54.000000000 +0100 +@@ -7,6 +7,7 @@ + + #include + #include ++#include + + /* + * These have to be done with inline assembly: that way the bit-setting +@@ -16,12 +17,6 @@ + * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1). + */ + +-#ifdef CONFIG_SMP +-#define LOCK_PREFIX "lock ; " +-#else +-#define LOCK_PREFIX "" +-#endif +- + #define ADDR (*(volatile long *) addr) + + /** +@@ -41,7 +36,7 @@ + */ + static inline void set_bit(int nr, volatile unsigned long * addr) + { +- __asm__ __volatile__( LOCK_PREFIX ++ __asm__ __volatile__( LOCK + "btsl %1,%0" + :"=m" (ADDR) + :"Ir" (nr)); +@@ -76,7 +71,7 @@ + */ + static inline void clear_bit(int nr, volatile unsigned long * addr) + { +- __asm__ __volatile__( LOCK_PREFIX ++ __asm__ __volatile__( LOCK + "btrl %1,%0" + :"=m" (ADDR) + :"Ir" (nr)); +@@ -121,7 +116,7 @@ + */ + static inline void change_bit(int nr, volatile unsigned long * addr) + { +- __asm__ __volatile__( LOCK_PREFIX ++ __asm__ __volatile__( LOCK + "btcl %1,%0" + :"=m" (ADDR) + :"Ir" (nr)); +@@ -140,7 +135,7 @@ + { + int oldbit; + +- __asm__ __volatile__( LOCK_PREFIX ++ __asm__ __volatile__( LOCK + "btsl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (ADDR) + :"Ir" (nr) : "memory"); +@@ -180,7 +175,7 @@ + { + int oldbit; + +- __asm__ __volatile__( LOCK_PREFIX ++ __asm__ __volatile__( LOCK + "btrl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (ADDR) + :"Ir" (nr) : "memory"); +@@ -231,7 +226,7 @@ + { + int oldbit; + +- __asm__ __volatile__( LOCK_PREFIX ++ __asm__ __volatile__( LOCK + "btcl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (ADDR) + :"Ir" (nr) : "memory"); +diff -Naur linux-2.6.11/include/asm-i386/rwsem.h linux-2.6.11.post/include/asm-i386/rwsem.h +--- linux-2.6.11/include/asm-i386/rwsem.h 2005-03-02 07:38:08.000000000 +0000 ++++ linux-2.6.11.post/include/asm-i386/rwsem.h 2005-06-13 10:13:06.000000000 +0100 +@@ -40,6 +40,7 @@ + + #include + #include ++#include + + struct rwsem_waiter; + +@@ -99,7 +100,7 @@ + { + __asm__ __volatile__( + "# beginning down_read\n\t" +-LOCK_PREFIX " incl (%%eax)\n\t" /* adds 0x00000001, returns the old value */ ++LOCK " incl (%%eax)\n\t" /* adds 0x00000001, returns the old value */ + " js 2f\n\t" /* jump if we weren't granted the lock */ + "1:\n\t" + LOCK_SECTION_START("") +@@ -130,7 +131,7 @@ + " movl %1,%2\n\t" + " addl %3,%2\n\t" + " jle 2f\n\t" +-LOCK_PREFIX " cmpxchgl %2,%0\n\t" ++LOCK " cmpxchgl %2,%0\n\t" + " jnz 1b\n\t" + "2:\n\t" + "# ending __down_read_trylock\n\t" +@@ -150,7 +151,7 @@ + tmp = RWSEM_ACTIVE_WRITE_BIAS; + __asm__ __volatile__( + "# beginning down_write\n\t" +-LOCK_PREFIX " xadd %%edx,(%%eax)\n\t" /* subtract 0x0000ffff, returns the old value */ ++LOCK " xadd %%edx,(%%eax)\n\t" /* subtract 0x0000ffff, returns the old value */ + " testl %%edx,%%edx\n\t" /* was the count 0 before? */ + " jnz 2f\n\t" /* jump if we weren't granted the lock */ + "1:\n\t" +@@ -188,7 +189,7 @@ + __s32 tmp = -RWSEM_ACTIVE_READ_BIAS; + __asm__ __volatile__( + "# beginning __up_read\n\t" +-LOCK_PREFIX " xadd %%edx,(%%eax)\n\t" /* subtracts 1, returns the old value */ ++LOCK " xadd %%edx,(%%eax)\n\t" /* subtracts 1, returns the old value */ + " js 2f\n\t" /* jump if the lock is being waited upon */ + "1:\n\t" + LOCK_SECTION_START("") +@@ -214,7 +215,7 @@ + __asm__ __volatile__( + "# beginning __up_write\n\t" + " movl %2,%%edx\n\t" +-LOCK_PREFIX " xaddl %%edx,(%%eax)\n\t" /* tries to transition 0xffff0001 -> 0x00000000 */ ++LOCK " xaddl %%edx,(%%eax)\n\t" /* tries to transition 0xffff0001 -> 0x00000000 */ + " jnz 2f\n\t" /* jump if the lock is being waited upon */ + "1:\n\t" + LOCK_SECTION_START("") +@@ -239,7 +240,7 @@ + { + __asm__ __volatile__( + "# beginning __downgrade_write\n\t" +-LOCK_PREFIX " addl %2,(%%eax)\n\t" /* transitions 0xZZZZ0001 -> 0xYYYY0001 */ ++LOCK " addl %2,(%%eax)\n\t" /* transitions 0xZZZZ0001 -> 0xYYYY0001 */ + " js 2f\n\t" /* jump if the lock is being waited upon */ + "1:\n\t" + LOCK_SECTION_START("") +@@ -263,7 +264,7 @@ + static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem) + { + __asm__ __volatile__( +-LOCK_PREFIX "addl %1,%0" ++LOCK "addl %1,%0" + : "=m"(sem->count) + : "ir"(delta), "m"(sem->count)); + } +@@ -276,7 +277,7 @@ + int tmp = delta; + + __asm__ __volatile__( +-LOCK_PREFIX "xadd %0,(%2)" ++LOCK "xadd %0,(%2)" + : "+r"(tmp), "=m"(sem->count) + : "r"(sem), "m"(sem->count) + : "memory"); +diff -Naur linux-2.6.11/include/asm-i386/smp_alt.h linux-2.6.11.post/include/asm-i386/smp_alt.h +--- linux-2.6.11/include/asm-i386/smp_alt.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.11.post/include/asm-i386/smp_alt.h 2005-06-16 11:16:50.109433206 +0100 +@@ -0,0 +1,32 @@ ++#ifndef __ASM_SMP_ALT_H__ ++#define __ASM_SMP_ALT_H__ ++ ++#include ++ ++#ifdef CONFIG_SMP ++#if defined(CONFIG_SMP_ALTERNATIVES) && !defined(MODULE) ++#define LOCK \ ++ "6677: nop\n" \ ++ ".section __smp_alternatives,\"a\"\n" \ ++ ".long 6677b\n" \ ++ ".long 6678f\n" \ ++ ".previous\n" \ ++ ".section __smp_replacements,\"a\"\n" \ ++ "6678: .byte 1\n" \ ++ ".byte 1\n" \ ++ ".byte 0\n" \ ++ ".byte 1\n" \ ++ ".byte -1\n" \ ++ "lock\n" \ ++ "nop\n" \ ++ ".previous\n" ++void prepare_for_smp(void); ++void unprepare_for_smp(void); ++#else ++#define LOCK "lock ; " ++#endif ++#else ++#define LOCK "" ++#endif ++ ++#endif /* __ASM_SMP_ALT_H__ */ +diff -Naur linux-2.6.11/include/asm-i386/spinlock.h linux-2.6.11.post/include/asm-i386/spinlock.h +--- linux-2.6.11/include/asm-i386/spinlock.h 2005-03-02 07:37:50.000000000 +0000 ++++ linux-2.6.11.post/include/asm-i386/spinlock.h 2005-06-13 14:13:52.000000000 +0100 +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + + asmlinkage int printk(const char * fmt, ...) + __attribute__ ((format (printf, 1, 2))); +@@ -47,8 +48,9 @@ + #define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x)) + + #define spin_lock_string \ +- "\n1:\t" \ +- "lock ; decb %0\n\t" \ ++ "1:\n" \ ++ LOCK \ ++ "decb %0\n\t" \ + "jns 3f\n" \ + "2:\t" \ + "rep;nop\n\t" \ +@@ -58,8 +60,9 @@ + "3:\n\t" + + #define spin_lock_string_flags \ +- "\n1:\t" \ +- "lock ; decb %0\n\t" \ ++ "1:\n" \ ++ LOCK \ ++ "decb %0\n\t" \ + "jns 4f\n\t" \ + "2:\t" \ + "testl $0x200, %1\n\t" \ +@@ -121,10 +124,34 @@ + static inline int _raw_spin_trylock(spinlock_t *lock) + { + char oldval; ++#ifdef CONFIG_SMP_ALTERNATIVES + __asm__ __volatile__( +- "xchgb %b0,%1" ++ "1:movb %1,%b0\n" ++ "movb $0,%1\n" ++ "2:" ++ ".section __smp_alternatives,\"a\"\n" ++ ".long 1b\n" ++ ".long 3f\n" ++ ".previous\n" ++ ".section __smp_replacements,\"a\"\n" ++ "3: .byte 2b - 1b\n" ++ ".byte 5f-4f\n" ++ ".byte 0\n" ++ ".byte 6f-5f\n" ++ ".byte -1\n" ++ "4: xchgb %b0,%1\n" ++ "5: movb %1,%b0\n" ++ "movb $0,%1\n" ++ "6:\n" ++ ".previous\n" + :"=q" (oldval), "=m" (lock->slock) + :"0" (0) : "memory"); ++#else ++ __asm__ __volatile__( ++ "xchgb %b0,%1\n" ++ :"=q" (oldval), "=m" (lock->slock) ++ :"0" (0) : "memory"); ++#endif + return oldval > 0; + } + +@@ -225,8 +252,8 @@ + __build_write_lock(rw, "__write_lock_failed"); + } + +-#define _raw_read_unlock(rw) asm volatile("lock ; incl %0" :"=m" ((rw)->lock) : : "memory") +-#define _raw_write_unlock(rw) asm volatile("lock ; addl $" RW_LOCK_BIAS_STR ",%0":"=m" ((rw)->lock) : : "memory") ++#define _raw_read_unlock(rw) asm volatile(LOCK "incl %0" :"=m" ((rw)->lock) : : "memory") ++#define _raw_write_unlock(rw) asm volatile(LOCK "addl $" RW_LOCK_BIAS_STR ",%0":"=m" ((rw)->lock) : : "memory") + + static inline int _raw_read_trylock(rwlock_t *lock) + { +diff -Naur linux-2.6.11/include/asm-i386/system.h linux-2.6.11.post/include/asm-i386/system.h +--- linux-2.6.11/include/asm-i386/system.h 2005-03-02 07:37:30.000000000 +0000 ++++ linux-2.6.11.post/include/asm-i386/system.h 2005-06-15 13:21:40.000000000 +0100 +@@ -5,7 +5,7 @@ + #include + #include + #include +-#include /* for LOCK_PREFIX */ ++#include + + #ifdef __KERNEL__ + +@@ -249,19 +249,19 @@ + unsigned long prev; + switch (size) { + case 1: +- __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2" ++ __asm__ __volatile__(LOCK "cmpxchgb %b1,%2" + : "=a"(prev) + : "q"(new), "m"(*__xg(ptr)), "0"(old) + : "memory"); + return prev; + case 2: +- __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2" ++ __asm__ __volatile__(LOCK "cmpxchgw %w1,%2" + : "=a"(prev) + : "q"(new), "m"(*__xg(ptr)), "0"(old) + : "memory"); + return prev; + case 4: +- __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2" ++ __asm__ __volatile__(LOCK "cmpxchgl %1,%2" + : "=a"(prev) + : "q"(new), "m"(*__xg(ptr)), "0"(old) + : "memory"); +@@ -425,11 +425,55 @@ + #endif + + #ifdef CONFIG_SMP +-#define smp_mb() mb() +-#define smp_rmb() rmb() + #define smp_wmb() wmb() +-#define smp_read_barrier_depends() read_barrier_depends() ++#if defined(CONFIG_SMP_ALTERNATIVES) && !defined(MODULE) ++#define smp_alt_mb(instr) \ ++__asm__ __volatile__("6667:\nnop\nnop\nnop\nnop\nnop\nnop\n6668:\n" \ ++ ".section __smp_alternatives,\"a\"\n" \ ++ ".long 6667b\n" \ ++ ".long 6673f\n" \ ++ ".previous\n" \ ++ ".section __smp_replacements,\"a\"\n" \ ++ "6673:.byte 6668b-6667b\n" \ ++ ".byte 6670f-6669f\n" \ ++ ".byte 6671f-6670f\n" \ ++ ".byte 0\n" \ ++ ".byte %c0\n" \ ++ "6669:lock;addl $0,0(%%esp)\n" \ ++ "6670:" instr "\n" \ ++ "6671:\n" \ ++ ".previous\n" \ ++ : \ ++ : "i" (X86_FEATURE_XMM2) \ ++ : "memory") ++#define smp_rmb() smp_alt_mb("lfence") ++#define smp_mb() smp_alt_mb("mfence") ++#define set_mb(var, value) do { \ ++unsigned long __set_mb_temp; \ ++__asm__ __volatile__("6667:movl %1, %0\n6668:\n" \ ++ ".section __smp_alternatives,\"a\"\n" \ ++ ".long 6667b\n" \ ++ ".long 6673f\n" \ ++ ".previous\n" \ ++ ".section __smp_replacements,\"a\"\n" \ ++ "6673: .byte 6668b-6667b\n" \ ++ ".byte 6670f-6669f\n" \ ++ ".byte 0\n" \ ++ ".byte 6671f-6670f\n" \ ++ ".byte -1\n" \ ++ "6669: xchg %1, %0\n" \ ++ "6670:movl %1, %0\n" \ ++ "6671:\n" \ ++ ".previous\n" \ ++ : "=m" (var), "=r" (__set_mb_temp) \ ++ : "1" (value) \ ++ : "memory"); } while (0) ++#else ++#define smp_rmb() rmb() ++#define smp_mb() mb() + #define set_mb(var, value) do { xchg(&var, value); } while (0) ++#endif ++#define smp_read_barrier_depends() read_barrier_depends() + #else + #define smp_mb() barrier() + #define smp_rmb() barrier() From 128fb33d1bdf485fc1641e81deb6d87b589a7f7a Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Fri, 17 Jun 2005 08:47:00 +0000 Subject: [PATCH 12/25] bitkeeper revision 1.1713.3.1 (42b28e04xelbNlMIz5vWQQ5_M71w0A) privcmd.h, privcmd.c: Add IOCTL_PRIVCMD_INITDOMAIN_STORE to setup dom0 xenstore page and event channel. From: Rusty Russell Signed-off-by: Christian Limpach --- .../drivers/xen/privcmd/privcmd.c | 30 +++++++++++++++++++ .../include/asm-xen/linux-public/privcmd.h | 2 ++ 2 files changed, 32 insertions(+) diff --git a/linux-2.6.11-xen-sparse/drivers/xen/privcmd/privcmd.c b/linux-2.6.11-xen-sparse/drivers/xen/privcmd/privcmd.c index 2f9d5fde38..9eea1835b5 100644 --- a/linux-2.6.11-xen-sparse/drivers/xen/privcmd/privcmd.c +++ b/linux-2.6.11-xen-sparse/drivers/xen/privcmd/privcmd.c @@ -196,6 +196,36 @@ static int privcmd_ioctl(struct inode *inode, struct file *file, } break; + case IOCTL_PRIVCMD_INITDOMAIN_STORE: + { + extern int do_xenbus_probe(void*); + + if (xen_start_info.store_evtchn != 0) { + ret = -EINVAL; + break; + } + + /* Allocate page. */ + xen_start_info.store_page = get_zeroed_page(GFP_KERNEL); + if (!xen_start_info.store_page) { + ret = -ENOMEM; + break; + } + + /* We don't refcnt properly, so set reserved on page. + * (this allocation is permanent) */ + SetPageReserved(virt_to_page(xen_start_info.store_page)); + + /* Initial connect. Setup channel and page. */ + xen_start_info.store_evtchn = data; + ret = pfn_to_mfn(virt_to_phys((void *)xen_start_info.store_page) >> + PAGE_SHIFT); + + /* We'll return then this will wait for daemon to answer */ + // kthread_run(do_xenbus_probe, NULL, "xenbus_probe"); + } + break; + default: ret = -EINVAL; break; diff --git a/linux-2.6.11-xen-sparse/include/asm-xen/linux-public/privcmd.h b/linux-2.6.11-xen-sparse/include/asm-xen/linux-public/privcmd.h index 9142c6b35d..51d1ce5acf 100644 --- a/linux-2.6.11-xen-sparse/include/asm-xen/linux-public/privcmd.h +++ b/linux-2.6.11-xen-sparse/include/asm-xen/linux-public/privcmd.h @@ -84,5 +84,7 @@ typedef struct privcmd_blkmsg _IOC(_IOC_NONE, 'P', 3, sizeof(privcmd_mmapbatch_t)) #define IOCTL_PRIVCMD_GET_MACH2PHYS_START_MFN \ _IOC(_IOC_READ, 'P', 4, sizeof(unsigned long)) +#define IOCTL_PRIVCMD_INITDOMAIN_STORE \ + _IOC(_IOC_READ, 'P', 5, 0) #endif /* __PRIVCMD_H__ */ From b68bddb48084b67eae67c9a794db4d28cb64d2f9 Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Fri, 17 Jun 2005 09:23:57 +0000 Subject: [PATCH 13/25] bitkeeper revision 1.1713.3.2 (42b296adTFf-i3SL6NuYF5MX4ai91Q) Makefile: Build libxenstore-pic.a. setup.py: Link with libxenstore-pic.a. Makefile: Build libxc-pic.a. Build xenstore once is enough. Signed-off-by: Christian Limpach --- tools/Makefile | 1 - tools/libxc/Makefile | 6 +++++- tools/python/setup.py | 2 +- tools/xenstore/Makefile | 23 ++++++++++++++++------- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/tools/Makefile b/tools/Makefile index b122ba465a..3a38e899de 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -10,7 +10,6 @@ SUBDIRS += xentrace SUBDIRS += python SUBDIRS += xcs SUBDIRS += xcutils -SUBDIRS += xenstore SUBDIRS += pygrub SUBDIRS += firmware diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile index cbe7983a44..e8c6058b7d 100644 --- a/tools/libxc/Makefile +++ b/tools/libxc/Makefile @@ -44,7 +44,8 @@ DEPS = .*.d LIB_OBJS := $(patsubst %.c,%.o,$(SRCS)) PIC_OBJS := $(patsubst %.c,%.opic,$(SRCS)) -LIB := libxc.a libxc.so libxc.so.$(MAJOR) libxc.so.$(MAJOR).$(MINOR) +LIB := libxc.a libxc-pic.a +LIB += libxc.so libxc.so.$(MAJOR) libxc.so.$(MAJOR).$(MINOR) all: build build: check-for-zlib mk-symlinks @@ -98,6 +99,9 @@ rpm: build libxc.a: $(LIB_OBJS) $(AR) rc $@ $^ +libxc-pic.a: $(PIC_OBJS) + $(AR) rc $@ $^ + libxc.so: libxc.so.$(MAJOR) ln -sf $< $@ libxc.so.$(MAJOR): libxc.so.$(MAJOR).$(MINOR) diff --git a/tools/python/setup.py b/tools/python/setup.py index fabe80bd8b..e2a5b09ca1 100644 --- a/tools/python/setup.py +++ b/tools/python/setup.py @@ -17,7 +17,7 @@ library_dirs = [ XEN_ROOT + "/tools/libxc", XEN_ROOT + "/tools/xenstore", ] -libraries = [ "xc", "xenstore" ] +libraries = [ "xc", "xenstore-pic" ] xc = Extension("xc", extra_compile_args = extra_compile_args, diff --git a/tools/xenstore/Makefile b/tools/xenstore/Makefile index 408078efba..3bfe8cb957 100644 --- a/tools/xenstore/Makefile +++ b/tools/xenstore/Makefile @@ -20,15 +20,12 @@ BASECFLAGS+= -I$(XEN_ROOT)/xen/include/public BASECFLAGS+= -I. CFLAGS += $(BASECFLAGS) -ifeq ($(XEN_TARGET_ARCH),x86_64) -CFLAGS += -fPIC -endif LDFLAGS=$(PROFILE) -L$(XEN_LIBXC) TESTDIR=`pwd`/testsuite/tmp TESTFLAGS=-DTESTING TESTENV=XENSTORED_ROOTDIR=$(TESTDIR) XENSTORED_RUNDIR=$(TESTDIR) -all: xen xenstored libxenstore.a +all: xen xenstored libxenstore.a libxenstore-pic.a testcode: xen xs_test xenstored_test xs_random @@ -56,10 +53,18 @@ xs_test_lib.o: xs.c talloc_test.o: talloc.c $(COMPILE.c) -o $@ $< -libxenstore.a: libxenstore.a(xs.o) libxenstore.a(xs_lib.o) +LIB_OBJS := xs.o xs_lib.o + +LIB_OBJS_A := $(patsubst %.o,libxenstore.a(%.o),$(LIB_OBJS)) +LIB_OBJS_PIC := $(patsubst %.o,libxenstore-pic.a(%.opic),$(LIB_OBJS)) + +libxenstore.a: $(LIB_OBJS_A) + +libxenstore-pic.a: $(LIB_OBJS_PIC) clean: testsuite-clean - rm -f *.o *.a xs_test xenstored xenstored_test xs_random xs_stress xen + rm -f *.o *.opic *.a + rm -f xs_test xenstored xenstored_test xs_random xs_stress xen -$(RM) $(PROG_DEP) check: testsuite-run randomcheck stresstest @@ -88,7 +93,7 @@ TAGS: tarball: clean cd .. && tar -c -j -v -h -f xenstore.tar.bz2 xenstore/ -install: xenstored libxenstore.a +install: xenstored libxenstore.a libxenstore-pic.a $(INSTALL_DIR) -p $(DESTDIR)/var/run/xenstored $(INSTALL_DIR) -p $(DESTDIR)/var/lib/xenstored $(INSTALL_DIR) -p $(DESTDIR)/usr/sbin @@ -96,7 +101,11 @@ install: xenstored libxenstore.a $(INSTALL_PROG) xenstored $(DESTDIR)/usr/sbin $(INSTALL_DIR) -p $(DESTDIR)/usr/$(LIBDIR) $(INSTALL_DATA) libxenstore.a $(DESTDIR)/usr/$(LIBDIR) + $(INSTALL_DATA) libxenstore-pic.a $(DESTDIR)/usr/$(LIBDIR) $(INSTALL_DATA) xs.h $(DESTDIR)/usr/include $(INSTALL_DATA) xs_lib.h $(DESTDIR)/usr/include -include $(PROG_DEP) + +# never delete any intermediate files. +.SECONDARY: From 6e1ff5f262f5c951de00817f6c261fddda6a2113 Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Fri, 17 Jun 2005 09:35:26 +0000 Subject: [PATCH 14/25] bitkeeper revision 1.1713.3.3 (42b2995e93GNUwPpV6yP21Fl3iIRRQ) Makefile: Add xs_dom0_test program to test IOCTL_PRIVCMD_INITDOMAIN_STORE. xs_dom0_test.c: new file From: Rusty Russell Signed-off-by: Christian Limpach --- .rootkeys | 1 + tools/xenstore/Makefile | 9 +++++--- tools/xenstore/xs_dom0_test.c | 43 +++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 tools/xenstore/xs_dom0_test.c diff --git a/.rootkeys b/.rootkeys index 98804345ab..4d3b69442d 100644 --- a/.rootkeys +++ b/.rootkeys @@ -1081,6 +1081,7 @@ 42a57d99-zLxBjzC7rfj_perV-orUg tools/xenstore/xenstored_watch.h 42a57d99BnkhISKgCCRcUqhteyuxCw tools/xenstore/xs.c 42a57d99FyiYSz9AkKKROrRydnA-gQ tools/xenstore/xs.h +42b29922EYQ87Y4fwZXSkEHgtQk7CQ tools/xenstore/xs_dom0_test.c 42a57d99SrtsJCDUlKyRPf3EX86A1Q tools/xenstore/xs_lib.c 42a57d99L2pYeMFyjQ_4Rnb17xTSMg tools/xenstore/xs_lib.h 42a57d99Kl6Ba8oCHv2fggl7QN9QZA tools/xenstore/xs_random.c diff --git a/tools/xenstore/Makefile b/tools/xenstore/Makefile index 3bfe8cb957..0a78cfbad7 100644 --- a/tools/xenstore/Makefile +++ b/tools/xenstore/Makefile @@ -27,7 +27,7 @@ TESTENV=XENSTORED_ROOTDIR=$(TESTDIR) XENSTORED_RUNDIR=$(TESTDIR) all: xen xenstored libxenstore.a libxenstore-pic.a -testcode: xen xs_test xenstored_test xs_random +testcode: xen xs_test xenstored_test xs_random xs_dom0_test xen: ln -sf $(XEN_ROOT)/xen/include/public $@ @@ -63,8 +63,8 @@ libxenstore.a: $(LIB_OBJS_A) libxenstore-pic.a: $(LIB_OBJS_PIC) clean: testsuite-clean - rm -f *.o *.opic *.a - rm -f xs_test xenstored xenstored_test xs_random xs_stress xen + rm -f *.o *.opic *.a xen + rm -f xs_test xenstored xenstored_test xs_random xs_stress xs_dom0_test -$(RM) $(PROG_DEP) check: testsuite-run randomcheck stresstest @@ -87,6 +87,9 @@ stresstest: xs_stress xenstored_test rm -rf $(TESTDIR)/store export $(TESTENV); PID=`./xenstored_test --output-pid`; ./xs_stress 10000; ret=$$?; kill $$PID; exit $$ret +xs_dom0_test: xs_dom0_test.o utils.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -lxc -o $@ + TAGS: etags `find . -name '*.[ch]'` diff --git a/tools/xenstore/xs_dom0_test.c b/tools/xenstore/xs_dom0_test.c new file mode 100644 index 0000000000..8b3b5e695a --- /dev/null +++ b/tools/xenstore/xs_dom0_test.c @@ -0,0 +1,43 @@ +/* Test introduction of domain 0 */ +#include +#include +#include "xs.h" +#include "utils.h" +#include +#include +#include +#include +#include + +int main() +{ + int h, local = 0, kernel = 0; + long err; + void *page; + + h = xc_interface_open(); + if (h < 0) + barf_perror("Failed to open xc"); + + if (xc_evtchn_bind_interdomain(h, DOMID_SELF, 0, &local, &kernel) != 0) + barf_perror("Failed to bind interdomain"); + + printf("Got ports %i & %i\n", local, kernel); + + err = ioctl(h, IOCTL_PRIVCMD_INITDOMAIN_STORE, kernel); + if (err < 0) + barf_perror("Failed to initialize store"); + printf("Got mfn %li\n", err); + + page = xc_map_foreign_range(h, 0, getpagesize(), PROT_READ|PROT_WRITE, + err); + if (!page) + barf_perror("Failed to map page %li", err); + printf("Mapped page at %p\n", page); + printf("Page says %s\n", (char *)page); + munmap(page, getpagesize()); + printf("unmapped\n"); + + return 0; +} + From c364cd9e1add6131c74a2507ea81ed556b0c0842 Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Fri, 17 Jun 2005 09:58:14 +0000 Subject: [PATCH 15/25] bitkeeper revision 1.1713.3.4 (42b29eb6XRlJtKSkJ3VkG8PI0Dl4sg) ignore: Add tools/xenstore/xs_dom0_test Signed-off-by: Christian Limpach --- BitKeeper/etc/ignore | 1 + 1 file changed, 1 insertion(+) diff --git a/BitKeeper/etc/ignore b/BitKeeper/etc/ignore index 33edc625d6..2bd05d6e4f 100644 --- a/BitKeeper/etc/ignore +++ b/BitKeeper/etc/ignore @@ -144,6 +144,7 @@ tools/xenstore/testsuite/tmp/* tools/xenstore/xen tools/xenstore/xenstored tools/xenstore/xenstored_test +tools/xenstore/xs_dom0_test tools/xenstore/xs_random tools/xenstore/xs_stress tools/xenstore/xs_test From 4ddc54b2db6264de8a8809d2a8763c5f4e3f4191 Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Fri, 17 Jun 2005 10:24:34 +0000 Subject: [PATCH 16/25] bitkeeper revision 1.1713.3.5 (42b2a4e2r6SNlC_nq2hAkXEQjEFAmA) Many files: - watch now takes a token, returned when reading watch - More tests - Fix domain shared page communication (flush output) - Add "home" path for domains - More permissions checks in various functions - Simplify watch acknowledgement code and fix occasional bug xs_watch_stress.c, 12readonly.sh, 11domain-watch.sh, 10domain-homedir.sh: new file xs_stress.c, xs_lib.h, xs_lib.c: Cleanup whitespace. ignore: Add tools/xenstore/xs_watch_stress Signed-off-by: Rusty Russell Signed-off-by: Christian Limpach --- .rootkeys | 4 + BitKeeper/etc/ignore | 1 + tools/python/xen/lowlevel/xs/xs.c | 35 ++-- tools/xenstore/Makefile | 14 +- tools/xenstore/testsuite/07watch.sh | 116 ++++++++++-- tools/xenstore/testsuite/10domain-homedir.sh | 12 ++ tools/xenstore/testsuite/11domain-watch.sh | 51 +++++ tools/xenstore/testsuite/12readonly.sh | 40 ++++ tools/xenstore/testsuite/test.sh | 2 +- tools/xenstore/xenstored_core.c | 126 ++++++++++--- tools/xenstore/xenstored_core.h | 19 +- tools/xenstore/xenstored_domain.c | 28 ++- tools/xenstore/xenstored_domain.h | 4 +- tools/xenstore/xenstored_transaction.c | 1 + tools/xenstore/xenstored_watch.c | 189 ++++++++++++------- tools/xenstore/xenstored_watch.h | 20 +- tools/xenstore/xs.c | 62 +++--- tools/xenstore/xs.h | 41 ++-- tools/xenstore/xs_lib.c | 3 +- tools/xenstore/xs_lib.h | 8 +- tools/xenstore/xs_stress.c | 2 +- tools/xenstore/xs_test.c | 35 ++-- tools/xenstore/xs_watch_stress.c | 120 ++++++++++++ 23 files changed, 717 insertions(+), 216 deletions(-) create mode 100644 tools/xenstore/testsuite/10domain-homedir.sh create mode 100644 tools/xenstore/testsuite/11domain-watch.sh create mode 100644 tools/xenstore/testsuite/12readonly.sh create mode 100644 tools/xenstore/xs_watch_stress.c diff --git a/.rootkeys b/.rootkeys index 4d3b69442d..d2c3de4b04 100644 --- a/.rootkeys +++ b/.rootkeys @@ -1066,6 +1066,9 @@ 42a57d98fdO519YyATk4_Zwr1STNfQ tools/xenstore/testsuite/07watch.sh 42a57d98zZUtvirUMjmHxFphJjmO7Q tools/xenstore/testsuite/08transaction.sh 42a57d98sn9RbpBgHRv1D99Kt7LwYA tools/xenstore/testsuite/09domain.sh +42b2a4bfxAwHlRgd31SJBgFnj8g3MA tools/xenstore/testsuite/10domain-homedir.sh +42b2a4bfHbUp4IB8tfNIa8j37S27fw tools/xenstore/testsuite/11domain-watch.sh +42b2a4bfhrB5v6uYKPj6jSO_Ng0PAA tools/xenstore/testsuite/12readonly.sh 42a57d98tSuoFCHnnM2GgENXJrRQmw tools/xenstore/testsuite/test.sh 42a57d98zxDP2Ti7dTznGROi66rUGw tools/xenstore/utils.c 42a57d98SDvOYCEjmCjwHSk6390GLA tools/xenstore/utils.h @@ -1087,6 +1090,7 @@ 42a57d99Kl6Ba8oCHv2fggl7QN9QZA tools/xenstore/xs_random.c 42a57d99SHYR1lQOD0shuErPDg9NKQ tools/xenstore/xs_stress.c 42a57d996aBawpkQNOWkNWXD6LrhPg tools/xenstore/xs_test.c +42b2a4bfp-lhxBfenUyHlvw7bPcVgA tools/xenstore/xs_watch_stress.c 403a3edbrr8RE34gkbR40zep98SXbg tools/xentrace/Makefile 40a107afN60pFdURgBv9KwEzgRl5mQ tools/xentrace/formats 420d52d2_znVbT4JAPIU36vQOme83g tools/xentrace/xenctx.c diff --git a/BitKeeper/etc/ignore b/BitKeeper/etc/ignore index 2bd05d6e4f..a6d5a390a0 100644 --- a/BitKeeper/etc/ignore +++ b/BitKeeper/etc/ignore @@ -148,6 +148,7 @@ tools/xenstore/xs_dom0_test tools/xenstore/xs_random tools/xenstore/xs_stress tools/xenstore/xs_test +tools/xenstore/xs_watch_stress tools/xentrace/xentrace tools/xfrd/xfrd xen/BLOG diff --git a/tools/python/xen/lowlevel/xs/xs.c b/tools/python/xen/lowlevel/xs/xs.c index 0da0fbcb3e..9c26c0f51c 100644 --- a/tools/python/xen/lowlevel/xs/xs.c +++ b/tools/python/xen/lowlevel/xs/xs.c @@ -277,10 +277,11 @@ static PyObject *xspy_set_permissions(PyObject *self, PyObject *args, static PyObject *xspy_watch(PyObject *self, PyObject *args, PyObject *kwds) { - static char *kwd_spec[] = { "path", "priority", NULL }; - static char *arg_spec = "s|i"; + static char *kwd_spec[] = { "path", "priority", "token", NULL }; + static char *arg_spec = "s|is"; char *path = NULL; int priority = 0; + char *token; struct xs_handle *xh = xshandle(self); PyObject *val = NULL; @@ -289,9 +290,9 @@ static PyObject *xspy_watch(PyObject *self, PyObject *args, PyObject *kwds) if (!xh) goto exit; if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, - &path, &priority)) + &path, &priority, &token)) goto exit; - xsval = xs_watch(xh, path, priority); + xsval = xs_watch(xh, path, token, priority); val = pyvalue_int(xsval); exit: return val; @@ -305,14 +306,19 @@ static PyObject *xspy_read_watch(PyObject *self, PyObject *args, struct xs_handle *xh = xshandle(self); PyObject *val = NULL; - char *xsval = NULL; + char **xsval = NULL; if (!xh) goto exit; if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec)) goto exit; xsval = xs_read_watch(xh); - val = pyvalue_str(xsval); + if(!xsval){ + val = PyErr_SetFromErrno(PyExc_RuntimeError); + goto exit; + } + /* Create tuple (path, token). */ + val = Py_BuildValue("(ss)", xsval[0], xsval[1]); exit: if (xsval) free(xsval); @@ -323,7 +329,8 @@ static PyObject *xspy_acknowledge_watch(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwd_spec[] = { NULL }; - static char *arg_spec = ""; + static char *arg_spec = "s"; + char *token = ""; struct xs_handle *xh = xshandle(self); PyObject *val = NULL; @@ -331,9 +338,9 @@ static PyObject *xspy_acknowledge_watch(PyObject *self, PyObject *args, if (!xh) goto exit; - if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &token)) goto exit; - xsval = xs_acknowledge_watch(xh); + xsval = xs_acknowledge_watch(xh, token); val = pyvalue_int(xsval); exit: return val; @@ -341,9 +348,10 @@ static PyObject *xspy_acknowledge_watch(PyObject *self, PyObject *args, static PyObject *xspy_unwatch(PyObject *self, PyObject *args, PyObject *kwds) { - static char *kwd_spec[] = { "path", NULL }; - static char *arg_spec = "s|"; + static char *kwd_spec[] = { "path", "token", NULL }; + static char *arg_spec = "s|s"; char *path = NULL; + char *token = ""; struct xs_handle *xh = xshandle(self); PyObject *val = NULL; @@ -351,9 +359,10 @@ static PyObject *xspy_unwatch(PyObject *self, PyObject *args, PyObject *kwds) if (!xh) goto exit; - if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path, + &token)) goto exit; - xsval = xs_unwatch(xh, path); + xsval = xs_unwatch(xh, path, token); val = pyvalue_int(xsval); exit: return val; diff --git a/tools/xenstore/Makefile b/tools/xenstore/Makefile index 0a78cfbad7..494a7f20d3 100644 --- a/tools/xenstore/Makefile +++ b/tools/xenstore/Makefile @@ -41,8 +41,9 @@ xenstored_test: xenstored_core_test.o xenstored_watch_test.o xenstored_domain_te xs_test: xs_test.o xs_lib.o utils.o xs_random: xs_random.o xs_test_lib.o xs_lib.o talloc.o utils.o xs_stress: xs_stress.o xs_test_lib.o xs_lib.o talloc.o utils.o +xs_watch_stress: xs_watch_stress.o xs_test_lib.o xs_lib.o talloc.o utils.o -xs_test.o xs_stress.o xenstored_core_test.o xenstored_watch_test.o xenstored_transaction_test.o xenstored_domain_test.o xs_random.o xs_test_lib.o talloc_test.o fake_libxc.o: CFLAGS=$(BASECFLAGS) $(TESTFLAGS) +xs_test.o xs_stress.o xs_watch_stress.o xenstored_core_test.o xenstored_watch_test.o xenstored_transaction_test.o xenstored_domain_test.o xs_random.o xs_test_lib.o talloc_test.o fake_libxc.o: CFLAGS=$(BASECFLAGS) $(TESTFLAGS) xenstored_%_test.o: xenstored_%.c $(COMPILE.c) -o $@ $< @@ -63,8 +64,9 @@ libxenstore.a: $(LIB_OBJS_A) libxenstore-pic.a: $(LIB_OBJS_PIC) clean: testsuite-clean - rm -f *.o *.opic *.a xen - rm -f xs_test xenstored xenstored_test xs_random xs_stress xs_dom0_test + rm -f *.o *.opic *.a + rm -f xen xenstored xs_random xs_stress xs_watch_stress + rm -f xs_test xenstored_test xs_dom0_test -$(RM) $(PROG_DEP) check: testsuite-run randomcheck stresstest @@ -83,9 +85,11 @@ randomcheck: xs_random xenstored_test $(TESTENV) ./xs_random --fast /tmp/xs_random 100000 $(RANDSEED) $(TESTENV) ./xs_random --fail /tmp/xs_random 10000 $(RANDSEED) -stresstest: xs_stress xenstored_test +stresstest: xs_stress xs_watch_stress xenstored_test rm -rf $(TESTDIR)/store - export $(TESTENV); PID=`./xenstored_test --output-pid`; ./xs_stress 10000; ret=$$?; kill $$PID; exit $$ret + export $(TESTENV); PID=`./xenstored_test --output-pid`; ./xs_stress 5000; ret=$$?; kill $$PID; exit $$ret + rm -rf $(TESTDIR)/store + export $(TESTENV); PID=`./xenstored_test --output-pid`; ./xs_watch_stress; ret=$$?; kill $$PID; exit $$ret xs_dom0_test: xs_dom0_test.o utils.o $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -lxc -o $@ diff --git a/tools/xenstore/testsuite/07watch.sh b/tools/xenstore/testsuite/07watch.sh index bedce6ad5b..e6156ea7f8 100644 --- a/tools/xenstore/testsuite/07watch.sh +++ b/tools/xenstore/testsuite/07watch.sh @@ -3,30 +3,118 @@ # Watch something, write to it, check watch has fired. [ "`echo -e 'write /test create contents' | ./xs_test 2>&1`" = "" ] -[ "`echo -e '1 watch /test 100\n2 write /test create contents2\n1 waitwatch\n1 ackwatch' | ./xs_test 2>&1`" = "1:/test" ] +[ "`echo -e '1 watch /test token 100 +2 write /test create contents2 +1 waitwatch +1 ackwatch token' | ./xs_test 2>&1`" = "1:/test:token" ] # Check that reads don't set it off. -[ "`echo -e '1 watch /test 100\n2 read /test\n1 waitwatch' | ./xs_test 2>&1`" = "2:contents2 +[ "`echo -e '1 watch /test token 100 +2 read /test +1 waitwatch' | ./xs_test 2>&1`" = "2:contents2 1:waitwatch timeout" ] -# mkdir, setperm and rm should (also /tests watching dirs) +# mkdir, setperm and rm should (also tests watching dirs) [ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "" ] -[ "`echo -e '1 watch /dir 100\n2 mkdir /dir/newdir\n1 waitwatch\n1 ackwatch\n2 setperm /dir/newdir 0 READ\n1 waitwatch\n1 ackwatch\n2 rm /dir/newdir\n1 waitwatch\n1 ackwatch' | ./xs_test 2>&1`" = "1:/dir/newdir -1:/dir/newdir -1:/dir/newdir" ] +[ "`echo -e '1 watch /dir token 100 +2 mkdir /dir/newdir +1 waitwatch +1 ackwatch token +2 setperm /dir/newdir 0 READ +1 waitwatch +1 ackwatch token +2 rm /dir/newdir +1 waitwatch +1 ackwatch token' | ./xs_test 2>&1`" = "1:/dir/newdir:token +1:/dir/newdir:token +1:/dir/newdir:token" ] # ignore watches while doing commands, should work. -[ "`echo -e 'watch /dir 100\nwrite /dir/test create contents\nread /dir/test\nwaitwatch\nackwatch' | ./xs_test 2>&1`" = "contents -/dir/test" ] +[ "`echo -e 'watch /dir token 100 +write /dir/test create contents +read /dir/test +waitwatch +ackwatch token' | ./xs_test 2>&1`" = "contents +/dir/test:token" ] # watch priority /test. -[ "`echo -e '1 watch /dir 1\n3 watch /dir 3\n2 watch /dir 2\nwrite /dir/test create contents\n3 waitwatch\n3 ackwatch\n2 waitwatch\n2 ackwatch\n1 waitwatch\n1 ackwatch' | ./xs_test 2>&1`" = "3:/dir/test -2:/dir/test -1:/dir/test" ] +[ "`echo -e '1 watch /dir token1 1 +3 watch /dir token3 3 +2 watch /dir token2 2 +write /dir/test create contents +3 waitwatch +3 ackwatch token3 +2 waitwatch +2 ackwatch token2 +1 waitwatch +1 ackwatch token1' | ./xs_test 2>&1`" = "3:/dir/test:token3 +2:/dir/test:token2 +1:/dir/test:token1" ] # If one dies (without acking), the other should still get ack. -[ "`echo -e '1 watch /dir 0\n2 watch /dir 1\nwrite /dir/test create contents\n2 waitwatch\n2 close\n1 waitwatch\n1 ackwatch' | ./xs_test 2>&1`" = "2:/dir/test -1:/dir/test" ] +[ "`echo -e '1 watch /dir token1 0 +2 watch /dir token2 1 +write /dir/test create contents +2 waitwatch +2 close +1 waitwatch +1 ackwatch token1' | ./xs_test 2>&1`" = "2:/dir/test:token2 +1:/dir/test:token1" ] # If one dies (without reading at all), the other should still get ack. -[ "`echo -e '1 watch /dir 0\n2 watch /dir 1\nwrite /dir/test create contents\n2 close\n1 waitwatch\n1 ackwatch' | ./xs_test 2>&1`" = "1:/dir/test" ] +[ "`echo -e '1 watch /dir token1 0 +2 watch /dir token2 1 +write /dir/test create contents +2 close +1 waitwatch +1 ackwatch token1' | ./xs_test 2>&1`" = "1:/dir/test:token1" ] + +# unwatch +[ "`echo -e '1 watch /dir token1 0 +1 unwatch /dir token1 +1 watch /dir token2 0 +2 write /dir/test2 create contents +1 waitwatch +1 unwatch /dir token2' | ./xs_test 2>&1`" = "1:/dir/test2:token2" ] + +# unwatch while watch pending. +[ "`echo -e '1 watch /dir token1 0 +2 watch /dir token2 1 +write /dir/test create contents +2 unwatch /dir token2 +1 waitwatch +1 ackwatch token1' | ./xs_test 2>&1`" = "1:/dir/test:token1" ] + +# check we only get notified once. +[ "`echo -e '1 watch /test token 100 +2 write /test create contents2 +1 waitwatch +1 ackwatch token +1 waitwatch' | ./xs_test 2>&1`" = "1:/test:token +1:waitwatch timeout" ] + +# watches are queued in order. +[ "`echo -e '1 watch / token 100 +2 write /test1 create contents +2 write /test2 create contents +2 write /test3 create contents +1 waitwatch +1 ackwatch token +1 waitwatch +1 ackwatch token +1 waitwatch +1 ackwatch token' | ./xs_test 2>&1`" = "1:/test1:token +1:/test2:token +1:/test3:token" ] + +# Creation of subpaths should be covered correctly. +[ "`echo -e '1 watch / token 100 +2 write /test/subnode create contents2 +2 write /test/subnode/subnode create contents2 +1 waitwatch +1 ackwatch token +1 waitwatch +1 ackwatch token +1 waitwatch' | ./xs_test 2>&1`" = "1:/test/subnode:token +1:/test/subnode/subnode:token +1:waitwatch timeout" ] diff --git a/tools/xenstore/testsuite/10domain-homedir.sh b/tools/xenstore/testsuite/10domain-homedir.sh new file mode 100644 index 0000000000..a3587d2a5e --- /dev/null +++ b/tools/xenstore/testsuite/10domain-homedir.sh @@ -0,0 +1,12 @@ +#! /bin/sh +# Test domain "implicit" paths. + +# Create a domain, write an entry using implicit path, read using implicit +[ "`echo -e 'mkdir /home +introduce 1 100 7 /home +1 write entry1 create contents +read /home/entry1 +dir /home' | ./xs_test 2>&1`" = "handle is 1 +contents +entry1" ] + diff --git a/tools/xenstore/testsuite/11domain-watch.sh b/tools/xenstore/testsuite/11domain-watch.sh new file mode 100644 index 0000000000..f42fb5f8c6 --- /dev/null +++ b/tools/xenstore/testsuite/11domain-watch.sh @@ -0,0 +1,51 @@ +#! /bin/sh +# Test watching from a domain. + +# Watch something, write to it, check watch has fired. +[ "`echo -e 'write /test create contents' | ./xs_test 2>&1`" = "" ] +[ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "" ] + +[ "`echo -e 'introduce 1 100 7 /my/home +1 watch /test token 100 +write /test create contents2 +1 waitwatch +1 ackwatch token +1 unwatch /test token +release 1' | ./xs_test 2>&1`" = "handle is 1 +1:/test:token" ] + +# ignore watches while doing commands, should work. +[ "`echo -e 'introduce 1 100 7 /my/home +1 watch /dir token 100 +1 write /dir/test create contents +1 read /dir/test +1 waitwatch +1 ackwatch token +release 1' | ./xs_test 2>&1`" = "handle is 1 +1:contents +1:/dir/test:token" ] + +# unwatch +[ "`echo -e 'introduce 1 100 7 /my/home +1 watch /dir token1 0 +1 unwatch /dir token1 +1 watch /dir token2 0 +2 write /dir/test2 create contents +1 waitwatch +1 unwatch /dir token2 +release 1' | ./xs_test 2>&1`" = "handle is 1 +1:/dir/test2:token2" ] + +# unwatch while watch pending. +[ "`echo -e 'introduce 1 100 7 /my/home +introduce 2 101 8 /my/secondhome +1 watch /dir token1 0 +2 watch /dir token2 1 +write /dir/test create contents +2 unwatch /dir token2 +1 waitwatch +1 ackwatch token1 +release 1 +release 2' | ./xs_test 2>&1`" = "handle is 1 +handle is 2 +1:/dir/test:token1" ] diff --git a/tools/xenstore/testsuite/12readonly.sh b/tools/xenstore/testsuite/12readonly.sh new file mode 100644 index 0000000000..5e7501a2e6 --- /dev/null +++ b/tools/xenstore/testsuite/12readonly.sh @@ -0,0 +1,40 @@ +#! /bin/sh +# Test that read only connection can't alter store. + +[ "`echo 'write /test create contents' | ./xs_test 2>&1`" = "" ] + +# These are all valid. +[ "`echo 'dir / +read /test +getperm /test +watch /test token 0 +unwatch /test token +start / +commit +start / +abort' | ./xs_test --readonly 2>&1`" = "test +contents +0 NONE" ] + +# These don't work +[ "`echo 'write /test2 create contents' | ./xs_test --readonly 2>&1`" = "FATAL: write: Read-only file system" ] +[ "`echo 'write /test create contents' | ./xs_test --readonly 2>&1`" = "FATAL: write: Read-only file system" ] +[ "`echo 'setperm /test 100 NONE' | ./xs_test --readonly 2>&1`" = "FATAL: setperm: Read-only file system" ] +[ "`echo 'setperm /test 100 NONE' | ./xs_test --readonly 2>&1`" = "FATAL: setperm: Read-only file system" ] +[ "`echo 'shutdown' | ./xs_test --readonly 2>&1`" = "FATAL: shutdown: Read-only file system" ] +[ "`echo 'introduce 1 100 7 /home' | ./xs_test --readonly 2>&1`" = "FATAL: introduce: Read-only file system" ] + +# Check that watches work like normal. +set -m +[ "`echo 'watch / token 0 +waitwatch +ackwatch token' | ./xs_test --readonly 2>&1`" = "/test:token" ] & + +[ "`echo 'write /test create contents' | ./xs_test 2>&1`" = "" ] +if wait; then :; else + echo Readonly wait test failed: $? + exit 1 +fi + + + diff --git a/tools/xenstore/testsuite/test.sh b/tools/xenstore/testsuite/test.sh index 5718e84a15..3f0055842d 100755 --- a/tools/xenstore/testsuite/test.sh +++ b/tools/xenstore/testsuite/test.sh @@ -9,7 +9,7 @@ run_test() mkdir $XENSTORED_ROOTDIR # Weird failures with this. if type valgrind >/dev/null 2>&1; then - valgrind -q --logfile-fd=3 ./xenstored_test --output-pid --no-fork 3>testsuite/tmp/vgout > /tmp/pid & + valgrind -q --logfile-fd=3 ./xenstored_test --output-pid --no-fork 3>testsuite/tmp/vgout > /tmp/pid 2> testsuite/tmp/xenstored_errors & while [ ! -s /tmp/pid ]; do sleep 0; done PID=`cat /tmp/pid` rm /tmp/pid diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c index 1df00f37b4..9f7ff2e1ce 100644 --- a/tools/xenstore/xenstored_core.c +++ b/tools/xenstore/xenstored_core.c @@ -122,6 +122,33 @@ void __attribute__((noreturn)) corrupt(struct connection *conn, _exit(2); } +static char *sockmsg_string(enum xsd_sockmsg_type type) +{ + switch (type) { + case XS_DEBUG: return "DEBUG"; + case XS_SHUTDOWN: return "SHUTDOWN"; + case XS_DIRECTORY: return "DIRECTORY"; + case XS_READ: return "READ"; + case XS_GET_PERMS: return "GET_PERMS"; + case XS_WATCH: return "WATCH"; + case XS_WATCH_ACK: return "WATCH_ACK"; + case XS_UNWATCH: return "UNWATCH"; + case XS_TRANSACTION_START: return "TRANSACTION_START"; + case XS_TRANSACTION_END: return "TRANSACTION_END"; + case XS_INTRODUCE: return "INTRODUCE"; + case XS_RELEASE: return "RELEASE"; + case XS_GETDOMAINPATH: return "GETDOMAINPATH"; + case XS_WRITE: return "WRITE"; + case XS_MKDIR: return "MKDIR"; + case XS_RM: return "RM"; + case XS_SET_PERMS: return "SET_PERMS"; + case XS_WATCH_EVENT: return "WATCH_EVENT"; + case XS_ERROR: return "ERROR"; + default: + return "**UNKNOWN**"; + } +} + static bool write_message(struct connection *conn) { int ret; @@ -129,8 +156,9 @@ static bool write_message(struct connection *conn) if (out->inhdr) { if (verbose) - xprintf("Writing msg %i out to %p\n", - out->hdr.msg.type, conn); + xprintf("Writing msg %s (%s) out to %p\n", + sockmsg_string(out->hdr.msg.type), + out->buffer, conn); ret = conn->write(conn, out->hdr.raw + out->used, sizeof(out->hdr) - out->used); if (ret < 0) @@ -148,9 +176,6 @@ static bool write_message(struct connection *conn) return true; } - if (verbose) - xprintf("Writing data len %i out to %p\n", - out->hdr.msg.len, conn); ret = conn->write(conn, out->buffer + out->used, out->hdr.msg.len - out->used); @@ -162,10 +187,7 @@ static bool write_message(struct connection *conn) return true; conn->out = NULL; - - /* If this was an event, we wait for ack, otherwise we're done. */ - if (!is_watch_event(conn, out)) - talloc_free(out); + talloc_free(out); queue_next_event(conn); return true; @@ -402,7 +424,7 @@ static bool valid_chars(const char *node) "0123456789-/_@") == strlen(node)); } -static bool is_valid_nodename(const char *node) +bool is_valid_nodename(const char *node) { /* Must start in /. */ if (!strstarts(node, "/")) @@ -601,17 +623,24 @@ static int check_with_parents(struct connection *conn, const char *node, return errnum; } +char *canonicalize(struct connection *conn, const char *node) +{ + const char *prefix; + + if (!node || strstarts(node, "/")) + return (char *)node; + prefix = get_implicit_path(conn); + if (prefix) + return talloc_asprintf(node, "%s/%s", prefix, node); + return (char *)node; +} + bool check_node_perms(struct connection *conn, const char *node, enum xs_perm_type perm) { struct xs_permissions *perms; unsigned int num; - if (!node) { - errno = EINVAL; - return false; - } - if (!node || !is_valid_nodename(node)) { errno = EINVAL; return false; @@ -651,6 +680,7 @@ static bool send_directory(struct connection *conn, const char *node) DIR *dir; struct dirent *dirent; + node = canonicalize(conn, node); if (!check_node_perms(conn, node, XS_PERM_READ)) return send_error(conn, errno); @@ -680,6 +710,7 @@ static bool do_read(struct connection *conn, const char *node) unsigned int size; int *fd; + node = canonicalize(conn, node); if (!check_node_perms(conn, node, XS_PERM_READ)) return send_error(conn, errno); @@ -750,7 +781,7 @@ static bool do_write(struct connection *conn, struct buffered_data *in) if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) return send_error(conn, EINVAL); - node = vec[0]; + node = canonicalize(conn, vec[0]); if (!within_transaction(conn->transaction, node)) return send_error(conn, EROFS); @@ -804,6 +835,7 @@ static bool do_write(struct connection *conn, struct buffered_data *in) static bool do_mkdir(struct connection *conn, const char *node) { + node = canonicalize(conn, node); if (!check_node_perms(conn, node, XS_PERM_WRITE|XS_PERM_CREATE)) return send_error(conn, errno); @@ -826,6 +858,7 @@ static bool do_rm(struct connection *conn, const char *node) { char *tmppath, *path; + node = canonicalize(conn, node); if (!check_node_perms(conn, node, XS_PERM_WRITE)) return send_error(conn, errno); @@ -848,6 +881,7 @@ static bool do_rm(struct connection *conn, const char *node) add_change_node(conn->transaction, node); send_ack(conn, XS_RM); + /* FIXME: traverse and fire watches for ALL of them! */ fire_watches(conn->transaction, node); return false; } @@ -858,6 +892,7 @@ static bool do_get_perms(struct connection *conn, const char *node) char *strings; unsigned int len, num; + node = canonicalize(conn, node); if (!check_node_perms(conn, node, XS_PERM_READ)) return send_error(conn, errno); @@ -883,7 +918,7 @@ static bool do_set_perms(struct connection *conn, struct buffered_data *in) return send_error(conn, EINVAL); /* First arg is node name. */ - node = in->buffer; + node = canonicalize(conn, in->buffer); in->buffer += strlen(in->buffer) + 1; num--; @@ -968,10 +1003,10 @@ static bool process_message(struct connection *conn, struct buffered_data *in) return do_watch(conn, in); case XS_WATCH_ACK: - return do_watch_ack(conn); + return do_watch_ack(conn, onearg(in)); case XS_UNWATCH: - return do_unwatch(conn, onearg(in)); + return do_unwatch(conn, in); case XS_TRANSACTION_START: return do_transaction_start(conn, onearg(in)); @@ -1015,13 +1050,13 @@ static void consider_message(struct connection *conn) } if (verbose) - xprintf("Got message %i len %i from %p\n", - type, conn->in->hdr.msg.len, conn); + xprintf("Got message %s len %i from %p\n", + sockmsg_string(type), conn->in->hdr.msg.len, conn); /* We might get a command while waiting for an ack: this means * the other end discarded it: we will re-transmit. */ if (type != XS_WATCH_ACK) - reset_watch_event(conn); + conn->waiting_for_ack = false; /* Careful: process_message may free connection. We detach * "in" beforehand and allocate the new buffer to avoid @@ -1136,7 +1171,6 @@ struct connection *new_connection(connwritefn_t *write, connreadfn_t *read) new->blocked = false; new->out = new->waiting_reply = NULL; - new->event = NULL; new->fd = -1; new->id = 0; new->domain = NULL; @@ -1203,6 +1237,42 @@ static void time_relative_to_now(struct timeval *tv) } } +#ifdef TESTING +/* Useful for running under debugger. */ +void dump_connection(void) +{ + struct connection *i; + + list_for_each_entry(i, &connections, list) { + printf("Connection %p:\n", i); + if (i->id) + printf(" id = %i\n", i->id); + if (i->blocked) + printf(" blocked on = %s\n", i->blocked); + if (i->waiting_for_ack) + printf(" waiting_for_ack TRUE\n"); + if (!i->in->inhdr || i->in->used) + printf(" got %i bytes of %s\n", + i->in->used, i->in->inhdr ? "header" : "data"); + if (i->out) + printf(" sending message %s (%s) out\n", + sockmsg_string(i->out->hdr.msg.type), + i->out->buffer); + if (i->waiting_reply) + printf(" ... and behind is queued %s (%s)\n", + sockmsg_string(i->waiting_reply->hdr.msg.type), + i->waiting_reply->buffer); +#if 0 + if (i->transaction) + dump_transaction(i); + if (i->domain) + dump_domain(i); +#endif + dump_watches(i); + } +} +#endif + static struct option options[] = { { "no-fork", 0, NULL, 'N' }, { "verbose", 0, NULL, 'V' }, { "output-pid", 0, NULL, 'P' }, @@ -1314,6 +1384,7 @@ int main(int argc, char *argv[]) timerclear(&tv); shortest_transaction_timeout(&tv); + shortest_watch_ack_timeout(&tv); if (timerisset(&tv)) { time_relative_to_now(&tv); tvp = &tv; @@ -1351,8 +1422,15 @@ int main(int argc, char *argv[]) } } - if (tvp) + /* Flush output for domain connections, */ + list_for_each_entry(i, &connections, list) + if (i->domain && i->out) + handle_output(i); + + if (tvp) { check_transaction_timeout(); + check_watch_ack_timeout(); + } /* If transactions ended, we might be able to do more work. */ unblock_connections(); diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h index 0d0ebcaae0..a82ae8b22e 100644 --- a/tools/xenstore/xenstored_core.h +++ b/tools/xenstore/xenstored_core.h @@ -16,8 +16,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _XENSTORED_INTERNAL_H -#define _XENSTORED_INTERNAL_H + +#ifndef _XENSTORED_CORE_H +#define _XENSTORED_CORE_H + #include #include #include @@ -59,8 +61,8 @@ struct connection /* Is this a read-only connection? */ bool can_write; - /* Our current event. If all used, we're waiting for ack. */ - struct watch_event *event; + /* Are we waiting for a watch event ack? */ + bool waiting_for_ack; /* Buffered incoming data. */ struct buffered_data *in; @@ -105,6 +107,9 @@ bool send_ack(struct connection *conn, enum xsd_sockmsg_type type); /* Send an error: error is usually "errno". */ bool send_error(struct connection *conn, int error); +/* Canonicalize this path if possible. */ +char *canonicalize(struct connection *conn, const char *node); + /* Check permissions on this node. */ bool check_node_perms(struct connection *conn, const char *node, enum xs_perm_type perm); @@ -121,6 +126,10 @@ struct connection *new_connection(connwritefn_t *write, connreadfn_t *read); void handle_input(struct connection *conn); void handle_output(struct connection *conn); +/* Is this a valid node name? */ +bool is_valid_nodename(const char *node); + /* Convenient talloc-style destructor for paths. */ int destroy_path(void *path); -#endif /* _XENSTORED_INTERNAL_H */ + +#endif /* _XENSTORED_CORE_H */ diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c index a6f69ddf5b..8b154c49e4 100644 --- a/tools/xenstore/xenstored_domain.c +++ b/tools/xenstore/xenstored_domain.c @@ -65,11 +65,6 @@ struct domain static LIST_HEAD(domains); -void domain_set_conn(struct domain *domain, struct connection *conn) -{ - domain->conn = conn; -} - struct ringbuf_head { u32 write; /* Next place to write to */ @@ -268,6 +263,9 @@ bool do_introduce(struct connection *conn, struct buffered_data *in) if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) return send_error(conn, EINVAL); + if (conn->id != 0) + return send_error(conn, EACCES); + if (!conn->can_write) return send_error(conn, EROFS); @@ -275,10 +273,9 @@ bool do_introduce(struct connection *conn, struct buffered_data *in) domain = talloc(in, struct domain); domain->domid = atoi(vec[0]); domain->port = atoi(vec[2]); - domain->path = talloc_strdup(domain, vec[3]); - talloc_set_destructor(domain, destroy_domain); - if (!domain->port || !domain->domid) + if (!domain->port || !domain->domid || !is_valid_nodename(vec[3])) return send_error(conn, EINVAL); + domain->path = talloc_strdup(domain, vec[3]); domain->page = xc_map_foreign_range(*xc_handle, domain->domid, getpagesize(), PROT_READ|PROT_WRITE, @@ -286,6 +283,9 @@ bool do_introduce(struct connection *conn, struct buffered_data *in) if (!domain->page) return send_error(conn, errno); + list_add(&domain->list, &domains); + talloc_set_destructor(domain, destroy_domain); + /* One in each half of page. */ domain->input = domain->page; domain->output = domain->page + getpagesize()/2; @@ -298,7 +298,6 @@ bool do_introduce(struct connection *conn, struct buffered_data *in) domain->conn->domain = domain; talloc_steal(domain->conn, domain); - list_add(&domain->list, &domains); return send_ack(conn, XS_INTRODUCE); } @@ -327,6 +326,9 @@ bool do_release(struct connection *conn, const char *domid_str) if (!domid) return send_error(conn, EINVAL); + if (conn->id != 0) + return send_error(conn, EACCES); + domain = find_domain_by_domid(domid); if (!domain) return send_error(conn, ENOENT); @@ -365,6 +367,14 @@ static int close_xc_handle(void *_handle) return 0; } +/* Returns the implicit path of a connection (only domains have this) */ +const char *get_implicit_path(const struct connection *conn) +{ + if (!conn->domain) + return NULL; + return conn->domain->path; +} + /* Returns the event channel handle. */ int domain_init(void) { diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h index 20e85a54b5..74dc34e8e5 100644 --- a/tools/xenstore/xenstored_domain.h +++ b/tools/xenstore/xenstored_domain.h @@ -16,6 +16,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #ifndef _XENSTORED_DOMAIN_H #define _XENSTORED_DOMAIN_H @@ -33,6 +34,7 @@ bool do_get_domain_path(struct connection *conn, const char *domid_str); /* Returns the event channel handle */ int domain_init(void); -void domain_set_conn(struct domain *domain, struct connection *conn); +/* Returns the implicit path of a connection (only domains have this) */ +const char *get_implicit_path(const struct connection *conn); #endif /* _XENSTORED_DOMAIN_H */ diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c index ca37307f8c..dd70579109 100644 --- a/tools/xenstore/xenstored_transaction.c +++ b/tools/xenstore/xenstored_transaction.c @@ -201,6 +201,7 @@ bool do_transaction_start(struct connection *conn, const char *node) if (conn->transaction) return send_error(conn, EBUSY); + node = canonicalize(conn, node); if (!check_node_perms(conn, node, XS_PERM_READ)) return send_error(conn, errno); diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c index 2df83e1a54..d0e00f53c2 100644 --- a/tools/xenstore/xenstored_watch.c +++ b/tools/xenstore/xenstored_watch.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include "talloc.h" #include "list.h" #include "xenstored_watch.h" @@ -28,6 +30,8 @@ #include "utils.h" #include "xenstored_test.h" +/* FIXME: time out unacked watches. */ + /* We create this if anyone is interested "node", then we pass it from * watch to watch as each connection acks it. */ @@ -39,7 +43,10 @@ struct watch_event /* Watch we are currently attached to. */ struct watch *watch; - struct buffered_data *data; + struct timeval timeout; + + /* Name of node which changed. */ + char *node; }; struct watch @@ -50,72 +57,63 @@ struct watch /* Current outstanding events applying to this watch. */ struct list_head events; + char *token; char *node; struct connection *conn; }; static LIST_HEAD(watches); -static void reset_event(struct watch_event *event) +static struct watch_event *get_first_event(struct connection *conn) { - event->data->inhdr = true; - event->data->used = 0; -} + struct watch *watch; + struct watch_event *event; -/* We received a non-ACK response: re-queue any watch we just sent. */ -void reset_watch_event(struct connection *conn) -{ - if (waiting_for_ack(conn)) - reset_event(conn->event); -} + /* Find first watch with an event. */ + list_for_each_entry(watch, &watches, list) { + if (watch->conn != conn) + continue; -/* We're waiting if we have an event and we sent it all. */ -bool waiting_for_ack(struct connection *conn) -{ - if (!conn->event) - return false; - - if (conn->event->data->inhdr) - return false; - return conn->event->data->used == conn->event->data->hdr.msg.len; -} - -bool is_watch_event(struct connection *conn, struct buffered_data *out) -{ - return (conn->event && out == conn->event->data); + event = list_top(&watch->events, struct watch_event, list); + if (event) + return event; + } + return NULL; } /* Look through our watches: if any of them have an event, queue it. */ void queue_next_event(struct connection *conn) { - struct watch *watch; + struct watch_event *event; + char *buffer; + unsigned int len; - /* We had a reply queued already? Send it. */ + /* We had a reply queued already? Send it: other end will + * discard watch. */ if (conn->waiting_reply) { conn->out = conn->waiting_reply; conn->waiting_reply = NULL; + conn->waiting_for_ack = false; return; } - /* If we're waiting for ack, don't queue more. */ - if (waiting_for_ack(conn)) + /* If we're already waiting for ack, don't queue more. */ + if (conn->waiting_for_ack) return; - /* Find a good event to send. */ - if (!conn->event) { - list_for_each_entry(watch, &watches, list) { - if (watch->conn != conn) - continue; + event = get_first_event(conn); + if (!event) + return; - conn->event = list_top(&watch->events, - struct watch_event, list); - if (conn->event) - break; - } - if (!conn->event) - return; - } + /* If we decide to cancel, we will reset this. */ + conn->waiting_for_ack = true; - conn->out = conn->event->data; + /* Create reply from path and token */ + len = strlen(event->node) + 1 + strlen(event->watch->token) + 1; + buffer = talloc_array(conn, char, len); + strcpy(buffer, event->node); + strcpy(buffer+strlen(event->node)+1, event->watch->token); + send_reply(conn, XS_WATCH_EVENT, buffer, len); + talloc_free(buffer); } /* Watch on DIR applies to DIR, DIR/FILE, but not DIRLONG. */ @@ -160,14 +158,15 @@ void fire_watches(struct transaction *trans, const char *node) /* Create and fill in info about event. */ event = talloc(talloc_autofree_context(), struct watch_event); - event->data = new_buffer(event); - event->data->hdr.msg.type = XS_WATCH_EVENT; - event->data->hdr.msg.len = strlen(node) + 1; - event->data->buffer = talloc_strdup(event->data, node); + event->node = talloc_strdup(event, node); /* Tie event to this watch. */ event->watch = watch; - list_add(&event->list, &watch->events); + list_add_tail(&event->list, &watch->events); + + /* Warn if not finished after thirty seconds. */ + gettimeofday(&event->timeout, NULL); + event->timeout.tv_sec += 30; /* If connection not doing anything, queue this. */ if (!watch->conn->out) @@ -178,16 +177,15 @@ void fire_watches(struct transaction *trans, const char *node) static void move_event_onwards(struct watch_event *event) { list_del(&event->list); - reset_event(event); /* Remove from this watch, and find next watch to put this on. */ - event->watch = find_next_watch(event->watch, event->data->buffer); + event->watch = find_next_watch(event->watch, event->node); if (!event->watch) { talloc_free(event); return; } - list_add(&event->list, &event->watch->events); + list_add_tail(&event->list, &event->watch->events); /* If connection not doing anything, queue this. */ if (!event->watch->conn->out) @@ -199,10 +197,6 @@ static int destroy_watch(void *_watch) struct watch *watch = _watch; struct watch_event *event; - /* Forget about sending out or waiting for acks for this watch. */ - if (watch->conn->event && watch->conn->event->watch == watch) - watch->conn->event = NULL; - /* If we have pending events, pass them on to others. */ while ((event = list_top(&watch->events, struct watch_event, list))) move_event_onwards(event); @@ -227,21 +221,59 @@ static void insert_watch(struct watch *watch) list_add_tail(&watch->list, &watches); } +void shortest_watch_ack_timeout(struct timeval *tv) +{ + struct watch *watch; + + list_for_each_entry(watch, &watches, list) { + struct watch_event *i; + list_for_each_entry(i, &watch->events, list) { + if (!timerisset(&i->timeout)) + continue; + if (!timerisset(tv) || timercmp(&i->timeout, tv, <)) + *tv = i->timeout; + } + } +} + +void check_watch_ack_timeout(void) +{ + struct watch *watch; + struct timeval now; + + gettimeofday(&now, NULL); + list_for_each_entry(watch, &watches, list) { + struct watch_event *i, *tmp; + list_for_each_entry_safe(i, tmp, &watch->events, list) { + if (!timerisset(&i->timeout)) + continue; + if (timercmp(&i->timeout, &now, <)) { + xprintf("Warning: timeout on watch event %s" + " token %s\n", + i->node, watch->token); + timerclear(&i->timeout); + } + } + } +} + bool do_watch(struct connection *conn, struct buffered_data *in) { struct watch *watch; - char *vec[2]; + char *vec[3]; if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) return send_error(conn, EINVAL); + vec[0] = canonicalize(conn, vec[0]); if (!check_node_perms(conn, vec[0], XS_PERM_READ)) return send_error(conn, errno); watch = talloc(conn, struct watch); watch->node = talloc_strdup(watch, vec[0]); + watch->token = talloc_strdup(watch, vec[1]); watch->conn = conn; - watch->priority = strtoul(vec[1], NULL, 0); + watch->priority = strtoul(vec[2], NULL, 0); INIT_LIST_HEAD(&watch->events); insert_watch(watch); @@ -249,31 +281,58 @@ bool do_watch(struct connection *conn, struct buffered_data *in) return send_ack(conn, XS_WATCH); } -bool do_watch_ack(struct connection *conn) +bool do_watch_ack(struct connection *conn, const char *token) { struct watch_event *event; - if (!waiting_for_ack(conn)) + if (!conn->waiting_for_ack) return send_error(conn, ENOENT); - /* Remove this watch event. */ - event = conn->event; - conn->event = NULL; + event = get_first_event(conn); + if (!streq(event->watch->token, token)) + return send_error(conn, EINVAL); move_event_onwards(event); + conn->waiting_for_ack = false; return send_ack(conn, XS_WATCH_ACK); } -bool do_unwatch(struct connection *conn, const char *node) +bool do_unwatch(struct connection *conn, struct buffered_data *in) { struct watch *watch; + char *node, *vec[2]; + if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) + return send_error(conn, EINVAL); + + node = canonicalize(conn, vec[0]); list_for_each_entry(watch, &watches, list) { - if (watch->conn == conn - && streq(watch->node, node)) { + if (watch->conn != conn) + continue; + + if (streq(watch->node, node) && streq(watch->token, vec[1])) { talloc_free(watch); return send_ack(conn, XS_UNWATCH); } } return send_error(conn, ENOENT); } + +#ifdef TESTING +void dump_watches(struct connection *conn) +{ + struct watch *watch; + struct watch_event *event; + + /* Find first watch with an event. */ + list_for_each_entry(watch, &watches, list) { + if (watch->conn != conn) + continue; + + printf(" watch on %s token %s prio %i\n", + watch->node, watch->token, watch->priority); + list_for_each_entry(event, &watch->events, list) + printf(" event: %s\n", event->node); + } +} +#endif diff --git a/tools/xenstore/xenstored_watch.h b/tools/xenstore/xenstored_watch.h index 656ce4c36b..e9c0ad8f0b 100644 --- a/tools/xenstore/xenstored_watch.h +++ b/tools/xenstore/xenstored_watch.h @@ -16,13 +16,15 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #ifndef _XENSTORED_WATCH_H #define _XENSTORED_WATCH_H + #include "xenstored_core.h" bool do_watch(struct connection *conn, struct buffered_data *in); -bool do_watch_ack(struct connection *conn); -bool do_unwatch(struct connection *conn, const char *node); +bool do_watch_ack(struct connection *conn, const char *token); +bool do_unwatch(struct connection *conn, struct buffered_data *in); /* Is this a watch event message for this connection? */ bool is_watch_event(struct connection *conn, struct buffered_data *out); @@ -30,13 +32,15 @@ bool is_watch_event(struct connection *conn, struct buffered_data *out); /* Look through our watches: if any of them have an event, queue it. */ void queue_next_event(struct connection *conn); -/* Is this connection waiting for a watch acknowledgement? */ -bool waiting_for_ack(struct connection *conn); - -/* Reset event if we were sending one */ -void reset_watch_event(struct connection *conn); - /* Fire all watches. */ void fire_watches(struct transaction *trans, const char *node); +/* Find shortest timeout: if any, reduce tv (may already be set). */ +void shortest_watch_ack_timeout(struct timeval *tv); + +/* Check for watches which may have timed out. */ +void check_watch_ack_timeout(void); + +void dump_watches(struct connection *conn); + #endif /* _XENSTORED_WATCH_H */ diff --git a/tools/xenstore/xs.c b/tools/xenstore/xs.c index d6e41380f9..e41ca652bd 100644 --- a/tools/xenstore/xs.c +++ b/tools/xenstore/xs.c @@ -159,8 +159,7 @@ static void *read_reply(int fd, enum xsd_sockmsg_type *type, unsigned int *len) /* Send message to xs, get malloc'ed reply. NULL and set errno on error. */ static void *xs_talkv(struct xs_handle *h, enum xsd_sockmsg_type type, - const struct iovec *iovec, - unsigned int num_vecs, + const struct iovec *iovec, unsigned int num_vecs, unsigned int *len) { struct xsd_sockmsg msg; @@ -330,8 +329,7 @@ bool xs_rm(struct xs_handle *h, const char *path) * Returns malloced array, or NULL: call free() after use. */ struct xs_permissions *xs_get_permissions(struct xs_handle *h, - const char *path, - unsigned int *num) + const char *path, unsigned int *num) { char *strings; unsigned int len; @@ -400,61 +398,75 @@ unwind: /* Watch a node for changes (poll on fd to detect, or call read_watch()). * When the node (or any child) changes, fd will become readable. + * Token is returned when watch is read, to allow matching. * Priority indicates order if multiple watchers: higher is first. * Returns false on failure. */ -bool xs_watch(struct xs_handle *h, const char *path, unsigned int priority) +bool xs_watch(struct xs_handle *h, const char *path, const char *token, + unsigned int priority) { char prio[MAX_STRLEN(priority)]; - struct iovec iov[2]; + struct iovec iov[3]; sprintf(prio, "%u", priority); iov[0].iov_base = (void *)path; iov[0].iov_len = strlen(path) + 1; - iov[1].iov_base = prio; - iov[1].iov_len = strlen(prio) + 1; + iov[1].iov_base = (void *)token; + iov[1].iov_len = strlen(token) + 1; + iov[2].iov_base = prio; + iov[2].iov_len = strlen(prio) + 1; return xs_bool(xs_talkv(h, XS_WATCH, iov, ARRAY_SIZE(iov), NULL)); } /* Find out what node change was on (will block if nothing pending). - * Returns malloced path, or NULL: call free() after use. + * Returns array of two pointers: path and token, or NULL. + * Call free() after use. */ -char *xs_read_watch(struct xs_handle *h) +char **xs_read_watch(struct xs_handle *h) { struct xsd_sockmsg msg; - char *path; + char **ret; if (!read_all(h->fd, &msg, sizeof(msg))) return NULL; assert(msg.type == XS_WATCH_EVENT); - path = malloc(msg.len); - if (!path) + ret = malloc(sizeof(char *)*2 + msg.len); + if (!ret) return NULL; - if (!read_all(h->fd, path, msg.len)) { - free_no_errno(path); + ret[0] = (char *)(ret + 2); + if (!read_all(h->fd, ret[0], msg.len)) { + free_no_errno(ret); return NULL; } - return path; + ret[1] = ret[0] + strlen(ret[0]) + 1; + return ret; } /* Acknowledge watch on node. Watches must be acknowledged before * any other watches can be read. * Returns false on failure. */ -bool xs_acknowledge_watch(struct xs_handle *h) +bool xs_acknowledge_watch(struct xs_handle *h, const char *token) { - return xs_bool(xs_single(h, XS_WATCH_ACK, "OK", NULL)); + return xs_bool(xs_single(h, XS_WATCH_ACK, token, NULL)); } /* Remove a watch on a node. * Returns false on failure (no watch on that node). */ -bool xs_unwatch(struct xs_handle *h, const char *path) +bool xs_unwatch(struct xs_handle *h, const char *path, const char *token) { - return xs_bool(xs_single(h, XS_UNWATCH, path, NULL)); + struct iovec iov[2]; + + iov[0].iov_base = (char *)path; + iov[0].iov_len = strlen(path) + 1; + iov[1].iov_base = (char *)token; + iov[1].iov_len = strlen(token) + 1; + + return xs_bool(xs_talkv(h, XS_UNWATCH, iov, ARRAY_SIZE(iov), NULL)); } /* Start a transaction: changes by others will not be seen during this @@ -488,11 +500,8 @@ bool xs_transaction_end(struct xs_handle *h, bool abort) * This tells the store daemon about a shared memory page and event channel * associated with a domain: the domain uses these to communicate. */ -bool xs_introduce_domain(struct xs_handle *h, - domid_t domid, - unsigned long mfn, - unsigned int eventchn, - const char *path) +bool xs_introduce_domain(struct xs_handle *h, domid_t domid, unsigned long mfn, + unsigned int eventchn, const char *path) { char domid_str[MAX_STRLEN(domid)]; char mfn_str[MAX_STRLEN(mfn)]; @@ -515,8 +524,7 @@ bool xs_introduce_domain(struct xs_handle *h, return xs_bool(xs_talkv(h, XS_INTRODUCE, iov, ARRAY_SIZE(iov), NULL)); } -bool xs_release_domain(struct xs_handle *h, - domid_t domid) +bool xs_release_domain(struct xs_handle *h, domid_t domid) { char domid_str[MAX_STRLEN(domid)]; diff --git a/tools/xenstore/xs.h b/tools/xenstore/xs.h index ff9481c3a6..b778cedd65 100644 --- a/tools/xenstore/xs.h +++ b/tools/xenstore/xs.h @@ -1,5 +1,3 @@ -#ifndef _XS_H -#define _XS_H /* Xen Store Daemon providing simple tree-like database. Copyright (C) 2005 Rusty Russell IBM Corporation @@ -19,11 +17,15 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* On failure, these routines set errno. */ +#ifndef _XS_H +#define _XS_H + #include "xs_lib.h" struct xs_handle; +/* On failure, these routines set errno. */ + /* Connect to the xs daemon. * Returns a handle or NULL. */ @@ -52,8 +54,8 @@ void *xs_read(struct xs_handle *h, const char *path, unsigned int *len); /* Write the value of a single file. * Returns false on failure. createflags can be 0, O_CREAT, or O_CREAT|O_EXCL. */ -bool xs_write(struct xs_handle *h, const char *path, const void *data, unsigned int len, - int createflags); +bool xs_write(struct xs_handle *h, const char *path, const void *data, + unsigned int len, int createflags); /* Create a new directory. * Returns false on failure. @@ -69,42 +71,42 @@ bool xs_rm(struct xs_handle *h, const char *path); * Returns malloced array, or NULL: call free() after use. */ struct xs_permissions *xs_get_permissions(struct xs_handle *h, - const char *path, - unsigned int *num); + const char *path, unsigned int *num); /* Set permissions of node (must be owner). * Returns false on failure. */ -bool xs_set_permissions(struct xs_handle *h, - const char *path, - struct xs_permissions *perms, - unsigned int num_perms); +bool xs_set_permissions(struct xs_handle *h, const char *path, + struct xs_permissions *perms, unsigned int num_perms); /* Watch a node for changes (poll on fd to detect, or call read_watch()). * When the node (or any child) changes, fd will become readable. + * Token is returned when watch is read, to allow matching. * Priority indicates order if multiple watchers: higher is first. * Returns false on failure. */ -bool xs_watch(struct xs_handle *h, const char *path, unsigned int priority); +bool xs_watch(struct xs_handle *h, const char *path, const char *token, + unsigned int priority); /* Return the FD to poll on to see if a watch has fired. */ int xs_fileno(struct xs_handle *h); /* Find out what node change was on (will block if nothing pending). - * Returns malloced path, or NULL: call free() after use. + * Returns array of two pointers: path and token, or NULL. + * Call free() after use. */ -char *xs_read_watch(struct xs_handle *h); +char **xs_read_watch(struct xs_handle *h); /* Acknowledge watch on node. Watches must be acknowledged before * any other watches can be read. * Returns false on failure. */ -bool xs_acknowledge_watch(struct xs_handle *h); +bool xs_acknowledge_watch(struct xs_handle *h, const char *token); /* Remove a watch on a node. * Returns false on failure (no watch on that node). */ -bool xs_unwatch(struct xs_handle *h, const char *path); +bool xs_unwatch(struct xs_handle *h, const char *path, const char *token); /* Start a transaction: changes by others will not be seen during this * transaction, and changes will not be visible to others until end. @@ -125,11 +127,8 @@ bool xs_transaction_end(struct xs_handle *h, bool abort); * This tells the store daemon about a shared memory page, event channel * and store path associated with a domain: the domain uses these to communicate. */ -bool xs_introduce_domain(struct xs_handle *h, - domid_t domid, - unsigned long mfn, - unsigned int eventchn, - const char *path); +bool xs_introduce_domain(struct xs_handle *h, domid_t domid, unsigned long mfn, + unsigned int eventchn, const char *path); /* Release a domain. * Tells the store domain to release the memory page to the domain. diff --git a/tools/xenstore/xs_lib.c b/tools/xenstore/xs_lib.c index 3f4f4b0899..cc9f9e1706 100644 --- a/tools/xenstore/xs_lib.c +++ b/tools/xenstore/xs_lib.c @@ -67,7 +67,7 @@ bool xs_write_all(int fd, const void *data, unsigned int len) /* Convert strings to permissions. False if a problem. */ bool xs_strings_to_perms(struct xs_permissions *perms, unsigned int num, - const char *strings) + const char *strings) { const char *p; char *end; @@ -138,4 +138,3 @@ unsigned int xs_count_strings(const char *strings, unsigned int len) return num; } - diff --git a/tools/xenstore/xs_lib.h b/tools/xenstore/xs_lib.h index 76ea9b67fe..97b72c8c7e 100644 --- a/tools/xenstore/xs_lib.h +++ b/tools/xenstore/xs_lib.h @@ -1,5 +1,3 @@ -#ifndef _XR_LIB_H -#define _XR_LIB_H /* Common routines between Xen store user library and daemon. Copyright (C) 2005 Rusty Russell IBM Corporation @@ -18,6 +16,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef _XS_LIB_H +#define _XS_LIB_H + #include #include #include @@ -52,7 +54,7 @@ bool xs_write_all(int fd, const void *data, unsigned int len); /* Convert strings to permissions. False if a problem. */ bool xs_strings_to_perms(struct xs_permissions *perms, unsigned int num, - const char *strings); + const char *strings); /* Convert permissions to a string (up to len MAX_STRLEN(domid_t)+1). */ bool xs_perm_to_string(const struct xs_permissions *perm, char *buffer); diff --git a/tools/xenstore/xs_stress.c b/tools/xenstore/xs_stress.c index 9c480b1553..0c257e465b 100644 --- a/tools/xenstore/xs_stress.c +++ b/tools/xenstore/xs_stress.c @@ -50,7 +50,7 @@ static void work(unsigned int cycles, unsigned int childnum) } if (streq(lockdir, "")) strcpy(lockdir, "/"); - + if (!xs_transaction_start(h, lockdir)) barf_perror("%i: starting transaction %i on %s", childnum, i, lockdir); diff --git a/tools/xenstore/xs_test.c b/tools/xenstore/xs_test.c index 4d769e220d..29929b7693 100644 --- a/tools/xenstore/xs_test.c +++ b/tools/xenstore/xs_test.c @@ -173,9 +173,9 @@ static void __attribute__((noreturn)) usage(void) " getperm \n" " setperm ...\n" " shutdown\n" - " watch \n" + " watch \n" " waitwatch\n" - " ackwatch\n" + " ackwatch \n" " unwatch \n" " close\n" " start \n" @@ -358,36 +358,37 @@ static void do_shutdown(unsigned int handle) failed(handle); } -static void do_watch(unsigned int handle, const char *node, const char *pri) +static void do_watch(unsigned int handle, const char *node, const char *token, + const char *pri) { - if (!xs_watch(handles[handle], node, atoi(pri))) + if (!xs_watch(handles[handle], node, token, atoi(pri))) failed(handle); } static void do_waitwatch(unsigned int handle) { - char *node; + char **vec; - node = xs_read_watch(handles[handle]); - if (!node) + vec = xs_read_watch(handles[handle]); + if (!vec) failed(handle); if (handle) - printf("%i:%s\n", handle, node); + printf("%i:%s:%s\n", handle, vec[0], vec[1]); else - printf("%s\n", node); - free(node); + printf("%s:%s\n", vec[0], vec[1]); + free(vec); } -static void do_ackwatch(unsigned int handle) +static void do_ackwatch(unsigned int handle, const char *token) { - if (!xs_acknowledge_watch(handles[handle])) + if (!xs_acknowledge_watch(handles[handle], token)) failed(handle); } -static void do_unwatch(unsigned int handle, const char *node) +static void do_unwatch(unsigned int handle, const char *node, const char *token) { - if (!xs_unwatch(handles[handle], node)) + if (!xs_unwatch(handles[handle], node, token)) failed(handle); } @@ -613,13 +614,13 @@ int main(int argc, char *argv[]) else if (streq(command, "shutdown")) do_shutdown(handle); else if (streq(command, "watch")) - do_watch(handle, arg(line, 1), arg(line, 2)); + do_watch(handle, arg(line, 1), arg(line, 2), arg(line, 3)); else if (streq(command, "waitwatch")) do_waitwatch(handle); else if (streq(command, "ackwatch")) - do_ackwatch(handle); + do_ackwatch(handle, arg(line, 1)); else if (streq(command, "unwatch")) - do_unwatch(handle, arg(line, 1)); + do_unwatch(handle, arg(line, 1), arg(line, 2)); else if (streq(command, "close")) { xs_daemon_close(handles[handle]); handles[handle] = NULL; diff --git a/tools/xenstore/xs_watch_stress.c b/tools/xenstore/xs_watch_stress.c new file mode 100644 index 0000000000..91431e2376 --- /dev/null +++ b/tools/xenstore/xs_watch_stress.c @@ -0,0 +1,120 @@ +/* Stress test for watch code: two processes communicating by watches */ +#include "xs.h" +#include "utils.h" +#include +#include +#include +#include +#include +#include +#include + +int main(int argc __attribute__((unused)), char *argv[]) +{ + int childpid, status, fds[2]; + bool parent; + unsigned int i, acks = 0; + struct xs_handle *h; + char *data; + unsigned int len; + const char *path, *otherpath; + + pipe(fds); + childpid = fork(); + if (childpid == -1) + barf_perror("Failed fork"); + parent = (childpid != 0); + + h = xs_daemon_open(); + if (!h) + barf_perror("Could not connect to daemon"); + + if (!xs_watch(h, "/", "token", 0)) + barf_perror("Could not set watch"); + + if (parent) { + char c; + + if (read(fds[0], &c, 1) != 1) + barf("Child exited"); + + path = "/parent"; + otherpath = "/child"; + /* Create initial node. */ + if (!xs_write(h, path, "0", 2, O_CREAT)) + barf_perror("Write to %s failed", path); + } else { + path = "/child"; + otherpath = "/parent"; + + if (write(fds[1], "", 1) != 1) + barf_perror("Write to parent failed"); + } + + for (i = 0; i < (argv[1] ? (unsigned)atoi(argv[1]) : 100);) { + char **vec; + + vec = xs_read_watch(h); + if (!vec) + barf_perror("Read watch failed"); + + if (!streq(vec[1], "token")) + barf("Watch token %s bad", vec[1]); + if (streq(vec[0], otherpath)) { + char number[32]; + + data = xs_read(h, otherpath, &len); + if (!data) + barf_perror("reading %s", otherpath); + sprintf(number, "%i", atoi(data) + 1); + free(data); + if (!xs_write(h, path, number, strlen(number) + 1, + O_CREAT)) + barf_perror("writing %s", path); + i++; + } else if (!streq(vec[0], path)) + barf_perror("Watch fired on unknown path %s", vec[0]); + xs_acknowledge_watch(h, vec[1]); + acks++; + free(vec); + } + + if (!parent) { + while (acks != 2 * i - 1) { + char **vec; + vec = xs_read_watch(h); + if (!vec) + barf_perror("Watch failed"); + if (!streq(vec[0], path)) + barf_perror("Watch fired path %s", vec[0]); + if (!streq(vec[1], "token")) + barf("Watch token %s bad", vec[1]); + free(vec); + + printf("Expect %i events, only got %i\n", + 2 * i - 1, acks); + acks++; + } + exit(0); + } + + if (acks != 2 * i) + barf("Parent got %i watch events\n", acks); + + printf("Waiting for %i\n", childpid); + if (waitpid(childpid, &status, 0) != childpid) + barf_perror("Child wait failed"); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + barf_perror("Child status %i", status); + + data = xs_read(h, path, &len); + if (atoi(data) != 2 * (int)i) + barf("%s count is %s\n", path, data); + free(data); + data = xs_read(h, otherpath, &len); + if (atoi(data) != 2 * (int)i - 1) + barf("%s count is %s\n", otherpath, data); + free(data); + printf("Success!\n"); + exit(0); +} From 99a2107ffafbf0a3d9f079ebd36ad051daa85857 Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Fri, 17 Jun 2005 14:20:55 +0000 Subject: [PATCH 17/25] bitkeeper revision 1.1713.3.6 (42b2dc47kgG53fAZb70R3lHX96n7dw) xsobj.py: Handle attribute lookups for non-existing attributes. Use setAttr consistently. Fix access to data in convertFromDB. console.py: Cleanup whitespace. channel.py: Cleanup saveToDB. blkif.py: Save dev_handle in DB. image.py: Cleanup exportToDB. XendDomainInfo.py: Cleanup {save,export}toDB use. Cleanup whitespace. Change id type to be int. Output store_mfn in sxpr. Use id variable name consistently for domain id's. Add eventChannel comment. On restore, the uuid must be known. Signed-off-by: Mike Wray Signed-off-by: Christian Limpach --- tools/python/xen/xend/XendDomainInfo.py | 77 ++++++++++++------------- tools/python/xen/xend/image.py | 4 +- tools/python/xen/xend/server/blkif.py | 1 + tools/python/xen/xend/server/channel.py | 8 +-- tools/python/xen/xend/server/console.py | 3 +- tools/python/xen/xend/xenstore/xsobj.py | 29 ++++++---- 6 files changed, 64 insertions(+), 58 deletions(-) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 16415d78a7..f14756015f 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -157,7 +157,7 @@ class XendDomainInfo: db = parentdb.addChild(uuid) vm = cls(db) vm.construct(config) - vm.saveDB(sync=True) + vm.saveToDB(sync=True) return vm create = classmethod(create) @@ -193,7 +193,7 @@ class XendDomainInfo: recreate = classmethod(recreate) - def restore(cls, parentdb, config, uuid=None): + def restore(cls, parentdb, config, uuid): """Create a domain and a VM object to do a restore. @param parentdb: parent db @@ -202,16 +202,20 @@ class XendDomainInfo: """ db = parentdb.addChild(uuid) vm = cls(db) - dom = xc.domain_create() - vm.setdom(dom) - vm.dom_construct(vm.id, config) - vm.saveDB(sync=True) + id = xc.domain_create() + vm.setdom(id) + try: + vm.restore = True + vm.construct(config) + finally: + vm.restore = False + vm.exportToDB(save=True, sync=True) return vm restore = classmethod(restore) __exports__ = [ - DBVar('id', ty='str'), + DBVar('id', ty='int'), DBVar('name', ty='str'), DBVar('uuid', ty='str'), DBVar('config', ty='sxpr'), @@ -267,14 +271,17 @@ class XendDomainInfo: def setDB(self, db): self.db = db - def saveDB(self, save=False, sync=False): + def saveToDB(self, save=False, sync=False): self.db.saveDB(save=save, sync=sync) def exportToDB(self, save=False, sync=False): if self.channel: - self.channel.saveToDB(self.db.addChild("channel")) + self.channel.saveToDB(self.db.addChild("channel"), save=save) if self.store_channel: - self.store_channel.saveToDB(self.db.addChild("store_channel")) + self.store_channel.saveToDB(self.db.addChild("store_channel"), + save=save) + if self.image: + self.image.exportToDB(save=save, sync=sync) self.db.exportToDB(self, fields=self.__exports__, save=save, sync=sync) def importFromDB(self): @@ -316,7 +323,7 @@ class XendDomainInfo: self.state = state self.state_updated.notifyAll() self.state_updated.release() - self.saveDB() + self.saveToDB() def state_wait(self, state): self.state_updated.acquire() @@ -325,14 +332,14 @@ class XendDomainInfo: self.state_updated.release() def __str__(self): - s = "domain" + s = " Created domain=%d name=%s memory=%d', - dom, self.name, self.memory) - if not self.restore: - self.setdom(dom) + id, self.name, self.memory) + self.setdom(id) def openChannel(self, key, local, remote): - """Create a channel to the domain. + """Create a control channel to the domain. If saved info is available recreate the channel. @param key db key for the saved data (if any) @@ -670,6 +680,11 @@ class XendDomainInfo: return chan def eventChannel(self, key): + """Create an event channel to the domain. + If saved info is available recreate the channel. + + @param key db key for the saved data (if any) + """ db = self.db.addChild(key) return EventChannel.restoreFromDB(db, 0, self.id) @@ -832,11 +847,12 @@ class XendDomainInfo: self.state = STATE_VM_OK self.shutdown_pending = None self.restart_check() + self.exportToDB() self.restart_state = STATE_RESTART_BOOTING if self.bootloader: self.config = self.bootloader_config() self.construct(self.config) - self.saveDB() + self.saveToDB() finally: self.restart_state = None @@ -910,23 +926,6 @@ class XendDomainInfo: backend = blkif.getBackend(0) backend.connect(recreate=self.recreate) - def dom_construct(self, dom, config): - """Construct a vm for an existing domain. - - @param dom: domain id - @param config: domain configuration - """ - d = dom_get(dom) - if not d: - raise VmError("Domain not found: %d" % dom) - try: - self.restore = True - self.setdom(dom) - self.memory = d['mem_kb']/1024 - self.construct(config) - finally: - self.restore = False - def configure_fields(self): """Process the vm configuration fields using the registered handlers. """ diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py index e0d70581bf..8d64472e98 100644 --- a/tools/python/xen/xend/image.py +++ b/tools/python/xen/xend/image.py @@ -96,8 +96,8 @@ class ImageHandler: self.db = vm.db.addChild('/image') self.config = config - def exportToDB(self, save=False): - self.db.exportToDB(self, fields=self.__exports__, save=save) + def exportToDB(self, save=False, sync=False): + self.db.exportToDB(self, fields=self.__exports__, save=save, sync=sync) def importFromDB(self): self.db.importFromDB(self, fields=self.__exports__) diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py index 75a76e8bda..0b40c30bf3 100755 --- a/tools/python/xen/xend/server/blkif.py +++ b/tools/python/xen/xend/server/blkif.py @@ -167,6 +167,7 @@ class BlkDev(Dev): DBVar('params', ty='str'), DBVar('node', ty='str'), DBVar('device', ty='long'), + DBVar('dev_handle', ty='long'), DBVar('start_sector', ty='long'), DBVar('nr_sectors', ty='long'), ] diff --git a/tools/python/xen/xend/server/channel.py b/tools/python/xen/xend/server/channel.py index 00f451a7b8..defe76f106 100755 --- a/tools/python/xen/xend/server/channel.py +++ b/tools/python/xen/xend/server/channel.py @@ -81,7 +81,7 @@ class EventChannel(dict): evtchn_close(self.dom1, self.port1) evtchn_close(self.dom2, self.port2) - def saveToDB(self, db): + def saveToDB(self, db, save=False): """Save the event channel to the db so it can be restored later, using restoreFromDB() on the class. @@ -91,7 +91,7 @@ class EventChannel(dict): db['dom2'] = str(self.dom2) db['port1'] = str(self.port1) db['port2'] = str(self.port2) - db.saveDB() + db.saveDB(save=save) def sxpr(self): return ['event-channel', @@ -339,7 +339,7 @@ class Channel: # Make sure the port will deliver all the messages. self.port.register(TYPE_WILDCARD) - def saveToDB(self, db): + def saveToDB(self, db, save=False): """Save the channel ports to the db so the channel can be restored later, using restoreFromDB() on the factory. @@ -348,7 +348,7 @@ class Channel: if self.closed: return db['local_port'] = str(self.getLocalPort()) db['remote_port'] = str(self.getRemotePort()) - db.saveDB() + db.saveDB(save=save) def getKey(self): """Get the channel key. diff --git a/tools/python/xen/xend/server/console.py b/tools/python/xen/xend/server/console.py index 743ace4aec..e0aa04a37a 100755 --- a/tools/python/xen/xend/server/console.py +++ b/tools/python/xen/xend/server/console.py @@ -214,7 +214,8 @@ class ConsoleDev(Dev, protocol.ServerFactory): self.unix_listener = reactor.listenUNIX(path, self) if xroot.get_xend_http_server(): interface = xroot.get_console_address() - self.tcp_listener = reactor.listenTCP(self.console_port, self, interface=interface) + self.tcp_listener = reactor.listenTCP( + self.console_port, self, interface=interface) finally: self.lock.release() diff --git a/tools/python/xen/xend/xenstore/xsobj.py b/tools/python/xen/xend/xenstore/xsobj.py index b1c9a4f1d1..cdb35c1735 100644 --- a/tools/python/xen/xend/xenstore/xsobj.py +++ b/tools/python/xen/xend/xenstore/xsobj.py @@ -1,6 +1,8 @@ import string import types +from xen.xend.XendLogging import log + from xen.xend import sxp from xsnode import XenNode from xen.util.mac import macToString, macFromString @@ -14,14 +16,19 @@ def hasAttr(obj, attr): return hasattr(obj, attr) def getAttr(obj, attr): - if isinstance(obj, dict): - return dict.get(attr) - else: - return getattr(obj, attr, None) + try: + if isinstance(obj, dict): + return obj.get(attr) + else: + return getattr(obj, attr, None) + except AttributeError: + return None + except LookupError: + return None def setAttr(obj, attr, val): if isinstance(obj, dict): - dict[attr] = val + obj[attr] = val else: setattr(obj, attr, val) @@ -53,8 +60,8 @@ class DBConverter: convertToDB = classmethod(convertToDB) - def convertFromDB(cls, val, ty=None): - return cls.getConverter(ty).fromDB(val) + def convertFromDB(cls, data, ty=None): + return cls.getConverter(ty).fromDB(data.getData()) convertFromDB = classmethod(convertFromDB) @@ -201,9 +208,8 @@ class DBVar: setAttr(o, self.attr, val) def getDB(self, db): - try: - data = getattr(db, self.path) - except AttributeError: + data = getAttr(db, self.path) + if data is None: return None return DBConverter.convertFromDB(data, ty=self.ty) @@ -214,8 +220,7 @@ class DBVar: return data = DBConverter.convertToDB(val, ty=self.ty) #print 'DBVar>setDB>', self.path, 'data=', data - setattr(db, self.path, data) - + setAttr(db, self.path, data) class DBMap(dict): """A persistent map. Extends dict with persistence. From c7fcce55897aad9f89127c731e0366d5ab207179 Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Fri, 17 Jun 2005 15:30:49 +0000 Subject: [PATCH 18/25] bitkeeper revision 1.1713.3.7 (42b2eca9N1e5S0oGdW8OeKAkL9oDOQ) netif.py, blkif.py: Add exportToDB functions to save evtchn port. Signed-off-by: Mike Wray Signed-off-by: Christian Limpach --- tools/python/xen/xend/server/blkif.py | 7 +++++++ tools/python/xen/xend/server/netif.py | 8 ++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py index 0b40c30bf3..59932a3d8b 100755 --- a/tools/python/xen/xend/server/blkif.py +++ b/tools/python/xen/xend/server/blkif.py @@ -193,6 +193,13 @@ class BlkDev(Dev): self.backendId = 0 self.configure(self.config, recreate=recreate) + def exportToDB(self, save=False): + Dev.exportToDB(self, save=save) + backend = self.getBackend() + if backend and backend.evtchn: + db = self.db.addChild("evtchn") + backend.evtchn.exportToDB(db, save=save) + def init(self, recreate=False, reboot=False): self.frontendDomain = self.getDomain() self.frontendChannel = self.getChannel() diff --git a/tools/python/xen/xend/server/netif.py b/tools/python/xen/xend/server/netif.py index 0a49842522..c799c621c1 100755 --- a/tools/python/xen/xend/server/netif.py +++ b/tools/python/xen/xend/server/netif.py @@ -66,11 +66,9 @@ class NetDev(Dev): DBVar('be_mac', ty='mac'), DBVar('bridge', ty='str'), DBVar('script', ty='str'), - #DBVar('ipaddr'), DBVar('credit', ty='int'), DBVar('period', ty='int'), DBVar('vifname', ty='str'), - DBVar('evtchn'), #todo: export fields (renamed) ] def __init__(self, controller, id, config, recreate=False): @@ -92,6 +90,12 @@ class NetDev(Dev): self.vifname = None self.configure(self.config, recreate=recreate) + def exportToDB(self, save=False): + Dev.exportToDB(self, save=save) + if self.evtchn: + db = self.db.addChild("evtchn") + self.evtchn.exportToDB(db, save=save) + def init(self, recreate=False, reboot=False): self.destroyed = False self.status = NETIF_INTERFACE_STATUS_DISCONNECTED From 936d91fbba790389cdf6f438f93888c0dbf09fd8 Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Fri, 17 Jun 2005 16:23:55 +0000 Subject: [PATCH 19/25] bitkeeper revision 1.1713.3.8 (42b2f91bG45uUFWHhUaUha3e1OAxJQ) xsnode.py: Updated watches/event code from Mike Wray. Signed-off-by: Mike Wray Signed-off-by: Christian Limpach --- tools/python/xen/xend/xenstore/xsnode.py | 219 +++++++++++++++-------- 1 file changed, 141 insertions(+), 78 deletions(-) diff --git a/tools/python/xen/xend/xenstore/xsnode.py b/tools/python/xen/xend/xenstore/xsnode.py index ae770219ab..f9721caf1b 100644 --- a/tools/python/xen/xend/xenstore/xsnode.py +++ b/tools/python/xen/xend/xenstore/xsnode.py @@ -2,7 +2,9 @@ import errno import os import os.path import select +import socket import sys +import threading import time from xen.lowlevel import xs @@ -12,18 +14,26 @@ from xen.xend.PrettyPrint import prettyprint SELECT_TIMEOUT = 2.0 def getEventPath(event): - return os.path.join("/_event", event) + if event and event.startswith("/"): + event = event[1:] + return os.path.join("/event", event) def getEventIdPath(event): - return os.path.join(eventPath(event), "@eid") + return os.path.join(getEventPath(event), "@eid") class Subscription: - def __init__(self, event, fn, id): - self.event = event + def __init__(self, path, fn, sid): + self.path = path self.watcher = None self.fn = fn - self.id = id + self.sid = sid + + def getPath(self): + return self.path + + def getSid(self): + return self.sid def watch(self, watcher): self.watcher = watcher @@ -34,10 +44,11 @@ class Subscription: if watcher: self.watcher = None watcher.delSubs(self) + return watcher - def notify(self, event): + def notify(self, path, val): try: - self.fn(event, id) + self.fn(self, path, val) except SystemExitException: raise except: @@ -45,45 +56,45 @@ class Subscription: class Watcher: - def __init__(self, store, event): - self.path = getEventPath(event) - self.eidPath = getEventIdPath(event) + def __init__(self, store, path): + self.path = path store.mkdirs(self.path) - if not store.exists(self.eidPath): - store.writeInt(self.eidPath, 0) self.xs = None - self.subs = [] + self.subscriptions = [] - def __getattr__(self, k, v): - if k == "fileno": - if self.xs: - return self.xs.fileno - else: - return -1 + def fileno(self): + if self.xs: + return self.xs.fileno else: - return self.__dict__.get(k, v) + return -1 + + def getPath(self): + return self.path def addSubs(self, subs): - self.subs.append(subs) + self.subscriptions.append(subs) self.watch() def delSubs(self, subs): - self.subs.remove(subs) - if len(self.subs) == 0: + self.subscriptions.remove(subs) + if len(self.subscriptions) == 0: self.unwatch() - def getEvent(self): - return self.event - def watch(self): if self.xs: return self.xs = xs.open() - self.xs.watch(path) + self.xs.watch(self.path) def unwatch(self): if self.xs: - self.xs.unwatch(self.path) - self.xs.close() + try: + self.xs.unwatch(self.path) + except Exception, ex: + print 'Watcher>unwatch>', ex + try: + self.xs.close() + except Exception, ex: + pass self.xs = None def watching(self): @@ -92,22 +103,38 @@ class Watcher: def getNotification(self): p = self.xs.read_watch() self.xs.acknowledge_watch() - eid = self.xs.readInt(self.eidPath) return p - def notify(self, subs): - p = self.getNotification() - for s in subs: - s.notify(p) - + def notify(self): + try: + p = self.getNotification() + v = self.xs.read(p) + for s in subscriptions: + s.notify(p, v) + except Exception, ex: + print 'Notify exception:', ex + +class EventWatcher(Watcher): + + def __init__(self, store, path, event): + Watcher.__init__(self, store, path) + self.event = event + self.eidPath = getEventIdPath(event) + if not store.exists(self.eidPath): + store.write(self.eidPath, str(0)) + + def getEvent(self): + return self.event + class XenStore: + xs = None + watchThread = None + subscription_id = 1 + def __init__(self): - self.xs = None - #self.xs = xs.open() - self.subscription = {} - self.subscription_id = 0 - self.events = {} + self.subscriptions = {} + self.watchers = {} self.write("/", "") def getxs(self): @@ -119,8 +146,8 @@ class XenStore: ex = None break except Exception, ex: - print >>stderr, "Exception connecting to xsdaemon:", ex - print >>stderr, "Trying again..." + print >>sys.stderr, "Exception connecting to xsdaemon:", ex + print >>sys.stderr, "Trying again..." time.sleep(1) else: raise ex @@ -217,70 +244,85 @@ class XenStore: self.getxs().write(path, data, create=create, excl=excl) def begin(self, path): - self.getxs().begin_transaction(path) + self.getxs().transaction_start(path) def commit(self, abandon=False): - self.getxs().end_transaction(abort=abandon) + self.getxs().transaction_end(abort=abandon) + + def watch(self, path, fn): + watcher = self.watchers.get(path) + if not watcher: + watcher = self.addWatcher(Watcher(self, path)) + return self.addSubscription(watcher, fn) + + def unwatch(self, sid): + s = self.subscriptions.get(sid) + if not s: return + del self.subscriptions[s.sid] + watcher = s.unwatch() + if watcher and not watcher.watching(): + del self.watchers[path] def subscribe(self, event, fn): - watcher = self.watchEvent(event) - self.subscription_id += 1 - subs = Subscription(event, fn, self.subscription_id) - self.subscription[subs.id] = subs - subs.watch(watcher) - return subs.id + path = getEventPath(event) + watcher = self.watchers.get(path) + if not watcher: + watcher = self.addWatcher(EventWatcher(self, path, event)) + return self.addSubscription(watcher, fn) - def unsubscribe(self, sid): - s = self.subscription.get(sid) - if not s: return - del self.subscription[s.id] - s.unwatch() - unwatchEvent(s.event) + unsubscribe = unwatch def sendEvent(self, event, data): eventPath = getEventPath(event) eidPath = getEventIdPath(event) try: - self.begin(eventPath) + #self.begin(eventPath) self.mkdirs(eventPath) + eid = 1 if self.exists(eidPath): - eid = self.readInt(eidPath) - eid += 1 - else: - eid = 1 - self.writeInt(eidPath, eid) + data = self.read(eidPath) + print 'sendEvent>', 'data=', data, type(data) + try: + eid = int(self.read(eidPath)) + eid += 1 + except Exception, ex: + print 'sendEvent>', ex + pass + self.write(eidPath, str(eid)) self.write(os.path.join(eventPath, str(eid)), data) finally: - self.commit() + #self.commit() + pass - def watchEvent(self, event): - if event in self.events: - return - watcher = Watcher(event) - self.watchers[watcher.getEvent()] = watcher + def addWatcher(self, watcher): + self.watchers[watcher.getPath()] = watcher self.watchStart() return watcher - def unwatchEvent(self, event): - watcher = self.watchers.get(event) - if not watcher: - return - if not watcher.watching(): - del self.watchers[event] + def addSubscription(self, watcher, fn): + self.subscription_id += 1 + subs = Subscription(watcher.getPath(), fn, self.subscription_id) + self.subscriptions[subs.sid] = subs + subs.watch(watcher) + return subs.sid def watchStart(self): if self.watchThread: return - + self.watchThread = threading.Thread(name="Watcher", + target=self.watchMain) + self.watchThread.setDaemon(True) + self.watchThread.start() + def watchMain(self): try: while True: if self.watchThread is None: return - if not self.events: + if not self.watchers: return rd = self.watchers.values() try: - (rd, wr, er) = select.select(rd, [], [], SELECT_TIMEOUT) - for watcher in rd: + (srd, swr, ser) = select.select(rd, [], [], SELECT_TIMEOUT) + for watcher in srd: watcher.notify() except socket.error, ex: if ex.args[0] in (EAGAIN, EINTR): @@ -315,6 +357,9 @@ class XenNode: else: raise ValueError("path does not exist: '%s'" % path) + def getStore(self): + return self.store + def relPath(self, path=""): if not path: return self.path @@ -376,6 +421,24 @@ class XenNode: def releaseDomain(self, dom): self.store.releaseDomain(dom) + def watch(self, fn, path=""): + """Watch a path for changes. The path is relative + to the node and defaults to the node itself. + """ + return self.store.watch(self.relPath(path), fn) + + def unwatch(self, sid): + return self.store.unwatch(sid) + + def subscribe(self, event, fn): + return self.store.subscribe(event, fn) + + def unsubscribe(self, sid): + self.store.unsubscribe(sid) + + def sendEvent(self, event, data): + return self.store.sendEvent(event, data) + def __repr__(self): return "" % self.path From 53f499bc57c139a0a11f915f283565bf38e19ed3 Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Fri, 17 Jun 2005 17:22:24 +0000 Subject: [PATCH 20/25] bitkeeper revision 1.1713.3.9 (42b306d0pFeN318FP89TE8LRrhROMQ) xsobj.py: Cleanup interface to DB. Updated watches/event code. Signed-off-by: Mike Wray Signed-off-by: Christian Limpach --- tools/python/xen/xend/xenstore/xsobj.py | 77 +++++++++++++++---------- 1 file changed, 48 insertions(+), 29 deletions(-) diff --git a/tools/python/xen/xend/xenstore/xsobj.py b/tools/python/xen/xend/xenstore/xsobj.py index cdb35c1735..e16bf43e83 100644 --- a/tools/python/xen/xend/xenstore/xsobj.py +++ b/tools/python/xen/xend/xenstore/xsobj.py @@ -55,15 +55,15 @@ class DBConverter: getConverter = classmethod(getConverter) - def convertToDB(cls, val, ty=None): - return cls.getConverter(ty).toDB(val) + def exportTypeToDB(cls, db, path, val, ty=None): + return cls.getConverter(ty).exportToDB(db, path, val) - convertToDB = classmethod(convertToDB) + exportTypeToDB = classmethod(exportTypeToDB) - def convertFromDB(cls, data, ty=None): - return cls.getConverter(ty).fromDB(data.getData()) + def importTypeFromDB(cls, db, path, ty=None): + return cls.getConverter(ty).importFromDB(db, path) - convertFromDB = classmethod(convertFromDB) + importTypeFromDB = classmethod(importTypeFromDB) # Must define in subclass. name = None @@ -76,6 +76,26 @@ class DBConverter: raise ValueError("invalid converter name: '%s'" % self.name) self.converters[self.name] = self + def exportToDB(self, db, path, val): + if val is None: + return + try: + data = self.toDB(val) + except Exception, ex: + raise + setattr(db, path, data) + + def importFromDB(self, db, path): + data = getAttr(db, path) + if data is None: + val = None + else: + try: + val = self.fromDB(data.getData()) + except Exception, ex: + raise + return val + def toDB(self, val): raise NotImplementedError() @@ -185,10 +205,12 @@ class DBVar: self.attr = varpath[-1] def exportToDB(self, db, obj): - self.setDB(db, self.getObj(obj)) + val = self.getObj(obj) + DBConverter.exportTypeToDB(db, self.path, val, ty=self.ty) def importFromDB(self, db, obj): - self.setObj(obj, self.getDB(db)) + val = DBConverter.importTypeFromDB(db, self.path, ty=self.ty) + self.setObj(obj, val) def getObj(self, obj): o = obj @@ -207,21 +229,6 @@ class DBVar: return setAttr(o, self.attr, val) - def getDB(self, db): - data = getAttr(db, self.path) - if data is None: - return None - return DBConverter.convertFromDB(data, ty=self.ty) - - def setDB(self, db, val): - # Don't set in db if val is None. - #print 'DBVar>setDB>', self.path, 'val=', val - if val is None: - return - data = DBConverter.convertToDB(val, ty=self.ty) - #print 'DBVar>setDB>', self.path, 'data=', data - setAttr(db, self.path, data) - class DBMap(dict): """A persistent map. Extends dict with persistence. Set and get values using the usual map syntax: @@ -319,6 +326,21 @@ class DBMap(dict): traceback.print_exc() print 'DBMap>releaseDomain>', ex pass # todo: don't ignore + + def watch(self, fn, path=""): + return self.__db__.watch(fn, path=path) + + def unwatch(self, sid): + return self.__db__.unwatch(sid) + + def subscribe(self, event, fn): + return self.__db__.subscribe(event, fn) + + def unsubscribe(self, sid): + return self.__db__.unsubscribe(sid) + + def sendEvent(self, event, val): + return self.__db__.sendEvent(event, val) def transactionBegin(self): # Begin a transaction. @@ -333,12 +355,6 @@ class DBMap(dict): # We have changed values, what do we do? pass - def watch(self, fn): - pass - - def unwatch(self, watch): - pass - def checkName(self, k): if k == "": raise ValueError("invalid key, empty string") @@ -461,6 +477,9 @@ class DBMap(dict): n = n._addChild(x) return n + def getDB(self): + return self.__db__ + def setDB(self, db): if (db is not None) and not isinstance(db, XenNode): raise ValueError("invalid db") From 8994c2f2ef6a2d804b41ac35906ce9c60a0301fc Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Fri, 17 Jun 2005 17:23:06 +0000 Subject: [PATCH 21/25] bitkeeper revision 1.1713.3.10 (42b306faXfFxqDZahYvvQJPQeaDm1A) netif.py: Add mtu config option for network interfaces. Signed-off-by: Mike Wray Signed-off-by: Christian Limpach --- tools/python/xen/xend/server/netif.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tools/python/xen/xend/server/netif.py b/tools/python/xen/xend/server/netif.py index c799c621c1..8c60904ec5 100755 --- a/tools/python/xen/xend/server/netif.py +++ b/tools/python/xen/xend/server/netif.py @@ -87,6 +87,7 @@ class NetDev(Dev): self.bridge = None self.script = None self.ipaddr = None + self.mtu = None self.vifname = None self.configure(self.config, recreate=recreate) @@ -132,6 +133,15 @@ class NetDev(Dev): val = None return val + def _get_config_mtu(self, config): + mtu = sxp.child_value(config, 'mtu') + if not mtu: return None + try: + mtu = int(mtu) + except: + raise XendError("invalid mtu: %s" & mtu) + return mtu + def configure(self, config, change=False, recreate=False): if change: return self.reconfigure(config) @@ -156,6 +166,7 @@ class NetDev(Dev): self.bridge = sxp.child_value(config, 'bridge') self.script = sxp.child_value(config, 'script') self.ipaddr = self._get_config_ipaddr(config) or [] + self.mtu = self._get_config_mtu(config) self._config_credit_limit(config) try: @@ -187,6 +198,7 @@ class NetDev(Dev): bridge = sxp.child_value(config, 'bridge') script = sxp.child_value(config, 'script') ipaddr = self._get_config_ipaddr(config) + mtu = self._get_config_mtu(config) xd = get_component('xen.xend.XendDomain') backendDomain = xd.domain_lookup_by_name(sxp.child_value(config, 'backend', '0')).id @@ -203,6 +215,8 @@ class NetDev(Dev): changes['script'] = script if (ipaddr is not None) and (ipaddr != self.ipaddr): changes['ipaddr'] = ipaddr + if (mtu is not None) and (mtu != self.mtu): + changes['mtu'] = mtu if changes: self.vifctl("down") From 21f4c1e5b995e38d42220928b1d0ae008036644e Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Fri, 17 Jun 2005 17:36:02 +0000 Subject: [PATCH 22/25] bitkeeper revision 1.1713.3.11 (42b30a02txpfqH2-OnZmhyrJWqPgHQ) xs.c: Add copyright notice. Signed-off-by: Mike Wray Signed-off-by: Christian Limpach --- tools/python/xen/lowlevel/xs/xs.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/python/xen/lowlevel/xs/xs.c b/tools/python/xen/lowlevel/xs/xs.c index 9c26c0f51c..8feb94f00b 100644 --- a/tools/python/xen/lowlevel/xs/xs.c +++ b/tools/python/xen/lowlevel/xs/xs.c @@ -1,3 +1,8 @@ +/* + Python interface to the Xen Store Daemon. + Copyright (C) 2005 Mike Wray Hewlett-Packard +*/ + #include #include From 996ee15db0d0576bd404c7862e5eaf22d60ff502 Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Fri, 17 Jun 2005 17:57:29 +0000 Subject: [PATCH 23/25] bitkeeper revision 1.1713.3.12 (42b30f09wgYSRV9tHZUjq2JpreIozQ) xs.c: Fix some oversights in watch/token code. Cleanup whitespace. Move method documentation next to method definition. Reorder functions in file. Signed-off-by: Mike Wray Signed-off-by: Christian Limpach --- tools/python/xen/lowlevel/xs/xs.c | 322 +++++++++++++++++++++--------- 1 file changed, 228 insertions(+), 94 deletions(-) diff --git a/tools/python/xen/lowlevel/xs/xs.c b/tools/python/xen/lowlevel/xs/xs.c index 8feb94f00b..bfddb966d0 100644 --- a/tools/python/xen/lowlevel/xs/xs.c +++ b/tools/python/xen/lowlevel/xs/xs.c @@ -52,6 +52,53 @@ static inline PyObject *pyvalue_str(char *val) { : PyErr_SetFromErrno(PyExc_RuntimeError)); } +#define xspy_read_doc "\n" \ + "Read data from a path.\n" \ + " path [string]: xenstore path\n" \ + "\n" \ + "Returns: [string] data read.\n" \ + "Raises RuntimeError on error.\n" \ + "\n" + +static PyObject *xspy_read(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwd_spec[] = { "path", NULL }; + static char *arg_spec = "s|"; + char *path = NULL; + + struct xs_handle *xh = xshandle(self); + char *xsval = NULL; + unsigned int xsval_n = 0; + PyObject *val = NULL; + + if (!xh) + goto exit; + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, + &path)) + goto exit; + xsval = xs_read(xh, path, &xsval_n); + if (!xsval) { + val = pyvalue_int(0); + goto exit; + } + val = PyString_FromStringAndSize(xsval, xsval_n); + exit: + if (xsval) + free(xsval); + return val; +} + +#define xspy_write_doc "\n" \ + "Write data to a path.\n" \ + " path [string] : xenstore path to write to\n." \ + " data [string] : data to write.\n" \ + " create [int] : create flag, default 0.\n" \ + " excl [int] : exclusive flag, default 0.\n" \ + "\n" \ + "Returns: [int] 0 on success.\n" \ + "Raises RuntimeError on error.\n" \ + "\n" + static PyObject *xspy_write(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwd_spec[] = { "path", "data", "create", "excl", NULL }; @@ -82,53 +129,13 @@ static PyObject *xspy_write(PyObject *self, PyObject *args, PyObject *kwds) return val; } -static PyObject *xspy_read(PyObject *self, PyObject *args, PyObject *kwds) -{ - static char *kwd_spec[] = { "path", NULL }; - static char *arg_spec = "s|"; - char *path = NULL; - - struct xs_handle *xh = xshandle(self); - char *xsval = NULL; - unsigned int xsval_n = 0; - PyObject *val = NULL; - - if (!xh) - goto exit; - if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, - &path)) - goto exit; - xsval = xs_read(xh, path, &xsval_n); - if (!xsval) { - val = pyvalue_int(0); - goto exit; - } - val = PyString_FromStringAndSize(xsval, xsval_n); - exit: - if (xsval) - free(xsval); - return val; -} - -static PyObject *xspy_mkdir(PyObject *self, PyObject *args, PyObject *kwds) -{ - static char *kwd_spec[] = { "path", NULL }; - static char *arg_spec = "s|"; - char *path = NULL; - - struct xs_handle *xh = xshandle(self); - PyObject *val = NULL; - int xsval = 0; - - if (!xh) - goto exit; - if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path)) - goto exit; - xsval = xs_mkdir(xh, path); - val = pyvalue_int(xsval); - exit: - return val; -} +#define xspy_ls_doc "\n" \ + "List a directory.\n" \ + " path [string]: path to list.\n" \ + "\n" \ + "Returns: [string array] list of subdirectory names.\n" \ + "Raises RuntimeError on error.\n" \ + "\n" static PyObject *xspy_ls(PyObject *self, PyObject *args, PyObject *kwds) { @@ -158,6 +165,41 @@ static PyObject *xspy_ls(PyObject *self, PyObject *args, PyObject *kwds) return val; } +#define xspy_mkdir_doc "\n" \ + "Make a directory.\n" \ + " path [string]: path to directory to create.\n" \ + "\n" \ + "Returns: [int] 0 on success.\n" \ + "Raises RuntimeError on error.\n" \ + "\n" + +static PyObject *xspy_mkdir(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwd_spec[] = { "path", NULL }; + static char *arg_spec = "s|"; + char *path = NULL; + + struct xs_handle *xh = xshandle(self); + PyObject *val = NULL; + int xsval = 0; + + if (!xh) + goto exit; + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path)) + goto exit; + xsval = xs_mkdir(xh, path); + val = pyvalue_int(xsval); + exit: + return val; +} + +#define xspy_rm_doc "\n" \ + "Remove a path.\n" \ + " path [string] : path to remove\n" \ + "Returns: [int] 0 on success.\n" \ + "Raises RuntimeError on error.\n" \ + "\n" + static PyObject *xspy_rm(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwd_spec[] = { "path", NULL }; @@ -178,6 +220,14 @@ static PyObject *xspy_rm(PyObject *self, PyObject *args, PyObject *kwds) return val; } +#define xspy_get_permissions_doc "\n" \ + "Get the permissions for a path\n" \ + " path [string]: xenstore path.\n" \ + "\n" \ + "Returns: permissions array.\n" \ + "Raises RuntimeError on error.\n" \ + "\n" + static PyObject *xspy_get_permissions(PyObject *self, PyObject *args, PyObject *kwds) { @@ -214,6 +264,15 @@ static PyObject *xspy_get_permissions(PyObject *self, PyObject *args, return val; } +#define xspy_set_permissions_doc "\n" \ + "Set the permissions for a path\n" \ + " path [string] : xenstore path.\n" \ + " perms : permissions.\n" \ + "\n" \ + "Returns: [int] 0 on success.\n" \ + "Raises RuntimeError on error.\n" \ + "\n" + static PyObject *xspy_set_permissions(PyObject *self, PyObject *args, PyObject *kwds) { @@ -280,13 +339,22 @@ static PyObject *xspy_set_permissions(PyObject *self, PyObject *args, return val; } +#define xspy_watch_doc "\n" \ + "Watch a path, get notifications when it changes.\n" \ + " path [string] : xenstore path.\n" \ + " token [string] : returned in watch notification\n" \ + "\n" \ + "Returns: [int] 0 on success.\n" \ + "Raises RuntimeError on error.\n" \ + "\n" + static PyObject *xspy_watch(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwd_spec[] = { "path", "priority", "token", NULL }; static char *arg_spec = "s|is"; char *path = NULL; int priority = 0; - char *token; + char *token = ""; struct xs_handle *xh = xshandle(self); PyObject *val = NULL; @@ -303,6 +371,14 @@ static PyObject *xspy_watch(PyObject *self, PyObject *args, PyObject *kwds) return val; } +#define xspy_read_watch_doc "\n" \ + "Read a watch notification.\n" \ + " path [string]: xenstore path.\n" \ + "\n" \ + "Returns: [tuple] (path, token).\n" \ + "Raises RuntimeError on error.\n" \ + "\n" + static PyObject *xspy_read_watch(PyObject *self, PyObject *args, PyObject *kwds) { @@ -318,7 +394,7 @@ static PyObject *xspy_read_watch(PyObject *self, PyObject *args, if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec)) goto exit; xsval = xs_read_watch(xh); - if(!xsval){ + if (!xsval) { val = PyErr_SetFromErrno(PyExc_RuntimeError); goto exit; } @@ -330,12 +406,20 @@ static PyObject *xspy_read_watch(PyObject *self, PyObject *args, return val; } +#define xspy_acknowledge_watch_doc "\n" \ + "Acknowledge a watch notification that has been read.\n" \ + " token [string] : returned in watch notification\n" \ + "\n" \ + "Returns: [int] 0 on success.\n" \ + "Raises RuntimeError on error.\n" \ + "\n" + static PyObject *xspy_acknowledge_watch(PyObject *self, PyObject *args, PyObject *kwds) { - static char *kwd_spec[] = { NULL }; + static char *kwd_spec[] = { "token", NULL }; static char *arg_spec = "s"; - char *token = ""; + char *token; struct xs_handle *xh = xshandle(self); PyObject *val = NULL; @@ -351,6 +435,15 @@ static PyObject *xspy_acknowledge_watch(PyObject *self, PyObject *args, return val; } +#define xspy_unwatch_doc "\n" \ + "Stop watching a path.\n" \ + " path [string] : xenstore path.\n" \ + " token [string] : token from the watch.\n" \ + "\n" \ + "Returns: [int] 0 on success.\n" \ + "Raises RuntimeError on error.\n" \ + "\n" + static PyObject *xspy_unwatch(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwd_spec[] = { "path", "token", NULL }; @@ -373,6 +466,15 @@ static PyObject *xspy_unwatch(PyObject *self, PyObject *args, PyObject *kwds) return val; } +#define xspy_transaction_start_doc "\n" \ + "Start a transaction on a path.\n" \ + "Only one transaction can be active at a time.\n" \ + " path [string]: xenstore path.\n" \ + "\n" \ + "Returns: [int] 0 on success.\n" \ + "Raises RuntimeError on error.\n" \ + "\n" + static PyObject *xspy_transaction_start(PyObject *self, PyObject *args, PyObject *kwds) { @@ -394,6 +496,15 @@ static PyObject *xspy_transaction_start(PyObject *self, PyObject *args, return val; } +#define xspy_transaction_end_doc "\n" \ + "End the current transaction.\n" \ + "Attempts to commit the transaction unless abort is true.\n" \ + " abort [int]: Abort flag..\n" \ + "\n" \ + "Returns: [int] 0 on success.\n" \ + "Raises RuntimeError on error.\n" \ + "\n" + static PyObject *xspy_transaction_end(PyObject *self, PyObject *args, PyObject *kwds) { @@ -415,6 +526,17 @@ static PyObject *xspy_transaction_end(PyObject *self, PyObject *args, return val; } +#define xspy_introduce_domain_doc "\n" \ + "Tell xenstore about a domain so it can talk to it.\n" \ + " dom [int] : domain id\n" \ + " page [long] : address of domain's xenstore page\n" \ + " port [int] : port the domain is using for xenstore\n" \ + " path [string]: path to the domain's data in xenstore\n" \ + "\n" \ + "Returns: [int] 0 on success.\n" \ + "Raises RuntimeError on error.\n" \ + "\n" + static PyObject *xspy_introduce_domain(PyObject *self, PyObject *args, PyObject *kwds) { @@ -443,6 +565,15 @@ static PyObject *xspy_introduce_domain(PyObject *self, PyObject *args, return val; } +#define xspy_release_domain_doc "\n" \ + "Tell xenstore to release its channel to a domain.\n" \ + "Unless this is done the domain will not be released.\n" \ + " dom [int]: domain id\n" \ + "\n" \ + "Returns: [int] 0 on success.\n" \ + "Raises RuntimeError on error.\n" \ + "\n" + static PyObject *xspy_release_domain(PyObject *self, PyObject *args, PyObject *kwds) { @@ -467,6 +598,13 @@ static PyObject *xspy_release_domain(PyObject *self, PyObject *args, return val; } +#define xspy_close_doc "\n" \ + "Close the connection to xenstore.\n" \ + "\n" \ + "Returns: [int] 0 on success.\n" \ + "Raises RuntimeError on error.\n" \ + "\n" + static PyObject *xspy_close(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwd_spec[] = { NULL }; @@ -487,6 +625,13 @@ static PyObject *xspy_close(PyObject *self, PyObject *args, PyObject *kwds) return val; } +#define xspy_shutdown_doc "\n" \ + "Shutdown the xenstore daemon (xsdaemon).\n" \ + "\n" \ + "Returns: [int] 0 on success.\n" \ + "Raises RuntimeError on error.\n" \ + "\n" + static PyObject *xspy_shutdown(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwd_spec[] = { NULL }; @@ -506,49 +651,31 @@ static PyObject *xspy_shutdown(PyObject *self, PyObject *args, PyObject *kwds) return val; } -#define XSPY_METH(_name) \ - #_name, \ - (PyCFunction) xspy_ ## _name, \ - (METH_VARARGS | METH_KEYWORDS) -// mtime -// ctime +#define XSPY_METH(_name) { \ + .ml_name = #_name, \ + .ml_meth = (PyCFunction) xspy_ ## _name, \ + .ml_flags = (METH_VARARGS | METH_KEYWORDS), \ + .ml_doc = xspy_ ## _name ## _doc } static PyMethodDef xshandle_methods[] = { - { XSPY_METH(read), - "read(path) : read data\n" }, - { XSPY_METH(write), - "write(path, data, [creat], [excl]): write data\n" }, - { XSPY_METH(ls), - "ls(path): list directory.\n" }, - { XSPY_METH(mkdir), - "mkdir(path): make a directory.\n" }, - { XSPY_METH(rm), - "rm(path): remove a path (dir must be empty).\n" }, - { XSPY_METH(get_permissions), - "get_permissions(path)\n" }, - { XSPY_METH(set_permissions), - "set_permissions(path)\n" }, - { XSPY_METH(watch), - "watch(path)\n" }, - { XSPY_METH(read_watch), - "read_watch()\n" }, - { XSPY_METH(acknowledge_watch), - "acknowledge_watch()\n" }, - { XSPY_METH(unwatch), - "unwatch()\n" }, - { XSPY_METH(transaction_start), - "transaction_start()\n" }, - { XSPY_METH(transaction_end), - "transaction_end([abort])\n" }, - { XSPY_METH(introduce_domain), - "introduce_domain(dom, page, port)\n" }, - { XSPY_METH(release_domain), - "release_domain(dom)\n" }, - { XSPY_METH(close), - "close()\n" }, - { XSPY_METH(shutdown), - "shutdown()\n" }, - { NULL, NULL, 0, NULL } + XSPY_METH(read), + XSPY_METH(write), + XSPY_METH(ls), + XSPY_METH(mkdir), + XSPY_METH(rm), + XSPY_METH(get_permissions), + XSPY_METH(set_permissions), + XSPY_METH(watch), + XSPY_METH(read_watch), + XSPY_METH(acknowledge_watch), + XSPY_METH(unwatch), + XSPY_METH(transaction_start), + XSPY_METH(transaction_end), + XSPY_METH(introduce_domain), + XSPY_METH(release_domain), + XSPY_METH(close), + XSPY_METH(shutdown), + { /* Terminator. */ }, }; static PyObject *xshandle_getattr(PyObject *self, char *name) @@ -618,8 +745,15 @@ static PyObject *xshandle_open(PyObject *self, PyObject *args, PyObject *kwds) } static PyMethodDef xs_methods[] = { - { "open", (PyCFunction)xshandle_open, (METH_VARARGS | METH_KEYWORDS), - "Open a connection to the xenstore daemon.\n" }, + { .ml_name = "open", + .ml_meth = (PyCFunction)xshandle_open, + .ml_flags = (METH_VARARGS | METH_KEYWORDS), + .ml_doc = "\n" + "Open a connection to the xenstore daemon.\n" + "Returns: xs connection object.\n" + "Raises RuntimeError on error.\n" + "\n" + }, { NULL, NULL, 0, NULL } }; From b00fe9d70973ff7f16a7412d52eec9caa478780f Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Fri, 17 Jun 2005 17:59:02 +0000 Subject: [PATCH 24/25] bitkeeper revision 1.1713.3.13 (42b30f66_kcj5tkDzz9DSBmqEbyHrQ) xs.c: Update comment. Signed-off-by: Christian Limpach --- tools/python/xen/lowlevel/xs/xs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/python/xen/lowlevel/xs/xs.c b/tools/python/xen/lowlevel/xs/xs.c index bfddb966d0..1b86a03f65 100644 --- a/tools/python/xen/lowlevel/xs/xs.c +++ b/tools/python/xen/lowlevel/xs/xs.c @@ -625,11 +625,11 @@ static PyObject *xspy_close(PyObject *self, PyObject *args, PyObject *kwds) return val; } -#define xspy_shutdown_doc "\n" \ - "Shutdown the xenstore daemon (xsdaemon).\n" \ - "\n" \ - "Returns: [int] 0 on success.\n" \ - "Raises RuntimeError on error.\n" \ +#define xspy_shutdown_doc "\n" \ + "Shutdown the xenstore daemon.\n" \ + "\n" \ + "Returns: [int] 0 on success.\n" \ + "Raises RuntimeError on error.\n" \ "\n" static PyObject *xspy_shutdown(PyObject *self, PyObject *args, PyObject *kwds) From 6d76d5803f88bd58134243e0527750770bd0a4fd Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Fri, 17 Jun 2005 18:18:44 +0000 Subject: [PATCH 25/25] bitkeeper revision 1.1713.3.14 (42b31404a5lBMKNKYzOsHXWQ0k_d-Q) xsnode.py: Updated watches/event code from Mike Wray. Signed-off-by: Mike Wray Signed-off-by: Christian Limpach --- tools/python/xen/xend/xenstore/xsnode.py | 72 ++++++++++++++++-------- 1 file changed, 48 insertions(+), 24 deletions(-) diff --git a/tools/python/xen/xend/xenstore/xsnode.py b/tools/python/xen/xend/xenstore/xsnode.py index f9721caf1b..fee14c395c 100644 --- a/tools/python/xen/xend/xenstore/xsnode.py +++ b/tools/python/xen/xend/xenstore/xsnode.py @@ -46,12 +46,12 @@ class Subscription: watcher.delSubs(self) return watcher - def notify(self, path, val): + def notify(self, token, path, val): try: - self.fn(self, path, val) - except SystemExitException: + self.fn(self, token, path, val) + except SystemExit: raise - except: + except Exception, ex: pass class Watcher: @@ -71,6 +71,9 @@ class Watcher: def getPath(self): return self.path + def getToken(self): + return self.path + def addSubs(self, subs): self.subscriptions.append(subs) self.watch() @@ -83,14 +86,15 @@ class Watcher: def watch(self): if self.xs: return self.xs = xs.open() - self.xs.watch(self.path) + self.xs.watch(path=self.getPath(), token=self.getToken()) def unwatch(self): if self.xs: - try: - self.xs.unwatch(self.path) - except Exception, ex: - print 'Watcher>unwatch>', ex +## Possibly crashes xenstored. +## try: +## self.xs.unwatch(path=self.getPath(), token=self.getToken()) +## except Exception, ex: +## print 'Watcher>unwatch>', ex try: self.xs.close() except Exception, ex: @@ -102,17 +106,22 @@ class Watcher: def getNotification(self): p = self.xs.read_watch() - self.xs.acknowledge_watch() + self.xs.acknowledge_watch(p[1]) return p def notify(self): try: - p = self.getNotification() - v = self.xs.read(p) - for s in subscriptions: - s.notify(p, v) + (path, token) = self.getNotification() + if path.endswith("@eid"): + pass + else: + val = self.xs.read(path) + for subs in self.subscriptions: + subs.notify(token, path, val) + except SystemExit: + raise except Exception, ex: - print 'Notify exception:', ex + raise class EventWatcher(Watcher): @@ -126,6 +135,9 @@ class EventWatcher(Watcher): def getEvent(self): return self.event + def getToken(self): + return self.event + class XenStore: xs = None @@ -145,8 +157,10 @@ class XenStore: self.xs = xs.open() ex = None break + except SystemExit: + raise except Exception, ex: - print >>sys.stderr, "Exception connecting to xsdaemon:", ex + print >>sys.stderr, "Exception connecting to xenstored:", ex print >>sys.stderr, "Trying again..." time.sleep(1) else: @@ -241,7 +255,10 @@ class XenStore: def write(self, path, data, create=True, excl=False): self.mkdirs(path) - self.getxs().write(path, data, create=create, excl=excl) + try: + self.getxs().write(path, data, create=create, excl=excl) + except Exception, ex: + raise def begin(self, path): self.getxs().transaction_start(path) @@ -261,7 +278,10 @@ class XenStore: del self.subscriptions[s.sid] watcher = s.unwatch() if watcher and not watcher.watching(): - del self.watchers[path] + try: + del self.watchers[watcher.getPath()] + except: + pass def subscribe(self, event, fn): path = getEventPath(event) @@ -280,13 +300,10 @@ class XenStore: self.mkdirs(eventPath) eid = 1 if self.exists(eidPath): - data = self.read(eidPath) - print 'sendEvent>', 'data=', data, type(data) try: eid = int(self.read(eidPath)) eid += 1 except Exception, ex: - print 'sendEvent>', ex pass self.write(eidPath, str(eid)) self.write(os.path.join(eventPath, str(eid)), data) @@ -346,6 +363,15 @@ def getXenStore(): xenstore = XenStore() return xenstore +def sendEvent(event, val): + getXenStore.sendEvent(event, val) + +def subscribe(event, fn): + return getXenStore().subscribe(event, fn) + +def unsubscribe(sid): + getXenStore().unsubscribe(sid) + class XenNode: def __init__(self, path="/", create=True): @@ -389,9 +415,7 @@ class XenNode: return None def setData(self, data, path=""): - path = self.relPath(path) - #print 'XenNode>setData>', 'path=', path, 'data=', data - return self.store.write(path, data) + return self.store.write(self.relPath(path), data) def getLock(self): return None