mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
Manual merge.
This commit is contained in:
commit
00244f3e7b
31 files changed
+306
-127
No files matched your search
@@ -115,7 +115,7 @@ config-update-pae:
|
||||
ifeq ($(XEN_TARGET_X86_PAE),y)
|
||||
sed -e 's!^CONFIG_HIGHMEM4G=y$$!\# CONFIG_HIGHMEM4G is not set!;s!^\# CONFIG_HIGHMEM64G is not set$$!CONFIG_HIGHMEM64G=y!' $(CONFIG_FILE) > $(CONFIG_FILE)- && mv $(CONFIG_FILE)- $(CONFIG_FILE)
|
||||
else
|
||||
@: # do nothing yet
|
||||
grep '^CONFIG_HIGHMEM64G=y' $(CONFIG_FILE) >/dev/null && ( sed -e 's!^CONFIG_HIGHMEM64G=y$$!\# CONFIG_HIGHMEM64G is not set!;s!^\# CONFIG_HIGHMEM4G is not set$$!CONFIG_HIGHMEM4G=y!' $(CONFIG_FILE) > $(CONFIG_FILE)- && mv $(CONFIG_FILE)- $(CONFIG_FILE) ) || true
|
||||
endif
|
||||
|
||||
# never delete any intermediate files.
|
||||
|
||||
@@ -61,7 +61,6 @@ SUBDIRS += arch/xen/drivers/console
|
||||
SUBDIRS += arch/xen/drivers/evtchn
|
||||
SUBDIRS += arch/xen/drivers/blkif
|
||||
SUBDIRS += arch/xen/drivers/netif
|
||||
#SUBDIRS += arch/xen/drivers/usbif
|
||||
SUBDIRS += arch/xen/drivers/balloon
|
||||
ifdef CONFIG_XEN_PRIVILEGED_GUEST
|
||||
SUBDIRS += arch/xen/drivers/dom0
|
||||
@@ -72,7 +71,6 @@ CORE_FILES += arch/xen/drivers/evtchn/drv.o
|
||||
CORE_FILES += arch/xen/drivers/console/drv.o
|
||||
DRIVERS += arch/xen/drivers/blkif/drv.o
|
||||
DRIVERS += arch/xen/drivers/netif/drv.o
|
||||
DRIVERS += arch/xen/drivers/usbif/drv.o
|
||||
ifdef CONFIG_XEN_PRIVILEGED_GUEST
|
||||
CORE_FILES += arch/xen/drivers/dom0/drv.o
|
||||
endif
|
||||
|
||||
@@ -16,14 +16,10 @@ mainmenu_option next_comment
|
||||
comment 'Xen'
|
||||
bool 'Support for privileged operations (domain 0)' CONFIG_XEN_PRIVILEGED_GUEST
|
||||
bool 'Device-driver domain (physical device access)' CONFIG_XEN_PHYSDEV_ACCESS
|
||||
if [ "$CONFIG_XEN_PHYSDEV_ACCESS" = "y" ]; then
|
||||
bool 'USB-device backend driver' CONFIG_XEN_USB_BACKEND
|
||||
fi
|
||||
bool 'Scrub memory before freeing it to Xen' CONFIG_XEN_SCRUB_PAGES
|
||||
bool 'Network-device frontend driver' CONFIG_XEN_NETDEV_FRONTEND
|
||||
bool 'Block-device frontend driver' CONFIG_XEN_BLKDEV_FRONTEND
|
||||
bool 'Block-device uses grant tables' CONFIG_XEN_BLKDEV_GRANT
|
||||
bool 'USB-device frontend driver' CONFIG_XEN_USB_FRONTEND
|
||||
endmenu
|
||||
# The IBM S/390 patch needs this.
|
||||
define_bool CONFIG_NO_IDLE_HZ y
|
||||
@@ -267,7 +263,7 @@ fi
|
||||
|
||||
source drivers/char/Config.in
|
||||
|
||||
if [ "$CONFIG_XEN_PHYSDEV_ACCESS" = "y" -o "$CONFIG_XEN_USB_FRONTEND" = "y" ]; then
|
||||
if [ "$CONFIG_XEN_PHYSDEV_ACCESS" = "y" ]; then
|
||||
source drivers/media/Config.in
|
||||
fi
|
||||
|
||||
@@ -302,14 +298,8 @@ if [ "$CONFIG_XEN_PHYSDEV_ACCESS" = "y" ]; then
|
||||
endmenu
|
||||
fi
|
||||
|
||||
if [ "$CONFIG_XEN_PHYSDEV_ACCESS" = "y" -o "$CONFIG_XEN_USB_FRONTEND" = "y" ]; then
|
||||
if [ "$CONFIG_XEN_USB_FRONTEND" = "y" -o "$CONFIG_XEN_USB_BACKEND" = "y" ]; then
|
||||
define_bool CONFIG_USB y
|
||||
fi
|
||||
source drivers/usb/Config.in
|
||||
fi
|
||||
|
||||
if [ "$CONFIG_XEN_PHYSDEV_ACCESS" = "y" ]; then
|
||||
source drivers/usb/Config.in
|
||||
source net/bluetooth/Config.in
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# Automatically generated make config: don't edit
|
||||
# Linux kernel version: 2.6.12-xen0
|
||||
# Mon Jul 25 09:48:34 2005
|
||||
# Wed Aug 3 09:54:56 2005
|
||||
#
|
||||
CONFIG_XEN=y
|
||||
CONFIG_ARCH_XEN=y
|
||||
@@ -18,8 +18,8 @@ CONFIG_XEN_BLKDEV_GRANT=y
|
||||
CONFIG_XEN_NETDEV_BACKEND=y
|
||||
CONFIG_XEN_BLKDEV_FRONTEND=y
|
||||
CONFIG_XEN_NETDEV_FRONTEND=y
|
||||
#CONFIG_XEN_NETDEV_GRANT_TX=y
|
||||
#CONFIG_XEN_NETDEV_GRANT_RX=y
|
||||
# CONFIG_XEN_NETDEV_GRANT_TX is not set
|
||||
# CONFIG_XEN_NETDEV_GRANT_RX is not set
|
||||
# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set
|
||||
# CONFIG_XEN_BLKDEV_TAP is not set
|
||||
# CONFIG_XEN_SHADOW_MODE is not set
|
||||
@@ -93,11 +93,11 @@ CONFIG_GENERIC_IOMAP=y
|
||||
# CONFIG_M586 is not set
|
||||
# CONFIG_M586TSC is not set
|
||||
# CONFIG_M586MMX is not set
|
||||
# CONFIG_M686 is not set
|
||||
CONFIG_M686=y
|
||||
# CONFIG_MPENTIUMII is not set
|
||||
# CONFIG_MPENTIUMIII is not set
|
||||
# CONFIG_MPENTIUMM is not set
|
||||
CONFIG_MPENTIUM4=y
|
||||
# CONFIG_MPENTIUM4 is not set
|
||||
# CONFIG_MK6 is not set
|
||||
# CONFIG_MK7 is not set
|
||||
# CONFIG_MK8 is not set
|
||||
@@ -112,15 +112,15 @@ CONFIG_MPENTIUM4=y
|
||||
# CONFIG_X86_GENERIC is not set
|
||||
CONFIG_X86_CMPXCHG=y
|
||||
CONFIG_X86_XADD=y
|
||||
CONFIG_X86_L1_CACHE_SHIFT=7
|
||||
CONFIG_X86_L1_CACHE_SHIFT=5
|
||||
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
|
||||
CONFIG_GENERIC_CALIBRATE_DELAY=y
|
||||
CONFIG_X86_PPRO_FENCE=y
|
||||
CONFIG_X86_WP_WORKS_OK=y
|
||||
CONFIG_X86_INVLPG=y
|
||||
CONFIG_X86_BSWAP=y
|
||||
CONFIG_X86_POPAD_OK=y
|
||||
CONFIG_X86_GOOD_APIC=y
|
||||
CONFIG_X86_INTEL_USERCOPY=y
|
||||
CONFIG_X86_USE_PPRO_CHECKSUM=y
|
||||
# CONFIG_HPET_TIMER is not set
|
||||
# CONFIG_HPET_EMULATE_RTC is not set
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# Automatically generated make config: don't edit
|
||||
# Linux kernel version: 2.6.12-xen0
|
||||
# Wed Jun 29 10:01:20 2005
|
||||
# Tue Aug 2 23:55:35 2005
|
||||
#
|
||||
CONFIG_XEN=y
|
||||
CONFIG_ARCH_XEN=y
|
||||
@@ -18,6 +18,8 @@ CONFIG_XEN_BLKDEV_GRANT=y
|
||||
CONFIG_XEN_NETDEV_BACKEND=y
|
||||
CONFIG_XEN_BLKDEV_FRONTEND=y
|
||||
CONFIG_XEN_NETDEV_FRONTEND=y
|
||||
# CONFIG_XEN_NETDEV_GRANT_TX is not set
|
||||
# CONFIG_XEN_NETDEV_GRANT_RX is not set
|
||||
# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set
|
||||
# CONFIG_XEN_BLKDEV_TAP is not set
|
||||
# CONFIG_XEN_SHADOW_MODE is not set
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# Automatically generated make config: don't edit
|
||||
# Linux kernel version: 2.6.12-xenU
|
||||
# Mon Jul 25 10:06:06 2005
|
||||
# Wed Aug 3 09:57:44 2005
|
||||
#
|
||||
CONFIG_XEN=y
|
||||
CONFIG_ARCH_XEN=y
|
||||
@@ -15,8 +15,8 @@ CONFIG_NO_IDLE_HZ=y
|
||||
CONFIG_XEN_BLKDEV_GRANT=y
|
||||
CONFIG_XEN_BLKDEV_FRONTEND=y
|
||||
CONFIG_XEN_NETDEV_FRONTEND=y
|
||||
#CONFIG_XEN_NETDEV_GRANT_TX=y
|
||||
#CONFIG_XEN_NETDEV_GRANT_RX=y
|
||||
# CONFIG_XEN_NETDEV_GRANT_TX is not set
|
||||
# CONFIG_XEN_NETDEV_GRANT_RX is not set
|
||||
# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set
|
||||
# CONFIG_XEN_BLKDEV_TAP is not set
|
||||
# CONFIG_XEN_SHADOW_MODE is not set
|
||||
@@ -90,11 +90,11 @@ CONFIG_GENERIC_IOMAP=y
|
||||
# CONFIG_M586 is not set
|
||||
# CONFIG_M586TSC is not set
|
||||
# CONFIG_M586MMX is not set
|
||||
# CONFIG_M686 is not set
|
||||
CONFIG_M686=y
|
||||
# CONFIG_MPENTIUMII is not set
|
||||
# CONFIG_MPENTIUMIII is not set
|
||||
# CONFIG_MPENTIUMM is not set
|
||||
CONFIG_MPENTIUM4=y
|
||||
# CONFIG_MPENTIUM4 is not set
|
||||
# CONFIG_MK6 is not set
|
||||
# CONFIG_MK7 is not set
|
||||
# CONFIG_MK8 is not set
|
||||
@@ -109,15 +109,15 @@ CONFIG_MPENTIUM4=y
|
||||
# CONFIG_X86_GENERIC is not set
|
||||
CONFIG_X86_CMPXCHG=y
|
||||
CONFIG_X86_XADD=y
|
||||
CONFIG_X86_L1_CACHE_SHIFT=7
|
||||
CONFIG_X86_L1_CACHE_SHIFT=5
|
||||
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
|
||||
CONFIG_GENERIC_CALIBRATE_DELAY=y
|
||||
CONFIG_X86_PPRO_FENCE=y
|
||||
CONFIG_X86_WP_WORKS_OK=y
|
||||
CONFIG_X86_INVLPG=y
|
||||
CONFIG_X86_BSWAP=y
|
||||
CONFIG_X86_POPAD_OK=y
|
||||
CONFIG_X86_GOOD_APIC=y
|
||||
CONFIG_X86_INTEL_USERCOPY=y
|
||||
CONFIG_X86_USE_PPRO_CHECKSUM=y
|
||||
# CONFIG_HPET_TIMER is not set
|
||||
# CONFIG_HPET_EMULATE_RTC is not set
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# Automatically generated make config: don't edit
|
||||
# Linux kernel version: 2.6.12-xenU
|
||||
# Thu Jul 7 11:43:14 2005
|
||||
# Tue Aug 2 23:56:13 2005
|
||||
#
|
||||
CONFIG_XEN=y
|
||||
CONFIG_ARCH_XEN=y
|
||||
@@ -15,6 +15,8 @@ CONFIG_NO_IDLE_HZ=y
|
||||
CONFIG_XEN_BLKDEV_GRANT=y
|
||||
CONFIG_XEN_BLKDEV_FRONTEND=y
|
||||
CONFIG_XEN_NETDEV_FRONTEND=y
|
||||
# CONFIG_XEN_NETDEV_GRANT_TX is not set
|
||||
# CONFIG_XEN_NETDEV_GRANT_RX is not set
|
||||
# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set
|
||||
# CONFIG_XEN_BLKDEV_TAP is not set
|
||||
# CONFIG_XEN_SHADOW_MODE is not set
|
||||
|
||||
@@ -1529,7 +1529,7 @@ void __init smp_cpus_done(unsigned int max_cpus)
|
||||
extern irqreturn_t smp_reschedule_interrupt(int, void *, struct pt_regs *);
|
||||
extern irqreturn_t smp_call_function_interrupt(int, void *, struct pt_regs *);
|
||||
|
||||
void __init smp_intr_init(void)
|
||||
void smp_intr_init(void)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
@@ -1546,3 +1546,28 @@ void __init smp_intr_init(void)
|
||||
smp_call_function_interrupt,
|
||||
SA_INTERRUPT, callfunc_name[cpu], NULL));
|
||||
}
|
||||
|
||||
static void smp_intr_exit(void)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
free_irq(per_cpu(resched_irq, cpu), NULL);
|
||||
unbind_ipi_from_irq(RESCHEDULE_VECTOR);
|
||||
|
||||
free_irq(per_cpu(callfunc_irq, cpu), NULL);
|
||||
unbind_ipi_from_irq(CALL_FUNCTION_VECTOR);
|
||||
}
|
||||
|
||||
void smp_suspend(void)
|
||||
{
|
||||
/* XXX todo: take down time and ipi's on all cpus */
|
||||
local_teardown_timer_irq();
|
||||
smp_intr_exit();
|
||||
}
|
||||
|
||||
void smp_resume(void)
|
||||
{
|
||||
/* XXX todo: restore time and ipi's on all cpus */
|
||||
smp_intr_init();
|
||||
local_setup_timer_irq();
|
||||
}
|
||||
@@ -860,6 +860,8 @@ void start_hz_timer(void)
|
||||
void time_suspend(void)
|
||||
{
|
||||
/* nothing */
|
||||
teardown_irq(per_cpu(timer_irq, 0), &irq_timer);
|
||||
unbind_virq_from_irq(VIRQ_TIMER);
|
||||
}
|
||||
|
||||
/* No locking required. We are only CPU running, and interrupts are off. */
|
||||
@@ -874,10 +876,25 @@ void time_resume(void)
|
||||
processed_system_time =
|
||||
per_cpu(shadow_time, smp_processor_id()).system_timestamp;
|
||||
per_cpu(processed_system_time, 0) = processed_system_time;
|
||||
|
||||
per_cpu(timer_irq, 0) = bind_virq_to_irq(VIRQ_TIMER);
|
||||
(void)setup_irq(per_cpu(timer_irq, 0), &irq_timer);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static char timer_name[NR_CPUS][15];
|
||||
void local_setup_timer_irq(void)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
if (cpu == 0)
|
||||
return;
|
||||
per_cpu(timer_irq, cpu) = bind_virq_to_irq(VIRQ_TIMER);
|
||||
sprintf(timer_name[cpu], "timer%d", cpu);
|
||||
BUG_ON(request_irq(per_cpu(timer_irq, cpu), timer_interrupt,
|
||||
SA_INTERRUPT, timer_name[cpu], NULL));
|
||||
}
|
||||
|
||||
void local_setup_timer(void)
|
||||
{
|
||||
int seq, cpu = smp_processor_id();
|
||||
@@ -888,10 +905,17 @@ void local_setup_timer(void)
|
||||
per_cpu(shadow_time, cpu).system_timestamp;
|
||||
} while (read_seqretry(&xtime_lock, seq));
|
||||
|
||||
per_cpu(timer_irq, cpu) = bind_virq_to_irq(VIRQ_TIMER);
|
||||
sprintf(timer_name[cpu], "timer%d", cpu);
|
||||
BUG_ON(request_irq(per_cpu(timer_irq, cpu), timer_interrupt,
|
||||
SA_INTERRUPT, timer_name[cpu], NULL));
|
||||
local_setup_timer_irq();
|
||||
}
|
||||
|
||||
void local_teardown_timer_irq(void)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
if (cpu == 0)
|
||||
return;
|
||||
free_irq(per_cpu(timer_irq, cpu), NULL);
|
||||
unbind_virq_from_irq(VIRQ_TIMER);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -284,7 +284,7 @@ void unbind_ipi_from_irq(int ipi)
|
||||
evtchn_op_t op;
|
||||
int cpu = smp_processor_id();
|
||||
int evtchn = per_cpu(ipi_to_evtchn, cpu)[ipi];
|
||||
int irq = irq_to_evtchn[evtchn];
|
||||
int irq = evtchn_to_irq[evtchn];
|
||||
|
||||
spin_lock(&irq_mapping_update_lock);
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ static int errno;
|
||||
#include <asm-xen/xen-public/dom0_ops.h>
|
||||
#include <asm-xen/linux-public/suspend.h>
|
||||
#include <asm-xen/queues.h>
|
||||
#include <asm-xen/xenbus.h>
|
||||
|
||||
void machine_restart(char * __unused)
|
||||
{
|
||||
@@ -90,6 +91,10 @@ static void __do_suspend(void)
|
||||
#define gnttab_resume() do{}while(0)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
extern void smp_suspend(void);
|
||||
extern void smp_resume(void);
|
||||
#endif
|
||||
extern void time_suspend(void);
|
||||
extern void time_resume(void);
|
||||
extern unsigned long max_pfn;
|
||||
@@ -114,6 +119,12 @@ static void __do_suspend(void)
|
||||
|
||||
time_suspend();
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
smp_suspend();
|
||||
#endif
|
||||
|
||||
xenbus_suspend();
|
||||
|
||||
ctrl_if_suspend();
|
||||
|
||||
irq_suspend();
|
||||
@@ -153,6 +164,12 @@ static void __do_suspend(void)
|
||||
|
||||
ctrl_if_resume();
|
||||
|
||||
xenbus_resume();
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
smp_resume();
|
||||
#endif
|
||||
|
||||
time_resume();
|
||||
|
||||
blkdev_resume();
|
||||
|
||||
@@ -84,9 +84,6 @@ static struct timer_list balloon_timer;
|
||||
/* Flag for dom0 xenstore workaround */
|
||||
static int balloon_xenbus_init=0;
|
||||
|
||||
/* Init Function */
|
||||
void balloon_init_watcher(void);
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
||||
/* Use the private and mapping fields of struct page as a list. */
|
||||
#define PAGE_TO_LIST(p) ( (struct list_head *)&p->private )
|
||||
@@ -354,27 +351,21 @@ static void watch_target(struct xenbus_watch *watch, const char *node)
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Try to set up our watcher, if not already set
|
||||
|
||||
*/
|
||||
void balloon_init_watcher(void)
|
||||
/* Init Function - Try to set up our watcher, if not already set. */
|
||||
void balloon_init_watcher(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if(!xen_start_info.store_evtchn)
|
||||
{
|
||||
if (!xen_start_info.store_evtchn) {
|
||||
IPRINTK("Delaying watcher init until xenstore is available\n");
|
||||
return;
|
||||
}
|
||||
|
||||
down(&xenbus_lock);
|
||||
|
||||
if(! balloon_xenbus_init)
|
||||
{
|
||||
if (!balloon_xenbus_init) {
|
||||
err = register_xenbus_watch(&xb_watch);
|
||||
if(err)
|
||||
{
|
||||
if (err) {
|
||||
/* BIG FAT FIXME: dom0 sequencing workaround
|
||||
* dom0 can't set a watch on memory/target until
|
||||
* after the tools create it. So, we have to watch
|
||||
@@ -384,16 +375,13 @@ void balloon_init_watcher(void)
|
||||
* non-existant keys
|
||||
*/
|
||||
register_xenbus_watch(&root_watch);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
IPRINTK("Balloon xenbus watcher initialized\n");
|
||||
balloon_xenbus_init = 1;
|
||||
}
|
||||
}
|
||||
|
||||
up(&xenbus_lock);
|
||||
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(balloon_init_watcher);
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
#include <linux/err.h>
|
||||
#include "xenbus_comms.h"
|
||||
|
||||
static unsigned int xb_irq;
|
||||
|
||||
#define RINGBUF_DATASIZE ((PAGE_SIZE / 2) - sizeof(struct ringbuf_head))
|
||||
struct ringbuf_head
|
||||
{
|
||||
@@ -202,14 +204,17 @@ int xb_read(void *data, unsigned len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set up interrpt handler off store event channel. */
|
||||
/* Set up interrupt handler off store event channel. */
|
||||
int xb_init_comms(void)
|
||||
{
|
||||
int err, irq;
|
||||
int err;
|
||||
|
||||
irq = bind_evtchn_to_irq(xen_start_info.store_evtchn);
|
||||
if (!xen_start_info.store_evtchn)
|
||||
return 0;
|
||||
|
||||
err = request_irq(irq, wake_waiting, SA_SHIRQ, "xenbus", &xb_waitq);
|
||||
xb_irq = bind_evtchn_to_irq(xen_start_info.store_evtchn);
|
||||
|
||||
err = request_irq(xb_irq, wake_waiting, 0, "xenbus", &xb_waitq);
|
||||
if (err) {
|
||||
printk(KERN_ERR "XENBUS request irq failed %i\n", err);
|
||||
unbind_evtchn_from_irq(xen_start_info.store_evtchn);
|
||||
@@ -222,3 +227,13 @@ int xb_init_comms(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xb_suspend_comms(void)
|
||||
{
|
||||
|
||||
if (!xen_start_info.store_evtchn)
|
||||
return;
|
||||
|
||||
free_irq(xb_irq, &xb_waitq);
|
||||
unbind_evtchn_from_irq(xen_start_info.store_evtchn);
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
#define _XENBUS_COMMS_H
|
||||
int xs_init(void);
|
||||
int xb_init_comms(void);
|
||||
void xb_suspend_comms(void);
|
||||
|
||||
/* Low level routines. */
|
||||
int xb_write(const void *data, unsigned len);
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include <asm-xen/hypervisor.h>
|
||||
#include <asm-xen/xenbus.h>
|
||||
#include <asm-xen/balloon.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/string.h>
|
||||
@@ -295,6 +296,19 @@ static struct xenbus_watch dev_watch = {
|
||||
.callback = dev_changed,
|
||||
};
|
||||
|
||||
void xenbus_suspend(void)
|
||||
{
|
||||
/* We keep lock, so no comms can happen as page moves. */
|
||||
down(&xenbus_lock);
|
||||
xb_suspend_comms();
|
||||
}
|
||||
|
||||
void xenbus_resume(void)
|
||||
{
|
||||
xb_init_comms();
|
||||
up(&xenbus_lock);
|
||||
}
|
||||
|
||||
/* called from a thread in privcmd/privcmd.c */
|
||||
int do_xenbus_probe(void *unused)
|
||||
{
|
||||
|
||||
@@ -37,7 +37,7 @@ do { \
|
||||
*/
|
||||
#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
|
||||
do { \
|
||||
set_pte_at((__vma)>vm_mm, (__address), __ptep, __entry); \
|
||||
set_pte_at((__vma)->vm_mm, (__address), __ptep, __entry); \
|
||||
flush_tlb_page(__vma, __address); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
@@ -129,6 +129,7 @@
|
||||
extern int bind_virq_to_irq(int virq);
|
||||
extern void unbind_virq_from_irq(int virq);
|
||||
extern int bind_ipi_to_irq(int ipi);
|
||||
extern int bind_ipi_on_cpu_to_irq(int ipi);
|
||||
extern void unbind_ipi_from_irq(int ipi);
|
||||
extern int bind_evtchn_to_irq(int evtchn);
|
||||
extern void unbind_evtchn_from_irq(int evtchn);
|
||||
|
||||
@@ -127,6 +127,7 @@
|
||||
extern int bind_virq_to_irq(int virq);
|
||||
extern void unbind_virq_from_irq(int virq);
|
||||
extern int bind_ipi_to_irq(int ipi);
|
||||
extern int bind_ipi_on_cpu_to_irq(int ipi);
|
||||
extern void unbind_ipi_from_irq(int ipi);
|
||||
extern int bind_evtchn_to_irq(int evtchn);
|
||||
extern void unbind_evtchn_from_irq(int evtchn);
|
||||
|
||||
@@ -48,4 +48,7 @@ extern spinlock_t balloon_lock;
|
||||
#define balloon_lock(__flags) spin_lock_irqsave(&balloon_lock, __flags)
|
||||
#define balloon_unlock(__flags) spin_unlock_irqrestore(&balloon_lock, __flags)
|
||||
|
||||
/* Init Function - Try to set up our watcher, if not already set. */
|
||||
void balloon_init_watcher(void);
|
||||
|
||||
#endif /* __ASM_BALLOON_H__ */
|
||||
@@ -115,4 +115,8 @@ struct xenbus_watch
|
||||
int register_xenbus_watch(struct xenbus_watch *watch);
|
||||
void unregister_xenbus_watch(struct xenbus_watch *watch);
|
||||
|
||||
/* Called from xen core code. */
|
||||
void xenbus_suspend(void);
|
||||
void xenbus_resume(void);
|
||||
|
||||
#endif /* _ASM_XEN_XENBUS_H */
|
||||
+4
-1
@@ -279,9 +279,12 @@ int xc_linux_save(int xc_handle, int fd, u32 dom);
|
||||
* @parm fd the file descriptor to restore a domain from
|
||||
* @parm dom the id of the domain
|
||||
* @parm nr_pfns the number of pages
|
||||
* @parm store_evtchn the store event channel for this domain to use
|
||||
* @parm store_mfn returned with the mfn of the store page
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
int xc_linux_restore(int xc_handle, int io_fd, u32 dom, unsigned long nr_pfns);
|
||||
int xc_linux_restore(int xc_handle, int io_fd, u32 dom, unsigned long nr_pfns,
|
||||
unsigned int store_evtchn, unsigned long *store_mfn);
|
||||
|
||||
int xc_linux_build(int xc_handle,
|
||||
u32 domid,
|
||||
|
||||
@@ -48,7 +48,8 @@ read_exact(int fd, void *buf, size_t count)
|
||||
return r;
|
||||
}
|
||||
|
||||
int xc_linux_restore(int xc_handle, int io_fd, u32 dom, unsigned long nr_pfns)
|
||||
int xc_linux_restore(int xc_handle, int io_fd, u32 dom, unsigned long nr_pfns,
|
||||
unsigned int store_evtchn, unsigned long *store_mfn)
|
||||
{
|
||||
dom0_op_t op;
|
||||
int rc = 1, i, n, k;
|
||||
@@ -464,10 +465,13 @@ int xc_linux_restore(int xc_handle, int io_fd, u32 dom, unsigned long nr_pfns)
|
||||
}
|
||||
ctxt.user_regs.esi = mfn = pfn_to_mfn_table[pfn];
|
||||
p_srec = xc_map_foreign_range(
|
||||
xc_handle, dom, PAGE_SIZE, PROT_WRITE, mfn);
|
||||
xc_handle, dom, PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);
|
||||
p_srec->resume_info.nr_pages = nr_pfns;
|
||||
p_srec->resume_info.shared_info = shared_info_frame << PAGE_SHIFT;
|
||||
p_srec->resume_info.flags = 0;
|
||||
*store_mfn = p_srec->resume_info.store_mfn =
|
||||
pfn_to_mfn_table[p_srec->resume_info.store_mfn];
|
||||
p_srec->resume_info.store_evtchn = store_evtchn;
|
||||
munmap(p_srec, PAGE_SIZE);
|
||||
|
||||
/* Uncanonicalise each GDT frame number. */
|
||||
|
||||
+17
-11
@@ -20,7 +20,7 @@
|
||||
#define DEBUG 0
|
||||
|
||||
#if 1
|
||||
#define ERR(_f, _a...) fprintf ( stderr, _f , ## _a )
|
||||
#define ERR(_f, _a...) do { fprintf(stderr, _f , ## _a); fflush(stderr); } while (0)
|
||||
#else
|
||||
#define ERR(_f, _a...) ((void)0)
|
||||
#endif
|
||||
@@ -643,6 +643,22 @@ int xc_linux_save(int xc_handle, int io_fd, u32 dom)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Map the suspend-record MFN to pin it. The page must be owned by
|
||||
dom for this to succeed. */
|
||||
p_srec = xc_map_foreign_range(xc_handle, dom,
|
||||
sizeof(*p_srec), PROT_READ | PROT_WRITE,
|
||||
ctxt.user_regs.esi);
|
||||
if (!p_srec){
|
||||
ERR("Couldn't map suspend record");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Canonicalize store mfn. */
|
||||
if ( !translate_mfn_to_pfn(&p_srec->resume_info.store_mfn) ) {
|
||||
ERR("Store frame is not in range of pseudophys map");
|
||||
goto out;
|
||||
}
|
||||
|
||||
print_stats( xc_handle, dom, 0, &stats, 0 );
|
||||
|
||||
/* Now write out each data page, canonicalising page tables as we go... */
|
||||
@@ -983,16 +999,6 @@ int xc_linux_save(int xc_handle, int io_fd, u32 dom)
|
||||
}
|
||||
}
|
||||
|
||||
/* Map the suspend-record MFN to pin it. The page must be owned by
|
||||
dom for this to succeed. */
|
||||
p_srec = xc_map_foreign_range(xc_handle, dom,
|
||||
sizeof(*p_srec), PROT_READ,
|
||||
ctxt.user_regs.esi);
|
||||
if (!p_srec){
|
||||
ERR("Couldn't map suspend record");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nr_pfns != p_srec->nr_pfns )
|
||||
{
|
||||
ERR("Suspend record nr_pfns unexpected (%ld != %ld)",
|
||||
|
||||
@@ -254,11 +254,11 @@ static PyObject *xspy_get_permissions(PyObject *self, PyObject *args,
|
||||
val = PyList_New(perms_n);
|
||||
for (i = 0; i < perms_n; i++, perms++) {
|
||||
PyObject *p = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i}",
|
||||
"dom", perms->id,
|
||||
"read", (perms->perms & XS_PERM_READ),
|
||||
"write", (perms->perms & XS_PERM_WRITE),
|
||||
"create", (perms->perms & XS_PERM_CREATE),
|
||||
"owner", (perms->perms & XS_PERM_OWNER));
|
||||
"dom", perms->id,
|
||||
"read", (perms->perms & XS_PERM_READ),
|
||||
"write", (perms->perms & XS_PERM_WRITE),
|
||||
"exist", (perms->perms & XS_PERM_ENOENT_OK),
|
||||
"owner", (perms->perms & XS_PERM_OWNER));
|
||||
PyList_SetItem(val, i, p);
|
||||
}
|
||||
exit:
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
import errno
|
||||
import os
|
||||
import re
|
||||
import select
|
||||
import sxp
|
||||
from string import join
|
||||
@@ -64,6 +65,13 @@ def save(xd, fd, dominfo):
|
||||
if l.rstrip() == "suspend":
|
||||
log.info("suspending %d" % dominfo.id)
|
||||
xd.domain_shutdown(dominfo.id, reason='suspend')
|
||||
if dominfo.store_channel:
|
||||
try:
|
||||
dominfo.db.releaseDomain(dominfo.id)
|
||||
except Exception, ex:
|
||||
log.warning("error in domain release on xenstore: %s",
|
||||
ex)
|
||||
pass
|
||||
dominfo.state_wait("suspended")
|
||||
log.info("suspend %d done" % dominfo.id)
|
||||
child.tochild.write("done\n")
|
||||
@@ -76,6 +84,11 @@ def save(xd, fd, dominfo):
|
||||
if child.wait() != 0:
|
||||
raise XendError("xc_save failed: %s" % lasterr)
|
||||
|
||||
if dominfo.store_channel:
|
||||
dominfo.store_channel.close()
|
||||
dominfo.db['store_channel'].delete()
|
||||
dominfo.db.saveDB(save=True)
|
||||
dominfo.store_channel = None
|
||||
xd.domain_destroy(dominfo.id)
|
||||
return None
|
||||
|
||||
@@ -107,8 +120,13 @@ def restore(xd, fd):
|
||||
raise XendError(
|
||||
"not a valid guest state file: pfn count out of range")
|
||||
|
||||
if dominfo.store_channel:
|
||||
evtchn = dominfo.store_channel.port2
|
||||
else:
|
||||
evtchn = 0
|
||||
|
||||
cmd = [PATH_XC_RESTORE, str(xc.handle()), str(fd),
|
||||
str(dominfo.id), str(nr_pfns)]
|
||||
str(dominfo.id), str(nr_pfns), str(evtchn)]
|
||||
log.info("[xc_restore] " + join(cmd))
|
||||
child = xPopen3(cmd, True, -1, [fd, xc.handle()])
|
||||
child.tochild.close()
|
||||
@@ -128,7 +146,21 @@ def restore(xd, fd):
|
||||
lasterr = l.rstrip()
|
||||
if fd == child.fromchild.fileno():
|
||||
l = child.fromchild.readline()
|
||||
log.info(l.rstrip())
|
||||
while l:
|
||||
m = re.match(r"^(store-mfn) (\d+)\n$", l)
|
||||
if m:
|
||||
if dominfo.store_channel:
|
||||
dominfo.store_mfn = int(m.group(2))
|
||||
if dominfo.store_mfn >= 0:
|
||||
dominfo.db.introduceDomain(dominfo.id,
|
||||
dominfo.store_mfn,
|
||||
dominfo.store_channel)
|
||||
dominfo.exportToDB(save=True, sync=True)
|
||||
log.info(l.rstrip())
|
||||
try:
|
||||
l = child.fromchild.readline()
|
||||
except:
|
||||
l = None
|
||||
if filter(lambda (fd, event): event & select.POLLHUP, r):
|
||||
break
|
||||
|
||||
|
||||
@@ -16,15 +16,23 @@
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
unsigned int xc_fd, io_fd, domid, nr_pfns;
|
||||
unsigned int xc_fd, io_fd, domid, nr_pfns, evtchn;
|
||||
int ret;
|
||||
unsigned long mfn;
|
||||
|
||||
if (argc != 5)
|
||||
errx(1, "usage: %s xcfd iofd domid nr_pfns", argv[0]);
|
||||
if (argc != 6)
|
||||
errx(1, "usage: %s xcfd iofd domid nr_pfns evtchn", argv[0]);
|
||||
|
||||
xc_fd = atoi(argv[1]);
|
||||
io_fd = atoi(argv[2]);
|
||||
domid = atoi(argv[3]);
|
||||
nr_pfns = atoi(argv[4]);
|
||||
evtchn = atoi(argv[5]);
|
||||
|
||||
return xc_linux_restore(xc_fd, io_fd, domid, nr_pfns);
|
||||
ret = xc_linux_restore(xc_fd, io_fd, domid, nr_pfns, evtchn, &mfn);
|
||||
if (ret == 0) {
|
||||
printf("store-mfn %li\n", mfn);
|
||||
fflush(stdout);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -160,3 +160,22 @@ async 2 write /test3 create contents
|
||||
1 waitwatch' | ./xs_test 2>&1`" = "1:/test2/foo:token
|
||||
1:contents2
|
||||
1:waitwatch timeout" ]
|
||||
|
||||
# We can watch something which doesn't exist.
|
||||
[ "`echo '1 watch /dir/subdir token
|
||||
2 mkdir /dir/subdir
|
||||
1 waitwatch' | ./xs_test 2>&1`" = "1:/dir/subdir:token" ]
|
||||
|
||||
# If we don't have permission, we won't see event (rm).
|
||||
[ "`echo '1 setid 1
|
||||
1 watch /dir/subdir token
|
||||
setperm /dir 0 NONE
|
||||
rm /dir/subdir
|
||||
1 waitwatch' | ./xs_test 2>&1`" = "1:waitwatch timeout" ]
|
||||
|
||||
# If we don't have permission, we won't see event (create).
|
||||
[ "`echo '1 setid 1
|
||||
1 watch /dir/subdir token
|
||||
mkdir /dir/subdir
|
||||
write /dir/subdir/entry create contents
|
||||
1 waitwatch' | ./xs_test 2>&1`" = "1:waitwatch timeout" ]
|
||||
@@ -14,7 +14,10 @@ run_test()
|
||||
PID=`cat /tmp/pid`
|
||||
rm /tmp/pid
|
||||
else
|
||||
PID=`./xenstored_test --output-pid`
|
||||
./xenstored_test --output-pid --trace-file=testsuite/tmp/trace --no-fork > /tmp/pid 2> testsuite/tmp/xenstored_errors &
|
||||
while [ ! -s /tmp/pid ]; do sleep 0; done
|
||||
PID=`cat /tmp/pid`
|
||||
rm /tmp/pid
|
||||
fi
|
||||
if sh -e $2 $1; then
|
||||
if [ -s testsuite/tmp/vgout ]; then
|
||||
|
||||
@@ -504,11 +504,13 @@ void send_error(struct connection *conn, int error)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; error != xsd_errors[i].errnum; i++)
|
||||
if (i == ARRAY_SIZE(xsd_errors) - 1)
|
||||
corrupt(conn, "Unknown error %i (%s)", error,
|
||||
strerror(error));
|
||||
|
||||
for (i = 0; error != xsd_errors[i].errnum; i++) {
|
||||
if (i == ARRAY_SIZE(xsd_errors) - 1) {
|
||||
eprintf("xenstored: error %i untranslatable", error);
|
||||
i = 0; /* EINVAL */
|
||||
break;
|
||||
}
|
||||
}
|
||||
send_reply(conn, XS_ERROR, xsd_errors[i].errstring,
|
||||
strlen(xsd_errors[i].errstring) + 1);
|
||||
}
|
||||
@@ -705,7 +707,7 @@ static enum xs_perm_type perm_for_id(domid_t id,
|
||||
|
||||
/* Owners and tools get it all... */
|
||||
if (!id || perms[0].id == id)
|
||||
return XS_PERM_READ|XS_PERM_WRITE|XS_PERM_CREATE|XS_PERM_OWNER;
|
||||
return XS_PERM_READ|XS_PERM_WRITE|XS_PERM_OWNER;
|
||||
|
||||
for (i = 1; i < num; i++)
|
||||
if (perms[i].id == id)
|
||||
@@ -714,20 +716,13 @@ static enum xs_perm_type perm_for_id(domid_t id,
|
||||
return perms[0].perms;
|
||||
}
|
||||
|
||||
/* We have a weird permissions system. You can allow someone into a
|
||||
* specific node without allowing it in the parents. If it's going to
|
||||
* fail, however, we don't want the errno to indicate any information
|
||||
* about the node. */
|
||||
static int check_with_parents(struct connection *conn, const char *node,
|
||||
int errnum)
|
||||
/* What do parents say? */
|
||||
static enum xs_perm_type ask_parents(struct connection *conn,
|
||||
const char *node)
|
||||
{
|
||||
struct xs_permissions *perms;
|
||||
unsigned int num;
|
||||
|
||||
/* We always tell them about memory failures. */
|
||||
if (errnum == ENOMEM)
|
||||
return errnum;
|
||||
|
||||
do {
|
||||
node = get_parent(node);
|
||||
perms = get_perms(conn->transaction, node, &num);
|
||||
@@ -739,10 +734,23 @@ static int check_with_parents(struct connection *conn, const char *node,
|
||||
if (!perms)
|
||||
corrupt(conn, "No permissions file at root");
|
||||
|
||||
if (!(perm_for_id(conn->id, perms, num) & XS_PERM_READ))
|
||||
return EACCES;
|
||||
return perm_for_id(conn->id, perms, num);
|
||||
}
|
||||
|
||||
return errnum;
|
||||
/* We have a weird permissions system. You can allow someone into a
|
||||
* specific node without allowing it in the parents. If it's going to
|
||||
* fail, however, we don't want the errno to indicate any information
|
||||
* about the node. */
|
||||
static int errno_from_parents(struct connection *conn, const char *node,
|
||||
int errnum)
|
||||
{
|
||||
/* We always tell them about memory failures. */
|
||||
if (errnum == ENOMEM)
|
||||
return errnum;
|
||||
|
||||
if (ask_parents(conn, node) & XS_PERM_READ)
|
||||
return errnum;
|
||||
return EACCES;
|
||||
}
|
||||
|
||||
char *canonicalize(struct connection *conn, const char *node)
|
||||
@@ -774,24 +782,26 @@ bool check_node_perms(struct connection *conn, const char *node,
|
||||
}
|
||||
|
||||
perms = get_perms(conn->transaction, node, &num);
|
||||
/* No permissions. If we want to create it and
|
||||
* it doesn't exist, check parent directory. */
|
||||
if (!perms && errno == ENOENT && (perm & XS_PERM_CREATE)) {
|
||||
char *parent = get_parent(node);
|
||||
if (!parent)
|
||||
return false;
|
||||
|
||||
perms = get_perms(conn->transaction, parent, &num);
|
||||
}
|
||||
if (!perms) {
|
||||
errno = check_with_parents(conn, node, errno);
|
||||
if (perms) {
|
||||
if (perm_for_id(conn->id, perms, num) & perm)
|
||||
return true;
|
||||
errno = EACCES;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (perm_for_id(conn->id, perms, num) & perm)
|
||||
return true;
|
||||
/* If it's OK not to exist, we consult parents. */
|
||||
if (errno == ENOENT && (perm & XS_PERM_ENOENT_OK)) {
|
||||
if (ask_parents(conn, node) & perm)
|
||||
return true;
|
||||
/* Parents say they should not know. */
|
||||
errno = EACCES;
|
||||
return false;
|
||||
}
|
||||
|
||||
errno = check_with_parents(conn, node, EACCES);
|
||||
/* They might not have permission to even *see* this node, in
|
||||
* which case we return EACCES even if it's ENOENT or EIO. */
|
||||
errno = errno_from_parents(conn, node, errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -928,9 +938,9 @@ static void do_write(struct connection *conn, struct buffered_data *in)
|
||||
if (streq(vec[1], XS_WRITE_NONE))
|
||||
mode = XS_PERM_WRITE;
|
||||
else if (streq(vec[1], XS_WRITE_CREATE))
|
||||
mode = XS_PERM_WRITE|XS_PERM_CREATE;
|
||||
mode = XS_PERM_WRITE|XS_PERM_ENOENT_OK;
|
||||
else if (streq(vec[1], XS_WRITE_CREATE_EXCL))
|
||||
mode = XS_PERM_WRITE|XS_PERM_CREATE;
|
||||
mode = XS_PERM_WRITE|XS_PERM_ENOENT_OK;
|
||||
else {
|
||||
send_error(conn, EINVAL);
|
||||
return;
|
||||
@@ -949,7 +959,7 @@ static void do_write(struct connection *conn, struct buffered_data *in)
|
||||
}
|
||||
|
||||
/* Not going to create it? */
|
||||
if (!(mode & XS_PERM_CREATE)) {
|
||||
if (streq(vec[1], XS_WRITE_NONE)) {
|
||||
send_error(conn, ENOENT);
|
||||
return;
|
||||
}
|
||||
@@ -983,7 +993,7 @@ static void do_write(struct connection *conn, struct buffered_data *in)
|
||||
static void do_mkdir(struct connection *conn, const char *node)
|
||||
{
|
||||
node = canonicalize(conn, node);
|
||||
if (!check_node_perms(conn, node, XS_PERM_WRITE|XS_PERM_CREATE)) {
|
||||
if (!check_node_perms(conn, node, XS_PERM_WRITE|XS_PERM_ENOENT_OK)) {
|
||||
send_error(conn, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -95,10 +95,19 @@ static int destroy_watch_event(void *_event)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void add_event(struct watch *watch, const char *node)
|
||||
static void add_event(struct connection *conn,
|
||||
struct watch *watch, const char *node)
|
||||
{
|
||||
struct watch_event *event;
|
||||
|
||||
/* Check read permission: no permission, no watch event.
|
||||
* If it doesn't exist, we need permission to read parent.
|
||||
*/
|
||||
if (!check_node_perms(conn, node, XS_PERM_READ|XS_PERM_ENOENT_OK)) {
|
||||
fprintf(stderr, "No permission for %s\n", node);
|
||||
return;
|
||||
}
|
||||
|
||||
if (watch->relative_path) {
|
||||
node += strlen(watch->relative_path);
|
||||
if (*node == '/') /* Could be "" */
|
||||
@@ -132,9 +141,9 @@ void fire_watches(struct connection *conn, const char *node, bool recurse)
|
||||
|
||||
list_for_each_entry(watch, &i->watches, list) {
|
||||
if (is_child(node, watch->node))
|
||||
add_event(watch, node);
|
||||
add_event(i, watch, node);
|
||||
else if (recurse && is_child(watch->node, node))
|
||||
add_event(watch, watch->node);
|
||||
add_event(i, watch, watch->node);
|
||||
else
|
||||
continue;
|
||||
/* If connection not doing anything, queue this. */
|
||||
@@ -206,7 +215,7 @@ void do_watch(struct connection *conn, struct buffered_data *in)
|
||||
|
||||
relative = !strstarts(vec[0], "/");
|
||||
vec[0] = canonicalize(conn, vec[0]);
|
||||
if (!check_node_perms(conn, vec[0], XS_PERM_READ)) {
|
||||
if (!is_valid_nodename(vec[0])) {
|
||||
send_error(conn, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ enum xs_perm_type {
|
||||
XS_PERM_READ = 1,
|
||||
XS_PERM_WRITE = 2,
|
||||
/* Internal use. */
|
||||
XS_PERM_CREATE = 4,
|
||||
XS_PERM_ENOENT_OK = 4,
|
||||
XS_PERM_OWNER = 8,
|
||||
};
|
||||
|
||||
|
||||