From 335bd9dff31d042b773591933d3ee5bd62d5ea27 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 26 Mar 2006 21:25:57 +0100 Subject: [SERIAL] Remove obsoleted au1x00_uart driver As announced in feature-removal-schedule.txt. Signed-off-by: Ralf Baechle Signed-off-by: Russell King --- arch/mips/au1000/common/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c index 1080558c810..307e98c29dd 100644 --- a/arch/mips/au1000/common/setup.c +++ b/arch/mips/au1000/common/setup.c @@ -94,7 +94,7 @@ void __init plat_setup(void) argptr = prom_getcmdline(); -#if defined(CONFIG_SERIAL_AU1X00_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) +#ifdef CONFIG_SERIAL_8250_CONSOLE if ((argptr = strstr(argptr, "console=")) == NULL) { argptr = prom_getcmdline(); strcat(argptr, " console=ttyS0,115200"); -- cgit v1.2.3 From bd8f103efef14980decf5d54a2de85835e9a6d9a Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Sun, 26 Mar 2006 21:40:27 +0100 Subject: [ARM] 3415/1: Akita: Add missing EXPORT_SYMBOL Patch from Richard Purdie Add an EXPORT_SYMBOL for the Akita IO Expander Device. Signed-off-by: Richard Purdie Signed-off-by: Russell King --- arch/arm/mach-pxa/spitz.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 30ec317bbb9..0dbb079ecd2 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -467,6 +467,8 @@ struct platform_device akitaioexp_device = { .id = -1, }; +EXPORT_SYMBOL_GPL(akitaioexp_device); + static void __init akita_init(void) { spitz_ficp_platform_data.transceiver_mode = akita_irda_transceiver_mode; -- cgit v1.2.3 From fbb18a277a6f192404aa20ece49529acb1e1e76d Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 26 Mar 2006 23:13:39 +0100 Subject: [SERIAL] amba-pl010: allow platforms to specify modem control method The amba-pl010 hardware does not provide RTS and DTR control lines; it is expected that these will be implemented using GPIO. Allow platforms to supply a function to implement manipulation of modem control lines. Signed-off-by: Russell King --- arch/arm/mach-integrator/core.c | 46 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index 20071a2767c..576a5e979c0 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c @@ -15,7 +15,9 @@ #include #include #include +#include #include +#include #include #include @@ -28,6 +30,8 @@ #include "common.h" +static struct amba_pl010_data integrator_uart_data; + static struct amba_device rtc_device = { .dev = { .bus_id = "mb:15", @@ -44,6 +48,7 @@ static struct amba_device rtc_device = { static struct amba_device uart0_device = { .dev = { .bus_id = "mb:16", + .platform_data = &integrator_uart_data, }, .res = { .start = INTEGRATOR_UART0_BASE, @@ -57,6 +62,7 @@ static struct amba_device uart0_device = { static struct amba_device uart1_device = { .dev = { .bus_id = "mb:17", + .platform_data = &integrator_uart_data, }, .res = { .start = INTEGRATOR_UART1_BASE, @@ -115,6 +121,46 @@ static int __init integrator_init(void) arch_initcall(integrator_init); +/* + * On the Integrator platform, the port RTS and DTR are provided by + * bits in the following SC_CTRLS register bits: + * RTS DTR + * UART0 7 6 + * UART1 5 4 + */ +#define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET) +#define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET) + +static void integrator_uart_set_mctrl(struct amba_device *dev, void __iomem *base, unsigned int mctrl) +{ + unsigned int ctrls = 0, ctrlc = 0, rts_mask, dtr_mask; + + if (dev == &uart0_device) { + rts_mask = 1 << 4; + dtr_mask = 1 << 5; + } else { + rts_mask = 1 << 6; + dtr_mask = 1 << 7; + } + + if (mctrl & TIOCM_RTS) + ctrlc |= rts_mask; + else + ctrls |= rts_mask; + + if (mctrl & TIOCM_DTR) + ctrlc |= dtr_mask; + else + ctrls |= dtr_mask; + + __raw_writel(ctrls, SC_CTRLS); + __raw_writel(ctrlc, SC_CTRLC); +} + +static struct amba_pl010_data integrator_uart_data = { + .set_mctrl = integrator_uart_set_mctrl, +}; + #define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_CTRL_OFFSET static DEFINE_SPINLOCK(cm_lock); -- cgit v1.2.3 From aee85fe8e8143d3f54d9e6d3c6cdd40ead563267 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Sun, 26 Mar 2006 23:16:39 +0100 Subject: [SERIAL] Provide Cirrus EP93xx AMBA PL010 serial support. Signed-off-by: Lennert Buytenhek Signed-off-by: Russell King --- arch/arm/mach-ep93xx/core.c | 68 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index 865427bfad7..2d892e4daa0 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -30,7 +30,9 @@ #include #include #include +#include #include +#include #include #include @@ -360,6 +362,68 @@ void __init ep93xx_init_irq(void) /************************************************************************* * EP93xx peripheral handling *************************************************************************/ +#define EP93XX_UART_MCR_OFFSET (0x0100) + +static void ep93xx_uart_set_mctrl(struct amba_device *dev, + void __iomem *base, unsigned int mctrl) +{ + unsigned int mcr; + + mcr = 0; + if (!(mctrl & TIOCM_RTS)) + mcr |= 2; + if (!(mctrl & TIOCM_DTR)) + mcr |= 1; + + __raw_writel(mcr, base + EP93XX_UART_MCR_OFFSET); +} + +static struct amba_pl010_data ep93xx_uart_data = { + .set_mctrl = ep93xx_uart_set_mctrl, +}; + +static struct amba_device uart1_device = { + .dev = { + .bus_id = "apb:uart1", + .platform_data = &ep93xx_uart_data, + }, + .res = { + .start = EP93XX_UART1_PHYS_BASE, + .end = EP93XX_UART1_PHYS_BASE + 0x0fff, + .flags = IORESOURCE_MEM, + }, + .irq = { IRQ_EP93XX_UART1, NO_IRQ }, + .periphid = 0x00041010, +}; + +static struct amba_device uart2_device = { + .dev = { + .bus_id = "apb:uart2", + .platform_data = &ep93xx_uart_data, + }, + .res = { + .start = EP93XX_UART2_PHYS_BASE, + .end = EP93XX_UART2_PHYS_BASE + 0x0fff, + .flags = IORESOURCE_MEM, + }, + .irq = { IRQ_EP93XX_UART2, NO_IRQ }, + .periphid = 0x00041010, +}; + +static struct amba_device uart3_device = { + .dev = { + .bus_id = "apb:uart3", + .platform_data = &ep93xx_uart_data, + }, + .res = { + .start = EP93XX_UART3_PHYS_BASE, + .end = EP93XX_UART3_PHYS_BASE + 0x0fff, + .flags = IORESOURCE_MEM, + }, + .irq = { IRQ_EP93XX_UART3, NO_IRQ }, + .periphid = 0x00041010, +}; + void __init ep93xx_init_devices(void) { unsigned int v; @@ -371,4 +435,8 @@ void __init ep93xx_init_devices(void) v &= ~EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE; __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK); __raw_writel(v, EP93XX_SYSCON_DEVICE_CONFIG); + + amba_device_register(&uart1_device, &iomem_resource); + amba_device_register(&uart2_device, &iomem_resource); + amba_device_register(&uart3_device, &iomem_resource); } -- cgit v1.2.3 From 7bebd83dbf096d0bf4b4bfbaf5d8844a05f5eafc Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 27 Mar 2006 01:07:55 -0800 Subject: [SPARC64]: Fix off-by-1 error in TSB grow check. The worst part about this bug is what it would cause a hugepage TSB to be allocated for every address space since "0 >= 0". Signed-off-by: David S. Miller --- arch/sparc64/mm/fault.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index d21ff3230c0..0db2f7d9fab 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c @@ -413,12 +413,12 @@ good_area: #ifdef CONFIG_HUGETLB_PAGE mm_rss -= (mm->context.huge_pte_count * (HPAGE_SIZE / PAGE_SIZE)); #endif - if (unlikely(mm_rss >= + if (unlikely(mm_rss > mm->context.tsb_block[MM_TSB_BASE].tsb_rss_limit)) tsb_grow(mm, MM_TSB_BASE, mm_rss); #ifdef CONFIG_HUGETLB_PAGE mm_rss = mm->context.huge_pte_count; - if (unlikely(mm_rss >= + if (unlikely(mm_rss > mm->context.tsb_block[MM_TSB_HUGE].tsb_rss_limit)) tsb_grow(mm, MM_TSB_HUGE, mm_rss); #endif -- cgit v1.2.3 From c8c4b939e8dff82ee2bc22ed506ae29ecffca4c2 Mon Sep 17 00:00:00 2001 From: Erik Mouw Date: Mon, 27 Mar 2006 15:32:30 +0100 Subject: [ARM] 3416/1: Update LART site URL Patch from Erik Mouw The LART website moved to http://www.lartmaker.nl/. This patch updates the URL in ARM specific files. Signed-off-by: Erik Mouw Acked-by: Jan-Derk Bakker Signed-off-by: Russell King --- arch/arm/mach-sa1100/Kconfig | 2 +- arch/arm/mach-sa1100/cpu-sa1100.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-sa1100/Kconfig b/arch/arm/mach-sa1100/Kconfig index 6923316b3d0..cd67ab1b217 100644 --- a/arch/arm/mach-sa1100/Kconfig +++ b/arch/arm/mach-sa1100/Kconfig @@ -111,7 +111,7 @@ config SA1100_LART bool "LART" help Say Y here if you are using the Linux Advanced Radio Terminal - (also known as the LART). See for + (also known as the LART). See for information on the LART. config SA1100_PLEB diff --git a/arch/arm/mach-sa1100/cpu-sa1100.c b/arch/arm/mach-sa1100/cpu-sa1100.c index 6435b2e48ff..d68630b74d7 100644 --- a/arch/arm/mach-sa1100/cpu-sa1100.c +++ b/arch/arm/mach-sa1100/cpu-sa1100.c @@ -11,7 +11,7 @@ * linux-2.4.5-rmk1 * * This software has been developed while working on the LART - * computing board (http://www.lart.tudelft.nl/), which is + * computing board (http://www.lartmaker.nl/), which is * sponsored by the Mobile Multi-media Communications * (http://www.mmc.tudelft.nl/) and Ubiquitous Communications * (http://www.ubicom.tudelft.nl/) projects. -- cgit v1.2.3 From 4682adcfb06448827fbdfd8b6c636796de569b7d Mon Sep 17 00:00:00 2001 From: "Hyok S. Choi" Date: Mon, 27 Mar 2006 15:46:06 +0100 Subject: [ARM] nommu: trivial patch for arch/arm/lib/Makefile ifeq ($CONFIG_PREEMPT,y) -> ifeq ($(CONFIG_PREEMPT),y) Signed-off-by: Hyok S. Choi Signed-off-by: Russell King --- arch/arm/lib/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index 391f3ab3ff3..7b726b627ea 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -18,7 +18,7 @@ lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ # the code in uaccess.S is not preemption safe and # probably faster on ARMv3 only -ifeq ($CONFIG_PREEMPT,y) +ifeq ($(CONFIG_PREEMPT),y) lib-y += copy_from_user.o copy_to_user.o else ifneq ($(CONFIG_CPU_32v3),y) -- cgit v1.2.3 From 3747b36eeab93d8969e86987bbc1d44971229b26 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 27 Mar 2006 16:59:07 +0100 Subject: [ARM] proc-v6: mark page table walks outer-cacheable, shared. Enable NX. Mark page table walks with outer-cacheable attribute, and enable no-execute in page tables. Signed-off-by: Russell King --- arch/arm/mm/proc-v6.S | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S index 9a7e7c096aa..ee6f1529873 100644 --- a/arch/arm/mm/proc-v6.S +++ b/arch/arm/mm/proc-v6.S @@ -21,6 +21,14 @@ #define D_CACHE_LINE_SIZE 32 +#define TTB_C (1 << 0) +#define TTB_S (1 << 1) +#define TTB_IMP (1 << 2) +#define TTB_RGN_NC (0 << 3) +#define TTB_RGN_WBWA (1 << 3) +#define TTB_RGN_WT (2 << 3) +#define TTB_RGN_WB (3 << 3) + .macro cpsie, flags .ifc \flags, f .long 0xf1080040 @@ -115,7 +123,7 @@ ENTRY(cpu_v6_switch_mm) mov r2, #0 ldr r1, [r1, #MM_CONTEXT_ID] @ get mm->context.id #ifdef CONFIG_SMP - orr r0, r0, #2 @ set shared pgtable + orr r0, r0, #TTB_RGN_WBWA|TTB_S @ mark PTWs shared, outer cacheable #endif mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB mcr p15, 0, r2, c7, c10, 4 @ drain write buffer @@ -161,8 +169,8 @@ ENTRY(cpu_v6_set_pte) tst r1, #L_PTE_YOUNG biceq r2, r2, #PTE_EXT_APX | PTE_EXT_AP_MASK -@ tst r1, #L_PTE_EXEC -@ orreq r2, r2, #PTE_EXT_XN + tst r1, #L_PTE_EXEC + orreq r2, r2, #PTE_EXT_XN tst r1, #L_PTE_PRESENT moveq r2, #0 @@ -221,7 +229,7 @@ __v6_setup: mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs mcr p15, 0, r0, c2, c0, 2 @ TTB control register #ifdef CONFIG_SMP - orr r4, r4, #2 @ set shared pgtable + orr r4, r4, #TTB_RGN_WBWA|TTB_S @ mark PTWs shared, outer cacheable #endif mcr p15, 0, r4, c2, c0, 1 @ load TTB1 #ifdef CONFIG_VFP -- cgit v1.2.3 From dbffa471611d3fc4b401ebabf7bb63ac0e0272b1 Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Mon, 27 Mar 2006 01:14:26 -0800 Subject: [PATCH] PM-Timer: don't use workaround if chipset is not buggy Current timer_pm.c reads I/O port triple times, in order to avoid the bug of chipset. But I/O port is slow. 2.6.16 (pmtmr) Simple gettimeofday: 3.6532 microseconds 2.6.16+patch (pmtmr) Simple gettimeofday: 1.4582 microseconds [if chip is buggy, probably it will be 7us or more in 4.2% of probability.] This patch adds blacklist of buggy chip, and if chip is not buggy, this uses fast normal version instead of slow workaround version. If chip is buggy, warnings "pmtmr is slow". But sounds like there is gray zone. I found the PIIX4 errata, but I couldn't find the ICH4 errata. But some motherboard seems to have problem. So, if we found a ICH4, generate warnings, and use a workaround version. If user's ICH4 is good, the user can specify the "pmtmr_good" boot parameter to use fast version. Acked-by: John Stultz Signed-off-by: OGAWA Hirofumi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/timers/timer_pm.c | 104 +++++++++++++++++++++++++++++++------ 1 file changed, 89 insertions(+), 15 deletions(-) (limited to 'arch') diff --git a/arch/i386/kernel/timers/timer_pm.c b/arch/i386/kernel/timers/timer_pm.c index 264edaaac31..144e94a0493 100644 --- a/arch/i386/kernel/timers/timer_pm.c +++ b/arch/i386/kernel/timers/timer_pm.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -45,24 +46,31 @@ static seqlock_t monotonic_lock = SEQLOCK_UNLOCKED; #define ACPI_PM_MASK 0xFFFFFF /* limit it to 24 bits */ +static int pmtmr_need_workaround __read_mostly = 1; + /*helper function to safely read acpi pm timesource*/ static inline u32 read_pmtmr(void) { - u32 v1=0,v2=0,v3=0; - /* It has been reported that because of various broken - * chipsets (ICH4, PIIX4 and PIIX4E) where the ACPI PM time - * source is not latched, so you must read it multiple - * times to insure a safe value is read. - */ - do { - v1 = inl(pmtmr_ioport); - v2 = inl(pmtmr_ioport); - v3 = inl(pmtmr_ioport); - } while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1) - || (v3 > v1 && v3 < v2)); - - /* mask the output to 24 bits */ - return v2 & ACPI_PM_MASK; + if (pmtmr_need_workaround) { + u32 v1, v2, v3; + + /* It has been reported that because of various broken + * chipsets (ICH4, PIIX4 and PIIX4E) where the ACPI PM time + * source is not latched, so you must read it multiple + * times to insure a safe value is read. + */ + do { + v1 = inl(pmtmr_ioport); + v2 = inl(pmtmr_ioport); + v3 = inl(pmtmr_ioport); + } while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1) + || (v3 > v1 && v3 < v2)); + + /* mask the output to 24 bits */ + return v2 & ACPI_PM_MASK; + } + + return inl(pmtmr_ioport) & ACPI_PM_MASK; } @@ -263,6 +271,72 @@ struct init_timer_opts __initdata timer_pmtmr_init = { .opts = &timer_pmtmr, }; +#ifdef CONFIG_PCI +/* + * PIIX4 Errata: + * + * The power management timer may return improper results when read. + * Although the timer value settles properly after incrementing, + * while incrementing there is a 3 ns window every 69.8 ns where the + * timer value is indeterminate (a 4.2% chance that the data will be + * incorrect when read). As a result, the ACPI free running count up + * timer specification is violated due to erroneous reads. + */ +static int __init pmtmr_bug_check(void) +{ + static struct pci_device_id gray_list[] __initdata = { + /* these chipsets may have bug. */ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82801DB_0) }, + { }, + }; + struct pci_dev *dev; + int pmtmr_has_bug = 0; + u8 rev; + + if (cur_timer != &timer_pmtmr || !pmtmr_need_workaround) + return 0; + + dev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB_3, NULL); + if (dev) { + pci_read_config_byte(dev, PCI_REVISION_ID, &rev); + /* the bug has been fixed in PIIX4M */ + if (rev < 3) { + printk(KERN_WARNING "* Found PM-Timer Bug on this " + "chipset. Due to workarounds for a bug,\n" + "* this time source is slow. Consider trying " + "other time sources (clock=)\n"); + pmtmr_has_bug = 1; + } + pci_dev_put(dev); + } + + if (pci_dev_present(gray_list)) { + printk(KERN_WARNING "* This chipset may have PM-Timer Bug. Due" + " to workarounds for a bug,\n" + "* this time source is slow. If you are sure your timer" + " does not have\n" + "* this bug, please use \"pmtmr_good\" to disable the " + "workaround\n"); + pmtmr_has_bug = 1; + } + + if (!pmtmr_has_bug) + pmtmr_need_workaround = 0; + + return 0; +} +device_initcall(pmtmr_bug_check); +#endif + +static int __init pmtr_good_setup(char *__str) +{ + pmtmr_need_workaround = 0; + return 1; +} +__setup("pmtmr_good", pmtr_good_setup); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Dominik Brodowski "); MODULE_DESCRIPTION("Power Management Timer (PMTMR) as primary timing source for x86"); -- cgit v1.2.3 From c90e12b86595dbd9996336ac9d762487c638d934 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 27 Mar 2006 01:14:29 -0800 Subject: [PATCH] uml: fix declaration of exit() This fixes a conflict between a header and what gcc "knows" the declaration' to be. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/include/kern.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/um/include/kern.h b/arch/um/include/kern.h index 7d223beccbc..4ce3fc650e5 100644 --- a/arch/um/include/kern.h +++ b/arch/um/include/kern.h @@ -29,7 +29,7 @@ extern int getuid(void); extern int getgid(void); extern int pause(void); extern int write(int, const void *, int); -extern int exit(int); +extern void exit(int); extern int close(int); extern int read(unsigned int, char *, int); extern int pipe(int *); -- cgit v1.2.3 From d9f8b62a6b033fe7226d7c2b2efdd164ca1aa07c Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 27 Mar 2006 01:14:29 -0800 Subject: [PATCH] uml: fix some printf formats Some printf formats are incorrect for large memory sizes. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/um_arch.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 80c9c18aae9..0c5b9dcfbe2 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -421,7 +421,7 @@ int linux_main(int argc, char **argv) #ifndef CONFIG_HIGHMEM highmem = 0; printf("CONFIG_HIGHMEM not enabled - physical memory shrunk " - "to %lu bytes\n", physmem_size); + "to %Lu bytes\n", physmem_size); #endif } @@ -433,8 +433,8 @@ int linux_main(int argc, char **argv) setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem); if(init_maps(physmem_size, iomem_size, highmem)){ - printf("Failed to allocate mem_map for %lu bytes of physical " - "memory and %lu bytes of highmem\n", physmem_size, + printf("Failed to allocate mem_map for %Lu bytes of physical " + "memory and %Lu bytes of highmem\n", physmem_size, highmem); exit(1); } -- cgit v1.2.3 From 63ae2a94d98dd9d94163918539ec80df33f44a69 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 27 Mar 2006 01:14:30 -0800 Subject: [PATCH] uml: move libc-dependent irq code to os-Linux The serial UML OS-abstraction layer patch (um/kernel dir). This moves all systemcalls from irq_user.c file under os-Linux dir Signed-off-by: Gennady Sharapov Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/include/irq_user.h | 15 ++- arch/um/include/misc_constants.h | 6 ++ arch/um/include/os.h | 16 +++ arch/um/kernel/irq_user.c | 204 +++++++++++--------------------------- arch/um/kernel/smp.c | 14 +-- arch/um/os-Linux/Makefile | 6 +- arch/um/os-Linux/irq.c | 162 ++++++++++++++++++++++++++++++ arch/um/os-Linux/tt.c | 10 ++ arch/um/sys-i386/user-offsets.c | 10 +- arch/um/sys-x86_64/user-offsets.c | 6 ++ 10 files changed, 288 insertions(+), 161 deletions(-) create mode 100644 arch/um/include/misc_constants.h create mode 100644 arch/um/os-Linux/irq.c (limited to 'arch') diff --git a/arch/um/include/irq_user.h b/arch/um/include/irq_user.h index b61deb8b362..69a93c804f0 100644 --- a/arch/um/include/irq_user.h +++ b/arch/um/include/irq_user.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -6,6 +6,17 @@ #ifndef __IRQ_USER_H__ #define __IRQ_USER_H__ +struct irq_fd { + struct irq_fd *next; + void *id; + int fd; + int type; + int irq; + int pid; + int events; + int current_events; +}; + enum { IRQ_READ, IRQ_WRITE }; extern void sigio_handler(int sig, union uml_pt_regs *regs); @@ -16,8 +27,6 @@ extern void reactivate_fd(int fd, int irqnum); extern void deactivate_fd(int fd, int irqnum); extern int deactivate_all_fds(void); extern void forward_interrupts(int pid); -extern void init_irq_signals(int on_sigstack); -extern void forward_ipi(int fd, int pid); extern int activate_ipi(int fd, int pid); extern unsigned long irq_lock(void); extern void irq_unlock(unsigned long flags); diff --git a/arch/um/include/misc_constants.h b/arch/um/include/misc_constants.h new file mode 100644 index 00000000000..989bc08de36 --- /dev/null +++ b/arch/um/include/misc_constants.h @@ -0,0 +1,6 @@ +#ifndef __MISC_CONSTANT_H_ +#define __MISC_CONSTANT_H_ + +#include + +#endif diff --git a/arch/um/include/os.h b/arch/um/include/os.h index 2a1c64d8d0b..efae3e6acb5 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -12,6 +12,7 @@ #include "sysdep/ptrace.h" #include "kern_util.h" #include "skas/mm_id.h" +#include "irq_user.h" #define OS_TYPE_FILE 1 #define OS_TYPE_DIR 2 @@ -198,6 +199,8 @@ extern void os_flush_stdout(void); /* tt.c * for tt mode only (will be deleted in future...) */ +extern void forward_ipi(int fd, int pid); +extern void kill_child_dead(int pid); extern void stop(void); extern int wait_for_stop(int pid, int sig, int cont_type, void *relay); extern int protect_memory(unsigned long addr, unsigned long len, @@ -294,4 +297,17 @@ extern void initial_thread_cb_skas(void (*proc)(void *), extern void halt_skas(void); extern void reboot_skas(void); +/* irq.c */ +extern int os_waiting_for_events(struct irq_fd *active_fds); +extern int os_isatty(int fd); +extern int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds); +extern void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg, + struct irq_fd *active_fds, struct irq_fd ***last_irq_ptr2); +extern void os_free_irq_later(struct irq_fd *active_fds, + int irq, void *dev_id); +extern int os_get_pollfd(int i); +extern void os_set_pollfd(int i, int fd); +extern void os_set_ioignore(void); +extern void init_irq_signals(int on_sigstack); + #endif diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c index 0e32f5f4a88..483e79c5ab9 100644 --- a/arch/um/kernel/irq_user.c +++ b/arch/um/kernel/irq_user.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -18,53 +18,25 @@ #include "sigio.h" #include "irq_user.h" #include "os.h" +#include "misc_constants.h" -struct irq_fd { - struct irq_fd *next; - void *id; - int fd; - int type; - int irq; - int pid; - int events; - int current_events; -}; - -static struct irq_fd *active_fds = NULL; +struct irq_fd *active_fds = NULL; static struct irq_fd **last_irq_ptr = &active_fds; -static struct pollfd *pollfds = NULL; -static int pollfds_num = 0; -static int pollfds_size = 0; - -extern int io_count, intr_count; - extern void free_irqs(void); void sigio_handler(int sig, union uml_pt_regs *regs) { struct irq_fd *irq_fd; - int i, n; + int n; if(smp_sigio_handler()) return; while(1){ - n = poll(pollfds, pollfds_num, 0); - if(n < 0){ - if(errno == EINTR) continue; - printk("sigio_handler : poll returned %d, " - "errno = %d\n", n, errno); - break; - } - if(n == 0) break; - - irq_fd = active_fds; - for(i = 0; i < pollfds_num; i++){ - if(pollfds[i].revents != 0){ - irq_fd->current_events = pollfds[i].revents; - pollfds[i].fd = -1; - } - irq_fd = irq_fd->next; - } + n = os_waiting_for_events(active_fds); + if (n <= 0) { + if(n == -EINTR) continue; + else break; + } for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){ if(irq_fd->current_events != 0){ @@ -77,14 +49,9 @@ void sigio_handler(int sig, union uml_pt_regs *regs) free_irqs(); } -int activate_ipi(int fd, int pid) -{ - return(os_set_fd_async(fd, pid)); -} - static void maybe_sigio_broken(int fd, int type) { - if(isatty(fd)){ + if(os_isatty(fd)){ if((type == IRQ_WRITE) && !pty_output_sigio){ write_sigio_workaround(); add_sigio_fd(fd, 0); @@ -96,12 +63,13 @@ static void maybe_sigio_broken(int fd, int type) } } + int activate_fd(int irq, int fd, int type, void *dev_id) { struct pollfd *tmp_pfd; struct irq_fd *new_fd, *irq_fd; unsigned long flags; - int pid, events, err, n, size; + int pid, events, err, n; pid = os_getpid(); err = os_set_fd_async(fd, pid); @@ -113,8 +81,8 @@ int activate_fd(int irq, int fd, int type, void *dev_id) if(new_fd == NULL) goto out; - if(type == IRQ_READ) events = POLLIN | POLLPRI; - else events = POLLOUT; + if(type == IRQ_READ) events = UM_POLLIN | UM_POLLPRI; + else events = UM_POLLOUT; *new_fd = ((struct irq_fd) { .next = NULL, .id = dev_id, .fd = fd, @@ -125,12 +93,12 @@ int activate_fd(int irq, int fd, int type, void *dev_id) .current_events = 0 } ); /* Critical section - locked by a spinlock because this stuff can - * be changed from interrupt handlers. The stuff above is done + * be changed from interrupt handlers. The stuff above is done * outside the lock because it allocates memory. */ /* Actually, it only looks like it can be called from interrupt - * context. The culprit is reactivate_fd, which calls + * context. The culprit is reactivate_fd, which calls * maybe_sigio_broken, which calls write_sigio_workaround, * which calls activate_fd. However, write_sigio_workaround should * only be called once, at boot time. That would make it clear that @@ -147,40 +115,42 @@ int activate_fd(int irq, int fd, int type, void *dev_id) } } - n = pollfds_num; - if(n == pollfds_size){ - while(1){ - /* Here we have to drop the lock in order to call - * kmalloc, which might sleep. If something else - * came in and changed the pollfds array, we free - * the buffer and try again. - */ - irq_unlock(flags); - size = (pollfds_num + 1) * sizeof(pollfds[0]); - tmp_pfd = um_kmalloc(size); - flags = irq_lock(); - if(tmp_pfd == NULL) - goto out_unlock; - if(n == pollfds_size) - break; + /*-------------*/ + if(type == IRQ_WRITE) + fd = -1; + + tmp_pfd = NULL; + n = 0; + + while(1){ + n = os_create_pollfd(fd, events, tmp_pfd, n); + if (n == 0) + break; + + /* n > 0 + * It means we couldn't put new pollfd to current pollfds + * and tmp_fds is NULL or too small for new pollfds array. + * Needed size is equal to n as minimum. + * + * Here we have to drop the lock in order to call + * kmalloc, which might sleep. + * If something else came in and changed the pollfds array + * so we will not be able to put new pollfd struct to pollfds + * then we free the buffer tmp_fds and try again. + */ + irq_unlock(flags); + if (tmp_pfd != NULL) { kfree(tmp_pfd); + tmp_pfd = NULL; } - if(pollfds != NULL){ - memcpy(tmp_pfd, pollfds, - sizeof(pollfds[0]) * pollfds_size); - kfree(pollfds); - } - pollfds = tmp_pfd; - pollfds_size++; - } - if(type == IRQ_WRITE) - fd = -1; + tmp_pfd = um_kmalloc(n); + if (tmp_pfd == NULL) + goto out_kfree; - pollfds[pollfds_num] = ((struct pollfd) { .fd = fd, - .events = events, - .revents = 0 }); - pollfds_num++; + flags = irq_lock(); + } + /*-------------*/ *last_irq_ptr = new_fd; last_irq_ptr = &new_fd->next; @@ -196,6 +166,7 @@ int activate_fd(int irq, int fd, int type, void *dev_id) out_unlock: irq_unlock(flags); + out_kfree: kfree(new_fd); out: return(err); @@ -203,43 +174,10 @@ int activate_fd(int irq, int fd, int type, void *dev_id) static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg) { - struct irq_fd **prev; unsigned long flags; - int i = 0; flags = irq_lock(); - prev = &active_fds; - while(*prev != NULL){ - if((*test)(*prev, arg)){ - struct irq_fd *old_fd = *prev; - if((pollfds[i].fd != -1) && - (pollfds[i].fd != (*prev)->fd)){ - printk("free_irq_by_cb - mismatch between " - "active_fds and pollfds, fd %d vs %d\n", - (*prev)->fd, pollfds[i].fd); - goto out; - } - - pollfds_num--; - - /* This moves the *whole* array after pollfds[i] (though - * it doesn't spot as such)! */ - - memmove(&pollfds[i], &pollfds[i + 1], - (pollfds_num - i) * sizeof(pollfds[0])); - - if(last_irq_ptr == &old_fd->next) - last_irq_ptr = prev; - *prev = (*prev)->next; - if(old_fd->type == IRQ_WRITE) - ignore_sigio_fd(old_fd->fd); - kfree(old_fd); - continue; - } - prev = &(*prev)->next; - i++; - } - out: + os_free_irq_by_cb(test, arg, active_fds, &last_irq_ptr); irq_unlock(flags); } @@ -277,6 +215,7 @@ static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out) { struct irq_fd *irq; int i = 0; + int fdi; for(irq=active_fds; irq != NULL; irq = irq->next){ if((irq->fd == fd) && (irq->irq == irqnum)) break; @@ -286,10 +225,11 @@ static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out) printk("find_irq_by_fd doesn't have descriptor %d\n", fd); goto out; } - if((pollfds[i].fd != -1) && (pollfds[i].fd != fd)){ + fdi = os_get_pollfd(i); + if((fdi != -1) && (fdi != fd)){ printk("find_irq_by_fd - mismatch between active_fds and " - "pollfds, fd %d vs %d, need %d\n", irq->fd, - pollfds[i].fd, fd); + "pollfds, fd %d vs %d, need %d\n", irq->fd, + fdi, fd); irq = NULL; goto out; } @@ -310,9 +250,7 @@ void reactivate_fd(int fd, int irqnum) irq_unlock(flags); return; } - - pollfds[i].fd = irq->fd; - + os_set_pollfd(i, irq->fd); irq_unlock(flags); /* This calls activate_fd, so it has to be outside the critical @@ -331,7 +269,7 @@ void deactivate_fd(int fd, int irqnum) irq = find_irq_by_fd(fd, irqnum, &i); if(irq == NULL) goto out; - pollfds[i].fd = -1; + os_set_pollfd(i, -1); out: irq_unlock(flags); } @@ -347,21 +285,11 @@ int deactivate_all_fds(void) return(err); } /* If there is a signal already queued, after unblocking ignore it */ - set_handler(SIGIO, SIG_IGN, 0, -1); + os_set_ioignore(); return(0); } -void forward_ipi(int fd, int pid) -{ - int err; - - err = os_set_owner(fd, pid); - if(err < 0) - printk("forward_ipi: set_owner failed, fd = %d, me = %d, " - "target = %d, err = %d\n", fd, os_getpid(), pid, -err); -} - void forward_interrupts(int pid) { struct irq_fd *irq; @@ -384,22 +312,6 @@ void forward_interrupts(int pid) irq_unlock(flags); } -void init_irq_signals(int on_sigstack) -{ - __sighandler_t h; - int flags; - - flags = on_sigstack ? SA_ONSTACK : 0; - if(timer_irq_inited) h = (__sighandler_t) alarm_handler; - else h = boot_timer_handler; - - set_handler(SIGVTALRM, h, flags | SA_RESTART, - SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1); - set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART, - SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); - signal(SIGWINCH, SIG_IGN); -} - /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c index 72113b0a96e..c8d8d0ac1a7 100644 --- a/arch/um/kernel/smp.c +++ b/arch/um/kernel/smp.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -77,9 +77,9 @@ static int idle_proc(void *cpup) if(err < 0) panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err); - activate_ipi(cpu_data[cpu].ipi_pipe[0], + os_set_fd_async(cpu_data[cpu].ipi_pipe[0], current->thread.mode.tt.extern_pid); - + wmb(); if (cpu_test_and_set(cpu, cpu_callin_map)) { printk("huh, CPU#%d already present??\n", cpu); @@ -106,7 +106,7 @@ static struct task_struct *idle_thread(int cpu) panic("copy_process failed in idle_thread, error = %ld", PTR_ERR(new_task)); - cpu_tasks[cpu] = ((struct cpu_task) + cpu_tasks[cpu] = ((struct cpu_task) { .pid = new_task->thread.mode.tt.extern_pid, .task = new_task } ); idle_threads[cpu] = new_task; @@ -134,12 +134,12 @@ void smp_prepare_cpus(unsigned int maxcpus) if(err < 0) panic("CPU#0 failed to create IPI pipe, errno = %d", -err); - activate_ipi(cpu_data[me].ipi_pipe[0], + os_set_fd_async(cpu_data[me].ipi_pipe[0], current->thread.mode.tt.extern_pid); for(cpu = 1; cpu < ncpus; cpu++){ printk("Booting processor %d...\n", cpu); - + idle = idle_thread(cpu); init_idle(idle, cpu); @@ -223,7 +223,7 @@ void smp_call_function_slave(int cpu) atomic_inc(&scf_finished); } -int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic, +int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic, int wait) { int cpus = num_online_cpus() - 1; diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index 08a4e628b24..73d3d837ed6 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile @@ -3,14 +3,14 @@ # Licensed under the GPL # -obj-y = aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \ +obj-y = aio.o elf_aux.o file.o helper.o irq.o main.o mem.o process.o signal.o \ start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o user_syms.o \ util.o drivers/ sys-$(SUBARCH)/ obj-$(CONFIG_MODE_SKAS) += skas/ -USER_OBJS := aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \ - start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o util.o +USER_OBJS := aio.o elf_aux.o file.o helper.o irq.o main.o mem.o process.o \ + signal.o start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o util.o elf_aux.o: $(ARCH_DIR)/kernel-offsets.h CFLAGS_elf_aux.o += -I$(objtree)/arch/um diff --git a/arch/um/os-Linux/irq.c b/arch/um/os-Linux/irq.c new file mode 100644 index 00000000000..e599be423da --- /dev/null +++ b/arch/um/os-Linux/irq.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "user_util.h" +#include "kern_util.h" +#include "user.h" +#include "process.h" +#include "sigio.h" +#include "irq_user.h" +#include "os.h" + +static struct pollfd *pollfds = NULL; +static int pollfds_num = 0; +static int pollfds_size = 0; + +int os_waiting_for_events(struct irq_fd *active_fds) +{ + struct irq_fd *irq_fd; + int i, n, err; + + n = poll(pollfds, pollfds_num, 0); + if(n < 0){ + err = -errno; + if(errno != EINTR) + printk("sigio_handler: os_waiting_for_events:" + " poll returned %d, errno = %d\n", n, errno); + return err; + } + + if(n == 0) + return 0; + + irq_fd = active_fds; + + for(i = 0; i < pollfds_num; i++){ + if(pollfds[i].revents != 0){ + irq_fd->current_events = pollfds[i].revents; + pollfds[i].fd = -1; + } + irq_fd = irq_fd->next; + } + return n; +} + +int os_isatty(int fd) +{ + return(isatty(fd)); +} + +int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds) +{ + if (pollfds_num == pollfds_size) { + if (size_tmpfds <= pollfds_size * sizeof(pollfds[0])) { + /* return min size needed for new pollfds area */ + return((pollfds_size + 1) * sizeof(pollfds[0])); + } + + if(pollfds != NULL){ + memcpy(tmp_pfd, pollfds, + sizeof(pollfds[0]) * pollfds_size); + /* remove old pollfds */ + kfree(pollfds); + } + pollfds = tmp_pfd; + pollfds_size++; + } else { + /* remove not used tmp_pfd */ + if (tmp_pfd != NULL) + kfree(tmp_pfd); + } + + pollfds[pollfds_num] = ((struct pollfd) { .fd = fd, + .events = events, + .revents = 0 }); + pollfds_num++; + + return(0); +} + +void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg, + struct irq_fd *active_fds, struct irq_fd ***last_irq_ptr2) +{ + struct irq_fd **prev; + int i = 0; + + prev = &active_fds; + while(*prev != NULL){ + if((*test)(*prev, arg)){ + struct irq_fd *old_fd = *prev; + if((pollfds[i].fd != -1) && + (pollfds[i].fd != (*prev)->fd)){ + printk("os_free_irq_by_cb - mismatch between " + "active_fds and pollfds, fd %d vs %d\n", + (*prev)->fd, pollfds[i].fd); + goto out; + } + + pollfds_num--; + + /* This moves the *whole* array after pollfds[i] + * (though it doesn't spot as such)! + */ + + memmove(&pollfds[i], &pollfds[i + 1], + (pollfds_num - i) * sizeof(pollfds[0])); + if(*last_irq_ptr2 == &old_fd->next) + *last_irq_ptr2 = prev; + + *prev = (*prev)->next; + if(old_fd->type == IRQ_WRITE) + ignore_sigio_fd(old_fd->fd); + kfree(old_fd); + continue; + } + prev = &(*prev)->next; + i++; + } + out: + return; +} + + +int os_get_pollfd(int i) +{ + return(pollfds[i].fd); +} + +void os_set_pollfd(int i, int fd) +{ + pollfds[i].fd = fd; +} + +void os_set_ioignore(void) +{ + set_handler(SIGIO, SIG_IGN, 0, -1); +} + +void init_irq_signals(int on_sigstack) +{ + __sighandler_t h; + int flags; + + flags = on_sigstack ? SA_ONSTACK : 0; + if(timer_irq_inited) h = (__sighandler_t) alarm_handler; + else h = boot_timer_handler; + + set_handler(SIGVTALRM, h, flags | SA_RESTART, + SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1); + set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART, + SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); + signal(SIGWINCH, SIG_IGN); +} diff --git a/arch/um/os-Linux/tt.c b/arch/um/os-Linux/tt.c index 919d19f1153..5461a065bbb 100644 --- a/arch/um/os-Linux/tt.c +++ b/arch/um/os-Linux/tt.c @@ -110,6 +110,16 @@ int wait_for_stop(int pid, int sig, int cont_type, void *relay) } } +void forward_ipi(int fd, int pid) +{ + int err; + + err = os_set_owner(fd, pid); + if(err < 0) + printk("forward_ipi: set_owner failed, fd = %d, me = %d, " + "target = %d, err = %d\n", fd, os_getpid(), pid, -err); +} + /* *------------------------- * only for tt mode (will be deleted in future...) diff --git a/arch/um/sys-i386/user-offsets.c b/arch/um/sys-i386/user-offsets.c index 26b68675053..6f4ef2b7fa4 100644 --- a/arch/um/sys-i386/user-offsets.c +++ b/arch/um/sys-i386/user-offsets.c @@ -3,12 +3,13 @@ #include #include #include +#include #define DEFINE(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val)) + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) #define DEFINE_LONGS(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val/sizeof(unsigned long))) + asm volatile("\n->" #sym " %0 " #val : : "i" (val/sizeof(unsigned long))) #define OFFSET(sym, str, mem) \ DEFINE(sym, offsetof(struct str, mem)); @@ -67,4 +68,9 @@ void foo(void) DEFINE(HOST_ES, ES); DEFINE(HOST_GS, GS); DEFINE(UM_FRAME_SIZE, sizeof(struct user_regs_struct)); + + /* XXX Duplicated between i386 and x86_64 */ + DEFINE(UM_POLLIN, POLLIN); + DEFINE(UM_POLLPRI, POLLPRI); + DEFINE(UM_POLLOUT, POLLOUT); } diff --git a/arch/um/sys-x86_64/user-offsets.c b/arch/um/sys-x86_64/user-offsets.c index 7bd54a921cf..899cebb57c3 100644 --- a/arch/um/sys-x86_64/user-offsets.c +++ b/arch/um/sys-x86_64/user-offsets.c @@ -1,6 +1,7 @@ #include #include #include +#include #define __FRAME_OFFSETS #include #include @@ -88,4 +89,9 @@ void foo(void) DEFINE_LONGS(HOST_IP, RIP); DEFINE_LONGS(HOST_SP, RSP); DEFINE(UM_FRAME_SIZE, sizeof(struct user_regs_struct)); + + /* XXX Duplicated between i386 and x86_64 */ + DEFINE(UM_POLLIN, POLLIN); + DEFINE(UM_POLLPRI, POLLPRI); + DEFINE(UM_POLLOUT, POLLOUT); } -- cgit v1.2.3 From 9b4f018d92dbeff9305b4cf4aa80874c3974cfcc Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 27 Mar 2006 01:14:31 -0800 Subject: [PATCH] uml: merge irq_user.c and irq.c The serial UML OS-abstraction layer patch (um/kernel dir). This joins irq_user.c and irq.c files. Signed-off-by: Gennady Sharapov Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/Makefile | 2 +- arch/um/kernel/irq.c | 294 +++++++++++++++++++++++++++++++++++++++++ arch/um/kernel/irq_user.c | 324 ---------------------------------------------- 3 files changed, 295 insertions(+), 325 deletions(-) delete mode 100644 arch/um/kernel/irq_user.c (limited to 'arch') diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 693018ba80f..8458c30a626 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -7,7 +7,7 @@ extra-y := vmlinux.lds clean-files := obj-y = config.o exec_kern.o exitcode.o \ - init_task.o irq.o irq_user.o ksyms.o mem.o physmem.o \ + init_task.o irq.o ksyms.o mem.o physmem.o \ process_kern.o ptrace.o reboot.o resource.o sigio_user.o sigio_kern.o \ signal_kern.o smp.o syscall_kern.o sysrq.o \ time_kern.o tlb.o trap_kern.o uaccess.o um_arch.o umid.o diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index bbf94bf2921..c39ea3abeda 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -31,6 +31,8 @@ #include "irq_user.h" #include "irq_kern.h" #include "os.h" +#include "sigio.h" +#include "misc_constants.h" /* * Generic, controller-independent functions: @@ -77,6 +79,298 @@ skip: return 0; } +struct irq_fd *active_fds = NULL; +static struct irq_fd **last_irq_ptr = &active_fds; + +extern void free_irqs(void); + +void sigio_handler(int sig, union uml_pt_regs *regs) +{ + struct irq_fd *irq_fd; + int n; + + if(smp_sigio_handler()) return; + while(1){ + n = os_waiting_for_events(active_fds); + if (n <= 0) { + if(n == -EINTR) continue; + else break; + } + + for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){ + if(irq_fd->current_events != 0){ + irq_fd->current_events = 0; + do_IRQ(irq_fd->irq, regs); + } + } + } + + free_irqs(); +} + +static void maybe_sigio_broken(int fd, int type) +{ + if(os_isatty(fd)){ + if((type == IRQ_WRITE) && !pty_output_sigio){ + write_sigio_workaround(); + add_sigio_fd(fd, 0); + } + else if((type == IRQ_READ) && !pty_close_sigio){ + write_sigio_workaround(); + add_sigio_fd(fd, 1); + } + } +} + + +int activate_fd(int irq, int fd, int type, void *dev_id) +{ + struct pollfd *tmp_pfd; + struct irq_fd *new_fd, *irq_fd; + unsigned long flags; + int pid, events, err, n; + + pid = os_getpid(); + err = os_set_fd_async(fd, pid); + if(err < 0) + goto out; + + new_fd = um_kmalloc(sizeof(*new_fd)); + err = -ENOMEM; + if(new_fd == NULL) + goto out; + + if(type == IRQ_READ) events = UM_POLLIN | UM_POLLPRI; + else events = UM_POLLOUT; + *new_fd = ((struct irq_fd) { .next = NULL, + .id = dev_id, + .fd = fd, + .type = type, + .irq = irq, + .pid = pid, + .events = events, + .current_events = 0 } ); + + /* Critical section - locked by a spinlock because this stuff can + * be changed from interrupt handlers. The stuff above is done + * outside the lock because it allocates memory. + */ + + /* Actually, it only looks like it can be called from interrupt + * context. The culprit is reactivate_fd, which calls + * maybe_sigio_broken, which calls write_sigio_workaround, + * which calls activate_fd. However, write_sigio_workaround should + * only be called once, at boot time. That would make it clear that + * this is called only from process context, and can be locked with + * a semaphore. + */ + flags = irq_lock(); + for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){ + if((irq_fd->fd == fd) && (irq_fd->type == type)){ + printk("Registering fd %d twice\n", fd); + printk("Irqs : %d, %d\n", irq_fd->irq, irq); + printk("Ids : 0x%p, 0x%p\n", irq_fd->id, dev_id); + goto out_unlock; + } + } + + /*-------------*/ + if(type == IRQ_WRITE) + fd = -1; + + tmp_pfd = NULL; + n = 0; + + while(1){ + n = os_create_pollfd(fd, events, tmp_pfd, n); + if (n == 0) + break; + + /* n > 0 + * It means we couldn't put new pollfd to current pollfds + * and tmp_fds is NULL or too small for new pollfds array. + * Needed size is equal to n as minimum. + * + * Here we have to drop the lock in order to call + * kmalloc, which might sleep. + * If something else came in and changed the pollfds array + * so we will not be able to put new pollfd struct to pollfds + * then we free the buffer tmp_fds and try again. + */ + irq_unlock(flags); + if (tmp_pfd != NULL) { + kfree(tmp_pfd); + tmp_pfd = NULL; + } + + tmp_pfd = um_kmalloc(n); + if (tmp_pfd == NULL) + goto out_kfree; + + flags = irq_lock(); + } + /*-------------*/ + + *last_irq_ptr = new_fd; + last_irq_ptr = &new_fd->next; + + irq_unlock(flags); + + /* This calls activate_fd, so it has to be outside the critical + * section. + */ + maybe_sigio_broken(fd, type); + + return(0); + + out_unlock: + irq_unlock(flags); + out_kfree: + kfree(new_fd); + out: + return(err); +} + +static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg) +{ + unsigned long flags; + + flags = irq_lock(); + os_free_irq_by_cb(test, arg, active_fds, &last_irq_ptr); + irq_unlock(flags); +} + +struct irq_and_dev { + int irq; + void *dev; +}; + +static int same_irq_and_dev(struct irq_fd *irq, void *d) +{ + struct irq_and_dev *data = d; + + return((irq->irq == data->irq) && (irq->id == data->dev)); +} + +void free_irq_by_irq_and_dev(unsigned int irq, void *dev) +{ + struct irq_and_dev data = ((struct irq_and_dev) { .irq = irq, + .dev = dev }); + + free_irq_by_cb(same_irq_and_dev, &data); +} + +static int same_fd(struct irq_fd *irq, void *fd) +{ + return(irq->fd == *((int *) fd)); +} + +void free_irq_by_fd(int fd) +{ + free_irq_by_cb(same_fd, &fd); +} + +static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out) +{ + struct irq_fd *irq; + int i = 0; + int fdi; + + for(irq=active_fds; irq != NULL; irq = irq->next){ + if((irq->fd == fd) && (irq->irq == irqnum)) break; + i++; + } + if(irq == NULL){ + printk("find_irq_by_fd doesn't have descriptor %d\n", fd); + goto out; + } + fdi = os_get_pollfd(i); + if((fdi != -1) && (fdi != fd)){ + printk("find_irq_by_fd - mismatch between active_fds and " + "pollfds, fd %d vs %d, need %d\n", irq->fd, + fdi, fd); + irq = NULL; + goto out; + } + *index_out = i; + out: + return(irq); +} + +void reactivate_fd(int fd, int irqnum) +{ + struct irq_fd *irq; + unsigned long flags; + int i; + + flags = irq_lock(); + irq = find_irq_by_fd(fd, irqnum, &i); + if(irq == NULL){ + irq_unlock(flags); + return; + } + os_set_pollfd(i, irq->fd); + irq_unlock(flags); + + /* This calls activate_fd, so it has to be outside the critical + * section. + */ + maybe_sigio_broken(fd, irq->type); +} + +void deactivate_fd(int fd, int irqnum) +{ + struct irq_fd *irq; + unsigned long flags; + int i; + + flags = irq_lock(); + irq = find_irq_by_fd(fd, irqnum, &i); + if(irq == NULL) + goto out; + os_set_pollfd(i, -1); + out: + irq_unlock(flags); +} + +int deactivate_all_fds(void) +{ + struct irq_fd *irq; + int err; + + for(irq=active_fds;irq != NULL;irq = irq->next){ + err = os_clear_fd_async(irq->fd); + if(err) + return(err); + } + /* If there is a signal already queued, after unblocking ignore it */ + os_set_ioignore(); + + return(0); +} + +void forward_interrupts(int pid) +{ + struct irq_fd *irq; + unsigned long flags; + int err; + + flags = irq_lock(); + for(irq=active_fds;irq != NULL;irq = irq->next){ + err = os_set_owner(irq->fd, pid); + if(err < 0){ + /* XXX Just remove the irq rather than + * print out an infinite stream of these + */ + printk("Failed to forward %d to pid %d, err = %d\n", + irq->fd, pid, -err); + } + + irq->pid = pid; + } + irq_unlock(flags); +} + /* * do_IRQ handles all normal device IRQ's (the special * SMP cross-CPU interrupts have their own specific diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c deleted file mode 100644 index 483e79c5ab9..00000000000 --- a/arch/um/kernel/irq_user.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "user_util.h" -#include "kern_util.h" -#include "user.h" -#include "process.h" -#include "sigio.h" -#include "irq_user.h" -#include "os.h" -#include "misc_constants.h" - -struct irq_fd *active_fds = NULL; -static struct irq_fd **last_irq_ptr = &active_fds; - -extern void free_irqs(void); - -void sigio_handler(int sig, union uml_pt_regs *regs) -{ - struct irq_fd *irq_fd; - int n; - - if(smp_sigio_handler()) return; - while(1){ - n = os_waiting_for_events(active_fds); - if (n <= 0) { - if(n == -EINTR) continue; - else break; - } - - for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){ - if(irq_fd->current_events != 0){ - irq_fd->current_events = 0; - do_IRQ(irq_fd->irq, regs); - } - } - } - - free_irqs(); -} - -static void maybe_sigio_broken(int fd, int type) -{ - if(os_isatty(fd)){ - if((type == IRQ_WRITE) && !pty_output_sigio){ - write_sigio_workaround(); - add_sigio_fd(fd, 0); - } - else if((type == IRQ_READ) && !pty_close_sigio){ - write_sigio_workaround(); - add_sigio_fd(fd, 1); - } - } -} - - -int activate_fd(int irq, int fd, int type, void *dev_id) -{ - struct pollfd *tmp_pfd; - struct irq_fd *new_fd, *irq_fd; - unsigned long flags; - int pid, events, err, n; - - pid = os_getpid(); - err = os_set_fd_async(fd, pid); - if(err < 0) - goto out; - - new_fd = um_kmalloc(sizeof(*new_fd)); - err = -ENOMEM; - if(new_fd == NULL) - goto out; - - if(type == IRQ_READ) events = UM_POLLIN | UM_POLLPRI; - else events = UM_POLLOUT; - *new_fd = ((struct irq_fd) { .next = NULL, - .id = dev_id, - .fd = fd, - .type = type, - .irq = irq, - .pid = pid, - .events = events, - .current_events = 0 } ); - - /* Critical section - locked by a spinlock because this stuff can - * be changed from interrupt handlers. The stuff above is done - * outside the lock because it allocates memory. - */ - - /* Actually, it only looks like it can be called from interrupt - * context. The culprit is reactivate_fd, which calls - * maybe_sigio_broken, which calls write_sigio_workaround, - * which calls activate_fd. However, write_sigio_workaround should - * only be called once, at boot time. That would make it clear that - * this is called only from process context, and can be locked with - * a semaphore. - */ - flags = irq_lock(); - for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){ - if((irq_fd->fd == fd) && (irq_fd->type == type)){ - printk("Registering fd %d twice\n", fd); - printk("Irqs : %d, %d\n", irq_fd->irq, irq); - printk("Ids : 0x%x, 0x%x\n", irq_fd->id, dev_id); - goto out_unlock; - } - } - - /*-------------*/ - if(type == IRQ_WRITE) - fd = -1; - - tmp_pfd = NULL; - n = 0; - - while(1){ - n = os_create_pollfd(fd, events, tmp_pfd, n); - if (n == 0) - break; - - /* n > 0 - * It means we couldn't put new pollfd to current pollfds - * and tmp_fds is NULL or too small for new pollfds array. - * Needed size is equal to n as minimum. - * - * Here we have to drop the lock in order to call - * kmalloc, which might sleep. - * If something else came in and changed the pollfds array - * so we will not be able to put new pollfd struct to pollfds - * then we free the buffer tmp_fds and try again. - */ - irq_unlock(flags); - if (tmp_pfd != NULL) { - kfree(tmp_pfd); - tmp_pfd = NULL; - } - - tmp_pfd = um_kmalloc(n); - if (tmp_pfd == NULL) - goto out_kfree; - - flags = irq_lock(); - } - /*-------------*/ - - *last_irq_ptr = new_fd; - last_irq_ptr = &new_fd->next; - - irq_unlock(flags); - - /* This calls activate_fd, so it has to be outside the critical - * section. - */ - maybe_sigio_broken(fd, type); - - return(0); - - out_unlock: - irq_unlock(flags); - out_kfree: - kfree(new_fd); - out: - return(err); -} - -static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg) -{ - unsigned long flags; - - flags = irq_lock(); - os_free_irq_by_cb(test, arg, active_fds, &last_irq_ptr); - irq_unlock(flags); -} - -struct irq_and_dev { - int irq; - void *dev; -}; - -static int same_irq_and_dev(struct irq_fd *irq, void *d) -{ - struct irq_and_dev *data = d; - - return((irq->irq == data->irq) && (irq->id == data->dev)); -} - -void free_irq_by_irq_and_dev(unsigned int irq, void *dev) -{ - struct irq_and_dev data = ((struct irq_and_dev) { .irq = irq, - .dev = dev }); - - free_irq_by_cb(same_irq_and_dev, &data); -} - -static int same_fd(struct irq_fd *irq, void *fd) -{ - return(irq->fd == *((int *) fd)); -} - -void free_irq_by_fd(int fd) -{ - free_irq_by_cb(same_fd, &fd); -} - -static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out) -{ - struct irq_fd *irq; - int i = 0; - int fdi; - - for(irq=active_fds; irq != NULL; irq = irq->next){ - if((irq->fd == fd) && (irq->irq == irqnum)) break; - i++; - } - if(irq == NULL){ - printk("find_irq_by_fd doesn't have descriptor %d\n", fd); - goto out; - } - fdi = os_get_pollfd(i); - if((fdi != -1) && (fdi != fd)){ - printk("find_irq_by_fd - mismatch between active_fds and " - "pollfds, fd %d vs %d, need %d\n", irq->fd, - fdi, fd); - irq = NULL; - goto out; - } - *index_out = i; - out: - return(irq); -} - -void reactivate_fd(int fd, int irqnum) -{ - struct irq_fd *irq; - unsigned long flags; - int i; - - flags = irq_lock(); - irq = find_irq_by_fd(fd, irqnum, &i); - if(irq == NULL){ - irq_unlock(flags); - return; - } - os_set_pollfd(i, irq->fd); - irq_unlock(flags); - - /* This calls activate_fd, so it has to be outside the critical - * section. - */ - maybe_sigio_broken(fd, irq->type); -} - -void deactivate_fd(int fd, int irqnum) -{ - struct irq_fd *irq; - unsigned long flags; - int i; - - flags = irq_lock(); - irq = find_irq_by_fd(fd, irqnum, &i); - if(irq == NULL) - goto out; - os_set_pollfd(i, -1); - out: - irq_unlock(flags); -} - -int deactivate_all_fds(void) -{ - struct irq_fd *irq; - int err; - - for(irq=active_fds;irq != NULL;irq = irq->next){ - err = os_clear_fd_async(irq->fd); - if(err) - return(err); - } - /* If there is a signal already queued, after unblocking ignore it */ - os_set_ioignore(); - - return(0); -} - -void forward_interrupts(int pid) -{ - struct irq_fd *irq; - unsigned long flags; - int err; - - flags = irq_lock(); - for(irq=active_fds;irq != NULL;irq = irq->next){ - err = os_set_owner(irq->fd, pid); - if(err < 0){ - /* XXX Just remove the irq rather than - * print out an infinite stream of these - */ - printk("Failed to forward %d to pid %d, err = %d\n", - irq->fd, pid, -err); - } - - irq->pid = pid; - } - irq_unlock(flags); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ -- cgit v1.2.3 From 8e367065eea04a6fde5cb8f3854164af99c45693 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 27 Mar 2006 01:14:32 -0800 Subject: [PATCH] uml: move SIGIO startup code to os-Linux/start_up.c The serial UML OS-abstraction layer patch (um/kernel dir). This moves all startup code from sigio_user.c file under os-Linux dir Signed-off-by: Gennady Sharapov Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/include/os.h | 1 + arch/um/include/sigio.h | 1 - arch/um/kernel/sigio_kern.c | 10 ++- arch/um/kernel/sigio_user.c | 162 +++----------------------------------------- arch/um/kernel/um_arch.c | 3 +- arch/um/os-Linux/start_up.c | 128 ++++++++++++++++++++++++++++++++++ 6 files changed, 148 insertions(+), 157 deletions(-) (limited to 'arch') diff --git a/arch/um/include/os.h b/arch/um/include/os.h index efae3e6acb5..6d865d4eade 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -161,6 +161,7 @@ extern int os_lock_file(int fd, int excl); /* start_up.c */ extern void os_early_checks(void); extern int can_do_skas(void); +extern void os_check_bugs(void); /* Make sure they are clear when running in TT mode. Required by * SEGV_MAYBE_FIXABLE */ diff --git a/arch/um/include/sigio.h b/arch/um/include/sigio.h index 37d76e29a14..1432fcfb321 100644 --- a/arch/um/include/sigio.h +++ b/arch/um/include/sigio.h @@ -8,7 +8,6 @@ extern int write_sigio_irq(int fd); extern int register_sigio_fd(int fd); -extern int read_sigio_fd(int fd); extern int add_sigio_fd(int fd, int read); extern int ignore_sigio_fd(int fd); extern void sigio_lock(void); diff --git a/arch/um/kernel/sigio_kern.c b/arch/um/kernel/sigio_kern.c index 229988463c4..1c1300fb1e9 100644 --- a/arch/um/kernel/sigio_kern.c +++ b/arch/um/kernel/sigio_kern.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -12,13 +12,16 @@ #include "sigio.h" #include "irq_user.h" #include "irq_kern.h" +#include "os.h" /* Protected by sigio_lock() called from write_sigio_workaround */ static int sigio_irq_fd = -1; static irqreturn_t sigio_interrupt(int irq, void *data, struct pt_regs *unused) { - read_sigio_fd(sigio_irq_fd); + char c; + + os_read_file(sigio_irq_fd, &c, sizeof(c)); reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ); return(IRQ_HANDLED); } @@ -51,6 +54,9 @@ void sigio_unlock(void) spin_unlock(&sigio_spinlock); } +extern void sigio_cleanup(void); +__uml_exitcall(sigio_cleanup); + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c index f7b18e157d3..9bef9413cb5 100644 --- a/arch/um/kernel/sigio_user.c +++ b/arch/um/kernel/sigio_user.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -20,127 +20,6 @@ #include "sigio.h" #include "os.h" -/* Changed during early boot */ -int pty_output_sigio = 0; -int pty_close_sigio = 0; - -/* Used as a flag during SIGIO testing early in boot */ -static volatile int got_sigio = 0; - -void __init handler(int sig) -{ - got_sigio = 1; -} - -struct openpty_arg { - int master; - int slave; - int err; -}; - -static void openpty_cb(void *arg) -{ - struct openpty_arg *info = arg; - - info->err = 0; - if(openpty(&info->master, &info->slave, NULL, NULL, NULL)) - info->err = -errno; -} - -void __init check_one_sigio(void (*proc)(int, int)) -{ - struct sigaction old, new; - struct openpty_arg pty = { .master = -1, .slave = -1 }; - int master, slave, err; - - initial_thread_cb(openpty_cb, &pty); - if(pty.err){ - printk("openpty failed, errno = %d\n", -pty.err); - return; - } - - master = pty.master; - slave = pty.slave; - - if((master == -1) || (slave == -1)){ - printk("openpty failed to allocate a pty\n"); - return; - } - - /* Not now, but complain so we now where we failed. */ - err = raw(master); - if (err < 0) - panic("check_sigio : __raw failed, errno = %d\n", -err); - - err = os_sigio_async(master, slave); - if(err < 0) - panic("tty_fds : sigio_async failed, err = %d\n", -err); - - if(sigaction(SIGIO, NULL, &old) < 0) - panic("check_sigio : sigaction 1 failed, errno = %d\n", errno); - new = old; - new.sa_handler = handler; - if(sigaction(SIGIO, &new, NULL) < 0) - panic("check_sigio : sigaction 2 failed, errno = %d\n", errno); - - got_sigio = 0; - (*proc)(master, slave); - - os_close_file(master); - os_close_file(slave); - - if(sigaction(SIGIO, &old, NULL) < 0) - panic("check_sigio : sigaction 3 failed, errno = %d\n", errno); -} - -static void tty_output(int master, int slave) -{ - int n; - char buf[512]; - - printk("Checking that host ptys support output SIGIO..."); - - memset(buf, 0, sizeof(buf)); - - while(os_write_file(master, buf, sizeof(buf)) > 0) ; - if(errno != EAGAIN) - panic("check_sigio : write failed, errno = %d\n", errno); - while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ; - - if (got_sigio) { - printk("Yes\n"); - pty_output_sigio = 1; - } else if (n == -EAGAIN) { - printk("No, enabling workaround\n"); - } else { - panic("check_sigio : read failed, err = %d\n", n); - } -} - -static void tty_close(int master, int slave) -{ - printk("Checking that host ptys support SIGIO on close..."); - - os_close_file(slave); - if(got_sigio){ - printk("Yes\n"); - pty_close_sigio = 1; - } - else printk("No, enabling workaround\n"); -} - -void __init check_sigio(void) -{ - if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) && - (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){ - printk("No pseudo-terminals available - skipping pty SIGIO " - "check\n"); - return; - } - check_one_sigio(tty_output); - check_one_sigio(tty_close); -} - /* Protected by sigio_lock(), also used by sigio_cleanup, which is an * exitcall. */ @@ -267,10 +146,10 @@ static void update_thread(void) if(write_sigio_pid != -1) os_kill_process(write_sigio_pid, 1); write_sigio_pid = -1; - os_close_file(sigio_private[0]); - os_close_file(sigio_private[1]); - os_close_file(write_sigio_fds[0]); - os_close_file(write_sigio_fds[1]); + close(sigio_private[0]); + close(sigio_private[1]); + close(write_sigio_fds[0]); + close(write_sigio_fds[1]); /* Critical section end */ set_signals(flags); } @@ -428,39 +307,18 @@ void write_sigio_workaround(void) out_free: kfree(p); out_close2: - os_close_file(l_sigio_private[0]); - os_close_file(l_sigio_private[1]); + close(l_sigio_private[0]); + close(l_sigio_private[1]); out_close1: - os_close_file(l_write_sigio_fds[0]); - os_close_file(l_write_sigio_fds[1]); + close(l_write_sigio_fds[0]); + close(l_write_sigio_fds[1]); return; } -int read_sigio_fd(int fd) -{ - int n; - char c; - - n = os_read_file(fd, &c, sizeof(c)); - if(n != sizeof(c)){ - if(n < 0) { - printk("read_sigio_fd - read failed, err = %d\n", -n); - return(n); - } - else { - printk("read_sigio_fd - short read, bytes = %d\n", n); - return(-EIO); - } - } - return(n); -} - -static void sigio_cleanup(void) +void sigio_cleanup(void) { if (write_sigio_pid != -1) { os_kill_process(write_sigio_pid, 1); write_sigio_pid = -1; } } - -__uml_exitcall(sigio_cleanup); diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 0c5b9dcfbe2..bb1c87211ac 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -487,8 +487,7 @@ void __init setup_arch(char **cmdline_p) void __init check_bugs(void) { arch_check_bugs(); - check_sigio(); - check_devanon(); + os_check_bugs(); } void apply_alternatives(struct alt_instr *start, struct alt_instr *end) diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 829d6b0d8b0..32753131f8d 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -3,6 +3,7 @@ * Licensed under the GPL */ +#include #include #include #include @@ -539,3 +540,130 @@ int __init parse_iomem(char *str, int *add) return(1); } + +/* Changed during early boot */ +int pty_output_sigio = 0; +int pty_close_sigio = 0; + +/* Used as a flag during SIGIO testing early in boot */ +static volatile int got_sigio = 0; + +static void __init handler(int sig) +{ + got_sigio = 1; +} + +struct openpty_arg { + int master; + int slave; + int err; +}; + +static void openpty_cb(void *arg) +{ + struct openpty_arg *info = arg; + + info->err = 0; + if(openpty(&info->master, &info->slave, NULL, NULL, NULL)) + info->err = -errno; +} + +static void __init check_one_sigio(void (*proc)(int, int)) +{ + struct sigaction old, new; + struct openpty_arg pty = { .master = -1, .slave = -1 }; + int master, slave, err; + + initial_thread_cb(openpty_cb, &pty); + if(pty.err){ + printk("openpty failed, errno = %d\n", -pty.err); + return; + } + + master = pty.master; + slave = pty.slave; + + if((master == -1) || (slave == -1)){ + printk("openpty failed to allocate a pty\n"); + return; + } + + /* Not now, but complain so we now where we failed. */ + err = raw(master); + if (err < 0) + panic("check_sigio : __raw failed, errno = %d\n", -err); + + err = os_sigio_async(master, slave); + if(err < 0) + panic("tty_fds : sigio_async failed, err = %d\n", -err); + + if(sigaction(SIGIO, NULL, &old) < 0) + panic("check_sigio : sigaction 1 failed, errno = %d\n", errno); + new = old; + new.sa_handler = handler; + if(sigaction(SIGIO, &new, NULL) < 0) + panic("check_sigio : sigaction 2 failed, errno = %d\n", errno); + + got_sigio = 0; + (*proc)(master, slave); + + close(master); + close(slave); + + if(sigaction(SIGIO, &old, NULL) < 0) + panic("check_sigio : sigaction 3 failed, errno = %d\n", errno); +} + +static void tty_output(int master, int slave) +{ + int n; + char buf[512]; + + printk("Checking that host ptys support output SIGIO..."); + + memset(buf, 0, sizeof(buf)); + + while(os_write_file(master, buf, sizeof(buf)) > 0) ; + if(errno != EAGAIN) + panic("check_sigio : write failed, errno = %d\n", errno); + while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ; + + if(got_sigio){ + printk("Yes\n"); + pty_output_sigio = 1; + } + else if(n == -EAGAIN) printk("No, enabling workaround\n"); + else panic("check_sigio : read failed, err = %d\n", n); +} + +static void tty_close(int master, int slave) +{ + printk("Checking that host ptys support SIGIO on close..."); + + close(slave); + if(got_sigio){ + printk("Yes\n"); + pty_close_sigio = 1; + } + else printk("No, enabling workaround\n"); +} + +void __init check_sigio(void) +{ + if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) && + (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){ + printk("No pseudo-terminals available - skipping pty SIGIO " + "check\n"); + return; + } + check_one_sigio(tty_output); + check_one_sigio(tty_close); +} + +void os_check_bugs(void) +{ + check_ptrace(); + check_sigio(); + check_devanon(); +} + -- cgit v1.2.3 From f206aabb035318ac4bafbf0b87798335de3634df Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 27 Mar 2006 01:14:33 -0800 Subject: [PATCH] uml: move sigio_user.c to os-Linux/sigio.c The serial UML OS-abstraction layer patch (um/kernel dir). This moves sigio_user.c to os-Linux dir Signed-off-by: Gennady Sharapov Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/include/os.h | 5 + arch/um/include/sigio.h | 2 - arch/um/include/user_util.h | 1 - arch/um/kernel/Makefile | 2 +- arch/um/kernel/sigio_user.c | 324 -------------------------------------------- arch/um/os-Linux/Makefile | 9 +- arch/um/os-Linux/sigio.c | 324 ++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 335 insertions(+), 332 deletions(-) delete mode 100644 arch/um/kernel/sigio_user.c create mode 100644 arch/um/os-Linux/sigio.c (limited to 'arch') diff --git a/arch/um/include/os.h b/arch/um/include/os.h index 6d865d4eade..53dee8d3cdc 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -311,4 +311,9 @@ extern void os_set_pollfd(int i, int fd); extern void os_set_ioignore(void); extern void init_irq_signals(int on_sigstack); +/* sigio.c */ +extern void write_sigio_workaround(void); +extern int add_sigio_fd(int fd, int read); +extern int ignore_sigio_fd(int fd); + #endif diff --git a/arch/um/include/sigio.h b/arch/um/include/sigio.h index 1432fcfb321..fe99ea163c2 100644 --- a/arch/um/include/sigio.h +++ b/arch/um/include/sigio.h @@ -8,8 +8,6 @@ extern int write_sigio_irq(int fd); extern int register_sigio_fd(int fd); -extern int add_sigio_fd(int fd, int read); -extern int ignore_sigio_fd(int fd); extern void sigio_lock(void); extern void sigio_unlock(void); diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h index a6f1f176cf8..992a7e1e0fc 100644 --- a/arch/um/include/user_util.h +++ b/arch/um/include/user_util.h @@ -58,7 +58,6 @@ extern int attach(int pid); extern void kill_child_dead(int pid); extern int cont(int pid); extern void check_sigio(void); -extern void write_sigio_workaround(void); extern void arch_check_bugs(void); extern int cpu_feature(char *what, char *buf, int len); extern int arch_handle_signal(int sig, union uml_pt_regs *regs); diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 8458c30a626..ac5afaa0306 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -8,7 +8,7 @@ clean-files := obj-y = config.o exec_kern.o exitcode.o \ init_task.o irq.o ksyms.o mem.o physmem.o \ - process_kern.o ptrace.o reboot.o resource.o sigio_user.o sigio_kern.o \ + process_kern.o ptrace.o reboot.o resource.o sigio_kern.o \ signal_kern.o smp.o syscall_kern.o sysrq.o \ time_kern.o tlb.o trap_kern.o uaccess.o um_arch.o umid.o diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c deleted file mode 100644 index 9bef9413cb5..00000000000 --- a/arch/um/kernel/sigio_user.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "init.h" -#include "user.h" -#include "kern_util.h" -#include "user_util.h" -#include "sigio.h" -#include "os.h" - -/* Protected by sigio_lock(), also used by sigio_cleanup, which is an - * exitcall. - */ -static int write_sigio_pid = -1; - -/* These arrays are initialized before the sigio thread is started, and - * the descriptors closed after it is killed. So, it can't see them change. - * On the UML side, they are changed under the sigio_lock. - */ -static int write_sigio_fds[2] = { -1, -1 }; -static int sigio_private[2] = { -1, -1 }; - -struct pollfds { - struct pollfd *poll; - int size; - int used; -}; - -/* Protected by sigio_lock(). Used by the sigio thread, but the UML thread - * synchronizes with it. - */ -struct pollfds current_poll = { - .poll = NULL, - .size = 0, - .used = 0 -}; - -struct pollfds next_poll = { - .poll = NULL, - .size = 0, - .used = 0 -}; - -static int write_sigio_thread(void *unused) -{ - struct pollfds *fds, tmp; - struct pollfd *p; - int i, n, respond_fd; - char c; - - signal(SIGWINCH, SIG_IGN); - fds = ¤t_poll; - while(1){ - n = poll(fds->poll, fds->used, -1); - if(n < 0){ - if(errno == EINTR) continue; - printk("write_sigio_thread : poll returned %d, " - "errno = %d\n", n, errno); - } - for(i = 0; i < fds->used; i++){ - p = &fds->poll[i]; - if(p->revents == 0) continue; - if(p->fd == sigio_private[1]){ - n = os_read_file(sigio_private[1], &c, sizeof(c)); - if(n != sizeof(c)) - printk("write_sigio_thread : " - "read failed, err = %d\n", -n); - tmp = current_poll; - current_poll = next_poll; - next_poll = tmp; - respond_fd = sigio_private[1]; - } - else { - respond_fd = write_sigio_fds[1]; - fds->used--; - memmove(&fds->poll[i], &fds->poll[i + 1], - (fds->used - i) * sizeof(*fds->poll)); - } - - n = os_write_file(respond_fd, &c, sizeof(c)); - if(n != sizeof(c)) - printk("write_sigio_thread : write failed, " - "err = %d\n", -n); - } - } - - return 0; -} - -static int need_poll(int n) -{ - if(n <= next_poll.size){ - next_poll.used = n; - return(0); - } - kfree(next_poll.poll); - next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd)); - if(next_poll.poll == NULL){ - printk("need_poll : failed to allocate new pollfds\n"); - next_poll.size = 0; - next_poll.used = 0; - return(-1); - } - next_poll.size = n; - next_poll.used = n; - return(0); -} - -/* Must be called with sigio_lock held, because it's needed by the marked - * critical section. */ -static void update_thread(void) -{ - unsigned long flags; - int n; - char c; - - flags = set_signals(0); - n = os_write_file(sigio_private[0], &c, sizeof(c)); - if(n != sizeof(c)){ - printk("update_thread : write failed, err = %d\n", -n); - goto fail; - } - - n = os_read_file(sigio_private[0], &c, sizeof(c)); - if(n != sizeof(c)){ - printk("update_thread : read failed, err = %d\n", -n); - goto fail; - } - - set_signals(flags); - return; - fail: - /* Critical section start */ - if(write_sigio_pid != -1) - os_kill_process(write_sigio_pid, 1); - write_sigio_pid = -1; - close(sigio_private[0]); - close(sigio_private[1]); - close(write_sigio_fds[0]); - close(write_sigio_fds[1]); - /* Critical section end */ - set_signals(flags); -} - -int add_sigio_fd(int fd, int read) -{ - int err = 0, i, n, events; - - sigio_lock(); - for(i = 0; i < current_poll.used; i++){ - if(current_poll.poll[i].fd == fd) - goto out; - } - - n = current_poll.used + 1; - err = need_poll(n); - if(err) - goto out; - - for(i = 0; i < current_poll.used; i++) - next_poll.poll[i] = current_poll.poll[i]; - - if(read) events = POLLIN; - else events = POLLOUT; - - next_poll.poll[n - 1] = ((struct pollfd) { .fd = fd, - .events = events, - .revents = 0 }); - update_thread(); - out: - sigio_unlock(); - return(err); -} - -int ignore_sigio_fd(int fd) -{ - struct pollfd *p; - int err = 0, i, n = 0; - - sigio_lock(); - for(i = 0; i < current_poll.used; i++){ - if(current_poll.poll[i].fd == fd) break; - } - if(i == current_poll.used) - goto out; - - err = need_poll(current_poll.used - 1); - if(err) - goto out; - - for(i = 0; i < current_poll.used; i++){ - p = ¤t_poll.poll[i]; - if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i]; - } - if(n == i){ - printk("ignore_sigio_fd : fd %d not found\n", fd); - err = -1; - goto out; - } - - update_thread(); - out: - sigio_unlock(); - return(err); -} - -static struct pollfd* setup_initial_poll(int fd) -{ - struct pollfd *p; - - p = um_kmalloc(sizeof(struct pollfd)); - if (p == NULL) { - printk("setup_initial_poll : failed to allocate poll\n"); - return NULL; - } - *p = ((struct pollfd) { .fd = fd, - .events = POLLIN, - .revents = 0 }); - return p; -} - -void write_sigio_workaround(void) -{ - unsigned long stack; - struct pollfd *p; - int err; - int l_write_sigio_fds[2]; - int l_sigio_private[2]; - int l_write_sigio_pid; - - /* We call this *tons* of times - and most ones we must just fail. */ - sigio_lock(); - l_write_sigio_pid = write_sigio_pid; - sigio_unlock(); - - if (l_write_sigio_pid != -1) - return; - - err = os_pipe(l_write_sigio_fds, 1, 1); - if(err < 0){ - printk("write_sigio_workaround - os_pipe 1 failed, " - "err = %d\n", -err); - return; - } - err = os_pipe(l_sigio_private, 1, 1); - if(err < 0){ - printk("write_sigio_workaround - os_pipe 1 failed, " - "err = %d\n", -err); - goto out_close1; - } - - p = setup_initial_poll(l_sigio_private[1]); - if(!p) - goto out_close2; - - sigio_lock(); - - /* Did we race? Don't try to optimize this, please, it's not so likely - * to happen, and no more than once at the boot. */ - if(write_sigio_pid != -1) - goto out_unlock; - - write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, - CLONE_FILES | CLONE_VM, &stack, 0); - - if (write_sigio_pid < 0) - goto out_clear; - - if (write_sigio_irq(l_write_sigio_fds[0])) - goto out_kill; - - /* Success, finally. */ - memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds)); - memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private)); - - current_poll = ((struct pollfds) { .poll = p, - .used = 1, - .size = 1 }); - - sigio_unlock(); - return; - - out_kill: - l_write_sigio_pid = write_sigio_pid; - write_sigio_pid = -1; - sigio_unlock(); - /* Going to call waitpid, avoid holding the lock. */ - os_kill_process(l_write_sigio_pid, 1); - goto out_free; - - out_clear: - write_sigio_pid = -1; - out_unlock: - sigio_unlock(); - out_free: - kfree(p); - out_close2: - close(l_sigio_private[0]); - close(l_sigio_private[1]); - out_close1: - close(l_write_sigio_fds[0]); - close(l_write_sigio_fds[1]); - return; -} - -void sigio_cleanup(void) -{ - if (write_sigio_pid != -1) { - os_kill_process(write_sigio_pid, 1); - write_sigio_pid = -1; - } -} diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index 73d3d837ed6..c3d56c2935c 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile @@ -3,14 +3,15 @@ # Licensed under the GPL # -obj-y = aio.o elf_aux.o file.o helper.o irq.o main.o mem.o process.o signal.o \ - start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o user_syms.o \ - util.o drivers/ sys-$(SUBARCH)/ +obj-y = aio.o elf_aux.o file.o helper.o irq.o main.o mem.o process.o sigio.o \ + signal.o start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o \ + user_syms.o util.o drivers/ sys-$(SUBARCH)/ obj-$(CONFIG_MODE_SKAS) += skas/ USER_OBJS := aio.o elf_aux.o file.o helper.o irq.o main.o mem.o process.o \ - signal.o start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o util.o + sigio.o signal.o start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o \ + util.o elf_aux.o: $(ARCH_DIR)/kernel-offsets.h CFLAGS_elf_aux.o += -I$(objtree)/arch/um diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c new file mode 100644 index 00000000000..7604c404c4c --- /dev/null +++ b/arch/um/os-Linux/sigio.c @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "init.h" +#include "user.h" +#include "kern_util.h" +#include "user_util.h" +#include "sigio.h" +#include "os.h" + +/* Protected by sigio_lock(), also used by sigio_cleanup, which is an + * exitcall. + */ +static int write_sigio_pid = -1; + +/* These arrays are initialized before the sigio thread is started, and + * the descriptors closed after it is killed. So, it can't see them change. + * On the UML side, they are changed under the sigio_lock. + */ +static int write_sigio_fds[2] = { -1, -1 }; +static int sigio_private[2] = { -1, -1 }; + +struct pollfds { + struct pollfd *poll; + int size; + int used; +}; + +/* Protected by sigio_lock(). Used by the sigio thread, but the UML thread + * synchronizes with it. + */ +struct pollfds current_poll = { + .poll = NULL, + .size = 0, + .used = 0 +}; + +struct pollfds next_poll = { + .poll = NULL, + .size = 0, + .used = 0 +}; + +static int write_sigio_thread(void *unused) +{ + struct pollfds *fds, tmp; + struct pollfd *p; + int i, n, respond_fd; + char c; + + signal(SIGWINCH, SIG_IGN); + fds = ¤t_poll; + while(1){ + n = poll(fds->poll, fds->used, -1); + if(n < 0){ + if(errno == EINTR) continue; + printk("write_sigio_thread : poll returned %d, " + "errno = %d\n", n, errno); + } + for(i = 0; i < fds->used; i++){ + p = &fds->poll[i]; + if(p->revents == 0) continue; + if(p->fd == sigio_private[1]){ + n = os_read_file(sigio_private[1], &c, sizeof(c)); + if(n != sizeof(c)) + printk("write_sigio_thread : " + "read failed, err = %d\n", -n); + tmp = current_poll; + current_poll = next_poll; + next_poll = tmp; + respond_fd = sigio_private[1]; + } + else { + respond_fd = write_sigio_fds[1]; + fds->used--; + memmove(&fds->poll[i], &fds->poll[i + 1], + (fds->used - i) * sizeof(*fds->poll)); + } + + n = os_write_file(respond_fd, &c, sizeof(c)); + if(n != sizeof(c)) + printk("write_sigio_thread : write failed, " + "err = %d\n", -n); + } + } + + return 0; +} + +static int need_poll(int n) +{ + if(n <= next_poll.size){ + next_poll.used = n; + return(0); + } + kfree(next_poll.poll); + next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd)); + if(next_poll.poll == NULL){ + printk("need_poll : failed to allocate new pollfds\n"); + next_poll.size = 0; + next_poll.used = 0; + return(-1); + } + next_poll.size = n; + next_poll.used = n; + return(0); +} + +/* Must be called with sigio_lock held, because it's needed by the marked + * critical section. */ +static void update_thread(void) +{ + unsigned long flags; + int n; + char c; + + flags = set_signals(0); + n = os_write_file(sigio_private[0], &c, sizeof(c)); + if(n != sizeof(c)){ + printk("update_thread : write failed, err = %d\n", -n); + goto fail; + } + + n = os_read_file(sigio_private[0], &c, sizeof(c)); + if(n != sizeof(c)){ + printk("update_thread : read failed, err = %d\n", -n); + goto fail; + } + + set_signals(flags); + return; + fail: + /* Critical section start */ + if(write_sigio_pid != -1) + os_kill_process(write_sigio_pid, 1); + write_sigio_pid = -1; + close(sigio_private[0]); + close(sigio_private[1]); + close(write_sigio_fds[0]); + close(write_sigio_fds[1]); + /* Critical section end */ + set_signals(flags); +} + +int add_sigio_fd(int fd, int read) +{ + int err = 0, i, n, events; + + sigio_lock(); + for(i = 0; i < current_poll.used; i++){ + if(current_poll.poll[i].fd == fd) + goto out; + } + + n = current_poll.used + 1; + err = need_poll(n); + if(err) + goto out; + + for(i = 0; i < current_poll.used; i++) + next_poll.poll[i] = current_poll.poll[i]; + + if(read) events = POLLIN; + else events = POLLOUT; + + next_poll.poll[n - 1] = ((struct pollfd) { .fd = fd, + .events = events, + .revents = 0 }); + update_thread(); + out: + sigio_unlock(); + return(err); +} + +int ignore_sigio_fd(int fd) +{ + struct pollfd *p; + int err = 0, i, n = 0; + + sigio_lock(); + for(i = 0; i < current_poll.used; i++){ + if(current_poll.poll[i].fd == fd) break; + } + if(i == current_poll.used) + goto out; + + err = need_poll(current_poll.used - 1); + if(err) + goto out; + + for(i = 0; i < current_poll.used; i++){ + p = ¤t_poll.poll[i]; + if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i]; + } + if(n == i){ + printk("ignore_sigio_fd : fd %d not found\n", fd); + err = -1; + goto out; + } + + update_thread(); + out: + sigio_unlock(); + return(err); +} + +static struct pollfd *setup_initial_poll(int fd) +{ + struct pollfd *p; + + p = um_kmalloc(sizeof(struct pollfd)); + if (p == NULL) { + printk("setup_initial_poll : failed to allocate poll\n"); + return NULL; + } + *p = ((struct pollfd) { .fd = fd, + .events = POLLIN, + .revents = 0 }); + return p; +} + +void write_sigio_workaround(void) +{ + unsigned long stack; + struct pollfd *p; + int err; + int l_write_sigio_fds[2]; + int l_sigio_private[2]; + int l_write_sigio_pid; + + /* We call this *tons* of times - and most ones we must just fail. */ + sigio_lock(); + l_write_sigio_pid = write_sigio_pid; + sigio_unlock(); + + if (l_write_sigio_pid != -1) + return; + + err = os_pipe(l_write_sigio_fds, 1, 1); + if(err < 0){ + printk("write_sigio_workaround - os_pipe 1 failed, " + "err = %d\n", -err); + return; + } + err = os_pipe(l_sigio_private, 1, 1); + if(err < 0){ + printk("write_sigio_workaround - os_pipe 2 failed, " + "err = %d\n", -err); + goto out_close1; + } + + p = setup_initial_poll(l_sigio_private[1]); + if(!p) + goto out_close2; + + sigio_lock(); + + /* Did we race? Don't try to optimize this, please, it's not so likely + * to happen, and no more than once at the boot. */ + if(write_sigio_pid != -1) + goto out_unlock; + + write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, + CLONE_FILES | CLONE_VM, &stack, 0); + + if (write_sigio_pid < 0) + goto out_clear; + + if (write_sigio_irq(l_write_sigio_fds[0])) + goto out_kill; + + /* Success, finally. */ + memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds)); + memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private)); + + current_poll = ((struct pollfds) { .poll = p, + .used = 1, + .size = 1 }); + + sigio_unlock(); + return; + + out_kill: + l_write_sigio_pid = write_sigio_pid; + write_sigio_pid = -1; + sigio_unlock(); + /* Going to call waitpid, avoid holding the lock. */ + os_kill_process(l_write_sigio_pid, 1); + goto out_free; + + out_clear: + write_sigio_pid = -1; + out_unlock: + sigio_unlock(); + out_free: + kfree(p); + out_close2: + close(l_sigio_private[0]); + close(l_sigio_private[1]); + out_close1: + close(l_write_sigio_fds[0]); + close(l_write_sigio_fds[1]); + return; +} + +void sigio_cleanup(void) +{ + if(write_sigio_pid != -1){ + os_kill_process(write_sigio_pid, 1); + write_sigio_pid = -1; + } +} -- cgit v1.2.3 From 81efcd3300754462537ffac60336158b2f773b4e Mon Sep 17 00:00:00 2001 From: Bodo Stroesser Date: Mon, 27 Mar 2006 01:14:34 -0800 Subject: [PATCH] uml: more carefully test whether we are in a system call For security reasons, UML in is_syscall() needs to have access to code in vsyscall-page. The current implementation grants this access by explicitly allowing access to vsyscall in access_ok_skas(). With this change, copy_from_user() may be used to read the code. Ptrace access to vsyscall-page for debugging already was implemented in get_user_pages() by mainline. In i386, copy_from_user can't access vsyscall-page, but returns EFAULT. To make UML behave as i386 does, I changed is_syscall to use access_process_vm(current) to read the code from vsyscall-page. This doesn't hurt security, but simplifies the code and prepares implementation of stub-vmas. Signed-off-by: Bodo Stroesser Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/sys-i386/ptrace.c | 15 ++++++++++++--- arch/um/sys-x86_64/ptrace.c | 22 +++++++++++++++++++++- 2 files changed, 33 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c index e839ce65ad2..8032a105949 100644 --- a/arch/um/sys-i386/ptrace.c +++ b/arch/um/sys-i386/ptrace.c @@ -6,6 +6,7 @@ #include #include #include "linux/sched.h" +#include "linux/mm.h" #include "asm/elf.h" #include "asm/ptrace.h" #include "asm/uaccess.h" @@ -26,9 +27,17 @@ int is_syscall(unsigned long addr) n = copy_from_user(&instr, (void __user *) addr, sizeof(instr)); if(n){ - printk("is_syscall : failed to read instruction from 0x%lx\n", - addr); - return(0); + /* access_process_vm() grants access to vsyscall and stub, + * while copy_from_user doesn't. Maybe access_process_vm is + * slow, but that doesn't matter, since it will be called only + * in case of singlestepping, if copy_from_user failed. + */ + n = access_process_vm(current, addr, &instr, sizeof(instr), 0); + if(n != sizeof(instr)) { + printk("is_syscall : failed to read instruction from " + "0x%lx\n", addr); + return(1); + } } /* int 0x80 or sysenter */ return((instr == 0x80cd) || (instr == 0x340f)); diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c index 74eee5c7c6d..147bbf05cbc 100644 --- a/arch/um/sys-x86_64/ptrace.c +++ b/arch/um/sys-x86_64/ptrace.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -136,9 +137,28 @@ void arch_switch(void) */ } +/* XXX Mostly copied from sys-i386 */ int is_syscall(unsigned long addr) { - panic("is_syscall"); + unsigned short instr; + int n; + + n = copy_from_user(&instr, (void __user *) addr, sizeof(instr)); + if(n){ + /* access_process_vm() grants access to vsyscall and stub, + * while copy_from_user doesn't. Maybe access_process_vm is + * slow, but that doesn't matter, since it will be called only + * in case of singlestepping, if copy_from_user failed. + */ + n = access_process_vm(current, addr, &instr, sizeof(instr), 0); + if(n != sizeof(instr)) { + printk("is_syscall : failed to read instruction from " + "0x%lx\n", addr); + return(1); + } + } + /* sysenter */ + return(instr == 0x050f); } int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu ) -- cgit v1.2.3 From c554f899b6747c9d8035bf91864d89b337ceb411 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 27 Mar 2006 01:14:36 -0800 Subject: [PATCH] uml: move tty logging to os-Linux The serial UML OS-abstraction layer patch (um/kernel dir). This moves all systemcalls from tty_log.c file under os-Linux dir Signed-off-by: Gennady Sharapov Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/Makefile | 5 +- arch/um/kernel/exec_kern.c | 2 - arch/um/kernel/tty_log.c | 230 --------------------------------------------- arch/um/os-Linux/Makefile | 8 +- arch/um/os-Linux/tty_log.c | 218 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 224 insertions(+), 239 deletions(-) delete mode 100644 arch/um/kernel/tty_log.c create mode 100644 arch/um/os-Linux/tty_log.c (limited to 'arch') diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index ac5afaa0306..fe08971b64c 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -15,15 +15,12 @@ obj-y = config.o exec_kern.o exitcode.o \ obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o obj-$(CONFIG_GPROF) += gprof_syms.o obj-$(CONFIG_GCOV) += gmon_syms.o -obj-$(CONFIG_TTY_LOG) += tty_log.o obj-$(CONFIG_SYSCALL_DEBUG) += syscall.o obj-$(CONFIG_MODE_TT) += tt/ obj-$(CONFIG_MODE_SKAS) += skas/ -user-objs-$(CONFIG_TTY_LOG) += tty_log.o - -USER_OBJS := $(user-objs-y) config.o tty_log.o +USER_OBJS := config.o include arch/um/scripts/Makefile.rules diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c index c264e1c05ab..1ca84319317 100644 --- a/arch/um/kernel/exec_kern.c +++ b/arch/um/kernel/exec_kern.c @@ -30,8 +30,6 @@ void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp); } -extern void log_exec(char **argv, void *tty); - static long execve1(char *file, char __user * __user *argv, char __user *__user *env) { diff --git a/arch/um/kernel/tty_log.c b/arch/um/kernel/tty_log.c deleted file mode 100644 index 9ada656f68c..00000000000 --- a/arch/um/kernel/tty_log.c +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and - * geoffrey hing - * Licensed under the GPL - */ - -#include -#include -#include -#include -#include -#include -#include "init.h" -#include "user.h" -#include "kern_util.h" -#include "os.h" - -#define TTY_LOG_DIR "./" - -/* Set early in boot and then unchanged */ -static char *tty_log_dir = TTY_LOG_DIR; -static int tty_log_fd = -1; - -#define TTY_LOG_OPEN 1 -#define TTY_LOG_CLOSE 2 -#define TTY_LOG_WRITE 3 -#define TTY_LOG_EXEC 4 - -#define TTY_READ 1 -#define TTY_WRITE 2 - -struct tty_log_buf { - int what; - unsigned long tty; - int len; - int direction; - unsigned long sec; - unsigned long usec; -}; - -int open_tty_log(void *tty, void *current_tty) -{ - struct timeval tv; - struct tty_log_buf data; - char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")]; - int fd; - - gettimeofday(&tv, NULL); - if(tty_log_fd != -1){ - data = ((struct tty_log_buf) { .what = TTY_LOG_OPEN, - .tty = (unsigned long) tty, - .len = sizeof(current_tty), - .direction = 0, - .sec = tv.tv_sec, - .usec = tv.tv_usec } ); - os_write_file(tty_log_fd, &data, sizeof(data)); - os_write_file(tty_log_fd, ¤t_tty, data.len); - return(tty_log_fd); - } - - sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec, - (unsigned int) tv.tv_usec); - - fd = os_open_file(buf, of_append(of_create(of_rdwr(OPENFLAGS()))), - 0644); - if(fd < 0){ - printk("open_tty_log : couldn't open '%s', errno = %d\n", - buf, -fd); - } - return(fd); -} - -void close_tty_log(int fd, void *tty) -{ - struct tty_log_buf data; - struct timeval tv; - - if(tty_log_fd != -1){ - gettimeofday(&tv, NULL); - data = ((struct tty_log_buf) { .what = TTY_LOG_CLOSE, - .tty = (unsigned long) tty, - .len = 0, - .direction = 0, - .sec = tv.tv_sec, - .usec = tv.tv_usec } ); - os_write_file(tty_log_fd, &data, sizeof(data)); - return; - } - os_close_file(fd); -} - -static int log_chunk(int fd, const char *buf, int len) -{ - int total = 0, try, missed, n; - char chunk[64]; - - while(len > 0){ - try = (len > sizeof(chunk)) ? sizeof(chunk) : len; - missed = copy_from_user_proc(chunk, (char *) buf, try); - try -= missed; - n = os_write_file(fd, chunk, try); - if(n != try) { - if(n < 0) - return(n); - return(-EIO); - } - if(missed != 0) - return(-EFAULT); - - len -= try; - total += try; - buf += try; - } - - return(total); -} - -int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read) -{ - struct timeval tv; - struct tty_log_buf data; - int direction; - - if(fd == tty_log_fd){ - gettimeofday(&tv, NULL); - direction = is_read ? TTY_READ : TTY_WRITE; - data = ((struct tty_log_buf) { .what = TTY_LOG_WRITE, - .tty = (unsigned long) tty, - .len = len, - .direction = direction, - .sec = tv.tv_sec, - .usec = tv.tv_usec } ); - os_write_file(tty_log_fd, &data, sizeof(data)); - } - - return(log_chunk(fd, buf, len)); -} - -void log_exec(char **argv, void *tty) -{ - struct timeval tv; - struct tty_log_buf data; - char **ptr,*arg; - int len; - - if(tty_log_fd == -1) return; - - gettimeofday(&tv, NULL); - - len = 0; - for(ptr = argv; ; ptr++){ - if(copy_from_user_proc(&arg, ptr, sizeof(arg))) - return; - if(arg == NULL) break; - len += strlen_user_proc(arg); - } - - data = ((struct tty_log_buf) { .what = TTY_LOG_EXEC, - .tty = (unsigned long) tty, - .len = len, - .direction = 0, - .sec = tv.tv_sec, - .usec = tv.tv_usec } ); - os_write_file(tty_log_fd, &data, sizeof(data)); - - for(ptr = argv; ; ptr++){ - if(copy_from_user_proc(&arg, ptr, sizeof(arg))) - return; - if(arg == NULL) break; - log_chunk(tty_log_fd, arg, strlen_user_proc(arg)); - } -} - -extern void register_tty_logger(int (*opener)(void *, void *), - int (*writer)(int, const char *, int, - void *, int), - void (*closer)(int, void *)); - -static int register_logger(void) -{ - register_tty_logger(open_tty_log, write_tty_log, close_tty_log); - return(0); -} - -__uml_initcall(register_logger); - -static int __init set_tty_log_dir(char *name, int *add) -{ - tty_log_dir = name; - return 0; -} - -__uml_setup("tty_log_dir=", set_tty_log_dir, -"tty_log_dir=\n" -" This is used to specify the directory where the logs of all pty\n" -" data from this UML machine will be written.\n\n" -); - -static int __init set_tty_log_fd(char *name, int *add) -{ - char *end; - - tty_log_fd = strtoul(name, &end, 0); - if((*end != '\0') || (end == name)){ - printf("set_tty_log_fd - strtoul failed on '%s'\n", name); - tty_log_fd = -1; - } - - *add = 0; - return 0; -} - -__uml_setup("tty_log_fd=", set_tty_log_fd, -"tty_log_fd=\n" -" This is used to specify a preconfigured file descriptor to which all\n" -" tty data will be written. Preconfigure the descriptor with something\n" -" like '10>tty_log tty_log_fd=10'.\n\n" -); - - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index c3d56c2935c..1659386b42b 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile @@ -8,10 +8,12 @@ obj-y = aio.o elf_aux.o file.o helper.o irq.o main.o mem.o process.o sigio.o \ user_syms.o util.o drivers/ sys-$(SUBARCH)/ obj-$(CONFIG_MODE_SKAS) += skas/ +obj-$(CONFIG_TTY_LOG) += tty_log.o +user-objs-$(CONFIG_TTY_LOG) += tty_log.o -USER_OBJS := aio.o elf_aux.o file.o helper.o irq.o main.o mem.o process.o \ - sigio.o signal.o start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o \ - util.o +USER_OBJS := $(user-objs-y) aio.o elf_aux.o file.o helper.o irq.o main.o mem.o \ + process.o sigio.o signal.o start_up.o time.o trap.o tt.o tty.o \ + uaccess.o umid.o util.o elf_aux.o: $(ARCH_DIR)/kernel-offsets.h CFLAGS_elf_aux.o += -I$(objtree)/arch/um diff --git a/arch/um/os-Linux/tty_log.c b/arch/um/os-Linux/tty_log.c new file mode 100644 index 00000000000..c6ba56c1560 --- /dev/null +++ b/arch/um/os-Linux/tty_log.c @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and + * geoffrey hing + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include "init.h" +#include "user.h" +#include "kern_util.h" +#include "os.h" + +#define TTY_LOG_DIR "./" + +/* Set early in boot and then unchanged */ +static char *tty_log_dir = TTY_LOG_DIR; +static int tty_log_fd = -1; + +#define TTY_LOG_OPEN 1 +#define TTY_LOG_CLOSE 2 +#define TTY_LOG_WRITE 3 +#define TTY_LOG_EXEC 4 + +#define TTY_READ 1 +#define TTY_WRITE 2 + +struct tty_log_buf { + int what; + unsigned long tty; + int len; + int direction; + unsigned long sec; + unsigned long usec; +}; + +int open_tty_log(void *tty, void *current_tty) +{ + struct timeval tv; + struct tty_log_buf data; + char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")]; + int fd; + + gettimeofday(&tv, NULL); + if(tty_log_fd != -1){ + data = ((struct tty_log_buf) { .what = TTY_LOG_OPEN, + .tty = (unsigned long) tty, + .len = sizeof(current_tty), + .direction = 0, + .sec = tv.tv_sec, + .usec = tv.tv_usec } ); + os_write_file(tty_log_fd, &data, sizeof(data)); + os_write_file(tty_log_fd, ¤t_tty, data.len); + return(tty_log_fd); + } + + sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec, + (unsigned int) tv.tv_usec); + + fd = os_open_file(buf, of_append(of_create(of_rdwr(OPENFLAGS()))), + 0644); + if(fd < 0){ + printk("open_tty_log : couldn't open '%s', errno = %d\n", + buf, -fd); + } + return(fd); +} + +void close_tty_log(int fd, void *tty) +{ + struct tty_log_buf data; + struct timeval tv; + + if(tty_log_fd != -1){ + gettimeofday(&tv, NULL); + data = ((struct tty_log_buf) { .what = TTY_LOG_CLOSE, + .tty = (unsigned long) tty, + .len = 0, + .direction = 0, + .sec = tv.tv_sec, + .usec = tv.tv_usec } ); + os_write_file(tty_log_fd, &data, sizeof(data)); + return; + } + os_close_file(fd); +} + +static int log_chunk(int fd, const char *buf, int len) +{ + int total = 0, try, missed, n; + char chunk[64]; + + while(len > 0){ + try = (len > sizeof(chunk)) ? sizeof(chunk) : len; + missed = copy_from_user_proc(chunk, (char *) buf, try); + try -= missed; + n = os_write_file(fd, chunk, try); + if(n != try) { + if(n < 0) + return(n); + return(-EIO); + } + if(missed != 0) + return(-EFAULT); + + len -= try; + total += try; + buf += try; + } + + return(total); +} + +int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read) +{ + struct timeval tv; + struct tty_log_buf data; + int direction; + + if(fd == tty_log_fd){ + gettimeofday(&tv, NULL); + direction = is_read ? TTY_READ : TTY_WRITE; + data = ((struct tty_log_buf) { .what = TTY_LOG_WRITE, + .tty = (unsigned long) tty, + .len = len, + .direction = direction, + .sec = tv.tv_sec, + .usec = tv.tv_usec } ); + os_write_file(tty_log_fd, &data, sizeof(data)); + } + + return(log_chunk(fd, buf, len)); +} + +void log_exec(char **argv, void *tty) +{ + struct timeval tv; + struct tty_log_buf data; + char **ptr,*arg; + int len; + + if(tty_log_fd == -1) return; + + gettimeofday(&tv, NULL); + + len = 0; + for(ptr = argv; ; ptr++){ + if(copy_from_user_proc(&arg, ptr, sizeof(arg))) + return; + if(arg == NULL) break; + len += strlen_user_proc(arg); + } + + data = ((struct tty_log_buf) { .what = TTY_LOG_EXEC, + .tty = (unsigned long) tty, + .len = len, + .direction = 0, + .sec = tv.tv_sec, + .usec = tv.tv_usec } ); + os_write_file(tty_log_fd, &data, sizeof(data)); + + for(ptr = argv; ; ptr++){ + if(copy_from_user_proc(&arg, ptr, sizeof(arg))) + return; + if(arg == NULL) break; + log_chunk(tty_log_fd, arg, strlen_user_proc(arg)); + } +} + +extern void register_tty_logger(int (*opener)(void *, void *), + int (*writer)(int, const char *, int, + void *, int), + void (*closer)(int, void *)); + +static int register_logger(void) +{ + register_tty_logger(open_tty_log, write_tty_log, close_tty_log); + return(0); +} + +__uml_initcall(register_logger); + +static int __init set_tty_log_dir(char *name, int *add) +{ + tty_log_dir = name; + return 0; +} + +__uml_setup("tty_log_dir=", set_tty_log_dir, +"tty_log_dir=\n" +" This is used to specify the directory where the logs of all pty\n" +" data from this UML machine will be written.\n\n" +); + +static int __init set_tty_log_fd(char *name, int *add) +{ + char *end; + + tty_log_fd = strtoul(name, &end, 0); + if((*end != '\0') || (end == name)){ + printf("set_tty_log_fd - strtoul failed on '%s'\n", name); + tty_log_fd = -1; + } + + *add = 0; + return 0; +} + +__uml_setup("tty_log_fd=", set_tty_log_fd, +"tty_log_fd=\n" +" This is used to specify a preconfigured file descriptor to which all\n" +" tty data will be written. Preconfigure the descriptor with something\n" +" like '10>tty_log tty_log_fd=10'.\n\n" +); -- cgit v1.2.3 From cf9165a50aa21027d2f0eefc90476ec59ae6d2b8 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 27 Mar 2006 01:14:36 -0800 Subject: [PATCH] uml: oS header cleanups This rearranges the OS declarations by moving some declarations into os.h. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/include/os.h | 14 ++++++++++++++ arch/um/include/skas/mode-skas.h | 1 - arch/um/include/skas/skas.h | 1 - 3 files changed, 14 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/um/include/os.h b/arch/um/include/os.h index 53dee8d3cdc..d3d1bc6074e 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -122,6 +122,7 @@ static inline struct openflags of_cloexec(struct openflags flags) return(flags); } +/* file.c */ extern int os_stat_file(const char *file_name, struct uml_stat *buf); extern int os_stat_fd(const int fd, struct uml_stat *buf); extern int os_access(const char *file, int mode); @@ -157,6 +158,15 @@ extern int os_connect_socket(char *name); extern int os_file_type(char *file); extern int os_file_mode(char *file, struct openflags *mode_out); extern int os_lock_file(int fd, int excl); +extern void os_flush_stdout(void); +extern int os_stat_filesystem(char *path, long *bsize_out, + long long *blocks_out, long long *bfree_out, + long long *bavail_out, long long *files_out, + long long *ffree_out, void *fsid_out, + int fsid_size, long *namelen_out, + long *spare_out); +extern int os_change_dir(char *dir); +extern int os_fchange_dir(int fd); /* start_up.c */ extern void os_early_checks(void); @@ -316,4 +326,8 @@ extern void write_sigio_workaround(void); extern int add_sigio_fd(int fd, int read); extern int ignore_sigio_fd(int fd); +/* skas/trap */ +extern void sig_handler_common_skas(int sig, void *sc_ptr); +extern void user_signal(int sig, union uml_pt_regs *regs, int pid); + #endif diff --git a/arch/um/include/skas/mode-skas.h b/arch/um/include/skas/mode-skas.h index 260065cfeef..8bc6916bbbb 100644 --- a/arch/um/include/skas/mode-skas.h +++ b/arch/um/include/skas/mode-skas.h @@ -13,7 +13,6 @@ extern unsigned long exec_fp_regs[]; extern unsigned long exec_fpx_regs[]; extern int have_fpx_regs; -extern void sig_handler_common_skas(int sig, void *sc_ptr); extern void kill_off_processes_skas(void); #endif diff --git a/arch/um/include/skas/skas.h b/arch/um/include/skas/skas.h index 86357282d68..853b26f148c 100644 --- a/arch/um/include/skas/skas.h +++ b/arch/um/include/skas/skas.h @@ -17,7 +17,6 @@ extern int user_thread(unsigned long stack, int flags); extern void new_thread_proc(void *stack, void (*handler)(int sig)); extern void new_thread_handler(int sig); extern void handle_syscall(union uml_pt_regs *regs); -extern void user_signal(int sig, union uml_pt_regs *regs, int pid); extern int new_mm(unsigned long stack); extern void get_skas_faultinfo(int pid, struct faultinfo * fi); extern long execute_syscall_skas(void *r); -- cgit v1.2.3 From 6c29256c5703ad7c3cf62276dbc38d802a05669e Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 27 Mar 2006 01:14:37 -0800 Subject: [PATCH] uml: allow ubd devices to be shared in a cluster This adds a 'c' option to the ubd switch which turns off host file locking so that the device can be shared, as with a cluster. There's also some whitespace cleanup while I was in this file. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/drivers/ubd_kern.c | 76 ++++++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 33 deletions(-) (limited to 'arch') diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index fa617e0719a..0336575d244 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -71,7 +71,7 @@ struct io_thread_req { int error; }; -extern int open_ubd_file(char *file, struct openflags *openflags, +extern int open_ubd_file(char *file, struct openflags *openflags, int shared, char **backing_file_out, int *bitmap_offset_out, unsigned long *bitmap_len_out, int *data_offset_out, int *create_cow_out); @@ -137,7 +137,7 @@ static int fake_major = MAJOR_NR; static struct gendisk *ubd_gendisk[MAX_DEV]; static struct gendisk *fake_gendisk[MAX_DEV]; - + #ifdef CONFIG_BLK_DEV_UBD_SYNC #define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \ .cl = 1 }) @@ -168,6 +168,7 @@ struct ubd { __u64 size; struct openflags boot_openflags; struct openflags openflags; + int shared; int no_cow; struct cow cow; struct platform_device pdev; @@ -189,6 +190,7 @@ struct ubd { .boot_openflags = OPEN_FLAGS, \ .openflags = OPEN_FLAGS, \ .no_cow = 0, \ + .shared = 0, \ .cow = DEFAULT_COW, \ } @@ -305,7 +307,7 @@ static int ubd_setup_common(char *str, int *index_out) } major = simple_strtoul(str, &end, 0); if((*end != '\0') || (end == str)){ - printk(KERN_ERR + printk(KERN_ERR "ubd_setup : didn't parse major number\n"); return(1); } @@ -316,7 +318,7 @@ static int ubd_setup_common(char *str, int *index_out) printk(KERN_ERR "Can't assign a fake major twice\n"); goto out1; } - + fake_major = major; printk(KERN_INFO "Setting extra ubd major number to %d\n", @@ -351,7 +353,7 @@ static int ubd_setup_common(char *str, int *index_out) if (index_out) *index_out = n; - for (i = 0; i < 4; i++) { + for (i = 0; i < sizeof("rscd="); i++) { switch (*str) { case 'r': flags.w = 0; @@ -362,11 +364,14 @@ static int ubd_setup_common(char *str, int *index_out) case 'd': dev->no_cow = 1; break; + case 'c': + dev->shared = 1; + break; case '=': str++; goto break_loop; default: - printk(KERN_ERR "ubd_setup : Expected '=' or flag letter (r,s or d)\n"); + printk(KERN_ERR "ubd_setup : Expected '=' or flag letter (r, s, c, or d)\n"); goto out; } str++; @@ -515,7 +520,7 @@ static void ubd_handler(void) spin_unlock(&ubd_io_lock); return; } - + ubd_finish(rq, req.error); reactivate_fd(thread_fd, UBD_IRQ); do_ubd_request(ubd_queue); @@ -532,7 +537,7 @@ static int io_pid = -1; void kill_io_thread(void) { - if(io_pid != -1) + if(io_pid != -1) os_kill_process(io_pid, 1); } @@ -567,14 +572,15 @@ static int ubd_open_dev(struct ubd *dev) create_cow = 0; create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL; back_ptr = dev->no_cow ? NULL : &dev->cow.file; - dev->fd = open_ubd_file(dev->file, &dev->openflags, back_ptr, - &dev->cow.bitmap_offset, &dev->cow.bitmap_len, - &dev->cow.data_offset, create_ptr); + dev->fd = open_ubd_file(dev->file, &dev->openflags, dev->shared, + back_ptr, &dev->cow.bitmap_offset, + &dev->cow.bitmap_len, &dev->cow.data_offset, + create_ptr); if((dev->fd == -ENOENT) && create_cow){ - dev->fd = create_cow_file(dev->file, dev->cow.file, + dev->fd = create_cow_file(dev->file, dev->cow.file, dev->openflags, 1 << 9, PAGE_SIZE, - &dev->cow.bitmap_offset, + &dev->cow.bitmap_offset, &dev->cow.bitmap_len, &dev->cow.data_offset); if(dev->fd >= 0){ @@ -598,16 +604,16 @@ static int ubd_open_dev(struct ubd *dev) } flush_tlb_kernel_vm(); - err = read_cow_bitmap(dev->fd, dev->cow.bitmap, - dev->cow.bitmap_offset, + err = read_cow_bitmap(dev->fd, dev->cow.bitmap, + dev->cow.bitmap_offset, dev->cow.bitmap_len); if(err < 0) goto error; flags = dev->openflags; flags.w = 0; - err = open_ubd_file(dev->cow.file, &flags, NULL, NULL, NULL, - NULL, NULL); + err = open_ubd_file(dev->cow.file, &flags, dev->shared, NULL, + NULL, NULL, NULL, NULL); if(err < 0) goto error; dev->cow.fd = err; } @@ -685,11 +691,11 @@ static int ubd_add(int n) dev->size = ROUND_BLOCK(dev->size); err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]); - if(err) + if(err) goto out_close; - + if(fake_major != MAJOR_NR) - ubd_new_disk(fake_major, dev->size, n, + ubd_new_disk(fake_major, dev->size, n, &fake_gendisk[n]); /* perhaps this should also be under the "if (fake_major)" above */ @@ -854,7 +860,7 @@ int ubd_init(void) return -1; } platform_driver_register(&ubd_driver); - for (i = 0; i < MAX_DEV; i++) + for (i = 0; i < MAX_DEV; i++) ubd_add(i); return 0; } @@ -872,16 +878,16 @@ int ubd_driver_init(void){ * enough. So use anyway the io thread. */ } stack = alloc_stack(0, 0); - io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), + io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), &thread_fd); if(io_pid < 0){ - printk(KERN_ERR + printk(KERN_ERR "ubd : Failed to start I/O thread (errno = %d) - " "falling back to synchronous I/O\n", -io_pid); io_pid = -1; return(0); } - err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, + err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, SA_INTERRUPT, "ubd", ubd_dev); if(err != 0) printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err); @@ -978,7 +984,7 @@ static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, if(req->op == UBD_READ) { for(i = 0; i < req->length >> 9; i++){ if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) - ubd_set_bit(i, (unsigned char *) + ubd_set_bit(i, (unsigned char *) &req->sector_mask); } } @@ -999,7 +1005,7 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req) /* This should be impossible now */ if((rq_data_dir(req) == WRITE) && !dev->openflags.w){ - printk("Write attempted on readonly ubd device %s\n", + printk("Write attempted on readonly ubd device %s\n", disk->disk_name); end_request(req, 0); return(1); @@ -1182,7 +1188,7 @@ int read_cow_bitmap(int fd, void *buf, int offset, int len) return(0); } -int open_ubd_file(char *file, struct openflags *openflags, +int open_ubd_file(char *file, struct openflags *openflags, int shared, char **backing_file_out, int *bitmap_offset_out, unsigned long *bitmap_len_out, int *data_offset_out, int *create_cow_out) @@ -1206,10 +1212,14 @@ int open_ubd_file(char *file, struct openflags *openflags, return fd; } - err = os_lock_file(fd, openflags->w); - if(err < 0){ - printk("Failed to lock '%s', err = %d\n", file, -err); - goto out_close; + if(shared) + printk("Not locking \"%s\" on the host\n", file); + else { + err = os_lock_file(fd, openflags->w); + if(err < 0){ + printk("Failed to lock '%s', err = %d\n", file, -err); + goto out_close; + } } /* Succesful return case! */ @@ -1260,7 +1270,7 @@ int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, int err, fd; flags.c = 1; - fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL, NULL); + fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL); if(fd < 0){ err = fd; printk("Open of COW file '%s' failed, errno = %d\n", cow_file, -- cgit v1.2.3 From 98c18238f146a9038098244d60a7d2b1f67ee790 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 27 Mar 2006 01:14:38 -0800 Subject: [PATCH] uml: fix segfault on signal delivery This fixes a process segfault where a signal was being delivered such that a new stack page needed to be allocated to hold the signal frame. This was tripping some logic in the page fault handler which wouldn't allocate the page if the faulting address was more that 32 bytes lower than the current stack pointer. Since a signal frame is greater than 32 bytes, this exercised that case. It's fixed by updating the SP in the pt_regs before starting to copy the signal frame. Since those are the registers that will be copied on to the stack, we have to be careful to put the original SP, not the new one which points to the signal frame, on the stack. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/sys-i386/signal.c | 59 +++++++++++++++++++++++++++++++++------------ arch/um/sys-x86_64/signal.c | 56 ++++++++++++++++++++++++++++++------------ 2 files changed, 85 insertions(+), 30 deletions(-) (limited to 'arch') diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c index 7cd1a82dc8c..33a40f5ef0d 100644 --- a/arch/um/sys-i386/signal.c +++ b/arch/um/sys-i386/signal.c @@ -58,7 +58,7 @@ static int copy_sc_from_user_skas(struct pt_regs *regs, } int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, - struct pt_regs *regs) + struct pt_regs *regs, unsigned long sp) { struct sigcontext sc; unsigned long fpregs[HOST_FP_SIZE]; @@ -72,7 +72,7 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, sc.edi = REGS_EDI(regs->regs.skas.regs); sc.esi = REGS_ESI(regs->regs.skas.regs); sc.ebp = REGS_EBP(regs->regs.skas.regs); - sc.esp = REGS_SP(regs->regs.skas.regs); + sc.esp = sp; sc.ebx = REGS_EBX(regs->regs.skas.regs); sc.edx = REGS_EDX(regs->regs.skas.regs); sc.ecx = REGS_ECX(regs->regs.skas.regs); @@ -132,7 +132,7 @@ int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, } int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, - struct sigcontext *from, int fpsize) + struct sigcontext *from, int fpsize, unsigned long sp) { struct _fpstate *to_fp, *from_fp; int err; @@ -140,11 +140,18 @@ int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, to_fp = (fp ? fp : (struct _fpstate *) (to + 1)); from_fp = from->fpstate; err = copy_to_user(to, from, sizeof(*to)); + + /* The SP in the sigcontext is the updated one for the signal + * delivery. The sp passed in is the original, and this needs + * to be restored, so we stick it in separately. + */ + err |= copy_to_user(&SC_SP(to), sp, sizeof(sp)); + if(from_fp != NULL){ err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); err |= copy_to_user(to_fp, from_fp, fpsize); } - return(err); + return err; } #endif @@ -159,11 +166,11 @@ static int copy_sc_from_user(struct pt_regs *to, void __user *from) } static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, - struct pt_regs *from) + struct pt_regs *from, unsigned long sp) { return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), - sizeof(*fp)), - copy_sc_to_user_skas(to, fp, from))); + sizeof(*fp), sp), + copy_sc_to_user_skas(to, fp, from, sp))); } static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp, @@ -174,7 +181,7 @@ static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp, err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp); err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags); err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size); - err |= copy_sc_to_user(&uc->uc_mcontext, fp, ¤t->thread.regs); + err |= copy_sc_to_user(&uc->uc_mcontext, fp, ¤t->thread.regs, sp); err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set)); return(err); } @@ -207,6 +214,7 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig, { struct sigframe __user *frame; void *restorer; + unsigned long save_sp = PT_REGS_SP(regs); int err = 0; stack_top &= -8UL; @@ -218,9 +226,19 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig, if(ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; + /* Update SP now because the page fault handler refuses to extend + * the stack if the faulting address is too far below the current + * SP, which frame now certainly is. If there's an error, the original + * value is restored on the way out. + * When writing the sigcontext to the stack, we have to write the + * original value, so that's passed to copy_sc_to_user, which does + * the right thing with it. + */ + PT_REGS_SP(regs) = (unsigned long) frame; + err |= __put_user(restorer, &frame->pretcode); err |= __put_user(sig, &frame->sig); - err |= copy_sc_to_user(&frame->sc, NULL, regs); + err |= copy_sc_to_user(&frame->sc, NULL, regs, save_sp); err |= __put_user(mask->sig[0], &frame->sc.oldmask); if (_NSIG_WORDS > 1) err |= __copy_to_user(&frame->extramask, &mask->sig[1], @@ -238,7 +256,7 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig, err |= __put_user(0x80cd, (short __user *)(frame->retcode+6)); if(err) - return(err); + goto err; PT_REGS_SP(regs) = (unsigned long) frame; PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler; @@ -248,7 +266,11 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig, if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) ptrace_notify(SIGTRAP); - return(0); + return 0; + +err: + PT_REGS_SP(regs) = save_sp; + return err; } int setup_signal_stack_si(unsigned long stack_top, int sig, @@ -257,6 +279,7 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, { struct rt_sigframe __user *frame; void *restorer; + unsigned long save_sp = PT_REGS_SP(regs); int err = 0; stack_top &= -8UL; @@ -268,13 +291,16 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, if(ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; + /* See comment above about why this is here */ + PT_REGS_SP(regs) = (unsigned long) frame; + err |= __put_user(restorer, &frame->pretcode); err |= __put_user(sig, &frame->sig); err |= __put_user(&frame->info, &frame->pinfo); err |= __put_user(&frame->uc, &frame->puc); err |= copy_siginfo_to_user(&frame->info, info); err |= copy_ucontext_to_user(&frame->uc, &frame->fpstate, mask, - PT_REGS_SP(regs)); + save_sp); /* * This is movl $,%eax ; int $0x80 @@ -288,9 +314,8 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, err |= __put_user(0x80cd, (short __user *)(frame->retcode+5)); if(err) - return(err); + goto err; - PT_REGS_SP(regs) = (unsigned long) frame; PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler; PT_REGS_EAX(regs) = (unsigned long) sig; PT_REGS_EDX(regs) = (unsigned long) &frame->info; @@ -298,7 +323,11 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) ptrace_notify(SIGTRAP); - return(0); + return 0; + +err: + PT_REGS_SP(regs) = save_sp; + return err; } long sys_sigreturn(struct pt_regs regs) diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c index fe1d065332b..e75c4e1838b 100644 --- a/arch/um/sys-x86_64/signal.c +++ b/arch/um/sys-x86_64/signal.c @@ -55,7 +55,8 @@ static int copy_sc_from_user_skas(struct pt_regs *regs, } int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, - struct pt_regs *regs, unsigned long mask) + struct pt_regs *regs, unsigned long mask, + unsigned long sp) { struct faultinfo * fi = ¤t->thread.arch.faultinfo; int err = 0; @@ -70,7 +71,11 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, err |= PUTREG(regs, RDI, to, rdi); err |= PUTREG(regs, RSI, to, rsi); err |= PUTREG(regs, RBP, to, rbp); - err |= PUTREG(regs, RSP, to, rsp); + /* Must use orignal RSP, which is passed in, rather than what's in + * the pt_regs, because that's already been updated to point at the + * signal frame. + */ + err |= __put_user(sp, &to->rsp); err |= PUTREG(regs, RBX, to, rbx); err |= PUTREG(regs, RDX, to, rdx); err |= PUTREG(regs, RCX, to, rcx); @@ -102,7 +107,7 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, #ifdef CONFIG_MODE_TT int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, - int fpsize) + int fpsize) { struct _fpstate *to_fp, *from_fp; unsigned long sigs; @@ -120,7 +125,7 @@ int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, } int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, - struct sigcontext *from, int fpsize) + struct sigcontext *from, int fpsize, unsigned long sp) { struct _fpstate *to_fp, *from_fp; int err; @@ -128,11 +133,17 @@ int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, to_fp = (fp ? fp : (struct _fpstate *) (to + 1)); from_fp = from->fpstate; err = copy_to_user(to, from, sizeof(*to)); + /* The SP in the sigcontext is the updated one for the signal + * delivery. The sp passed in is the original, and this needs + * to be restored, so we stick it in separately. + */ + err |= copy_to_user(&SC_SP(to), sp, sizeof(sp)); + if(from_fp != NULL){ err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); err |= copy_to_user(to_fp, from_fp, fpsize); } - return(err); + return err; } #endif @@ -148,11 +159,12 @@ static int copy_sc_from_user(struct pt_regs *to, void __user *from) } static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, - struct pt_regs *from, unsigned long mask) + struct pt_regs *from, unsigned long mask, + unsigned long sp) { return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), - sizeof(*fp)), - copy_sc_to_user_skas(to, fp, from, mask))); + sizeof(*fp), sp), + copy_sc_to_user_skas(to, fp, from, mask, sp))); } struct rt_sigframe @@ -170,6 +182,7 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, { struct rt_sigframe __user *frame; struct _fpstate __user *fp = NULL; + unsigned long save_sp = PT_REGS_RSP(regs); int err = 0; struct task_struct *me = current; @@ -193,14 +206,25 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, goto out; } + /* Update SP now because the page fault handler refuses to extend + * the stack if the faulting address is too far below the current + * SP, which frame now certainly is. If there's an error, the original + * value is restored on the way out. + * When writing the sigcontext to the stack, we have to write the + * original value, so that's passed to copy_sc_to_user, which does + * the right thing with it. + */ + PT_REGS_RSP(regs) = (unsigned long) frame; + /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); - err |= __put_user(sas_ss_flags(PT_REGS_SP(regs)), + err |= __put_user(sas_ss_flags(save_sp), &frame->uc.uc_stack.ss_flags); err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); - err |= copy_sc_to_user(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); + err |= copy_sc_to_user(&frame->uc.uc_mcontext, fp, regs, set->sig[0], + save_sp); err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); if (sizeof(*set) == 16) { __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); @@ -217,10 +241,10 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); else /* could use a vstub here */ - goto out; + goto restore_sp; if (err) - goto out; + goto restore_sp; /* Set up registers for signal handler */ { @@ -238,10 +262,12 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, PT_REGS_RSI(regs) = (unsigned long) &frame->info; PT_REGS_RDX(regs) = (unsigned long) &frame->uc; PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler; - - PT_REGS_RSP(regs) = (unsigned long) frame; out: - return(err); + return err; + +restore_sp: + PT_REGS_RSP(regs) = save_sp; + return err; } long sys_rt_sigreturn(struct pt_regs *regs) -- cgit v1.2.3 From 1fbbd6844e6a84e5d166ab475dc298d3b89fa4bf Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 27 Mar 2006 01:14:39 -0800 Subject: [PATCH] uml: prevent umid theft Behavior when booting two UMLs with the same umid was broken. The second one would steal the umid. This fixes that, making the second UML take a random umid instead. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/os-Linux/umid.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'arch') diff --git a/arch/um/os-Linux/umid.c b/arch/um/os-Linux/umid.c index ecf107ae5ac..198e5916328 100644 --- a/arch/um/os-Linux/umid.c +++ b/arch/um/os-Linux/umid.c @@ -143,8 +143,10 @@ static int not_dead_yet(char *dir) goto out_close; } - if((kill(p, 0) == 0) || (errno != ESRCH)) + if((kill(p, 0) == 0) || (errno != ESRCH)){ + printk("umid \"%s\" is already in use by pid %d\n", umid, p); return 1; + } err = actually_do_remove(dir); if(err) @@ -234,33 +236,44 @@ int __init make_umid(void) err = mkdir(tmp, 0777); if(err < 0){ err = -errno; - if(errno != EEXIST) + if(err != -EEXIST) goto err; - if(not_dead_yet(tmp) < 0) + /* 1 -> this umid is already in use + * < 0 -> we couldn't remove the umid directory + * In either case, we can't use this umid, so return -EEXIST. + */ + if(not_dead_yet(tmp) != 0) goto err; err = mkdir(tmp, 0777); } - if(err < 0){ - printk("Failed to create '%s' - err = %d\n", umid, err); - goto err_rmdir; + if(err){ + err = -errno; + printk("Failed to create '%s' - err = %d\n", umid, -errno); + goto err; } umid_setup = 1; create_pid_file(); - return 0; - - err_rmdir: - rmdir(tmp); + err = 0; err: return err; } static int __init make_umid_init(void) { + if(!make_umid()) + return 0; + + /* If initializing with the given umid failed, then try again with + * a random one. + */ + printk("Failed to initialize umid \"%s\", trying with a random umid\n", + umid); + *umid = '\0'; make_umid(); return 0; -- cgit v1.2.3 From 5f4e8fd08f3993bc31a7dd91767fdb4da4fe6278 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 27 Mar 2006 01:14:40 -0800 Subject: [PATCH] uml: fix thread startup race This fixes a race in the starting of write_sigio_thread. Previously, some of the data needed by the thread was initialized after the clone. If the thread ran immediately, it would see the uninitialized data, including an empty pollfds, which would cause it to hang. We move the data initialization to before the clone, and adjust the error paths and cleanup accordingly. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/os-Linux/sigio.c | 55 ++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 28 deletions(-) (limited to 'arch') diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c index 7604c404c4c..9ba94294714 100644 --- a/arch/um/os-Linux/sigio.c +++ b/arch/um/os-Linux/sigio.c @@ -29,8 +29,10 @@ static int write_sigio_pid = -1; * the descriptors closed after it is killed. So, it can't see them change. * On the UML side, they are changed under the sigio_lock. */ -static int write_sigio_fds[2] = { -1, -1 }; -static int sigio_private[2] = { -1, -1 }; +#define SIGIO_FDS_INIT {-1, -1} + +static int write_sigio_fds[2] = SIGIO_FDS_INIT; +static int sigio_private[2] = SIGIO_FDS_INIT; struct pollfds { struct pollfd *poll; @@ -270,49 +272,46 @@ void write_sigio_workaround(void) /* Did we race? Don't try to optimize this, please, it's not so likely * to happen, and no more than once at the boot. */ if(write_sigio_pid != -1) - goto out_unlock; - - write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, - CLONE_FILES | CLONE_VM, &stack, 0); + goto out_free; - if (write_sigio_pid < 0) - goto out_clear; + current_poll = ((struct pollfds) { .poll = p, + .used = 1, + .size = 1 }); if (write_sigio_irq(l_write_sigio_fds[0])) - goto out_kill; + goto out_clear_poll; - /* Success, finally. */ memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds)); memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private)); - current_poll = ((struct pollfds) { .poll = p, - .used = 1, - .size = 1 }); + write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, + CLONE_FILES | CLONE_VM, &stack, 0); - sigio_unlock(); - return; + if (write_sigio_pid < 0) + goto out_clear; - out_kill: - l_write_sigio_pid = write_sigio_pid; - write_sigio_pid = -1; sigio_unlock(); - /* Going to call waitpid, avoid holding the lock. */ - os_kill_process(l_write_sigio_pid, 1); - goto out_free; + return; - out_clear: +out_clear: write_sigio_pid = -1; - out_unlock: - sigio_unlock(); - out_free: + write_sigio_fds[0] = -1; + write_sigio_fds[1] = -1; + sigio_private[0] = -1; + sigio_private[1] = -1; +out_clear_poll: + current_poll = ((struct pollfds) { .poll = NULL, + .size = 0, + .used = 0 }); +out_free: kfree(p); - out_close2: + sigio_unlock(); +out_close2: close(l_sigio_private[0]); close(l_sigio_private[1]); - out_close1: +out_close1: close(l_write_sigio_fds[0]); close(l_write_sigio_fds[1]); - return; } void sigio_cleanup(void) -- cgit v1.2.3 From 1e9f28fa1eb9773bf65bae08288c6a0a38eef4a7 Mon Sep 17 00:00:00 2001 From: "Siddha, Suresh B" Date: Mon, 27 Mar 2006 01:15:22 -0800 Subject: [PATCH] sched: new sched domain for representing multi-core Add a new sched domain for representing multi-core with shared caches between cores. Consider a dual package system, each package containing two cores and with last level cache shared between cores with in a package. If there are two runnable processes, with this appended patch those two processes will be scheduled on different packages. On such systems, with this patch we have observed 8% perf improvement with specJBB(2 warehouse) benchmark and 35% improvement with CFP2000 rate(with 2 users). This new domain will come into play only on multi-core systems with shared caches. On other systems, this sched domain will be removed by domain degeneration code. This new domain can be also used for implementing power savings policy (see OLS 2005 CMP kernel scheduler paper for more details.. I will post another patch for power savings policy soon) Most of the arch/* file changes are for cpu_coregroup_map() implementation. Signed-off-by: Suresh Siddha Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/Kconfig | 9 +++++++++ arch/i386/kernel/cpu/common.c | 10 +++++++--- arch/i386/kernel/cpu/intel_cacheinfo.c | 22 ++++++++++++++++++++-- arch/i386/kernel/smpboot.c | 24 ++++++++++++++++++++++++ arch/x86_64/Kconfig | 9 +++++++++ arch/x86_64/kernel/setup.c | 3 ++- arch/x86_64/kernel/smpboot.c | 24 ++++++++++++++++++++++++ 7 files changed, 95 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index f7db71d0b91..f17bd1d2707 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -231,6 +231,15 @@ config SCHED_SMT cost of slightly increased overhead in some places. If unsure say N here. +config SCHED_MC + bool "Multi-core scheduler support" + depends on SMP + default y + help + Multi-core scheduler support improves the CPU scheduler's decision + making when dealing with multi-core CPU chips at a cost of slightly + increased overhead in some places. If unsure say N here. + source "kernel/Kconfig.preempt" config X86_UP_APIC diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index 7e3d6b6a4e9..a06a49075f1 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -266,7 +266,7 @@ static void __init early_cpu_detect(void) void __cpuinit generic_identify(struct cpuinfo_x86 * c) { u32 tfms, xlvl; - int junk; + int ebx; if (have_cpuid_p()) { /* Get vendor name */ @@ -282,7 +282,7 @@ void __cpuinit generic_identify(struct cpuinfo_x86 * c) /* Intel-defined flags: level 0x00000001 */ if ( c->cpuid_level >= 0x00000001 ) { u32 capability, excap; - cpuid(0x00000001, &tfms, &junk, &excap, &capability); + cpuid(0x00000001, &tfms, &ebx, &excap, &capability); c->x86_capability[0] = capability; c->x86_capability[4] = excap; c->x86 = (tfms >> 8) & 15; @@ -292,6 +292,11 @@ void __cpuinit generic_identify(struct cpuinfo_x86 * c) if (c->x86 >= 0x6) c->x86_model += ((tfms >> 16) & 0xF) << 4; c->x86_mask = tfms & 15; +#ifdef CONFIG_SMP + c->apicid = phys_pkg_id((ebx >> 24) & 0xFF, 0); +#else + c->apicid = (ebx >> 24) & 0xFF; +#endif } else { /* Have CPUID level 0 only - unheard of */ c->x86 = 4; @@ -474,7 +479,6 @@ void __cpuinit detect_ht(struct cpuinfo_x86 *c) cpuid(1, &eax, &ebx, &ecx, &edx); - c->apicid = phys_pkg_id((ebx >> 24) & 0xFF, 0); if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY)) return; diff --git a/arch/i386/kernel/cpu/intel_cacheinfo.c b/arch/i386/kernel/cpu/intel_cacheinfo.c index ce61921369e..7e7fd4e67dd 100644 --- a/arch/i386/kernel/cpu/intel_cacheinfo.c +++ b/arch/i386/kernel/cpu/intel_cacheinfo.c @@ -173,6 +173,10 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c) unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */ unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */ unsigned int new_l2 = 0, new_l3 = 0, i; /* Cache sizes from cpuid(4) */ + unsigned int l2_id = 0, l3_id = 0, num_threads_sharing, index_msb; +#ifdef CONFIG_SMP + unsigned int cpu = (c == &boot_cpu_data) ? 0 : (c - cpu_data); +#endif if (c->cpuid_level > 3) { static int is_initialized; @@ -205,9 +209,15 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c) break; case 2: new_l2 = this_leaf.size/1024; + num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing; + index_msb = get_count_order(num_threads_sharing); + l2_id = c->apicid >> index_msb; break; case 3: new_l3 = this_leaf.size/1024; + num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing; + index_msb = get_count_order(num_threads_sharing); + l3_id = c->apicid >> index_msb; break; default: break; @@ -273,11 +283,19 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c) if (new_l1i) l1i = new_l1i; - if (new_l2) + if (new_l2) { l2 = new_l2; +#ifdef CONFIG_SMP + cpu_llc_id[cpu] = l2_id; +#endif + } - if (new_l3) + if (new_l3) { l3 = new_l3; +#ifdef CONFIG_SMP + cpu_llc_id[cpu] = l3_id; +#endif + } if ( trace ) printk (KERN_INFO "CPU: Trace cache: %dK uops", trace); diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 82371d83bfa..a6969903f2d 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -72,6 +72,9 @@ int phys_proc_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID}; /* Core ID of each logical CPU */ int cpu_core_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID}; +/* Last level cache ID of each logical CPU */ +int cpu_llc_id[NR_CPUS] __cpuinitdata = {[0 ... NR_CPUS-1] = BAD_APICID}; + /* representing HT siblings of each logical CPU */ cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly; EXPORT_SYMBOL(cpu_sibling_map); @@ -440,6 +443,18 @@ static void __devinit smp_callin(void) static int cpucount; +/* maps the cpu to the sched domain representing multi-core */ +cpumask_t cpu_coregroup_map(int cpu) +{ + struct cpuinfo_x86 *c = cpu_data + cpu; + /* + * For perf, we return last level cache shared map. + * TBD: when power saving sched policy is added, we will return + * cpu_core_map when power saving policy is enabled + */ + return c->llc_shared_map; +} + /* representing cpus for which sibling maps can be computed */ static cpumask_t cpu_sibling_setup_map; @@ -459,12 +474,16 @@ set_cpu_sibling_map(int cpu) cpu_set(cpu, cpu_sibling_map[i]); cpu_set(i, cpu_core_map[cpu]); cpu_set(cpu, cpu_core_map[i]); + cpu_set(i, c[cpu].llc_shared_map); + cpu_set(cpu, c[i].llc_shared_map); } } } else { cpu_set(cpu, cpu_sibling_map[cpu]); } + cpu_set(cpu, c[cpu].llc_shared_map); + if (current_cpu_data.x86_max_cores == 1) { cpu_core_map[cpu] = cpu_sibling_map[cpu]; c[cpu].booted_cores = 1; @@ -472,6 +491,11 @@ set_cpu_sibling_map(int cpu) } for_each_cpu_mask(i, cpu_sibling_setup_map) { + if (cpu_llc_id[cpu] != BAD_APICID && + cpu_llc_id[cpu] == cpu_llc_id[i]) { + cpu_set(i, c[cpu].llc_shared_map); + cpu_set(cpu, c[i].llc_shared_map); + } if (phys_proc_id[cpu] == phys_proc_id[i]) { cpu_set(i, cpu_core_map[cpu]); cpu_set(cpu, cpu_core_map[i]); diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index 45efe0ca88f..1cb4aa241c8 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -250,6 +250,15 @@ config SCHED_SMT cost of slightly increased overhead in some places. If unsure say N here. +config SCHED_MC + bool "Multi-core scheduler support" + depends on SMP + default y + help + Multi-core scheduler support improves the CPU scheduler's decision + making when dealing with multi-core CPU chips at a cost of slightly + increased overhead in some places. If unsure say N here. + source "kernel/Kconfig.preempt" config NUMA diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index a57eec8311a..d1f3e9272c0 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -962,7 +962,6 @@ static void __cpuinit detect_ht(struct cpuinfo_x86 *c) cpuid(1, &eax, &ebx, &ecx, &edx); - c->apicid = phys_pkg_id(0); if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY)) return; @@ -1171,6 +1170,8 @@ void __cpuinit identify_cpu(struct cpuinfo_x86 *c) c->x86_capability[2] = cpuid_edx(0x80860001); } + c->apicid = phys_pkg_id(0); + /* * Vendor-specific initialization. In this section we * canonicalize the feature flags, meaning if there are diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index 66e98659d07..ea48fa63807 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -68,6 +68,9 @@ u8 phys_proc_id[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID }; /* core ID of each logical CPU */ u8 cpu_core_id[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID }; +/* Last level cache ID of each logical CPU */ +u8 cpu_llc_id[NR_CPUS] __cpuinitdata = {[0 ... NR_CPUS-1] = BAD_APICID}; + /* Bitmask of currently online CPUs */ cpumask_t cpu_online_map __read_mostly; @@ -445,6 +448,18 @@ void __cpuinit smp_callin(void) cpu_set(cpuid, cpu_callin_map); } +/* maps the cpu to the sched domain representing multi-core */ +cpumask_t cpu_coregroup_map(int cpu) +{ + struct cpuinfo_x86 *c = cpu_data + cpu; + /* + * For perf, we return last level cache shared map. + * TBD: when power saving sched policy is added, we will return + * cpu_core_map when power saving policy is enabled + */ + return c->llc_shared_map; +} + /* representing cpus for which sibling maps can be computed */ static cpumask_t cpu_sibling_setup_map; @@ -463,12 +478,16 @@ static inline void set_cpu_sibling_map(int cpu) cpu_set(cpu, cpu_sibling_map[i]); cpu_set(i, cpu_core_map[cpu]); cpu_set(cpu, cpu_core_map[i]); + cpu_set(i, c[cpu].llc_shared_map); + cpu_set(cpu, c[i].llc_shared_map); } } } else { cpu_set(cpu, cpu_sibling_map[cpu]); } + cpu_set(cpu, c[cpu].llc_shared_map); + if (current_cpu_data.x86_max_cores == 1) { cpu_core_map[cpu] = cpu_sibling_map[cpu]; c[cpu].booted_cores = 1; @@ -476,6 +495,11 @@ static inline void set_cpu_sibling_map(int cpu) } for_each_cpu_mask(i, cpu_sibling_setup_map) { + if (cpu_llc_id[cpu] != BAD_APICID && + cpu_llc_id[cpu] == cpu_llc_id[i]) { + cpu_set(i, c[cpu].llc_shared_map); + cpu_set(cpu, c[i].llc_shared_map); + } if (phys_proc_id[cpu] == phys_proc_id[i]) { cpu_set(i, cpu_core_map[cpu]); cpu_set(cpu, cpu_core_map[i]); -- cgit v1.2.3 From b06be912a3ad68c69dba0ed6e92723140020e392 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Mon, 27 Mar 2006 01:15:24 -0800 Subject: [PATCH] x86: don't use cpuid.2 to determine cache info if cpuid.4 is supported Don't use cpuid.2 to determine cache info if cpuid.4 is supported. The exception is P4 trace cache. We always use cpuid.2 to get trace cache under P4. Signed-off-by: Shaohua Li Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/cpu/intel_cacheinfo.c | 69 ++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 28 deletions(-) (limited to 'arch') diff --git a/arch/i386/kernel/cpu/intel_cacheinfo.c b/arch/i386/kernel/cpu/intel_cacheinfo.c index 7e7fd4e67dd..9df87b03612 100644 --- a/arch/i386/kernel/cpu/intel_cacheinfo.c +++ b/arch/i386/kernel/cpu/intel_cacheinfo.c @@ -225,11 +225,19 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c) } } } - if (c->cpuid_level > 1) { + /* + * Don't use cpuid2 if cpuid4 is supported. For P4, we use cpuid2 for + * trace cache + */ + if ((num_cache_leaves == 0 || c->x86 == 15) && c->cpuid_level > 1) { /* supports eax=2 call */ int i, j, n; int regs[4]; unsigned char *dp = (unsigned char *)regs; + int only_trace = 0; + + if (num_cache_leaves != 0 && c->x86 == 15) + only_trace = 1; /* Number of times to iterate */ n = cpuid_eax(2) & 0xFF; @@ -251,6 +259,8 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c) while (cache_table[k].descriptor != 0) { if (cache_table[k].descriptor == des) { + if (only_trace && cache_table[k].cache_type != LVL_TRACE) + break; switch (cache_table[k].cache_type) { case LVL_1_INST: l1i += cache_table[k].size; @@ -276,43 +286,46 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c) } } } + } - if (new_l1d) - l1d = new_l1d; + if (new_l1d) + l1d = new_l1d; - if (new_l1i) - l1i = new_l1i; + if (new_l1i) + l1i = new_l1i; - if (new_l2) { - l2 = new_l2; + if (new_l2) { + l2 = new_l2; #ifdef CONFIG_SMP - cpu_llc_id[cpu] = l2_id; + cpu_llc_id[cpu] = l2_id; #endif - } + } - if (new_l3) { - l3 = new_l3; + if (new_l3) { + l3 = new_l3; #ifdef CONFIG_SMP - cpu_llc_id[cpu] = l3_id; + cpu_llc_id[cpu] = l3_id; #endif - } - - if ( trace ) - printk (KERN_INFO "CPU: Trace cache: %dK uops", trace); - else if ( l1i ) - printk (KERN_INFO "CPU: L1 I cache: %dK", l1i); - if ( l1d ) - printk(", L1 D cache: %dK\n", l1d); - else - printk("\n"); - if ( l2 ) - printk(KERN_INFO "CPU: L2 cache: %dK\n", l2); - if ( l3 ) - printk(KERN_INFO "CPU: L3 cache: %dK\n", l3); - - c->x86_cache_size = l3 ? l3 : (l2 ? l2 : (l1i+l1d)); } + if (trace) + printk (KERN_INFO "CPU: Trace cache: %dK uops", trace); + else if ( l1i ) + printk (KERN_INFO "CPU: L1 I cache: %dK", l1i); + + if (l1d) + printk(", L1 D cache: %dK\n", l1d); + else + printk("\n"); + + if (l2) + printk(KERN_INFO "CPU: L2 cache: %dK\n", l2); + + if (l3) + printk(KERN_INFO "CPU: L3 cache: %dK\n", l3); + + c->x86_cache_size = l3 ? l3 : (l2 ? l2 : (l1i+l1d)); + return l2; } -- cgit v1.2.3 From dc8ecb43701a78bd3c38e7fed1d1c76840579450 Mon Sep 17 00:00:00 2001 From: KAMEZAWA Hiroyuki Date: Mon, 27 Mar 2006 01:15:34 -0800 Subject: [PATCH] unify pfn_to_page: x86_64 pfn_to_page x86_64 can use generic funcs. For DISCONTIGMEM, CONFIG_OUT_OF_LINE_PFN_TO_PAGE is selected. Signed-off-by: KAMEZAWA Hiroyuki Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/Kconfig | 4 ++++ arch/x86_64/mm/numa.c | 15 --------------- 2 files changed, 4 insertions(+), 15 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index 1cb4aa241c8..4310b4a311a 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -334,6 +334,10 @@ config HAVE_ARCH_EARLY_PFN_TO_NID def_bool y depends on NUMA +config OUT_OF_LINE_PFN_TO_PAGE + def_bool y + depends on DISCONTIGMEM + config NR_CPUS int "Maximum number of CPUs (2-256)" range 2 255 diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c index 63c72641b73..4be82d6e2b4 100644 --- a/arch/x86_64/mm/numa.c +++ b/arch/x86_64/mm/numa.c @@ -377,21 +377,6 @@ EXPORT_SYMBOL(node_data); * Should do that. */ -/* Requires pfn_valid(pfn) to be true */ -struct page *pfn_to_page(unsigned long pfn) -{ - int nid = phys_to_nid(((unsigned long)(pfn)) << PAGE_SHIFT); - return (pfn - node_start_pfn(nid)) + NODE_DATA(nid)->node_mem_map; -} -EXPORT_SYMBOL(pfn_to_page); - -unsigned long page_to_pfn(struct page *page) -{ - return (long)(((page) - page_zone(page)->zone_mem_map) + - page_zone(page)->zone_start_pfn); -} -EXPORT_SYMBOL(page_to_pfn); - int pfn_valid(unsigned long pfn) { unsigned nid; -- cgit v1.2.3 From ec936fc563715a9e2b2e363eb060655b49529325 Mon Sep 17 00:00:00 2001 From: KAMEZAWA Hiroyuki Date: Mon, 27 Mar 2006 01:15:59 -0800 Subject: [PATCH] for_each_online_pgdat: renaming for_each_pgdat Replace for_each_pgdat() with for_each_online_pgdat(). Signed-off-by: KAMEZAWA Hiroyuki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/mm/pgtable.c | 2 +- arch/ia64/mm/discontig.c | 4 ++-- arch/ia64/mm/init.c | 2 +- arch/m32r/mm/init.c | 2 +- arch/powerpc/mm/mem.c | 4 ++-- arch/x86_64/mm/init.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c index 9db3242103b..2889567e21a 100644 --- a/arch/i386/mm/pgtable.c +++ b/arch/i386/mm/pgtable.c @@ -36,7 +36,7 @@ void show_mem(void) printk(KERN_INFO "Mem-info:\n"); show_free_areas(); printk(KERN_INFO "Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); - for_each_pgdat(pgdat) { + for_each_online_pgdat(pgdat) { pgdat_resize_lock(pgdat, &flags); for (i = 0; i < pgdat->node_spanned_pages; ++i) { page = pgdat_page_nr(pgdat, i); diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c index 2f5e44862e9..384f1d7dce9 100644 --- a/arch/ia64/mm/discontig.c +++ b/arch/ia64/mm/discontig.c @@ -386,7 +386,7 @@ static void __init pgdat_insert(pg_data_t *pgdat) { pg_data_t *prev = NULL, *next; - for_each_pgdat(next) + for_each_online_pgdat(next) if (pgdat->node_id < next->node_id) break; else @@ -560,7 +560,7 @@ void show_mem(void) printk("Mem-info:\n"); show_free_areas(); printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); - for_each_pgdat(pgdat) { + for_each_online_pgdat(pgdat) { unsigned long present; unsigned long flags; int shared = 0, cached = 0, reserved = 0; diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index ff4f31fcd33..2ef1151cde9 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -600,7 +600,7 @@ mem_init (void) kclist_add(&kcore_vmem, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START); kclist_add(&kcore_kernel, _stext, _end - _stext); - for_each_pgdat(pgdat) + for_each_online_pgdat(pgdat) if (pgdat->bdata->node_bootmem_map) totalram_pages += free_all_bootmem_node(pgdat); diff --git a/arch/m32r/mm/init.c b/arch/m32r/mm/init.c index c9e7dad860b..2e0fe199ce3 100644 --- a/arch/m32r/mm/init.c +++ b/arch/m32r/mm/init.c @@ -47,7 +47,7 @@ void show_mem(void) printk("Mem-info:\n"); show_free_areas(); printk("Free swap: %6ldkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); - for_each_pgdat(pgdat) { + for_each_online_pgdat(pgdat) { unsigned long flags; pgdat_resize_lock(pgdat, &flags); for (i = 0; i < pgdat->node_spanned_pages; ++i) { diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index badac10d700..5e435a9c343 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -195,7 +195,7 @@ void show_mem(void) printk("Mem-info:\n"); show_free_areas(); printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); - for_each_pgdat(pgdat) { + for_each_online_pgdat(pgdat) { unsigned long flags; pgdat_resize_lock(pgdat, &flags); for (i = 0; i < pgdat->node_spanned_pages; i++) { @@ -351,7 +351,7 @@ void __init mem_init(void) max_mapnr = max_pfn; totalram_pages += free_all_bootmem(); #endif - for_each_pgdat(pgdat) { + for_each_online_pgdat(pgdat) { for (i = 0; i < pgdat->node_spanned_pages; i++) { if (!pfn_valid(pgdat->node_start_pfn + i)) continue; diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c index b0441562544..e5f7f1c3446 100644 --- a/arch/x86_64/mm/init.c +++ b/arch/x86_64/mm/init.c @@ -72,7 +72,7 @@ void show_mem(void) show_free_areas(); printk(KERN_INFO "Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); - for_each_pgdat(pgdat) { + for_each_online_pgdat(pgdat) { for (i = 0; i < pgdat->node_spanned_pages; ++i) { page = pfn_to_page(pgdat->node_start_pfn + i); total++; -- cgit v1.2.3 From 3571761fe49d960bb720c2308ffb9401f0a5e161 Mon Sep 17 00:00:00 2001 From: KAMEZAWA Hiroyuki Date: Mon, 27 Mar 2006 01:16:00 -0800 Subject: [PATCH] for_each_online_pgdat: remove sorting pgdat Because pgdat_list was linked to pgdat_list in *reverse* order, (By default) some of arch has to sort it by themselves. for_each_pgdat has gone..for_each_online_pgdat() uses node_online_map, which doesn't need to be sorted. This patch removes codes for sorting pgdat. Signed-off-by: KAMEZAWA Hiroyuki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/mm/discontig.c | 11 ----------- arch/ia64/mm/discontig.c | 31 ------------------------------- arch/m32r/mm/discontig.c | 6 ------ 3 files changed, 48 deletions(-) (limited to 'arch') diff --git a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c index c4af9638dbf..c3f3ae95e22 100644 --- a/arch/i386/mm/discontig.c +++ b/arch/i386/mm/discontig.c @@ -352,17 +352,6 @@ void __init zone_sizes_init(void) { int nid; - /* - * Insert nodes into pgdat_list backward so they appear in order. - * Clobber node 0's links and NULL out pgdat_list before starting. - */ - pgdat_list = NULL; - for (nid = MAX_NUMNODES - 1; nid >= 0; nid--) { - if (!node_online(nid)) - continue; - NODE_DATA(nid)->pgdat_next = pgdat_list; - pgdat_list = NODE_DATA(nid); - } for_each_online_node(nid) { unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c index 384f1d7dce9..ec9eeb89975 100644 --- a/arch/ia64/mm/discontig.c +++ b/arch/ia64/mm/discontig.c @@ -378,31 +378,6 @@ static void __init *memory_less_node_alloc(int nid, unsigned long pernodesize) return ptr; } -/** - * pgdat_insert - insert the pgdat into global pgdat_list - * @pgdat: the pgdat for a node. - */ -static void __init pgdat_insert(pg_data_t *pgdat) -{ - pg_data_t *prev = NULL, *next; - - for_each_online_pgdat(next) - if (pgdat->node_id < next->node_id) - break; - else - prev = next; - - if (prev) { - prev->pgdat_next = pgdat; - pgdat->pgdat_next = next; - } else { - pgdat->pgdat_next = pgdat_list; - pgdat_list = pgdat; - } - - return; -} - /** * memory_less_nodes - allocate and initialize CPU only nodes pernode * information. @@ -745,11 +720,5 @@ void __init paging_init(void) pfn_offset, zholes_size); } - /* - * Make memory less nodes become a member of the known nodes. - */ - for_each_node_mask(node, memory_less_mask) - pgdat_insert(mem_data[node].pgdat); - zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page)); } diff --git a/arch/m32r/mm/discontig.c b/arch/m32r/mm/discontig.c index 08e72795555..70c8528a0ad 100644 --- a/arch/m32r/mm/discontig.c +++ b/arch/m32r/mm/discontig.c @@ -137,12 +137,6 @@ unsigned long __init zone_sizes_init(void) int nid, i; mem_prof_t *mp; - pgdat_list = NULL; - for (nid = num_online_nodes() - 1 ; nid >= 0 ; nid--) { - NODE_DATA(nid)->pgdat_next = pgdat_list; - pgdat_list = NODE_DATA(nid); - } - for_each_online_node(nid) { mp = &mem_prof[nid]; for (i = 0 ; i < MAX_NR_ZONES ; i++) { -- cgit v1.2.3 From 22a9835c350782a5c3257343713932af3ac92ee0 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Mon, 27 Mar 2006 01:16:04 -0800 Subject: [PATCH] unify PFN_* macros Just about every architecture defines some macros to do operations on pfns. They're all virtually identical. This patch consolidates all of them. One minor glitch is that at least i386 uses them in a very skeletal header file. To keep away from #include dependency hell, I stuck the new definitions in a new, isolated header. Of all of the implementations, sh64 is the only one that varied by a bit. It used some masks to ensure that any sign-extension got ripped away before the arithmetic is done. This has been posted to that sh64 maintainers and the development list. Compiles on x86, x86_64, ia64 and ppc64. Signed-off-by: Dave Hansen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/kernel/setup.c | 9 +-------- arch/alpha/mm/numa.c | 4 +--- arch/arm26/mm/init.c | 7 +------ arch/cris/kernel/setup.c | 5 +---- arch/i386/kernel/setup.c | 1 + arch/i386/mm/discontig.c | 1 + arch/m32r/kernel/setup.c | 1 + arch/m32r/mm/discontig.c | 1 + arch/m32r/mm/init.c | 1 + arch/mips/ite-boards/ivr/init.c | 3 --- arch/mips/ite-boards/qed-4n-s01b/init.c | 3 --- arch/mips/kernel/setup.c | 9 +-------- arch/mips/mips-boards/generic/memory.c | 7 ++----- arch/mips/mips-boards/sim/sim_mem.c | 7 ++----- arch/mips/mm/init.c | 4 +--- arch/mips/sgi-ip27/ip27-memory.c | 3 +-- arch/sh/kernel/setup.c | 5 +---- arch/sh64/kernel/setup.c | 1 + arch/um/kernel/physmem.c | 3 +-- 19 files changed, 19 insertions(+), 56 deletions(-) (limited to 'arch') diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index b4e5f8ff2b2..9402624453c 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -34,6 +34,7 @@ #include #include #include +#include #ifdef CONFIG_MAGIC_SYSRQ #include #include @@ -241,9 +242,6 @@ reserve_std_resources(void) request_resource(io, standard_io_resources+i); } -#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) -#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) -#define PFN_PHYS(x) ((x) << PAGE_SHIFT) #define PFN_MAX PFN_DOWN(0x80000000) #define for_each_mem_cluster(memdesc, cluster, i) \ for ((cluster) = (memdesc)->cluster, (i) = 0; \ @@ -472,11 +470,6 @@ page_is_ram(unsigned long pfn) return 0; } -#undef PFN_UP -#undef PFN_DOWN -#undef PFN_PHYS -#undef PFN_MAX - void __init setup_arch(char **cmdline_p) { diff --git a/arch/alpha/mm/numa.c b/arch/alpha/mm/numa.c index 6d5251254f6..bf6b65c81be 100644 --- a/arch/alpha/mm/numa.c +++ b/arch/alpha/mm/numa.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -27,9 +28,6 @@ bootmem_data_t node_bdata[MAX_NUMNODES]; #define DBGDCONT(args...) #endif -#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) -#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) -#define PFN_PHYS(x) ((x) << PAGE_SHIFT) #define for_each_mem_cluster(memdesc, cluster, i) \ for ((cluster) = (memdesc)->cluster, (i) = 0; \ (i) < (memdesc)->numclusters; (i)++, (cluster)++) diff --git a/arch/arm26/mm/init.c b/arch/arm26/mm/init.c index e3ecaa45374..7da8a520567 100644 --- a/arch/arm26/mm/init.c +++ b/arch/arm26/mm/init.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -101,12 +102,6 @@ struct node_info { int bootmap_pages; }; -#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) -#define PFN_UP(x) (PAGE_ALIGN(x) >> PAGE_SHIFT) -#define PFN_SIZE(x) ((x) >> PAGE_SHIFT) -#define PFN_RANGE(s,e) PFN_SIZE(PAGE_ALIGN((unsigned long)(e)) - \ - (((unsigned long)(s)) & PAGE_MASK)) - /* * FIXME: We really want to avoid allocating the bootmap bitmap * over the top of the initrd. Hopefully, this is located towards diff --git a/arch/cris/kernel/setup.c b/arch/cris/kernel/setup.c index 1ba57efff60..619a6eefd89 100644 --- a/arch/cris/kernel/setup.c +++ b/arch/cris/kernel/setup.c @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -88,10 +89,6 @@ setup_arch(char **cmdline_p) init_mm.end_data = (unsigned long) &_edata; init_mm.brk = (unsigned long) &_end; -#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) -#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) -#define PFN_PHYS(x) ((x) << PAGE_SHIFT) - /* min_low_pfn points to the start of DRAM, start_pfn points * to the first DRAM pages after the kernel, and max_low_pfn * to the end of DRAM. diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 6917daa159a..8c08660b4e5 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -46,6 +46,7 @@ #include #include #include +#include #include