diff --git a/.rootkeys b/.rootkeys index 8a288f2c98..8b50a8e60d 100644 --- a/.rootkeys +++ b/.rootkeys @@ -182,48 +182,28 @@ 40e1b09dMYB4ItGCqcMIzirdMd9I-w tools/libxutil/Makefile 40e033325Sjqs-_4TuzeUEprP_gYFg tools/libxutil/allocate.c 40e03332KYz7o1bn2MG_KPbBlyoIMA tools/libxutil/allocate.h -40e03332IyRttYoXKoJla5qCC514SQ tools/libxutil/debug.h -40e03332qV5tJ-GJZjo-LBCeGuEjJA tools/libxutil/enum.c -40e03332wwMVxfobgA1PSMTSAGLiCw tools/libxutil/enum.h 40e03332p5Dc_owJQRuN72ymJZddFQ tools/libxutil/file_stream.c 40e03332jWfB2viAhLSkq1WK0r_iDQ tools/libxutil/file_stream.h 40e03332rUjNMGg11n2rN6V4DCrvOg tools/libxutil/gzip_stream.c 40e033321O5Qg22haLoq5lpmk4tooQ tools/libxutil/gzip_stream.h -40e03332QrTR96tc6yS2rMBpd2mq1A tools/libxutil/hash_table.c -40e033325KoIb0d_uy8s7b5DUR9fPQ tools/libxutil/hash_table.h 40e03332ihnBGzHykVwZnFmkAppb4g tools/libxutil/iostream.c 40e03332UGwbLR4wsw4ft14p0Yw5pg tools/libxutil/iostream.h 40e0333245DLDzJemeSVBLuutHtzEQ tools/libxutil/kernel_stream.c 40e03332aK0GkgpDdc-PVTkWKTeOBg tools/libxutil/kernel_stream.h -40e03332HJ0cDcZDKDUUT-tEiBWOZw tools/libxutil/lexis.c -40e03332tnH9Ggzxbfi3xY9Vh2hUlg tools/libxutil/lexis.h -40e03332aYIW0BNBh6wXuKKn_P7Yyg tools/libxutil/lzi_stream.c -40e0333233voTffE4cJSMGJARfiSSQ tools/libxutil/lzi_stream.h -40e03332FXuMoUnfsAKSgV8X4rFbYQ tools/libxutil/lzo_stream.c -40e03332InJaiLfpDcIXBy2fI0RFGQ tools/libxutil/lzo_stream.h -40e03332a5SCuRsejHStTuWzMQNv8Q tools/libxutil/marshal.c -40e03332TwKyJrZQiiQfNq4vc2hpgw tools/libxutil/marshal.h -40e033328ccHlJuTR1FswYL_EC6LFA tools/libxutil/socket_stream.c -40e03332P0KVQGkmahj47aafo1X0nA tools/libxutil/socket_stream.h 40e03332KT_tnnoAMbPVAZBB7kSOAQ tools/libxutil/string_stream.c 40e03332-VtK6_OZa1vMHXFil8uq6w tools/libxutil/string_stream.h -40e03332dDtczi6YX7_mMxhYjJeAdQ tools/libxutil/sxpr.c -40e03332QPuyNKDOTIYVvkwK5qO-vg tools/libxutil/sxpr.h -40e03332Pi0_osJ3XPBi38ADPqdl4A tools/libxutil/sxpr_parser.c -40e033324v5QFMvWEXXzv38uUT9kHg tools/libxutil/sxpr_parser.h -40e03332gKUInsqtxQOV4mPiMqf_dg tools/libxutil/sys_ctype.h 40e03332Rkvq6nn_UNjzAAK_Tk9v1g tools/libxutil/sys_net.c 40e03332lQHvQHw4Rh7VsT1_sui29A tools/libxutil/sys_net.h 40e033321smklZd7bDSdWvQCeIshtg tools/libxutil/sys_string.c 40e03332h5V611rRWURRLqb1Ekatxg tools/libxutil/sys_string.h -40e03332u4q5kgF0N7RfqB4s0pZVew tools/libxutil/xdr.c -40e03332hY16nfRXF4gGd5S1aUJUBw tools/libxutil/xdr.h 3f776bd2Xd-dUcPKlPN2vG89VGtfvQ tools/misc/Makefile 40ab2cfawIw8tsYo0dQKtp83h4qfTQ tools/misc/fakei386xen 3f6dc136ZKOjd8PIqLbFBl_v-rnkGg tools/misc/miniterm/Makefile 3f6dc140C8tAeBfroAF24VrmCS4v_w tools/misc/miniterm/README 3f6dc142IHaf6XIcAYGmhV9nNSIHFQ tools/misc/miniterm/miniterm.c 40c9c469kT0H9COWzA4XzPBjWK0WsA tools/misc/netfix +4022a73cEKvrYe_DVZW2JlAxobg9wg tools/misc/nsplitd/Makefile +4022a73cKms4Oq030x2JBzUB426lAQ tools/misc/nsplitd/nsplitd.c 3f870808_8aFBAcZbWiWGdgrGQyIEw tools/misc/p4perf.h 3f5ef5a2ir1kVAthS14Dc5QIRCEFWg tools/misc/xen-clone 3f5ef5a2dTZP0nnsFoeq2jRf3mWDDg tools/misc/xen-clone.README @@ -262,6 +242,7 @@ 40c9c468xzANp6o2D_MeCYwNmOIUsQ tools/python/xen/xend/XendVnet.py 40c9c468x191zetrVlMnExfsQWHxIQ tools/python/xen/xend/__init__.py 40c9c468S2YnCEKmk4ey8XQIST7INg tools/python/xen/xend/encode.py +40e9808elkoRulOo1GxRTp5ulJGVNw tools/python/xen/xend/packing.py 40c9c468DCpMe542varOolW1Xc68ew tools/python/xen/xend/server/SrvBase.py 40c9c468IxQabrKJSWs0aEjl-27mRQ tools/python/xen/xend/server/SrvConsole.py 40c9c4689Io5bxfbYIfRiUvsiLX0EQ tools/python/xen/xend/server/SrvConsoleDir.py @@ -280,7 +261,6 @@ 40c9c469N2-b3GqpLHHHPZykJPLVvA tools/python/xen/xend/server/channel.py 40c9c469hJ_IlatRne-9QEa0-wlquw tools/python/xen/xend/server/console.py 40c9c469UcNJh_NuLU0ytorM0Lk5Ow tools/python/xen/xend/server/controller.py -40c9c469vHh-qLiiubdbKEQbJf18Zw tools/python/xen/xend/server/cstruct.py 40d83983OXjt-y3HjSCcuoPp9rzvmw tools/python/xen/xend/server/domain.py 40c9c469yrm31i60pGKslTi2Zgpotg tools/python/xen/xend/server/messages.py 40c9c46925x-Rjb0Cv2f1-l2jZrPYg tools/python/xen/xend/server/netif.py @@ -288,6 +268,7 @@ 40c9c469LNxLVizOUpOjEaTKKCm8Aw tools/python/xen/xend/sxp.py 40d05079aFRp6NQdo5wIh5Ly31c0cg tools/python/xen/xm/__init__.py 40cf2937gKQcATgXKGtNeWb1PDH5nA tools/python/xen/xm/create.py +40e41cd2w0I4En6qrJn4em8HkK_oxQ tools/python/xen/xm/help.py 40cf2937isyS250zyd0Q2GuEDoNXfQ tools/python/xen/xm/main.py 40cf2937PSslwBliN1g7ofDy2H_RhA tools/python/xen/xm/opts.py 40cf2937Z8WCNOnO2FcWdubvEAF9QQ tools/python/xen/xm/shutdown.py @@ -297,6 +278,32 @@ 403a3edbVpV2E_wq1zeEkJ_n4Uu2eg tools/xentrace/xentrace.c 403a3edblCUrzSj0mmKhO5HOPrOrSQ tools/xentrace/xentrace_format 4050c413NtuyIq5lsYJV4P7KIjujXw tools/xentrace/xentrace_format.1 +40e9808eHO3QprCFKg9l2JJzgt2voA tools/xfrd/Make.xfrd +40e9808epTR4zWrYjGUnaaynK20Q5A tools/xfrd/Makefile +40e9808eysqT4VNDlJFqsZB2rdg4Qw tools/xfrd/connection.c +40e9808eyXfJUi4E0C3WSgrEXqQ1sQ tools/xfrd/connection.h +40e9808eULGwffNOE4kBrAfZ9YAVMA tools/xfrd/debug.h +40e9808eyjiahG5uF6AMelNVujBzCg tools/xfrd/enum.c +40e9808eZpbdn9q2KSSMGCNvY_ZgpQ tools/xfrd/enum.h +40e9808easXCzzAZQodEfKAhgUXSPA tools/xfrd/hash_table.c +40e9808e94BNXIVVKBFHC3rnkvwtJg tools/xfrd/hash_table.h +40e9808epW9iHcLXuO3QfUfLzB7onw tools/xfrd/lexis.c +40e9808egccMhCizayQRGtpBA3L5MQ tools/xfrd/lexis.h +40e9808ePADCSKL1YgGCt2TbYPnYkw tools/xfrd/lzi_stream.c +40e9808eDNAdpF71o5teYb9DTT-PRw tools/xfrd/lzi_stream.h +40e9808eQxi0EzTcPJtosrzxEIjA-Q tools/xfrd/marshal.c +40e9808etg13xfRm0Lqd8vY-jHOoTg tools/xfrd/marshal.h +40e9808eCsmywryb036TdtRMJHDMmQ tools/xfrd/select.c +40e9808e99OcM547cKMTfmCVSoWVAw tools/xfrd/select.h +40e9808e5_PLdodqVOSx0b4T_f5aeg tools/xfrd/sxpr.c +40e9808e0O4sHZtkDv5hlSqjYcdQAQ tools/xfrd/sxpr.h +40e9808eF3NVldqRNS5IHM8gbFAvpw tools/xfrd/xdr.c +40e9808ezXzoRHm7pybXU69NtnjimA tools/xfrd/xdr.h +40e9808edpUtf4bJ8IbqClPJj_OvbA tools/xfrd/xen_domain.c +40e9808eHviFFIwdUKOA234uIeifjA tools/xfrd/xen_domain.h +40e9808eIFeV-MDCNyVTNt5NfMPKeQ tools/xfrd/xfrd.c +40e9808eGIbOoSNJRiwWK2C3mjGWaA tools/xfrd/xfrd.h +40e9808eHXvs_5eggj9McD_J90mhNw tools/xfrd/xfrdClient.py 3f72f1bdJPsV3JCnBqs9ddL9tr6D2g xen/COPYING 3ddb79bcbOVHh38VJzc97-JEGD4dJQ xen/Makefile 3ddb79bcWnTwYsQRWl_PaneJfa6p0w xen/Rules.mk @@ -304,10 +311,11 @@ 3ddb79bcBQF85CfLS4i1WGZ4oLLaCA xen/arch/x86/Rules.mk 3e5636e5FAYZ5_vQnmgwFJfSdmO5Mw xen/arch/x86/acpi.c 3ddb79bcsjinG9k1KcvbVBuas1R2dA xen/arch/x86/apic.c -3ddb79bcSC_LvnmFlX-T5iTgaR0SKg xen/arch/x86/boot/boot.S +3ddb79bcSC_LvnmFlX-T5iTgaR0SKg xen/arch/x86/boot/x86_32.S +40e42bdbNu4MjI750THP_8J1S-Sa0g xen/arch/x86/boot/x86_64.S 3ddb79bcUrk2EIaM5VsT6wUudH1kkg xen/arch/x86/delay.c -3e32af9aRnYGl4GMOaDKp7JdfhOGhg xen/arch/x86/domain_page.c -3ddb79bcecupHj56ZbTa3B0FxDowMg xen/arch/x86/entry.S +40e34414WiQO4h2m3tcpaCPn7SyYyg xen/arch/x86/dom0_ops.c +3ddb79bc1_2bAt67x9MFCP4AZrQnvQ xen/arch/x86/domain.c 3ddb79bcY5zW7KhvI9gvfuPi3ZumEg xen/arch/x86/extable.c 3fe443fdDDb0Sw6NQBCk4GQapayfTA xen/arch/x86/flushtlb.c 3ddb79bcesE5E-lS4QhRhlqXxqj9cA xen/arch/x86/i387.c @@ -315,7 +323,6 @@ 3ddb79bcBit4xJXbwtX0kb1hh2uO1Q xen/arch/x86/idle0_task.c 3ddb79bcKIkRR0kqWaJhe5VUDkMdxg xen/arch/x86/io_apic.c 3ddb79bdqfIcjkz_h9Hvtp8Tk_19Zw xen/arch/x86/irq.c -3ddb79bcHwuCQDjBICDTSis52hWguw xen/arch/x86/mm.c 3ddb79bdS4UeWWXDH-FaBKqcpMFcnw xen/arch/x86/mpparse.c 3f12cff65EV3qOG2j37Qm0ShgvXGRw xen/arch/x86/nmi.c 3ddb79bdHe6_Uij4-glW91vInNtBYQ xen/arch/x86/pci-irq.c @@ -324,16 +331,22 @@ 3ddb79bdIKgipvGoqExEQ7jawfVowA xen/arch/x86/pci-x86.h 40a4dfced2dnSzbKgJFlD3chKHexjQ xen/arch/x86/pdb-linux.c 4022a73czgX7d-2zfF_cb33oVemApQ xen/arch/x86/pdb-stub.c -3ddb79bc1_2bAt67x9MFCP4AZrQnvQ xen/arch/x86/process.c 3ddb79bc7KxGCEJsgBnkDX7XjD_ZEQ xen/arch/x86/rwlock.c 3ddb79bcrD6Z_rUvSDgrvjyb4846Eg xen/arch/x86/setup.c +405b8599xI_PoEr3zZoJ2on-jdn7iw xen/arch/x86/shadow.c 3ddb79bcSx2e8JSR3pdSGa8x1ScYzA xen/arch/x86/smp.c 3ddb79bcfUN3-UBCPzX26IU8bq-3aw xen/arch/x86/smpboot.c 3ddb79bc-Udq7ol-NX4q9XsYnN7A2Q xen/arch/x86/time.c 3ddb79bccYVzXZJyVaxuv5T42Z1Fsw xen/arch/x86/trampoline.S 3ddb79bcOftONV9h4QCxXOfiT0h91w xen/arch/x86/traps.c -3ddb79bc4nTpGQOe6_-MbyZzkhlhFQ xen/arch/x86/usercopy.c -3ddb79bcOMCu9-5mKpjIh5d0qqBDPg xen/arch/x86/xen.lds +3e32af9aRnYGl4GMOaDKp7JdfhOGhg xen/arch/x86/x86_32/domain_page.c +3ddb79bcecupHj56ZbTa3B0FxDowMg xen/arch/x86/x86_32/entry.S +3ddb79bcHwuCQDjBICDTSis52hWguw xen/arch/x86/x86_32/mm.c +3ddb79bc4nTpGQOe6_-MbyZzkhlhFQ xen/arch/x86/x86_32/usercopy.c +3ddb79bcOMCu9-5mKpjIh5d0qqBDPg xen/arch/x86/x86_32/xen.lds +40e96d3aLDI-nViMuYneD7VKYlZrVg xen/arch/x86/x86_64/entry.S +40e96d3ahBTZqbTViInnq0lM03vs7A xen/arch/x86/x86_64/usercopy.c +40e96d3akN3Hu_J5Bk-WXD8OGscrYQ xen/arch/x86/x86_64/xen.lds 3ddb79bdff-gj-jFGKjOejeHLqL8Lg xen/common/Makefile 3e397e66AyyD5fYraAySWuwi9uqSXg xen/common/ac_timer.c 4022a73c_BbDFd2YJ_NQYVvKX5Oz7w xen/common/debug-linux.c @@ -355,7 +368,6 @@ 40ec1922He_dRhVJdOicTcHvT8v1NQ xen/common/sched_fair_bvt.c 40589968be_t_n0-w6ggceW7h-sx0w xen/common/sched_rrobin.c 3e397e6619PgAfBbw2XFbXkewvUWgw xen/common/schedule.c -405b8599xI_PoEr3zZoJ2on-jdn7iw xen/common/shadow.c 3ddb79bdB9RNMnkQnUyZ5C9hhMSQQw xen/common/slab.c 3ddb79bd0gVQYmL2zvuJnldvD0AGxQ xen/common/softirq.c 3e7f358awXBC3Vw-wFRwPw18qL1khg xen/common/string.c @@ -445,6 +457,7 @@ 3ddb79c2QF5-pZGzuX4QukPCDAl59A xen/include/asm-x86/processor.h 40cf1596bim9F9DNdV75klgRSZ6Y2A xen/include/asm-x86/ptrace.h 3ddb79c2plf7ciNgoNjU-RsbUzawsw xen/include/asm-x86/rwlock.h +405b8599BsDsDwKEJLS0XipaiQW3TA xen/include/asm-x86/shadow.h 3ddb79c3Hgbb2g8CyWLMCK-6_ZVQSQ xen/include/asm-x86/smp.h 3ddb79c3jn8ALV_S9W5aeTYUQRKBpg xen/include/asm-x86/smpboot.h 3ddb79c3NiyQE2vQnyGiaBnNjBO1rA xen/include/asm-x86/spinlock.h @@ -502,7 +515,7 @@ 40589969nPq3DMzv24RDb5LXE9brHw xen/include/xen/sched-if.h 3ddb79c0LzqqS0LhAQ50ekgj4oGl7Q xen/include/xen/sched.h 403a06a7H0hpHcKpAiDe5BPnaXWTlA xen/include/xen/serial.h -405b8599BsDsDwKEJLS0XipaiQW3TA xen/include/xen/shadow.h +40e3392dib7GrcBAu5cT-EUZTYzeEQ xen/include/xen/shadow.h 3ddb79c14dXIhP7C2ahnoD08K90G_w xen/include/xen/slab.h 3ddb79c09xbS-xxfKxuV3JETIhBzmg xen/include/xen/smp.h 3ddb79c1Vi5VleJAOKHAlY0G2zAsgw xen/include/xen/softirq.h diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 04eb20bb84..94cfc0620d 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -9,6 +9,7 @@ bd240@labyrinth.cl.cam.ac.uk br260@br260.wolfson.cam.ac.uk br260@labyrinth.cl.cam.ac.uk br260@laudney.cl.cam.ac.uk +djm@kirby.fc.hp.com gm281@boulderdash.cl.cam.ac.uk iap10@freefall.cl.cam.ac.uk iap10@labyrinth.cl.cam.ac.uk @@ -39,4 +40,5 @@ smh22@uridium.cl.cam.ac.uk sos22@labyrinth.cl.cam.ac.uk tlh20@elite.cl.cam.ac.uk tlh20@labyrinth.cl.cam.ac.uk +tw275@striker.cl.cam.ac.uk xenbk@gandalf.hpl.hp.com diff --git a/docs/HOWTOs/XenDebugger-HOWTO b/docs/HOWTOs/XenDebugger-HOWTO index 8d5dc69e69..1aba294abb 100644 --- a/docs/HOWTOs/XenDebugger-HOWTO +++ b/docs/HOWTOs/XenDebugger-HOWTO @@ -77,7 +77,7 @@ Serial Port Configuration 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/nsplitd + See: xeno.bk/tools/misc/nsplitd nsplitd configuration --------------------- @@ -107,7 +107,7 @@ Serial Port Configuration characters received. You can connect to the nsplitd using - 'tools/xenctl/lib/console_client.py ' + 'tools/misc/xencons ' GDB 6.0 pdb has been tested with gdb 6.0. It should also work with diff --git a/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/common.h b/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/common.h index daf09a76f9..a9f2b87844 100644 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/common.h +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/common.h @@ -19,7 +19,7 @@ #define ASSERT(_p) \ if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \ __LINE__, __FILE__); *(int*)0=0; } -#define DPRINTK(_f, _a...) printk("(file=%s, line=%d) " _f, \ +#define DPRINTK(_f, _a...) printk(KERN_ALERT "(file=%s, line=%d) " _f, \ __FILE__ , __LINE__ , ## _a ) #else #define ASSERT(_p) ((void)0) diff --git a/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/interface.c b/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/interface.c index 780d793c6c..a555b18e72 100644 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/interface.c +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/interface.c @@ -217,12 +217,14 @@ int blkif_disconnect(blkif_be_disconnect_t *disconnect, u8 rsp_id) blkif->status = DISCONNECTING; blkif->disconnect_rspid = rsp_id; wmb(); /* Let other CPUs see the status change. */ - free_irq(blkif->irq, NULL); + free_irq(blkif->irq, blkif); blkif_deschedule(blkif); blkif_put(blkif); + return 0; /* Caller should not send response message. */ } - return 0; /* Caller should not send response message. */ + disconnect->status = BLKIF_BE_STATUS_OKAY; + return 1; } void __init blkif_interface_init(void) diff --git a/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/frontend/main.c b/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/frontend/main.c index fa662496ec..1216600eff 100644 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/frontend/main.c +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/frontend/main.c @@ -616,7 +616,7 @@ static void blkif_status_change(blkif_fe_interface_status_changed_t *status) printk(KERN_INFO "VBD driver recovery in progress\n"); - /* Prevent new requests being issued until we've fixed things up. */ + /* Prevent new requests being issued until we fix things up. */ spin_lock_irq(&io_request_lock); recovery = 1; blkif_state = BLKIF_STATE_DISCONNECTED; diff --git a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/common.h b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/common.h index f3eff0d81b..87fdb730d1 100644 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/common.h +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/common.h @@ -21,7 +21,7 @@ #define ASSERT(_p) \ if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \ __LINE__, __FILE__); *(int*)0=0; } -#define DPRINTK(_f, _a...) printk("(file=%s, line=%d) " _f, \ +#define DPRINTK(_f, _a...) printk(KERN_ALERT "(file=%s, line=%d) " _f, \ __FILE__ , __LINE__ , ## _a ) #else #define ASSERT(_p) ((void)0) diff --git a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c index 2c4b74e1ea..757d10ba2c 100644 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c @@ -266,12 +266,14 @@ int netif_disconnect(netif_be_disconnect_t *disconnect, u8 rsp_id) netif->disconnect_rspid = rsp_id; wmb(); /* Let other CPUs see the status change. */ netif_stop_queue(netif->dev); - free_irq(netif->irq, NULL); + free_irq(netif->irq, netif); netif_deschedule(netif); netif_put(netif); + return 0; /* Caller should not send response message. */ } - return 0; /* Caller should not send response message. */ + disconnect->status = NETIF_BE_STATUS_OKAY; + return 1; } void netif_interface_init(void) diff --git a/linux-2.4.26-xen-sparse/arch/xen/kernel/ctrl_if.c b/linux-2.4.26-xen-sparse/arch/xen/kernel/ctrl_if.c index 0e6389406c..f208efe100 100644 --- a/linux-2.4.26-xen-sparse/arch/xen/kernel/ctrl_if.c +++ b/linux-2.4.26-xen-sparse/arch/xen/kernel/ctrl_if.c @@ -17,6 +17,13 @@ #include #include +#if 0 +#define DPRINTK(_f, _a...) printk(KERN_ALERT "(file=%s, line=%d) " _f, \ + __FILE__ , __LINE__ , ## _a ) +#else +#define DPRINTK(_f, _a...) ((void)0) +#endif + /* * Only used by initial domain which must create its own control-interface * event channel. This value is picked up by the user-space domain controller @@ -86,6 +93,11 @@ static void __ctrl_if_tx_tasklet(unsigned long data) { msg = &ctrl_if->tx_ring[MASK_CONTROL_IDX(ctrl_if_tx_resp_cons)]; + DPRINTK("Rx-Rsp %u/%u :: %d/%d\n", + ctrl_if_tx_resp_cons, + ctrl_if->tx_resp_prod, + msg->type, msg->subtype); + /* Execute the callback handler, if one was specified. */ if ( msg->id != 0xFF ) { @@ -131,8 +143,15 @@ static void __ctrl_if_rx_tasklet(unsigned long data) { pmsg = &ctrl_if->rx_ring[MASK_CONTROL_IDX(ctrl_if_rx_req_cons++)]; memcpy(&msg, pmsg, offsetof(ctrl_msg_t, msg)); + + DPRINTK("Rx-Req %u/%u :: %d/%d\n", + ctrl_if_rx_req_cons-1, + ctrl_if->rx_req_prod, + msg.type, msg.subtype); + if ( msg.length != 0 ) memcpy(msg.msg, pmsg->msg, msg.length); + if ( test_bit(msg.type, &ctrl_if_rxmsg_blocking_context) ) { pmsg = &ctrl_if_rxmsg_deferred[MASK_CONTROL_IDX( @@ -185,6 +204,11 @@ int ctrl_if_send_message_noblock( msg->id = i; } + DPRINTK("Tx-Req %u/%u :: %d/%d\n", + ctrl_if->tx_req_prod, + ctrl_if_tx_resp_cons, + msg->type, msg->subtype); + memcpy(&ctrl_if->tx_ring[MASK_CONTROL_IDX(ctrl_if->tx_req_prod)], msg, sizeof(*msg)); wmb(); /* Write the message before letting the controller peek at it. */ @@ -262,11 +286,18 @@ void ctrl_if_send_response(ctrl_msg_t *msg) * In this situation we may have src==dst, so no copying is required. */ spin_lock_irqsave(&ctrl_if_lock, flags); + + DPRINTK("Tx-Rsp %u :: %d/%d\n", + ctrl_if->rx_resp_prod, + msg->type, msg->subtype); + dmsg = &ctrl_if->rx_ring[MASK_CONTROL_IDX(ctrl_if->rx_resp_prod)]; if ( dmsg != msg ) memcpy(dmsg, msg, sizeof(*msg)); + wmb(); /* Write the message before letting the controller peek at it. */ ctrl_if->rx_resp_prod++; + spin_unlock_irqrestore(&ctrl_if_lock, flags); ctrl_if_notify_controller(); diff --git a/linux-2.4.26-xen-sparse/arch/xen/kernel/process.c b/linux-2.4.26-xen-sparse/arch/xen/kernel/process.c index aa59c37790..6d80505743 100644 --- a/linux-2.4.26-xen-sparse/arch/xen/kernel/process.c +++ b/linux-2.4.26-xen-sparse/arch/xen/kernel/process.c @@ -115,7 +115,7 @@ void cpu_idle (void) } } -void machine_restart(char * __unused) +void machine_restart(char *__unused) { /* We really want to get pending console data out before we die. */ extern void xencons_force_flush(void); @@ -128,7 +128,11 @@ void machine_halt(void) /* We really want to get pending console data out before we die. */ extern void xencons_force_flush(void); xencons_force_flush(); - HYPERVISOR_shutdown(); + for ( ; ; ) /* loop without wasting cpu cycles */ + { + HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_pending = 0; + HYPERVISOR_block(); + } } void machine_power_off(void) diff --git a/linux-2.4.26-xen-sparse/arch/xen/kernel/setup.c b/linux-2.4.26-xen-sparse/arch/xen/kernel/setup.c index b329632b78..42ef543546 100644 --- a/linux-2.4.26-xen-sparse/arch/xen/kernel/setup.c +++ b/linux-2.4.26-xen-sparse/arch/xen/kernel/setup.c @@ -8,6 +8,8 @@ * This file handles the architecture-dependent parts of initialization */ +#define __KERNEL_SYSCALLS__ +static int errno; #include #include #include @@ -30,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -1148,10 +1151,10 @@ void __init cpu_init (void) #include -/* Treat multiple suspend requests as a single one. */ -static int suspending; +/* Ignore multiple shutdown requests. */ +static int shutting_down = -1; -static void suspend_task(void *unused) +static void __do_suspend(void) { /* Hmmm... a cleaner interface to suspend/resume blkdevs would be nice. */ extern void blkdev_suspend(void); @@ -1220,7 +1223,7 @@ static void suspend_task(void *unused) HYPERVISOR_suspend(virt_to_machine(suspend_record) >> PAGE_SHIFT); - suspending = 0; + shutting_down = -1; memcpy(&start_info, &suspend_record->resume_info, sizeof(start_info)); @@ -1272,25 +1275,78 @@ static void suspend_task(void *unused) free_page((unsigned long)suspend_record); } -static struct tq_struct suspend_tq; - -static void shutdown_handler(ctrl_msg_t *msg, unsigned long id) +static int shutdown_process(void *__unused) { - if ( msg->subtype != CMSG_SHUTDOWN_SUSPEND ) + static char *envp[] = { "HOME=/", "TERM=linux", + "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; + static char *restart_argv[] = { "/sbin/shutdown", "-r", "now", NULL }; + static char *poweroff_argv[] = { "/sbin/halt", "-p", NULL }; + + extern asmlinkage long sys_reboot(int magic1, int magic2, + unsigned int cmd, void *arg); + + daemonize(); + + switch ( shutting_down ) { - extern void ctrl_alt_del(void); - ctrl_if_send_response(msg); - ctrl_alt_del(); + case CMSG_SHUTDOWN_POWEROFF: + if ( execve("/sbin/halt", poweroff_argv, envp) < 0 ) + { + sys_reboot(LINUX_REBOOT_MAGIC1, + LINUX_REBOOT_MAGIC2, + LINUX_REBOOT_CMD_POWER_OFF, + NULL); + } + break; + + case CMSG_SHUTDOWN_REBOOT: + if ( execve("/sbin/shutdown", restart_argv, envp) < 0 ) + { + sys_reboot(LINUX_REBOOT_MAGIC1, + LINUX_REBOOT_MAGIC2, + LINUX_REBOOT_CMD_RESTART, + NULL); + } + break; } - else if ( !suspending ) + + return 0; +} + +static void __shutdown_handler(void *unused) +{ + int err; + + if ( shutting_down != CMSG_SHUTDOWN_SUSPEND ) { - suspending = 1; - suspend_tq.routine = suspend_task; - schedule_task(&suspend_tq); + err = kernel_thread(shutdown_process, NULL, CLONE_FS | CLONE_FILES); + if ( err < 0 ) + printk(KERN_ALERT "Error creating shutdown process!\n"); + else + shutting_down = -1; /* could try again */ } else { - printk(KERN_ALERT"Ignore queued suspend request\n"); + __do_suspend(); + } +} + +static void shutdown_handler(ctrl_msg_t *msg, unsigned long id) +{ + static struct tq_struct shutdown_tq; + + if ( (shutting_down == -1) && + ((msg->subtype == CMSG_SHUTDOWN_POWEROFF) || + (msg->subtype == CMSG_SHUTDOWN_REBOOT) || + (msg->subtype == CMSG_SHUTDOWN_SUSPEND)) ) + { + shutting_down = msg->subtype; + shutdown_tq.routine = __shutdown_handler; + schedule_task(&shutdown_tq); + } + else + { + printk("Ignore spurious shutdown request\n"); } ctrl_if_send_response(msg); diff --git a/tools/examples/xmdefaults b/tools/examples/xmdefaults index f7b2f53c21..640a7390a0 100644 --- a/tools/examples/xmdefaults +++ b/tools/examples/xmdefaults @@ -2,17 +2,23 @@ #============================================================================ # Python defaults setup for 'xm create'. # Edit this file to reflect the configuration of your system. -# This file expects the variable 'vmid' to be set. #============================================================================ -try: - vmid = int(vmid) # convert to integer -except: - raise ValueError, "Variable 'vmid' must be an integer" +# Define script variables here. +# xm_vars is defined automatically, use xm_vars.var() to define a variable. -if vmid <= 0: - raise ValueError, "Variable 'vmid' must be greater than 0" +def vmid_check(var, val): + val = int(val) + if val <= 0: + raise ValueError + return val + +xm_vars.var('vmid', + use="Virtual machine id. Integer greater than 0.", + check=vmid_check) +# This checks the script variables. +xm_vars.check() #---------------------------------------------------------------------------- # Kernel image file. @@ -87,6 +93,6 @@ extra = "4 VMID=%d usr=/dev/sda6" % vmid #---------------------------------------------------------------------------- # Set according to whether you want the domain restarted when it exits. # The default is False. -#restart = True +#autorestart = True #============================================================================ diff --git a/tools/examples/xmnetbsd b/tools/examples/xmnetbsd index 0563239464..4f920087b6 100644 --- a/tools/examples/xmnetbsd +++ b/tools/examples/xmnetbsd @@ -2,24 +2,23 @@ #============================================================================ # Python defaults setup for 'xm create'. # Edit this file to reflect the configuration of your system. -# This file expects the variable 'vmid' to be set. #============================================================================ -def config_usage (): - print >>sys.stderr,""" -The config file '%s' requires the following variable to be defined: - vmid -- Numeric identifier for the new domain, used to calculate - the VM's IP address and root partition. E.g. -Dvmid=1 -""" % config_file +# Define script variables here. +# xm_vars is defined automatically, use xm_vars.var() to define a variable. +def vmid_check(var, val): + val = int(val) + if val <= 0: + raise ValueError + return val + +xm_vars.var('vmid', + use="Virtual machine id. Integer greater than 0.", + check=vmid_check) -try: - vmid = int(vmid) # convert to integer -except: - raise ValueError, "Variable 'vmid' must be an integer" - -if vmid <= 0: - raise ValueError, "Variable 'vmid' must be greater than 0" +# This checks the script variables. +xm_vars.check() #---------------------------------------------------------------------------- # Kernel image file. @@ -97,6 +96,6 @@ extra = "4 VMID=%d bootdev=xennet0" % vmid #---------------------------------------------------------------------------- # Set according to whether you want the domain restarted when it exits. # The default is False. -#restart = True +#autorestart = True #============================================================================ diff --git a/tools/libxutil/Makefile b/tools/libxutil/Makefile index 8ba9eb3454..8be24daa92 100644 --- a/tools/libxutil/Makefile +++ b/tools/libxutil/Makefile @@ -8,7 +8,7 @@ LIB_SRCS += allocate.c LIB_SRCS += file_stream.c LIB_SRCS += gzip_stream.c LIB_SRCS += iostream.c -LIB_SRCS += sys_net.c +#LIB_SRCS += sys_net.c LIB_SRCS += sys_string.c LIB_OBJS := $(LIB_SRCS:.c=.o) diff --git a/tools/libxutil/allocate.h b/tools/libxutil/allocate.h index 08bc67b910..391b7be2bd 100644 --- a/tools/libxutil/allocate.h +++ b/tools/libxutil/allocate.h @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _XEN_LIB_ALLOCATE_H_ -#define _XEN_LIB_ALLOCATE_H_ +#ifndef _XUTIL_ALLOCATE_H_ +#define _XUTIL_ALLOCATE_H_ /** Allocate memory for a given type, and cast. */ #define ALLOCATE(ctype) (ctype *)allocate(sizeof(ctype)) @@ -33,7 +33,7 @@ extern void memzero(void *p, int size); typedef void AllocateFailedFn(int size, int type); extern AllocateFailedFn *allocate_failed_fn; -#endif /* _XEN_LIB_ALLOCATE_H_ */ +#endif /* _XUTIL_ALLOCATE_H_ */ diff --git a/tools/libxutil/file_stream.h b/tools/libxutil/file_stream.h index 36a0f928b2..f717656c24 100644 --- a/tools/libxutil/file_stream.h +++ b/tools/libxutil/file_stream.h @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _XEN_LIB_FILE_STREAM_H_ -#define _XEN_LIB_FILE_STREAM_H_ +#ifndef _XUTIL_FILE_STREAM_H_ +#define _XUTIL_FILE_STREAM_H_ #ifndef __KERNEL__ #include "iostream.h" @@ -32,4 +32,4 @@ extern IOStream get_stream_stdin(void); extern int file_stream_setvbuf(IOStream *io, char *buf, int mode, size_t size); #endif -#endif /* !_XEN_LIB_FILE_STREAM_H_ */ +#endif /* !_XUTIL_FILE_STREAM_H_ */ diff --git a/tools/libxutil/gzip_stream.c b/tools/libxutil/gzip_stream.c index af46023f9d..a933c5ff73 100644 --- a/tools/libxutil/gzip_stream.c +++ b/tools/libxutil/gzip_stream.c @@ -1,4 +1,3 @@ -/* $Id: gzip_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */ /* * Copyright (C) 2003 Hewlett-Packard Company. * diff --git a/tools/libxutil/gzip_stream.h b/tools/libxutil/gzip_stream.h index cf76d25275..fd28e39575 100644 --- a/tools/libxutil/gzip_stream.h +++ b/tools/libxutil/gzip_stream.h @@ -1,4 +1,3 @@ -#/* $Id: gzip_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */ /* * Copyright (C) 2003 Hewlett-Packard Company. * @@ -17,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _SP_GZIP_STREAM_H_ -#define _SP_GZIP_STREAM_H_ +#ifndef _XUTIL_GZIP_STREAM_H_ +#define _XUTIL_GZIP_STREAM_H_ #ifndef __KERNEL__ #include "iostream.h" @@ -28,4 +27,4 @@ extern IOStream *gzip_stream_new(gzFile *f); extern IOStream *gzip_stream_fopen(const char *file, const char *flags); extern IOStream *gzip_stream_fdopen(int fd, const char *flags); #endif -#endif /* !_SP_FILE_STREAM_H_ */ +#endif /* !_XUTIL_GZIP_STREAM_H_ */ diff --git a/tools/libxutil/kernel_stream.h b/tools/libxutil/kernel_stream.h index be370f2a45..0f18058d59 100644 --- a/tools/libxutil/kernel_stream.h +++ b/tools/libxutil/kernel_stream.h @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _XEN_LIB_KERNEL_STREAM_H_ -#define _XEN_LIB_KERNEL_STREAM_H_ +#ifndef _XUTIL_KERNEL_STREAM_H_ +#define _XUTIL_KERNEL_STREAM_H_ #ifdef __KERNEL__ #include "iostream.h" @@ -26,4 +26,4 @@ extern IOStream get_stream_kernel(void); #define get_stream_stdout get_stream_kernel #endif /* __KERNEL__ */ -#endif /* !_XEN_LIB_KERNEL_STREAM_H_ */ +#endif /* !_XUTIL_KERNEL_STREAM_H_ */ diff --git a/tools/libxutil/lzo_stream.c b/tools/libxutil/lzo_stream.c deleted file mode 100644 index bf7c348471..0000000000 --- a/tools/libxutil/lzo_stream.c +++ /dev/null @@ -1,596 +0,0 @@ -/* $Id: lzo_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */ -#define __FILE_ID_INFO "$Id: lzo_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $" -#include -static char __rcsid[] __attribute__((unused)) = WHAT_ID __FILE_ID_INFO; -/* - * Copyright (C) 2003 Hewlett-Packard Company. - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/** @file - * An IOStream implementation using LZO to provide compression and decompression. - * This is designed to provide reasonable compression without output latency. - * Flushing an LZO stream flushes all pending data to the underlying stream. - * This is essential for stream-based (e.g. networked) applications. - * - * A compressed data stream is a sequence of blocks. - * Each block except the last is the plain data size followed by the compressed data size - * and the compressed data. The last block has plain data size zero and omits the rest. - * Sizes are 4-byte unsigned in network order. If the compressed size is smaller than - * the plain size the block data is compressed, otherwise it is plain (uncompressed). - * - * This format allows compressed data to be read from a stream without reading - * past the logical end of compressed data. - * - * @author Mike Wray - */ -#ifndef __KERNEL__ - -#include -#include -#include -#include - -#include "lzo1x.h" - -#include "allocate.h" -#include "lzo_stream.h" -#include "file_stream.h" -#include "marshal.h" - -#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] LZO>%s" fmt, __FUNCTION__, ##args) -#define wprintf(fmt, args...) fprintf(stderr, "[WARN] LZO>%s" fmt, __FUNCTION__, ##args) -#define iprintf(fmt, args...) fprintf(stdout, "[INFO] LZO>%s" fmt, __FUNCTION__, ##args) -#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] LZO>%s" fmt, __FUNCTION__, ##args) - -static int lzo_read(IOStream *s, void *buf, size_t size, size_t count); -static int lzo_write(IOStream *s, const void *buf, size_t size, size_t count); -static int lzo_print(IOStream *s, const char *msg, va_list args); -static int lzo_getc(IOStream *s); -static int lzo_error(IOStream *s); -static int lzo_close(IOStream *s); -static void lzo_free(IOStream *s); -static int lzo_flush(IOStream *s); - -enum { - LZO_WRITE = 1, - LZO_READ = 2, -}; - -/** Methods used by a gzFile* IOStream. */ -static const IOMethods lzo_methods = { - read: lzo_read, - write: lzo_write, - print: lzo_print, - getc: lzo_getc, - error: lzo_error, - close: lzo_close, - free: lzo_free, - flush: lzo_flush, -}; - -//#define PLAIN_SIZE (64 * 1024) -//#define PLAIN_SIZE (128 * 1024) -#define PLAIN_SIZE (512 * 1024) - -//#define NOCOMPRESS - -typedef struct LZOState { - /** Flags. */ - int flags; - /** Error indicator. */ - int error; - /** Underlying stream for I/O. */ - IOStream *io; - /** Working memory (only needed for compression, not decompression). */ - lzo_byte *memory; - /** Buffer for plain (uncompressed) data. */ - lzo_byte *plain; - /** Size of the plain buffer. */ - lzo_uint plain_size; - /** Pointer into the plain buffer. */ - lzo_byte *plain_ptr; - /** Number of bytes of plain data available. */ - lzo_uint plain_n; - /** Buffer for compressed data. */ - lzo_byte *comp; - /** Size of the compressed buffer. */ - lzo_uint comp_size; - - int plain_bytes; - int comp_bytes; -} LZOState; - -void LZOState_free(LZOState *z){ - if(!z) return; - deallocate(z->memory); - deallocate(z->plain); - deallocate(z->comp); - deallocate(z); -} - -/** Maximum size of compressed data for the given plain data size. - * - * @param plain_size size of plain data - * @return maximum size of compressed data - */ -static int comp_size(int plain_size){ - return plain_size + (plain_size / 64) + 16 + 3; -} - -static int mode_flags(const char *mode, int *flags){ - int err = 0; - int r=0, w=0; - if(!mode){ - err = -EINVAL; - goto exit; - } - for(; *mode; mode++){ - if(*mode == 'w') w = 1; - if(*mode == 'r') r = 1; - } - if(r + w != 1){ - err = -EINVAL; - goto exit; - } - if(r) *flags |= LZO_READ; - if(w) *flags |= LZO_WRITE; - exit: - return err; -} - -/** Get the stream state. - * - * @param s lzo stream - * @return stream state. - */ -static inline LZOState * lzo_state(IOStream *s){ - return s->data; -} - -IOStream *lzo_stream_io(IOStream *s){ - LZOState *state = lzo_state(s); - return state->io; -} - -static inline void set_error(LZOState *state, int err){ - if(err < 0 && !state->error){ - state->error = err; - } -} - -int lzo_stream_plain_bytes(IOStream *s){ - LZOState *state = lzo_state(s); - return state->plain_bytes; -} - -int lzo_stream_comp_bytes(IOStream *s){ - LZOState *state = lzo_state(s); - return state->comp_bytes; -} - -float lzo_stream_ratio(IOStream *s){ - LZOState *state = lzo_state(s); - float ratio = 0.0; - if(state->comp_bytes){ - ratio = ((float) state->comp_bytes)/((float) state->plain_bytes); - } - return ratio; -} - -static inline int LZOState_writeable(LZOState *state){ - return (state->flags & LZO_WRITE) != 0; -} - -static inline int LZOState_readable(LZOState *state){ - return (state->flags & LZO_READ) != 0; -} - -LZOState * LZOState_new(IOStream *io, int flags){ - int err = -ENOMEM; - LZOState *z = ALLOCATE(LZOState); - //dprintf(">\n"); - if(!z) goto exit; - z->io = io; - z->flags = flags; - if(LZOState_writeable(z)){ - z->memory = allocate(LZO1X_1_MEM_COMPRESS); - if(!z->memory) goto exit; - } - z->plain_size = PLAIN_SIZE; - z->plain = allocate(z->plain_size); - if(!z->plain) goto exit; - z->plain_ptr = z->plain; - z->comp_size = comp_size(z->plain_size); - z->comp = allocate(z->comp_size); - if(!z->comp) goto exit; - err = 0; - exit: - if(err){ - LZOState_free(z); - z = NULL; - } - //dprintf("< z=%p\n", z); - return z; -} - -static int lzo_compress(LZOState *state){ - int err = 0; - int k, comp_n; - //dprintf(">\n"); - //dprintf(">plain=%p plain_n=%d comp=%p memory=%p\n", state->plain, state->plain_n, state->comp, state->memory); - // Compress the plain buffer. - err = lzo1x_1_compress(state->plain, state->plain_n, - state->comp, &comp_n, - state->memory); - //dprintf("> err=%d plain_n=%d comp_n=%d\n", err, state->plain_n, comp_n); - // Write plain size, compressed size. - err = marshal_uint32(state->io, state->plain_n); - if(err) goto exit; - err = marshal_uint32(state->io, comp_n); - if(err) goto exit; - //dprintf("> write data...\n"); - // Write the smaller of the compressed and plain data. - if(state->plain_n < comp_n){ - k = state->plain_n; - err = marshal_bytes(state->io, state->plain, state->plain_n); - } else { - k = comp_n; - err = marshal_bytes(state->io, state->comp, comp_n); - } - if(err) goto exit; - // Total output bytes. - k+= 8; - //dprintf("> wrote %d bytes\n", k); - state->plain_bytes += state->plain_n; - state->comp_bytes += k; - //dprintf("> plain=%d, comp=%d, ratio=%3.2f\n", - // state->plain_bytes, state->comp_bytes, - // ((float)state->comp_bytes)/((float)state->plain_bytes)); - // Reset the plain buffer. - state->plain_ptr = state->plain; - state->plain_n = 0; - err = k; - exit: - //dprintf("< err=%d\n", err); - return err; -} - -static int lzo_decompress(LZOState *state){ - int plain_n, comp_n; - int err, k; - //dprintf(">\n"); - err = unmarshal_uint32(state->io, &plain_n); - //dprintf("> err=%d plain_n=%d\n", err, plain_n); - if(err) goto exit; - state->comp_bytes += 4; - if(plain_n == 0) goto exit; - err = unmarshal_uint32(state->io, &comp_n); - //dprintf("> err=%d comp_n=%d\n", err, comp_n); - if(err) goto exit; - state->comp_bytes += 4; - if(plain_n > state->plain_size){ - err = -EINVAL; - goto exit; - } - if(comp_n > plain_n){ - //dprintf("> reading plain data %d...\n", plain_n); - k = plain_n; - err = unmarshal_bytes(state->io, state->plain, plain_n); - state->plain_n = plain_n; - } else { - //dprintf("> reading comp data %d...\n", comp_n); - k = comp_n; - err = unmarshal_bytes(state->io, state->comp, comp_n); - //dprintf("> decompress comp_n=%d\n", comp_n); - err = lzo1x_decompress(state->comp, comp_n, - state->plain, &state->plain_n, - state->memory); - //dprintf("> err=%d plain=%d state->plain_n=%d\n", err, plain_n, state->plain_n); - if(err != LZO_E_OK || state->plain_n != plain_n){ - // Bad. Corrupted input. - err = -EINVAL; - eprintf("> Corrupted!\n"); - goto exit; - } - } - state->comp_bytes += k; - state->plain_bytes += state->plain_n; - state->plain_ptr = state->plain; - err = k; - exit: - //dprintf("< err=%d\n", err); - return err; -} - -/** Write to the underlying stream using fwrite(); - * - * @param stream destination - * @param buf data - * @param size size of data elements - * @param count number of data elements to write - * @return number of data elements written - */ -static int lzo_write(IOStream *s, const void *buf, size_t size, size_t count){ - int err = 0; - int n = size * count; // Total number of bytes to write. - int chunk; // Size of chunk to write. - int remaining; // Number of bytes remaining to write. - int space; // Amount of space left in plain buffer. - LZOState *state = lzo_state(s); -#ifdef NOCOMPRESS - //dprintf("> buf=%p size=%d count=%d\n", buf, size, count); - err = IOStream_write(state->io, buf, size, count); - //dprintf("< err=%d\n", err); -#else - //dprintf("> buf=%p size=%d count=%d n=%d\n", buf, size, count, n); - remaining = n; - space = state->plain_size - state->plain_n; - //dprintf("> plain=%p plain_ptr=%p plain_n=%d space=%d\n", - // state->plain, state->plain_ptr, state->plain_n, space); - while(remaining){ - chunk = remaining; - if(chunk > space) chunk = space; - //dprintf("> memcpy %p %p %d\n", state->plain_ptr, buf, chunk); - memcpy(state->plain_ptr, buf, chunk); - remaining -= chunk; - space -= chunk; - state->plain_ptr += chunk; - state->plain_n += chunk; - if(space == 0){ - // Input buffer is full. Compress and write it. - err = lzo_compress(state); - if(err < 0) goto exit; - space = state->plain_size - state->plain_n; - } - } - err = (size > 1 ? n / size : n); - exit: - set_error(state, err); -#endif - return err; -} - - -/** Read from the underlying stream. - * - * @param stream input - * @param buf where to put input - * @param size size of data elements - * @param count number of data elements to read - * @return number of data elements read - */ -static int lzo_read(IOStream *s, void *buf, size_t size, size_t count){ - int err = 0; - int k = 0; // Number of (plain) bytes read. - int remaining = size * count; // Number of bytes remaining to read. - int chunk; // Size of chunk to read. - LZOState *state = lzo_state(s); -#ifdef NOCOMPRESS - //dprintf("> buf=%p size=%d count=%d\n", buf, size, count); - err = IOStream_read(state->io, buf, size, count); - //dprintf("< err=%d\n", err); -#else - if(!(state->flags & LZO_READ)){ - err = -EINVAL; - goto exit; - } - while(remaining){ - if(state->plain_n == 0){ - // No more plain input, decompress some more. - err = lzo_decompress(state); - if(err < 0) goto exit; - // Stop reading if there is no more input. - if(err == 0 || state->plain_n == 0) break; - } - chunk = remaining; - if(chunk > state->plain_n) chunk = state->plain_n; - memcpy(buf, state->plain_ptr, chunk); - k += chunk; - buf += chunk; - state->plain_ptr += chunk; - state->plain_n -= chunk; - remaining -= chunk; - } - err = k; - exit: - set_error(state, err); -#endif - return err; -} - -/** Print to the underlying stream. - * Returns 0 if the formatted output is too big for the internal buffer. - * - * @param s lzo stream - * @param msg format to use - * @param args arguments - * @return result of the print - */ -static int lzo_print(IOStream *s, const char *msg, va_list args){ - char buf[1024]; - int buf_n = sizeof(buf); - int n; - LZOState *state = lzo_state(s); - if(!LZOState_writeable(state)){ - n = -EINVAL; - goto exit; - } - n = vsnprintf(buf, buf_n, (char*)msg, args); - if(n < 0) goto exit; - if(n > buf_n){ - n = 0; - } else { - n = lzo_write(s, buf, 1, n); - } - exit: - return n; -} - -/** Read a character from the underlying stream - * - * @param s lzo stream - * @return character read, IOSTREAM_EOF on end of file (or error) - */ -static int lzo_getc(IOStream *s){ - int err; - char c; - err = lzo_read(s, &c, 1, 1); - if(err < 1) c = EOF; - err = (c==EOF ? IOSTREAM_EOF : c); - return err; -} - -/** Flush any pending input to the underlying stream. - * - * @param s lzo stream - * @return 0 on success, error code otherwise - */ -static int lzo_flush(IOStream *s){ - int err = 0; - LZOState *state = lzo_state(s); - //dprintf(">\n"); -#ifdef NOCOMPRESS - err = IOStream_flush(state->io); -#else - if(!LZOState_writeable(state)){ - err = -EINVAL; - goto exit; - } - if(state->plain_n){ - err = lzo_compress(state); - if(err < 0) goto exit; - } - err = IOStream_flush(state->io); - exit: - set_error(state, err); -#endif - //dprintf("< err=%d\n", err); - return (err < 0 ? err : 0); -} - -/** Check if a stream has an error. - * - * @param s lzo stream - * @return code if has an error, 0 otherwise - */ -static int lzo_error(IOStream *s){ - int err = 0; - LZOState *state = lzo_state(s); - err = state->error; - if(err) goto exit; - err = IOStream_error(state->io); - exit: - return err; -} - -int lzo_stream_finish(IOStream *s){ - int err = 0; - LZOState *state = lzo_state(s); - if(!LZOState_writeable(state)){ - err = -EINVAL; - goto exit; - } - err = lzo_flush(s); - if(err < 0) goto exit; - err = marshal_int32(state->io, 0); - exit: - return err; -} - -/** Close an lzo stream. - * - * @param s lzo stream to close - * @return result of the close - */ -static int lzo_close(IOStream *s){ - int err = 0; - LZOState *state = lzo_state(s); -#ifdef NOCOMPRESS - err = IOStream_close(state->io); -#else - if(LZOState_writeable(state)){ - err = lzo_stream_finish(s); - } - err = IOStream_close(state->io); - set_error(state, err); -#endif - return err; -} - -/** Free an lzo stream. - * - * @param s lzo stream - */ -static void lzo_free(IOStream *s){ - LZOState *state = lzo_state(s); - IOStream_free(state->io); - LZOState_free(state); - s->data = NULL; -} - -/** Create an lzo stream for an IOStream. - * - * @param io stream to wrap - * @return new IOStream using f for i/o - */ -IOStream *lzo_stream_new(IOStream *io, const char *mode){ - int err = -ENOMEM; - int flags = 0; - IOStream *zio = NULL; - LZOState *state = NULL; - - zio = ALLOCATE(IOStream); - if(!zio) goto exit; - err = mode_flags(mode, &flags); - if(err) goto exit; - state = LZOState_new(io, flags); - if(!state) goto exit; - err = 0; - zio->data = state; - zio->methods = &lzo_methods; - exit: - if(err){ - if(state) LZOState_free(state); - if(zio) deallocate(zio); - zio = NULL; - } - return zio; -} - -/** IOStream version of fdopen(). - * - * @param fd file descriptor - * @param flags giving the mode to open in (as for fdopen()) - * @return new stream for the open file, or NULL if failed - */ -IOStream *lzo_stream_fdopen(int fd, const char *mode){ - int err = -ENOMEM; - IOStream *io = NULL, *zio = NULL; - io = file_stream_fdopen(fd, mode); - if(!io) goto exit; - zio = lzo_stream_new(io, mode); - if(!io) goto exit; - err = 0; - exit: - if(err){ - IOStream_free(io); - IOStream_free(zio); - zio = NULL; - } - return zio; -} -#endif diff --git a/tools/libxutil/lzo_stream.h b/tools/libxutil/lzo_stream.h deleted file mode 100644 index 493da7b1ad..0000000000 --- a/tools/libxutil/lzo_stream.h +++ /dev/null @@ -1,36 +0,0 @@ -#/* $Id: lzo_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */ -/* - * Copyright (C) 2003 Hewlett-Packard Company. - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _SP_LZO_STREAM_H_ -#define _SP_LZO_STREAM_H_ - -#ifndef __KERNEL__ -#include "iostream.h" - -extern IOStream *lzo_stream_new(IOStream *io, const char *mode); -extern IOStream *lzo_stream_fopen(const char *file, const char *mode); -extern IOStream *lzo_stream_fdopen(int fd, const char *mode); -extern IOStream *lzo_stream_io(IOStream *zio); - -extern int lzo_stream_plain_bytes(IOStream *io); -extern int lzo_stream_comp_bytes(IOStream *io); -extern float lzo_stream_ratio(IOStream *io); - -#endif -#endif /* !_SP_FILE_STREAM_H_ */ diff --git a/tools/libxutil/socket_stream.c b/tools/libxutil/socket_stream.c deleted file mode 100644 index cfa6e3abf0..0000000000 --- a/tools/libxutil/socket_stream.c +++ /dev/null @@ -1,259 +0,0 @@ -/* $Id: socket_stream.c,v 1.9 2004/03/05 14:45:34 mjw Exp $ */ -/* - * Copyright (C) 2004 Mike Wray - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/** @file - * An IOStream implementation using sockets. - */ - -#include -#include -#include -#include -#include -#include "allocate.h" -#include "socket_stream.h" - -#define MODULE_NAME "sock" -#define DEBUG 0 -//#undef DEBUG -#include "debug.h" - -static int socket_read(IOStream *s, void *buf, size_t n); -static int socket_write(IOStream *s, const void *buf, size_t n); -static int socket_error(IOStream *s); -static int socket_close(IOStream *s); -static void socket_free(IOStream *s); -static int socket_flush(IOStream *s); - -/** Methods used by a socket IOStream. */ -static const IOMethods socket_methods = { - read: socket_read, - write: socket_write, - error: socket_error, - close: socket_close, - free: socket_free, - flush: socket_flush, -}; - -/** Get the socket data. - * - * @param io socket stream - * @return data - */ -static inline SocketData * socket_data(IOStream *io){ - return (SocketData *)io->data; -} - -/** Test if a stream is a socket stream. - * - * @param io stream - * @return 0 if a socket stream, -EINVAL if not - */ -int socket_stream_check(IOStream *io){ - return (io && io->methods == &socket_methods ? 0 : -EINVAL); -} - -/** Get the data for a socket stream. - * - * @param io stream - * @param data return value for the data - * @return 0 if a socket stream, -EINVAL if not - */ -int socket_stream_data(IOStream *io, SocketData **data){ - int err = socket_stream_check(io); - if(err){ - *data = NULL; - } else { - *data = socket_data(io); - } - return err; -} - -/** Set the destination address for a socket stream. - * - * @param io stream - * @param addr address - * @return 0 if a socket stream, -EINVAL if not - */ -int socket_stream_set_addr(IOStream *io, struct sockaddr_in *addr){ - int err = 0; - SocketData *data = NULL; - err = socket_stream_data(io, &data); - if(!err){ - data->daddr = *addr; - } - return err; -} - -/** Set the send flags for a socket stream. - * - * @param io stream - * @param flags flags - * @return 0 if a socket stream, -EINVAL if not - */ -int socket_stream_set_flags(IOStream *io, int flags){ - int err = 0; - SocketData *data = NULL; - err = socket_stream_data(io, &data); - if(!err){ - data->flags = flags; - } - return err; -} - -/** Write to the underlying socket using sendto. - * - * @param stream input - * @param buf where to put input - * @param n number of bytes to write - * @return number of bytes written - */ -static int socket_write(IOStream *s, const void *buf, size_t n){ - SocketData *data = socket_data(s); - struct sockaddr *daddr = (struct sockaddr *)&data->daddr; - socklen_t daddr_n = sizeof(data->daddr); - int k; - dprintf("> sock=%d addr=%s:%d n=%d\n", - data->fd, inet_ntoa(data->daddr.sin_addr), ntohs(data->daddr.sin_port), n); - if(0){ - struct sockaddr_in self = {}; - socklen_t self_n; - getsockname(data->fd, (struct sockaddr *)&self, &self_n); - dprintf("> sockname sock=%d %s:%d\n", - data->fd, inet_ntoa(self.sin_addr), ntohs(self.sin_port)); - } - k = sendto(data->fd, buf, n, data->flags, daddr, daddr_n); - dprintf("> sendto=%d\n", k); - return k; -} - -/** Read from the underlying stream using recv(); - * - * @param stream input - * @param buf where to put input - * @param n number of bytes to read - * @return number of bytes read - */ -static int socket_read(IOStream *s, void *buf, size_t n){ - SocketData *data = socket_data(s); - int k; - struct sockaddr *saddr = (struct sockaddr *)&data->saddr; - socklen_t saddr_n = sizeof(data->saddr); - k = recvfrom(data->fd, buf, n, data->flags, saddr, &saddr_n); - return k; -} - -/** Print to the underlying socket. - * - * @param s socket stream - * @param msg format to use - * @param args arguments - * @return result of the print - */ -static int socket_print(IOStream *s, const char *msg, va_list args){ - SocketData *data = socket_data(s); - int n; - n = vsnprintf(data->buf, data->buf_n - 1, msg, args); - if(0 < n && n < data->buf_n){ - socket_write(s, data->buf, n); - } - return n; -} - -/** Read a character from the underlying socket - * - * @param s socket stream - * @return character read, IOSTREAM_EOF on end of socket (or error) - */ -static int socket_getc(IOStream *s){ - char b; - int n, c; - n = socket_read(s, &b, 1); - c = (n <= 0 ? IOSTREAM_EOF : b); - return c; -} - -/** Flush the socket (no-op). - * - * @param s socket stream - * @return 0 on success, error code otherwise - */ -static int socket_flush(IOStream *s){ - return 0; -} - -/** Check if a socket stream has an error (no-op). - * - * @param s socket stream - * @return 1 if has an error, 0 otherwise - */ -static int socket_error(IOStream *s){ - // Read SOL_SOCKET/SO_ERROR ? - return 0; -} - -/** Close a socket stream. - * - * @param s socket stream to close - * @return result of the close - */ -static int socket_close(IOStream *s){ - SocketData *data = socket_data(s); - return close(data->fd); -} - -/** Free a socket stream. - * - * @param s socket stream - */ -static void socket_free(IOStream *s){ - SocketData *data = socket_data(s); - deallocate(data); -} - -/** Create an IOStream for a socket. - * - * @param fd socket to wtap - * @return new IOStream using fd for i/o - */ -IOStream *socket_stream_new(int fd){ - int err = -ENOMEM; - IOStream *io = NULL; - SocketData *data = NULL; - - io = ALLOCATE(IOStream); - if(!io) goto exit; - io->methods = &socket_methods; - data = ALLOCATE(SocketData); - if(!data) goto exit; - io->data = data; - data->fd = fd; - data->buf_n = sizeof(data->buf); - err = 0; - exit: - if(err){ - if(io){ - if(data) deallocate(data); - deallocate(io); - io = NULL; - } - } - return io; -} - diff --git a/tools/libxutil/socket_stream.h b/tools/libxutil/socket_stream.h deleted file mode 100644 index 5b8515f6b3..0000000000 --- a/tools/libxutil/socket_stream.h +++ /dev/null @@ -1,54 +0,0 @@ -/* $Id: socket_stream.h,v 1.2 2004/03/04 17:38:13 mjw Exp $ */ -/* - * Copyright (C) 2004 Mike Wray - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _XEN_LIB_SOCKET_STREAM_H_ -#define _XEN_LIB_SOCKET_STREAM_H_ - -#ifndef __KERNEL__ -#include "iostream.h" -#include - -#include -#include -#include - -/** Data associated with a socket stream. */ -typedef struct SocketData { - /** The socket file descriptor. */ - int fd; - /** Source address from last read (recvfrom). */ - struct sockaddr_in saddr; - /** Destination address for writes (sendto). */ - struct sockaddr_in daddr; - /** Write flags (sendto). */ - int flags; - /** Buffer size. */ - int buf_n; - /** Buffer for formatted printing. */ - char buf[1024]; -} SocketData; - -extern IOStream *socket_stream_new(int fd); -extern int socket_stream_data(IOStream *io, SocketData **data); -extern int socket_stream_check(IOStream *io); -extern int socket_stream_set_addr(IOStream *io, struct sockaddr_in *addr); -extern int socket_stream_set_flags(IOStream *io, int flags); - -#endif -#endif /* !_XEN_LIB_SOCKET_STREAM_H_ */ diff --git a/tools/libxutil/string_stream.c b/tools/libxutil/string_stream.c index c3cf423d84..495238d74a 100644 --- a/tools/libxutil/string_stream.c +++ b/tools/libxutil/string_stream.c @@ -25,8 +25,6 @@ #include "string_stream.h" #include "allocate.h" -static int string_print(IOStream *io, const char *msg, va_list args); -static int string_getc(IOStream *io); static int string_error(IOStream *io); static int string_close(IOStream *io); static void string_free(IOStream *io); @@ -49,45 +47,6 @@ static inline StringData *get_string_data(IOStream *io){ return (StringData*)io->data; } -/** Read a character from a string stream. - * - * @param io string stream - * @return character read, IOSTREAM_EOF if no more input - */ -static int string_getc(IOStream *io){ - StringData *data = get_string_data(io); - int c = IOSTREAM_EOF; - char *s = data->in; - - if(s && s < data->end){ - c = (unsigned)*s; - data->in = s+1; - } - return c; -} - -/** Print to a string stream. - * Formats the data to an internal buffer and prints it. - * The formatted data must fit into the internal buffer. - * - * @param io string stream - * @param format print format - * @param args print arguments - * @return result of the print - */ -static int string_print(IOStream *io, const char *msg, va_list args){ - StringData *data = get_string_data(io); - int k = data->end - data->out; - int n = vsnprintf(data->out, k, (char*)msg, args); - if(n < 0 || n > k ){ - n = k; - IOStream_close(io); - } else { - data->out += n; - } - return n; -} - /** Test if a string stream has an error. * * @param io string stream @@ -118,7 +77,7 @@ static int string_close(IOStream *io){ */ static void string_free(IOStream *io){ StringData *data = get_string_data(io); - zero(data, sizeof(*data)); + memzero(data, sizeof(*data)); deallocate(data); } @@ -139,13 +98,13 @@ IOMethods *string_stream_get_methods(void){ */ void string_stream_init(IOStream *io, StringData *data, char *s, int n){ if(data && io){ - zero(data, sizeof(*data)); + memzero(data, sizeof(*data)); data->string = (char*)s; data->in = data->string; data->out = data->string; data->size = n; data->end = data->string + n; - zero(io, sizeof(*io)); + memzero(io, sizeof(*io)); io->methods = &string_methods; io->data = data; } diff --git a/tools/libxutil/string_stream.h b/tools/libxutil/string_stream.h index 36d764b265..b6cbc0f3df 100644 --- a/tools/libxutil/string_stream.h +++ b/tools/libxutil/string_stream.h @@ -1,4 +1,3 @@ -/* $Id: string_stream.h,v 1.1 2003/08/22 14:25:48 mjw Exp $ */ /* * Copyright (C) 2001, 2002 Hewlett-Packard Company. * @@ -17,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _SP_STRING_STREAM_H_ -#define _SP_STRING_STREAM_H_ +#ifndef _XUTIL_STRING_STREAM_H_ +#define _XUTIL_STRING_STREAM_H_ #include "iostream.h" @@ -43,4 +42,4 @@ extern IOMethods *string_stream_get_methods(void); extern IOStream *string_stream_new(char *s, int n); extern void string_stream_init(IOStream *stream, StringData *data, char *s, int n); -#endif /* !_SP_STRING_STREAM_H_ */ +#endif /* !_XUTIL_STRING_STREAM_H_ */ diff --git a/tools/libxutil/sxpr_parser.c b/tools/libxutil/sxpr_parser.c deleted file mode 100644 index 16fec56b67..0000000000 --- a/tools/libxutil/sxpr_parser.c +++ /dev/null @@ -1,897 +0,0 @@ - -#ifdef __KERNEL__ -# include -# include -# include -# include -# include -#else -# include -# include -#endif - -#include "iostream.h" -#include "lexis.h" -#include "sxpr_parser.h" -#include "sys_string.h" - -/** @file - * Sxpr parsing. - * - * So that the parser does not leak memory, all sxprs constructed by - * the parser must be freed on error. On successful parse the sxpr - * returned becomes the responsibility of the caller. - * - * @author Mike Wray - */ - -#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args) -#define printf(fmt, args...) IOStream_print(iostdout, fmt, ##args) - -static void reset(Parser *z); -static int inputchar(Parser *p, char c); -static int savechar(Parser *p, char c); -extern void parse_error(Parser *in); -extern void parse_error_id(Parser *in, ParseErrorId id); - -static int begin_start(Parser *p, char c); -static int state_start(Parser *p, char c); -static int end_start(Parser *p); - -static int begin_comment(Parser *p, char c); -static int state_comment(Parser *p, char c); -static int end_comment(Parser *p); - -static int begin_string(Parser *p, char c); -static int state_string(Parser *p, char c); -static int end_string(Parser *p); -static int state_escape(Parser *p, char c); -static int state_octal(Parser *p, char c); -static int state_hex(Parser *p, char c); - -static int begin_atom(Parser *p, char c); -static int state_atom(Parser *p, char c); -static int end_atom(Parser *p); - -static int state_list(Parser *p, char c); -static int begin_list(Parser *p, char c); -static int end_list(Parser *p); - -/** Print a parse error. - * - * @param in parser - * @param msg format followed by printf arguments - */ -void eprintf(Parser *in, char *msg, ...){ - va_list args; - if(in->error_out){ - va_start(args, msg); - IOStream_vprint(in->error_out, msg, args); - va_end(args); - } -} - -/** Print a parse warning. - * - * @param in parser - * @param msg format followed by printf arguments - */ -void wprintf(Parser *in, char *msg, ...){ - va_list args; - if(in->error_out){ - va_start(args, msg); - IOStream_vprint(in->error_out, msg, args); - va_end(args); - } -} - -/*============================================================================*/ - -/** Record defining the message for a parse error. */ -typedef struct { - ParseErrorId id; - char *message; -} ParseError; - -/** Format for printing parse error messages. */ -#define PARSE_ERR_FMT "parse error> line %3d, column %2d: %s" - -/** Message catalog for the parse error codes. */ -static ParseError catalog[] = { - { PARSE_ERR_UNSPECIFIED, "unspecified error" }, - { PARSE_ERR_NOMEM, "out of memory" }, - { PARSE_ERR_UNEXPECTED_EOF, "unexpected end of input" }, - { PARSE_ERR_TOKEN_TOO_LONG, "token too long" }, - { PARSE_ERR_INVALID_SYNTAX, "syntax error" }, - { PARSE_ERR_INVALID_ESCAPE, "invalid escape" }, - { 0, NULL } -}; - -/** Number of entries in the message catalog. */ -const static int catalog_n = sizeof(catalog)/sizeof(ParseError); - -void ParserState_free(ParserState *z){ - if(!z) return; - objfree(z->val); - deallocate(z); -} - -int ParserState_new(ParserStateFn *fn, ParserState *parent, ParserState **val){ - int err = 0; - ParserState *z; - z = ALLOCATE(ParserState); - if(z){ - z->fn = fn; - z->parent = parent; - z->val = ONULL; - } else { - err = -ENOMEM; - } - if(!err) *val = z; - return err; -} - -/** Free a parser. - * No-op if the parser is null. - * - * @param z parser - */ -void Parser_free(Parser *z){ - if(!z) return; - objfree(z->val); - z->val = ONONE; - deallocate(z); -} - -/** Create a new parser. The error stream defaults to null. - */ -Parser * Parser_new(void){ - Parser *z = ALLOCATE(Parser); - int err = -ENOMEM; - - if(!z) goto exit; - err = 0; - reset(z); - exit: - if(err){ - Parser_free(z); - z = NULL; - } - return z; -} - -/** Get the next character. - * Records the character read in the parser, - * and sets the line and character counts. - * - * @param p parser - * @return error flag: 0 on success, non-zero on error - */ -static int inputchar(Parser *p, char c){ - int err = 0; - if(c=='\n'){ - p->line_no++; - p->char_no = 0; - } else { - p->char_no++; - } - return err; -} - -static int savechar(Parser *p, char c){ - int err = 0; - if(p->buf_i >= p->buf_n){ - err = -ENOMEM; - goto exit; - } - p->buf[p->buf_i] = c; - p->buf_i++; - exit: - return err; -} - -int Parser_input_char(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - //skip; - } else { - inputchar(p, c); - } - if(!p->state){ - err = begin_start(p, c); - if(err) goto exit; - } - err = p->state->fn(p, c); - exit: - return err; -} - -int Parser_input_eof(Parser *p){ - int err = 0; - p->eof = 1; - err = Parser_input_char(p, IOSTREAM_EOF); - return err; -} - -int Parser_input(Parser *p, char *buf, int buf_n){ - int err = 0; - int i = 0; - if(buf_n <= 0){ - err = Parser_input_eof(p); - goto exit; - } - for(i = 0; istate, &p->state); - return err; -} - -int Parser_pop(Parser *p){ - int err = 0; - ParserState *s = p->state; - p->state = s->parent; - ParserState_free(s); - return err; -} - -int Parser_return(Parser *p){ - int err = 0; - Sxpr val = ONONE; - if(!p->state){ - err = -EINVAL; - goto exit; - } - val = p->state->val; - p->state->val = ONONE; - err = Parser_pop(p); - if(err) goto exit; - if(p->state){ - err = cons_push(&p->state->val, val); - } else { - val = nrev(val); - p->val = val; - } - exit: - if(err){ - objfree(val); - } - return err; -} - -/** Determine if a character is a separator. - * - * @param p parser - * @param c character to test - * @return 1 if a separator, 0 otherwise - */ -static int is_separator(Parser *p, char c){ - return in_sep_class(c); -} - -/** Return the current token. - * The return value points at the internal buffer, so - * it must not be modified (or freed). Use copy_token() if you need a copy. - * - * @param p parser - * @return token - */ -char *peek_token(Parser *p){ - return p->buf; -} - -/** Return a copy of the current token. - * The returned value should be freed when finished with. - * - * @param p parser - * @return copy of token - */ -char *copy_token(Parser *p){ - return strdup(peek_token(p)); -} - -static int do_intern(Parser *p){ - int err = 0; - Sxpr obj = intern(peek_token(p)); - if(NOMEMP(obj)){ - err = -ENOMEM; - } else { - p->state->val = obj; - } - return err; -} - -static int do_string(Parser *p){ - int err = 0; - Sxpr obj; - obj = string_new(peek_token(p)); - if(NOMEMP(obj)){ - err = -ENOMEM; - } else { - p->state->val = obj; - } - return err; -} - -void newtoken(Parser *p){ - memset(p->buf, 0, p->buf_n); - p->buf_i = 0; - p->tok_begin_line = p->line_no; - p->tok_begin_char = p->char_no; -} - -int get_escape(char c, char *d){ - int err = 0; - switch(c){ - case 'a': *d = '\a'; break; - case 'b': *d = '\b'; break; - case 'f': *d = '\f'; break; - case 'n': *d = '\n'; break; - case 'r': *d = '\r'; break; - case 't': *d = '\t'; break; - case 'v': *d = '\v'; break; - case c_escape: *d = c_escape; break; - case c_single_quote: *d = c_single_quote; break; - case c_double_quote: *d = c_double_quote; break; - default: - err = -EINVAL; - } - return err; -} - - -int begin_start(Parser *p, char c){ - return Parser_push(p, state_start); -} - -int state_start(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - err = end_start(p); - } else if(in_space_class(c)){ - //skip - } else if(in_comment_class(c)){ - begin_comment(p, c); - } else if(c == c_list_open){ - begin_list(p, c); - } else if(c == c_list_close){ - parse_error(p); - err = -EINVAL; - } else if(in_string_quote_class(c)){ - begin_string(p, c); - } else if(in_printable_class(c)){ - begin_atom(p, c); - } else if(c == 0x04){ - //ctrl-D, EOT: end-of-text. - Parser_input_eof(p); - } else { - parse_error(p); - err = -EINVAL; - } - return err; -} - -int end_start(Parser *p){ - int err = 0; - err = Parser_return(p); - return err; -} - -int begin_comment(Parser *p, char c){ - int err = 0; - err = Parser_push(p, state_comment); - if(err) goto exit; - err = inputchar(p, c); - exit: - return err; -} - -int state_comment(Parser *p, char c){ - int err = 0; - if(c == '\n' || at_eof(p)){ - err = end_comment(p); - } else { - err = inputchar(p, c); - } - return err; -} - -int end_comment(Parser *p){ - return Parser_pop(p); -} - -int begin_string(Parser *p, char c){ - int err = 0; - err = Parser_push(p, state_string); - if(err) goto exit; - newtoken(p); - p->state->delim = c; - exit: - return err; -} - -int state_string(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); - err = -EINVAL; - } else if(c == p->state->delim){ - err = end_string(p); - } else if(c == '\\'){ - err = Parser_push(p, state_escape); - } else { - err = savechar(p, c); - } - return err; -} - -int end_string(Parser *p){ - int err = 0; - err = do_string(p); - if(err) goto exit; - err = Parser_return(p); - exit: - return err; -} - -int state_escape(Parser *p, char c){ - int err = 0; - char d; - if(at_eof(p)){ - parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); - err = -EINVAL; - goto exit; - } - if(get_escape(c, &d) == 0){ - err = savechar(p, d); - if(err) goto exit; - err = Parser_pop(p); - } else if(c == 'x'){ - p->state->fn = state_hex; - p->state->ival = 0; - p->state->count = 0; - } else { - p->state->fn = state_octal; - p->state->ival = 0; - p->state->count = 0; - err = Parser_input_char(p, c); - } - exit: - return err; -} - -int octaldone(Parser *p){ - int err = 0; - char d = (char)(p->state->ival & 0xff); - err = Parser_pop(p); - if(err) goto exit; - err = Parser_input_char(p, d); - exit: - return err; -} - -int octaldigit(Parser *p, char c){ - int err = 0; - p->state->ival *= 8; - p->state->ival += c - '0'; - p->state->count++; - if(err) goto exit; - if(p->state->ival < 0 || p->state->ival > 0xff){ - parse_error(p); - err = -EINVAL; - goto exit; - } - if(p->state->count == 3){ - err = octaldone(p); - } - exit: - return err; -} - -int state_octal(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); - err = -EINVAL; - goto exit; - } else if('0' <= c && c <= '7'){ - err = octaldigit(p, c); - } else { - err = octaldone(p); - if(err) goto exit; - Parser_input_char(p, c); - } - exit: - return err; -} - -int hexdone(Parser *p){ - int err = 0; - char d = (char)(p->state->ival & 0xff); - err = Parser_pop(p); - if(err) goto exit; - err = Parser_input_char(p, d); - exit: - return err; -} - -int hexdigit(Parser *p, char c, char d){ - int err = 0; - p->state->ival *= 16; - p->state->ival += c - d; - p->state->count++; - if(err) goto exit; - if(p->state->ival < 0 || p->state->ival > 0xff){ - parse_error(p); - err = -EINVAL; - goto exit; - } - if(p->state->count == 2){ - err = hexdone(p); - } - exit: - return err; -} - -int state_hex(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); - err = -EINVAL; - goto exit; - } else if('0' <= c && c <= '9'){ - err = hexdigit(p, c, '0'); - } else if('A' <= c && c <= 'F'){ - err = hexdigit(p, c, 'A'); - } else if('a' <= c && c <= 'f'){ - err = hexdigit(p, c, 'a'); - } else if(p->state->count){ - err =hexdone(p); - if(err) goto exit; - Parser_input_char(p, c); - } - exit: - return err; -} - -int begin_atom(Parser *p, char c){ - int err = 0; - err = Parser_push(p, state_atom); - if(err) goto exit; - newtoken(p); - err = savechar(p, c); - exit: - return err; -} - -int state_atom(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - err = end_atom(p); - } else if(is_separator(p, c) || - in_space_class(c) || - in_comment_class(c)){ - err = end_atom(p); - if(err) goto exit; - err = Parser_input_char(p, c); - } else { - err = savechar(p, c); - } - exit: - return err; -} - -int end_atom(Parser *p){ - int err = 0; - err = do_intern(p); - if(err) goto exit; - err = Parser_return(p); - exit: - return err; -} - -int state_list(Parser *p, char c){ - int err = 0; - if(at_eof(p)){ - parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF); - err = -EINVAL; - } else if(c == c_list_close){ - p->state->val = nrev(p->state->val); - err = end_list(p); - } else { - err = state_start(p, c); - } - return err; - -} - -int begin_list(Parser *p, char c){ - return Parser_push(p, state_list); -} - -int end_list(Parser *p){ - return Parser_return(p); -} - -/** Reset the fields of a parser to initial values. - * - * @param z parser - */ -static void reset(Parser *z){ - IOStream *error_out = z->error_out; - int flags = z->flags; - zero(z, sizeof(Parser)); - z->buf_n = sizeof(z->buf) - 1; - z->buf_i = 0; - z->line_no = 1; - z->char_no = 0; - z->error_out = error_out; - z->flags = flags; -} - -/** Set the parser error stream. - * Parse errors are reported on the the error stream if it is non-null. - * - * @param z parser - * @param error_out error stream - */ -void set_error_stream(Parser *z, IOStream *error_out){ - if(z){ - z->error_out = error_out; - } -} - -/** Get the parser error message for an error code. - * - * @param id error code - * @return error message (empty string if the code is unknown) - */ -static char *get_message(ParseErrorId id){ - int i; - for(i=0; iline_no; -} - -/** Get the column number. - * - * @param in parser - */ -int get_column(Parser *in){ - return in->char_no; -} - -/** Get the line number the current token started on. - * - * @param in parser - */ -int get_tok_line(Parser *in){ - return in->tok_begin_line; -} - -/** Get the column number the current token started on. - * - * @param in parser - */ -int get_tok_column(Parser *in){ - return in->tok_begin_char; -} - -/** Report a parse error. - * Does nothing if the error stream is null or there is no error. - * - * @param in parser - */ -static void report_error(Parser *in){ - if(in->error_out && in->err){ - char *msg = get_message(in->err); - char *tok = peek_token(in); - IOStream_print(in->error_out, PARSE_ERR_FMT, - get_tok_line(in), get_tok_column(in), msg); - if(tok && tok[0]){ - IOStream_print(in->error_out, " '%s'", tok); - } - IOStream_print(in->error_out, "\n"); - } -} - -/** Get the error message for the current parse error code. - * Does nothing if there is no error. - * - * @param in parser - * @param buf where to place the message - * @param n maximum number of characters to place in buf - * @return current error code (zero for no error) - */ -int parse_error_message(Parser *in, char *buf, int n){ - if(in->err){ - char *msg = get_message(in->err); - snprintf(buf, n, PARSE_ERR_FMT, get_tok_line(in), get_tok_column(in), msg); - } - return in->err; -} - -/** Flag an unspecified parse error. All subsequent reads will fail. - * - * @param in parser - */ -void parse_error(Parser *in){ - parse_error_id(in, PARSE_ERR_INVALID_SYNTAX); -} - -/** Flag a parse error. All subsequent reads will fail. - * Does not change the parser error code if it is already set. - * - * @param in parser - * @param id error code - */ -void parse_error_id(Parser *in, ParseErrorId id){ - if(!in->err){ - in->err = id; - report_error(in); - } -} - -/** Test if the parser's error flag is set. - * - * @param in parser - * @return 1 if set, 0 otherwise - */ -int has_error(Parser *in){ - return (in->err > 0); -} - -/** Test if the parser is at end of input. - * - * @param in parser - * @return 1 if at EOF, 0 otherwise - */ -int at_eof(Parser *p){ - return p->eof; -} - -#ifdef SXPR_PARSER_MAIN -/* Stuff for standalone testing. */ - -#include "file_stream.h" -#include "string_stream.h" - -int stringof(Sxpr exp, char **s){ - int err = 0; - if(ATOMP(exp)){ - *s = atom_name(exp); - } else if(STRINGP(exp)){ - *s = string_string(exp); - } else { - err = -EINVAL; - *s = NULL; - } - return err; -} - -int child_string(Sxpr exp, Sxpr key, char **s){ - int err = 0; - Sxpr val = sxpr_child_value(exp, key, ONONE); - err = stringof(val, s); - return err; -} - -int intof(Sxpr exp, int *v){ - int err = 0; - char *s; - unsigned long l; - if(INTP(exp)){ - *v = OBJ_INT(exp); - } else { - err = stringof(exp, &s); - if(err) goto exit; - err = convert_atoul(s, &l); - *v = (int)l; - } - exit: - return err; -} - -int child_int(Sxpr exp, Sxpr key, int *v){ - int err = 0; - Sxpr val = sxpr_child_value(exp, key, ONONE); - err = intof(val, v); - return err; -} - -int eval_vnet(Sxpr exp){ - int err = 0; - Sxpr oid = intern("id"); - int id; - err = child_int(exp, oid, &id); - if(err) goto exit; - dprintf("> vnet id=%d\n", id); - exit: - dprintf("< err=%d\n", err); - return err; -} - -int eval_connect(Sxpr exp){ - int err = 0; - Sxpr ovif = intern("vif"); - Sxpr ovnet = intern("vnet"); - char *vif; - int vnet; - - err = child_string(exp, ovif, &vif); - if(err) goto exit; - err = child_int(exp, ovnet, &vnet); - if(err) goto exit; - dprintf("> connect vif=%s vnet=%d\n", vif, vnet); - exit: - dprintf("< err=%d\n", err); - return err; -} - -int eval(Sxpr exp){ - int err = 0; - Sxpr oconnect = intern("connect"); - Sxpr ovnet = intern("vnet"); - - if(sxpr_elementp(exp, ovnet)){ - err = eval_vnet(exp); - } else if(sxpr_elementp(exp, oconnect)){ - err = eval_connect(exp); - } else { - err = -EINVAL; - } - return err; -} - -/** Main program for testing. - * Parses input and prints it. - * - * @param argc number of arguments - * @param argv arguments - * @return error code - */ -int main(int argc, char *argv[]){ - Parser *pin; - int err = 0; - char buf[1024]; - int k; - Sxpr obj, l, x; - - pin = Parser_new(); - set_error_stream(pin, iostdout); - dprintf("> parse...\n"); - while(1){ - k = fread(buf, 1, 1024, stdin); - err = Parser_input(pin, buf, k); - dprintf("> Parser_input=%d\n", err); - if(k <= 0) break; - } - obj = pin->val; - for(l = obj ; CONSP(l); l = CDR(l)){ - x = CAR(l); - objprint(iostdout, x, 0); printf("\n"); - eval(x); - } - dprintf("> err=%d\n", err); - return 0; -} -#endif diff --git a/tools/libxutil/sxpr_parser.h b/tools/libxutil/sxpr_parser.h deleted file mode 100644 index 7296312e44..0000000000 --- a/tools/libxutil/sxpr_parser.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of the - * License, or (at your option) any later version. This library is - * distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _XEN_LIB_SXPR_PARSER_H_ -#define _XEN_LIB_SXPR_PARSER_H_ - -#include "sxpr.h" -#include "iostream.h" - -/** @file - * Sxpr parsing definitions. - */ - -/** Size of a parser input buffer. - * Tokens read must fit into this size (including trailing null). - */ -#define PARSER_BUF_SIZE 1024 - -struct Parser; -typedef int ParserStateFn(struct Parser *, char c); - -typedef struct ParserState { - struct ParserState *parent; - Sxpr val; - int ival; - int count; - char delim; - ParserStateFn *fn; -} ParserState; - -/** Structure representing an input source for the parser. - * Can read from any IOStream implementation. - */ -typedef struct Parser { - Sxpr val; - /** Error reporting stream (null for no reports). */ - IOStream *error_out; - int eof; - /** Error flag. Non-zero if there has been a read error. */ - int err; - /** Line number on input (from 1). */ - int line_no; - /** Column number of input (reset on new line). */ - int char_no; - /** Lookahead character. */ - char c; - /** Buffer for reading tokens. */ - char buf[PARSER_BUF_SIZE]; - /** Size of token buffer. */ - int buf_n; - int buf_i; - /** Line the last token started on. */ - int tok_begin_line; - /** Character number the last token started on. */ - int tok_begin_char; - /** Parsing flags. */ - int flags; - ParserState *state; -} Parser; - -/** Parser error codes. */ -typedef enum { - PARSE_ERR_NONE=0, - PARSE_ERR_UNSPECIFIED, - PARSE_ERR_NOMEM, - PARSE_ERR_UNEXPECTED_EOF, - PARSE_ERR_TOKEN_TOO_LONG, - PARSE_ERR_INVALID_SYNTAX, - PARSE_ERR_INVALID_ESCAPE, -} ParseErrorId; - - -/** Parser flags. */ -//enum { -//}; - -/** Raise some parser flags. - * - * @param in parser - * @param flags flags mask - */ -inline static void parser_flags_raise(Parser *in, int flags){ - in->flags |= flags; -} - -/** Lower some parser flags. - * - * @param in parser - * @param flags flags mask - */ -inline static void parser_flags_lower(Parser *in, int flags){ - in->flags &= ~flags; -} - -/** Clear all parser flags. - * - * @param in parser - */ -inline static void parser_flags_clear(Parser *in){ - in->flags = 0; -} - -extern void Parser_free(Parser *z); -extern Parser * Parser_new(void); -extern int Parser_input(Parser *p, char *buf, int buf_n); -extern int Parser_input_eof(Parser *p); - -extern int parse_error_message(Parser *in, char *buf, int n); -extern int has_error(Parser *in); -extern int at_eof(Parser *in); - -#endif /* ! _XEN_LIB_SXPR_PARSER_H_ */ diff --git a/tools/libxutil/sys_ctype.h b/tools/libxutil/sys_ctype.h deleted file mode 100644 index 1dc6cf2fac..0000000000 --- a/tools/libxutil/sys_ctype.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _XENO_SYS_CTYPE_H_ -#define _XENO_SYS_CTYPE_H_ -/** @file - ** Replacement for ctype include that can be used - * from user or kernel code. - */ -#ifdef __KERNEL__ -# include -#else -# include -#endif -#endif /* ! _XENO_SYS_CTYPE_H_ */ diff --git a/tools/libxutil/sys_net.h b/tools/libxutil/sys_net.h index da6c1e8fd5..61754940f2 100644 --- a/tools/libxutil/sys_net.h +++ b/tools/libxutil/sys_net.h @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _XEN_LIB_SYS_NET_H_ -#define _XEN_LIB_SYS_NET_H_ +#ifndef _XUTIL_SYS_NET_H_ +#define _XUTIL_SYS_NET_H_ /** @file * * Replacement for standard network includes. @@ -72,7 +72,7 @@ extern int inet_aton(const char *address, struct in_addr *inp); extern char *mac_ntoa(const unsigned char *macaddr); extern int mac_aton(const char *addr, unsigned char *macaddr); -#endif /* !_SP_SYS_NET_H_ */ +#endif /* !_XUTIL_SYS_NET_H_ */ diff --git a/tools/libxutil/sys_string.h b/tools/libxutil/sys_string.h index f39935f669..ea60401168 100644 --- a/tools/libxutil/sys_string.h +++ b/tools/libxutil/sys_string.h @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _XEN_LIB_SYS_STRING_H_ -#define _XEN_LIB_SYS_STRING_H_ +#ifndef _XUTIL_SYS_STRING_H_ +#define _XUTIL_SYS_STRING_H_ /** @file * Replacement for standard string includes. * Works in user or kernel code. @@ -88,4 +88,4 @@ static inline size_t strnlen(const char *s, size_t n){ extern int convert_atoul(const char *s, unsigned long *v); extern int path_concat(char *s, char *t, char **val); -#endif /* !_XEN_LIB_SYS_STRING_H_ */ +#endif /* !_XUTIL_SYS_STRING_H_ */ diff --git a/tools/misc/nsplitd/Makefile b/tools/misc/nsplitd/Makefile new file mode 100644 index 0000000000..c5c4c9ed40 --- /dev/null +++ b/tools/misc/nsplitd/Makefile @@ -0,0 +1,22 @@ + +CC = gcc +CFLAGS = -Wall -O3 +CFILES = $(wildcard *.c) + +HDRS = $(wildcard *.h) +OBJS = $(patsubst %.c,%.o,$(wildcard *.c)) + +TARGET = nsplitd + +all: $(TARGET) + +install: all + +clean: + $(RM) *.o $(TARGET) *~ + +$(TARGET): $(OBJS) + $(CC) $(CFLAGS) -o $@ $^ + +%.o: %.c $(HDRS) Makefile + $(CC) $(CFLAGS) -c -o $@ $< diff --git a/tools/misc/nsplitd/nsplitd.c b/tools/misc/nsplitd/nsplitd.c new file mode 100644 index 0000000000..48fbd65103 --- /dev/null +++ b/tools/misc/nsplitd/nsplitd.c @@ -0,0 +1,686 @@ +/* + * nsplitd.c + * --------- + * + * $Id: nsplitd.c,v 2.6 1998/09/17 14:28:37 sde1000 Exp $ + * + * Copyright (c) 1995, University of Cambridge Computer Laboratory, + * Copyright (c) 1995, Richard Black, All Rights Reserved. + * + * + * A complete re-implementation of DME's nsplitd for use from inetd + * + */ + +/* The basic stream comes in (via inetd) and we then conenct to + * somewhere else providing a loop-through service, except we offer + * two other ports for connection - one of which gets a second channel + * using the top bit to distinguish, and the other is a master control + * port (normally used for gdb) which gets complete exclusive access + * for its duration. + * + * Originally designed for multiplexing a xwcons/telnet with a gdb + * post-mortem debugging session. + * + * Here is a picture: + * + * port0 (from inetd) + * 8-bit connection / + * made by us <----> nsplitd <-----gdbport (default port0+2) + * to host:port/tcp |\ + * | port1 (default port0+1) + * \ + * control (default port0+3) + * + * If port1 is explicitly disabled (through a command-line option) then + * port0 becomes 8-bit clean. + */ + +/* + * N.B.: We do NOT support 8 bit stdin/stdout usage on a + * /dev/... because to do that right involves much messing with ioctl + * and TIOC... etc. If you want to do that sort of thing then the + * right way to do it is to chain this onto wconsd (which does know + * about and understand all the ioctl and TIOC grief). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef LOG_DAEMON +#define LOG_DAEMON 0 +#endif + +#define DB(x) /* ((x), fflush(stderr)) */ + +extern char *optarg; + +extern int optind, opterr, optopt; + +static char *prog_name; + +static void usage(void) +{ + fprintf(stderr, "This program (%s) should be run via inetd (tcp)\n\n", + prog_name); + fprintf(stderr, "usage: %s [-h][-g]" + "[-c][-8] host:service\n", + prog_name); + exit(1); +} + +static void fault(char *format, ...) +{ + va_list ap; + char logbuf[1024]; + + va_start(ap, format); + fprintf(stderr, "%s: ", prog_name); + vfprintf(stderr, format, ap); + fflush(stderr); + va_end(ap); + + /* XXX This is a bit dubious, but there is no vsyslog */ + va_start(ap, format); + vsprintf(logbuf, format, ap); + syslog(LOG_ERR, logbuf); + va_end(ap); + exit(1); +} + +static int getservice(char *name, unsigned short *port) +{ + struct servent *se; + + if (!name) return -1; + + if (isdigit(name[0])) + *port = atoi(name); + else + { + if (!(se = getservbyname(name, "tcp"))) + return -1; + *port = ntohs(se->s_port); + } + return 0; +} + +/* + * connect_host: connect to ("name", "port") + */ +static int connect_host (char *name, unsigned int port) +{ + int fd; + struct hostent *hostent; + struct sockaddr_in sin; + int on; + + if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) + fault("socket"); + + if (!(hostent = gethostbyname(name))) + fault("gethostbyname: %s: %s\n", name, strerror(errno)); + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons (port); + memcpy(&sin.sin_addr.s_addr, hostent->h_addr, sizeof(struct in_addr)); + + if (connect(fd, (struct sockaddr *) &sin, sizeof (sin)) < 0) + fault("connect: %s:%u: %s\n", name, port, strerror(errno)); + + on = 1; + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0) + syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m"); + + on = 1; + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) + syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); + + return fd; +} + +/* + * open a tcp socket and start listening for connections on it + */ +static int startlistening(unsigned short port) +{ + int fd, on; + struct sockaddr_in sin; + + if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) + fault("socket"); + + on = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) + syslog(LOG_WARNING, "setsockopt (SO_REUSEADDR): %m"); + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons (port); + sin.sin_addr.s_addr = INADDR_ANY; + if (bind(fd, &sin, sizeof(sin)) < 0) + fault("bind: %u: %s\n", port, strerror(errno)); + + if (listen(fd, 1) < 0) + fault("listen: %s\n", strerror(errno)); + + return fd; +} + +static void noblock(int fd) +{ + int on=1; + + if (ioctl(fd, FIONBIO, &on) < 0) + fault("ioctl: FIONBIO: %s\n", strerror(errno)); +} + + +/* You might not believe this, but fd_sets don't have to be a 32-bit + * integer. In particular, in glibc2 it is an array of unsigned + * longs. Hence, this hacked up FD_SET_rjb() that works out if it + * would have been a nop. */ +#define FD_SET_rjb(fd, setp) \ +do { \ + if ((fd) != 32) \ + FD_SET((fd), (setp)); \ +} while(0) + +#define FD_ISSET_rjb(fd, setp) (((fd) != 32)? FD_ISSET((fd), (setp)) : 0) + +#define MAXSIZE 256 + +/* ----------------------------------------------------------------- + * The main bit of the algorithm. Note we use 32 to mean not connected + * because this gives us 1<<32 == 0. We could have done this one + * character at a time, but that would have been very inefficient and + * not the unix way. */ +static int debug; + +static void doit(int actl, int acto, int lish, int lisg, int lisc) +{ + int acth, actg, actc; + int gdbmode = FALSE; + char gibuf[MAXSIZE], oibuf[MAXSIZE]; + char libuf[MAXSIZE], lobuf[MAXSIZE]; + char hibuf[MAXSIZE], hobuf[MAXSIZE]; + char ctlbuf[MAXSIZE]; + fd_set rdfs, wrfs, exfs; + int gicc, oicc, licc, locc, hicc, hocc, ctlcc; + char *giptr, *oiptr, *liptr, *loptr, *hiptr, *hoptr; + int rc, fromlen; + struct sockaddr_in from; + + gicc = oicc = licc = locc = hicc = hocc = ctlcc = 0; + acth = actg = actc = 32; /* XXX yummy */ + + noblock(actl); + noblock(acto); + + for(;;) + { + FD_ZERO(&rdfs); + FD_ZERO(&wrfs); + FD_ZERO(&exfs); + + /* always take input from the control port (if it's connected) */ + FD_SET_rjb(actc, &rdfs); + + if (gdbmode) + { + if (oicc) + FD_SET_rjb(actg, &wrfs); + else + FD_SET_rjb(acto, &rdfs); + + if (gicc) + FD_SET_rjb(acto, &wrfs); + else + FD_SET_rjb(actg, &rdfs); + } + else + { + /* There is no such thing as oibuf because its been split into + * lobuf and hobuf + */ + if (locc || hocc) + { + if (locc) + FD_SET_rjb(actl, &wrfs); + if (hocc) + FD_SET_rjb(acth, &wrfs); + } + else + FD_SET_rjb(acto, &rdfs); + + if (licc) + FD_SET_rjb(acto, &wrfs); + else + FD_SET_rjb(actl, &rdfs); + + if (hicc) + FD_SET_rjb(acto, &wrfs); + else + FD_SET_rjb(acth, &rdfs); + } + + if (acth == 32 && lish>=0) FD_SET_rjb(lish, &rdfs); + if (actg == 32) FD_SET_rjb(lisg, &rdfs); + if (actc == 32) FD_SET_rjb(lisc, &rdfs); + + /* now make exfs the union of the read and write fd sets, plus + * "actl" */ + { + int i; + exfs = rdfs; + for(i=0; i<32; i++) /* XXX we only copy fd numbers up to 31 */ + if (FD_ISSET(i, &wrfs)) + FD_SET_rjb(i, &exfs); + FD_SET_rjb(actl, &exfs); + } + + /* XXX AND: can't print something of type fd_set as %x - it + * might be an array */ + DB(fprintf(stderr, "%s: before select: %08x %08x %08x\n", + prog_name, rdfs, wrfs, exfs)); + + if (select(32, &rdfs, &wrfs, &exfs, NULL) < 0) + fault("select: %s\n", strerror(errno)); + + DB(fprintf(stderr, "%s: after select: %08x %08x %08x\n", + prog_name, rdfs, wrfs, exfs)); + + /* XXX it appears that a non-blocking socket may not show up + * correctly in exfs but instead goes readable with no data in + * it. Thus we check for zero and goto the appropriate close + * method. */ + + /* Deal with exceptions */ + if (FD_ISSET_rjb(actg, &exfs)) + { + exfs_actg: + close(actg); + gdbmode = FALSE; + oicc = 0; + oiptr = oibuf; + actg = 32; + continue; /* because assumptions changed */ + } + if (FD_ISSET_rjb(acth, &exfs)) + { + exfs_acth: + close(acth); + hicc = hocc = 0; + hiptr = hibuf; + hoptr = hibuf; + acth = 32; + continue; /* because assumptions changed */ + } + if (FD_ISSET_rjb(actl, &exfs) || + FD_ISSET_rjb(acto, &exfs)) + { + exfs_actl: + exfs_acto: + /* Thats all folks ... */ + break; + } + if (FD_ISSET_rjb(actc, &exfs)) + { + exfs_ctl: + close(actc); + actc = 32; + ctlcc = 0; + continue; + } + + /* Deal with reading */ + if (FD_ISSET_rjb(acto, &rdfs)) + { + if ((oicc = read(acto, oiptr = oibuf, MAXSIZE)) < 0) + fault("read acto: %d: %s\n", oicc, strerror(errno)); + if (!oicc) goto exfs_acto; + + if (!gdbmode) + { + int t; + + assert((locc == 0) && (hocc == 0)); + loptr = lobuf; + hoptr = hobuf; + + if (lish>=0) { + for(t=0; t=0 && (FD_ISSET_rjb(lish, &rdfs))) + { + fromlen = sizeof(from); + if ((acth = accept(lish, &from, &fromlen)) < 0) + { + syslog(LOG_WARNING, "accept: %m"); + acth = 32; + } + else + { + noblock(acth); + hicc = hocc = 0; + syslog(LOG_INFO, "highbit client peer is %s:%u\n", + inet_ntoa(from.sin_addr), ntohs(from.sin_port)); + } + } + + if ((actg == 32) && (FD_ISSET_rjb(lisg, &rdfs))) + { + fromlen = sizeof(from); + if ((actg = accept(lisg, &from, &fromlen)) < 0) + { + syslog(LOG_WARNING, "accept: %m"); + actg = 32; + } + else + { + noblock(actg); + gicc = 0; + gdbmode = TRUE; + syslog(LOG_INFO, "gdb client peer is %s:%u\n", + inet_ntoa(from.sin_addr), ntohs(from.sin_port)); + } + } + + if ((actc == 32) && (FD_ISSET_rjb(lisc, &rdfs))) + { + fromlen = sizeof(from); + if ((actc = accept(lisc, &from, &fromlen)) < 0) + { + syslog(LOG_WARNING, "accept (ctl): %m"); + actc = 32; + } + else + { + noblock(actc); + syslog(LOG_INFO, "ctl client peer is %s:%u\n", + inet_ntoa(from.sin_addr), ntohs(from.sin_port)); + } + } + + /* Back to top of loop */ + } + + /* We are bailing because one of the primary connections has gone + * away. We close these all explicitly here because that way the + * timeout on reusing the port numbers is smnaller. */ + + close(acth); + close(actg); + /* XXX AND: why are we closing all these "character counts" ?? */ + close(gicc); + close(oicc); + close(licc); + close(locc); + close(hicc); + close(hocc); +} + +/* + * ------------------------------------------------------------ + */ +int main(int argc, char **argv) +{ + /* In general, suffix "l" is low channel, "h" is high channel, "g" + * is gdb channel, "c" is control channel and "o" is output channel. + */ + struct sockaddr_in from; + int infd = 0, outfd; + unsigned short portl, porth, portg, portc, porto; + int on = 1, c; + char *outname, *outservice; + int fromlen; + int lish, lisg, lisc; +#if 0 + FILE *newerr; +#endif /* 0 */ + + prog_name = argv[0]; + + if (isatty(infd)) + usage(); + + /* Here, then not just a simple idiot. */ + + signal(SIGPIPE, SIG_IGN); + + openlog(prog_name, LOG_PID, LOG_DAEMON); + + fromlen = sizeof(from); + if (getsockname(infd, &from, &fromlen) < 0) + fault("getsockname: %s", strerror(errno)); + if ((fromlen != sizeof(from)) || (from.sin_family != AF_INET)) + fault("not an inet socket (family=%d)\n", from.sin_family); + + portl = ntohs(from.sin_port); + porth = portl+1; + portg = porth+1; + portc = portg+1; + + fromlen = sizeof(from); + if (getpeername(infd, &from, &fromlen) < 0) + fault("getpeername: %s", strerror(errno)); + if ((fromlen != sizeof(from)) || (from.sin_family != AF_INET)) + fault("not an inet socket (family=%d)\n", from.sin_family); + + syslog(LOG_INFO, "on port %u peer is %s:%u\n", portl, + inet_ntoa(from.sin_addr), ntohs(from.sin_port)); + + if (setsockopt(infd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) + syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); + + /* from here on, we map stderr to output on the connection so we can + * report errors to the remote user. + */ +#if 0 + if (!(newerr = fdopen(infd, "w"))) + syslog(LOG_WARNING, "fdopen: %m"); + else + *stderr = *newerr; +#endif + + while((c = getopt(argc, argv, "d8h:g:c:")) != EOF) + { + switch(c) + { + case 'd': + debug++; + break; + + case 'h': + /* high bit port */ + if (getservice(optarg, &porth) < 0) + fault("getservice failed (high port '%s')\n", optarg); + break; + + case 'g': + /* gdb port */ + if (getservice(optarg, &portg) < 0) + fault("getservice failed (gdb port '%s')\n", optarg); + break; + + case 'c': + /* control port */ + if (getservice(optarg, &portc) < 0) + fault("getservice failed (control port '%s')\n", optarg); + break; + + case '8': + /* 8-bit clean; no high port */ + porth=0; + break; + + default: + fault("bad argument list!\n"); + } + } + + if (argc != optind + 1) + fault("unparsed arguments (%d!=%d)\n", argc, optind+1); + + outname = argv[optind]; + if (!(outservice = strchr(outname, ':'))) + fault("output arg '%s' doesn't contain ':'\n", outname); + *outservice++ = 0; + if (getservice(outservice, &porto) < 0) + fault("getservice failed (output port '%s')\n", outservice); + + /* Time to start the sockets */ + + if (porth) { + lish = startlistening(porth); + } else { + lish = -1; + } + lisg = startlistening(portg); + lisc = startlistening(portc); + + outfd = connect_host(outname, porto); + + doit(infd, outfd, lish, lisg, lisc); + + syslog(LOG_INFO, "terminating normally\n"); + + fclose(stderr); + + closelog(); + exit(0); +} + +/* End $Id: nsplitd.c,v 2.6 1998/09/17 14:28:37 sde1000 Exp $ */ diff --git a/tools/python/xen/util/ip.py b/tools/python/xen/util/ip.py index 8396e0d014..39eb01f944 100644 --- a/tools/python/xen/util/ip.py +++ b/tools/python/xen/util/ip.py @@ -3,7 +3,7 @@ import re import socket import struct -def readlines(fd): +def _readlines(fd): """Version of readlines safe against EINTR. """ import errno @@ -21,7 +21,7 @@ def readlines(fd): lines.append(line) return lines -def readline(fd): +def _readline(fd): """Version of readline safe against EINTR. """ while 1: @@ -42,11 +42,14 @@ as it may have been moved onto the bridge. NBE_BRIDGE = 'nbe-br' def get_current_ipaddr(dev='eth0'): - """Return a string containing the primary IP address for the given - network interface (default 'eth0'). + """Get the primary IP address for the given network interface. + + dev network interface (default eth0) + + returns interface address as a string """ fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' ) - lines = readlines(fd) + lines = _readlines(fd) for line in lines: m = re.search( '^\s+inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*', line ) @@ -57,11 +60,14 @@ def get_current_ipaddr(dev='eth0'): return None def get_current_ipmask(dev='eth0'): - """Return a string containing the primary IP netmask for the given - network interface (default 'eth0'). + """Get the primary IP netmask for a network interface. + + dev network interface (default eth0) + + returns interface netmask as a string """ fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' ) - lines = readlines(fd) + lines = _readlines(fd) for line in lines: m = re.search( '^.+Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*', line ) @@ -72,11 +78,14 @@ def get_current_ipmask(dev='eth0'): return None def get_current_ipgw(dev='eth0'): - """Return a string containing the IP gateway for the given - network interface (default 'eth0'). + """Get the IP gateway for a network interface. + + dev network interface (default eth0) + + returns gateway address as a string """ fd = os.popen( '/sbin/route -n' ) - lines = readlines(fd) + lines = _readlines(fd) for line in lines: m = re.search( '^\S+\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' + '\s+\S+\s+\S*G.*' + dev + '.*', line ) @@ -88,24 +97,46 @@ def get_current_ipgw(dev='eth0'): def inet_aton(addr): """Convert an IP addr in IPv4 dot notation into an int. + + addr IP address as a string + + returns integer """ b = socket.inet_aton(addr) return struct.unpack('!I', b)[0] def inet_ntoa(n): """Convert an int into an IP addr in IPv4 dot notation. + + n IP address + + returns string """ b = struct.pack('!I', n) return socket.inet_ntoa(b) def add_offset_to_ip(addr, offset): """Add a numerical offset to an IP addr in IPv4 dot notation. + + addr IP address + offset offset to add + + returns new address """ n = inet_aton(addr) n += offset return inet_ntoa(n) def check_subnet( ip, network, netmask ): + """Check if an IP address is in the subnet defined by + a network address and mask'. + + ip IP adress + network network address + netmask network mask + + returns 1 if it is in the subnet, 0 if not + """ n_ip = inet_aton(ip) n_net = inet_aton(network) n_mask = inet_aton(netmask) diff --git a/tools/python/xen/xend/Args.py b/tools/python/xen/xend/Args.py index 527e841d3d..31bc067d07 100644 --- a/tools/python/xen/xend/Args.py +++ b/tools/python/xen/xend/Args.py @@ -1,3 +1,4 @@ +import types import sxp class ArgError(StandardError): diff --git a/tools/python/xen/xend/XendClient.py b/tools/python/xen/xend/XendClient.py index e8d62fbc55..b09412894b 100644 --- a/tools/python/xen/xend/XendClient.py +++ b/tools/python/xen/xend/XendClient.py @@ -1,6 +1,11 @@ # Copyright (C) 2004 Mike Wray """Client API for the HTTP interface on xend. Callable as a script - see main(). + +This API is the 'control-plane' for xend. +The 'data-plane' is done separately. For example, consoles +are accessed via sockets on xend, but the list of consoles +is accessible via this API. """ import sys import httplib @@ -27,6 +32,8 @@ class Foo(httplib.HTTPResponse): def sxprio(sxpr): + """Convert an sxpr to a string. + """ io = StringIO() sxp.show(sxpr, out=io) print >> io @@ -80,6 +87,12 @@ def eventurl(location, root, id=''): return urljoin(location, root, 'event/', id) def xend_request(url, method, data=None): + """Make a request to xend. + + url xend request url + method http method: POST or GET + data request argument data (dict) + """ urlinfo = urlparse.urlparse(url) (uproto, ulocation, upath, uparam, uquery, ufrag) = urlinfo if DEBUG: print url, urlinfo @@ -122,20 +135,37 @@ def xend_request(url, method, data=None): return val def xend_get(url, args=None): + """Make a xend request using GET. + Requests using GET are 'safe' and may be repeated without + nasty side-effects. + """ return xend_request(url, "GET", args) def xend_call(url, data): + """Make xend request using POST. + Requests using POST potentially cause side-effects and should + not be repeated unless it really is wanted to do the side + effect again. + """ return xend_request(url, "POST", data) class Xend: + """Default location of the xend server.""" SRV_DEFAULT = "localhost:8000" + + """Default path to the xend root on the server.""" ROOT_DEFAULT = "/xend/" def __init__(self, srv=None, root=None): self.bind(srv, root) def bind(self, srv=None, root=None): + """Bind to a given server. + + srv server location (host:port) + root server xend root path + """ if srv is None: srv = self.SRV_DEFAULT if root is None: root = self.ROOT_DEFAULT if not root.endswith('/'): root += '/' @@ -200,9 +230,10 @@ class Xend: return xend_call(self.domainurl(id), {'op' : 'pause'}) - def xend_domain_shutdown(self, id): + def xend_domain_shutdown(self, id, reason): return xend_call(self.domainurl(id), - {'op' : 'shutdown'}) + {'op' : 'shutdown', + 'reason' : reason }) def xend_domain_destroy(self, id): return xend_call(self.domainurl(id), diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index d75405861a..12362f381d 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -5,8 +5,11 @@ Needs to be persistent for one uptime. """ import sys +import traceback from twisted.internet import defer +defer.Deferred.debug = 1 +from twisted.internet import reactor import xen.lowlevel.xc; xc = xen.lowlevel.xc.new() @@ -28,10 +31,19 @@ __all__ = [ "XendDomain" ] class XendDomain: """Index of all domains. Singleton. """ - + + """Path to domain database.""" dbpath = "domain" + + """Table of domain info indexed by domain id.""" domain = {} + """Table of configs for domain restart, indexed by domain id.""" + restarts = {} + + """Table of delayed calls.""" + schedule = {} + def __init__(self): self.xconsole = XendConsole.instance() # Table of domain info indexed by domain id. @@ -49,6 +61,53 @@ class XendDomain: print 'XendDomain> virq', val self.reap() + def schedule_later(self, _delay, _name, _fn, *args): + """Schedule a function to be called later (if not already scheduled). + + _delay delay in seconds + _name schedule name + _fn function + args arguments + """ + if self.schedule.get(_name): return + self.schedule[_name] = reactor.callLater(_delay, _fn, *args) + + def schedule_cancel(self, name): + """Cancel a scheduled function call. + + name schedule name to cancel + """ + callid = self.schedule.get(name) + if not callid: + return + if callid.active(): + callid.cancel() + del self.schedule[name] + + def reap_schedule(self, delay=0): + """Schedule reap to be called later. + + delay delay in seconds + """ + self.schedule_later(delay, 'reap', self.reap) + + def reap_cancel(self): + """Cancel any scheduled reap. + """ + self.schedule_cancel('reap') + + def refresh_schedule(self, delay=0): + """Schedule refresh to be called later. + + delay delay in seconds + """ + self.schedule_later(delay, 'refresh', self.refresh) + + def refresh_cancel(self): + """Cancel any scheduled refresh. + """ + self.schedule_cancel('refresh') + def rm_all(self): """Remove all domain info. Used after reboot. """ @@ -145,6 +204,7 @@ class XendDomain: """Look for domains that have crashed or stopped. Tidy them up. """ + self.reap_cancel() print 'XendDomain>reap>' domlist = xc.domain_getinfo() casualties = [] @@ -158,12 +218,14 @@ class XendDomain: for d in casualties: id = str(d['dom']) print 'XendDomain>reap> died id=', id, d - self.domain_destroy(id, refresh=0) + self.final_domain_destroy(id) print 'XendDomain>reap<' def refresh(self): """Refresh domain list from Xen. """ + self.refresh_cancel() + print 'XendDomain>refresh>' domlist = xc.domain_getinfo() # Index the domlist by id. # Add entries for any domains we don't know about. @@ -184,7 +246,7 @@ class XendDomain: d.update(dominfo) else: self._delete_domain(d.id) - self.reap() + self.reap_schedule(1) def refresh_domain(self, id): """Refresh information for a single domain. @@ -267,21 +329,70 @@ class XendDomain: """Shutdown domain (nicely). id domain id - reason shutdown type: poweroff, reboot, halt + reason shutdown type: poweroff, reboot, suspend, halt """ dom = int(id) if dom <= 0: return 0 + self.domain_restart_schedule(id, reason) eserver.inject('xend.domain.shutdown', [id, reason]) + if reason == 'halt': + reason = 'poweroff' val = xend.domain_shutdown(dom, reason) - self.refresh() + self.refresh_schedule() return val - - def domain_destroy(self, id, refresh=1): - """Terminate domain immediately. + + def domain_restart_schedule(self, id, reason): + """Schedule a restart for a domain if it needs one. + + id domain id + reason shutdown reason + """ + if id in self.restarts: + # Don't schedule if already there. + return + restart = 0 + if reason in ['poweroff', 'reboot']: + dominfo = self.domain.get(id) + if dominfo and (dominfo.autorestart or reason == 'reboot'): + restart = 1 + # Clear autorestart flag to avoid multiple restarts. + dominfo.autorestart = 0 + + if restart: + self.restarts[id] = dominfo.config + + def domain_restart_cancel(self, id): + """Cancel any restart scheduled for a domain. + + id domain id + """ + dominfo = self.domain.get(id) + if dominfo: + dominfo.autorestart = 0 + if id in self.restarts: + del self.restarts[id] + + def domain_restarts(self): + """Execute any scheduled domain restarts for domains that have gone. + """ + for id in self.restarts.keys(): + if id in self.domain: + # Don't execute restart for domains still running. + continue + config = self.restarts[id] + # Remove it from the restarts. + del self.restarts[id] + try: + self.domain_create(config) + except: + print >>sys.stderr, "XendDomain> Exception restarting domain" + traceback.print_exc(sys.stderr) + + def final_domain_destroy(self, id): + """Final destruction of a domain.. id domain id - refresh send a domain destroy event if true """ dom = int(id) if dom <= 0: @@ -292,15 +403,26 @@ class XendDomain: val = dominfo.destroy() else: val = xc.domain_destroy(dom=dom) - if refresh: self.refresh() return val + def domain_destroy(self, id): + """Terminate domain immediately. + Camcels any restart for the domain. + + id domain id + """ + self.domain_restart_cancel(id) + val = self.final_domain_destroy(id) + self.refresh_schedule() + return val + def domain_migrate(self, id, dst): """Start domain migration. id domain id """ # Need a cancel too? + # Don't forget to cancel restart for it. pass def domain_save(self, id, dst, progress=0): diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index c43dcfe892..619d575466 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -9,11 +9,13 @@ Author: Mike Wray """ import string +import types import re import sys import os from twisted.internet import defer +defer.Deferred.debug = 1 import xen.lowlevel.xc; xc = xen.lowlevel.xc.new() import xen.util.ip @@ -78,8 +80,13 @@ def lookup_raw_partn(partition): if not re.match( '/dev/', partition ): partition = '/dev/' + partition - - drive = re.split( '[0-9]', partition )[0] + + """Try and match non-standard scsi raid arraysa + """ + if re.match( '/dev/cciss/c[0-9]+d[0-9]+p[0-9]+', partition ): + drive = re.split( 'p[0-9]+', partition )[0] + else: + drive = re.split( '[0-9]', partition )[0] if drive == partition: fd = os.popen( '/sbin/sfdisk -s ' + drive + ' 2>/dev/null' ) @@ -283,7 +290,7 @@ def vm_restore(src, progress=0): d = restorefn(state_file=src, progress=progress) dom = int(d['dom']) if dom < 0: - raise VMError('restore failed') + raise VmError('restore failed') vmconfig = sxp.from_string(d['vmconfig']) vm.config = sxp.child_value(vmconfig, 'config') deferred = vm.dom_configure(dom) @@ -356,6 +363,8 @@ class XendDomainInfo: self.state = self.STATE_OK #todo: set to migrate info if migrating self.migrate = None + #Whether to auto-restart + self.autorestart = 0 def setdom(self, dom): self.dom = int(dom) @@ -412,6 +421,8 @@ class XendDomainInfo: try: self.name = sxp.child_value(config, 'name') self.memory = int(sxp.child_value(config, 'memory', '128')) + if sxp.child(config, 'autorestart', None): + self.autorestart = 1 self.configure_backends() image = sxp.child_value(config, 'image') image_name = sxp.name(image) @@ -420,14 +431,18 @@ class XendDomainInfo: raise VmError('unknown image type: ' + image_name) image_handler(self, image) deferred = self.configure() + def cbok(x): + print 'vm_create> cbok', x + return x + def cberr(err): + self.destroy() + return err + deferred.addCallback(cbok) + deferred.addErrback(cberr) except StandardError, ex: # Catch errors, cleanup and re-raise. self.destroy() raise - def cbok(x): - print 'vm_create> cbok', x - return x - deferred.addCallback(cbok) print 'vm_create<' return deferred @@ -503,6 +518,9 @@ class XendDomainInfo: devices have been released. """ if self.dom is None: return 0 + chan = xend.getDomChannel(self.dom) + if chan: + chan.close() return xc.domain_destroy(dom=self.dom) def cleanup(self): @@ -611,7 +629,7 @@ class XendDomainInfo: if not os.path.isfile(kernel): raise VmError('Kernel image does not exist: %s' % kernel) if ramdisk and not os.path.isfile(ramdisk): - raise VMError('Kernel ramdisk does not exist: %s' % ramdisk) + raise VmError('Kernel ramdisk does not exist: %s' % ramdisk) print 'create-domain> init_domain...' self.init_domain() print 'create_domain>', 'dom=', self.dom @@ -691,12 +709,16 @@ class XendDomainInfo: """ d = dom_get(dom) if not d: - raise VMError("Domain not found: %d" % dom) + raise VmError("Domain not found: %d" % dom) try: self.setdom(dom) self.name = d['name'] self.memory = d['memory']/1024 deferred = self.configure() + def cberr(err): + self.destroy() + return err + deferred.addErrback(cberr) except StandardError, ex: self.destroy() raise @@ -807,10 +829,10 @@ def vm_dev_vbd(vm, val, index): vdev = index uname = sxp.child_value(val, 'uname') if not uname: - raise VMError('vbd: Missing uname') + raise VmError('vbd: Missing uname') dev = sxp.child_value(val, 'dev') if not dev: - raise VMError('vbd: Missing dev') + raise VmError('vbd: Missing dev') mode = sxp.child_value(val, 'mode', 'r') defer = make_disk(vm.dom, uname, dev, mode, vm.recreate) def fn(vbd): @@ -821,7 +843,7 @@ def vm_dev_vbd(vm, val, index): return defer def parse_pci(val): - if isinstance(val, StringType): + if isinstance(val, types.StringType): radix = 10 if val.startswith('0x') or val.startswith('0X'): radix = 16 @@ -833,24 +855,24 @@ def parse_pci(val): def vm_dev_pci(vm, val, index): bus = sxp.child_value(val, 'bus') if not bus: - raise VMError('pci: Missing bus') + raise VmError('pci: Missing bus') dev = sxp.child_value(val, 'dev') if not dev: - raise VMError('pci: Missing dev') + raise VmError('pci: Missing dev') func = sxp.child_value(val, 'func') if not func: - raise VMError('pci: Missing func') + raise VmError('pci: Missing func') try: bus = parse_pci(bus) dev = parse_pci(dev) func = parse_pci(func) except: - raise VMError('pci: invalid parameter') + raise VmError('pci: invalid parameter') rc = xc.physdev_pci_access_modify(dom=vm.dom, bus=bus, dev=dev, func=func, enable=1) if rc < 0: #todo non-fatal - raise VMError('pci: Failed to configure device: bus=%s dev=%s func=%s' % + raise VmError('pci: Failed to configure device: bus=%s dev=%s func=%s' % (bus, dev, func)) return rc diff --git a/tools/python/xen/xend/XendMigrate.py b/tools/python/xen/xend/XendMigrate.py index 1580ba83ed..a598913792 100644 --- a/tools/python/xen/xend/XendMigrate.py +++ b/tools/python/xen/xend/XendMigrate.py @@ -2,22 +2,125 @@ import sys import socket +import time + +from twisted.internet import reactor +from twisted.internet import defer +defer.Deferred.debug = 1 +from twisted.internet.protocol import Protocol +from twisted.internet.protocol import ClientFactory import sxp import XendDB import EventServer; eserver = EventServer.instance() +from xen.xend.packing import SxpPacker, SxpUnpacker +from xen.xend import XendDomain +xd = XendDomain.instance() + + +XFRD_PORT = 8002 + +XFR_PROTO_MAJOR = 1 +XFR_PROTO_MINOR = 0 + +class Migrate(Protocol): + + def __init__(self, minfo): + self.packer = None + self.unpacker = None + self.minfo = minfo + + def connectionMade(self): + self.packer = SxpPacker(self.transport) + self.unpacker = SxpPacker() + # Send hello. + self.packer.pack(['xfr.hello', XFR_PROTO_MAJOR, XFR_PROTO_MINOR]) + # Send migrate. + vmconfig = self.minfo.vmconfig() + if not vmconfig: + self.loseConnection() + return + self.packer.pack(['xfr.migrate', + self.minfo.src_dom, + vmconfig, + self.minfo.dst_host, + self.minfo.dst_port]) + + def connectionLost(self, reason): + self.minfo.closed(reason) + + def dataReceived(self, data): + try: + self.unpacker.reset(data) + val = self.unpacker.unpack() + print 'dataReceived>', 'val=', val + op = val[0] + op.replace('.', '_') + if op.startwith('xfr_'): + fn = getattr(self, op, self.unknown) + else: + fn = self.unknown + fn(val) + except Exception, ex: + print 'dataReceived>', ex + pass + + def unknown(self, val): + print 'unknown>', val + + def xfr_progress(self, val): + print 'xfr_progress>', val + + def xfr_error(self, val): + # If we get an error with non-zero code the migrate failed. + # An error with code zero indicates hello success. + err = int(val[1]) + if not err: return + self.minfo.error(err); + self.loseConnection() + + def xfr_ok(self, val): + # An ok indicates migrate completed successfully, and contains + # the new domain id on the remote system. + dom = int(val[1]) + self.minfo.ok(dom) + self.loseConnection() + +class MigrateClientFactory(ClientFactory): + + def __init__(self, minfo): + ClientFactory.__init__(self) + self.minfo = minfo + + def startedConnecting(self, connector): + print 'Started to connect', 'self=', self, 'connector=', connector + + def buildProtocol(self, addr): + print 'buildProtocol>', addr + return Migrate(self.minfo) + + def clientConnectionLost(self, connector, reason): + print 'clientConnectionLost>', 'connector=', connector, 'reason=', reason + + def clientConnectionFailed(self, connector, reason): + print 'clientConnectionFailed>', 'connector=', connector, 'reason=', reason + + class XendMigrateInfo: # states: begin, active, failed, succeeded? - def __init__(self, id, dom, dst): + def __init__(self, id, dom, host, port): self.id = id self.state = 'begin' self.src_host = socket.gethostname() self.src_dom = dom self.dst_host = dst + self.dst_port = port self.dst_dom = None + self.start = 0 + self.deferred = defer.Deferred() def set_state(self, state): self.state = state @@ -29,12 +132,33 @@ class XendMigrateInfo: sxpr = ['migrate', ['id', self.id], ['state', self.state] ] sxpr_src = ['src', ['host', self.src_host], ['domain', self.src_dom] ] sxpr.append(sxpr_src) - sxpr_dst = ['dst', ['host', self.dst] ] + sxpr_dst = ['dst', ['host', self.dst_host] ] if self.dst_dom: sxpr_dst.append(['domain', self.dst_dom]) sxpr.append(sxpr_dst) return sxpr - + + def vmconfig(self): + dominfo = xd.domain_get(self.dom) + if dominfo: + val = return sxp.to_string(dominfo) + else: + val = None + return None + + def error(self, err): + self.state = 'error' + + def ok(self, dom): + self.state = 'ok' + self.dst_dom = dom + + def close(self): + if self.state =='ok': + eserver.inject('xend.migrate.ok', self.sxpr()) + else: + self.state = 'error' + eserver.inject('xend.migrate.error', self.sxpr()) class XendMigrate: # Represents migration in progress. @@ -84,15 +208,15 @@ class XendMigrate: def migrate_get(self, id): return self.migrate.get(id) - def migrate_begin(self, dom, dst): + def migrate_begin(self, dom, host): # Check dom for existence, not migrating already. - # Create migrate info, tell xend to migrate it? - # - or fork migrate command ourselves? # Subscribe to migrate notifications (for updating). id = self.nextid() - info = XenMigrateInfo(id, dom, dst) + info = XenMigrateInfo(id, dom, host, XFRD_PORT) self._add_migrate(id, info) - return id + mcf = MigrateClientFactory(info) + reactor.connectTCP('localhost', XFRD_PORT, mcf) + return info.deferred def instance(): global inst diff --git a/tools/python/xen/xend/packing.py b/tools/python/xen/xend/packing.py new file mode 100644 index 0000000000..760af7f5a1 --- /dev/null +++ b/tools/python/xen/xend/packing.py @@ -0,0 +1,329 @@ + +# XDR-style packer/unpacker for sxpr. +# +# string -> [STRING] [len:u16] +# atom -> [ATOM] [len:u16] +# int -> [UINT] [value] +# list -> [LIST] {1 elt}* 0 +# null -> [NULL] +# none -> [NONE] +# bool -> [BOOL] { 0:u8 | 1:u8 } +# +# types packed as u16. +# +# So (a b c) -> [LIST] 1 a 1 b 1 c 0 +# () -> [LIST] 0 + +import struct + +try: + from cStringIO import StringIO as _StringIO +except ImportError: + from StringIO import StringIO as _StringIO + +import types + +class Error(Exception): + + def __init__(self, msg): + self.msg = msg + + def __repr__(self): + return repr(self.msg) + + def __str__(self): + return str(self.msg) + + +class ConversionError(Error): + pass + +BOOL_SIZE = 1 +BOOL_FMT = '>B' + +BYTE_SIZE = 1 +BYTE_FMT = '>b' +UBYTE_FMT = '>B' + +SHORT_SIZE = 2 +SHORT_FMT = '>h' +USHORT_FMT = '>H' + +INT_SIZE = 4 +INT_FMT = '>l' +UINT_FMT = '>L' + +NONE_CODE = 0 +NULL_CODE = 1 +INT_CODE = 2 +STRING_CODE = 3 +ATOM_CODE = 4 +BOOL_CODE = 5 +LIST_CODE = 10 + +class Packer: + + def __init__(self, io=None): + self.reset(io=io) + + def reset(self, io=None): + if io is None: + io = _StringIO() + self.io = io + + def get_buffer(self): + return self.io.getvalue() + + def get_io(self): + return self.io + + def struct_pack(self, fmt, x): + try: + self.io.write(struct.pack(fmt, x)) + except struct.error, msg: + raise ConversionError, msg + + def pack_none(self): + pass + + def pack_bool(self, x): + # { '1' | '0' } + print 'bool>', x + if x: + self.io.write('\1') + else: + self.io.write('\0') + + def pack_byte(self, x): + self.struct_pack(BYTE_FMT, x & 0xff) + + def pack_char(self, x): + print 'char>', x + self.io.write(x) + + def pack_ubyte(self, x): + print 'ubyte>', x + self.struct_pack(UBYTE_FMT, x & 0xff) + + def pack_ushort(self, x): + print 'ushort>', x + self.struct_pack(USHORT_FMT, x & 0xffff) + + def pack_short(self, x): + print 'short>', x + self.struct_pack(SHORT_FMT, x & 0xffff) + + def pack_uint(self, x): + print 'uint>', x + self.struct_pack(UINT_FMT, x) + + def pack_int(self, x): + print 'int>', x + self.struct_pack(INT_FMT, x) + + def pack_uhyper(self, x): + print 'uhyper>', x + self.pack_uint(x>>32 & 0xffffffffL) + self.pack_uint(x & 0xffffffffL) + + pack_hyper = pack_uhyper + + def pack_fstring(self, n, x): + print 'fstring>', x + self.io.write(x) + + pack_fopaque = pack_fstring + + def pack_string(self, x): + print 'string>', x + n = len(x) + self.pack_ushort(n) + self.pack_fstring(n, x) + + pack_opaque = pack_string + pack_bytes = pack_string + + def pack_list(self, x, pack_item): + print 'list>', x + # { '1' }* '0' + for item in x: + self.pack_bool(1) + pack_item(item) + self.pack_bool(0) + + def pack_farray(self, x, pack_item): + # * + # Can pass n and check length - but is it worth it? + print 'farray>', list + for item in x: + pack_item(item) + + def pack_array(self, x, pack_item): + # n *n + print 'array>', x + self.pack_uint(len(x)) + self.pack_farray(x, pack_item) + +class Unpacker: + + def __init__(self, data): + self.reset(data) + + def reset(self, data): + if isinstance(data, types.StringType): + data = _StringIO(data) + self.io = data + + def get_bytes(self, n): + if n < 0: + raise ConversionError('negative byte count') + data = self.io.read(n) + return data + + def struct_unpack(self, fmt, n): + data = self.get_bytes(n) + try: + return struct.unpack(fmt, data)[0] + except struct.error, msg: + raise ConversionError, msg + + def unpack_none(self): + return None + + def unpack_bool(self): + return self.struct_unpack(BOOL_FMT, BOOL_SIZE) + + def unpack_char(self): + return self.get_bytes(1)[0] + + def unpack_byte(self): + return self.struct_unpack(BYTE_FMT, BYTE_SIZE) + + def unpack_ubyte(self): + return self.struct_unpack(UBYTE_FMT, BYTE_SIZE) + + def unpack_ushort(self): + return self.struct_unpack(USHORT_FMT, SHORT_SIZE) + + def unpack_short(self): + return self.struct_unpack(SHORT_FMT, SHORT_SIZE) + + def unpack_uint(self): + x = self.struct_unpack(UINT_FMT, UINT_SIZE) + try: + return int(x) + except OverflowError: + return x + + def unpack_int(self): + return self.struct_unpack(INT_FMT, INT_SIZE) + + def unpack_uhyper(self): + hi = self.unpack_uint() + lo = self.unpack_uint() + return long(hi)<<32 | lo + + def unpack_hyper(self): + x = self.unpack_uhyper() + if x >= 0x8000000000000000L: + x = x - 0x10000000000000000L + return x + + def unpack_fstring(self, n): + return self.get_bytes(n) + + unpack_fopaque = unpack_fstring + + def unpack_string(self): + n = self.unpack_ushort() + return self.unpack_fstring(n) + + unpack_opaque = unpack_string + unpack_bytes = unpack_string + + def unpack_list(self, unpack_item): + list = [] + while self.unpack_bool(): + list.append(unpack_item()) + return list + + def unpack_farray(self, n, unpack_item): + list = [] + for i in range(n): + list.append(unpack_item()) + return list + + def unpack_array(self, unpack_item): + n = self.unpack_ushort() + return self.unpack_farray(n, unpack_item) + +class SxpPacker(Packer): + + pack_code = Packer.pack_ushort + + def pack(self, x): + if isinstance(x, types.NoneType): + self.pack_code(NONE_CODE) + self.pack_none() + elif isinstance(x, types.IntType): + self.pack_code(INT_CODE) + self.pack_int(x) + elif isinstance(x, types.StringType): + self.pack_code(STRING_CODE) + self.pack_string(x) + elif isinstance(x, types.ListType): + self.pack_code(LIST_CODE) + self.pack_list(x, self.pack) + else: + raise Error('invalid type ' + str(type(x))) + +class SxpUnpacker(Unpacker): + + unpack_code = Unpacker.unpack_ushort + + def unpack(self): + code = self.unpack_code() + if code == NONE_CODE: + val = self.unpack_none() + elif code == INT_CODE: + val = self.unpack_int() + elif code == BOOL_CODE: + val = self.unpack_bool() + elif code == STRING_CODE: + val = self.unpack_string() + elif code == ATOM_CODE: + val = self.unpack_string() + elif code == LIST_CODE: + val = self.unpack_list(self.unpack) + else: + raise Error('invalid code ' + str(code)) + return val + +def main(): + d = "['vfarm', ['@', ['name', 'vfarm1']], ['memory', 1024], ['image', 'splinux'], ['args', 'root=/dev/nfs ip=dhcp'], [ 1, -1, 1000000]]" + print"> len=", len(d), "d=", d + obj = ['vfarm', ['@', ['name', 'vfarm1']], + ['memory', 1024], + ['image', 'splinux'], + ['args', 'root=/dev/nfs ip=dhcp'], + [ 1, -1, 1000000] ] + print "> obj=", obj + pack = SxpPacker() + pack.pack(obj) + data = pack.get_buffer() + print "> len=", len(data), "data=", data + unpack = SxpUnpacker(data) + obj_unpack = unpack.unpack() + print "> obj=", obj_unpack + #obj = [100,101,102, 999.00234, { 'a': 1, 'b': 2 } ] + #pack.reset() + #pack.pack_item(obj) + #data = pack.get_buffer() + #print "> obj=", obj + #print "> len=", len(data), "data=", data + #unpack.reset(data) + #obj_unpack = unpack.unpack_item() + #print "> obj=", obj_unpack + +if __name__ == "__main__": + main() diff --git a/tools/python/xen/xend/server/SrvBase.py b/tools/python/xen/xend/server/SrvBase.py index bcff1bc3a0..059220c408 100644 --- a/tools/python/xen/xend/server/SrvBase.py +++ b/tools/python/xen/xend/server/SrvBase.py @@ -8,6 +8,7 @@ import types import StringIO from twisted.internet import defer +defer.Deferred.debug = 1 from twisted.internet import reactor from twisted.web import error from twisted.web import resource diff --git a/tools/python/xen/xend/server/SrvDaemon.py b/tools/python/xen/xend/server/SrvDaemon.py index 1f66ecc933..a514b89108 100644 --- a/tools/python/xen/xend/server/SrvDaemon.py +++ b/tools/python/xen/xend/server/SrvDaemon.py @@ -14,6 +14,7 @@ import socket import pwd import re import StringIO +import traceback from twisted.internet import pollreactor pollreactor.install() @@ -22,6 +23,7 @@ from twisted.internet import reactor from twisted.internet import protocol from twisted.internet import abstract from twisted.internet import defer +defer.Deferred.debug = 1 from xen.lowlevel import xu @@ -392,6 +394,12 @@ class EventProtocol(protocol.Protocol): eserver.inject(sxp.name(event), event) return ['ok'] + def op_traceon(self, name, v): + self.daemon.tracing(1) + + def op_traceoff(self, name, v): + self.daemon.tracing(0) + class EventFactory(protocol.Factory): """Asynchronous handler for the event server socket. @@ -424,6 +432,7 @@ class Daemon: """ def __init__(self): self.shutdown = 0 + self.traceon = 0 def daemon_pids(self): pids = [] @@ -482,7 +491,7 @@ class Daemon: while code > 0: code = os.waitpid(-1, os.WNOHANG) - def start(self,trace=0): + def start(self, trace=0): if self.cleanup(kill=False): return 1 @@ -506,7 +515,21 @@ class Daemon: # Child logfile = self.open_logfile() self.redirect_output(logfile) - if trace: + + self.tracing(trace) + + self.run() + return 0 + + def tracing(self, traceon): + """Turn tracing on or off. + + traceon tracing flag + """ + if traceon == self.traceon: + return + self.traceon = traceon + if traceon: self.tracefile = open('/var/log/xend.trace', 'w+', 1) self.traceindent = 0 sys.settrace(self.trace) @@ -514,26 +537,35 @@ class Daemon: threading.settrace(self.trace) # Only in Python >= 2.3 except: pass - self.run() - return 0 - def print_trace(self,str): + def print_trace(self, str): for i in range(self.traceindent): - self.tracefile.write(" ") + ch = " " + if (i % 5): + ch = ' ' + else: + ch = '|' + self.tracefile.write(ch) self.tracefile.write(str) def trace(self, frame, event, arg): + if not self.traceon: + print >>self.tracefile + print >>self.tracefile, '-' * 20, 'TRACE OFF', '-' * 20 + self.tracefile.close() + self.tracefile = None + return None if event == 'call': code = frame.f_code filename = code.co_filename - m = re.search('.*xenmgr/(.*)', code.co_filename) + m = re.search('.*xend/(.*)', filename) if not m: return None modulename = m.group(1) if re.search('sxp.py', modulename): return None self.traceindent += 1 - self.print_trace("++++ %s:%s\n" + self.print_trace("> %s:%s\n" % (modulename, code.co_name)) elif event == 'line': filename = frame.f_code.co_filename @@ -543,15 +575,18 @@ class Daemon: elif event == 'return': code = frame.f_code filename = code.co_filename - m = re.search('.*xenmgr/(.*)', code.co_filename) + m = re.search('.*xend/(.*)', filename) if not m: return None modulename = m.group(1) - self.print_trace("---- %s:%s\n" + self.print_trace("< %s:%s\n" % (modulename, code.co_name)) self.traceindent -= 1 elif event == 'exception': - pass + self.print_trace("! Exception:\n") + (ex, val, tb) = arg + traceback.print_exception(ex, val, tb, 10, self.tracefile) + #del tb return self.trace def open_logfile(self): @@ -629,6 +664,15 @@ class Daemon: reactor.diconnectAll() sys.exit(0) + def getDomChannel(self, dom): + """Get the channel to a domain. + + dom domain + + returns channel (or None) + """ + return self.channelF.getDomChannel(dom) + def blkif_set_control_domain(self, dom, recreate=0): """Set the block device backend control domain. """ diff --git a/tools/python/xen/xend/server/SrvDomain.py b/tools/python/xen/xend/server/SrvDomain.py index 122f2f0cc4..b71dd63161 100644 --- a/tools/python/xen/xend/server/SrvDomain.py +++ b/tools/python/xen/xend/server/SrvDomain.py @@ -27,7 +27,11 @@ class SrvDomain(SrvDir): return val def op_shutdown(self, op, req): - val = self.xd.domain_shutdown(self.dom.id) + #val = self.xd.domain_shutdown(self.dom.id) + fn = FormFn(self.xd.domain_shutdown, + [['dom', 'int'], + ['reason', 'str']]) + val = fn(req.args, {'dom': self.dom.id}) req.setResponseCode(202) req.setHeader("Location", "%s/.." % req.prePathURL()) return val diff --git a/tools/python/xen/xend/server/SrvDomainDir.py b/tools/python/xen/xend/server/SrvDomainDir.py index af4bc7a15c..eb1521e117 100644 --- a/tools/python/xen/xend/server/SrvDomainDir.py +++ b/tools/python/xen/xend/server/SrvDomainDir.py @@ -1,5 +1,6 @@ # Copyright (C) 2004 Mike Wray +import traceback from StringIO import StringIO from twisted.protocols import http @@ -24,6 +25,7 @@ class SrvDomainDir(SrvDir): val = None try: dom = self.xd.domain_get(x) + if not dom: raise KeyError('No such domain') val = SrvDomain(dom) except KeyError, ex: print 'SrvDomainDir>', ex @@ -38,6 +40,9 @@ class SrvDomainDir(SrvDir): return v def op_create(self, op, req): + """Create a domain. + Expects the domain config in request parameter 'config' in SXP format. + """ ok = 0 try: configstring = req.args.get('config')[0] @@ -48,7 +53,8 @@ class SrvDomainDir(SrvDir): config = pin.get_val() ok = 1 except Exception, ex: - print 'op_create>', ex + print 'op_create> Exception in config', ex + traceback.print_exc() if not ok: req.setResponseCode(http.BAD_REQUEST, "Invalid configuration") return "Invalid configuration" @@ -57,19 +63,20 @@ class SrvDomainDir(SrvDir): "Invalid configuration") try: deferred = self.xd.domain_create(config) - deferred.addCallback(self._cb_op_create, configstring, req) + deferred.addCallback(self._op_create_cb, configstring, req) + deferred.addErrback(self._op_create_err, req) return deferred except Exception, ex: - raise - #return ['err', str(ex) ] - #req.setResponseCode(http.BAD_REQUEST, "Error creating domain") - #return str(ex) + print 'op_create> Exception creating domain:' + traceback.print_exc() + req.setResponseCode(http.BAD_REQUEST, "Error creating domain") + return str(ex) #return error.ErrorPage(http.BAD_REQUEST, # "Error creating domain", # str(ex)) - def _cb_op_create(self, dominfo, configstring, req): + def _op_create_cb(self, dominfo, configstring, req): """Callback to handle deferred domain creation. """ dom = dominfo.id @@ -89,7 +96,16 @@ class SrvDomainDir(SrvDir): out.close() return val + def _op_create_err(self, err, req): + """Callback to handle errors in deferred domain creation. + """ + print 'op_create> Deferred Exception creating domain:', err + req.setResponseCode(http.BAD_REQUEST, "Error creating domain") + return str(err) + def op_restore(self, op, req): + """Restore a domain from file. + """ fn = FormFn(self.xd.domain_restore, [['file', 'str']]) val = fn(req.args) @@ -131,6 +147,8 @@ class SrvDomainDir(SrvDir): req.write('') def form(self, req): + """Generate the form(s) for domain dir operations. + """ req.write('
' % req.prePathURL()) req.write('') diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py index 4e2a49f7d8..5596ddb842 100755 --- a/tools/python/xen/xend/server/blkif.py +++ b/tools/python/xen/xend/server/blkif.py @@ -1,4 +1,7 @@ +# Copyright (C) 2004 Mike Wray + from twisted.internet import defer +defer.Deferred.debug = 1 from xen.xend import sxp from xen.xend import PrettyPrint @@ -18,53 +21,78 @@ class BlkifControllerFactory(controller.ControllerFactory): self.majorTypes = [ CMSG_BLKIF_BE ] self.subTypes = { - CMSG_BLKIF_BE_CREATE : self.recv_be_create, - CMSG_BLKIF_BE_CONNECT : self.recv_be_connect, - CMSG_BLKIF_BE_VBD_CREATE : self.recv_be_vbd_create, - CMSG_BLKIF_BE_VBD_GROW : self.recv_be_vbd_grow, CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed, } self.attached = 1 self.registerChannel() def createInstance(self, dom, recreate=0): - d = self.addDeferred() + """Create a block device controller for a domain. + + dom domain + recreate if true it's a recreate (after xend restart) + """ + d = defer.Deferred() blkif = self.getInstanceByDom(dom) if blkif: - self.callDeferred(blkif) + d.callback(blkif) else: blkif = BlkifController(self, dom) self.addInstance(blkif) if recreate: - self.callDeferred(blkif) + d.callback(blkif) else: - blkif.send_be_create() + d1 = defer.Deferred() + d1.addCallback(self.respond_be_create, d) + d1.addErrback(d.errback) + blkif.send_be_create(response=d1) return d def getDomainDevices(self, dom): + """Get the block devices for a domain. + + dom domain + + returns devices + """ blkif = self.getInstanceByDom(dom) return (blkif and blkif.getDevices()) or [] def getDomainDevice(self, dom, vdev): + """Get a block device from a domain. + + dom domain + vdev device index + + returns device + """ blkif = self.getInstanceByDom(dom) return (blkif and blkif.getDevice(vdev)) or None def setControlDomain(self, dom, recreate=0): + """Set the back-end block device controller domain. + + dom domain + recreate if true it's a recreate (after xend restart) + """ if self.dom == dom: return self.deregisterChannel() if not recreate: self.attached = 0 self.dom = dom self.registerChannel() - # - #if xend.blkif.be_port: - # xend.blkif.recovery = True - #xend.blkif.be_port = xend.main.port_from_dom(dom) def getControlDomain(self): + """Get the back-end block device controller domain. + """ return self.dom def reattachDevice(self, dom, vdev): + """Reattach a device (on changing control domain). + + dom domain + vdev device index + """ blkif = self.getInstanceByDom(dom) if blkif: blkif.reattachDevice(vdev) @@ -83,17 +111,20 @@ class BlkifControllerFactory(controller.ControllerFactory): return attached def reattached(self): + """Notify all block interface we have been reattached + (after changing control domain). + """ for blkif in self.getInstances(): blkif.reattached() - def recv_be_create(self, msg, req): - #print 'recv_be_create>' + def respond_be_create(self, msg, d): + print 'respond_be_create>' val = unpackMsg('blkif_be_create_t', msg) blkif = self.getInstanceByDom(val['domid']) - self.callDeferred(blkif) + d.callback(blkif) - def recv_be_connect(self, msg, req): - #print 'recv_be_create>' + def respond_be_connect(self, msg): + print 'respond_be_connect>', self val = unpackMsg('blkif_be_connect_t', msg) blkif = self.getInstanceByDom(val['domid']) if blkif: @@ -101,25 +132,30 @@ class BlkifControllerFactory(controller.ControllerFactory): else: pass - def recv_be_vbd_create(self, msg, req): - #print 'recv_be_vbd_create>' + def respond_be_vbd_create(self, msg, d): + print 'recv_be_vbd_create>', self val = unpackMsg('blkif_be_vbd_create_t', msg) blkif = self.getInstanceByDom(val['domid']) if blkif: - blkif.send_be_vbd_grow(val['vdevice']) + d1 = defer.Deferred() + d1.addCallback(self.respond_be_vbd_grow, d) + if d: d1.addErrback(d.errback) + blkif.send_be_vbd_grow(val['vdevice'], response=d1) else: pass - def recv_be_vbd_grow(self, msg, req): - #print 'recv_be_vbd_grow>' + def respond_be_vbd_grow(self, msg, d): + print 'recv_be_vbd_grow>', self val = unpackMsg('blkif_be_vbd_grow_t', msg) # Check status? if self.attached: - self.callDeferred(0) + if d: + d.callback(0) else: self.reattachDevice(val['domid'], val['vdevice']) def recv_be_driver_status_changed(self, msg, req): + print 'recv_be_driver_status_changed>', self, req val = unpackMsg('blkif_be_driver_status_changed_t', msg) status = val['status'] if status == BLKIF_DRIVER_STATUS_UP and not self.attached: @@ -147,7 +183,6 @@ class BlkDev(controller.Dev): return val def destroy(self): - print 'BlkDev>destroy>', self.vdev PrettyPrint.prettyprint(self.sxpr()) self.controller.send_be_vbd_destroy(self.vdev) @@ -157,7 +192,6 @@ class BlkifController(controller.Controller): """ def __init__(self, factory, dom): - #print 'BlkifController> dom=', dom controller.Controller.__init__(self, factory, dom) self.devices = {} @@ -172,7 +206,6 @@ class BlkifController(controller.Controller): self.attached = 1 self.evtchn = None self.registerChannel() - #print 'BlkifController<', 'dom=', self.dom, 'idx=', self.idx def sxpr(self): val = ['blkif', ['dom', self.dom]] @@ -182,11 +215,6 @@ class BlkifController(controller.Controller): self.evtchn['port2']]) return val - def lostChannel(self): - print 'BlkifController>lostChannel>', 'dom=', self.dom - #self.destroyDevices() - controller.Controller.lostChannel(self) - def getDevices(self): return self.devices.values() @@ -201,26 +229,32 @@ class BlkifController(controller.Controller): def attachDevice(self, vdev, mode, segment, recreate=0): """Attach a device to the specified interface. + + vdev device index + mode read/write mode + segment segment + recreate if true it's being recreated (after xend restart) + + returns deferred """ - #print 'BlkifController>attach_device>', self.dom, vdev, mode, segment dev = self.addDevice(vdev, mode, segment) if not dev: return -1 + d = defer.Deferred() if recreate: - d = defer.Deferred() d.callback(self) else: - self.send_be_vbd_create(vdev) - d = self.factory.addDeferred() + d1 = defer.Deferred() + d1.addCallback(self.factory.respond_be_vbd_create, d) + d1.addErrback(d.errback) + self.send_be_vbd_create(vdev, response=d1) return d def destroy(self): - print 'BlkifController>destroy> dom=', self.dom def cb_destroy(val): self.send_be_destroy() - d = self.factory.addDeferred() + d = defer.Deferred() d.addCallback(cb_destroy) - self.send_be_disconnect() - #self.destroyDevices() + self.send_be_disconnect(response=d) def destroyDevices(self): for dev in self.getDevices(): @@ -232,7 +266,9 @@ class BlkifController(controller.Controller): self.attached = 0 for dev in self.devices.values(): dev.attached = 0 - self.send_be_vbd_create(vdev) + d1 = defer.Deferred() + d1.addCallback(self.factory.respond_be_vbd_create, None) + self.send_be_vbd_create(vdev, response=d1) def reattachDevice(self, vdev): """Reattach a device, when the back-end control domain has changed. @@ -273,51 +309,47 @@ class BlkifController(controller.Controller): 'blkif_handle' : val['handle'], 'evtchn' : self.evtchn['port1'], 'shmem_frame' : val['shmem_frame'] }) - self.factory.writeRequest(msg) - pass + d = defer.Deferred() + d.addCallback(self.factory.respond_be_connect) + self.factory.writeRequest(msg, response=d) - #def recv_fe_interface_status_changed(self, msg, req): - # (hnd, status, chan) = unpackMsg('blkif_fe_interface_status_changed_t', msg) - # print 'recv_fe_interface_status_changed>', hnd, status, chan - # pass - - def send_fe_interface_status_changed(self): + def send_fe_interface_status_changed(self, response=None): msg = packMsg('blkif_fe_interface_status_changed_t', { 'handle' : 0, 'status' : BLKIF_INTERFACE_STATUS_CONNECTED, 'evtchn' : self.evtchn['port2'] }) - self.writeRequest(msg) + self.writeRequest(msg, response=response) - def send_be_create(self): + def send_be_create(self, response=None): msg = packMsg('blkif_be_create_t', { 'domid' : self.dom, 'blkif_handle' : 0 }) - self.factory.writeRequest(msg) + self.factory.writeRequest(msg, response=response) - def send_be_disconnect(self): + def send_be_disconnect(self, response=None): print '>BlkifController>send_be_disconnect>', 'dom=', self.dom msg = packMsg('blkif_be_disconnect_t', { 'domid' : self.dom, 'blkif_handle' : 0 }) - self.factory.writeRequest(msg) + self.factory.writeRequest(msg, response=response) - def send_be_destroy(self): + def send_be_destroy(self, response=None): print '>BlkifController>send_be_destroy>', 'dom=', self.dom msg = packMsg('blkif_be_destroy_t', { 'domid' : self.dom, 'blkif_handle' : 0 }) - self.factory.writeRequest(msg) + self.factory.writeRequest(msg, response=response) - def send_be_vbd_create(self, vdev): + def send_be_vbd_create(self, vdev, response=None): dev = self.devices[vdev] msg = packMsg('blkif_be_vbd_create_t', { 'domid' : self.dom, 'blkif_handle' : 0, 'vdevice' : dev.vdev, 'readonly' : dev.readonly() }) - self.factory.writeRequest(msg) + self.factory.writeRequest(msg, response=response) - def send_be_vbd_grow(self, vdev): + def send_be_vbd_grow(self, vdev, response=None): dev = self.devices[vdev] msg = packMsg('blkif_be_vbd_grow_t', { 'domid' : self.dom, @@ -326,9 +358,9 @@ class BlkifController(controller.Controller): 'extent.device' : dev.device, 'extent.sector_start' : dev.start_sector, 'extent.sector_length' : dev.nr_sectors }) - self.factory.writeRequest(msg) + self.factory.writeRequest(msg, response=response) - def send_be_vbd_destroy(self, vdev): + def send_be_vbd_destroy(self, vdev, response=None): print '>BlkifController>send_be_vbd_destroy>', 'dom=', self.dom, 'vdev=', vdev PrettyPrint.prettyprint(self.sxpr()) dev = self.devices[vdev] @@ -337,5 +369,5 @@ class BlkifController(controller.Controller): 'blkif_handle' : 0, 'vdevice' : dev.vdev }) del self.devices[vdev] - self.factory.writeRequest(msg) + self.factory.writeRequest(msg, response=response) diff --git a/tools/python/xen/xend/server/channel.py b/tools/python/xen/xend/server/channel.py index 214020214b..caaa66e28c 100755 --- a/tools/python/xen/xend/server/channel.py +++ b/tools/python/xen/xend/server/channel.py @@ -1,3 +1,5 @@ +# Copyright (C) 2004 Mike Wray + import xen.lowlevel.xc; xc = xen.lowlevel.xc.new() from xen.lowlevel import xu from messages import msgTypeName @@ -24,14 +26,11 @@ class ChannelFactory: self.notifier = xu.notifier() def addChannel(self, channel): - """Add a channel. + """Add a channel. Registers with the notifier. """ idx = channel.idx self.channels[idx] = channel self.notifier.bind(idx) - # Try to wake it up - #self.notifier.unmask(idx) - #channel.notify() def getChannel(self, idx): """Get the channel with the given index (if any). @@ -40,6 +39,7 @@ class ChannelFactory: def delChannel(self, idx): """Remove the channel with the given index (if any). + Deregisters with the notifier. """ if idx in self.channels: del self.channels[idx] @@ -48,15 +48,31 @@ class ChannelFactory: def domChannel(self, dom): """Get the channel for the given domain. Construct if necessary. + + dom domain + + returns channel + """ + chan = self.getDomChannel(dom) + if not chan: + chan = Channel(self, dom) + self.addChannel(chan) + return chan + + def getDomChannel(self, dom): + """Get the channel for the given domain. + + dom domain + + returns channel (or None) """ dom = int(dom) for chan in self.channels.values(): if not isinstance(chan, Channel): continue if chan.dom == dom: return chan - chan = Channel(self, dom) - self.addChannel(chan) - return chan + return None + def virqChannel(self, virq): """Get the channel for the given virq. @@ -109,12 +125,11 @@ class BaseChannel: def notificationReceived(self): """Called when a notification is received. - Closes the channel on error, otherwise calls - handleNotification(type), which should be defined + Calls handleNotification(), which should be defined in a subclass. """ - if not self.closed: - self.handleNotification(type) + if self.closed: return + self.handleNotification() def close(self): """Close the channel. Calls channelClosed() on the factory. @@ -122,7 +137,7 @@ class BaseChannel: """ self.factory.channelClosed(self) - def handleNotification(self, type): + def handleNotification(self): """Handle notification. Define in subclass. """ @@ -159,9 +174,9 @@ class VirqChannel(BaseChannel): """Close the channel. Calls lostChannel(self) on all its clients and channelClosed() on the factory. """ - for c in self.clients: + for c in self.clients[:]: c.lostChannel(self) - del self.clients + self.clients = [] BaseChannel.close(self) def registerClient(self, client): @@ -172,7 +187,7 @@ class VirqChannel(BaseChannel): """ self.clients.append(client) - def handleNotification(self, type): + def handleNotification(self): for c in self.clients: c.virqReceived(self.virq) @@ -208,23 +223,27 @@ class Channel(BaseChannel): def getLocalPort(self): """Get the local port. """ + if self.closed: return -1 return self.port.local_port def getRemotePort(self): """Get the remote port. """ + if self.closed: return -1 return self.port.remote_port def close(self): """Close the channel. Calls lostChannel() on all its devices and channelClosed() on the factory. """ + if self.closed: return self.closed = 1 - for d in self.devs: + for d in self.devs[:]: d.lostChannel() self.factory.channelClosed(self) self.devs = [] self.devs_by_type = {} + self.port.disconnect() def registerDevice(self, types, dev): """Register a device controller. @@ -265,10 +284,15 @@ class Channel(BaseChannel): def __repr__(self): return ('' % (self.dom, - self.port.local_port, - self.port.remote_port)) + self.getLocalPort(), + self.getRemotePort())) - def handleNotification(self, type): + def handleNotification(self): + """Process outstanding messages in repsonse to notification on the port. + """ + if self.closed: + print 'handleNotification> Notification on closed channel', self + return work = 0 work += self.handleRequests() work += self.handleResponses() @@ -277,6 +301,9 @@ class Channel(BaseChannel): self.notify() def notify(self): + """Notify the other end of the port that messages have been processed. + """ + if self.closed: return self.port.notify() def handleRequests(self): diff --git a/tools/python/xen/xend/server/console.py b/tools/python/xen/xend/server/console.py index 3227dc1b5e..77f6343c3d 100755 --- a/tools/python/xen/xend/server/console.py +++ b/tools/python/xen/xend/server/console.py @@ -1,3 +1,4 @@ +# Copyright (C) 2004 Mike Wray from twisted.internet import reactor from twisted.internet import protocol @@ -12,11 +13,6 @@ import controller from messages import * from params import * -"""Telnet binary option.""" -TRANSMIT_BINARY = '0' -WILL = chr(251) -IAC = chr(255) - class ConsoleProtocol(protocol.Protocol): """Asynchronous handler for a console TCP socket. """ @@ -36,19 +32,12 @@ class ConsoleProtocol(protocol.Protocol): self.loseConnection() return else: - # KAF: A nice quiet successful connect. Don't bother with telnet - # control sequence -- telnet is not the appropriate protocol here. + # KAF: A nice quiet successful connect. #self.transport.write("Connected to console %d on domain %d\n" # % (self.idx, self.controller.dom)) - #self.setTelnetTransmitBinary() eserver.inject('xend.console.connect', [self.idx, self.addr[0], self.addr[1]]) - def setTelnetTransmitBinary(self): - """Send the sequence to set the telnet TRANSMIT-BINARY option. - """ - self.write(IAC + WILL + TRANSMIT_BINARY) - def dataReceived(self, data): if self.controller.handleInput(self, data): self.loseConnection() @@ -104,11 +93,15 @@ class ConsoleController(controller.Controller): output and the connected TCP sockets to post console input. """ + STATUS_NEW = 'new' + STATUS_CLOSED = 'closed' + STATUS_CONNECTED = 'connected' + STATUS_LISTENING = 'listening' + def __init__(self, factory, dom, console_port): - #print 'ConsoleController> dom=', dom, type(dom) controller.Controller.__init__(self, factory, dom) self.majorTypes = [ CMSG_CONSOLE ] - self.status = "new" + self.status = self.STATUS_NEW self.addr = None self.conn = None self.rbuf = xu.buffer() @@ -118,7 +111,6 @@ class ConsoleController(controller.Controller): self.registerChannel() self.listener = None self.listen() - #print 'ConsoleController<', 'dom=', self.dom, 'idx=', self.idx def sxpr(self): val =['console', @@ -136,29 +128,31 @@ class ConsoleController(controller.Controller): return not (self.closed() or self.rbuf.empty()) def closed(self): - return self.status == 'closed' + return self.status == self.STATUS_CLOSED def connected(self): - return self.status == 'connected' + return self.status == self.STATUS_CONNECTED def close(self): - try: - #print 'ConsoleController> close dom=', self.dom - self.status = "closed" - if self.conn: - self.conn.loseConnection() - self.listener.stopListening() - self.deregisterChannel() - self.lostChannel() - except Exception, ex: - print 'ConsoleController>close>', ex - raise + """Close the console controller. + """ + self.lostChannel() + + def lostChannel(self): + """The channel to the domain has been lost. + Cleanup: disconnect TCP connections and listeners, notify the controller. + """ + self.status = self.STATUS_CLOSED + if self.conn: + self.conn.loseConnection() + self.listener.stopListening() + controller.Controller.lostChannel(self) def listen(self): """Listen for TCP connections to the console port.. """ if self.closed(): return - self.status = "listening" + self.status = self.STATUS_LISTENING if self.listener: #self.listener.startListening() pass @@ -167,15 +161,25 @@ class ConsoleController(controller.Controller): self.listener = reactor.listenTCP(self.console_port, f) def connect(self, addr, conn): + """Connect a TCP connection to the console. + Fails if closed or already connected. + + addr peer address + conn connection + + returns 0 if ok, negative otherwise + """ if self.closed(): return -1 if self.connected(): return -1 self.addr = addr self.conn = conn - self.status = "connected" + self.status = self.STATUS_CONNECTED self.handleOutput() return 0 def disconnect(self): + """Disconnect the TCP connection to the console. + """ if self.conn: self.conn.loseConnection() self.addr = None @@ -183,15 +187,29 @@ class ConsoleController(controller.Controller): self.listen() def requestReceived(self, msg, type, subtype): - #print '***Console', self.dom, msg.get_payload() + """Receive console data from the console channel. + + msg console message + type major message type + subtype minor message typ + """ self.rbuf.write(msg.get_payload()) self.handleOutput() def responseReceived(self, msg, type, subtype): + """Handle a response to a request written to the console channel. + Just ignore it because the return values are not interesting. + + msg console message + type major message type + subtype minor message typ + """ pass def produceRequests(self): - # Send as much pending console data as there is room for. + """Write pending console data to the console channel. + Writes as much to the channel as it can. + """ work = 0 while not self.wbuf.empty() and self.channel.writeReady(): msg = xu.message(CMSG_CONSOLE, 0, 0) @@ -201,7 +219,12 @@ class ConsoleController(controller.Controller): def handleInput(self, conn, data): """Handle some external input aimed at the console. - Called from a TCP connection (conn). + Called from a TCP connection (conn). Ignores the input + if the calling connection (conn) is not the one connected + to the console (self.conn). + + conn connection + data input data """ if self.closed(): return -1 if conn != self.conn: return 0 @@ -215,18 +238,14 @@ class ConsoleController(controller.Controller): Sends it to the connected console (if any). """ if self.closed(): - #print 'Console>handleOutput> closed' return -1 if not self.conn: - #print 'Console>handleOutput> not connected' return 0 while not self.rbuf.empty(): try: - #print 'Console>handleOutput> writing...' bytes = self.conn.write(self.rbuf.peek()) if bytes > 0: self.rbuf.discard(bytes) except socket.error, error: pass - #print 'Console>handleOutput<' return 0 diff --git a/tools/python/xen/xend/server/controller.py b/tools/python/xen/xend/server/controller.py index 900c2d55b0..6d0bd9295f 100755 --- a/tools/python/xen/xend/server/controller.py +++ b/tools/python/xen/xend/server/controller.py @@ -1,10 +1,50 @@ +# Copyright (C) 2004 Mike Wray + from twisted.internet import defer +defer.Deferred.debug = 1 import channel from messages import msgTypeName +DEBUG=0 + +class OutOfOrderError(RuntimeError): + """Error reported when a response arrives out of order. + """ + pass + +class Responder: + """Handler for a response to a message. + """ + + def __init__(self, mid, deferred): + """Create a responder. + + mid message id of response to handle + deferred deferred object holding the callbacks + """ + self.mid = mid + self.deferred = deferred + + def responseReceived(self, msg): + if self.deferred.called: return + self.deferred.callback(msg) + + def error(self, err): + if self.deferred.called: return + self.deferred.errback(err) + class CtrlMsgRcvr: """Abstract class for things that deal with a control interface to a domain. + + Instance variables: + + dom : the domain we are a control interface for + majorTypes: list of major message types we are interested in + subTypes : mapping of message subtypes to methods + + channel : channel to the domain + idx : channel index """ @@ -15,50 +55,140 @@ class CtrlMsgRcvr: self.dom = None self.channel = None self.idx = None + self.responders = [] + # Timeout (in seconds) for deferreds. + self.timeout = 10 + + def setTimeout(self, timeout): + self.timeout = timeout def requestReceived(self, msg, type, subtype): + """Dispatch a request to handlers. + + msg message + type major message type + subtype minor message type + """ + msgid = msg.get_header()['id'] + if DEBUG: + print 'requestReceived>', self, msgid, msgTypeName(type, subtype) method = self.subTypes.get(subtype) if method: method(msg, 1) - else: + elif DEBUG: print ('requestReceived> No handler: Message type %s %d:%d' % (msgTypeName(type, subtype), type, subtype)), self def responseReceived(self, msg, type, subtype): + """Dispatch a response to handlers. + + msg message + type major message type + subtype minor message type + """ + msgid = msg.get_header()['id'] + if DEBUG: + print 'responseReceived>', self, msgid, msgTypeName(type, subtype) + if self.callResponders(msg): + return method = self.subTypes.get(subtype) if method: method(msg, 0) - else: + elif DEBUG: print ('responseReceived> No handler: Message type %s %d:%d' % (msgTypeName(type, subtype), type, subtype)), self + def addResponder(self, mid, deferred): + """Add a responder for a message id. + The deferred is called with callback(msg) when a response + with the given message id arrives. Responses are expected + to arrive in order of message id. When a response arrives, + waiting responders for messages with lower id have errback + called with an OutOfOrder error. + + mid message id of response expected + deferred a Deferred to handle the response + + returns Responder + """ + if self.timeout > 0: + deferred.setTimeout(self.timeout) + resp = Responder(mid, deferred) + self.responders.append(resp) + return resp + + def callResponders(self, msg): + """Call any waiting responders for a response message. + + msg response message + + returns 1 if there was a responder for the message, 0 otherwise + """ + hdr = msg.get_header() + mid = hdr['id'] + handled = 0 + while self.responders: + resp = self.responders[0] + if resp.mid > mid: + break + self.responders.pop() + if resp.mid < mid: + print 'handleResponse> Out of order:', resp.mid, mid + resp.error(OutOfOrderError()) + else: + handled = 1 + resp.responseReceived(msg) + break + return handled + def lostChannel(self): + """Called when the channel to the domain is lost. + """ pass def registerChannel(self): - #print 'CtrlMsgRcvr>registerChannel>', self + """Register interest in our major message types with the + channel to our domain. + """ self.channel = self.channelFactory.domChannel(self.dom) self.idx = self.channel.getIndex() if self.majorTypes: self.channel.registerDevice(self.majorTypes, self) def deregisterChannel(self): - #print 'CtrlMsgRcvr>deregisterChannel>', self + """Deregister interest in our major message types with the + channel to our domain. + """ if self.channel: self.channel.deregisterDevice(self) del self.channel def produceRequests(self): + """Produce any queued requests. + + return number produced + """ return 0 - def writeRequest(self, msg): + def writeRequest(self, msg, response=None): + """Write a request to the channel. + + msg message + response Deferred to handle the response (optional) + """ if self.channel: + if DEBUG: print 'CtrlMsgRcvr>writeRequest>', self, msg + if response: + self.addResponder(msg.get_header()['id'], response) self.channel.writeRequest(msg) else: print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self def writeResponse(self, msg): + """Write a response to the channel. + """ if self.channel: + if DEBUG: print 'CtrlMsgRcvr>writeResponse>', self, msg self.channel.writeResponse(msg) else: print 'CtrlMsgRcvr>writeResponse>', 'no channel!', self @@ -66,6 +196,12 @@ class CtrlMsgRcvr: class ControllerFactory(CtrlMsgRcvr): """Abstract class for factories creating controllers. Maintains a table of instances. + + Instance variables: + + instances : mapping of index to controller instance + dlist : list of deferreds + dom : domain """ def __init__(self): @@ -73,55 +209,46 @@ class ControllerFactory(CtrlMsgRcvr): self.instances = {} self.dlist = [] self.dom = 0 - # Timeout (in seconds) for deferreds. - self.timeout = 10 def addInstance(self, instance): + """Add a controller instance (under its index). + """ self.instances[instance.idx] = instance def getInstance(self, idx): + """Get a controller instance from its index. + """ return self.instances.get(idx) def getInstances(self): + """Get a list of all controller instances. + """ return self.instances.values() def getInstanceByDom(self, dom): + """Get the controller instance for the given domain. + """ for inst in self.instances.values(): if inst.dom == dom: return inst return None def delInstance(self, instance): - #print 'ControllerFactory>delInstance>', instance.idx + """Delete an instance from the table. + """ if instance.idx in self.instances: - #print 'ControllerFactory>delInstance> remove', instance.idx del self.instances[instance.idx] def createInstance(self, dom, recreate=0): + """Create an instance. Define in a subclass. + """ raise NotImplementedError() def instanceClosed(self, instance): - #print 'ControllerFactory>instanceClosed>', instance.idx, instance + """Callback called when an instance is closed (usually by the instance). + """ self.delInstance(instance) - def addDeferred(self): - d = defer.Deferred() - if self.timeout > 0: - # The deferred will error if not called before timeout. - d.setTimeout(self.timeout) - self.dlist.append(d) - return d - - def callDeferred(self, *args): - if self.dlist: - d = self.dlist.pop(0) - d.callback(*args) - - def errDeferred(self, *args): - if self.dlist: - d = self.dlist.pop(0) - d.errback(*args) - class Controller(CtrlMsgRcvr): """Abstract class for a device controller attached to a domain. """ @@ -134,15 +261,20 @@ class Controller(CtrlMsgRcvr): self.idx = None def close(self): - self.deregisterChannel() + """Close the controller. + """ self.lostChannel() def lostChannel(self): - #print 'Controller>lostChannel>', self, self.factory + """The controller channel has been lost. + """ + self.deregisterChannel() self.factory.instanceClosed(self) class Dev: - + """Abstract class for a device attached to a device controller. + """ + def __init__(self, controller): self.controller = controller self.props = {} @@ -160,9 +292,6 @@ class Dev: if k in self.props: del self.props[k] - #def __repr__(self): - # return str(self.sxpr()) - def sxpr(self): raise NotImplementedError() diff --git a/tools/python/xen/xend/server/cstruct.py b/tools/python/xen/xend/server/cstruct.py deleted file mode 100755 index 880931b41f..0000000000 --- a/tools/python/xen/xend/server/cstruct.py +++ /dev/null @@ -1,269 +0,0 @@ -import struct - -class Struct: - - maxDepth = 10 - - base = ['x', 'B', 'H', 'I', 'L', 'Q', 'c', 'h', 'i', 'l', 'q', ] - - sizes = {'B': 1, - 'H': 2, - 'I': 4, - 'L': 4, - 'Q': 8, - 'c': 1, - 'h': 2, - 'i': 4, - 'l': 4, - 'q': 8, - 'x': 1, - } - - formats = { - 'int8' : 'B', - 'int16' : 'H', - 'int32' : 'I', - 'int64' : 'Q', - 'u8' : 'B', - 'u16' : 'H', - 'u32' : 'I', - 'u64' : 'Q' - } - - def typedef(self, name, val): - self.formats[name] = val - - def struct(self, name, *f): - self.typedef(name, StructInfo(self, f)) - - def getType(self, name): - return self.formats[name] - - def format(self, ty): - d = 0 - f = ty - while d < self.maxDepth: - d += 1 - f = self.formats[f] - if isinstance(f, StructInfo): - return f.format() - if f in self.base: - return f - return -1 - - def alignedformat(self, ty): - fmt = self.format(ty) - #print 'alignedformat> %s |%s|' %(ty, fmt) - afmt = self.align(fmt) - #print 'alignedformat< %s |%s| |%s|' % (ty, fmt, afmt) - return afmt - - def align(self, fmt): - n1 = 0 - afmt = '' - for a in fmt: - n2 = self.getSize(a) - m = n1 % n2 - if m: - d = (n2 - m) - afmt += 'x' * d - n1 += d - afmt += a - n1 += n2 - return afmt - - def fmtsize(self, fmt): - s = 0 - for f in fmt: - s += self.getSize(f) - return s - - def getSize(self, f): - return self.sizes[f] - - def pack(self, ty, data): - return self.getType(ty).pack(data) - - def unpack(self, ty, data): - return self.getType(ty).unpack(data) - - def show(self): - l = self.formats.keys() - l.sort() - for v in l: - print "%-35s %-10s %s" % (v, self.format(v), self.alignedformat(v)) - - -class StructInfo: - - def __init__(self, s, f): - self.fmt = None - self.structs = s - self.fields = f - - def alignedformat(self): - if self.afmt: return self.afmt - self.afmt = self.structs.align(self.format()) - return self.afmt - - def format(self): - if self.fmt: return self.fmt - fmt = "" - for (ty, name) in self.fields: - fmt += self.formatString(ty) - self.fmt = fmt - return fmt - - def formatString(self, ty): - if ty in self.fields: - ty = self.fields[ty] - return self.structs.format(ty) - - def pack(self, *args): - return struct.pack(self.alignedformat(), *args) - - def unpack(self, data): - return struct.unpack(self.alignedformat(), data) - -types = Struct() - -types.typedef('short' , 'h') -types.typedef('int' , 'i') -types.typedef('long' , 'l') -types.typedef('unsigned short', 'H') -types.typedef('unsigned int' , 'I') -types.typedef('unsigned long' , 'L') -types.typedef('domid_t' , 'u64') -types.typedef('blkif_vdev_t' , 'u16') -types.typedef('blkif_pdev_t' , 'u16') -types.typedef('blkif_sector_t', 'u64') - -types.struct('u8[6]', - ('u8', 'a1'), - ('u8', 'a2'), - ('u8', 'a3'), - ('u8', 'a4'), - ('u8', 'a5'), - ('u8', 'a6')) - -types.struct('blkif_fe_interface_status_changed_t', - ('unsigned int', 'handle'), - ('unsigned int', 'status'), - ('unsigned int', 'evtchn')) - -types.struct('blkif_fe_driver_status_changed_t', - ('unsigned int', 'status'), - ('unsigned int', 'nr_interfaces')) - -types.struct('blkif_fe_interface_connect_t', - ('unsigned int' , 'handle'), - ('unsigned long', 'shmem_frame')) - -types.struct('blkif_fe_interface_disconnect_t', - ('unsigned int', 'handle')) - -types.struct('blkif_extent_t', - ('blkif_pdev_t' , 'device'), - ('blkif_sector_t', 'sector_start'), - ('blkif_sector_t', 'sector_length')) - -types.struct('blkif_be_create_t', - ('domid_t' , 'domid'), - ('unsigned int', 'blkif_handle'), - ('unsigned int', 'status')) - -types.struct('blkif_be_destroy_t', - ('domid_t' , 'domid'), - ('unsigned int', 'blkif_handle'), - ('unsigned int', 'status')) - -types.struct('blkif_be_connect_t', - ('domid_t' , 'domid'), - ('unsigned int' , 'blkif_handle'), - ('unsigned int' , 'evtchn'), - ('unsigned long', 'shmem_frame'), - ('unsigned int' , 'status')) - -types.struct('blkif_be_disconnect_t', - ('domid_t' , 'domid'), - ('unsigned int', 'blkif_handle'), - ('unsigned int', 'status')) - -types.struct('blkif_be_vbd_create_t', - ('domid_t' , 'domid'), #Q - ('unsigned int', 'blkif_handle'), #I - ('blkif_vdev_t', 'vdevice'), #H - ('int' , 'readonly'), #i - ('unsigned int', 'status')) #I - -types.struct('blkif_be_vbd_destroy_t', - ('domid_t' , 'domid'), - ('unsigned int', 'blkif_handle'), - ('blkif_vdev_t', 'vdevice'), - ('unsigned int', 'status')) - -types.struct('blkif_be_vbd_grow_t', - ('domid_t' , 'domid'), #Q - ('unsigned int' , 'blkif_handle'), #I - ('blkif_vdev_t' , 'vdevice'), #H - ('blkif_extent_t', 'extent'), #HQQ - ('unsigned int' , 'status')) #I - -types.struct('blkif_be_vbd_shrink_t', - ('domid_t' , 'domid'), - ('unsigned int', 'blkif_handle'), - ('blkif_vdev_t', 'vdevice'), - ('unsigned int', 'status')) - -types.struct('blkif_be_driver_status_changed_t', - ('unsigned int', 'status'), - ('unsigned int', 'nr_interfaces')) - -types.struct('netif_fe_interface_status_changed_t', - ('unsigned int', 'handle'), - ('unsigned int', 'status'), - ('unsigned int', 'evtchn'), - ('u8[6]', 'mac')) - -types.struct('netif_fe_driver_status_changed_t', - ('unsigned int', 'status'), - ('unsigned int', 'nr_interfaces')) - -types.struct('netif_fe_interface_connect_t', - ('unsigned int', 'handle'), - ('unsigned long', 'tx_shmem_frame'), - ('unsigned long', 'rx_shmem_frame')) - -types.struct('netif_fe_interface_disconnect_t', - ('unsigned int', 'handle')) - -types.struct('netif_be_create_t', - ('domid_t' , 'domid'), - ('unsigned int', 'netif_handle'), - ('u8[6]' , 'mac'), - ('unsigned int', 'status')) - -types.struct('netif_be_destroy_t', - ('domid_t' , 'domid'), - ('unsigned int', 'netif_handle'), - ('unsigned int', 'status')) - -types.struct('netif_be_connect_t', - ('domid_t' , 'domid'), - ('unsigned int' , 'netif_handle'), - ('unsigned int' , 'evtchn'), - ('unsigned long', 'tx_shmem_frame'), - ('unsigned long', 'rx_shmem_frame'), - ('unsigned int' , 'status')) - -types.struct('netif_be_disconnect_t', - ('domid_t' , 'domid'), - ('unsigned int', 'netif_handle'), - ('unsigned int', 'status')) - -types.struct('netif_be_driver_status_changed_t', - ('unsigned int', 'status'), - ('unsigned int', 'nr_interfaces')) - -if 1 or __name__ == "__main__": - types.show() diff --git a/tools/python/xen/xend/server/domain.py b/tools/python/xen/xend/server/domain.py index ab22234480..683d352ec0 100644 --- a/tools/python/xen/xend/server/domain.py +++ b/tools/python/xen/xend/server/domain.py @@ -1,3 +1,5 @@ +# Copyright (C) 2004 Mike Wray + import channel import controller from messages import * @@ -7,11 +9,23 @@ class DomainControllerFactory(controller.ControllerFactory): """ def createInstance(self, dom): + """Create a domain controller. + + dom domain + + returns domain controller + """ d = DomainController(self, dom) self.addInstance(d) return d def getInstanceByDom(self, dom): + """Get a domain controller for a domain, creating if necessary. + + dom domain + + returns domain controller + """ for inst in self.instances.values(): if inst.dom == dom: return inst @@ -21,8 +35,11 @@ class DomainControllerFactory(controller.ControllerFactory): class DomainController(controller.Controller): """Generic controller for a domain. + Used for domain shutdown. """ + """Map shutdown reasons to the message type to use. + """ reasons = {'poweroff' : 'shutdown_poweroff_t', 'reboot' : 'shutdown_reboot_t', 'suspend' : 'shutdown_suspend_t' } @@ -34,6 +51,10 @@ class DomainController(controller.Controller): print 'DomainController>', self, self.channel, self.idx def shutdown(self, reason): + """Shutdown a domain. + + reason shutdown reason + """ msgtype = self.reasons.get(reason) if not msgtype: raise ValueError('invalid reason:' + reason) diff --git a/tools/python/xen/xend/server/messages.py b/tools/python/xen/xend/server/messages.py index f3257ca832..edda5f2303 100644 --- a/tools/python/xen/xend/server/messages.py +++ b/tools/python/xen/xend/server/messages.py @@ -148,6 +148,9 @@ netif_formats = { msg_formats.update(netif_formats) #============================================================================ +# Domain shutdown message types. +#============================================================================ + CMSG_SHUTDOWN = 6 CMSG_SHUTDOWN_POWEROFF = 0 @@ -176,8 +179,23 @@ msg_formats.update(shutdown_formats) class Msg: pass +_next_msgid = 0 + +def nextid(): + global _next_msgid + return ++_next_msgid + def packMsg(ty, params): - if DEBUG: print '>packMsg', ty, params + """Pack a message. + Any 'mac' parameter is passed in as an int[6] array and converted. + + ty message type name + params message parameter dict + + returns xu message + """ + msgid = nextid() + if DEBUG: print '>packMsg', msgid, ty, params (major, minor) = msg_formats[ty] args = {} for (k, v) in params.items(): @@ -189,11 +207,19 @@ def packMsg(ty, params): if DEBUG: for (k, v) in args.items(): print 'packMsg>', k, v, type(v) - msgid = 0 msg = xu.message(major, minor, msgid, args) return msg def unpackMsg(ty, msg): + """Unpack a message. + Any mac addresses in the message are converted to int[6] array + in the return dict. + + ty message type + msg xu message + + returns parameter dict + """ args = msg.get_payload() mac = [0, 0, 0, 0, 0, 0] macs = [] @@ -208,10 +234,19 @@ def unpackMsg(ty, msg): args['mac'] = mac for k in macs: del args[k] - if DEBUG: print ' + import random from twisted.internet import defer +defer.Deferred.debug = 1 from xen.xend import sxp from xen.xend import PrettyPrint @@ -21,8 +24,8 @@ class NetifControllerFactory(controller.ControllerFactory): self.majorTypes = [ CMSG_NETIF_BE ] self.subTypes = { - CMSG_NETIF_BE_CREATE : self.recv_be_create, - CMSG_NETIF_BE_CONNECT: self.recv_be_connect, + #CMSG_NETIF_BE_CREATE : self.recv_be_create, + #CMSG_NETIF_BE_CONNECT: self.recv_be_connect, CMSG_NETIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed, } self.attached = 1 @@ -30,8 +33,12 @@ class NetifControllerFactory(controller.ControllerFactory): def createInstance(self, dom, recreate=0): """Create or find the network interface controller for a domain. + + dom domain + recreate if true this is a recreate (xend restarted) + + returns netif controller """ - #print 'netif>createInstance> dom=', dom netif = self.getInstanceByDom(dom) if netif is None: netif = NetifController(self, dom) @@ -39,15 +46,31 @@ class NetifControllerFactory(controller.ControllerFactory): return netif def getDomainDevices(self, dom): + """Get the network device controllers for a domain. + + dom domain + + returns netif controller + """ netif = self.getInstanceByDom(dom) return (netif and netif.getDevices()) or [] def getDomainDevice(self, dom, vif): + """Get a virtual network interface device for a domain. + + dom domain + vif virtual interface index + + returns NetDev + """ netif = self.getInstanceByDom(dom) return (netif and netif.getDevice(vif)) or None def setControlDomain(self, dom, recreate=0): """Set the 'back-end' device driver domain. + + dom domain + recreate if true this is a recreate (xend restarted) """ if self.dom == dom: return self.deregisterChannel() @@ -55,19 +78,13 @@ class NetifControllerFactory(controller.ControllerFactory): self.attached = 0 self.dom = dom self.registerChannel() - # - #if xend.netif.be_port.remote_dom != 0: - # xend.netif.recovery = True - # xend.netif.be_port = xend.main.port_from_dom(dom) - # def getControlDomain(self): + """Get the domain id of the back-end control domain. + """ return self.dom - def recv_be_create(self, msg, req): - self.callDeferred(0) - - def recv_be_connect(self, msg, req): + def respond_be_connect(self, msg): val = unpackMsg('netif_be_connect_t', msg) dom = val['domid'] vif = val['netif_handle'] @@ -75,7 +92,7 @@ class NetifControllerFactory(controller.ControllerFactory): if netif: netif.send_interface_connected(vif) else: - print "recv_be_connect> unknown vif=", vif + print "respond_be_connect> unknown vif=", vif pass def recv_be_driver_status_changed(self, msg, req): @@ -88,23 +105,6 @@ class NetifControllerFactory(controller.ControllerFactory): netif.reattach_devices() self.attached = 1 -## pl = msg.get_payload() -## status = pl['status'] -## if status == NETIF_DRIVER_STATUS_UP: -## if xend.netif.recovery: -## print "New netif backend now UP, notifying guests:" -## for netif_key in interface.list.keys(): -## netif = interface.list[netif_key] -## netif.create() -## print " Notifying %d" % netif.dom -## msg = xu.message( -## CMSG_NETIF_FE, -## CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED, 0, -## { 'handle' : 0, 'status' : 1 }) -## netif.ctrlif_tx_req(xend.main.port_from_dom(netif.dom),msg) -## print "Done notifying guests" -## recovery = False - class NetDev(controller.Dev): """Info record for a network device. """ @@ -130,9 +130,13 @@ class NetDev(controller.Dev): return val def get_vifname(self): + """Get the virtual interface device name. + """ return "vif%d.%d" % (self.controller.dom, self.vif) def get_mac(self): + """Get the MAC address as a string. + """ return ':'.join(map(lambda x: "%x" % x, self.mac)) def vifctl_params(self): @@ -141,23 +145,31 @@ class NetDev(controller.Dev): 'ipaddr': self.ipaddr } def up(self, bridge=None, ipaddr=[]): + """Bring the device up. + + bridge ethernet bridge to connect to + ipaddr list of ipaddrs to filter using iptables + """ self.bridge = bridge self.ipaddr = ipaddr Vifctl.up(self.get_vifname(), **self.vifctl_params()) def down(self): + """Bring the device down. + """ Vifctl.down(self.get_vifname(), **self.vifctl_params()) def destroy(self): + """Destroy the device's resources and disconnect from the back-end + device controller. + """ def cb_destroy(val): self.controller.send_be_destroy(self.vif) - print 'NetDev>destroy>', 'vif=', self.vif - PrettyPrint.prettyprint(self.sxpr()) self.down() - d = self.controller.factory.addDeferred() + #d = self.controller.factory.addDeferred() + d = defer.Deferred() d.addCallback(cb_destroy) - self.controller.send_be_disconnect(self.vif) - #self.controller.send_be_destroy(self.vif) + self.controller.send_be_disconnect(self.vif, response=d) class NetifController(controller.Controller): @@ -165,7 +177,6 @@ class NetifController(controller.Controller): """ def __init__(self, factory, dom): - #print 'NetifController> dom=', dom controller.Controller.__init__(self, factory, dom) self.devices = {} @@ -178,21 +189,23 @@ class NetifController(controller.Controller): self.recv_fe_interface_connect, } self.registerChannel() - #print 'NetifController<', 'dom=', self.dom, 'idx=', self.idx def sxpr(self): val = ['netif', ['dom', self.dom]] return val def randomMAC(self): - # VIFs get a random MAC address with a "special" vendor id. - # - # NB. The vendor is currently an "obsolete" one that used to belong - # to DEC (AA-00-00). Using it is probably a bit rude :-) - # - # NB2. The first bit of the first random octet is set to zero for - # all dynamic MAC addresses. This may allow us to manually specify - # MAC addresses for some VIFs with no fear of clashes. + """Generate a random MAC address. + + Uses OUI (Organizationally Unique Identifier) AA:00:00, an + unassigned one that used to belong to DEC. The OUI list is + available at 'standards.ieee.org'. + + The remaining 3 fields are random, with the first bit of the first + random field set 0. + + returns array of 6 ints + """ mac = [ 0xaa, 0x00, 0x00, random.randint(0x00, 0x7f), random.randint(0x00, 0xff), @@ -200,29 +213,46 @@ class NetifController(controller.Controller): return mac def lostChannel(self): - print 'NetifController>lostChannel>', 'dom=', self.dom - #self.destroyDevices() + """Method called when the channel has been lost. + """ controller.Controller.lostChannel(self) def getDevices(self): + """Get a list of the devices. + """ return self.devices.values() def getDevice(self, vif): + """Get a device. + + vif device index + + returns device (or None) + """ return self.devices.get(vif) def addDevice(self, vif, vmac): + """Add a network interface. If vmac is None a random MAC is + assigned. If specified, vmac must be a string of the form + XX:XX:XX:XX:XX where X is hex digit. + + vif device index + vmac device MAC + + returns device + """ if vmac is None: mac = self.randomMAC() else: mac = [ int(x, 16) for x in vmac.split(':') ] if len(mac) != 6: raise ValueError("invalid mac") - #print "attach_device>", "vif=", vif, "mac=", mac dev = NetDev(self, vif, mac) self.devices[vif] = dev return dev def destroy(self): - print 'NetifController>destroy>', 'dom=', self.dom + """Destroy the controller and all devices. + """ self.destroyDevices() def destroyDevices(self): @@ -237,20 +267,19 @@ class NetifController(controller.Controller): @param vmac mac address (string) """ self.addDevice(vif, vmac) + d = defer.Deferred() if recreate: - d = defer.Deferred() d.callback(self) else: - d = self.factory.addDeferred() - self.send_be_create(vif) + self.send_be_create(vif, response=d) return d def reattach_devices(self): """Reattach all devices when the back-end control domain has changed. """ - d = self.factory.addDeferred() + #d = self.factory.addDeferred() self.send_be_create(vif) - self.attach_fe_devices(0) + self.attach_fe_devices() def attach_fe_devices(self): for dev in self.devices.values(): @@ -279,38 +308,39 @@ class NetifController(controller.Controller): 'evtchn' : dev.evtchn['port1'], 'tx_shmem_frame' : val['tx_shmem_frame'], 'rx_shmem_frame' : val['rx_shmem_frame'] }) - self.factory.writeRequest(msg) + d = defer.Deferred() + d.addCallback(self.factory.respond_be_connect) + self.factory.writeRequest(msg, response=d) - def send_interface_connected(self, vif): + def send_interface_connected(self, vif, response=None): dev = self.devices[vif] msg = packMsg('netif_fe_interface_status_changed_t', { 'handle' : dev.vif, 'status' : NETIF_INTERFACE_STATUS_CONNECTED, 'evtchn' : dev.evtchn['port2'], 'mac' : dev.mac }) - self.writeRequest(msg) + self.writeRequest(msg, response=response) - def send_be_create(self, vif): + def send_be_create(self, vif, response=None): dev = self.devices[vif] msg = packMsg('netif_be_create_t', { 'domid' : self.dom, 'netif_handle' : dev.vif, 'mac' : dev.mac }) - self.factory.writeRequest(msg) + self.factory.writeRequest(msg, response=response) - def send_be_disconnect(self, vif): + def send_be_disconnect(self, vif, response=None): dev = self.devices[vif] msg = packMsg('netif_be_disconnect_t', { 'domid' : self.dom, 'netif_handle' : dev.vif }) - self.factory.writeRequest(msg) + self.factory.writeRequest(msg, response=response) - def send_be_destroy(self, vif): - print 'NetifController>send_be_destroy>', 'dom=', self.dom, 'vif=', vif + def send_be_destroy(self, vif, response=None): PrettyPrint.prettyprint(self.sxpr()) dev = self.devices[vif] del self.devices[vif] msg = packMsg('netif_be_destroy_t', { 'domid' : self.dom, 'netif_handle' : vif }) - self.factory.writeRequest(msg) + self.factory.writeRequest(msg, response=response) diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index 7819243adb..cf82d075f9 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -1,4 +1,5 @@ # Copyright (C) 2004 Mike Wray + """Domain creation. """ import string @@ -12,15 +13,25 @@ from xen.util import console_client from xen.xm.opts import * -gopts = Opts(use="""[options] +gopts = Opts(use="""[options] [vars] Create a domain. + +Domain creation parameters can be set by command-line switches, from +a python configuration script or an SXP config file. See documentation +for --defaults, --config. Configuration variables can be set using +VAR=VAL on the command line. For example vmid=3 sets vmid to 3. + """) gopts.opt('help', short='h', fn=set_true, default=0, use="Print this help.") +gopts.opt('help_config', + fn=set_true, default=0, + use="Print help for configuration file.") + gopts.opt('quiet', short='q', fn=set_true, default=0, use="Quiet.") @@ -31,58 +42,73 @@ gopts.opt('path', val='PATH', gopts.opt('defaults', short='f', val='FILE', fn=set_value, default='xmdefaults', - use="Use the given default script.") + use="""Use the given Python defaults script. +The defaults script is loaded after arguments have been processed. +Each command-line option sets a configuration variable named after +its long option name, and these variables are placed in the +environment of the script before it is loaded. +Variables for options that may be repeated have list values. +Other variables can be set using VAR=VAL on the command line. + +After the script is loaded, option values that were not set on the +command line are replaced by the values set in the script. +""") gopts.opt('config', short='F', val='FILE', fn=set_value, default=None, - use='Domain configuration to use (SXP).') + use="""Domain configuration to use (SXP). +SXP is the underlying configuration format used by Xen. +SXP configs can be hand-written or generated from Python defaults +scripts, using the -n (dryrun) option to print the config. +""") gopts.opt('load', short='L', val='FILE', fn=set_value, default=None, use='Domain saved state to load.') -gopts.opt('define', short='D', val='VAR=VAL', - fn=set_var, default=None, - use="""Set a variable before loading defaults, e.g. '-D vmid=3' - to set vmid. May be repeated to set more thanone variable.""") - gopts.opt('dryrun', short='n', fn=set_true, default=0, - use="Dry run - print the config but don't create the domain.") - -gopts.opt('name', short='N', val='NAME', - fn=set_value, default=None, - use="Domain name.") + use="""Dry run - print the config but don't create the domain. +The defaults file is loaded and the SXP configuration is created and printed. +""") gopts.opt('console_autoconnect', short='c', fn=set_true, default=0, use="Connect to console after domain is created.") -gopts.opt('kernel', short='k', val='FILE', +gopts.var('name', val='NAME', + fn=set_value, default=None, + use="Domain name.") + +gopts.var('kernel', val='FILE', fn=set_value, default=None, use="Path to kernel image.") -gopts.opt('ramdisk', short='r', val='FILE', +gopts.var('ramdisk', val='FILE', fn=set_value, default='', use="Path to ramdisk.") -gopts.opt('builder', short='b', val='FUNCTION', +gopts.var('builder', val='FUNCTION', fn=set_value, default='linux', use="Function to use to build the domain.") -gopts.opt('memory', short='m', val='MEMORY', +gopts.var('memory', val='MEMORY', fn=set_value, default=128, use="Domain memory in MB.") -gopts.opt('blkif', - fn=set_true, default=0, +gopts.var('autorestart', val='no|yes', + fn=set_bool, default=0, + use="Whether to restart the domain on exit.") + +gopts.var('blkif', val='no|yes', + fn=set_bool, default=0, use="Make the domain a block device backend.") -gopts.opt('netif', - fn=set_true, default=0, +gopts.var('netif', val='no|yes', + fn=set_bool, default=0, use="Make the domain a network interface backend.") -gopts.opt('disk', short='d', val='phy:DEV,VDEV,MODE', +gopts.var('disk', val='phy:DEV,VDEV,MODE', fn=append_value, default=[], use="""Add a disk device to a domain. The physical device is DEV, which is exported to the domain as VDEV. The disk is read-only if MODE @@ -90,18 +116,18 @@ gopts.opt('disk', short='d', val='phy:DEV,VDEV,MODE', The option may be repeated to add more than one disk. """) -gopts.opt('pci', val='BUS,DEV,FUNC', +gopts.var('pci', val='BUS,DEV,FUNC', fn=append_value, default=[], use="""Add a PCI device to a domain, using given params (in hex). For example '-pci c0,02,1a'. The option may be repeated to add more than one pci device. """) -gopts.opt('ipaddr', short='i', val="IPADDR", +gopts.var('ipaddr', val="IPADDR", fn=append_value, default=[], use="Add an IP address to the domain.") -gopts.opt('vif', val="mac=MAC,bridge=BRIDGE", +gopts.var('vif', val="mac=MAC,bridge=BRIDGE", fn=append_value, default=[], use="""Add a network interface with the given MAC address and bridge. If mac is not specified a random MAC address is used. @@ -110,7 +136,7 @@ gopts.opt('vif', val="mac=MAC,bridge=BRIDGE", Specifying vifs will increase the number of interfaces as needed. """) -gopts.opt('nics', val="NUM", +gopts.var('nics', val="NUM", fn=set_int, default=1, use="""Set the number of network interfaces. Use the vif option to define interface parameters, otherwise @@ -118,44 +144,44 @@ gopts.opt('nics', val="NUM", number of interfaces as needed. """) -gopts.opt('root', short='R', val='DEVICE', +gopts.var('root', val='DEVICE', fn=set_value, default='', use="""Set the root= parameter on the kernel command line. Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""") -gopts.opt('extra', short='E', val="ARGS", +gopts.var('extra', val="ARGS", fn=set_value, default='', use="Set extra arguments to append to the kernel command line.") -gopts.opt('ip', short='I', val='IPADDR', +gopts.var('ip', val='IPADDR', fn=set_value, default='', use="Set the kernel IP interface address.") -gopts.opt('gateway', val="IPADDR", +gopts.var('gateway', val="IPADDR", fn=set_value, default='', use="Set the kernel IP gateway.") -gopts.opt('netmask', val="MASK", +gopts.var('netmask', val="MASK", fn=set_value, default = '', use="Set the kernel IP netmask.") -gopts.opt('hostname', val="NAME", +gopts.var('hostname', val="NAME", fn=set_value, default='', use="Set the kernel IP hostname.") -gopts.opt('interface', val="INTF", +gopts.var('interface', val="INTF", fn=set_value, default="eth0", use="Set the kernel IP interface name.") -gopts.opt('dhcp', val="off|dhcp", +gopts.var('dhcp', val="off|dhcp", fn=set_value, default='off', use="Set the kernel dhcp option.") -gopts.opt('nfs_server', val="IPADDR", +gopts.var('nfs_server', val="IPADDR", fn=set_value, default=None, use="Set the address of the NFS server for NFS root.") -gopts.opt('nfs_root', val="PATH", +gopts.var('nfs_root', val="PATH", fn=set_value, default=None, use="Set the path of the root NFS directory.") @@ -244,6 +270,8 @@ def make_config(opts): config.append(['backend', ['blkif']]) if opts.netif: config.append(['backend', ['netif']]) + if opts.autorestart: + config.append(['autorestart']) configure_image(config, opts) config_devs = [] @@ -282,7 +310,7 @@ def preprocess_vifs(opts): d = {} a = vif.split(',') for b in a: - (k, v) = b.strip().split('=') + (k, v) = b.strip().split('=', 1) k = k.strip() v = v.strip() if k not in ['mac', 'bridge']: @@ -352,7 +380,15 @@ def main(argv): args = opts.parse(argv) if opts.vals.help: opts.usage() + if opts.vals.help or opts.vals.help_config: + opts.load_defaults(help=1) + if opts.vals.help or opts.vals.help_config: return + # Process remaining args as config variables. + for arg in args: + if '=' in arg: + (var, val) = arg.strip().split('=', 1) + gopts.setvar(var.strip(), val.strip()) if opts.vals.config: pass else: diff --git a/tools/python/xen/xm/help.py b/tools/python/xen/xm/help.py new file mode 100644 index 0000000000..88df4412c0 --- /dev/null +++ b/tools/python/xen/xm/help.py @@ -0,0 +1,82 @@ +# Copyright (C) 2004 Mike Wray + +"""Variable definition and help support for Python defaults files. +""" + +import sys + +class Vars: + """A set of configuration variables. + """ + + def __init__(self, name, help, env): + """Create a variable set. + + name name of the defaults file + help help flag + env local environment + """ + self.name = name + self.help = help + self.env = env + self.vars = [] + + def var(self, name, use=None, check=None): + """Define a configuration variable. + If provided, the check function will be called as check(var, val) + where var is the variable name and val is its value (string). + It should return a new value for the variable, or raise ValueError if + the value is not acceptable. + + name variable name + use variable usage string + check variable check function + """ + self.vars.append(Var(name, use, check)) + + def check(self): + """Execute the variable checks or print help, depending on the value + of the help flag passed to the constructor. + """ + if self.help: + self.doHelp() + else: + for v in self.vars: + v.doCheck(self.env) + + def doHelp(self, out=sys.stderr): + """Print help for the variables. + """ + if self.vars: + print >>out, "\nConfiguration variables for %s:\n" % self.name + for v in self.vars: + v.doHelp(out) + print >>out + +class Var: + """A single variable. + """ + + def __init__(self, name, use, check): + """Create a variable. + + name variable name + use variable use string + check variable value check function + """ + self.name = name + self.use = use or '' + self.check = check + + def doCheck(self, env): + """Execute the check and set the variable to the new value. + """ + if not self.check: return + env[self.name] = self.check(self.name, env.get(self.name)) + + def doHelp(self, out): + """Print help for the variable. + """ + print >>out, "%-12s" % self.name, self.use + + diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index 4e8f5b68a3..8f0cdb247e 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -5,10 +5,12 @@ import os import os.path import sys from getopt import getopt +import socket from xen.xend import PrettyPrint from xen.xend import sxp from xen.xend.XendClient import server +from xen.xend.XendClient import main as xend_client_main from xen.xm import create, shutdown class Prog: @@ -65,6 +67,13 @@ class Xm: sys.exit(1) def main(self, args): + try: + self.main_call(args) + except socket.error, ex: + print >>sys.stderr, ex + self.err("Error connecting to xend, is xend running?") + + def main_call(self, args): """Main entry point. Dispatches to the progs. """ self.name = args[0] @@ -478,5 +487,21 @@ class ProgConsole(Prog): xm.prog(ProgConsole) +class ProgCall(Prog): + name = "call" + info = "Call xend api functions." + + def help (self, args): + print "call fn argss..." + print """ + Call a xend HTTP API function. The leading 'xend_' on the function +can be omitted. See xen.xend.XendClient for the API functions. +""" + + def main(self, args): + xend_client_main(args) + +xm.prog(ProgCall) + def main(args): xm.main(args) diff --git a/tools/python/xen/xm/opts.py b/tools/python/xen/xm/opts.py index eb07936f1e..325698875d 100644 --- a/tools/python/xen/xm/opts.py +++ b/tools/python/xen/xm/opts.py @@ -126,6 +126,42 @@ class Opt: """ return self.specified_opt +class OptVar(Opt): + """An individual option variable. + """ + def __init__(self, opts, name, + val=None, fn=None, use=None, default=None): + """Create an option. + + opts parent options object + name name of the field it controls + val string used to print option args in help. + If val is not specified the option has no arg. + fn function to call when the option is specified. + use usage (help) string + default default value if not specified on command-line + """ + if val is None: + val = name.upper() + Opt.__init__(self, opts, name, val=val, fn=fn, use=use, default=default) + self.optkeys = [] + self.optkeys.append(self.long) + + def short_opt(self): + return None + + def long_opt(self): + return None + + def show(self): + print '%s=%s' %(self.optkeys[0], self.val) + print + if self.use: + print '\t', + print self.use + if self.val: + print '\tDefault', self.default or 'None' + class OptVals: """Class to hold option values. """ @@ -134,6 +170,13 @@ class OptVals: class Opts: """Container for options. """ + + imports = ["import sys", + "import os", + "import os.path", + "from xen.util.ip import *", + ] + def __init__(self, use=None): """Options constructor. @@ -168,6 +211,12 @@ class Opts: self.options_map[name] = x return x + def var(self, name, **args): + x = OptVar(self, name, **args) + self.options.append(x) + self.options_map[name] = x + return x + def setvar(self, var, val): """Set a default script variable. """ @@ -232,7 +281,18 @@ class Opts: else: print >>sys.stderr, "Error: Unknown option:", k self.usage() - return args + xargs = [] + for arg in args: + isvar = 0 + if '=' in arg: + (k, v) = arg.split('=', 1) + for opt in self.options: + if opt.specify(k, v): + isvar = 1 + break + if not isvar: + xargs.append(arg) + return xargs def short_opts(self): """Get short options specifier for getopt. @@ -257,9 +317,10 @@ class Opts: def usage(self): print 'Usage: ', self.argv[0], self.use or 'OPTIONS' for opt in self.options: + print opt.show() - def load_defaults(self): + def load_defaults(self, help=0): """Load a defaults script. Assumes these options set: 'path' search path 'default' script name @@ -270,12 +331,12 @@ class Opts: else: p = self.vals.defaults if os.path.exists(p): - self.load(p) + self.load(p, help) break else: self.err("Cannot open defaults file %s" % self.vals.defaults) - def load(self, defaults, help=0): + def load(self, defaults, help): """Load a defaults file. Local variables in the file are used to set options with the same names. Variables are not used to set options that are already specified. @@ -287,15 +348,22 @@ class Opts: globals = {} locals = {} locals.update(self.vars) - cmd = '\n'.join(["import sys", - "import os", - "import os.path", - "import xen.util.ip", - "xm_file = '%s'" % defaults, - "xm_help = %d" % help ]) + cmd = '\n'.join(self.imports + + [ "from xen.xm.help import Vars", + "xm_file = '%s'" % defaults, + "xm_help = %d" % help, + "xm_vars = Vars(xm_file, xm_help, locals())" + ]) exec cmd in globals, locals - execfile(defaults, globals, locals) - if help: return + try: + execfile(defaults, globals, locals) + except: + if not help: raise + if help: + print 'The following imports are done automatically:' + for x in self.imports: + print x + return # Extract the values set by the script and set the corresponding # options, if not set on the command line. vtypes = [ types.StringType, @@ -316,6 +384,17 @@ def set_false(opt, k, v): """Set an option false.""" opt.set(0) +def set_bool(opt, k, v): + """Set a boolean option. + """ + if v in ['yes']: + opt.set(1) + elif v in ['no']: + opt.set(0) + else: + opt.opts.err('Invalid value:' +v) + + def set_value(opt, k, v): """Set an option to a valoue.""" opt.set(v) @@ -335,6 +414,6 @@ def append_value(opt, k, v): def set_var(opt, k, v): """Set a default script variable. """ - (var, val) = v.strip().split('=') + (var, val) = v.strip().split('=', 1) opt.opts.setvar(var.strip(), val.strip()) diff --git a/tools/python/xen/xm/shutdown.py b/tools/python/xen/xm/shutdown.py index aaa354554a..926aaf27f3 100644 --- a/tools/python/xen/xm/shutdown.py +++ b/tools/python/xen/xm/shutdown.py @@ -1,4 +1,5 @@ # Copyright (C) 2004 Mike Wray + """Domain shutdown. """ import string @@ -10,7 +11,8 @@ from xen.xm.opts import * gopts = Opts(use="""[options] [DOM] -Shutdown one or more domains gracefully.""") +Shutdown one or more domains gracefully. +""") gopts.opt('help', short='h', fn=set_true, default=0, @@ -24,18 +26,22 @@ gopts.opt('wait', short='w', fn=set_true, default=0, use='Wait for shutdown to complete.') -gopts.opt('norestart', short='n', +gopts.opt('halt', short='H', fn=set_true, default=0, - use='Prevent domain restart.') + use='Shutdown without reboot.') -def shutdown(opts, doms, wait): +gopts.opt('reboot', short='R', + fn=set_true, default=0, + use='Shutdown and reboot.') + +def shutdown(opts, doms, mode, wait): def domains(): return [ int(a) for a in server.xend_domains() ] if doms == None: doms = domains() if 0 in doms: doms.remove(0) for d in doms: - server.xend_domain_shutdown(d) + server.xend_domain_shutdown(d, mode) if wait: while doms: alive = domains() @@ -49,6 +55,21 @@ def shutdown(opts, doms, wait): time.sleep(1) opts.info("All domains terminated") +def shutdown_mode(opts): + mode = 'poweroff' + if opts.vals.wait: + mode = 'halt' + if opts.vals.reboot: + opts.err("Can't specify wait and reboot") + else: + if opts.vals.halt and opts.vals.reboot: + opts.err("Can't specify halt and reboot") + if opts.vals.halt: + mode = 'halt' + elif opts.vals.reboot: + mode = 'reboot' + return mode + def main_all(opts, args): shutdown(opts, None, opts.vals.wait) @@ -59,7 +80,9 @@ def main_dom(opts, args): domid = int(dom) except: opts.err('Invalid domain: ' + dom) - shutdown(opts, [ domid ], opts.vals.wait) + + mode = shutdown_mode(opts) + shutdown(opts, [ domid ], mode, opts.vals.wait) def main(argv): opts = gopts diff --git a/tools/xfrd/Make.xfrd b/tools/xfrd/Make.xfrd new file mode 100644 index 0000000000..39f3afd3c5 --- /dev/null +++ b/tools/xfrd/Make.xfrd @@ -0,0 +1,34 @@ +# -*- mode: Makefile; -*- +#============================================================================ + +UTIL_LIB = libutil.a + +UTIL_LIB_SRC = +UTIL_LIB_SRC += allocate.c +UTIL_LIB_SRC += enum.c +UTIL_LIB_SRC += file_stream.c +UTIL_LIB_SRC += gzip_stream.c +UTIL_LIB_SRC += hash_table.c +UTIL_LIB_SRC += iostream.c +UTIL_LIB_SRC += lexis.c +UTIL_LIB_SRC += lzi_stream.c +UTIL_LIB_SRC += marshal.c +UTIL_LIB_SRC += string_stream.c +UTIL_LIB_SRC += sxpr.c +#UTIL_LIB_SRC += sxpr_parser.c +UTIL_LIB_SRC += sys_net.c +UTIL_LIB_SRC += sys_string.c +#UTIL_LIB_SRC += util.c +UTIL_LIB_SRC += xdr.c + +#---------------------------------------------------------------------------- +# Xfrd. + +XFRD_PROG_SRC = +XFRD_PROG_SRC += xfrd.c +#XFRD_PROG_SRC += xfr_msg.c +XFRD_PROG_SRC += xen_domain.c +XFRD_PROG_SRC += select.c +XFRD_PROG_SRC += connection.c + +#============================================================================ diff --git a/tools/xfrd/Makefile b/tools/xfrd/Makefile new file mode 100644 index 0000000000..fe84120471 --- /dev/null +++ b/tools/xfrd/Makefile @@ -0,0 +1,68 @@ +# -*- mode: Makefile; -*- +#============================================================================ +# +# Mike Wray +#============================================================================ + +XEN_ROOT = ../.. +include $(XEN_ROOT)/tools/Make.defs + +XFRD_INSTALL_DIR = /usr/sbin + +vpath %.h $(XEN_HYPERVISOR_IFS) +INCLUDES += -I $(XEN_HYPERVISOR_IFS) + +vpath %h $(XEN_LINUX_INCLUDE) +INCLUDES += -I $(XEN_LINUX_INCLUDE) + +vpath %.h $(XEN_XU) +INCLUDES += -I $(XEN_XU) + +vpath %c $(XEN_LIBXUTIL) +INCLUDES += -I $(XEN_LIBXUTIL) + +include Make.xfrd + +UTIL_LIB_OBJ = $(UTIL_LIB_SRC:.c=.o) + +XFRD_PROG_OBJ = $(XFRD_PROG_SRC:.c=.o) +XFRD_PROG_OBJ += $(UTIL_LIB) + +CPPFLAGS += -D _XEN_XFR_STUB_ + +CFLAGS += -g +CFLAGS += -Wall +CFALGS += -Werror +CFLAGS += $(INCLUDES) +# Make gcc generate dependencies. +CFLAGS += -Wp,-MD,.$(@F).d +PROG_DEP = .*.d + +#LDFLAGS += -L $(COMPRESS_DIR) -lz + +$(warning XFRD_PROG_OBJ= $(XFRD_PROG_OBJ)) +$(warning UTIL_LIB= $(UTIL_LIB)) +$(warning UTIL_LIB_OBJ= $(UTIL_LIB_OBJ)) + +all: xfrd + +xfrd: $(XFRD_PROG_OBJ) -lz + +.PHONY: install +install: xfrd + mkdir -p $(prefix)/$(XFRD_INSTALL_DIR) + install -m 0755 xfrd $(prefix)/$(XFRD_INSTALL_DIR) + +.PHONY: libutil +libutil: $(UTIL_LIB) + +$(UTIL_LIB): $(UTIL_LIB_OBJ) + $(AR) rc $@ $^ + +.PHONY: clean +clean: + $(RM) *.o *.a *.so *~ xfrd + $(RM) $(PROG_DEP) + +-include $(PROG_DEP) + diff --git a/tools/xfrd/connection.c b/tools/xfrd/connection.c new file mode 100644 index 0000000000..26dca9968b --- /dev/null +++ b/tools/xfrd/connection.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include + +#include "connection.h" +#include "file_stream.h" +#include "lzi_stream.h" + +#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args) +#define wprintf(fmt, args...) fprintf(stderr, "[WARN] %s" fmt, __FUNCTION__, ##args) +#define iprintf(fmt, args...) fprintf(stdout, "[INFO] %s" fmt, __FUNCTION__, ##args) +#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] %s" fmt, __FUNCTION__, ##args) + +/** Compress magic header. */ +char compress_magic[2] = { 0x1f, 0x8b }; + +/** Plain magic header. */ +char plain_magic[2] = { 0x0, 0x0 }; + +int Conn_read_header(int sock, int *flags){ + int err = 0; + char magic[2] = {}; + int k, n = sizeof(magic); + k = read(sock, magic, n); + if(k != n){ + err = -EINVAL; + goto exit; + } + dprintf("> magic={ 0x%x, 0x%x }\n", magic[0], magic[1]); + if(magic[0] == compress_magic[0] && magic[1] == compress_magic[1]){ + *flags |= CONN_READ_COMPRESS; + dprintf("> Using compress read.\n"); + } else { + dprintf("> Using plain read.\n"); + } + exit: + return err; +} + +int Conn_write_header(int sock, int flags){ + int err = 0; + if(flags & CONN_WRITE_COMPRESS){ + dprintf("> Using compress write.\n"); + err = write(sock, compress_magic, 2); + } else { + dprintf("> Using plain write.\n"); + err = write(sock, plain_magic, 2); + } + if(err == 2) err = 0; + return err; +} + +/** Initialize a file stream from a file desciptor. + * + * @param fd file descriptor + * @param mode file mode + * @param flags control compression and buffering + * @param io return parameter for the stream + * @return 0 on success, error code otherwise + */ +int stream_init(int fd, const char *mode, int flags, int compress, IOStream **io){ + int err = 0; + dprintf(">mode=%s flags=%x compress=%d\n", mode, flags, compress); + if(compress){ + *io = lzi_stream_fdopen(fd, mode); + } else { + *io = file_stream_fdopen(fd, mode); + } + if(!*io){ + err = -errno; + perror("fdopen"); + goto exit; + } + if(1 && (flags & CONN_NOBUFFER)){ + // Make unbuffered. + dprintf("> unbuffer...\n"); + err = file_stream_setvbuf((compress ? lzi_stream_io(*io) : *io), NULL, _IONBF, 0); + if(err){ + err = -errno; + perror("setvbuf"); + goto exit; + } + } + exit: + if(err && *io){ + dprintf("> close err=%d\n", err); + IOStream_close(*io); + *io = NULL; + } + dprintf("< err=%d\n", err); + return err; +} + +/** Initialize a connection. + * + * @param conn connection + * @param flags + * @param sock socket + * @param ipaddr ip address + * @return 0 on success, error code otherwise + */ +int Conn_init(Conn *conn, int flags, int sock, struct sockaddr_in addr){ + int err = 0; + dprintf("> flags=%x\n", flags); + conn->addr = addr; + conn->sock = sock; + dprintf("> write stream...\n"); + err = stream_init(sock, "w", flags, (flags & CONN_WRITE_COMPRESS), &conn->out); + if(err) goto exit; + IOStream_flush(conn->out); + dprintf("> read stream...\n"); + err = stream_init(sock, "r", flags, (flags & CONN_READ_COMPRESS) , &conn->in); + if(err) goto exit; + exit: + if(err) eprintf("< err=%d\n", err); + return err; +} + +/** Open a connection. + * + * @param conn connection + * @param flags + * @param ipaddr ip address to connect to + * @param port port + * @return 0 on success, error code otherwise + */ +int Conn_connect(Conn *conn, int flags, struct in_addr ipaddr, uint16_t port){ + int err = 0; + int sock; + struct sockaddr_in addr_in; + struct sockaddr *addr = (struct sockaddr *)&addr_in; + socklen_t addr_n = sizeof(addr_in); + dprintf("> addr=%s:%d\n", inet_ntoa(ipaddr), ntohs(port)); + sock = socket(AF_INET, SOCK_STREAM, 0); + if(sock < 0){ + err = -errno; + goto exit; + } + addr_in.sin_family = AF_INET; + addr_in.sin_addr = ipaddr; + addr_in.sin_port = port; + err = connect(sock, addr, addr_n); + if(err) goto exit; + //err = Conn_write_header(sock, flags); + //if(err < 0) goto exit; + err = Conn_init(conn, flags, sock, addr_in); + exit: + if(err) eprintf("< err=%d\n", err); + return err; +} + +/** Close a connection. + * + * @param conn connection + */ +void Conn_close(Conn *conn){ + if(conn->in) IOStream_close(conn->in); + if(conn->out) IOStream_close(conn->out); + shutdown(conn->sock, 2); +} diff --git a/tools/xfrd/connection.h b/tools/xfrd/connection.h new file mode 100644 index 0000000000..790c01f1e8 --- /dev/null +++ b/tools/xfrd/connection.h @@ -0,0 +1,32 @@ +/* $Id: connection.h,v 1.1 2003/10/17 15:48:43 mjw Exp $ */ +#ifndef _VFC_CONNECTION_H_ +#define _VFC_CONNECTION_H_ + +#include + +#include "iostream.h" + +/** A connection. + * The underlying transport is a socket. + * Contains in and out streams using the socket. + */ +typedef struct Conn { + struct sockaddr_in addr; + int sock; + IOStream *in; + IOStream *out; +} Conn; + +enum { + CONN_NOBUFFER=1, + CONN_READ_COMPRESS=2, + CONN_WRITE_COMPRESS=4, +}; + +extern int Conn_read_header(int sock, int *flags); +extern int Conn_write_header(int sock, int flags); +extern int Conn_init(Conn *conn, int flags, int sock, struct sockaddr_in addr); +extern int Conn_connect(Conn *conn, int flags, struct in_addr ipaddr, uint16_t port); +extern void Conn_close(Conn *conn); + +#endif /* ! _VFC_CONNECTION_H_ */ diff --git a/tools/libxutil/debug.h b/tools/xfrd/debug.h similarity index 96% rename from tools/libxutil/debug.h rename to tools/xfrd/debug.h index 4f5228faa3..69a6b49937 100644 --- a/tools/libxutil/debug.h +++ b/tools/xfrd/debug.h @@ -15,8 +15,8 @@ * along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _XEN_LIB_DEBUG_H_ -#define _XEN_LIB_DEBUG_H_ +#ifndef _XUTIL_DEBUG_H_ +#define _XUTIL_DEBUG_H_ #ifndef MODULE_NAME #define MODULE_NAME "" @@ -69,4 +69,4 @@ */ #define IPFMT "%u.%u.%u.%u" -#endif /* ! _XEN_LIB_DEBUG_H_ */ +#endif /* ! _XUTIL_DEBUG_H_ */ diff --git a/tools/libxutil/enum.c b/tools/xfrd/enum.c similarity index 100% rename from tools/libxutil/enum.c rename to tools/xfrd/enum.c diff --git a/tools/libxutil/enum.h b/tools/xfrd/enum.h similarity index 92% rename from tools/libxutil/enum.h rename to tools/xfrd/enum.h index db6e7b0058..cdc0f6f1b1 100644 --- a/tools/libxutil/enum.h +++ b/tools/xfrd/enum.h @@ -15,8 +15,8 @@ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _XEN_LIB_ENUM_H_ -#define _XEN_LIB_ENUM_H_ +#ifndef _XUTIL_ENUM_H_ +#define _XUTIL_ENUM_H_ /** Mapping of an enum value to a name. */ typedef struct EnumDef { @@ -27,4 +27,4 @@ typedef struct EnumDef { extern int enum_name_to_val(char *name, EnumDef *defs); extern char *enum_val_to_name(int val, EnumDef *defs); -#endif /* _XEN_LIB_ENUM_H_ */ +#endif /* _XUTIL_ENUM_H_ */ diff --git a/tools/libxutil/hash_table.c b/tools/xfrd/hash_table.c similarity index 100% rename from tools/libxutil/hash_table.c rename to tools/xfrd/hash_table.c diff --git a/tools/libxutil/hash_table.h b/tools/xfrd/hash_table.h similarity index 98% rename from tools/libxutil/hash_table.h rename to tools/xfrd/hash_table.h index 6d7e76ff33..6608b49cda 100644 --- a/tools/libxutil/hash_table.h +++ b/tools/xfrd/hash_table.h @@ -1,4 +1,3 @@ -/* $Id: hash_table.h,v 1.1 2004/03/30 16:21:26 mjw Exp $ */ /* * Copyright (C) 2001 - 2004 Mike Wray * @@ -17,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _XEN_LIB_HASH_TABLE_H_ -#define _XEN_LIB_HASH_TABLE_H_ +#ifndef _XUTIL_HASH_TABLE_H_ +#define _XUTIL_HASH_TABLE_H_ #include "iostream.h" @@ -292,4 +291,4 @@ static inline Hashcode hash_hul(Hashcode a, unsigned long b){ */ #define HVAL(x) ((unsigned long)(x)) -#endif /* !_XEN_LIB_HASH_TABLE_H_ */ +#endif /* !_XUTIL_HASH_TABLE_H_ */ diff --git a/tools/libxutil/lexis.c b/tools/xfrd/lexis.c similarity index 100% rename from tools/libxutil/lexis.c rename to tools/xfrd/lexis.c diff --git a/tools/libxutil/lexis.h b/tools/xfrd/lexis.h similarity index 95% rename from tools/libxutil/lexis.h rename to tools/xfrd/lexis.h index 7d8fe7bc63..796a8a415a 100644 --- a/tools/libxutil/lexis.h +++ b/tools/xfrd/lexis.h @@ -14,11 +14,16 @@ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _SP_LEXIS_H_ -#define _SP_LEXIS_H_ +#ifndef _XUTIL_LEXIS_H_ +#define _XUTIL_LEXIS_H_ #include "sys_string.h" -#include "sys_ctype.h" + +#ifdef __KERNEL__ +# include +#else +# include +#endif /** @file * Lexical analysis. @@ -119,4 +124,4 @@ extern int is_hex_number(const char *s, int n); extern int is_keyword(const char *s, const char *k); extern int is_keychar(const char *s, char c); -#endif /* !_SP_LEXIS_H_ */ +#endif /* !_XUTIL_LEXIS_H_ */ diff --git a/tools/libxutil/lzi_stream.c b/tools/xfrd/lzi_stream.c similarity index 85% rename from tools/libxutil/lzi_stream.c rename to tools/xfrd/lzi_stream.c index 0f09734201..5fbec775c4 100644 --- a/tools/libxutil/lzi_stream.c +++ b/tools/xfrd/lzi_stream.c @@ -1,7 +1,3 @@ -/* $Id: lzi_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */ -#define __FILE_ID_INFO "$Id: lzi_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $" -#include -static char __rcsid[] __attribute__((unused)) = WHAT_ID __FILE_ID_INFO; /* * Copyright (C) 2003 Hewlett-Packard Company. * @@ -55,10 +51,8 @@ static char __rcsid[] __attribute__((unused)) = WHAT_ID __FILE_ID_INFO; #define iprintf(fmt, args...) fprintf(stdout, "[INFO] LZI>%s" fmt, __FUNCTION__, ##args) #define eprintf(fmt, args...) fprintf(stderr, "[ERROR] LZI>%s" fmt, __FUNCTION__, ##args) -static int lzi_read(IOStream *s, void *buf, size_t size, size_t count); -static int lzi_write(IOStream *s, const void *buf, size_t size, size_t count); -static int lzi_print(IOStream *s, const char *msg, va_list args); -static int lzi_getc(IOStream *s); +static int lzi_read(IOStream *s, void *buf, size_t n); +static int lzi_write(IOStream *s, const void *buf, size_t n); static int lzi_error(IOStream *s); static int lzi_close(IOStream *s); static void lzi_free(IOStream *s); @@ -71,10 +65,8 @@ enum { /** Methods used by a gzFile* IOStream. */ static const IOMethods lzi_methods = { - read: lzi_read, + read: lzi_read, write: lzi_write, - print: lzi_print, - getc: lzi_getc, error: lzi_error, close: lzi_close, free: lzi_free, @@ -151,7 +143,7 @@ static int mode_flags(const char *mode, int *flags){ * @return stream state. */ static inline LZIState * lzi_state(IOStream *io){ - return io->data; + return (LZIState*)io->data; } IOStream *lzi_stream_io(IOStream *io){ @@ -274,7 +266,7 @@ int read_block(LZIState *s){ int write_block(LZIState *s){ int err = 0; int k = ((char*)s->zstream.next_out) - ((char*)s->outbuf); - int k2 = s->outbuf_size - s->zstream.avail_out; + //int k2 = s->outbuf_size - s->zstream.avail_out; //dprintf("> k=%d k2=%d\n", k, k2); if(!k) goto exit; err = marshal_uint32(s->io, k); @@ -308,16 +300,14 @@ int write_terminator(LZIState *s){ * * @param io destination * @param buf data - * @param size size of data elements - * @param count number of data elements to write - * @return number of data elements written + * @param n number of bytes to write + * @return number of bytes written */ -static int lzi_write(IOStream *io, const void *buf, size_t size, size_t count){ +static int lzi_write(IOStream *io, const void *buf, size_t n){ int err = 0; - int n = size * count; LZIState *s = lzi_state(io); - //dprintf("> buf=%p size=%d count=%d n=%d\n", buf, size, count, n); + //dprintf("> buf=%p n=%d\n", buf, n); if(!LZIState_writeable(s)){ err = -EINVAL; goto exit; @@ -339,7 +329,6 @@ static int lzi_write(IOStream *io, const void *buf, size_t size, size_t count){ } err = n; s->plain_bytes += n; - if(size != 1) err /= size; exit: //dprintf("< err=%d\n", err); return err; @@ -350,16 +339,14 @@ static int lzi_write(IOStream *io, const void *buf, size_t size, size_t count){ * * @param io input * @param buf where to put input - * @param size size of data elements - * @param count number of data elements to read - * @return number of data elements read + * @param n number of bytes to read + * @return number of bytes read */ -static int lzi_read(IOStream *io, void *buf, size_t size, size_t count){ +static int lzi_read(IOStream *io, void *buf, size_t n){ int err, zerr; - int n = size * count; LZIState *s = lzi_state(io); - //dprintf("> size=%d count=%d n=%d\n", size, count, n); + //dprintf("> n=%d\n", n); if(!LZIState_readable(s)){ err = -EINVAL; goto exit; @@ -380,60 +367,16 @@ static int lzi_read(IOStream *io, void *buf, size_t size, size_t count){ } err = n - s->zstream.avail_out; s->plain_bytes += err; - if(size != 1) err /= size; exit: set_error(s, err); //dprintf("< err=%d\n", err); return err; } -/** Print to the underlying stream. - * Returns 0 if the formatted output is too big for the internal buffer. - * - * @param io lzi stream - * @param msg format to use - * @param args arguments - * @return result of the print - */ -static int lzi_print(IOStream *io, const char *msg, va_list args){ - char buf[1024]; - int buf_n = sizeof(buf); - int n; - LZIState *s = lzi_state(io); - if(!LZIState_writeable(s)){ - n = -EINVAL; - goto exit; - } - n = vsnprintf(buf, buf_n, (char*)msg, args); - if(n < 0) goto exit; - if(n > buf_n){ - n = 0; - } else { - n = lzi_write(io, buf, 1, n); - } - exit: - return n; -} - -/** Read a character from the underlying stream - * - * @param io lzi stream - * @return character read, IOSTREAM_EOF on end of file (or error) - */ -static int lzi_getc(IOStream *io){ - int err; - char c; - err = lzi_read(io, &c, 1, 1); - if(err < 1) c = EOF; - err = (c==EOF ? IOSTREAM_EOF : c); - return err; -} - static int flush_output(LZIState *s, int mode){ int err = 0, zerr; int done = 0; int avail_out_old; - int count = 10; //dprintf("> avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out); if(s->flushed == 1 + mode) goto exit; diff --git a/tools/libxutil/lzi_stream.h b/tools/xfrd/lzi_stream.h similarity index 89% rename from tools/libxutil/lzi_stream.h rename to tools/xfrd/lzi_stream.h index 0ad4f8db8e..959059eccf 100644 --- a/tools/libxutil/lzi_stream.h +++ b/tools/xfrd/lzi_stream.h @@ -1,4 +1,3 @@ -#/* $Id: lzi_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */ /* * Copyright (C) 2003 Hewlett-Packard Company. * @@ -17,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _SP_LZI_STREAM_H_ -#define _SP_LZI_STREAM_H_ +#ifndef _XUTIL_LZI_STREAM_H_ +#define _XUTIL_LZI_STREAM_H_ #ifndef __KERNEL__ #include "iostream.h" @@ -33,4 +32,4 @@ extern int lzi_stream_comp_bytes(IOStream *io); extern float lzi_stream_ratio(IOStream *io); #endif -#endif /* !_SP_FILE_STREAM_H_ */ +#endif /* !_XUTIL_LZI_STREAM_H_ */ diff --git a/tools/libxutil/marshal.c b/tools/xfrd/marshal.c similarity index 100% rename from tools/libxutil/marshal.c rename to tools/xfrd/marshal.c diff --git a/tools/libxutil/marshal.h b/tools/xfrd/marshal.h similarity index 90% rename from tools/libxutil/marshal.h rename to tools/xfrd/marshal.h index 9a9d465b9b..65e9682cea 100644 --- a/tools/libxutil/marshal.h +++ b/tools/xfrd/marshal.h @@ -1,6 +1,5 @@ -/* $Id: marshal.h,v 1.1 2003/10/17 15:48:43 mjw Exp $ */ -#ifndef _SP_MARSHAL_H_ -#define _SP_MARSHAL_H_ +#ifndef _XUTIL_MARSHAL_H_ +#define _XUTIL_MARSHAL_H_ #include "iostream.h" @@ -40,4 +39,4 @@ extern int marshal_string(IOStream *io, char *s, uint32_t s_n); extern int unmarshal_string(IOStream *io, char *s, uint32_t s_n); extern int unmarshal_new_string(IOStream *io, char **s, uint32_t *s_n); -#endif /* ! _SP_MARSHAL_H_ */ +#endif /* ! _XUTIL_MARSHAL_H_ */ diff --git a/tools/xfrd/select.c b/tools/xfrd/select.c new file mode 100644 index 0000000000..bdaccfe000 --- /dev/null +++ b/tools/xfrd/select.c @@ -0,0 +1,50 @@ +#include +#include +#include + +#include "select.h" + +/** Zero all the file descriptor sets. + * + * @param set select set + * @param fd file descriptor + * @return 0 on success, -1 otherwise + */ +void SelectSet_zero(SelectSet *set){ + set->n = 0; + FD_ZERO(&set->rd); + FD_ZERO(&set->wr); + FD_ZERO(&set->er); +} + +/** Add a file descriptor to the write set. + * + * @param set select set + * @param fd file descriptor + * @return 0 on success, -1 otherwise + */ +void SelectSet_add_read(SelectSet *set, int fd){ + FD_SET(fd, &set->rd); + if(fd > set->n) set->n = fd; +} + +/** Add a file descriptor to the write set. + * + * @param set select set + * @param fd file descriptor + * @return 0 on success, -1 otherwise + */ +void SelectSet_add_write(SelectSet *set, int fd){ + FD_SET(fd, &set->wr); + if(fd > set->n) set->n = fd; +} + +/** Select on file descriptors. + * + * @param set select set + * @param timeout timeout (may be NULL for no timeout) + * @return 0 on success, -1 otherwise + */ +int SelectSet_select(SelectSet *set, struct timeval *timeout){ + return select(set->n+1, &set->rd, &set->wr, &set->er, timeout); +} diff --git a/tools/xfrd/select.h b/tools/xfrd/select.h new file mode 100644 index 0000000000..2453f98536 --- /dev/null +++ b/tools/xfrd/select.h @@ -0,0 +1,16 @@ +#ifndef _XFRD_SELECT_H_ +#define _XFRD_SELECT_H_ + +/** Set of file descriptors for select. + */ +typedef struct SelectSet { + int n; + fd_set rd, wr, er; +} SelectSet; + +extern void SelectSet_zero(SelectSet *set); +extern void SelectSet_add_read(SelectSet *set, int fd); +extern void SelectSet_add_write(SelectSet *set, int fd); +extern int SelectSet_select(SelectSet *set, struct timeval *timeout); + +#endif /* ! _XFRD_SELECT_H_ */ diff --git a/tools/libxutil/sxpr.c b/tools/xfrd/sxpr.c similarity index 98% rename from tools/libxutil/sxpr.c rename to tools/xfrd/sxpr.c index adeffbe5eb..81fd14801c 100644 --- a/tools/libxutil/sxpr.c +++ b/tools/xfrd/sxpr.c @@ -757,7 +757,9 @@ int sxpr_is(Sxpr obj, char *s){ } int sxpr_elementp(Sxpr obj, Sxpr name){ - return CONSP(obj) && objequal(CAR(obj), name); + int ok = 0; + ok = CONSP(obj) && objequal(CAR(obj), name); + return ok; } /** Get the attributes of an sxpr. @@ -830,6 +832,19 @@ Sxpr sxpr_child0(Sxpr obj, Sxpr def){ return val; } +Sxpr sxpr_childN(Sxpr obj, int n, Sxpr def){ + Sxpr val = def; + Sxpr l; + int i; + for (i = 0, l = sxpr_children(obj); CONSP(l); i++, l = CDR(l)){ + if(i == n){ + val = CAR(l); + break; + } + } + return val; +} + Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def){ Sxpr val = ONONE; val = sxpr_child(obj, name, ONONE); diff --git a/tools/libxutil/sxpr.h b/tools/xfrd/sxpr.h similarity index 98% rename from tools/libxutil/sxpr.h rename to tools/xfrd/sxpr.h index b90083139c..a5875c76bd 100644 --- a/tools/libxutil/sxpr.h +++ b/tools/xfrd/sxpr.h @@ -13,8 +13,8 @@ * along with this library; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _XEN_LIB_SXPR_H_ -#define _XEN_LIB_SXPR_H_ +#ifndef _XUTIL_SXPR_H_ +#define _XUTIL_SXPR_H_ #include @@ -350,6 +350,7 @@ Sxpr sxpr_attributes(Sxpr obj); Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def); Sxpr sxpr_children(Sxpr obj); Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def); +Sxpr sxpr_childN(Sxpr obj, int n, Sxpr def); Sxpr sxpr_child0(Sxpr obj, Sxpr def); Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def); @@ -410,4 +411,4 @@ static inline Sxpr mkbool(int b){ #define c_concat_open '{' #define c_concat_close '}' -#endif /* ! _XEN_LIB_SXPR_H_ */ +#endif /* ! _XUTIL_SXPR_H_ */ diff --git a/tools/libxutil/xdr.c b/tools/xfrd/xdr.c similarity index 64% rename from tools/libxutil/xdr.c rename to tools/xfrd/xdr.c index dfb91f23c4..61dbe44ed6 100644 --- a/tools/libxutil/xdr.c +++ b/tools/xfrd/xdr.c @@ -1,13 +1,18 @@ -/* $Id: xdr.c,v 1.3 2003/09/29 13:40:00 mjw Exp $ */ -#include "xdr.h" #include +#include "xdr.h" + +#define MODULE_NAME "XDR" +//#define DEBUG 1 +#undef DEBUG +#include "debug.h" + /** @file * XDR packer/unpacker for elements. * - * string -> [T_STRING] [len:u32] - * atom -> [T_ATOM] [len:u32] + * string -> [T_STRING] [len:u16] + * atom -> [T_ATOM] [len:u16] * uint -> [T_UINT] [value] - * cons -> [T_CONS] + * cons -> [T_LIST] {1 elt}* 0 * null -> [T_NULL] * none -> [T_NONE] * bool -> [T_BOOL] { 0:u8 | 1:u8 } @@ -20,33 +25,40 @@ int pack_bool(IOStream *io, int x){ int err=0; + //dprintf("> x=%d\n", x); err = IOStream_print(io, "%c", 0xff & x); if(err > 0) err = 0; + //dprintf("< err=%d\n", err); return err; } int unpack_bool(IOStream *io, int *x){ int err = 0; int c; + //dprintf(">\n"); c = IOStream_getc(io); *x = (c < 0 ? 0 : c); err = IOStream_error(io); if(c < 0 && !err) err = -EIO; + //dprintf("< err=%d x=%d\n", err, *x); return err; } int pack_ushort(IOStream *io, unsigned short x){ int err=0; + //dprintf("> x=%u\n", x); err = IOStream_print(io, "%c%c", 0xff & (x >> 8), 0xff & (x )); if(err > 0) err = 0; + //dprintf("< err=%d\n", err); return err; } int unpack_ushort(IOStream *io, unsigned short *x){ int err = 0; int i, c = 0; + //dprintf(">\n"); *x = 0; for(i = 0; i< 2; i++){ c = IOStream_getc(io); @@ -55,24 +67,37 @@ int unpack_ushort(IOStream *io, unsigned short *x){ *x |= (0xff & c); } err = IOStream_error(io); + if(c < 0 && !err) err = -EIO; + //dprintf("< err=%d x=%u\n", err, *x); return err; } +int pack_type(IOStream *io, unsigned short x){ + return pack_ushort(io, x); +} + +int unpack_type(IOStream *io, unsigned short *x){ + return unpack_ushort(io, x); +} + int pack_uint(IOStream *io, unsigned int x){ int err=0; + //dprintf("> x=%u\n", x); err = IOStream_print(io, "%c%c%c%c", 0xff & (x >> 24), 0xff & (x >> 16), 0xff & (x >> 8), 0xff & (x )); if(err > 0) err = 0; + //dprintf("< err=%d\n", err); return err; } int unpack_uint(IOStream *io, unsigned int *x){ int err = 0; int i, c = 0; + //dprintf(">\n"); *x = 0; for(i = 0; i< 4; i++){ c = IOStream_getc(io); @@ -82,15 +107,17 @@ int unpack_uint(IOStream *io, unsigned int *x){ } err = IOStream_error(io); if(c < 0 && !err) err = -EIO; + //dprintf("< err=%d x=%u\n", err, *x); return err; } int pack_string(IOStream *io, Sxpr x){ int err = 0; - int n = string_length(x); + unsigned short n = 0xffff & string_length(x); char *s = string_string(x); int i; - err = pack_uint(io, n); + //dprintf("> n=%d s=%s\n", n, s); + err = pack_ushort(io, n); if(err) goto exit; for(i = 0; i < n; i++){ err = IOStream_print(io, "%c", s[i]); @@ -98,17 +125,19 @@ int pack_string(IOStream *io, Sxpr x){ } if(err > 0) err = 0; exit: + //dprintf("< err=%d\n", err); return err; } int unpack_string(IOStream *io, Sxpr *x){ int err; - unsigned int n; + unsigned short n; int i, c = 0; char *s; Sxpr val = ONONE; - err = unpack_uint(io, &n); + //dprintf(">\n"); + err = unpack_ushort(io, &n); if(err) goto exit; val = halloc(n+1, T_STRING); if(NOMEMP(val)){ @@ -130,50 +159,85 @@ int unpack_string(IOStream *io, Sxpr *x){ val = ONONE; } *x = val; + //IOStream_print(iostdout, "n=%d str=", n); + //objprint(iostdout, *x, 0); + //IOStream_print(iostdout, "\n"); + //dprintf("< err=%d\n", err); return err; } int pack_cons(IOStream *io, Sxpr x){ int err = 0; - err = pack_sxpr(io, CAR(x)); - if(err) goto exit; - err = pack_sxpr(io, CDR(x)); + Sxpr l; + //dprintf(">\n"); + for(l = x; CONSP(l); l = CDR(l)){ + err = pack_bool(io, 1); + if(err) goto exit; + err = pack_sxpr(io, CAR(l)); + if(err) goto exit; + } + err = pack_bool(io, 0); exit: + //dprintf("< err=%d\n", err); return err; } int unpack_cons(IOStream *io, Sxpr *x){ int err = 0; - Sxpr u = ONONE, v = ONONE, val = ONONE; - err = unpack_sxpr(io, &u); - if(err) goto exit; - err = unpack_sxpr(io, &v); - if(err) goto exit; - val = cons_new(u, v); - if(NOMEMP(val)){ - err = -ENOMEM; + int more = 0; + Sxpr u = ONONE, v = ONONE, val = ONULL; + + dprintf(">\n"); + while(1){ + err = unpack_bool(io, &more); + if(err) goto exit; + if(!more){ + //IOStream_print(iostdout, "unpack_cons 1 val="); + ////objprint(iostdout, val, 0); + IOStream_print(iostdout, "\n"); + + val = nrev(val); + + //IOStream_print(iostdout, "unpack_cons 2 val="); + //objprint(iostdout, val, 0); + //IOStream_print(iostdout, "\n"); + + break; + } + err = unpack_sxpr(io, &u); + if(err) goto exit; + v = cons_new(u, val); + if(NOMEMP(v)){ + err = -ENOMEM; + objfree(u); + goto exit; + } + val = v; } exit: if(err){ - objfree(u); - objfree(v); + objfree(val); val = ONONE; - } + } *x = val; + dprintf("< err=%d\n", err); return err; } - + int pack_sxpr(IOStream *io, Sxpr x){ int err = 0; unsigned short type = get_type(x); - err = pack_ushort(io, type); + //dprintf(">\n"); + //objprint(iostdout, x, 0); + //IOStream_print(iostdout, "\n"); + + err = pack_type(io, type); if(err) goto exit; switch(type){ case T_NULL: break; case T_NONE: break; - break; case T_BOOL: err = pack_bool(io, get_ul(x)); break; @@ -195,6 +259,7 @@ int pack_sxpr(IOStream *io, Sxpr x){ break; } exit: + //dprintf("< err=%d\n", err); return err; } @@ -204,7 +269,8 @@ int unpack_sxpr(IOStream *io, Sxpr *x){ unsigned int u; Sxpr val = ONONE, y; - err = unpack_ushort(io, &type); + //dprintf(">\n"); + err = unpack_type(io, &type); if(err) goto exit; switch(type){ case T_NULL: @@ -242,5 +308,9 @@ int unpack_sxpr(IOStream *io, Sxpr *x){ } exit: *x = (err ? ONONE : val); + //IOStream_print(iostdout, "sxpr="); + //objprint(iostdout, *x, 0); + //IOStream_print(iostdout, "\n"); + //dprintf("< err=%d\n", err); return err; } diff --git a/tools/libxutil/xdr.h b/tools/xfrd/xdr.h similarity index 59% rename from tools/libxutil/xdr.h rename to tools/xfrd/xdr.h index cb7d97df95..793cd34a29 100644 --- a/tools/libxutil/xdr.h +++ b/tools/xfrd/xdr.h @@ -1,14 +1,30 @@ -/* $Id: xdr.h,v 1.2 2003/09/29 13:40:00 mjw Exp $ */ -#ifndef _SP_XDR_H_ -#define _SP_XDR_H_ +#ifndef _XUTIL_XDR_H_ +#define _XUTIL_XDR_H_ #include "iostream.h" #include "sxpr.h" + +int pack_type(IOStream *io, unsigned short x); + +int unpack_type(IOStream *io, unsigned short *x); + +int pack_bool(IOStream *io, int x); + +int unpack_bool(IOStream *io, int *x); + int pack_uint(IOStream *out, unsigned int x); + int unpack_uint(IOStream *in, unsigned int *x); + int pack_string(IOStream *out, Sxpr x); + int unpack_string(IOStream *in, Sxpr *x); + int pack_cons(IOStream *out, Sxpr x); + int unpack_cons(IOStream *in, Sxpr *x); + int pack_sxpr(IOStream *out, Sxpr x); + int unpack_sxpr(IOStream *in, Sxpr *x); -#endif /* _SP_XDR_H_ */ + +#endif /* _XUTIL_XDR_H_ */ diff --git a/tools/xfrd/xen_domain.c b/tools/xfrd/xen_domain.c new file mode 100644 index 0000000000..5c5f7c5bef --- /dev/null +++ b/tools/xfrd/xen_domain.c @@ -0,0 +1,90 @@ +#include +#include +#include + +#ifndef _XEN_XFR_STUB_ +#include "dom0_defs.h" +#include "mem_defs.h" +#endif + +#include "xen_domain.h" +#include "marshal.h" +#include "xdr.h" + +#define MODULE_NAME "XFRD" +#define DEBUG 1 +#include "debug.h" + +/** Write domain state. + * + * At some point during this the domain is suspended, and then there's no way back. + * Even if something later goes wrong we can't restart the domain. + */ +int xen_domain_snd(Conn *xend, IOStream *io, uint32_t dom, char *vmconfig, int vmconfig_n){ + int err = 0; + char buf[1024]; + int n, k, d, buf_n; + dprintf("> dom=%d\n", dom); +#ifdef _XEN_XFR_STUB_ + err = marshal_uint32(io, dom); + if(err) goto exit; + err = marshal_string(io, vmconfig, vmconfig_n); + if(err) goto exit; + n = 32 * 1024 * 1024; + buf_n = sizeof(buf); + err = marshal_uint32(io, n); + for(k = 0; k < n; k += d){ + d = n - k; + if(d > buf_n) d = buf_n; + err = marshal_bytes(io, buf, d); + if(err) goto exit; + //dprintf("> k=%d n=%d\n", k, n); + } + + exit: +#else +#endif + dprintf("< err=%d\n", err); + return err; +} + +/** Receive domain state. + * Create a new domain and store the received state into it. + */ +int xen_domain_rcv(IOStream *io, uint32_t *dom, char **vmconfig, int *vmconfig_n){ + int err = 0; + char buf[1024]; + int n, k, d, buf_n; + dprintf(">\n"); +#ifdef _XEN_XFR_STUB_ + err = unmarshal_uint32(io, dom); + if(err) goto exit; + err = unmarshal_new_string(io, vmconfig, vmconfig_n); + if(err) goto exit; + err = unmarshal_uint32(io, &n); + buf_n = sizeof(buf); + for(k = 0; k < n; k += d){ + d = n - k; + if(d > buf_n) d = buf_n; + err = unmarshal_bytes(io, buf, d); + if(err) goto exit; + //dprintf("> k=%d n=%d\n", k, n); + } + exit: +#else +#endif + dprintf("< err=%d\n", err); + return err; +} + +/** Configure a new domain. Talk to xend. Use libcurl? + */ +int xen_domain_configure(uint32_t dom, char *vmconfig, int vmconfig_n){ + int err = 0; + dprintf(">\n"); +#ifdef _XEN_XFR_STUB_ +#else +#endif + dprintf("< err=%d\n", err); + return err; +} diff --git a/tools/xfrd/xen_domain.h b/tools/xfrd/xen_domain.h new file mode 100644 index 0000000000..4618c642b7 --- /dev/null +++ b/tools/xfrd/xen_domain.h @@ -0,0 +1,15 @@ +#ifndef _XFRD_XEN_DOMAIN_H_ +#define _XFRD_XEN_DOMAIN_H_ +#include +#include +#include "connection.h" + +/** Define to use stubs. Undefine to use Xen ops. */ +//#define _XEN_XFR_STUB_ + +extern int xen_domain_snd(Conn *xend, IOStream *io, uint32_t dom, char *vmconfig, int vmconfig_n); +extern int xen_domain_rcv(IOStream *io, uint32_t *dom, char **vmconfig, int *vmconfig_n); + + +extern int xen_domain_configure(uint32_t dom, char *vmconfig, int vmconfig_n); +#endif diff --git a/tools/xfrd/xfrd.c b/tools/xfrd/xfrd.c new file mode 100644 index 0000000000..1836231075 --- /dev/null +++ b/tools/xfrd/xfrd.c @@ -0,0 +1,1127 @@ +/** @file + * XFRD - Domain Transfer Daemon for Xen. + * + * The xfrd is forked by xend to transfer a vm to a remote system. + * + * The vm is suspended, then its state and memory are transferred to the remote system. + * The remote system attempts to create a vm and copy the transferred state and memory into it, + * finally resuming the vm. If all is OK the vm ends up running on the remote + * system and is removed from the originating system. If the transfer does not complete + * successfully the originating system attempts to resume the vm. + * The children exit when the transfer completes. + * + * @author Mike Wray + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "allocate.h" +#include "file_stream.h" +#include "string_stream.h" +#include "lzi_stream.h" +#include "sys_net.h" +#include "sys_string.h" + +#include "xdr.h" +#include "enum.h" +#include "xfrd.h" + +#include "xen_domain.h" + +#include "connection.h" +#include "select.h" + +#define MODULE_NAME "XFRD" +#define DEBUG 1 +#include "debug.h" + +/* +sender: + xend connects to xfrd and writes migrate message + xend writes domain config to xfrd + + xfrd forks + + xfrd connects to peer + xfrd sends hello, reads response + xfrd sends domain + xfrd reads response + reports progress/status to xend + + xend reads xfrd for progress/status, disconnects + If ok, destroys domain. + If not ok, unpauses domain. + +receiver: + xfrd accepts connection on inbound port + xfrd forks and accepts connection + xfrd receives hello, writes response + xfrd receives domain + xfrd connects to xend, configures new domain + xfrd writes status back to peer, child exits + + + (xfr.hello ) + (xfr.err ) + + xend->xfrd (xfr.migrate ) + (xfr.save ) + xfrd->xend (xfr.suspend ) + xfrd->xend (xfr.progress ) + xfrd->xend (xfr.err ) | (xfr.ok ) + xfrd->xfrd (xfr.xfr ) + xfrd->xfrd (xfr.err ) | (xfr.ok ) + + xfrd->xend (xfr.configure ) + */ + +Sxpr oxfr_configure; // (xfr.configure ) +Sxpr oxfr_err; // (xfr.err ) +Sxpr oxfr_hello; // (xfr.hello ) +Sxpr oxfr_migrate; // (xfr.migrate ) +Sxpr oxfr_ok; // (xfr.ok ) +Sxpr oxfr_progress; // (xfr.progress ) +Sxpr oxfr_save; // (xfr.save ) +Sxpr oxfr_suspend; // (xfr.suspend ) +Sxpr oxfr_xfr; // (xfr.xfr ) + +void xfr_init(void){ + oxfr_configure = intern("xfr.configure"); + oxfr_err = intern("xfr.err"); + oxfr_hello = intern("xfr.hello"); + oxfr_migrate = intern("xfr.migrate"); + oxfr_ok = intern("xfr.ok"); + oxfr_progress = intern("xfr.progress"); + oxfr_save = intern("xfr.save"); + oxfr_suspend = intern("xfr.suspend"); + oxfr_xfr = intern("xfr.xfr"); +} + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define PROGRAM "xfrd" + +#define OPT_PORT 'P' +#define KEY_PORT "port" +#define DOC_PORT "\n\txfr port (as a number or service name)" + +#define OPT_COMPRESS 'Z' +#define KEY_COMPRESS "compress" +#define DOC_COMPRESS "\n\tuse compression for migration" + +#define OPT_HELP 'h' +#define KEY_HELP "help" +#define DOC_HELP "\n\tprint help" + +#define OPT_VERSION 'v' +#define KEY_VERSION "version" +#define DOC_VERSION "\n\tprint version" + +#define OPT_VERBOSE 'V' +#define KEY_VERBOSE "verbose" +#define DOC_VERBOSE "\n\tverbose flag" + +/** Print a usage message. + * Prints to stdout if err is zero, and exits with 0. + * Prints to stderr if err is non-zero, and exits with 1. + */ +void usage(int err){ + FILE *out = (err ? stderr : stdout); + + fprintf(out, "Usage: %s [options]\n", PROGRAM); + fprintf(out, "-%c, --%s %s\n", OPT_PORT, KEY_PORT, DOC_PORT); + fprintf(out, "-%c, --%s %s\n", OPT_COMPRESS, KEY_COMPRESS, DOC_COMPRESS); + fprintf(out, "-%c, --%s %s\n", OPT_VERBOSE, KEY_VERBOSE, DOC_VERBOSE); + fprintf(out, "-%c, --%s %s\n", OPT_VERSION, KEY_VERSION, DOC_VERSION); + fprintf(out, "-%c, --%s %s\n", OPT_HELP, KEY_HELP, DOC_HELP); + exit(err ? 1 : 0); +} + +/** Short options. Options followed by ':' take an argument. */ +static char *short_opts = (char[]){ + OPT_PORT, ':', + OPT_COMPRESS, + OPT_HELP, + OPT_VERSION, + OPT_VERBOSE, + 0 }; + +/** Long options. */ +static struct option const long_opts[] = { + { KEY_PORT, required_argument, NULL, OPT_PORT }, + { KEY_COMPRESS, no_argument, NULL, OPT_COMPRESS }, + { KEY_HELP, no_argument, NULL, OPT_HELP }, + { KEY_VERSION, no_argument, NULL, OPT_VERSION }, + { KEY_VERBOSE, no_argument, NULL, OPT_VERBOSE }, + { NULL, 0, NULL, 0 } +}; + +typedef struct Args { + int bufsize; + unsigned long port; + int verbose; + int compress; +} Args; + +/** Transfer states. */ +enum { + XFR_INIT, + XFR_HELLO, + XFR_STATE, + XFR_RUN, + XFR_FAIL, + XFR_DONE, + XFR_MAX +}; + +/** Initialize an array element for a constant to its string name. */ +#define VALDEF(val) { val, #val } + +/** Names for the transfer states. */ +static EnumDef xfr_states[] = { + VALDEF(XFR_INIT), + VALDEF(XFR_HELLO), + VALDEF(XFR_STATE), + VALDEF(XFR_RUN), + VALDEF(XFR_FAIL), + VALDEF(XFR_DONE), + { 0, NULL } +}; + + +/** State machine for transfer. */ +typedef struct XfrState { + /** Current state. */ + int state; + /** Error codes for the states. */ + int state_err[XFR_MAX]; + /** First error. */ + int err; + /** State when first error happened. */ + int err_state; + + uint32_t vmid; + char* vmconfig; + int vmconfig_n; + unsigned long xfr_port; + char *xfr_host; + uint32_t vmid_new; +} XfrState; + +/** Get the name of a transfer state. + * + * @param s state + * @return name + */ +char * xfr_state_name(int s){ + return enum_val_to_name(s, xfr_states); +} + +/** Set the state of a transfer. + * + * @param s transfer + * @param state state + * @return state + */ +int XfrState_set_state(XfrState *s, int state){ + s->state = state; + return s->state; +} + +/** Get the state of a transfer. + * + * @param s transfer + * @return state + */ +int XfrState_get_state(XfrState *s){ + return s->state; +} + +/** Set an error in the current state. + * Does nothing if an error is already set. + * + * @param s transfer + * @param err error + * @return error + */ +int XfrState_set_err(XfrState *s, int err){ + if(!s->state_err[s->state]){ + s->state_err[s->state] = err; + } + if(!s->err){ + s->err = err; + s->err_state = s->state; + } + return err; +} + +/** Get the error in the current state. + * + * @param s transfer + * @return error + */ +int XfrState_get_err(XfrState *s){ + return s->state_err[s->state]; +} + +/** Get the first error of a transfer. + * + * @param s transfer + * @return error + */ +int XfrState_first_err(XfrState *s){ + return s->err; +} + +/** Get the state a transfer was in when it had its first error. + * + * @param s transfer + * @return error state + */ +int XfrState_first_err_state(XfrState *s){ + return s->err_state; +} + +/** Xfrd arguments. */ +static Args _args = {}; + +/** Xfrd arguments. */ +static Args *args = &_args; + +/** Set xfrd default arguments. + * + * @param args arguments to set + */ +void set_defaults(Args *args){ + args->compress = FALSE; + args->bufsize = 128 * 1024; + args->port = htons(XFRD_PORT); +} + +int stringof(Sxpr exp, char **s){ + int err = 0; + dprintf(">\n"); + objprint(iostdout, exp, PRINT_TYPE); IOStream_print(iostdout, "\n"); + if(ATOMP(exp)){ + *s = atom_name(exp); + } else if(STRINGP(exp)){ + *s = string_string(exp); + } else { + err = -EINVAL; + *s = NULL; + } + dprintf("< err=%d s=%s\n", err, *s); + return err; +} + +int intof(Sxpr exp, int *v){ + int err = 0; + char *s; + unsigned long l; + dprintf(">\n"); + objprint(iostdout, exp, 0); IOStream_print(iostdout, "\n"); + if(INTP(exp)){ + *v = OBJ_INT(exp); + } else { + err = stringof(exp, &s); + if(err) goto exit; + err = convert_atoul(s, &l); + *v = (int)l; + } + exit: + dprintf("< err=%d v=%d\n", err, *v); + return err; +} + +int addrof(Sxpr exp, uint32_t *v){ + char *h; + unsigned long a; + int err = 0; + dprintf(">\n"); + objprint(iostdout, exp, 0); IOStream_print(iostdout, "\n"); + err = stringof(exp, &h); + if(err) goto exit; + if(get_host_address(h, &a)){ + *v = a; + } else { + err = -EINVAL; + } + exit: + dprintf("< err=%d v=%x\n", err, *v); + return err; +} + +int portof(Sxpr exp, uint16_t *v){ + char *s; + int err = 0; + dprintf(">\n"); + objprint(iostdout, exp, 0); IOStream_print(iostdout, "\n"); + if(INTP(exp)){ + *v = get_ul(exp); + *v = htons(*v); + } else { + unsigned long p; + err = stringof(exp, &s); + if(err) goto exit; + if(get_service_port(s, &p)){ + *v = p; + } else { + err = -EINVAL; + } + } + exit: + dprintf("< err=%d v=%u\n", err, *v); + return err; +} + +static inline struct in_addr inaddr(uint32_t addr){ + return (struct in_addr){ .s_addr = addr }; +} + +time_t stats(time_t t0, uint64_t offset, uint64_t memory, float *percent, float *rate){ + time_t t1 = time(NULL); + *percent = (offset * 100.0f) / memory; + t1 = time(NULL) - t0; + *rate = (t1 ? offset/(t1 * 1024.0f) : 0.0f); + return t1; +} + +/** Notify success or error. + * + * @param conn connection + * @param errcode error code + * @return 0 on success, error code otherwise + */ +int xfr_error(Conn *conn, int errcode){ + int err = 0; + if(!conn->out) return -ENOTCONN; + err = pack_type(conn->out, T_CONS); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, oxfr_err); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, mkint(errcode)); + if(err) goto exit; + err = pack_bool(conn->out, 0); + exit: + return err; +} + +/** Read a response message - error or ok. + * + * @param conn connection + * @return 0 on success, error code otherwise + */ +int xfr_response(Conn *conn){ + int err; + Sxpr sxpr; + + dprintf(">\n"); + if(!conn->out) return -ENOTCONN; + err = unpack_sxpr(conn->in, &sxpr); + if(err) goto exit; + if(sxpr_elementp(sxpr, oxfr_err)){ + int errcode; + err = intof(sxpr_childN(sxpr, 0, ONONE), &errcode); + if(err) goto exit; + err = errcode; + } + exit: + dprintf("< err=%d\n", err); + return err; +} + +/** Get the initial hello message and check the protocol version. + * It is an error to receive anything other than a hello message + * with the correct protocol version. + * + * @param conn connection + * @return 0 on success, error code otherwise + */ +int xfr_hello(Conn *conn){ + int err; + uint32_t major = XFR_PROTO_MAJOR, minor = XFR_PROTO_MINOR; + uint32_t hello_major, hello_minor; + Sxpr sxpr; + if(!conn->in) return -ENOTCONN; + dprintf(">\n"); + err = unpack_sxpr(conn->in, &sxpr); + if(err) goto exit; + if(!sxpr_elementp(sxpr, oxfr_hello)){ + dprintf("> sxpr_elementp test failed\n"); + err = -EINVAL; + goto exit; + } + err = intof(sxpr_childN(sxpr, 0, ONONE), &hello_major); + if(err) goto exit; + err = intof(sxpr_childN(sxpr, 1, ONONE), &hello_minor); + if(err) goto exit; + if(hello_major != major || hello_minor != minor){ + eprintf("> Wanted protocol version %d.%d, got %d.%d", + major, minor, hello_major, hello_minor); + err = -EINVAL; + goto exit; + } + exit: + xfr_error(conn, err); + if(err){ + eprintf("> Hello failed: %d\n", err); + } + dprintf("< err=%d\n", err); + return err; +} + +/** Send the initial hello message. + * + * @param conn connection + * @param msg message + * @return 0 on success, error code otherwise + */ +int xfr_send_hello(Conn *conn){ + int err = 0; + dprintf(">\n"); + err = pack_type(conn->out, T_CONS); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, oxfr_hello); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, mkint(XFR_PROTO_MAJOR)); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, mkint(XFR_PROTO_MINOR)); + if(err) goto exit; + err = pack_bool(conn->out, 0); + IOStream_flush(conn->out); + dprintf("> xfr_response...\n"); + err = xfr_response(conn); + exit: + dprintf("< err=%d\n", err); + return err; +} + +int xfr_send_xfr(Conn *conn, uint32_t vmid){ + int err; + err = pack_type(conn->out, T_CONS); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, oxfr_xfr); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, mkint(vmid)); + if(err) goto exit; + err = pack_bool(conn->out, 0); + if(err) goto exit; + exit: + return err; +} + +int xfr_send_ok(Conn *conn, uint32_t vmid){ + int err = 0; + err = pack_type(conn->out, T_CONS); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, oxfr_ok); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, mkint(vmid)); + if(err) goto exit; + err = pack_bool(conn->out, 0); + exit: + return err; +} + +int xfr_send_suspend(Conn *conn, uint32_t vmid){ + int err = 0; + + err = pack_type(conn->out, T_CONS); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, oxfr_suspend); + if(err) goto exit; + err = pack_bool(conn->out, 1); + if(err) goto exit; + err = pack_sxpr(conn->out, mkint(vmid)); + if(err) goto exit; + err = pack_bool(conn->out, 0); + exit: + return err; +} + +/** Get vm state. Send transfer message. + * + * @param peer connection + * @param msg message + * @return 0 on success, error code otherwise + */ +int xfr_send_state(XfrState *state, Conn *xend, Conn *peer){ + int err = 0; + Sxpr sxpr; + + dprintf(">\n"); + XfrState_set_state(state, XFR_STATE); + // Send xfr message and the domain state. + err = xfr_send_xfr(peer, state->vmid); + if(err) goto exit; + err = xen_domain_snd(xend, peer->out, state->vmid, state->vmconfig, state->vmconfig_n); + if(err) goto exit; + IOStream_flush(peer->out); + // Read the response from the peer. + err = unpack_sxpr(peer->in, &sxpr); + if(err) goto exit; + if(sxpr_elementp(sxpr, oxfr_err)){ + // Error. + int errcode; + err = intof(sxpr_childN(sxpr, 0, ONONE), &errcode); + if(!err) err = errcode; + } else if(sxpr_elementp(sxpr, oxfr_ok)){ + // Ok - get the new domain id. + err = intof(sxpr_childN(sxpr, 0, ONONE), &state->vmid_new); + xfr_error(peer, err); + } else { + // Anything else is invalid. But it may be too late. + err = -EINVAL; + xfr_error(peer, err); + } + exit: + XfrState_set_err(state, err); + dprintf("< err=%d\n", err); + return err; +} + +/** Finish the transfer. + */ +int xfr_send_done(XfrState *state, Conn *xend){ + int err = 0; + int first_err = 0; + + first_err = XfrState_first_err(state); + if(first_err){ + XfrState_set_state(state, XFR_FAIL); + } else { + XfrState_set_state(state, XFR_DONE); + } + if(first_err){ + err = xfr_error(xend, first_err); + } else { + // Report new domain id to xend. + err = xfr_send_ok(xend, state->vmid_new); + } + + XfrState_set_err(state, err); + if(XfrState_first_err(state)){ + int s, serr; + + wprintf("> Transfer errors:\n"); + for(s = 0; s < XFR_MAX; s++){ + serr = state->state_err[s]; + if(!serr) continue; + wprintf("> state=%-12s err=%d\n", xfr_state_name(s), serr); + } + } else { + wprintf("> Transfer OK\n"); + } + dprintf("< err=%d\n", err); + return err; +} + +/** Migrate a vm to another node. + * + * @param xend connection + * @return 0 on success, error code otherwise + */ +int xfr_send(Args *args, XfrState *state, Conn *xend, uint32_t addr, uint32_t port){ + int err = 0; + Conn _peer = {}, *peer = &_peer; + int flags = 0; + struct in_addr xfr_addr; + uint16_t xfr_port; + time_t t0 = time(NULL), t1; + + dprintf(">\n"); + flags |= CONN_NOBUFFER; + if(args->compress){ + flags |= CONN_WRITE_COMPRESS; + } + xfr_addr.s_addr = addr; + xfr_port = port; + if(!xfr_port) xfr_port = htons(XFRD_PORT); + dprintf("> Xfr vmid=%u\n", state->vmid); + dprintf("> Xfr xfr_addr=%s:%d\n", inet_ntoa(xfr_addr), ntohs(xfr_port)); + err = Conn_connect(peer, flags, xfr_addr, xfr_port); + if(err) goto exit; + printf("\n"); + XfrState_set_state(state, XFR_HELLO); + // Send hello message. + err = xfr_send_hello(peer); + if(err) goto exit; + printf("\n"); + // Send vm state. + err = xfr_send_state(state, xend, peer); + if(err) goto exit; + if(args->compress){ + IOStream *zio = peer->out; + int plain_bytes = lzi_stream_plain_bytes(zio); + int comp_bytes = lzi_stream_comp_bytes(zio); + float ratio = lzi_stream_ratio(zio); + dprintf("> Compression: plain %d bytes, compressed %d bytes, ratio %3.2f\n", + plain_bytes, comp_bytes, ratio); + } + printf("\n"); + exit: + dprintf("> err=%d\n", err); + if(err && !XfrState_get_err(state)){ + XfrState_set_err(state, err); + } + Conn_close(peer); + if(!err){ + t1 = time(NULL) - t0; + dprintf("> Transfer complete in %lu seconds\n", t1); + } + dprintf("> done err=%d, notifying xend...\n", err); + xfr_send_done(state, xend); + dprintf("< err=%d\n", err); + return err; +} + +/** Save a vm to file. + */ +int xfr_save(Args *args, XfrState *state, Conn *xend, char *file){ + int err = 0; + IOStream *io = NULL; + + io = file_stream_fopen(file, "wb"); + if(!io){ + err = -EIO; + goto exit; + } + err = xen_domain_snd(xend, io, state->vmid, state->vmconfig, state->vmconfig_n); + exit: + if(io){ + IOStream_close(io); + IOStream_free(io); + } + return err; +} + +/** Accept the transfer of a vm from another node. + * + * @param peer connection + * @param msg message + * @return 0 on success, error code otherwise + */ +int xfr_recv(Args *args, XfrState *state, Conn *peer){ + int err = 0; + time_t t0 = time(NULL), t1; + + dprintf(">\n"); + err = xen_domain_rcv(peer->in, &state->vmid_new, &state->vmconfig, &state->vmconfig_n); + if(err) goto exit; + + err = xen_domain_configure(state->vmid_new, state->vmconfig, state->vmconfig_n); + if(err) goto exit; + + // Report new domain id to peer. + err = xfr_send_ok(peer, state->vmid_new); + if(err) goto exit; + // Get the final ok. + err = xfr_response(peer); + exit: + if(!err){ + t1 = time(NULL) - t0; + dprintf("> Transfer complete in %lu seconds\n", t1); + } + if(err){ + xfr_error(peer, err); + } + dprintf("< err=%d\n", err); + return err; +} + +/** Listen for a hello followed by a service request. + * The request can be from the local xend or from xfrd on another node. + * + * @param peersock socket + * @param peer_in peer address + * @return 0 on success, error code otherwise + */ +int xfrd_service(Args *args, int peersock, struct sockaddr_in peer_in){ + int err = 0; + Sxpr sxpr; + Conn _conn = {}, *conn = &_conn; + int flags = CONN_NOBUFFER; + + dprintf(">\n"); + err = Conn_init(conn, flags, peersock, peer_in); + if(err) goto exit; + err = xfr_hello(conn); + if(err) goto exit; + err = unpack_sxpr(conn->in, &sxpr); + if(err) goto exit; + if(sxpr_elementp(sxpr, oxfr_migrate)){ + // Migrate message from xend. + uint32_t addr; + uint16_t port; + XfrState _state = {}, *state = &_state; + int n = 0; + + dprintf("> xfr.migrate\n"); + err = intof(sxpr_childN(sxpr, n++, ONONE), &state->vmid); + if(err) goto exit; + err = stringof(sxpr_childN(sxpr, n++, ONONE), &state->vmconfig); + if(err) goto exit; + state->vmconfig_n = strlen(state->vmconfig); + err = addrof(sxpr_childN(sxpr, n++, ONONE), &addr); + if(err) goto exit; + err = portof(sxpr_childN(sxpr, n++, ONONE), &port); + if(err) goto exit; + err = xfr_send(args, state, conn, addr, port); + + } else if(sxpr_elementp(sxpr, oxfr_save)){ + // Save message from xend. + char *file; + XfrState _state = {}, *state = &_state; + int n = 0; + + dprintf("> xfr.save\n"); + err = intof(sxpr_childN(sxpr, n++, ONONE), &state->vmid); + if(err) goto exit; + err = stringof(sxpr_childN(sxpr, n++, ONONE), &state->vmconfig); + if(err) goto exit; + state->vmconfig_n = strlen(state->vmconfig); + err = stringof(sxpr_childN(sxpr, n++, ONONE), &file); + if(err) goto exit; + err = xfr_save(args, state, conn, file); + + } else if(sxpr_elementp(sxpr, oxfr_xfr)){ + // Xfr message from peer xfrd. + XfrState _state = {}, *state = &_state; + int n = 0; + + dprintf("> xfr.xfr\n"); + err = intof(sxpr_childN(sxpr, n++, ONONE), &state->vmid); + if(err) goto exit; + err = xfr_recv(args, state, conn); + + } else{ + // Anything else is invalid. + err = -EINVAL; + dprintf("> Invalid message: "); + objprint(iostderr, sxpr, 0); + IOStream_print(iostderr, "\n"); + xfr_error(conn, err); + } + exit: + Conn_close(conn); + dprintf("< err=%d\n", err); + return err; +} + +/** Accept an incoming connection. + * + * @param sock tcp socket + * @return 0 on success, error code otherwise + */ +int xfrd_accept(Args *args, int sock){ + struct sockaddr_in peer_in; + struct sockaddr *peer = (struct sockaddr *)&peer_in; + socklen_t peer_n = sizeof(peer_in); + int peersock; + pid_t pid; + int err = 0; + + dprintf(">\n"); + dprintf("> accept...\n"); + peersock = accept(sock, peer, &peer_n); + dprintf("> accept=%d\n", peersock); + if(peersock < 0){ + perror("accept"); + err = -errno; + goto exit; + } + iprintf("> Accepted connection from %s:%d\n", + inet_ntoa(peer_in.sin_addr), htons(peer_in.sin_port)); + pid = fork(); + if(pid > 0){ + // Parent, fork succeeded. + iprintf("> Forked child pid=%d\n", pid); + close(peersock); + } else if (pid < 0){ + // Parent, fork failed. + perror("fork"); + close(peersock); + } else { + // Child. + iprintf("> Xfr service for %s:%d\n", + inet_ntoa(peer_in.sin_addr), htons(peer_in.sin_port)); + err = xfrd_service(args, peersock, peer_in); + iprintf("> Xfr service err=%d\n", err); + shutdown(peersock, 2); + exit(err ? 1 : 0); + } + exit: + dprintf("< err=%d\n", err); + return err; +} + +/** Socket select loop. + * Accepts connections on the tcp socket. + * + * @param listen_sock tcp listen socket + * @return 0 on success, error code otherwise + */ +int xfrd_select(Args *args, int listen_sock){ + int err = 0; + SelectSet set = {}; + dprintf("> socks: %d\n", listen_sock); + while(1){ + SelectSet_zero(&set); + SelectSet_add_read(&set, listen_sock); + err = SelectSet_select(&set, NULL); + if(err < 0){ + if(errno == EINTR) continue; + perror("select"); + goto exit; + } + if(FD_ISSET(listen_sock, &set.rd)){ + xfrd_accept(args, listen_sock); + } + } + exit: + dprintf("< err=%d\n", err); + return err; +} + +/** Create a socket. + * + * @param args program arguments + * @param socktype socket type + * @param reuse whether to set SO_REUSEADDR + * @param val return value for the socket + * @return 0 on success, error code otherwise + */ +int create_socket(Args *args, int socktype, int reuse, int *val){ + int err = 0; + int sock = 0; + struct sockaddr_in addr_in; + struct sockaddr *addr = (struct sockaddr *)&addr_in; + socklen_t addr_n = sizeof(addr_in); + + dprintf(">\n"); + // Create socket and bind it. + sock = socket(AF_INET, socktype, 0); + if(sock < 0){ + err = -errno; + goto exit; + } + addr_in.sin_family = AF_INET; + addr_in.sin_addr.s_addr = INADDR_ANY; + addr_in.sin_port = args->port; + dprintf("> port=%d\n", ntohs(addr_in.sin_port)); + if(reuse){ + // Set socket option to reuse address. + int val = 1; + err = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); + if(err < 0){ + err = -errno; + perror("setsockopt"); + goto exit; + } + } + err = bind(sock, addr, addr_n); + if(err < 0){ + err = -errno; + perror("bind"); + goto exit; + } + exit: + *val = (err ? -1 : sock); + dprintf("< err=%d\n", err); + return err; +} + +/** Create the tcp listen socket. + * + * @param args program arguments + * @param val return value for the socket + * @return 0 on success, error code otherwise + */ +int xfrd_listen_socket(Args *args, int *val){ + int err = 0; + int sock; + dprintf(">\n"); + err = create_socket(args, SOCK_STREAM, 1, &sock); + if(err) goto exit; + dprintf("> listen...\n"); + err = listen(sock, 5); + if(err < 0){ + err = -errno; + perror("listen"); + goto exit; + } + exit: + *val = (err ? -1 : sock); + if(err) close(sock); + dprintf("< err=%d\n", err); + return err; +} + +/** Type for signal handling functions. */ +typedef void SignalAction(int code, siginfo_t *info, void *data); + +/** Handle SIGCHLD by getting child exit status. + * This prevents child processes being defunct. + * + * @param code signal code + * @param info signal info + * @param data + */ +void sigaction_SIGCHLD(int code, siginfo_t *info, void *data){ + int status; + pid_t pid; + //dprintf("> child_exit=%d waiting...\n", child_exit); + pid = wait(&status); + dprintf("> child pid=%d status=%d\n", pid, status); +} + +/** Handle SIGPIPE. + * + * @param code signal code + * @param info signal info + * @param data + */ +void sigaction_SIGPIPE(int code, siginfo_t *info, void *data){ + dprintf("> SIGPIPE\n"); + //fflush(stdout); + //fflush(stderr); + //exit(1); +} + +/** Handle SIGALRM. + * + * @param code signal code + * @param info signal info + * @param data + */ +void sigaction_SIGALRM(int code, siginfo_t *info, void *data){ + dprintf("> SIGALRM\n"); +} + +/** Install a handler for a signal. + * + * @param signum signal + * @param action handler + * @return 0 on success, error code otherwise + */ +int catch_signal(int signum, SignalAction *action){ + int err = 0; + struct sigaction sig = {}; + sig.sa_sigaction = action; + sig.sa_flags = SA_SIGINFO; + err = sigaction(signum, &sig, NULL); + if(err){ + perror("sigaction"); + } + return err; +} + +/** Transfer daemon main program. + * + * @param args program arguments + * @return 0 on success, error code otherwise + */ +int xfrd_main(Args *args){ + int err = 0; + int listen_sock; + + dprintf(">\n"); + catch_signal(SIGCHLD,sigaction_SIGCHLD); + catch_signal(SIGPIPE,sigaction_SIGPIPE); + catch_signal(SIGALRM,sigaction_SIGALRM); + err = xfrd_listen_socket(args, &listen_sock); + if(err) goto exit; + err = xfrd_select(args, listen_sock); + exit: + close(listen_sock); + dprintf("< err=%d\n", err); + return err; +} + +/** Parse command-line arguments and call the xfrd main program. + * + * @param arg argument count + * @param argv arguments + * @return 0 on success, 1 otherwise + */ +int main(int argc, char *argv[]){ + int err = 0; + int key = 0; + int long_index = 0; + + set_defaults(args); + while(1){ + key = getopt_long(argc, argv, short_opts, long_opts, &long_index); + if(key == -1) break; + switch(key){ + case OPT_PORT: + err = !convert_service_to_port(optarg, &args->port); + if(err) goto exit; + break; + case OPT_COMPRESS: + args->compress = TRUE; + break; + case OPT_HELP: + usage(0); + break; + case OPT_VERBOSE: + args->verbose = TRUE; + break; + case OPT_VERSION: + printf("> Version %d.%d\n", XFR_PROTO_MAJOR, XFR_PROTO_MINOR); + exit(0); + break; + default: + usage(EINVAL); + break; + } + } + xfr_init(); + err = xfrd_main(args); + exit: + if(err && key > 0){ + fprintf(stderr, "Error in arg %c\n", key); + } + return (err ? 1 : 0); +} + diff --git a/tools/xfrd/xfrd.h b/tools/xfrd/xfrd.h new file mode 100644 index 0000000000..2537fd67ab --- /dev/null +++ b/tools/xfrd/xfrd.h @@ -0,0 +1,14 @@ +#ifndef _XFRD_XFRD_H_ +#define _XFRD_XFRD_H_ + +/** Xend port in host order. */ +#define XEND_PORT 8001 + +/** Xfrd port in host order. */ +#define XFRD_PORT 8002 + +/** Protocol version. */ +#define XFR_PROTO_MAJOR 1 +#define XFR_PROTO_MINOR 0 + +#endif diff --git a/tools/xfrd/xfrdClient.py b/tools/xfrd/xfrdClient.py new file mode 100755 index 0000000000..b8a3554729 --- /dev/null +++ b/tools/xfrd/xfrdClient.py @@ -0,0 +1,127 @@ +#!/bin/env python +""" +Test client for the migration daemon (xfrd). + +Author: Mike Wray + +""" +import getopt +import sys +import os +from socket import * +import StringIO + +sys.path.append("/home/mjw/repos-bk/xeno-unstable.bk/tools/python") + +import xen.xend.sxp as sxp +from xen.xend.packing import SxpPacker, SxpUnpacker + +XFRD_PORT = 8002 + +verbose = 0 + +class TCPClient: + + def __init__(self, host, port): + print ">TCPClient" + self.sock = socket(AF_INET, SOCK_STREAM, 0) + print ">TCPClient sock=", self.sock + print ">TCPClient> connect ", host, port + v = self.sock.connect((host, port)) + print ">TCPClient> connect=", v + # Send plain header (no gzip). + #self.sock.send("\0\0") + + self.sockin = self.sock.makefile("r") + self.sockout = self.sock.makefile("w") + self.packer = SxpPacker(self.sockout) + self.unpacker = SxpUnpacker(self.sockin) + #pass + + def request(self, req): + print "request>", req + self.packer.pack(req) + self.sockout.flush() + print "request<" + + def request_hello(self): + self.request(['xfr.hello', XFR_PROTO_MAJOR, XFR_PROTO_MINOR]) + + def request_migrate(self, vmid, vhost, vport, vmconfig='(vm)'): + self.request(['xfr.migrate', vmid, vmconfig, vhost, vport]) + + def read(self): + while(1): + v = self.unpacker.unpack() + print 'read>', v + if v[0] == 'xfr.err' and v[1]: return + if v[0] == 'xfr.ok': return + +XFR_PROTO_MAJOR = 1 +XFR_PROTO_MINOR = 0 + +host_default = "localhost" +port_default = XFRD_PORT +vhost_default = "localhost" +vport_default = 8003 +vmid_default = 1 + +# Short options. Options followed by ':' need a parameter. +short_opts = 'h' + +# Long options. Options ending in '=' need a parameter. +long_opts = [ 'host=', 'port=', 'vhost=', 'vport=', 'vmid=', 'verbose', 'help'] + +def usage(err=None): + if err: + out = sys.stderr + else: + out = sys.stdout + print >> out, 'Usage: %s [options] [command...]\n' % sys.argv[0] + print >> out, '--host \n\tHost to initiate transfer on. Default %s.' % host_default + print >> out, '--port \n\tPort to initiate transfer on. Default %d.' % port_default + print >> out, '--vhost \n\tHost to transfer VM to. Default %s.' % vhost_default + print >> out, '--vport \n\tPort to transfer VM to. Default %d.' % vport_default + print >> out, '--vmid \n\tVM id. Default %d.' % vmid_default + print >> out, '--help\n\tPrint help.' + +def main(argv): + global verbose + host = host_default + port = port_default + vhost = vhost_default + vport = vport_default + vmid = vmid_default + + try: + opts, args = getopt.getopt(argv[1:], short_opts, long_opts) + except getopt.GetoptError, ex: + print >>sys.stderr, 'Error:', ex + usage(1) + sys.exit(1) + + for key, val in opts: + if key == '--help': + usage() + sys.exit(0) + elif key == '--host': + host = val + elif key == '--port': + port = int(val) + elif key == '--vhost': + vhost = val + elif key == '--vport': + vport = int(val) + elif key == '--vmid': + vmid = int(val) + + print "host=%s port=%d" % (host, port) + print "vhost=%s vport=%d vmid=%d" % (vhost, vport, vmid) + client = TCPClient(gethostbyname(host), port) + client.request_hello() + client.request_migrate(vmid, gethostbyname(vhost), vport) + client.read() + +if __name__ == '__main__': + main(sys.argv) + diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index 7a6d659d0b..039df504ef 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -6,6 +6,9 @@ OBJS := $(subst pdb-linux.o,,$(OBJS)) OBJS := $(subst pdb-stub.o,,$(OBJS)) endif +OBJS += $(patsubst %.S,%.o,$(wildcard $(TARGET_SUBARCH)/*.S)) +OBJS += $(patsubst %.c,%.o,$(wildcard $(TARGET_SUBARCH)/*.c)) + LINK_BASE := 0xFC500000 # Xen is linked here LOAD_BASE := 0x00100000 # Xen is loaded here @@ -15,11 +18,13 @@ LOAD_BASE := 0x00100000 # Xen is loaded here # segment offsets from LINK_BASE-relative to LOAD_BASE-relative. # (NB. Linux gets round this by turning its image into raw binary, then # wrapping that with a low-memory bootstrapper.) -default: boot/boot.o $(OBJS) +default: boot/$(TARGET_SUBARCH).o $(OBJS) $(LD) -r -o arch.o $(OBJS) - $(LD) $(LDFLAGS) boot/boot.o $(ALL_OBJS) -o $(TARGET)-syms + $(LD) $(LDFLAGS) boot/$(TARGET_SUBARCH).o $(ALL_OBJS) -o $(TARGET)-syms objcopy -R .note -R .comment -S $(TARGET)-syms $(TARGET) $(BASEDIR)/tools/elf-reloc $(LINK_BASE) $(LOAD_BASE) $(TARGET) clean: rm -f *.o *~ core boot/*.o boot/*~ boot/core + rm -f $(TARGET_SUBARCH)/*.o $(TARGET_SUBARCH)/*~ + rm -f $(TARGETSUBARCH)/core diff --git a/xen/arch/x86/Rules.mk b/xen/arch/x86/Rules.mk index 5963e99d80..560b381845 100644 --- a/xen/arch/x86/Rules.mk +++ b/xen/arch/x86/Rules.mk @@ -8,7 +8,7 @@ CFLAGS := -nostdinc -fno-builtin -fno-common -fno-strict-aliasing -O3 CFLAGS += -iwithprefix include -Wall -Werror -fomit-frame-pointer CFLAGS += -I$(BASEDIR)/include -Wno-pointer-arith -Wredundant-decls -LDFLAGS := -T xen.lds -N +LDFLAGS := -T $(TARGET_SUBARCH)/xen.lds -N ifeq ($(TARGET_SUBARCH),x86_32) CFLAGS += -m32 -march=i686 diff --git a/xen/arch/x86/apic.c b/xen/arch/x86/apic.c index cd1733c173..64974f670d 100644 --- a/xen/arch/x86/apic.c +++ b/xen/arch/x86/apic.c @@ -491,9 +491,9 @@ void __init init_apic_mappings(void) *****************************************************************************/ /* used for system time scaling */ -static unsigned int bus_freq; -static u32 bus_cycle; /* length of one bus cycle in pico-seconds */ -static u32 bus_scale; /* scaling factor convert ns to bus cycles */ +static unsigned long bus_freq; /* KAF: pointer-size avoids compile warns. */ +static u32 bus_cycle; /* length of one bus cycle in pico-seconds */ +static u32 bus_scale; /* scaling factor convert ns to bus cycles */ /* * The timer chip is already set up at HZ interrupts per second here, diff --git a/xen/arch/x86/boot/boot.S b/xen/arch/x86/boot/x86_32.S similarity index 67% rename from xen/arch/x86/boot/boot.S rename to xen/arch/x86/boot/x86_32.S index 55a4cc4cc2..fea54c1336 100644 --- a/xen/arch/x86/boot/boot.S +++ b/xen/arch/x86/boot/x86_32.S @@ -7,7 +7,7 @@ .text ENTRY(start) - jmp hal_entry + jmp __start .align 4 @@ -19,7 +19,27 @@ ENTRY(start) /* Checksum: must be the negated sum of the first two fields. */ .long -0x1BADB004 -hal_entry: +bad_cpu_msg: + .asciz "Bad CPU: we need at least a P6-compatible core." +bad_cpu: + mov $SYMBOL_NAME(bad_cpu_msg)-__PAGE_OFFSET,%esi + mov $0xB8000,%edi # VGA framebuffer +1: mov (%esi),%bl + test %bl,%bl # Terminate on '\0' sentinel +2: je 2b + mov $0x3f8+5,%dx # UART Line Status Register +3: in %dx,%al + test $0x20,%al # Test THR Empty flag + je 3b + mov $0x3f8+0,%dx # UART Transmit Holding Register + mov %bl,%al + out %al,%dx # Send a character over the serial line + movsb # Write a character to the VGA framebuffer + mov $7,%al + stosb # Write an attribute to the VGA framebuffer + jmp 1b + +__start: /* Set up a few descriptors: on entry only CS is guaranteed good. */ lgdt %cs:nopaging_gdt_descr-__PAGE_OFFSET mov $(__HYPERVISOR_DS),%ecx @@ -47,34 +67,18 @@ hal_entry: and %edx,%ecx je bad_cpu # ID bit should be set - /* Set up CR0. */ - mov %cr0,%ecx - and $0x00000011,%ecx # save ET and PE - or $0x00050022,%ecx # set AM, WP, NE and MP - mov %ecx,%cr0 - /* Set up FPU. */ fninit /* Set up CR4, except global flag which Intel requires should be */ /* left until after paging is enabled (IA32 Manual Vol. 3, Sec. 2.5) */ - mov %cr4,%ecx - or mmu_cr4_features-__PAGE_OFFSET,%ecx - mov %ecx,mmu_cr4_features-__PAGE_OFFSET - and $0x7f,%ecx /* disable GLOBAL bit */ + mov mmu_cr4_features-__PAGE_OFFSET,%ecx + and $0x7f,%cl # CR4.PGE (global enable) mov %ecx,%cr4 -#ifdef CONFIG_SMP - /* Is this a non-boot processor? */ cmp $(SECONDARY_CPU_FLAG),%ebx - jne continue_boot_cpu - - call start_paging - lidt idt_descr - jmp start_secondary -#endif - -continue_boot_cpu: + je start_paging + add $__PAGE_OFFSET,%ebx push %ebx /* Multiboot info struct */ push %eax /* Multiboot magic value */ @@ -86,31 +90,6 @@ continue_boot_cpu: xor %eax,%eax rep stosb - /* Copy all modules (dom0 + initrd if present) out of the Xen heap */ - mov (%esp),%eax - cmp $0x2BADB002,%eax - jne skip_dom0_copy - sub $__PAGE_OFFSET,%ebx /* turn back into a phys addr */ - mov 0x14(%ebx),%edi /* mbi->mods_count */ - dec %edi /* mbi->mods_count-- */ - jb skip_dom0_copy /* skip if no modules */ - mov 0x18(%ebx),%eax /* mbi->mods_addr */ - mov (%eax),%ebx /* %ebx = mod[0]->mod_start */ - shl $4,%edi - add %edi,%eax - mov 0x4(%eax),%eax /* %eax = mod[mod_count-1]->end */ - mov %eax,%ecx - sub %ebx,%ecx /* %ecx = byte len of all mods */ - mov $(DIRECTMAP_PHYS_END), %edi - add %ecx, %edi /* %edi = src + length */ - shr $2,%ecx /* %ecx = length/4 */ -1: sub $4,%eax /* %eax = src, %edi = dst */ - sub $4,%edi - mov (%eax),%ebx - mov %ebx,(%edi) - loop 1b -skip_dom0_copy: - /* Initialize low and high mappings of all memory with 4MB pages */ mov $idle_pg_table-__PAGE_OFFSET,%edi mov $0x1e3,%eax /* PRESENT+RW+A+D+4MB+GLOBAL */ @@ -119,20 +98,27 @@ skip_dom0_copy: add $(1< +#include +#include + +#define SECONDARY_CPU_FLAG 0xA5A5A5A5 + + .text + .code32 + +ENTRY(start) + jmp __start + + .align 4 + +/*** MULTIBOOT HEADER ****/ + /* Magic number indicating a Multiboot header. */ + .long 0x1BADB002 + /* Flags to bootloader (see Multiboot spec). */ + .long 0x00000002 + /* Checksum: must be the negated sum of the first two fields. */ + .long -0x1BADB004 + +bad_cpu_msg: + .asciz "Bad CPU: does not support 64-bit (long) mode." +bad_cpu: + mov $SYMBOL_NAME(bad_cpu_msg)-__PAGE_OFFSET,%esi + mov $0xB8000,%edi # VGA framebuffer +1: mov (%esi),%bl + test %bl,%bl # Terminate on '\0' sentinel +2: je 2b + mov $0x3f8+5,%dx # UART Line Status Register +3: in %dx,%al + test $0x20,%al # Test THR Empty flag + je 3b + mov $0x3f8+0,%dx # UART Transmit Holding Register + mov %bl,%al + out %al,%dx # Send a character over the serial line + movsb # Write a character to the VGA framebuffer + mov $7,%al + stosb # Write an attribute to the VGA framebuffer + jmp 1b + +__start: + /* Set up a few descriptors: on entry only CS is guaranteed good. */ + lgdt %cs:nopaging_gdt_descr-__PAGE_OFFSET + mov $(__HYPERVISOR_DS),%ecx + mov %ecx,%ds + mov %ecx,%es + mov %ecx,%fs + mov %ecx,%gs + ljmp $(__HYPERVISOR_CS32),$(1f)-__PAGE_OFFSET +1: lss stack_start-__PAGE_OFFSET,%esp + + /* Reset EFLAGS (subsumes CLI and CLD). */ + pushl $0 + popf + + /* We begin by interrogating the CPU for the presence of long mode. */ + mov $0x80000000,%eax + cpuid + cmp $0x80000000,%eax # any function > 0x80000000? + jbe bad_cpu + mov $0x80000001,%eax + cpuid + bt $29,%edx # Long mode feature? + jnc bad_cpu + + /* Set up FPU. */ + fninit + + /* Set up CR4, except global flag which Intel requires should be */ + /* left until after paging is enabled (IA32 Manual Vol. 3, Sec. 2.5) */ + mov mmu_cr4_features-__PAGE_OFFSET,%ecx + and $0x7f,%cl # CR4.PGE (global enable) + mov %ecx,%cr4 + + cmp $(SECONDARY_CPU_FLAG),%ebx + je start_paging + + add $__PAGE_OFFSET,%ebx + push %ebx /* Multiboot info struct */ + push %eax /* Multiboot magic value */ + + /* Initialize BSS (no nasty surprises!) */ + mov $__bss_start-__PAGE_OFFSET,%edi + mov $_end-__PAGE_OFFSET,%ecx + sub %edi,%ecx + xor %eax,%eax + rep stosb + + /* Initialize low and high mappings of all memory with 4MB pages */ + mov $idle_pg_table-__PAGE_OFFSET,%edi + mov $0x1e3,%eax /* PRESENT+RW+A+D+4MB+GLOBAL */ +1: mov %eax,__PAGE_OFFSET>>20(%edi) /* high mapping */ + stosl /* low mapping */ + add $(1< +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TRC_DOM0OP_ENTER_BASE 0x00020000 +#define TRC_DOM0OP_LEAVE_BASE 0x00030000 + +extern unsigned int alloc_new_dom_mem(struct domain *, unsigned int); + +static int msr_cpu_mask; +static unsigned long msr_addr; +static unsigned long msr_lo; +static unsigned long msr_hi; + +static void write_msr_for(void *unused) +{ + if (((1 << current->processor) & msr_cpu_mask)) + wrmsr(msr_addr, msr_lo, msr_hi); +} + +static void read_msr_for(void *unused) +{ + if (((1 << current->processor) & msr_cpu_mask)) + rdmsr(msr_addr, msr_lo, msr_hi); +} + +long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op) +{ + long ret = 0; + + if ( !IS_PRIV(current) ) + return -EPERM; + + switch ( op->cmd ) + { + + case DOM0_MSR: + { + if ( op->u.msr.write ) + { + msr_cpu_mask = op->u.msr.cpu_mask; + msr_addr = op->u.msr.msr; + msr_lo = op->u.msr.in1; + msr_hi = op->u.msr.in2; + smp_call_function(write_msr_for, NULL, 1, 1); + write_msr_for(NULL); + } + else + { + msr_cpu_mask = op->u.msr.cpu_mask; + msr_addr = op->u.msr.msr; + smp_call_function(read_msr_for, NULL, 1, 1); + read_msr_for(NULL); + + op->u.msr.out1 = msr_lo; + op->u.msr.out2 = msr_hi; + copy_to_user(u_dom0_op, op, sizeof(*op)); + } + ret = 0; + } + break; + + case DOM0_SHADOW_CONTROL: + { + struct domain *d; + ret = -ESRCH; + d = find_domain_by_id(op->u.shadow_control.domain); + if ( d != NULL ) + { + ret = shadow_mode_control(d, &op->u.shadow_control); + put_domain(d); + copy_to_user(u_dom0_op, op, sizeof(*op)); + } + } + break; + + default: + ret = -ENOSYS; + + } + + return ret; +} + +void arch_getdomaininfo_ctxt(struct domain *d, full_execution_context_t *c) +{ + int i; + + c->flags = 0; + memcpy(&c->cpu_ctxt, + &d->shared_info->execution_context, + sizeof(d->shared_info->execution_context)); + if ( test_bit(DF_DONEFPUINIT, &d->flags) ) + c->flags |= ECF_I387_VALID; + memcpy(&c->fpu_ctxt, + &d->thread.i387, + sizeof(d->thread.i387)); + memcpy(&c->trap_ctxt, + d->thread.traps, + sizeof(d->thread.traps)); +#ifdef ARCH_HAS_FAST_TRAP + if ( (d->thread.fast_trap_desc.a == 0) && + (d->thread.fast_trap_desc.b == 0) ) + c->fast_trap_idx = 0; + else + c->fast_trap_idx = + d->thread.fast_trap_idx; +#endif + c->ldt_base = d->mm.ldt_base; + c->ldt_ents = d->mm.ldt_ents; + c->gdt_ents = 0; + if ( GET_GDT_ADDRESS(d) == GDT_VIRT_START ) + { + for ( i = 0; i < 16; i++ ) + c->gdt_frames[i] = + l1_pgentry_to_pagenr(d->mm.perdomain_pt[i]); + c->gdt_ents = + (GET_GDT_ENTRIES(d) + 1) >> 3; + } + c->guestos_ss = d->thread.guestos_ss; + c->guestos_esp = d->thread.guestos_sp; + c->pt_base = + pagetable_val(d->mm.pagetable); + memcpy(c->debugreg, + d->thread.debugreg, + sizeof(d->thread.debugreg)); + c->event_callback_cs = + d->event_selector; + c->event_callback_eip = + d->event_address; + c->failsafe_callback_cs = + d->failsafe_selector; + c->failsafe_callback_eip = + d->failsafe_address; +} diff --git a/xen/arch/x86/process.c b/xen/arch/x86/domain.c similarity index 98% rename from xen/arch/x86/process.c rename to xen/arch/x86/domain.c index d3bf5ab4b8..459a85b393 100644 --- a/xen/arch/x86/process.c +++ b/xen/arch/x86/domain.c @@ -1,17 +1,10 @@ /* - * linux/arch/i386/kernel/process.c - * * Copyright (C) 1995 Linus Torvalds * * Pentium III FXSR, SSE support * Gareth Hughes , May 2000 */ -/* - * This file handles the architecture-dependent parts of process handling.. - */ - -#define __KERNEL_SYSCALLS__ #include #include #include @@ -192,6 +185,8 @@ void machine_power_off(void) machine_restart(0); } +#if defined(__i386__) + void new_thread(struct domain *p, unsigned long start_pc, unsigned long start_stack, @@ -361,3 +356,5 @@ long do_iopl(domid_t domain, unsigned int new_io_pl) ec->eflags = (ec->eflags & 0xffffcfff) | ((new_io_pl&3) << 12); return 0; } + +#endif diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c index 950138849b..af0b0de1fb 100644 --- a/xen/arch/x86/irq.c +++ b/xen/arch/x86/irq.c @@ -89,7 +89,11 @@ void enable_irq(unsigned int irq) asmlinkage void do_IRQ(struct pt_regs regs) { +#if defined(__i386__) unsigned int irq = regs.orig_eax; +#else + unsigned int irq = 0; /* XXX */ +#endif irq_desc_t *desc = &irq_desc[irq]; struct irqaction *action; diff --git a/xen/arch/x86/mpparse.c b/xen/arch/x86/mpparse.c index ae1e1da93b..d10e4ce9dd 100644 --- a/xen/arch/x86/mpparse.c +++ b/xen/arch/x86/mpparse.c @@ -458,7 +458,7 @@ static int __init smp_read_mpc(struct mp_config_table *mpc) if ((clustered_apic_mode == CLUSTERED_APIC_NUMAQ) && mpc->mpc_oemptr) { /* We need to process the oem mpc tables to tell us which quad things are in ... */ mpc_record = 0; - smp_read_mpc_oem((struct mp_config_oemtable *) mpc->mpc_oemptr, mpc->mpc_oemsize); + smp_read_mpc_oem((struct mp_config_oemtable *)(unsigned long)mpc->mpc_oemptr, mpc->mpc_oemsize); mpc_record = 0; } @@ -824,7 +824,7 @@ void __init get_smp_config (void) * Read the physical hardware table. Anything here will * override the defaults. */ - if (!smp_read_mpc((void *)mpf->mpf_physptr)) { + if (!smp_read_mpc((void *)(unsigned long)mpf->mpf_physptr)) { smp_found_config = 0; printk(KERN_ERR "BIOS bug, MP table errors detected!...\n"); printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n"); diff --git a/xen/arch/x86/rwlock.c b/xen/arch/x86/rwlock.c index 2ef7af16b1..d8c1b7dde5 100644 --- a/xen/arch/x86/rwlock.c +++ b/xen/arch/x86/rwlock.c @@ -6,22 +6,22 @@ asm( ".align 4\n" ".globl __write_lock_failed\n" "__write_lock_failed:\n" -" " LOCK "addl $" RW_LOCK_BIAS_STR ",(%eax)\n" +" " LOCK "addl $" RW_LOCK_BIAS_STR ",(%"__OP"ax)\n" "1: rep; nop\n" -" cmpl $" RW_LOCK_BIAS_STR ",(%eax)\n" +" cmpl $" RW_LOCK_BIAS_STR ",(%"__OP"ax)\n" " jne 1b\n" -" " LOCK "subl $" RW_LOCK_BIAS_STR ",(%eax)\n" +" " LOCK "subl $" RW_LOCK_BIAS_STR ",(%"__OP"ax)\n" " jnz __write_lock_failed\n" " ret\n" ".align 4\n" ".globl __read_lock_failed\n" "__read_lock_failed:\n" -" lock ; incl (%eax)\n" +" lock ; incl (%"__OP"ax)\n" "1: rep; nop\n" -" cmpl $1,(%eax)\n" +" cmpl $1,(%"__OP"ax)\n" " js 1b\n" -" lock ; decl (%eax)\n" +" lock ; decl (%"__OP"ax)\n" " js __read_lock_failed\n" " ret\n" ); diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index ec803472fc..831a27e092 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -28,8 +28,11 @@ extern int do_timer_lists_from_pit; char ignore_irq13; /* set if exception 16 works */ struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1 }; -/* Lots of nice things, since we only target PPro+. */ +#if defined(__x86_64__) +unsigned long mmu_cr4_features = X86_CR4_PSE | X86_CR4_PGE | X86_CR4_PAE; +#else unsigned long mmu_cr4_features = X86_CR4_PSE | X86_CR4_PGE; +#endif EXPORT_SYMBOL(mmu_cr4_features); unsigned long wait_init_idle; @@ -51,6 +54,8 @@ int acpi_force __initdata = 0; int phys_proc_id[NR_CPUS]; int logical_proc_id[NR_CPUS]; +#if defined(__i386__) + /* Standard macro to see if a specific flag is changeable */ static inline int flag_is_changeable_p(u32 flag) { @@ -78,6 +83,12 @@ static int __init have_cpuid_p(void) return flag_is_changeable_p(X86_EFLAGS_ID); } +#elif defined(__x86_64__) + +#define have_cpuid_p() (1) + +#endif + void __init get_cpu_vendor(struct cpuinfo_x86 *c) { char *v = c->x86_vendor_id; @@ -256,6 +267,7 @@ void __init identify_cpu(struct cpuinfo_x86 *c) unsigned long cpu_initialized; void __init cpu_init(void) { +#if defined(__i386__) /* XXX */ int nr = smp_processor_id(); struct tss_struct * t = &init_tss[nr]; @@ -294,6 +306,7 @@ void __init cpu_init(void) write_ptbase(¤t->mm); init_idle_task(); +#endif } static void __init do_initcalls(void) diff --git a/xen/common/shadow.c b/xen/arch/x86/shadow.c similarity index 100% rename from xen/common/shadow.c rename to xen/arch/x86/shadow.c diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c index 6a643ada24..ef7a39df89 100644 --- a/xen/arch/x86/smpboot.c +++ b/xen/arch/x86/smpboot.c @@ -659,7 +659,9 @@ static void __init do_boot_cpu (int apicid) map_cpu_to_boot_apicid(cpu, apicid); +#if defined(__i386__) SET_DEFAULT_FAST_TRAP(&idle->thread); +#endif idle_task[cpu] = idle; diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c index dec7618ed7..dfe20e415d 100644 --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -107,7 +107,8 @@ static struct irqaction irq0 = { timer_interrupt, "timer", NULL}; static unsigned long __init calibrate_tsc(void) { - unsigned long startlow, starthigh, endlow, endhigh, count; + u64 start, end, diff; + unsigned long count; /* Set the Gate high, disable speaker */ outb((inb(0x61) & ~0x02) | 0x01, 0x61); @@ -123,22 +124,24 @@ static unsigned long __init calibrate_tsc(void) outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */ outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */ - rdtsc(startlow, starthigh); + rdtscll(start); for ( count = 0; (inb(0x61) & 0x20) == 0; count++ ) continue; - rdtsc(endlow, endhigh); + rdtscll(end); /* Error if the CTC doesn't behave itself. */ if ( count == 0 ) return 0; - /* [endhigh:endlow] = [endhigh:endlow] - [starthigh:startlow] */ - __asm__( "subl %2,%0 ; sbbl %3,%1" - : "=a" (endlow), "=d" (endhigh) - : "g" (startlow), "g" (starthigh), "0" (endlow), "1" (endhigh) ); + diff = end - start; +#if defined(_i386__) /* If quotient doesn't fit in 32 bits then we return error (zero). */ - return endhigh ? 0 : endlow; + if ( diff & ~0xffffffffULL ) + return 0; +#endif + + return (unsigned long)diff; } diff --git a/xen/arch/x86/trampoline.S b/xen/arch/x86/trampoline.S index 064159046d..02018f347a 100644 --- a/xen/arch/x86/trampoline.S +++ b/xen/arch/x86/trampoline.S @@ -43,7 +43,11 @@ r_base = . lmsw %ax # into protected mode jmp flush_instr flush_instr: - ljmpl $__HYPERVISOR_CS, $0x100000 # 1MB +#if defined(__x86_64__) + ljmpl $__HYPERVISOR_CS32, $0x100000 # 1MB +#else + ljmpl $__HYPERVISOR_CS, $0x100000 # 1MB +#endif idt_48: .word 0 # idt limit = 0 diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index 59d0e320d6..c43aafea23 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -62,6 +62,8 @@ struct guest_trap_bounce { unsigned long eip; /* 12 */ } guest_trap_bounce[NR_CPUS] = { { 0 } }; +#if defined(__i386__) + #define DOUBLEFAULT_STACK_SIZE 1024 static struct tss_struct doublefault_tss; static unsigned char doublefault_stack[DOUBLEFAULT_STACK_SIZE]; @@ -906,3 +908,5 @@ unsigned long do_get_debugreg(int reg) if ( (reg < 0) || (reg > 7) ) return -EINVAL; return current->thread.debugreg[reg]; } + +#endif /* __i386__ */ diff --git a/xen/arch/x86/domain_page.c b/xen/arch/x86/x86_32/domain_page.c similarity index 100% rename from xen/arch/x86/domain_page.c rename to xen/arch/x86/x86_32/domain_page.c diff --git a/xen/arch/x86/entry.S b/xen/arch/x86/x86_32/entry.S similarity index 100% rename from xen/arch/x86/entry.S rename to xen/arch/x86/x86_32/entry.S diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/x86_32/mm.c similarity index 100% rename from xen/arch/x86/mm.c rename to xen/arch/x86/x86_32/mm.c diff --git a/xen/arch/x86/usercopy.c b/xen/arch/x86/x86_32/usercopy.c similarity index 100% rename from xen/arch/x86/usercopy.c rename to xen/arch/x86/x86_32/usercopy.c diff --git a/xen/arch/x86/xen.lds b/xen/arch/x86/x86_32/xen.lds similarity index 100% rename from xen/arch/x86/xen.lds rename to xen/arch/x86/x86_32/xen.lds diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xen/arch/x86/x86_64/usercopy.c b/xen/arch/x86/x86_64/usercopy.c new file mode 100644 index 0000000000..e7c11fa501 --- /dev/null +++ b/xen/arch/x86/x86_64/usercopy.c @@ -0,0 +1,136 @@ +/* + * User address space access functions. + * + * Copyright 1997 Andi Kleen + * Copyright 1997 Linus Torvalds + * Copyright 2002 Andi Kleen + */ +#include + +/* + * Copy a null terminated string from userspace. + */ + +#define __do_strncpy_from_user(dst,src,count,res) \ +do { \ + long __d0, __d1, __d2; \ + __asm__ __volatile__( \ + " testq %1,%1\n" \ + " jz 2f\n" \ + "0: lodsb\n" \ + " stosb\n" \ + " testb %%al,%%al\n" \ + " jz 1f\n" \ + " decq %1\n" \ + " jnz 0b\n" \ + "1: subq %1,%0\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: movq %5,%0\n" \ + " jmp 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 8\n" \ + " .quad 0b,3b\n" \ + ".previous" \ + : "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \ + "=&D" (__d2) \ + : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \ + : "memory"); \ +} while (0) + +long +__strncpy_from_user(char *dst, const char *src, long count) +{ + long res; + __do_strncpy_from_user(dst, src, count, res); + return res; +} + +long +strncpy_from_user(char *dst, const char *src, long count) +{ + long res = -EFAULT; + if (access_ok(VERIFY_READ, src, 1)) + __do_strncpy_from_user(dst, src, count, res); + return res; +} + +/* + * Zero Userspace + */ + +unsigned long __clear_user(void *addr, unsigned long size) +{ + long __d0; + /* no memory constraint because it doesn't change any memory gcc knows + about */ + asm volatile( + " testq %[size8],%[size8]\n" + " jz 4f\n" + "0: movq %[zero],(%[dst])\n" + " addq %[eight],%[dst]\n" + " decl %%ecx ; jnz 0b\n" + "4: movq %[size1],%%rcx\n" + " testl %%ecx,%%ecx\n" + " jz 2f\n" + "1: movb %b[zero],(%[dst])\n" + " incq %[dst]\n" + " decl %%ecx ; jnz 1b\n" + "2:\n" + ".section .fixup,\"ax\"\n" + "3: lea 0(%[size1],%[size8],8),%[size8]\n" + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 8\n" + " .quad 0b,3b\n" + " .quad 1b,2b\n" + ".previous" + : [size8] "=c"(size), [dst] "=&D" (__d0) + : [size1] "r"(size & 7), "[size8]" (size / 8), "[dst] "(addr), + [zero] "r" (0UL), [eight] "r" (8UL)); + return size; +} + + +unsigned long clear_user(void *to, unsigned long n) +{ + if (access_ok(VERIFY_WRITE, to, n)) + return __clear_user(to, n); + return n; +} + +/* + * Return the size of a string (including the ending 0) + * + * Return 0 on exception, a value greater than N if too long + */ + +long strnlen_user(const char *s, long n) +{ + unsigned long res = 0; + char c; + + if (!access_ok(VERIFY_READ, s, n)) + return 0; + + while (1) { + if (get_user(c, s)) + return 0; + if (!c) + return res+1; + if (res>n) + return n+1; + res++; + s++; + } +} + +unsigned long copy_in_user(void *to, const void *from, unsigned len) +{ + if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) { + return copy_user_generic(to, from, len); + } + return len; +} diff --git a/xen/arch/x86/x86_64/xen.lds b/xen/arch/x86/x86_64/xen.lds new file mode 100644 index 0000000000..caea240e52 --- /dev/null +++ b/xen/arch/x86/x86_64/xen.lds @@ -0,0 +1,85 @@ +/* Excerpts written by Martin Mares */ +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(start) +SECTIONS +{ + . = 0xFFFF840000100000; + _text = .; /* Text and read-only data */ + .text : { + *(.text) + *(.fixup) + *(.gnu.warning) + } = 0x9090 + .text.lock : { *(.text.lock) } /* out-of-line lock text */ + + _etext = .; /* End of text section */ + + .rodata : { *(.rodata) *(.rodata.*) } + .kstrtab : { *(.kstrtab) } + + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + __ksymtab : { *(__ksymtab) } + __stop___ksymtab = .; + + __start___kallsyms = .; /* All kernel symbols */ + __kallsyms : { *(__kallsyms) } + __stop___kallsyms = .; + + .data : { /* Data */ + *(.data) + CONSTRUCTORS + } + + _edata = .; /* End of data section */ + + . = ALIGN(8192); /* init_task */ + .data.init_task : { *(.data.init_task) } + + . = ALIGN(4096); /* Init code and data */ + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(16); + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { *(.initcall.init) } + __initcall_end = .; + . = ALIGN(4096); + __init_end = .; + + . = ALIGN(4096); + .data.page_aligned : { *(.data.idt) } + + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + + __bss_start = .; /* BSS */ + .bss : { + *(.bss) + } + _end = . ; + + /* Sections to be discarded */ + /DISCARD/ : { + *(.text.exit) + *(.data.exit) + *(.exitcall.exit) + } + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff --git a/xen/common/debug.c b/xen/common/debug.c index fd2d7d28c3..1cf4c57d37 100644 --- a/xen/common/debug.c +++ b/xen/common/debug.c @@ -69,7 +69,7 @@ void pdb_do_debug (dom0_op_t *op) struct domain *d; d = find_domain_by_id(op->u.debug.domain); - if ( d->mm.shadow_mode ) + if ( shadow_mode(d) ) cr3 = pagetable_val(d->mm.shadow_table); else cr3 = pagetable_val(d->mm.pagetable); diff --git a/xen/common/dom0_ops.c b/xen/common/dom0_ops.c index 96d7197b3e..fcec8991b2 100644 --- a/xen/common/dom0_ops.c +++ b/xen/common/dom0_ops.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -25,23 +24,8 @@ #define TRC_DOM0OP_LEAVE_BASE 0x00030000 extern unsigned int alloc_new_dom_mem(struct domain *, unsigned int); - -static int msr_cpu_mask; -static unsigned long msr_addr; -static unsigned long msr_lo; -static unsigned long msr_hi; - -static void write_msr_for(void *unused) -{ - if (((1 << current->processor) & msr_cpu_mask)) - wrmsr(msr_addr, msr_lo, msr_hi); -} - -static void read_msr_for(void *unused) -{ - if (((1 << current->processor) & msr_cpu_mask)) - rdmsr(msr_addr, msr_lo, msr_hi); -} +extern long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op); +extern void arch_getdomaininfo_ctxt(struct domain *, full_execution_context_t *); long do_dom0_op(dom0_op_t *u_dom0_op) { @@ -276,7 +260,6 @@ long do_dom0_op(dom0_op_t *u_dom0_op) full_execution_context_t *c; struct domain *d; unsigned long flags; - int i; read_lock_irqsave(&tasklist_lock, flags); @@ -328,52 +311,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op) if ( d != current ) domain_pause(d); - c->flags = 0; - memcpy(&c->cpu_ctxt, - &d->shared_info->execution_context, - sizeof(d->shared_info->execution_context)); - if ( test_bit(DF_DONEFPUINIT, &d->flags) ) - c->flags |= ECF_I387_VALID; - memcpy(&c->fpu_ctxt, - &d->thread.i387, - sizeof(d->thread.i387)); - memcpy(&c->trap_ctxt, - d->thread.traps, - sizeof(d->thread.traps)); -#ifdef ARCH_HAS_FAST_TRAP - if ( (d->thread.fast_trap_desc.a == 0) && - (d->thread.fast_trap_desc.b == 0) ) - c->fast_trap_idx = 0; - else - c->fast_trap_idx = - d->thread.fast_trap_idx; -#endif - c->ldt_base = d->mm.ldt_base; - c->ldt_ents = d->mm.ldt_ents; - c->gdt_ents = 0; - if ( GET_GDT_ADDRESS(d) == GDT_VIRT_START ) - { - for ( i = 0; i < 16; i++ ) - c->gdt_frames[i] = - l1_pgentry_to_pagenr(d->mm.perdomain_pt[i]); - c->gdt_ents = - (GET_GDT_ENTRIES(d) + 1) >> 3; - } - c->guestos_ss = d->thread.guestos_ss; - c->guestos_esp = d->thread.guestos_sp; - c->pt_base = - pagetable_val(d->mm.pagetable); - memcpy(c->debugreg, - d->thread.debugreg, - sizeof(d->thread.debugreg)); - c->event_callback_cs = - d->event_selector; - c->event_callback_eip = - d->event_address; - c->failsafe_callback_cs = - d->failsafe_selector; - c->failsafe_callback_eip = - d->failsafe_address; + arch_getdomaininfo_ctxt(d,c); if ( d != current ) domain_unpause(d); @@ -448,32 +386,6 @@ long do_dom0_op(dom0_op_t *u_dom0_op) } break; - case DOM0_MSR: - { - if ( op->u.msr.write ) - { - msr_cpu_mask = op->u.msr.cpu_mask; - msr_addr = op->u.msr.msr; - msr_lo = op->u.msr.in1; - msr_hi = op->u.msr.in2; - smp_call_function(write_msr_for, NULL, 1, 1); - write_msr_for(NULL); - } - else - { - msr_cpu_mask = op->u.msr.cpu_mask; - msr_addr = op->u.msr.msr; - smp_call_function(read_msr_for, NULL, 1, 1); - read_msr_for(NULL); - - op->u.msr.out1 = msr_lo; - op->u.msr.out2 = msr_hi; - copy_to_user(u_dom0_op, op, sizeof(*op)); - } - ret = 0; - } - break; - #ifdef XEN_DEBUGGER case DOM0_DEBUG: { @@ -543,20 +455,6 @@ long do_dom0_op(dom0_op_t *u_dom0_op) } break; - case DOM0_SHADOW_CONTROL: - { - struct domain *d; - ret = -ESRCH; - d = find_domain_by_id(op->u.shadow_control.domain); - if ( d != NULL ) - { - ret = shadow_mode_control(d, &op->u.shadow_control); - put_domain(d); - copy_to_user(u_dom0_op, op, sizeof(*op)); - } - } - break; - case DOM0_SCHED_ID: { op->u.sched_id.sched_id = sched_id(); @@ -696,7 +594,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op) break; default: - ret = -ENOSYS; + ret = arch_do_dom0_op(op,u_dom0_op); } diff --git a/xen/common/domain.c b/xen/common/domain.c index 5375a5de18..58ed42b25f 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -57,7 +56,7 @@ struct domain *do_createdomain(domid_t dom_id, unsigned int cpu) atomic_set(&d->refcnt, 1); atomic_set(&d->pausecnt, 0); - spin_lock_init(&d->mm.shadow_lock); + shadow_lock_init(d); d->domain = dom_id; d->processor = cpu; @@ -335,7 +334,7 @@ void domain_relinquish_memory(struct domain *d) write_ptbase(¤t->mm); /* Exit shadow mode before deconstructing final guest page table. */ - if ( d->mm.shadow_mode ) + if ( shadow_mode(d) ) shadow_mode_disable(d); /* Drop the in-use reference to the page-table base. */ diff --git a/xen/common/kernel.c b/xen/common/kernel.c index 92602e0bf5..a2b06acc9d 100644 --- a/xen/common/kernel.c +++ b/xen/common/kernel.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -202,6 +201,18 @@ void cmain(unsigned long magic, multiboot_info_t *mbi) #if defined(__i386__) + initial_images_start = DIRECTMAP_PHYS_END; + initial_images_end = initial_images_start + + (mod[mbi->mods_count-1].mod_end - mod[0].mod_start); + if ( initial_images_end > (max_page << PAGE_SHIFT) ) + { + printk("Not enough memory to stash the DOM0 kernel image.\n"); + for ( ; ; ) ; + } + memmove((void *)initial_images_start, /* use low mapping */ + (void *)mod[0].mod_start, /* use low mapping */ + mod[mbi->mods_count-1].mod_end - mod[0].mod_start); + if ( opt_xenheap_megabytes > XENHEAP_DEFAULT_MB ) { printk("Xen heap size is limited to %dMB - you specified %dMB.\n", @@ -214,10 +225,6 @@ void cmain(unsigned long magic, multiboot_info_t *mbi) init_frametable((void *)FRAMETABLE_VIRT_START, max_page); - /* Initial images stashed away above DIRECTMAP area in boot.S. */ - initial_images_start = DIRECTMAP_PHYS_END; - initial_images_end = initial_images_start + - (mod[mbi->mods_count-1].mod_end - mod[0].mod_start); #elif defined(__x86_64__) diff --git a/xen/common/slab.c b/xen/common/slab.c index 2266baa9af..ab97bc5c33 100644 --- a/xen/common/slab.c +++ b/xen/common/slab.c @@ -117,9 +117,9 @@ * is less than 512 (PAGE_SIZE<<3), but greater than 256. */ -#define BUFCTL_END 0xffffFFFF -#define SLAB_LIMIT 0xffffFFFE -typedef unsigned int kmem_bufctl_t; +#define BUFCTL_END (((kmem_bufctl_t)(~0U))-0) +#define BUFCTL_FREE (((kmem_bufctl_t)(~0U))-1) +#define SLAB_LIMIT (((kmem_bufctl_t)(~0U))-2) /* Max number of objs-per-slab for caches which use off-slab slabs. * Needed to avoid a possible looping condition in kmem_cache_grow(). diff --git a/xen/drivers/pci/pci.c b/xen/drivers/pci/pci.c index 258d9d8c8a..f8697d1337 100644 --- a/xen/drivers/pci/pci.c +++ b/xen/drivers/pci/pci.c @@ -890,7 +890,7 @@ pci_set_mwi(struct pci_dev *dev) u16 cmd; #ifdef HAVE_ARCH_PCI_MWI - rc = pcibios_set_mwi(dev); + rc = pcibios_prep_mwi(dev); #else rc = pci_generic_prep_mwi(dev); #endif @@ -1384,7 +1384,7 @@ struct pci_dev * __devinit pci_scan_slot(struct pci_dev *temp) temp->hdr_type = hdr_type & 0x7f; dev = pci_scan_device(temp); - if (!pcibios_scan_all_fns() && func == 0) { + if (!pcibios_scan_all_fns(0,0) && func == 0) { if (!dev) break; } else { diff --git a/xen/drivers/pci/quirks.c b/xen/drivers/pci/quirks.c index 4e920c5234..71c0bb428d 100644 --- a/xen/drivers/pci/quirks.c +++ b/xen/drivers/pci/quirks.c @@ -18,6 +18,7 @@ #include #include #include +#include #undef DEBUG diff --git a/xen/include/acpi/acpi_bus.h b/xen/include/acpi/acpi_bus.h index 50eaf61c0a..4326bc934b 100644 --- a/xen/include/acpi/acpi_bus.h +++ b/xen/include/acpi/acpi_bus.h @@ -36,8 +36,6 @@ #include -extern int acpi_disabled; - /* TBD: Make dynamic */ #define ACPI_MAX_HANDLES 10 struct acpi_handle_list { diff --git a/xen/include/asm-x86/acpi.h b/xen/include/asm-x86/acpi.h index 35d45f4151..be7d6dfda7 100644 --- a/xen/include/asm-x86/acpi.h +++ b/xen/include/asm-x86/acpi.h @@ -108,6 +108,7 @@ extern int acpi_lapic; extern int acpi_ioapic; extern int acpi_noirq; +extern int acpi_disabled; /* Fixmap pages to reserve for ACPI boot-time tables (see fixmap.h) */ #define FIX_ACPI_PAGES 4 diff --git a/xen/include/asm-x86/config.h b/xen/include/asm-x86/config.h index af0172df90..f8cd450451 100644 --- a/xen/include/asm-x86/config.h +++ b/xen/include/asm-x86/config.h @@ -18,8 +18,10 @@ #define CONFIG_ACPI_BOOT 1 #define CONFIG_PCI 1 -#define CONFIG_PCI_BIOS 1 #define CONFIG_PCI_DIRECT 1 +#if defined(__i386__) +#define CONFIG_PCI_BIOS 1 +#endif #define CONFIG_IDE 1 #define CONFIG_BLK_DEV_IDE 1 @@ -164,7 +166,8 @@ extern void __out_of_line_bug(int line) __attribute__((noreturn)); #define DIRECTMAP_PHYS_END (40*1024*1024) /* Hypervisor owns top 64MB of virtual address space. */ -#define HYPERVISOR_VIRT_START (0xFC000000UL) +#define __HYPERVISOR_VIRT_START 0xFC000000 +#define HYPERVISOR_VIRT_START (0xFC000000UL) /* * First 4MB are mapped read-only for all. It's for the machine->physical diff --git a/xen/include/asm-x86/io_apic.h b/xen/include/asm-x86/io_apic.h index 89e0fc0b5b..1c2b24085a 100644 --- a/xen/include/asm-x86/io_apic.h +++ b/xen/include/asm-x86/io_apic.h @@ -3,6 +3,7 @@ #include #include +#include /* * Intel IO-APIC support for SMP and UP systems. diff --git a/xen/include/asm-x86/irq.h b/xen/include/asm-x86/irq.h index 7c5212e50f..1e35752a84 100644 --- a/xen/include/asm-x86/irq.h +++ b/xen/include/asm-x86/irq.h @@ -86,6 +86,8 @@ extern char _stext, _etext; #define __STR(x) #x #define STR(x) __STR(x) +#if defined(__i386__) + #define SAVE_ALL \ "cld\n\t" \ "pushl %gs\n\t" \ @@ -105,8 +107,11 @@ extern char _stext, _etext; "movl %edx,%fs\n\t" \ "movl %edx,%gs\n\t" -#define IRQ_NAME2(nr) nr##_interrupt(void) -#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) +#else + +#define SAVE_ALL + +#endif #define BUILD_SMP_INTERRUPT(x,v) XBUILD_SMP_INTERRUPT(x,v) #define XBUILD_SMP_INTERRUPT(x,v)\ @@ -115,7 +120,7 @@ asmlinkage void call_##x(void); \ __asm__( \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(x) ":\n\t" \ - "pushl $"#v"\n\t" \ + "push"__OS" $"#v"\n\t" \ SAVE_ALL \ SYMBOL_NAME_STR(call_##x)":\n\t" \ "call "SYMBOL_NAME_STR(smp_##x)"\n\t" \ @@ -128,13 +133,13 @@ asmlinkage void call_##x(void); \ __asm__( \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(x) ":\n\t" \ - "pushl $"#v"\n\t" \ + "push"__OS" $"#v"\n\t" \ SAVE_ALL \ - "movl %esp,%eax\n\t" \ - "pushl %eax\n\t" \ + "mov %"__OP"sp,%"__OP"ax\n\t" \ + "push %"__OP"ax\n\t" \ SYMBOL_NAME_STR(call_##x)":\n\t" \ "call "SYMBOL_NAME_STR(smp_##x)"\n\t" \ - "addl $4,%esp\n\t" \ + "add $4,%"__OP"sp\n\t" \ "jmp ret_from_intr\n"); #define BUILD_COMMON_IRQ() \ @@ -147,12 +152,15 @@ __asm__( \ "call " SYMBOL_NAME_STR(do_IRQ) "\n\t" \ "jmp ret_from_intr\n"); +#define IRQ_NAME2(nr) nr##_interrupt(void) +#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) + #define BUILD_IRQ(nr) \ asmlinkage void IRQ_NAME(nr); \ __asm__( \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ - "pushl $"#nr"\n\t" \ + "push"__OS" $"#nr"\n\t" \ "jmp common_interrupt"); extern unsigned long prof_cpu_mask; diff --git a/xen/include/asm-x86/page.h b/xen/include/asm-x86/page.h index 8eb30e35ea..8e4a7ec093 100644 --- a/xen/include/asm-x86/page.h +++ b/xen/include/asm-x86/page.h @@ -180,6 +180,8 @@ static __inline__ int get_order(unsigned long size) } while (size); return order; } + +extern void zap_low_mappings(void); #endif #endif /* _I386_PAGE_H */ diff --git a/xen/include/asm-x86/pci.h b/xen/include/asm-x86/pci.h index 1a217315a4..c5f72c0fae 100644 --- a/xen/include/asm-x86/pci.h +++ b/xen/include/asm-x86/pci.h @@ -12,7 +12,7 @@ extern unsigned int pcibios_assign_all_busses(void); #else #define pcibios_assign_all_busses() 0 #endif -#define pcibios_scan_all_fns() 0 +#define pcibios_scan_all_fns(a,b) 0 extern unsigned long pci_mem_start; #define PCIBIOS_MIN_IO 0x1000 diff --git a/xen/include/asm-x86/shadow.h b/xen/include/asm-x86/shadow.h new file mode 100644 index 0000000000..df24329b2b --- /dev/null +++ b/xen/include/asm-x86/shadow.h @@ -0,0 +1,604 @@ +/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*- */ + +#ifndef _XEN_SHADOW_H +#define _XEN_SHADOW_H + +#include +#include +#include +#include + + +/* Shadow PT flag bits in pfn_info */ +#define PSH_shadowed (1<<31) /* page has a shadow. PFN points to shadow */ +#define PSH_pending (1<<29) /* page is in the process of being shadowed */ +#define PSH_pfn_mask ((1<<21)-1) + +/* Shadow PT operation mode : shadowmode variable in mm_struct */ +#define SHM_test (1) /* just run domain on shadow PTs */ +#define SHM_logdirty (2) /* log pages that are dirtied */ +#define SHM_translate (3) /* lookup machine pages in translation table */ +//#define SHM_cow (4) /* copy on write all dirtied pages */ + + +#define shadow_linear_pg_table ((l1_pgentry_t *)SH_LINEAR_PT_VIRT_START) +#define shadow_linear_l2_table ((l2_pgentry_t *)(SH_LINEAR_PT_VIRT_START+(SH_LINEAR_PT_VIRT_START>>(L2_PAGETABLE_SHIFT-L1_PAGETABLE_SHIFT)))) + +extern void shadow_mode_init(void); +extern int shadow_mode_control( struct domain *p, dom0_shadow_control_t *sc ); +extern int shadow_fault( unsigned long va, long error_code ); +extern void shadow_l1_normal_pt_update( unsigned long pa, unsigned long gpte, + unsigned long *prev_spfn_ptr, + l1_pgentry_t **prev_spl1e_ptr ); +extern void shadow_l2_normal_pt_update( unsigned long pa, unsigned long gpte ); +extern void unshadow_table( unsigned long gpfn, unsigned int type ); +extern int shadow_mode_enable( struct domain *p, unsigned int mode ); +extern void shadow_mode_disable( struct domain *p ); +extern unsigned long shadow_l2_table( + struct mm_struct *m, unsigned long gpfn ); + +#define SHADOW_DEBUG 0 +#define SHADOW_HASH_DEBUG 0 +#define SHADOW_OPTIMISE 1 + +struct shadow_status { + unsigned long pfn; // gpfn + unsigned long spfn_and_flags; // spfn plus flags + struct shadow_status *next; // use pull-to-front list. +}; + +#define shadow_ht_extra_size 128 /*128*/ +#define shadow_ht_buckets 256 /*256*/ + +#ifndef NDEBUG +#define SH_LOG(_f, _a...) \ +printk("DOM%u: (file=shadow.c, line=%d) " _f "\n", \ + current->domain , __LINE__ , ## _a ) +#else +#define SH_LOG(_f, _a...) +#endif + +#if SHADOW_DEBUG +#define SH_VLOG(_f, _a...) \ + printk("DOM%u: (file=shadow.c, line=%d) " _f "\n", \ + current->domain , __LINE__ , ## _a ) +#else +#define SH_VLOG(_f, _a...) +#endif + +#if 0 +#define SH_VVLOG(_f, _a...) \ + printk("DOM%u: (file=shadow.c, line=%d) " _f "\n", \ + current->domain , __LINE__ , ## _a ) +#else +#define SH_VVLOG(_f, _a...) +#endif + + +/************************************************************************/ + +#define shadow_mode(d) (d->mm.shadow_mode) +#define shadow_lock_init(d) spin_lock_init(&d->mm.shadow_lock) + +/************************************************************************/ + +static inline int __mark_dirty( struct mm_struct *m, unsigned int mfn ) +{ + unsigned int pfn; + int rc = 0; + + ASSERT(spin_is_locked(&m->shadow_lock)); + + pfn = machine_to_phys_mapping[mfn]; + + /* We use values with the top bit set to mark MFNs that aren't + really part of the domain's psuedo-physical memory map e.g. + the shared info frame. Nothing to do here... + */ + if ( unlikely(pfn & 0x80000000U) ) return rc; + + ASSERT(m->shadow_dirty_bitmap); + if( likely(pfnshadow_dirty_bitmap_size) ) + { + /* These updates occur with mm.shadow_lock held, so use + (__) version of test_and_set */ + if( __test_and_set_bit( pfn, m->shadow_dirty_bitmap ) == 0 ) + { + // if we set it + m->shadow_dirty_count++; + rc = 1; + } + } + else + { + extern void show_traceX(void); + SH_LOG("mark_dirty OOR! mfn=%x pfn=%x max=%x (mm %p)", + mfn, pfn, m->shadow_dirty_bitmap_size, m ); + SH_LOG("dom=%u caf=%08x taf=%08x\n", + frame_table[mfn].u.domain->domain, + frame_table[mfn].count_and_flags, + frame_table[mfn].type_and_flags ); + } + + return rc; +} + + +static inline int mark_dirty( struct mm_struct *m, unsigned int mfn ) +{ + int rc; + ASSERT(local_irq_is_enabled()); + //if(spin_is_locked(&m->shadow_lock)) printk("+"); + spin_lock(&m->shadow_lock); + rc = __mark_dirty( m, mfn ); + spin_unlock(&m->shadow_lock); + return rc; +} + + +/************************************************************************/ + +static inline void l1pte_write_fault( struct mm_struct *m, + unsigned long *gpte_p, unsigned long *spte_p ) +{ + unsigned long gpte = *gpte_p; + unsigned long spte = *spte_p; + + switch( m->shadow_mode ) + { + case SHM_test: + spte = gpte; + gpte |= _PAGE_DIRTY | _PAGE_ACCESSED; + spte |= _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED; + break; + + case SHM_logdirty: + spte = gpte; + gpte |= _PAGE_DIRTY | _PAGE_ACCESSED; + spte |= _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED; + __mark_dirty( m, (gpte >> PAGE_SHIFT) ); + break; + } + + *gpte_p = gpte; + *spte_p = spte; +} + +static inline void l1pte_read_fault( struct mm_struct *m, + unsigned long *gpte_p, unsigned long *spte_p ) +{ + unsigned long gpte = *gpte_p; + unsigned long spte = *spte_p; + + switch( m->shadow_mode ) + { + case SHM_test: + spte = gpte; + gpte |= _PAGE_ACCESSED; + spte |= _PAGE_ACCESSED; + if ( ! (gpte & _PAGE_DIRTY ) ) + spte &= ~ _PAGE_RW; + break; + + case SHM_logdirty: + spte = gpte; + gpte |= _PAGE_ACCESSED; + spte |= _PAGE_ACCESSED; + spte &= ~ _PAGE_RW; + break; + } + + *gpte_p = gpte; + *spte_p = spte; +} + +static inline void l1pte_no_fault( struct mm_struct *m, + unsigned long *gpte_p, unsigned long *spte_p ) +{ + unsigned long gpte = *gpte_p; + unsigned long spte = *spte_p; + + switch( m->shadow_mode ) + { + case SHM_test: + spte = 0; + if ( (gpte & (_PAGE_PRESENT|_PAGE_ACCESSED) ) == + (_PAGE_PRESENT|_PAGE_ACCESSED) ) + { + spte = gpte; + if ( ! (gpte & _PAGE_DIRTY ) ) + spte &= ~ _PAGE_RW; + } + break; + + case SHM_logdirty: + spte = 0; + if ( (gpte & (_PAGE_PRESENT|_PAGE_ACCESSED) ) == + (_PAGE_PRESENT|_PAGE_ACCESSED) ) + { + spte = gpte; + spte &= ~ _PAGE_RW; + } + + break; + } + + *gpte_p = gpte; + *spte_p = spte; +} + +static inline void l2pde_general( struct mm_struct *m, + unsigned long *gpde_p, unsigned long *spde_p, + unsigned long sl1pfn) +{ + unsigned long gpde = *gpde_p; + unsigned long spde = *spde_p; + + spde = 0; + + if ( sl1pfn ) + { + spde = (gpde & ~PAGE_MASK) | (sl1pfn<shadow_ht[j]; + if(a->pfn){live++; ASSERT(a->spfn_and_flags&PSH_pfn_mask);} + ASSERT((a->pfn&0xf0000000)==0); + ASSERT(a->pfn<0x00100000); + a=a->next; + while(a && live<9999) + { + live++; + if(a->pfn == 0 || a->spfn_and_flags == 0) + { + printk("XXX live=%d pfn=%08lx sp=%08lx next=%p\n", + live, a->pfn, a->spfn_and_flags, a->next); + BUG(); + } + ASSERT(a->pfn); + ASSERT((a->pfn&0xf0000000)==0); + ASSERT(a->pfn<0x00100000); + ASSERT(a->spfn_and_flags&PSH_pfn_mask); + a=a->next; + } + ASSERT(live<9999); + } + + a = m->shadow_ht_free; + while(a) { free++; a=a->next; } + + if(print) printk("Xlive=%d free=%d\n",live,free); + + abs=(perfc_value(shadow_l1_pages)+perfc_value(shadow_l2_pages))-live; + if( abs < -1 || abs > 1 ) + { + printk("live=%d free=%d l1=%d l2=%d\n",live,free, + perfc_value(shadow_l1_pages), perfc_value(shadow_l2_pages) ); + BUG(); + } + +} + +#else +#define shadow_audit(p, print) +#endif + + + +static inline struct shadow_status* hash_bucket( struct mm_struct *m, + unsigned int gpfn ) +{ + return &(m->shadow_ht[gpfn % shadow_ht_buckets]); +} + + +static inline unsigned long __shadow_status( struct mm_struct *m, + unsigned int gpfn ) +{ + struct shadow_status **ob, *b, *B = hash_bucket( m, gpfn ); + + b = B; + ob = NULL; + + SH_VVLOG("lookup gpfn=%08x bucket=%p", gpfn, b ); + shadow_audit(m,0); // if in debug mode + + do + { + if ( b->pfn == gpfn ) + { + unsigned long t; + struct shadow_status *x; + + // swap with head + t=B->pfn; B->pfn=b->pfn; b->pfn=t; + t=B->spfn_and_flags; B->spfn_and_flags=b->spfn_and_flags; + b->spfn_and_flags=t; + + if( ob ) + { // pull to front + *ob=b->next; + x=B->next; + B->next=b; + b->next=x; + } + return B->spfn_and_flags; + } +#if SHADOW_HASH_DEBUG + else + { + if(b!=B)ASSERT(b->pfn); + } +#endif + ob=&b->next; + b=b->next; + } + while (b); + + return 0; +} + +/* we can make this locking more fine grained e.g. per shadow page if it +ever becomes a problem, but since we need a spin lock on the hash table +anyway its probably not worth being too clever. */ + +static inline unsigned long get_shadow_status( struct mm_struct *m, + unsigned int gpfn ) +{ + unsigned long res; + + /* If we get here, we know that this domain is running in shadow mode. + We also know that some sort of update has happened to the underlying + page table page: either a PTE has been updated, or the page has + changed type. If we're in log dirty mode, we should set the approrpiate + bit in the dirty bitmap. + NB: the VA update path doesn't use this so needs to be handled + independnetly. + */ + + ASSERT(local_irq_is_enabled()); + //if(spin_is_locked(&m->shadow_lock)) printk("*"); + spin_lock(&m->shadow_lock); + + if( m->shadow_mode == SHM_logdirty ) + __mark_dirty( m, gpfn ); + + res = __shadow_status( m, gpfn ); + if (!res) spin_unlock(&m->shadow_lock); + return res; +} + + +static inline void put_shadow_status( struct mm_struct *m ) +{ + spin_unlock(&m->shadow_lock); +} + + +static inline void delete_shadow_status( struct mm_struct *m, + unsigned int gpfn ) +{ + struct shadow_status *b, *B, **ob; + + ASSERT(spin_is_locked(&m->shadow_lock)); + + B = b = hash_bucket( m, gpfn ); + + SH_VVLOG("delete gpfn=%08x bucket=%p", gpfn, b ); + shadow_audit(m,0); + ASSERT(gpfn); + + if( b->pfn == gpfn ) + { + if (b->next) + { + struct shadow_status *D=b->next; + b->spfn_and_flags = b->next->spfn_and_flags; + b->pfn = b->next->pfn; + + b->next = b->next->next; + D->next = m->shadow_ht_free; + D->pfn = 0; + D->spfn_and_flags = 0; + m->shadow_ht_free = D; + } + else + { + b->pfn = 0; + b->spfn_and_flags = 0; + } + +#if SHADOW_HASH_DEBUG + if( __shadow_status(m,gpfn) ) BUG(); + shadow_audit(m,0); +#endif + return; + } + + ob = &b->next; + b=b->next; + + do + { + if ( b->pfn == gpfn ) + { + b->pfn = 0; + b->spfn_and_flags = 0; + + // b is in the list + *ob=b->next; + b->next = m->shadow_ht_free; + m->shadow_ht_free = b; + +#if SHADOW_HASH_DEBUG + if( __shadow_status(m,gpfn) ) BUG(); +#endif + shadow_audit(m,0); + return; + } + + ob = &b->next; + b=b->next; + } + while (b); + + // if we got here, it wasn't in the list + BUG(); +} + + +static inline void set_shadow_status( struct mm_struct *m, + unsigned int gpfn, unsigned long s ) +{ + struct shadow_status *b, *B, *extra, **fptr; + int i; + + ASSERT(spin_is_locked(&m->shadow_lock)); + + B = b = hash_bucket( m, gpfn ); + + ASSERT(gpfn); + SH_VVLOG("set gpfn=%08x s=%08lx bucket=%p(%p)", gpfn, s, b, b->next ); + + shadow_audit(m,0); + + do + { + if ( b->pfn == gpfn ) + { + b->spfn_and_flags = s; + shadow_audit(m,0); + return; + } + + b=b->next; + } + while (b); + + // if we got here, this is an insert rather than update + + ASSERT( s ); // deletes must have succeeded by here + + if ( B->pfn == 0 ) + { + // we can use this head + ASSERT( B->next == 0 ); + B->pfn = gpfn; + B->spfn_and_flags = s; + shadow_audit(m,0); + return; + } + + if( unlikely(m->shadow_ht_free == NULL) ) + { + SH_LOG("allocate more shadow hashtable blocks"); + + // we need to allocate more space + extra = kmalloc(sizeof(void*) + (shadow_ht_extra_size * + sizeof(struct shadow_status))); + + if( ! extra ) BUG(); // should be more graceful here.... + + memset(extra, 0, sizeof(void*) + (shadow_ht_extra_size * + sizeof(struct shadow_status))); + + m->shadow_extras_count++; + + // add extras to free list + fptr = &m->shadow_ht_free; + for ( i=0; ishadow_ht_extras; + m->shadow_ht_extras = extra; + + } + + // should really put this in B to go right to front + b = m->shadow_ht_free; + m->shadow_ht_free = b->next; + b->spfn_and_flags = s; + b->pfn = gpfn; + b->next = B->next; + B->next = b; + + shadow_audit(m,0); + + return; +} + +static inline void __shadow_mk_pagetable( struct mm_struct *mm ) +{ + unsigned long gpfn, spfn=0; + + gpfn = pagetable_val(mm->pagetable) >> PAGE_SHIFT; + + if ( unlikely((spfn=__shadow_status(mm, gpfn)) == 0 ) ) + { + spfn = shadow_l2_table(mm, gpfn ); + } + mm->shadow_table = mk_pagetable(spfn<pagetable), mm->shadow_mode ); + + if ( unlikely(mm->shadow_mode) ) + { + ASSERT(local_irq_is_enabled()); + spin_lock(&mm->shadow_lock); + + __shadow_mk_pagetable( mm ); + + spin_unlock(&mm->shadow_lock); + } + + SH_VVLOG("leaving shadow_mk_pagetable( gptbase=%08lx, mode=%d ) sh=%08lx", + pagetable_val(mm->pagetable), mm->shadow_mode, + pagetable_val(mm->shadow_table) ); + +} + + +#if SHADOW_DEBUG +extern int check_pagetable(struct mm_struct *m, pagetable_t pt, char *s); +#else +#define check_pagetable(m, pt, s) ((void)0) +#endif + + +#endif /* XEN_SHADOW_H */ + + diff --git a/xen/include/asm-x86/smp.h b/xen/include/asm-x86/smp.h index ac9cc5292f..25c29de2e8 100644 --- a/xen/include/asm-x86/smp.h +++ b/xen/include/asm-x86/smp.h @@ -42,7 +42,6 @@ extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs); extern void smp_send_reschedule(int cpu); extern void smp_invalidate_rcv(void); /* Process an NMI */ extern void (*mtrr_hook) (void); -extern void zap_low_mappings (void); /* * On x86 all CPUs are mapped 1:1 to the APIC space. diff --git a/xen/include/asm-x86/types.h b/xen/include/asm-x86/types.h index e2b229edcf..3f1f0a6c6a 100644 --- a/xen/include/asm-x86/types.h +++ b/xen/include/asm-x86/types.h @@ -56,4 +56,6 @@ typedef unsigned long size_t; typedef unsigned long dma_addr_t; typedef u64 dma64_addr_t; +typedef unsigned short kmem_bufctl_t; + #endif diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h index f4d9d72f9c..90fce051b1 100644 --- a/xen/include/xen/pci.h +++ b/xen/include/xen/pci.h @@ -393,6 +393,10 @@ struct pci_dev { this is D0-D3, D0 being fully functional, and D3 being off. */ +#ifdef LINUX_2_6 + struct device dev; /* Generic device interface */ +#endif + /* device is compatible with these IDs */ unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE]; unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE]; diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 3725801477..206ce157ae 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -15,6 +15,7 @@ #include #include #include +#include #define STACK_SIZE (2*PAGE_SIZE) #include diff --git a/xen/include/xen/shadow.h b/xen/include/xen/shadow.h index e4dbd1b061..c59e02e14c 100644 --- a/xen/include/xen/shadow.h +++ b/xen/include/xen/shadow.h @@ -1,599 +1 @@ -/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*- */ - -#ifndef _XEN_SHADOW_H -#define _XEN_SHADOW_H - -#include -#include -#include -#include - - -/* Shadow PT flag bits in pfn_info */ -#define PSH_shadowed (1<<31) /* page has a shadow. PFN points to shadow */ -#define PSH_pending (1<<29) /* page is in the process of being shadowed */ -#define PSH_pfn_mask ((1<<21)-1) - -/* Shadow PT operation mode : shadowmode variable in mm_struct */ -#define SHM_test (1) /* just run domain on shadow PTs */ -#define SHM_logdirty (2) /* log pages that are dirtied */ -#define SHM_translate (3) /* lookup machine pages in translation table */ -//#define SHM_cow (4) /* copy on write all dirtied pages */ - - -#define shadow_linear_pg_table ((l1_pgentry_t *)SH_LINEAR_PT_VIRT_START) -#define shadow_linear_l2_table ((l2_pgentry_t *)(SH_LINEAR_PT_VIRT_START+(SH_LINEAR_PT_VIRT_START>>(L2_PAGETABLE_SHIFT-L1_PAGETABLE_SHIFT)))) - -extern void shadow_mode_init(void); -extern int shadow_mode_control( struct domain *p, dom0_shadow_control_t *sc ); -extern int shadow_fault( unsigned long va, long error_code ); -extern void shadow_l1_normal_pt_update( unsigned long pa, unsigned long gpte, - unsigned long *prev_spfn_ptr, - l1_pgentry_t **prev_spl1e_ptr ); -extern void shadow_l2_normal_pt_update( unsigned long pa, unsigned long gpte ); -extern void unshadow_table( unsigned long gpfn, unsigned int type ); -extern int shadow_mode_enable( struct domain *p, unsigned int mode ); -extern void shadow_mode_disable( struct domain *p ); -extern unsigned long shadow_l2_table( - struct mm_struct *m, unsigned long gpfn ); - -#define SHADOW_DEBUG 0 -#define SHADOW_HASH_DEBUG 0 -#define SHADOW_OPTIMISE 1 - -struct shadow_status { - unsigned long pfn; // gpfn - unsigned long spfn_and_flags; // spfn plus flags - struct shadow_status *next; // use pull-to-front list. -}; - -#define shadow_ht_extra_size 128 /*128*/ -#define shadow_ht_buckets 256 /*256*/ - -#ifndef NDEBUG -#define SH_LOG(_f, _a...) \ -printk("DOM%u: (file=shadow.c, line=%d) " _f "\n", \ - current->domain , __LINE__ , ## _a ) -#else -#define SH_LOG(_f, _a...) -#endif - -#if SHADOW_DEBUG -#define SH_VLOG(_f, _a...) \ - printk("DOM%u: (file=shadow.c, line=%d) " _f "\n", \ - current->domain , __LINE__ , ## _a ) -#else -#define SH_VLOG(_f, _a...) -#endif - -#if 0 -#define SH_VVLOG(_f, _a...) \ - printk("DOM%u: (file=shadow.c, line=%d) " _f "\n", \ - current->domain , __LINE__ , ## _a ) -#else -#define SH_VVLOG(_f, _a...) -#endif - - -/************************************************************************/ - -static inline int __mark_dirty( struct mm_struct *m, unsigned int mfn ) -{ - unsigned int pfn; - int rc = 0; - - ASSERT(spin_is_locked(&m->shadow_lock)); - - pfn = machine_to_phys_mapping[mfn]; - - /* We use values with the top bit set to mark MFNs that aren't - really part of the domain's psuedo-physical memory map e.g. - the shared info frame. Nothing to do here... - */ - if ( unlikely(pfn & 0x80000000U) ) return rc; - - ASSERT(m->shadow_dirty_bitmap); - if( likely(pfnshadow_dirty_bitmap_size) ) - { - /* These updates occur with mm.shadow_lock held, so use - (__) version of test_and_set */ - if( __test_and_set_bit( pfn, m->shadow_dirty_bitmap ) == 0 ) - { - // if we set it - m->shadow_dirty_count++; - rc = 1; - } - } - else - { - extern void show_traceX(void); - SH_LOG("mark_dirty OOR! mfn=%x pfn=%x max=%x (mm %p)", - mfn, pfn, m->shadow_dirty_bitmap_size, m ); - SH_LOG("dom=%u caf=%08x taf=%08x\n", - frame_table[mfn].u.domain->domain, - frame_table[mfn].count_and_flags, - frame_table[mfn].type_and_flags ); - } - - return rc; -} - - -static inline int mark_dirty( struct mm_struct *m, unsigned int mfn ) -{ - int rc; - ASSERT(local_irq_is_enabled()); - //if(spin_is_locked(&m->shadow_lock)) printk("+"); - spin_lock(&m->shadow_lock); - rc = __mark_dirty( m, mfn ); - spin_unlock(&m->shadow_lock); - return rc; -} - - -/************************************************************************/ - -static inline void l1pte_write_fault( struct mm_struct *m, - unsigned long *gpte_p, unsigned long *spte_p ) -{ - unsigned long gpte = *gpte_p; - unsigned long spte = *spte_p; - - switch( m->shadow_mode ) - { - case SHM_test: - spte = gpte; - gpte |= _PAGE_DIRTY | _PAGE_ACCESSED; - spte |= _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED; - break; - - case SHM_logdirty: - spte = gpte; - gpte |= _PAGE_DIRTY | _PAGE_ACCESSED; - spte |= _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED; - __mark_dirty( m, (gpte >> PAGE_SHIFT) ); - break; - } - - *gpte_p = gpte; - *spte_p = spte; -} - -static inline void l1pte_read_fault( struct mm_struct *m, - unsigned long *gpte_p, unsigned long *spte_p ) -{ - unsigned long gpte = *gpte_p; - unsigned long spte = *spte_p; - - switch( m->shadow_mode ) - { - case SHM_test: - spte = gpte; - gpte |= _PAGE_ACCESSED; - spte |= _PAGE_ACCESSED; - if ( ! (gpte & _PAGE_DIRTY ) ) - spte &= ~ _PAGE_RW; - break; - - case SHM_logdirty: - spte = gpte; - gpte |= _PAGE_ACCESSED; - spte |= _PAGE_ACCESSED; - spte &= ~ _PAGE_RW; - break; - } - - *gpte_p = gpte; - *spte_p = spte; -} - -static inline void l1pte_no_fault( struct mm_struct *m, - unsigned long *gpte_p, unsigned long *spte_p ) -{ - unsigned long gpte = *gpte_p; - unsigned long spte = *spte_p; - - switch( m->shadow_mode ) - { - case SHM_test: - spte = 0; - if ( (gpte & (_PAGE_PRESENT|_PAGE_ACCESSED) ) == - (_PAGE_PRESENT|_PAGE_ACCESSED) ) - { - spte = gpte; - if ( ! (gpte & _PAGE_DIRTY ) ) - spte &= ~ _PAGE_RW; - } - break; - - case SHM_logdirty: - spte = 0; - if ( (gpte & (_PAGE_PRESENT|_PAGE_ACCESSED) ) == - (_PAGE_PRESENT|_PAGE_ACCESSED) ) - { - spte = gpte; - spte &= ~ _PAGE_RW; - } - - break; - } - - *gpte_p = gpte; - *spte_p = spte; -} - -static inline void l2pde_general( struct mm_struct *m, - unsigned long *gpde_p, unsigned long *spde_p, - unsigned long sl1pfn) -{ - unsigned long gpde = *gpde_p; - unsigned long spde = *spde_p; - - spde = 0; - - if ( sl1pfn ) - { - spde = (gpde & ~PAGE_MASK) | (sl1pfn<shadow_ht[j]; - if(a->pfn){live++; ASSERT(a->spfn_and_flags&PSH_pfn_mask);} - ASSERT((a->pfn&0xf0000000)==0); - ASSERT(a->pfn<0x00100000); - a=a->next; - while(a && live<9999) - { - live++; - if(a->pfn == 0 || a->spfn_and_flags == 0) - { - printk("XXX live=%d pfn=%08lx sp=%08lx next=%p\n", - live, a->pfn, a->spfn_and_flags, a->next); - BUG(); - } - ASSERT(a->pfn); - ASSERT((a->pfn&0xf0000000)==0); - ASSERT(a->pfn<0x00100000); - ASSERT(a->spfn_and_flags&PSH_pfn_mask); - a=a->next; - } - ASSERT(live<9999); - } - - a = m->shadow_ht_free; - while(a) { free++; a=a->next; } - - if(print) printk("Xlive=%d free=%d\n",live,free); - - abs=(perfc_value(shadow_l1_pages)+perfc_value(shadow_l2_pages))-live; - if( abs < -1 || abs > 1 ) - { - printk("live=%d free=%d l1=%d l2=%d\n",live,free, - perfc_value(shadow_l1_pages), perfc_value(shadow_l2_pages) ); - BUG(); - } - -} - -#else -#define shadow_audit(p, print) -#endif - - - -static inline struct shadow_status* hash_bucket( struct mm_struct *m, - unsigned int gpfn ) -{ - return &(m->shadow_ht[gpfn % shadow_ht_buckets]); -} - - -static inline unsigned long __shadow_status( struct mm_struct *m, - unsigned int gpfn ) -{ - struct shadow_status **ob, *b, *B = hash_bucket( m, gpfn ); - - b = B; - ob = NULL; - - SH_VVLOG("lookup gpfn=%08x bucket=%p", gpfn, b ); - shadow_audit(m,0); // if in debug mode - - do - { - if ( b->pfn == gpfn ) - { - unsigned long t; - struct shadow_status *x; - - // swap with head - t=B->pfn; B->pfn=b->pfn; b->pfn=t; - t=B->spfn_and_flags; B->spfn_and_flags=b->spfn_and_flags; - b->spfn_and_flags=t; - - if( ob ) - { // pull to front - *ob=b->next; - x=B->next; - B->next=b; - b->next=x; - } - return B->spfn_and_flags; - } -#if SHADOW_HASH_DEBUG - else - { - if(b!=B)ASSERT(b->pfn); - } -#endif - ob=&b->next; - b=b->next; - } - while (b); - - return 0; -} - -/* we can make this locking more fine grained e.g. per shadow page if it -ever becomes a problem, but since we need a spin lock on the hash table -anyway its probably not worth being too clever. */ - -static inline unsigned long get_shadow_status( struct mm_struct *m, - unsigned int gpfn ) -{ - unsigned long res; - - /* If we get here, we know that this domain is running in shadow mode. - We also know that some sort of update has happened to the underlying - page table page: either a PTE has been updated, or the page has - changed type. If we're in log dirty mode, we should set the approrpiate - bit in the dirty bitmap. - NB: the VA update path doesn't use this so needs to be handled - independnetly. - */ - - ASSERT(local_irq_is_enabled()); - //if(spin_is_locked(&m->shadow_lock)) printk("*"); - spin_lock(&m->shadow_lock); - - if( m->shadow_mode == SHM_logdirty ) - __mark_dirty( m, gpfn ); - - res = __shadow_status( m, gpfn ); - if (!res) spin_unlock(&m->shadow_lock); - return res; -} - - -static inline void put_shadow_status( struct mm_struct *m ) -{ - spin_unlock(&m->shadow_lock); -} - - -static inline void delete_shadow_status( struct mm_struct *m, - unsigned int gpfn ) -{ - struct shadow_status *b, *B, **ob; - - ASSERT(spin_is_locked(&m->shadow_lock)); - - B = b = hash_bucket( m, gpfn ); - - SH_VVLOG("delete gpfn=%08x bucket=%p", gpfn, b ); - shadow_audit(m,0); - ASSERT(gpfn); - - if( b->pfn == gpfn ) - { - if (b->next) - { - struct shadow_status *D=b->next; - b->spfn_and_flags = b->next->spfn_and_flags; - b->pfn = b->next->pfn; - - b->next = b->next->next; - D->next = m->shadow_ht_free; - D->pfn = 0; - D->spfn_and_flags = 0; - m->shadow_ht_free = D; - } - else - { - b->pfn = 0; - b->spfn_and_flags = 0; - } - -#if SHADOW_HASH_DEBUG - if( __shadow_status(m,gpfn) ) BUG(); - shadow_audit(m,0); -#endif - return; - } - - ob = &b->next; - b=b->next; - - do - { - if ( b->pfn == gpfn ) - { - b->pfn = 0; - b->spfn_and_flags = 0; - - // b is in the list - *ob=b->next; - b->next = m->shadow_ht_free; - m->shadow_ht_free = b; - -#if SHADOW_HASH_DEBUG - if( __shadow_status(m,gpfn) ) BUG(); -#endif - shadow_audit(m,0); - return; - } - - ob = &b->next; - b=b->next; - } - while (b); - - // if we got here, it wasn't in the list - BUG(); -} - - -static inline void set_shadow_status( struct mm_struct *m, - unsigned int gpfn, unsigned long s ) -{ - struct shadow_status *b, *B, *extra, **fptr; - int i; - - ASSERT(spin_is_locked(&m->shadow_lock)); - - B = b = hash_bucket( m, gpfn ); - - ASSERT(gpfn); - SH_VVLOG("set gpfn=%08x s=%08lx bucket=%p(%p)", gpfn, s, b, b->next ); - - shadow_audit(m,0); - - do - { - if ( b->pfn == gpfn ) - { - b->spfn_and_flags = s; - shadow_audit(m,0); - return; - } - - b=b->next; - } - while (b); - - // if we got here, this is an insert rather than update - - ASSERT( s ); // deletes must have succeeded by here - - if ( B->pfn == 0 ) - { - // we can use this head - ASSERT( B->next == 0 ); - B->pfn = gpfn; - B->spfn_and_flags = s; - shadow_audit(m,0); - return; - } - - if( unlikely(m->shadow_ht_free == NULL) ) - { - SH_LOG("allocate more shadow hashtable blocks"); - - // we need to allocate more space - extra = kmalloc(sizeof(void*) + (shadow_ht_extra_size * - sizeof(struct shadow_status))); - - if( ! extra ) BUG(); // should be more graceful here.... - - memset(extra, 0, sizeof(void*) + (shadow_ht_extra_size * - sizeof(struct shadow_status))); - - m->shadow_extras_count++; - - // add extras to free list - fptr = &m->shadow_ht_free; - for ( i=0; ishadow_ht_extras; - m->shadow_ht_extras = extra; - - } - - // should really put this in B to go right to front - b = m->shadow_ht_free; - m->shadow_ht_free = b->next; - b->spfn_and_flags = s; - b->pfn = gpfn; - b->next = B->next; - B->next = b; - - shadow_audit(m,0); - - return; -} - -static inline void __shadow_mk_pagetable( struct mm_struct *mm ) -{ - unsigned long gpfn, spfn=0; - - gpfn = pagetable_val(mm->pagetable) >> PAGE_SHIFT; - - if ( unlikely((spfn=__shadow_status(mm, gpfn)) == 0 ) ) - { - spfn = shadow_l2_table(mm, gpfn ); - } - mm->shadow_table = mk_pagetable(spfn<pagetable), mm->shadow_mode ); - - if ( unlikely(mm->shadow_mode) ) - { - ASSERT(local_irq_is_enabled()); - spin_lock(&mm->shadow_lock); - - __shadow_mk_pagetable( mm ); - - spin_unlock(&mm->shadow_lock); - } - - SH_VVLOG("leaving shadow_mk_pagetable( gptbase=%08lx, mode=%d ) sh=%08lx", - pagetable_val(mm->pagetable), mm->shadow_mode, - pagetable_val(mm->shadow_table) ); - -} - - -#if SHADOW_DEBUG -extern int check_pagetable(struct mm_struct *m, pagetable_t pt, char *s); -#else -#define check_pagetable(m, pt, s) ((void)0) -#endif - - -#endif /* XEN_SHADOW_H */ - - +#include diff --git a/xen/include/xen/smp.h b/xen/include/xen/smp.h index d7f71b6fae..12885a5037 100644 --- a/xen/include/xen/smp.h +++ b/xen/include/xen/smp.h @@ -72,7 +72,9 @@ extern volatile int smp_msg_id; /* * These macros fold the SMP functionality into a single CPU system */ - + +#define smp_send_event_check_mask(_m) ((void)0) +#define smp_send_event_check_cpu(_p) ((void)0) #define smp_num_cpus 1 #define smp_processor_id() 0 #define hard_smp_processor_id() 0 diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h index 206f3c1762..b74b5f802f 100644 --- a/xen/include/xen/spinlock.h +++ b/xen/include/xen/spinlock.h @@ -54,6 +54,8 @@ typedef struct { int gcc_is_buggy; } spinlock_t; #define spin_trylock(lock) ({1; }) #define spin_unlock_wait(lock) do { } while(0) #define spin_unlock(lock) do { } while(0) +#define spin_lock_recursive(lock) do { } while(0) +#define spin_unlock_recursive(lock) do { } while(0) #if (__GNUC__ > 2) typedef struct { } rwlock_t;