diff options
79 files changed, 1918 insertions, 1164 deletions
diff --git a/arch/arm/mach-s3c2410/cpu.h b/arch/arm/mach-s3c2410/cpu.h index 30594b007a50..39556c4516b5 100644 --- a/arch/arm/mach-s3c2410/cpu.h +++ b/arch/arm/mach-s3c2410/cpu.h @@ -15,9 +15,10 @@ * 04-Jan-2005 BJD New uart initialisation * 10-Jan-2005 BJD Moved generic init here, specific to cpu headers * 14-Jan-2005 BJD Added s3c24xx_init_clocks() call + * 10-Mar-2005 LCVR Changed S3C2410_{VA,SZ} to S3C24XX_{VA,SZ} on IODESC_ENT */ -#define IODESC_ENT(x) { S3C2410_VA_##x, S3C2410_PA_##x, S3C2410_SZ_##x, MT_DEVICE } +#define IODESC_ENT(x) { S3C24XX_VA_##x, S3C2410_PA_##x, S3C24XX_SZ_##x, MT_DEVICE } #ifndef MHZ #define MHZ (1000*1000) diff --git a/arch/arm/mach-s3c2410/devs.c b/arch/arm/mach-s3c2410/devs.c index d6f1fd8f9977..64792f678668 100644 --- a/arch/arm/mach-s3c2410/devs.c +++ b/arch/arm/mach-s3c2410/devs.c @@ -10,6 +10,7 @@ * published by the Free Software Foundation. * * Modifications: + * 10-Mar-2005 LCVR Changed S3C2410_{VA,SZ} to S3C24XX_{VA,SZ} * 10-Feb-2005 BJD Added camera from guillaume.gourat@nexvision.tv * 29-Aug-2004 BJD Added timers 0 through 3 * 29-Aug-2004 BJD Changed index of devices we only have one of to -1 @@ -46,7 +47,7 @@ struct platform_device *s3c24xx_uart_devs[3]; static struct resource s3c_usb_resource[] = { [0] = { .start = S3C2410_PA_USBHOST, - .end = S3C2410_PA_USBHOST + S3C2410_SZ_USBHOST, + .end = S3C2410_PA_USBHOST + S3C24XX_SZ_USBHOST, .flags = IORESOURCE_MEM, }, [1] = { @@ -76,7 +77,7 @@ EXPORT_SYMBOL(s3c_device_usb); static struct resource s3c_lcd_resource[] = { [0] = { .start = S3C2410_PA_LCD, - .end = S3C2410_PA_LCD + S3C2410_SZ_LCD, + .end = S3C2410_PA_LCD + S3C24XX_SZ_LCD, .flags = IORESOURCE_MEM, }, [1] = { @@ -107,7 +108,7 @@ EXPORT_SYMBOL(s3c_device_lcd); static struct resource s3c_nand_resource[] = { [0] = { .start = S3C2410_PA_NAND, - .end = S3C2410_PA_NAND + S3C2410_SZ_NAND, + .end = S3C2410_PA_NAND + S3C24XX_SZ_NAND, .flags = IORESOURCE_MEM, } }; @@ -126,7 +127,7 @@ EXPORT_SYMBOL(s3c_device_nand); static struct resource s3c_usbgadget_resource[] = { [0] = { .start = S3C2410_PA_USBDEV, - .end = S3C2410_PA_USBDEV + S3C2410_SZ_USBDEV, + .end = S3C2410_PA_USBDEV + S3C24XX_SZ_USBDEV, .flags = IORESOURCE_MEM, }, [1] = { @@ -151,7 +152,7 @@ EXPORT_SYMBOL(s3c_device_usbgadget); static struct resource s3c_wdt_resource[] = { [0] = { .start = S3C2410_PA_WATCHDOG, - .end = S3C2410_PA_WATCHDOG + S3C2410_SZ_WATCHDOG, + .end = S3C2410_PA_WATCHDOG + S3C24XX_SZ_WATCHDOG, .flags = IORESOURCE_MEM, }, [1] = { @@ -176,7 +177,7 @@ EXPORT_SYMBOL(s3c_device_wdt); static struct resource s3c_i2c_resource[] = { [0] = { .start = S3C2410_PA_IIC, - .end = S3C2410_PA_IIC + S3C2410_SZ_IIC, + .end = S3C2410_PA_IIC + S3C24XX_SZ_IIC, .flags = IORESOURCE_MEM, }, [1] = { @@ -201,7 +202,7 @@ EXPORT_SYMBOL(s3c_device_i2c); static struct resource s3c_iis_resource[] = { [0] = { .start = S3C2410_PA_IIS, - .end = S3C2410_PA_IIS + S3C2410_SZ_IIS, + .end = S3C2410_PA_IIS + S3C24XX_SZ_IIS, .flags = IORESOURCE_MEM, } }; @@ -255,7 +256,7 @@ EXPORT_SYMBOL(s3c_device_rtc); static struct resource s3c_adc_resource[] = { [0] = { .start = S3C2410_PA_ADC, - .end = S3C2410_PA_ADC + S3C2410_SZ_ADC, + .end = S3C2410_PA_ADC + S3C24XX_SZ_ADC, .flags = IORESOURCE_MEM, }, [1] = { @@ -278,7 +279,7 @@ struct platform_device s3c_device_adc = { static struct resource s3c_sdi_resource[] = { [0] = { .start = S3C2410_PA_SDI, - .end = S3C2410_PA_SDI + S3C2410_SZ_SDI, + .end = S3C2410_PA_SDI + S3C24XX_SZ_SDI, .flags = IORESOURCE_MEM, }, [1] = { diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c index 792481c4dc89..e825cddc0ad6 100644 --- a/arch/arm/mach-s3c2410/mach-bast.c +++ b/arch/arm/mach-s3c2410/mach-bast.c @@ -24,6 +24,7 @@ * 10-Jan-2005 BJD Removed include of s3c2410.h * 14-Jan-2005 BJD Add support for muitlple NAND devices * 03-Mar-2005 BJD Ensured that bast-cpld.h is included + * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA */ #include <linux/kernel.h> @@ -82,8 +83,8 @@ static struct map_desc bast_iodesc[] __initdata = { /* ISA IO areas */ - { S3C2410_VA_ISA_BYTE, PA_CS2(BAST_PA_ISAIO), SZ_16M, MT_DEVICE }, - { S3C2410_VA_ISA_WORD, PA_CS3(BAST_PA_ISAIO), SZ_16M, MT_DEVICE }, + { S3C24XX_VA_ISA_BYTE, PA_CS2(BAST_PA_ISAIO), SZ_16M, MT_DEVICE }, + { S3C24XX_VA_ISA_WORD, PA_CS3(BAST_PA_ISAIO), SZ_16M, MT_DEVICE }, /* we could possibly compress the next set down into a set of smaller tables * pagetables, but that would mean using an L2 section, and it still means @@ -409,7 +410,7 @@ static __init void bast_init_machine(void) MACHINE_START(BAST, "Simtec-BAST") MAINTAINER("Ben Dooks <ben@simtec.co.uk>") - BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART) + BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C24XX_VA_UART) BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100) MAPIO(bast_map_io) INITIRQ(bast_init_irq) diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c index e834c00c3019..b2f11209c5b4 100644 --- a/arch/arm/mach-s3c2410/mach-h1940.c +++ b/arch/arm/mach-s3c2410/mach-h1940.c @@ -23,6 +23,7 @@ * 04-Jan-2005 BJD Updated uart init call * 10-Jan-2005 BJD Removed include of s3c2410.h * 14-Jan-2005 BJD Added clock init + * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA */ #include <linux/kernel.h> @@ -117,7 +118,7 @@ void __init h1940_init_irq(void) MACHINE_START(H1940, "IPAQ-H1940") MAINTAINER("Ben Dooks <ben@fluff.org>") - BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART) + BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C24XX_VA_UART) BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100) MAPIO(h1940_map_io) INITIRQ(h1940_init_irq) diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c index 044c8d9e04a0..a687b7ffb608 100644 --- a/arch/arm/mach-s3c2410/mach-n30.c +++ b/arch/arm/mach-s3c2410/mach-n30.c @@ -11,6 +11,9 @@ * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. + * + * Modifications: + * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA */ #include <linux/kernel.h> @@ -138,7 +141,7 @@ void __init n30_init(void) MACHINE_START(N30, "Acer-N30") MAINTAINER("Christer Weinigel <christer@weinigel.se>, Ben Dooks <ben-linux@fluff.org>") - BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART) + BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C24XX_VA_UART) BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100) .timer = &s3c24xx_timer, diff --git a/arch/arm/mach-s3c2410/mach-rx3715.c b/arch/arm/mach-s3c2410/mach-rx3715.c index cd8d4ff93fbd..2c776fb6956a 100644 --- a/arch/arm/mach-s3c2410/mach-rx3715.c +++ b/arch/arm/mach-s3c2410/mach-rx3715.c @@ -10,10 +10,11 @@ * published by the Free Software Foundation. * * Modifications: - * 16-Sep-2004 BJD Copied from mach-h1940.c - * 25-Oct-2004 BJD Updates for 2.6.10-rc1 - * 10-Jan-2005 BJD Removed include of s3c2410.h s3c2440.h - * 14-Jan-2005 BJD Added new clock init + * 16-Sep-2004 BJD Copied from mach-h1940.c + * 25-Oct-2004 BJD Updates for 2.6.10-rc1 + * 10-Jan-2005 BJD Removed include of s3c2410.h s3c2440.h + * 14-Jan-2005 BJD Added new clock init + * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA */ #include <linux/kernel.h> @@ -48,8 +49,8 @@ static struct map_desc rx3715_iodesc[] __initdata = { /* dump ISA space somewhere unused */ - { S3C2410_VA_ISA_WORD, S3C2410_CS3, SZ_16M, MT_DEVICE }, - { S3C2410_VA_ISA_BYTE, S3C2410_CS3, SZ_16M, MT_DEVICE }, + { S3C24XX_VA_ISA_WORD, S3C2410_CS3, SZ_16M, MT_DEVICE }, + { S3C24XX_VA_ISA_BYTE, S3C2410_CS3, SZ_16M, MT_DEVICE }, }; static struct s3c2410_uartcfg rx3715_uartcfgs[] = { @@ -114,7 +115,7 @@ static void __init rx3715_init_machine(void) MACHINE_START(RX3715, "IPAQ-RX3715") MAINTAINER("Ben Dooks <ben@fluff.org>") - BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART) + BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C24XX_VA_UART) BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100) MAPIO(rx3715_map_io) INITIRQ(rx3715_init_irq) diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c index cd272f79f06e..5d3e915920c5 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2410.c +++ b/arch/arm/mach-s3c2410/mach-smdk2410.c @@ -26,6 +26,9 @@ * @History: * derived from linux/arch/arm/mach-s3c2410/mach-bast.c, written by * Ben Dooks <ben@simtec.co.uk> + * + * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA + * ***********************************************************************/ #include <linux/kernel.h> @@ -110,7 +113,7 @@ void __init smdk2410_init_irq(void) MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch * to SMDK2410 */ MAINTAINER("Jonas Dietsche") - BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART) + BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C24XX_VA_UART) BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100) MAPIO(smdk2410_map_io) INITIRQ(smdk2410_init_irq) diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2410/mach-smdk2440.c index 0d1608f0239b..0122f6a9ca43 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2440.c +++ b/arch/arm/mach-s3c2410/mach-smdk2440.c @@ -12,10 +12,11 @@ * published by the Free Software Foundation. * * Modifications: - * 01-Nov-2004 BJD Initial version - * 12-Nov-2004 BJD Updated for release - * 04-Jan-2005 BJD Fixes for pre-release - * 22-Feb-2005 BJD Updated for 2.6.11-rc5 relesa + * 01-Nov-2004 BJD Initial version + * 12-Nov-2004 BJD Updated for release + * 04-Jan-2005 BJD Fixes for pre-release + * 22-Feb-2005 BJD Updated for 2.6.11-rc5 relesa + * 10-Mar-2005 LCVR Replaced S3C2410_VA by S3C24XX_VA */ #include <linux/kernel.h> @@ -50,8 +51,8 @@ static struct map_desc smdk2440_iodesc[] __initdata = { /* ISA IO Space map (memory space selected by A24) */ - { S3C2410_VA_ISA_WORD, S3C2410_CS2, SZ_16M, MT_DEVICE }, - { S3C2410_VA_ISA_BYTE, S3C2410_CS2, SZ_16M, MT_DEVICE }, + { S3C24XX_VA_ISA_WORD, S3C2410_CS2, SZ_16M, MT_DEVICE }, + { S3C24XX_VA_ISA_BYTE, S3C2410_CS2, SZ_16M, MT_DEVICE }, }; #define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK @@ -123,7 +124,7 @@ void __init smdk2440_machine_init(void) MACHINE_START(S3C2440, "SMDK2440") MAINTAINER("Ben Dooks <ben@fluff.org>") - BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART) + BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C24XX_VA_UART) BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100) .init_irq = s3c24xx_init_irq, diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c index 0949e1910290..8cc7db518ab7 100644 --- a/arch/arm/mach-s3c2410/mach-vr1000.c +++ b/arch/arm/mach-s3c2410/mach-vr1000.c @@ -25,6 +25,7 @@ * 15-Jan-2005 BJD Add serial port device definition * 20-Jan-2005 BJD Use UPF_IOREMAP for ports * 10-Feb-2005 BJD Added power-off capability + * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA */ #include <linux/kernel.h> @@ -77,8 +78,8 @@ static struct map_desc vr1000_iodesc[] __initdata = { /* ISA IO areas */ - { S3C2410_VA_ISA_BYTE, PA_CS2(BAST_PA_ISAIO), SZ_16M, MT_DEVICE }, - { S3C2410_VA_ISA_WORD, PA_CS3(BAST_PA_ISAIO), SZ_16M, MT_DEVICE }, + { S3C24XX_VA_ISA_BYTE, PA_CS2(BAST_PA_ISAIO), SZ_16M, MT_DEVICE }, + { S3C24XX_VA_ISA_WORD, PA_CS3(BAST_PA_ISAIO), SZ_16M, MT_DEVICE }, /* we could possibly compress the next set down into a set of smaller tables * pagetables, but that would mean using an L2 section, and it still means @@ -307,7 +308,7 @@ void __init vr1000_init_irq(void) MACHINE_START(VR1000, "Thorcom-VR1000") MAINTAINER("Ben Dooks <ben@simtec.co.uk>") - BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART) + BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C24XX_VA_UART) BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100) MAPIO(vr1000_map_io) INITIRQ(vr1000_init_irq) diff --git a/arch/arm/mach-s3c2410/pm.c b/arch/arm/mach-s3c2410/pm.c index ea7c25a50c73..c96fd16afb4e 100644 --- a/arch/arm/mach-s3c2410/pm.c +++ b/arch/arm/mach-s3c2410/pm.c @@ -24,6 +24,9 @@ * Parts based on arch/arm/mach-pxa/pm.c * * Thanks to Dimitry Andric for debugging + * + * Modifications: + * 10-Mar-2005 LCVR Changed S3C2410_VA_UART to S3C24XX_VA_UART */ #include <linux/config.h> @@ -144,9 +147,11 @@ static struct sleep_save gpio_save[] = { SAVE_ITEM((va) + S3C2410_UBRDIV) static struct sleep_save uart_save[] = { - SAVE_UART(S3C2410_VA_UART0), - SAVE_UART(S3C2410_VA_UART1), - SAVE_UART(S3C2410_VA_UART2), + SAVE_UART(S3C24XX_VA_UART0), + SAVE_UART(S3C24XX_VA_UART1), +#ifndef CONFIG_CPU_S3C2400 + SAVE_UART(S3C24XX_VA_UART2), +#endif }; /* debug diff --git a/arch/ia64/mm/extable.c b/arch/ia64/mm/extable.c index 8e72e01b424d..6d259e34f359 100644 --- a/arch/ia64/mm/extable.c +++ b/arch/ia64/mm/extable.c @@ -17,10 +17,15 @@ static int cmp_ex(const void *a, const void *b) u64 lip = (u64) &l->addr + l->addr; u64 rip = (u64) &r->addr + r->addr; - return lip - rip; + /* avoid overflow */ + if (lip > rip) + return 1; + if (lip < rip) + return -1; + return 0; } -static void swap_ex(void *a, void *b) +static void swap_ex(void *a, void *b, int size) { struct exception_table_entry *l = a, *r = b, tmp; u64 delta = (u64) r - (u64) l; diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index 3f7c4bbb3f51..2b15c4ce84f0 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig @@ -1,6 +1,6 @@ config AGP tristate "/dev/agpgart (AGP Support)" if !GART_IOMMU - depends on ALPHA || IA64 || PPC32 || X86 + depends on ALPHA || IA64 || PPC || X86 default y if GART_IOMMU ---help--- AGP (Accelerated Graphics Port) is a bus system mainly used to @@ -146,11 +146,11 @@ config AGP_ALPHA_CORE default AGP config AGP_UNINORTH - tristate "Apple UniNorth AGP support" + tristate "Apple UniNorth & U3 AGP support" depends on AGP && PPC_PMAC help This option gives you AGP support for Apple machines with a - UniNorth bridge. + UniNorth or U3 (Apple G5) bridge. config AGP_EFFICEON tristate "Transmeta Efficeon support" diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index ad08df4ae223..ad9c11391d81 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -322,7 +322,7 @@ extern int agp_try_unsupported_boot; #define AGPCTRL_GTLBEN (1<<7) #define AGP2_RESERVED_MASK 0x00fffcc8 -#define AGP3_RESERVED_MASK 0x00ff00cc +#define AGP3_RESERVED_MASK 0x00ff00c4 #define AGP_ERRATA_FASTWRITES 1<<0 #define AGP_ERRATA_SBA 1<<1 diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 6338ebd5642c..05a248d5a9fb 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -515,13 +515,9 @@ static void agp_v3_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_ printk (KERN_INFO PFX "%s tried to set rate=x0. Setting to AGP3 x4 mode.\n", current->comm); *requested_mode |= AGPSTAT3_4X; } - if (tmp == 3) { - printk (KERN_INFO PFX "%s tried to set rate=x3. Setting to AGP3 x4 mode.\n", current->comm); - *requested_mode |= AGPSTAT3_4X; - } - if (tmp >3) { - printk (KERN_INFO PFX "%s tried to set rate=x%d. Setting to AGP3 x8 mode.\n", current->comm, tmp); - *requested_mode |= AGPSTAT3_8X; + if (tmp >= 3) { + printk (KERN_INFO PFX "%s tried to set rate=x%d. Setting to AGP3 x8 mode.\n", current->comm, tmp * 4); + *requested_mode = (*requested_mode & ~7) | AGPSTAT3_8X; } /* ARQSZ - Set the value to the maximum one. @@ -632,26 +628,18 @@ done: u32 agp_collect_device_status(struct agp_bridge_data *bridge, u32 requested_mode, u32 bridge_agpstat) { struct pci_dev *device = NULL; - u8 cap_ptr = 0; u32 vga_agpstat; + u8 cap_ptr; - while (!cap_ptr) { + for (;;) { device = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, device); if (!device) { printk (KERN_INFO PFX "Couldn't find an AGP VGA controller.\n"); return 0; } cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); - if (!cap_ptr) { - pci_dev_put(device); - continue; - } - if ((device->bus->self->vendor != bridge->dev->vendor) && - (device->bus->self->device != bridge->dev->device)) { - pci_dev_put(device); - cap_ptr = 0; - continue; - } + if (cap_ptr) + break; } /* diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index 263e001fa994..0f248239b4ba 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -9,8 +9,23 @@ #include <linux/delay.h> #include <asm/uninorth.h> #include <asm/pci-bridge.h> +#include <asm/prom.h> #include "agp.h" +/* + * NOTES for uninorth3 (G5 AGP) supports : + * + * There maybe also possibility to have bigger cache line size for + * agp (see pmac_pci.c and look for cache line). Need to be investigated + * by someone. + * + * PAGE size are hardcoded but this may change, see asm/page.h. + * + * Jerome Glisse <j.glisse@gmail.com> + */ +static int uninorth_rev; +static int is_u3; + static int uninorth_fetch_size(void) { int i; @@ -40,14 +55,20 @@ static int uninorth_fetch_size(void) static void uninorth_tlbflush(struct agp_memory *mem) { + u32 ctrl = UNI_N_CFG_GART_ENABLE; + + if (is_u3) + ctrl |= U3_N_CFG_GART_PERFRD; pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, - UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_INVAL); - pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, - UNI_N_CFG_GART_ENABLE); - pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, - UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_2xRESET); - pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, - UNI_N_CFG_GART_ENABLE); + ctrl | UNI_N_CFG_GART_INVAL); + pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, ctrl); + + if (uninorth_rev <= 0x30) { + pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, + ctrl | UNI_N_CFG_GART_2xRESET); + pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, + ctrl); + } } static void uninorth_cleanup(void) @@ -57,14 +78,16 @@ static void uninorth_cleanup(void) pci_read_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, &tmp); if (!(tmp & UNI_N_CFG_GART_ENABLE)) return; - pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, - UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_INVAL); - pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, - 0); - pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, - UNI_N_CFG_GART_2xRESET); - pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, - 0); + tmp |= UNI_N_CFG_GART_INVAL; + pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, tmp); + pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, 0); + + if (uninorth_rev <= 0x30) { + pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, + UNI_N_CFG_GART_2xRESET); + pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, + 0); + } } static int uninorth_configure(void) @@ -87,8 +110,21 @@ static int uninorth_configure(void) * the AGP aperture isn't mapped at bus physical address 0 */ agp_bridge->gart_bus_addr = 0; +#ifdef CONFIG_PPC64 + /* Assume U3 or later on PPC64 systems */ + /* high 4 bits of GART physical address go in UNI_N_CFG_AGP_BASE */ + pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_AGP_BASE, + (agp_bridge->gatt_bus_addr >> 32) & 0xf); +#else pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_AGP_BASE, agp_bridge->gart_bus_addr); +#endif + + if (is_u3) { + pci_write_config_dword(agp_bridge->dev, + UNI_N_CFG_GART_DUMMY_PAGE, + agp_bridge->scratch_page_real >> 12); + } return 0; } @@ -111,13 +147,14 @@ static int uninorth_insert_memory(struct agp_memory *mem, off_t pg_start, j = pg_start; while (j < (pg_start + mem->page_count)) { - if (!PGE_EMPTY(agp_bridge, agp_bridge->gatt_table[j])) + if (agp_bridge->gatt_table[j]) return -EBUSY; j++; } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { - agp_bridge->gatt_table[j] = cpu_to_le32((mem->memory[i] & 0xfffff000) | 0x00000001UL); + agp_bridge->gatt_table[j] = + cpu_to_le32((mem->memory[i] & 0xFFFFF000UL) | 0x1UL); flush_dcache_range((unsigned long)__va(mem->memory[i]), (unsigned long)__va(mem->memory[i])+0x1000); } @@ -130,17 +167,90 @@ static int uninorth_insert_memory(struct agp_memory *mem, off_t pg_start, return 0; } +static int u3_insert_memory(struct agp_memory *mem, off_t pg_start, int type) +{ + int i, num_entries; + void *temp; + u32 *gp; + + temp = agp_bridge->current_size; + num_entries = A_SIZE_32(temp)->num_entries; + + if (type != 0 || mem->type != 0) + /* We know nothing of memory types */ + return -EINVAL; + if ((pg_start + mem->page_count) > num_entries) + return -EINVAL; + + gp = (u32 *) &agp_bridge->gatt_table[pg_start]; + for (i = 0; i < mem->page_count; ++i) { + if (gp[i]) { + printk("u3_insert_memory: entry 0x%x occupied (%x)\n", + i, gp[i]); + return -EBUSY; + } + } + + for (i = 0; i < mem->page_count; i++) { + gp[i] = (mem->memory[i] >> PAGE_SHIFT) | 0x80000000UL; + flush_dcache_range((unsigned long)__va(mem->memory[i]), + (unsigned long)__va(mem->memory[i])+0x1000); + } + mb(); + flush_dcache_range((unsigned long)gp, (unsigned long) &gp[i]); + uninorth_tlbflush(mem); + + return 0; +} + +int u3_remove_memory(struct agp_memory *mem, off_t pg_start, int type) +{ + size_t i; + u32 *gp; + + if (type != 0 || mem->type != 0) + /* We know nothing of memory types */ + return -EINVAL; + + gp = (u32 *) &agp_bridge->gatt_table[pg_start]; + for (i = 0; i < mem->page_count; ++i) + gp[i] = 0; + mb(); + flush_dcache_range((unsigned long)gp, (unsigned long) &gp[i]); + uninorth_tlbflush(mem); + + return 0; +} + static void uninorth_agp_enable(struct agp_bridge_data *bridge, u32 mode) { - u32 command, scratch; + u32 command, scratch, status; int timeout; pci_read_config_dword(bridge->dev, bridge->capndx + PCI_AGP_STATUS, - &command); + &status); - command = agp_collect_device_status(bridge, mode, command); - command |= 0x100; + command = agp_collect_device_status(bridge, mode, status); + command |= PCI_AGP_COMMAND_AGP; + + if (uninorth_rev == 0x21) { + /* + * Darwin disable AGP 4x on this revision, thus we + * may assume it's broken. This is an AGP2 controller. + */ + command &= ~AGPSTAT2_4X; + } + + if ((uninorth_rev >= 0x30) && (uninorth_rev <= 0x33)) { + /* + * We need to to set REQ_DEPTH to 7 for U3 versions 1.0, 2.1, + * 2.2 and 2.3, Darwin do so. + */ + if ((command >> AGPSTAT_RQ_DEPTH_SHIFT) > 7) + command = (command & ~AGPSTAT_RQ_DEPTH) + | (7 << AGPSTAT_RQ_DEPTH_SHIFT); + } uninorth_tlbflush(NULL); @@ -152,11 +262,17 @@ static void uninorth_agp_enable(struct agp_bridge_data *bridge, u32 mode) pci_read_config_dword(bridge->dev, bridge->capndx + PCI_AGP_COMMAND, &scratch); - } while ((scratch & 0x100) == 0 && ++timeout < 1000); - if ((scratch & 0x100) == 0) + } while ((scratch & PCI_AGP_COMMAND_AGP) == 0 && ++timeout < 1000); + if ((scratch & PCI_AGP_COMMAND_AGP) == 0) printk(KERN_ERR PFX "failed to write UniNorth AGP command reg\n"); - agp_device_command(command, 0); + if (uninorth_rev >= 0x30) { + /* This is an AGP V3 */ + agp_device_command(command, (status & AGPSTAT_MODE_3_0)); + } else { + /* AGP V2 */ + agp_device_command(command, 0); + } uninorth_tlbflush(NULL); } @@ -229,12 +345,12 @@ static int uninorth_create_gatt_table(struct agp_bridge_data *bridge) struct page *page; /* We can't handle 2 level gatt's */ - if (agp_bridge->driver->size_type == LVL2_APER_SIZE) + if (bridge->driver->size_type == LVL2_APER_SIZE) return -EINVAL; table = NULL; - i = agp_bridge->aperture_size_idx; - temp = agp_bridge->current_size; + i = bridge->aperture_size_idx; + temp = bridge->current_size; size = page_order = num_entries = 0; do { @@ -246,11 +362,11 @@ static int uninorth_create_gatt_table(struct agp_bridge_data *bridge) if (table == NULL) { i++; - agp_bridge->current_size = A_IDX32(agp_bridge); + bridge->current_size = A_IDX32(bridge); } else { - agp_bridge->aperture_size_idx = i; + bridge->aperture_size_idx = i; } - } while (!table && (i < agp_bridge->driver->num_aperture_sizes)); + } while (!table && (i < bridge->driver->num_aperture_sizes)); if (table == NULL) return -ENOMEM; @@ -260,14 +376,12 @@ static int uninorth_create_gatt_table(struct agp_bridge_data *bridge) for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) SetPageReserved(page); - agp_bridge->gatt_table_real = (u32 *) table; - agp_bridge->gatt_table = (u32 *)table; - agp_bridge->gatt_bus_addr = virt_to_phys(table); + bridge->gatt_table_real = (u32 *) table; + bridge->gatt_table = (u32 *)table; + bridge->gatt_bus_addr = virt_to_phys(table); - for (i = 0; i < num_entries; i++) { - agp_bridge->gatt_table[i] = - (unsigned long) agp_bridge->scratch_page; - } + for (i = 0; i < num_entries; i++) + bridge->gatt_table[i] = 0; flush_dcache_range((unsigned long)table, (unsigned long)table_end); @@ -281,7 +395,7 @@ static int uninorth_free_gatt_table(struct agp_bridge_data *bridge) void *temp; struct page *page; - temp = agp_bridge->current_size; + temp = bridge->current_size; page_order = A_SIZE_32(temp)->page_order; /* Do not worry about freeing memory, because if this is @@ -289,13 +403,13 @@ static int uninorth_free_gatt_table(struct agp_bridge_data *bridge) * from the table. */ - table = (char *) agp_bridge->gatt_table_real; + table = (char *) bridge->gatt_table_real; table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) ClearPageReserved(page); - free_pages((unsigned long) agp_bridge->gatt_table_real, page_order); + free_pages((unsigned long) bridge->gatt_table_real, page_order); return 0; } @@ -320,6 +434,22 @@ static struct aper_size_info_32 uninorth_sizes[7] = {4, 1024, 0, 1} }; +/* + * Not sure that u3 supports that high aperture sizes but it + * would strange if it did not :) + */ +static struct aper_size_info_32 u3_sizes[8] = +{ + {512, 131072, 7, 128}, + {256, 65536, 6, 64}, + {128, 32768, 5, 32}, + {64, 16384, 4, 16}, + {32, 8192, 3, 8}, + {16, 4096, 2, 4}, + {8, 2048, 1, 2}, + {4, 1024, 0, 1} +}; + struct agp_bridge_driver uninorth_agp_driver = { .owner = THIS_MODULE, .aperture_sizes = (void *)uninorth_sizes, @@ -344,6 +474,31 @@ struct agp_bridge_driver uninorth_agp_driver = { .cant_use_aperture = 1, }; +struct agp_bridge_driver u3_agp_driver = { + .owner = THIS_MODULE, + .aperture_sizes = (void *)u3_sizes, + .size_type = U32_APER_SIZE, + .num_aperture_sizes = 8, + .configure = uninorth_configure, + .fetch_size = uninorth_fetch_size, + .cleanup = uninorth_cleanup, + .tlb_flush = uninorth_tlbflush, + .mask_memory = agp_generic_mask_memory, + .masks = NULL, + .cache_flush = null_cache_flush, + .agp_enable = uninorth_agp_enable, + .create_gatt_table = uninorth_create_gatt_table, + .free_gatt_table = uninorth_free_gatt_table, + .insert_memory = u3_insert_memory, + .remove_memory = u3_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .cant_use_aperture = 1, + .needs_scratch_page = 1, +}; + static struct agp_device_ids uninorth_agp_device_ids[] __devinitdata = { { .device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP, @@ -361,6 +516,18 @@ static struct agp_device_ids uninorth_agp_device_ids[] __devinitdata = { .device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP2, .chipset_name = "UniNorth 2", }, + { + .device_id = PCI_DEVICE_ID_APPLE_U3_AGP, + .chipset_name = "U3", + }, + { + .device_id = PCI_DEVICE_ID_APPLE_U3L_AGP, + .chipset_name = "U3L", + }, + { + .device_id = PCI_DEVICE_ID_APPLE_U3H_AGP, + .chipset_name = "U3H", + }, }; static int __devinit agp_uninorth_probe(struct pci_dev *pdev, @@ -368,6 +535,7 @@ static int __devinit agp_uninorth_probe(struct pci_dev *pdev, { struct agp_device_ids *devs = uninorth_agp_device_ids; struct agp_bridge_data *bridge; + struct device_node *uninorth_node; u8 cap_ptr; int j; @@ -389,13 +557,36 @@ static int __devinit agp_uninorth_probe(struct pci_dev *pdev, return -ENODEV; found: + /* Set revision to 0 if we could not read it. */ + uninorth_rev = 0; + is_u3 = 0; + /* Locate core99 Uni-N */ + uninorth_node = of_find_node_by_name(NULL, "uni-n"); + /* Locate G5 u3 */ + if (uninorth_node == NULL) { + is_u3 = 1; + uninorth_node = of_find_node_by_name(NULL, "u3"); + } + if (uninorth_node) { + int *revprop = (int *) + get_property(uninorth_node, "device-rev", NULL); + if (revprop != NULL) + uninorth_rev = *revprop & 0x3f; + of_node_put(uninorth_node); + } + bridge = agp_alloc_bridge(); if (!bridge) return -ENOMEM; - bridge->driver = &uninorth_agp_driver; + if (is_u3) + bridge->driver = &u3_agp_driver; + else + bridge->driver = &uninorth_agp_driver; + bridge->dev = pdev; bridge->capndx = cap_ptr; + bridge->flags = AGP_ERRATA_FASTWRITES; /* Fill in the mode register */ pci_read_config_dword(pdev, cap_ptr+PCI_AGP_STATUS, &bridge->mode); diff --git a/drivers/char/s3c2410-rtc.c b/drivers/char/s3c2410-rtc.c index b953eaa20de0..ec666395a26c 100644 --- a/drivers/char/s3c2410-rtc.c +++ b/drivers/char/s3c2410-rtc.c @@ -13,6 +13,7 @@ * 08-Nov-2004 BJD Initial creation * 12-Nov-2004 BJD Added periodic IRQ and PM code * 22-Nov-2004 BJD Sign-test on alarm code to check for <0 + * 10-Mar-2005 LCVR Changed S3C2410_VA_RTC to S3C24XX_VA_RTC */ #include <linux/module.h> @@ -38,8 +39,8 @@ /* need this for the RTC_AF definitions */ #include <linux/mc146818rtc.h> -#undef S3C2410_VA_RTC -#define S3C2410_VA_RTC s3c2410_rtc_base +#undef S3C24XX_VA_RTC +#define S3C24XX_VA_RTC s3c2410_rtc_base static struct resource *s3c2410_rtc_mem; diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index 47480f8c7b42..1add6e29aa3a 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c @@ -26,6 +26,8 @@ * 05-Oct-2004 BJD Added semaphore init to stop crashes on open * Fixed tmr_count / wdt_count confusion * Added configurable debug + * + * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA */ #include <linux/module.h> @@ -48,8 +50,8 @@ #include <asm/arch/map.h> #include <asm/hardware/clock.h> -#undef S3C2410_VA_WATCHDOG -#define S3C2410_VA_WATCHDOG (0) +#undef S3C24XX_VA_WATCHDOG +#define S3C24XX_VA_WATCHDOG (0) #include <asm/arch/regs-watchdog.h> diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index a012c4cd9b76..6269797bd95b 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -29,6 +29,8 @@ * 06-Mar-2005 BJD Add s3c2440 fclk clock source * * 09-Mar-2005 BJD Add s3c2400 support + * + * 10-Mar-2005 LCVR Changed S3C2410_VA_UART to S3C24XX_VA_UART */ /* Note on 2440 fclk clock source handling @@ -1093,7 +1095,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, port->mapbase = res->start; port->membase = (void __iomem *)(res->start - S3C2410_PA_UART); - port->membase += S3C2410_VA_UART; + port->membase += S3C24XX_VA_UART; port->irq = platform_get_irq(platdev, 0); ourport->clk = clk_get(&platdev->dev, "uart"); @@ -1441,9 +1443,9 @@ static int s3c2440_serial_getsource(struct uart_port *port, /* the fun of calculating the uart divisors on * the s3c2440 */ - ucon0 = __raw_readl(S3C2410_VA_UART0 + S3C2410_UCON); - ucon1 = __raw_readl(S3C2410_VA_UART1 + S3C2410_UCON); - ucon2 = __raw_readl(S3C2410_VA_UART2 + S3C2410_UCON); + ucon0 = __raw_readl(S3C24XX_VA_UART0 + S3C2410_UCON); + ucon1 = __raw_readl(S3C24XX_VA_UART1 + S3C2410_UCON); + ucon2 = __raw_readl(S3C24XX_VA_UART2 + S3C2410_UCON); printk("ucons: %08lx, %08lx, %08lx\n", ucon0, ucon1, ucon2); diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 5fc0a3b0f870..8494023e48eb 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -322,14 +322,13 @@ static int nlm_wait_on_grace(wait_queue_head_t *queue) /* * Generic NLM call */ -int +static int nlmclnt_call(struct nlm_rqst *req, u32 proc) { struct nlm_host *host = req->a_host; struct rpc_clnt *clnt; struct nlm_args *argp = &req->a_args; struct nlm_res *resp = &req->a_res; - struct file *filp = argp->lock.fl.fl_file; struct rpc_message msg = { .rpc_argp = argp, .rpc_resp = resp, @@ -339,9 +338,6 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc) dprintk("lockd: call procedure %d on %s\n", (int)proc, host->h_name); - if (filp) - msg.rpc_cred = nfs_file_cred(filp); - do { if (host->h_reclaiming && !argp->reclaim) goto in_grace_period; @@ -428,14 +424,13 @@ nlmsvc_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback) return status; } -int +static int nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback) { struct nlm_host *host = req->a_host; struct rpc_clnt *clnt; struct nlm_args *argp = &req->a_args; struct nlm_res *resp = &req->a_res; - struct file *file = argp->lock.fl.fl_file; struct rpc_message msg = { .rpc_argp = argp, .rpc_resp = resp, @@ -450,11 +445,9 @@ nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback) return -ENOLCK; msg.rpc_proc = &clnt->cl_procinfo[proc]; - /* bootstrap and kick off the async RPC call */ - if (file) - msg.rpc_cred = nfs_file_cred(file); /* Increment host refcount */ nlm_get_host(host); + /* bootstrap and kick off the async RPC call */ status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, callback, req); if (status < 0) nlm_release_host(host); @@ -516,6 +509,24 @@ static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *ho fl->fl_ops = &nlmclnt_lock_ops; } +static void do_vfs_lock(struct file_lock *fl) +{ + int res = 0; + switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) { + case FL_POSIX: + res = posix_lock_file_wait(fl->fl_file, fl); + break; + case FL_FLOCK: + res = flock_lock_file_wait(fl->fl_file, fl); + break; + default: + BUG(); + } + if (res < 0) + printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", + __FUNCTION__); +} + /* * LOCK: Try to create a lock * @@ -564,9 +575,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) fl->fl_u.nfs_fl.state = host->h_state; fl->fl_u.nfs_fl.flags |= NFS_LCK_GRANTED; fl->fl_flags |= FL_SLEEP; - if (posix_lock_file_wait(fl->fl_file, fl) < 0) - printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", - __FUNCTION__); + do_vfs_lock(fl); } status = nlm_stat_to_errno(resp->status); out: @@ -635,7 +644,7 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) nlmclnt_unlock_callback); /* Hrmf... Do the unlock early since locks_remove_posix() * really expects us to free the lock synchronously */ - posix_lock_file(fl->fl_file, fl); + do_vfs_lock(fl); if (status < 0) { nlmclnt_release_lockargs(req); kfree(req); @@ -648,7 +657,7 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) if (status < 0) return status; - posix_lock_file(fl->fl_file, fl); + do_vfs_lock(fl); if (resp->status == NLM_LCK_GRANTED) return 0; diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 54f25ae2ad64..52707c5ad6ea 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -110,7 +110,6 @@ nlm_lookup_host(int server, struct sockaddr_in *sin, host->h_addr.sin_port = 0; /* ouch! */ host->h_version = version; host->h_proto = proto; - host->h_authflavor = RPC_AUTH_UNIX; host->h_rpcclnt = NULL; init_MUTEX(&host->h_sema); host->h_nextrebind = jiffies + NLM_HOST_REBIND; @@ -191,8 +190,9 @@ nlm_bind_host(struct nlm_host *host) xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout); + /* Existing NLM servers accept AUTH_UNIX only */ clnt = rpc_create_client(xprt, host->h_name, &nlm_program, - host->h_version, host->h_authflavor); + host->h_version, RPC_AUTH_UNIX); if (IS_ERR(clnt)) { xprt_destroy(xprt); goto forgetit; diff --git a/fs/locks.c b/fs/locks.c index 80c58d97b84c..1792ce547af7 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1865,8 +1865,13 @@ void locks_remove_flock(struct file *filp) return; if (filp->f_op && filp->f_op->flock) { - struct file_lock fl = { .fl_flags = FL_FLOCK, - .fl_type = F_UNLCK }; + struct file_lock fl = { + .fl_pid = current->tgid, + .fl_file = filp, + .fl_flags = FL_FLOCK, + .fl_type = F_UNLCK, + .fl_end = OFFSET_MAX, + }; filp->f_op->flock(filp, F_SETLKW, &fl); } diff --git a/fs/namei.c b/fs/namei.c index 63e3e6494f8d..ed5f58498300 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -681,7 +681,7 @@ fail: * * We expect 'base' to be positive and a directory. */ -int fastcall link_path_walk(const char * name, struct nameidata *nd) +static fastcall int __link_path_walk(const char * name, struct nameidata *nd) { struct path next; struct inode *inode; @@ -881,6 +881,37 @@ return_err: return err; } +/* + * Wrapper to retry pathname resolution whenever the underlying + * file system returns an ESTALE. + * + * Retry the whole path once, forcing real lookup requests + * instead of relying on the dcache. + */ +int fastcall link_path_walk(const char *name, struct nameidata *nd) +{ + struct nameidata save = *nd; + int result; + + /* make sure the stuff we saved doesn't go away */ + dget(save.dentry); + mntget(save.mnt); + + result = __link_path_walk(name, nd); + if (result == -ESTALE) { + *nd = save; + dget(nd->dentry); + mntget(nd->mnt); + nd->flags |= LOOKUP_REVAL; + result = __link_path_walk(name, nd); + } + + dput(save.dentry); + mntput(save.mnt); + + return result; +} + int fastcall path_walk(const char * name, struct nameidata *nd) { current->total_link_count = 0; diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 1018f1f97c2a..cb094d03287c 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -529,13 +529,24 @@ static inline void nfs_renew_times(struct dentry * dentry) } static inline -int nfs_lookup_verify_inode(struct inode *inode, int isopen) +int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd) { struct nfs_server *server = NFS_SERVER(inode); - if (isopen && !(server->flags & NFS_MOUNT_NOCTO)) - return __nfs_revalidate_inode(server, inode); + if (nd != NULL) { + int ndflags = nd->flags; + /* VFS wants an on-the-wire revalidation */ + if (ndflags & LOOKUP_REVAL) + goto out_force; + /* This is an open(2) */ + if ((ndflags & LOOKUP_OPEN) && + !(ndflags & LOOKUP_CONTINUE) && + !(server->flags & NFS_MOUNT_NOCTO)) + goto out_force; + } return nfs_revalidate_inode(server, inode); +out_force: + return __nfs_revalidate_inode(server, inode); } /* @@ -579,16 +590,12 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) struct nfs_fh fhandle; struct nfs_fattr fattr; unsigned long verifier; - int isopen = 0; parent = dget_parent(dentry); lock_kernel(); dir = parent->d_inode; inode = dentry->d_inode; - if (nd && !(nd->flags & LOOKUP_CONTINUE) && (nd->flags & LOOKUP_OPEN)) - isopen = 1; - if (!inode) { if (nfs_neg_need_reval(dir, dentry, nd)) goto out_bad; @@ -602,11 +609,12 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) } /* Revalidate parent directory attribute cache */ - nfs_revalidate_inode(NFS_SERVER(dir), dir); + if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0) + goto out_zap_parent; /* Force a full look up iff the parent directory has changed */ if (nfs_check_verifier(dir, dentry)) { - if (nfs_lookup_verify_inode(inode, isopen)) + if (nfs_lookup_verify_inode(inode, nd)) goto out_zap_parent; goto out_valid; } @@ -722,7 +730,11 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru lock_kernel(); /* Revalidate parent directory attribute cache */ - nfs_revalidate_inode(NFS_SERVER(dir), dir); + error = nfs_revalidate_inode(NFS_SERVER(dir), dir); + if (error < 0) { + res = ERR_PTR(error); + goto out_unlock; + } /* If we're doing an exclusive create, optimize away the lookup */ if (nfs_is_exclusive_create(dir, nd)) @@ -780,6 +792,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry { struct dentry *res = NULL; struct inode *inode = NULL; + int error; /* Check that we are indeed trying to open this file */ if (!is_atomic_open(dir, nd)) @@ -798,7 +811,11 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry /* Open the file on the server */ lock_kernel(); /* Revalidate parent directory attribute cache */ - nfs_revalidate_inode(NFS_SERVER(dir), dir); + error = nfs_revalidate_inode(NFS_SERVER(dir), dir); + if (error < 0) { + res = ERR_PTR(error); + goto out; + } if (nd->intent.open.flags & O_CREAT) { nfs_begin_data_update(dir); @@ -808,7 +825,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry inode = nfs4_atomic_open(dir, dentry, nd); unlock_kernel(); if (IS_ERR(inode)) { - int error = PTR_ERR(inode); + error = PTR_ERR(inode); switch (error) { /* Make a negative dentry */ case -ENOENT: @@ -938,7 +955,7 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc) /* * Code common to create, mkdir, and mknod. */ -static int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, +int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { struct inode *inode; @@ -959,14 +976,12 @@ static int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, if (error < 0) goto out_err; } - inode = nfs_fhget(dentry->d_sb, fhandle, fattr); - if (inode) { - d_instantiate(dentry, inode); - nfs_renew_times(dentry); - nfs_set_verifier(dentry, nfs_save_change_attribute(dentry->d_parent->d_inode)); - return 0; - } error = -ENOMEM; + inode = nfs_fhget(dentry->d_sb, fhandle, fattr); + if (inode == NULL) + goto out_err; + d_instantiate(dentry, inode); + return 0; out_err: d_drop(dentry); return error; @@ -982,7 +997,6 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { struct iattr attr; - struct inode *inode; int error; int open_flags = 0; @@ -997,18 +1011,17 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, lock_kernel(); nfs_begin_data_update(dir); - inode = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags); + error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags); nfs_end_data_update(dir); - if (!IS_ERR(inode)) { - d_instantiate(dentry, inode); - nfs_renew_times(dentry); - nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); - error = 0; - } else { - error = PTR_ERR(inode); - d_drop(dentry); - } + if (error != 0) + goto out_err; + nfs_renew_times(dentry); + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); + unlock_kernel(); + return 0; +out_err: unlock_kernel(); + d_drop(dentry); return error; } @@ -1019,9 +1032,7 @@ static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) { struct iattr attr; - struct nfs_fattr fattr; - struct nfs_fh fhandle; - int error; + int status; dfprintk(VFS, "NFS: mknod(%s/%ld, %s\n", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); @@ -1034,15 +1045,18 @@ nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) lock_kernel(); nfs_begin_data_update(dir); - error = NFS_PROTO(dir)->mknod(dir, &dentry->d_name, &attr, rdev, - &fhandle, &fattr); + status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev); nfs_end_data_update(dir); - if (!error) - error = nfs_instantiate(dentry, &fhandle, &fattr); - else - d_drop(dentry); + if (status != 0) + goto out_err; + nfs_renew_times(dentry); + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); unlock_kernel(); - return error; + return 0; +out_err: + unlock_kernel(); + d_drop(dentry); + return status; } /* @@ -1051,8 +1065,6 @@ nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { struct iattr attr; - struct nfs_fattr fattr; - struct nfs_fh fhandle; int error; dfprintk(VFS, "NFS: mkdir(%s/%ld, %s\n", dir->i_sb->s_id, @@ -1062,23 +1074,17 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) attr.ia_mode = mode | S_IFDIR; lock_kernel(); -#if 0 - /* - * Always drop the dentry, we can't always depend on - * the fattr returned by the server (AIX seems to be - * broken). We're better off doing another lookup than - * depending on potentially bogus information. - */ - d_drop(dentry); -#endif nfs_begin_data_update(dir); - error = NFS_PROTO(dir)->mkdir(dir, &dentry->d_name, &attr, &fhandle, - &fattr); + error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr); nfs_end_data_update(dir); - if (!error) - error = nfs_instantiate(dentry, &fhandle, &fattr); - else - d_drop(dentry); + if (error != 0) + goto out_err; + nfs_renew_times(dentry); + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); + unlock_kernel(); + return 0; +out_err: + d_drop(dentry); unlock_kernel(); return error; } @@ -1107,7 +1113,7 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry) static unsigned int sillycounter; const int i_inosize = sizeof(dir->i_ino)*2; const int countersize = sizeof(sillycounter)*2; - const int slen = strlen(".nfs") + i_inosize + countersize; + const int slen = sizeof(".nfs") + i_inosize + countersize - 1; char silly[slen+1]; struct qstr qsilly; struct dentry *sdentry; @@ -1498,34 +1504,52 @@ out: int nfs_permission(struct inode *inode, int mask, struct nameidata *nd) { struct rpc_cred *cred; - int res; + int res = 0; if (mask == 0) - return 0; + goto out; + /* Is this sys_access() ? */ + if (nd != NULL && (nd->flags & LOOKUP_ACCESS)) + goto force_lookup; - /* Are we checking permissions on anything other than lookup/execute? */ - if ((mask & MAY_EXEC) == 0) { - /* We only need to check permissions on file open() and access() */ - if (!nd || !(nd->flags & (LOOKUP_OPEN|LOOKUP_ACCESS))) - return 0; - /* NFSv4 has atomic_open... */ - if (NFS_PROTO(inode)->version > 3 && (nd->flags & LOOKUP_OPEN)) - return 0; + switch (inode->i_mode & S_IFMT) { + case S_IFLNK: + goto out; + case S_IFREG: + /* NFSv4 has atomic_open... */ + if (nfs_server_capable(inode, NFS_CAP_ATOMIC_OPEN) + && nd != NULL + && (nd->flags & LOOKUP_OPEN)) + goto out; + break; + case S_IFDIR: + /* + * Optimize away all write operations, since the server + * will check permissions when we perform the op. + */ + if ((mask & MAY_WRITE) && !(mask & MAY_READ)) + goto out; } +force_lookup: lock_kernel(); if (!NFS_PROTO(inode)->access) goto out_notsup; cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); - res = nfs_do_access(inode, cred, mask); - put_rpccred(cred); + if (!IS_ERR(cred)) { + res = nfs_do_access(inode, cred, mask); + put_rpccred(cred); + } else + res = PTR_ERR(cred); unlock_kernel(); +out: return res; out_notsup: - nfs_revalidate_inode(NFS_SERVER(inode), inode); - res = generic_permission(inode, mask, NULL); + res = nfs_revalidate_inode(NFS_SERVER(inode), inode); + if (res == 0) + res = generic_permission(inode, mask, NULL); unlock_kernel(); return res; } diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 57ccbd277fce..bae0528bad8a 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -44,6 +44,8 @@ static ssize_t nfs_file_write(struct kiocb *, const char __user *, size_t, loff_ static int nfs_file_flush(struct file *); static int nfs_fsync(struct file *, struct dentry *dentry, int datasync); static int nfs_check_flags(int flags); +static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl); +static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl); struct file_operations nfs_file_operations = { .llseek = remote_llseek, @@ -57,6 +59,7 @@ struct file_operations nfs_file_operations = { .release = nfs_file_release, .fsync = nfs_fsync, .lock = nfs_lock, + .flock = nfs_flock, .sendfile = nfs_file_sendfile, .check_flags = nfs_check_flags, }; @@ -312,6 +315,25 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) return status; } +static int do_vfs_lock(struct file *file, struct file_lock *fl) +{ + int res = 0; + switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) { + case FL_POSIX: + res = posix_lock_file_wait(file, fl); + break; + case FL_FLOCK: + res = flock_lock_file_wait(file, fl); + break; + default: + BUG(); + } + if (res < 0) + printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", + __FUNCTION__); + return res; +} + static int do_unlk(struct file *filp, int cmd, struct file_lock *fl) { struct inode *inode = filp->f_mapping->host; @@ -338,7 +360,7 @@ static int do_unlk(struct file *filp, int cmd, struct file_lock *fl) if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) status = NFS_PROTO(inode)->lock(filp, cmd, fl); else - status = posix_lock_file_wait(filp, fl); + status = do_vfs_lock(filp, fl); unlock_kernel(); rpc_clnt_sigunmask(NFS_CLIENT(inode), &oldset); return status; @@ -377,9 +399,9 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) * the process exits. */ if (status == -EINTR || status == -ERESTARTSYS) - posix_lock_file_wait(filp, fl); + do_vfs_lock(filp, fl); } else - status = posix_lock_file_wait(filp, fl); + status = do_vfs_lock(filp, fl); unlock_kernel(); if (status < 0) goto out; @@ -401,8 +423,7 @@ out: /* * Lock a (portion of) a file */ -int -nfs_lock(struct file *filp, int cmd, struct file_lock *fl) +static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl) { struct inode * inode = filp->f_mapping->host; @@ -418,6 +439,27 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl) if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) return -ENOLCK; + if (IS_GETLK(cmd)) + return do_getlk(filp, cmd, fl); + if (fl->fl_type == F_UNLCK) + return do_unlk(filp, cmd, fl); + return do_setlk(filp, cmd, fl); +} + +/* + * Lock a (portion of) a file + */ +static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl) +{ + struct inode * inode = filp->f_mapping->host; + + dprintk("NFS: nfs_flock(f=%s/%ld, t=%x, fl=%x)\n", + inode->i_sb->s_id, inode->i_ino, + fl->fl_type, fl->fl_flags); + + if (!inode) + return -EINVAL; + /* * No BSD flocks over NFS allowed. * Note: we could try to fake a POSIX lock request here by @@ -425,11 +467,14 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl) * Not sure whether that would be unique, though, or whether * that would break in other places. */ - if (!fl->fl_owner || !(fl->fl_flags & FL_POSIX)) + if (!(fl->fl_flags & FL_FLOCK)) return -ENOLCK; - if (IS_GETLK(cmd)) - return do_getlk(filp, cmd, fl); + /* We're simulating flock() locks using posix locks on the server */ + fl->fl_owner = (fl_owner_t)filp; + fl->fl_start = 0; + fl->fl_end = OFFSET_MAX; + if (fl->fl_type == F_UNLCK) return do_unlk(filp, cmd, fl); return do_setlk(filp, cmd, fl); diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 5e732f7cd6b5..6345f26e87ee 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -64,6 +64,8 @@ static void nfs_umount_begin(struct super_block *); static int nfs_statfs(struct super_block *, struct kstatfs *); static int nfs_show_options(struct seq_file *, struct vfsmount *); +static struct rpc_program nfs_program; + static struct super_operations nfs_sops = { .alloc_inode = nfs_alloc_inode, .destroy_inode = nfs_destroy_inode, @@ -78,7 +80,7 @@ static struct super_operations nfs_sops = { /* * RPC cruft for NFS */ -struct rpc_stat nfs_rpcstat = { +static struct rpc_stat nfs_rpcstat = { .program = &nfs_program }; static struct rpc_version * nfs_version[] = { @@ -95,7 +97,7 @@ static struct rpc_version * nfs_version[] = { #endif }; -struct rpc_program nfs_program = { +static struct rpc_program nfs_program = { .name = "nfs", .number = NFS_PROGRAM, .nrvers = sizeof(nfs_version) / sizeof(nfs_version[0]), @@ -247,6 +249,7 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor) .fattr = &fattr, }; int no_root_error = 0; + unsigned long max_rpc_payload; /* We probably want something more informative here */ snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev)); @@ -283,6 +286,12 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor) if (fsinfo.wtmax >= 512 && server->wsize > fsinfo.wtmax) server->wsize = nfs_block_size(fsinfo.wtmax, NULL); + max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL); + if (server->rsize > max_rpc_payload) + server->rsize = max_rpc_payload; + if (server->wsize > max_rpc_payload) + server->wsize = max_rpc_payload; + server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; if (server->rpages > NFS_READ_MAXIOV) { server->rpages = NFS_READ_MAXIOV; @@ -317,6 +326,9 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor) if (sb->s_maxbytes > MAX_LFS_FILESIZE) sb->s_maxbytes = MAX_LFS_FILESIZE; + server->client->cl_intr = (server->flags & NFS_MOUNT_INTR) ? 1 : 0; + server->client->cl_softrtry = (server->flags & NFS_MOUNT_SOFT) ? 1 : 0; + /* We're airborne Set socket buffersize */ rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100); return 0; @@ -364,9 +376,8 @@ nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data) goto out_fail; } - clnt->cl_intr = (server->flags & NFS_MOUNT_INTR) ? 1 : 0; - clnt->cl_softrtry = (server->flags & NFS_MOUNT_SOFT) ? 1 : 0; - clnt->cl_droppriv = (server->flags & NFS_MOUNT_BROKEN_SUID) ? 1 : 0; + clnt->cl_intr = 1; + clnt->cl_softrtry = 1; clnt->cl_chatty = 1; return clnt; @@ -538,7 +549,6 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) { NFS_MOUNT_NOCTO, ",nocto", "" }, { NFS_MOUNT_NOAC, ",noac", "" }, { NFS_MOUNT_NONLM, ",nolock", ",lock" }, - { NFS_MOUNT_BROKEN_SUID, ",broken_suid", "" }, { 0, NULL, NULL } }; struct proc_nfs_info *nfs_infop; @@ -792,7 +802,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) * Wait for the inode to get unlocked. * (Used for NFS_INO_LOCKED and NFS_INO_REVALIDATING). */ -int +static int nfs_wait_on_inode(struct inode *inode, int flag) { struct rpc_clnt *clnt = NFS_CLIENT(inode); @@ -856,6 +866,12 @@ struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) void put_nfs_open_context(struct nfs_open_context *ctx) { if (atomic_dec_and_test(&ctx->count)) { + if (!list_empty(&ctx->list)) { + struct inode *inode = ctx->dentry->d_inode; + spin_lock(&inode->i_lock); + list_del(&ctx->list); + spin_unlock(&inode->i_lock); + } if (ctx->state != NULL) nfs4_close_state(ctx->state, ctx->mode); if (ctx->cred != NULL) @@ -904,7 +920,7 @@ void nfs_file_clear_open_context(struct file *filp) if (ctx) { filp->private_data = NULL; spin_lock(&inode->i_lock); - list_del(&ctx->list); + list_move_tail(&ctx->list, &NFS_I(inode)->open_files); spin_unlock(&inode->i_lock); put_nfs_open_context(ctx); } @@ -918,8 +934,9 @@ int nfs_open(struct inode *inode, struct file *filp) struct nfs_open_context *ctx; struct rpc_cred *cred; - if ((cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0)) == NULL) - return -ENOMEM; + cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); + if (IS_ERR(cred)) + return PTR_ERR(cred); ctx = alloc_nfs_open_context(filp->f_dentry, cred); put_rpccred(cred); if (ctx == NULL) @@ -1542,6 +1559,7 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, if (data->wsize != 0) server->wsize = nfs_block_size(data->wsize, NULL); server->flags = data->flags & NFS_MOUNT_FLAGMASK; + server->caps = NFS_CAP_ATOMIC_OPEN; server->acregmin = data->acregmin*HZ; server->acregmax = data->acregmax*HZ; @@ -1609,9 +1627,17 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, err = PTR_ERR(clnt); goto out_fail; } + clnt->cl_intr = 1; + clnt->cl_softrtry = 1; clnt->cl_chatty = 1; clp->cl_rpcclient = clnt; clp->cl_cred = rpcauth_lookupcred(clnt->cl_auth, 0); + if (IS_ERR(clp->cl_cred)) { + up_write(&clp->cl_sem); + err = PTR_ERR(clp->cl_cred); + clp->cl_cred = NULL; + goto out_fail; + } memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr)); nfs_idmap_new(clp); } @@ -1634,8 +1660,6 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, return PTR_ERR(clnt); } - clnt->cl_intr = (server->flags & NFS4_MOUNT_INTR) ? 1 : 0; - clnt->cl_softrtry = (server->flags & NFS4_MOUNT_SOFT) ? 1 : 0; server->client = clnt; if (server->nfs4_state->cl_idmap == NULL) { diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 857e3ea4c40b..9d3ddad96d9e 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c @@ -31,7 +31,7 @@ static struct rpc_clnt * mnt_create(char *, struct sockaddr_in *, int, int); -struct rpc_program mnt_program; +static struct rpc_program mnt_program; struct mnt_fhstatus { unsigned int status; @@ -174,7 +174,7 @@ static struct rpc_version * mnt_version[] = { static struct rpc_stat mnt_stats; -struct rpc_program mnt_program = { +static struct rpc_program mnt_program = { .name = "mount", .number = NFS_MNT_PROGRAM, .nrvers = sizeof(mnt_version)/sizeof(mnt_version[0]), diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 828945d68342..3878494dfc2c 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -295,7 +295,7 @@ static int nfs3_proc_commit(struct nfs_write_data *cdata) * Create a regular file. * For now, we don't implement O_EXCL. */ -static struct inode * +static int nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, int flags) { @@ -342,29 +342,19 @@ again: break; case NFS3_CREATE_UNCHECKED: - goto exit; + goto out; } goto again; } -exit: - dprintk("NFS reply create: %d\n", status); - + if (status == 0) + status = nfs_instantiate(dentry, &fhandle, &fattr); if (status != 0) goto out; - if (fhandle.size == 0 || !(fattr.valid & NFS_ATTR_FATTR)) { - status = nfs3_proc_lookup(dir, &dentry->d_name, &fhandle, &fattr); - if (status != 0) - goto out; - } /* When we created the file with exclusive semantics, make * sure we set the attributes afterwards. */ if (arg.createmode == NFS3_CREATE_EXCLUSIVE) { - struct nfs3_sattrargs arg = { - .fh = &fhandle, - .sattr = sattr, - }; dprintk("NFS call setattr (post-create)\n"); if (!(sattr->ia_valid & ATTR_ATIME_SET)) @@ -375,20 +365,13 @@ exit: /* Note: we could use a guarded setattr here, but I'm * not sure this buys us anything (and I'd have * to revamp the NFSv3 XDR code) */ - fattr.valid = 0; - status = rpc_call(NFS_CLIENT(dir), NFS3PROC_SETATTR, - &arg, &fattr, 0); + status = nfs3_proc_setattr(dentry, &fattr, sattr); + nfs_refresh_inode(dentry->d_inode, &fattr); dprintk("NFS reply setattr (post-create): %d\n", status); } - if (status == 0) { - struct inode *inode; - inode = nfs_fhget(dir->i_sb, &fhandle, &fattr); - if (inode) - return inode; - status = -ENOMEM; - } out: - return ERR_PTR(status); + dprintk("NFS reply create: %d\n", status); + return status; } static int @@ -540,28 +523,30 @@ nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, } static int -nfs3_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr, - struct nfs_fh *fhandle, struct nfs_fattr *fattr) +nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) { - struct nfs_fattr dir_attr; + struct nfs_fh fhandle; + struct nfs_fattr fattr, dir_attr; struct nfs3_mkdirargs arg = { .fh = NFS_FH(dir), - .name = name->name, - .len = name->len, + .name = dentry->d_name.name, + .len = dentry->d_name.len, .sattr = sattr }; struct nfs3_diropres res = { .dir_attr = &dir_attr, - .fh = fhandle, - .fattr = fattr + .fh = &fhandle, + .fattr = &fattr }; int status; - dprintk("NFS call mkdir %s\n", name->name); + dprintk("NFS call mkdir %s\n", dentry->d_name.name); dir_attr.valid = 0; - fattr->valid = 0; + fattr.valid = 0; status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0); nfs_refresh_inode(dir, &dir_attr); + if (status == 0) + status = nfs_instantiate(dentry, &fhandle, &fattr); dprintk("NFS reply mkdir: %d\n", status); return status; } @@ -639,23 +624,24 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, } static int -nfs3_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr, - dev_t rdev, struct nfs_fh *fh, struct nfs_fattr *fattr) +nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, + dev_t rdev) { - struct nfs_fattr dir_attr; + struct nfs_fh fh; + struct nfs_fattr fattr, dir_attr; struct nfs3_mknodargs arg = { .fh = NFS_FH(dir), - .name = name->name, - .len = name->len, + .name = dentry->d_name.name, + .len = dentry->d_name.len, .sattr = sattr, .rdev = rdev }; struct nfs3_diropres res = { .dir_attr = &dir_attr, - .fh = fh, - .fattr = fattr + .fh = &fh, + .fattr = &fattr }; - int status; + int status; switch (sattr->ia_mode & S_IFMT) { case S_IFBLK: arg.type = NF3BLK; break; @@ -665,12 +651,14 @@ nfs3_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr, default: return -EINVAL; } - dprintk("NFS call mknod %s %u:%u\n", name->name, + dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name, MAJOR(rdev), MINOR(rdev)); dir_attr.valid = 0; - fattr->valid = 0; + fattr.valid = 0; status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0); nfs_refresh_inode(dir, &dir_attr); + if (status == 0) + status = nfs_instantiate(dentry, &fh, &fattr); dprintk("NFS reply mknod: %d\n", status); return status; } diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 7d56ca4d63b7..1d5cb3e80c3e 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -37,6 +37,7 @@ #include <linux/mm.h> #include <linux/utsname.h> +#include <linux/delay.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/sunrpc/clnt.h> @@ -57,16 +58,17 @@ static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); static int nfs4_async_handle_error(struct rpc_task *, struct nfs_server *); static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); +static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception); extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); extern struct rpc_procinfo nfs4_procedures[]; extern nfs4_stateid zero_stateid; /* Prevent leaks of NFSv4 errors into userland */ -static inline int nfs4_map_errors(int err) +int nfs4_map_errors(int err) { if (err < -1000) { - printk(KERN_WARNING "%s could not handle NFSv4 error %d\n", + dprintk("%s could not handle NFSv4 error %d\n", __FUNCTION__, -err); return -EIO; } @@ -188,6 +190,23 @@ static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinf nfsi->change_attr = cinfo->after; } +static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) +{ + struct inode *inode = state->inode; + + open_flags &= (FMODE_READ|FMODE_WRITE); + /* Protect against nfs4_find_state() */ + spin_lock(&inode->i_lock); + state->state |= open_flags; + /* NB! List reordering - see the reclaim code for why. */ + if ((open_flags & FMODE_WRITE) && 0 == state->nwriters++) + list_move(&state->open_states, &state->owner->so_states); + if (open_flags & FMODE_READ) + state->nreaders++; + memcpy(&state->stateid, stateid, sizeof(state->stateid)); + spin_unlock(&inode->i_lock); +} + /* * OPEN_RECLAIM: * reclaim state on the server after a reboot. @@ -244,7 +263,7 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st return status; } -int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state) +static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state) { struct nfs_server *server = NFS_SERVER(state->inode); struct nfs4_exception exception = { }; @@ -332,7 +351,7 @@ int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) return err; } -static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid) +static inline int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid) { struct nfs_open_confirmargs arg = { .fh = fh, @@ -355,11 +374,49 @@ static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *f return status; } -static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int mask) +static int _nfs4_proc_open(struct inode *dir, struct nfs4_state_owner *sp, struct nfs_openargs *o_arg, struct nfs_openres *o_res) +{ + struct nfs_server *server = NFS_SERVER(dir); + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN], + .rpc_argp = o_arg, + .rpc_resp = o_res, + .rpc_cred = sp->so_cred, + }; + int status; + + /* Update sequence id. The caller must serialize! */ + o_arg->seqid = sp->so_seqid; + o_arg->id = sp->so_id; + o_arg->clientid = sp->so_client->cl_clientid; + + status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); + nfs4_increment_seqid(status, sp); + if (status != 0) + goto out; + update_changeattr(dir, &o_res->cinfo); + if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { + status = _nfs4_proc_open_confirm(server->client, &o_res->fh, + sp, &o_res->stateid); + if (status != 0) + goto out; + } + if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) + status = server->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); +out: + return status; +} + +static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags) { struct nfs_access_entry cache; + int mask = 0; int status; + if (openflags & FMODE_READ) + mask |= MAY_READ; + if (openflags & FMODE_WRITE) + mask |= MAY_WRITE; status = nfs_access_get_cached(inode, cred, &cache); if (status == 0) goto out; @@ -379,9 +436,103 @@ out: } /* + * OPEN_EXPIRED: + * reclaim state on the server after a network partition. + * Assumes caller holds the appropriate lock + */ +static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) +{ + struct dentry *parent = dget_parent(dentry); + struct inode *dir = parent->d_inode; + struct inode *inode = state->inode; + struct nfs_server *server = NFS_SERVER(dir); + struct nfs_delegation *delegation = NFS_I(inode)->delegation; + struct nfs_fattr f_attr = { + .valid = 0, + }; + struct nfs_openargs o_arg = { + .fh = NFS_FH(dir), + .open_flags = state->state, + .name = &dentry->d_name, + .bitmask = server->attr_bitmask, + .claim = NFS4_OPEN_CLAIM_NULL, + }; + struct nfs_openres o_res = { + .f_attr = &f_attr, + .server = server, + }; + int status = 0; + + if (delegation != NULL && !(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) { + status = _nfs4_do_access(inode, sp->so_cred, state->state); + if (status < 0) + goto out; + memcpy(&state->stateid, &delegation->stateid, sizeof(state->stateid)); + set_bit(NFS_DELEGATED_STATE, &state->flags); + goto out; + } + status = _nfs4_proc_open(dir, sp, &o_arg, &o_res); + if (status != 0) + goto out_nodeleg; + /* Check if files differ */ + if ((f_attr.mode & S_IFMT) != (inode->i_mode & S_IFMT)) + goto out_stale; + /* Has the file handle changed? */ + if (nfs_compare_fh(&o_res.fh, NFS_FH(inode)) != 0) { + /* Verify if the change attributes are the same */ + if (f_attr.change_attr != NFS_I(inode)->change_attr) + goto out_stale; + if (nfs_size_to_loff_t(f_attr.size) != inode->i_size) + goto out_stale; + /* Lets just pretend that this is the same file */ + nfs_copy_fh(NFS_FH(inode), &o_res.fh); + NFS_I(inode)->fileid = f_attr.fileid; + } + memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid)); + if (o_res.delegation_type != 0) { + if (!(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) + nfs_inode_set_delegation(inode, sp->so_cred, &o_res); + else + nfs_inode_reclaim_delegation(inode, sp->so_cred, &o_res); + } +out_nodeleg: + clear_bit(NFS_DELEGATED_STATE, &state->flags); +out: + dput(parent); + return status; +out_stale: + status = -ESTALE; + /* Invalidate the state owner so we don't ever use it again */ + nfs4_drop_state_owner(sp); + d_drop(dentry); + /* Should we be trying to close that stateid? */ + goto out_nodeleg; +} + +static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) +{ + struct nfs_inode *nfsi = NFS_I(state->inode); + struct nfs_open_context *ctx; + int status; + + spin_lock(&state->inode->i_lock); + list_for_each_entry(ctx, &nfsi->open_files, list) { + if (ctx->state != state) + continue; + get_nfs_open_context(ctx); + spin_unlock(&state->inode->i_lock); + status = _nfs4_open_expired(sp, state, ctx->dentry); + put_nfs_open_context(ctx); + return status; + } + spin_unlock(&state->inode->i_lock); + return -ENOENT; +} + +/* * Returns an nfs4_state + an extra reference to the inode */ -int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred, struct nfs4_state **res) +static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred, struct nfs4_state **res) { struct nfs_delegation *delegation; struct nfs_server *server = NFS_SERVER(inode); @@ -390,7 +541,6 @@ int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred, struct nfs4_state_owner *sp = NULL; struct nfs4_state *state = NULL; int open_flags = flags & (FMODE_READ|FMODE_WRITE); - int mask = 0; int err; /* Protect against reboot recovery - NOTE ORDER! */ @@ -424,20 +574,12 @@ int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred, goto out_err; lock_kernel(); - err = _nfs4_do_access(inode, cred, mask); + err = _nfs4_do_access(inode, cred, open_flags); unlock_kernel(); if (err != 0) goto out_err; - spin_lock(&inode->i_lock); - memcpy(state->stateid.data, delegation->stateid.data, - sizeof(state->stateid.data)); - state->state |= open_flags; - if (open_flags & FMODE_READ) - state->nreaders++; - if (open_flags & FMODE_WRITE) - state->nwriters++; set_bit(NFS_DELEGATED_STATE, &state->flags); - spin_unlock(&inode->i_lock); + update_open_stateid(state, &delegation->stateid, open_flags); out_ok: up(&sp->so_sema); nfs4_put_state_owner(sp); @@ -500,12 +642,6 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st .f_attr = &f_attr, .server = server, }; - struct rpc_message msg = { - .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN], - .rpc_argp = &o_arg, - .rpc_resp = &o_res, - .rpc_cred = cred, - }; /* Protect against reboot recovery conflicts */ down_read(&clp->cl_sem); @@ -522,26 +658,10 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st o_arg.u.attrs = sattr; /* Serialization for the sequence id */ down(&sp->so_sema); - o_arg.seqid = sp->so_seqid; - o_arg.id = sp->so_id; - o_arg.clientid = clp->cl_clientid, - status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); - nfs4_increment_seqid(status, sp); - if (status) + status = _nfs4_proc_open(dir, sp, &o_arg, &o_res); + if (status != 0) goto out_err; - update_changeattr(dir, &o_res.cinfo); - if(o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) { - status = _nfs4_proc_open_confirm(server->client, &o_res.fh, - sp, &o_res.stateid); - if (status != 0) - goto out_err; - } - if (!(f_attr.valid & NFS_ATTR_FATTR)) { - status = server->rpc_ops->getattr(server, &o_res.fh, &f_attr); - if (status < 0) - goto out_err; - } status = -ENOMEM; inode = nfs_fhget(dir->i_sb, &o_res.fh, &f_attr); @@ -550,14 +670,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st state = nfs4_get_open_state(inode, sp); if (!state) goto out_err; - memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid)); - spin_lock(&inode->i_lock); - if (flags & FMODE_READ) - state->nreaders++; - if (flags & FMODE_WRITE) - state->nwriters++; - state->state |= flags & (FMODE_READ|FMODE_WRITE); - spin_unlock(&inode->i_lock); + update_open_stateid(state, &o_res.stateid, flags); if (o_res.delegation_type != 0) nfs_inode_set_delegation(inode, cred, &o_res); up(&sp->so_sema); @@ -581,7 +694,7 @@ out_err: } -struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred) +static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred) { struct nfs4_exception exception = { }; struct nfs4_state *res; @@ -645,7 +758,7 @@ static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, return rpc_call_sync(server->client, &msg, 0); } -int nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, +static int nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, struct nfs_fh *fhandle, struct iattr *sattr, struct nfs4_state *state) { @@ -680,7 +793,6 @@ static void nfs4_close_done(struct rpc_task *task) nfs4_increment_seqid(task->tk_status, sp); switch (task->tk_status) { case 0: - state->state = calldata->arg.open_flags; memcpy(&state->stateid, &calldata->res.stateid, sizeof(state->stateid)); break; @@ -695,6 +807,7 @@ static void nfs4_close_done(struct rpc_task *task) return; } } + state->state = calldata->arg.open_flags; nfs4_put_open_state(state); up(&sp->so_sema); nfs4_put_state_owner(sp); @@ -774,6 +887,8 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) } cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); + if (IS_ERR(cred)) + return (struct inode *)cred; state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred); put_rpccred(cred); if (IS_ERR(state)) @@ -789,6 +904,8 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags) struct inode *inode; cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); + if (IS_ERR(cred)) + return PTR_ERR(cred); state = nfs4_open_delegated(dentry->d_inode, openflags, cred); if (IS_ERR(state)) state = nfs4_do_open(dir, dentry, openflags, NULL, cred); @@ -1009,6 +1126,8 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, if (size_change) { struct rpc_cred *cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); + if (IS_ERR(cred)) + return PTR_ERR(cred); state = nfs4_find_state(inode, cred, FMODE_WRITE); if (state == NULL) { state = nfs4_open_delegated(dentry->d_inode, @@ -1315,33 +1434,37 @@ static int nfs4_proc_commit(struct nfs_write_data *cdata) * opens the file O_RDONLY. This will all be resolved with the VFS changes. */ -static struct inode * +static int nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, int flags) { - struct inode *inode; - struct nfs4_state *state = NULL; + struct nfs4_state *state; struct rpc_cred *cred; + int status = 0; cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); + if (IS_ERR(cred)) { + status = PTR_ERR(cred); + goto out; + } state = nfs4_do_open(dir, dentry, flags, sattr, cred); put_rpccred(cred); - if (!IS_ERR(state)) { - inode = state->inode; - if (flags & O_EXCL) { - struct nfs_fattr fattr; - int status; - status = nfs4_do_setattr(NFS_SERVER(dir), &fattr, - NFS_FH(inode), sattr, state); - if (status != 0) { - nfs4_close_state(state, flags); - iput(inode); - inode = ERR_PTR(status); - } - } - } else - inode = (struct inode *)state; - return inode; + if (IS_ERR(state)) { + status = PTR_ERR(state); + goto out; + } + d_instantiate(dentry, state->inode); + if (flags & O_EXCL) { + struct nfs_fattr fattr; + status = nfs4_do_setattr(NFS_SERVER(dir), &fattr, + NFS_FH(state->inode), sattr, state); + if (status == 0) + goto out; + } else if (flags != 0) + goto out; + nfs4_close_state(state, flags); +out: + return status; } static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) @@ -1539,23 +1662,24 @@ static int nfs4_proc_symlink(struct inode *dir, struct qstr *name, return err; } -static int _nfs4_proc_mkdir(struct inode *dir, struct qstr *name, - struct iattr *sattr, struct nfs_fh *fhandle, - struct nfs_fattr *fattr) +static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, + struct iattr *sattr) { struct nfs_server *server = NFS_SERVER(dir); + struct nfs_fh fhandle; + struct nfs_fattr fattr; struct nfs4_create_arg arg = { .dir_fh = NFS_FH(dir), .server = server, - .name = name, + .name = &dentry->d_name, .attrs = sattr, .ftype = NF4DIR, .bitmask = server->attr_bitmask, }; struct nfs4_create_res res = { .server = server, - .fh = fhandle, - .fattr = fattr, + .fh = &fhandle, + .fattr = &fattr, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE], @@ -1564,24 +1688,24 @@ static int _nfs4_proc_mkdir(struct inode *dir, struct qstr *name, }; int status; - fattr->valid = 0; + fattr.valid = 0; status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); - if (!status) + if (!status) { update_changeattr(dir, &res.dir_cinfo); + status = nfs_instantiate(dentry, &fhandle, &fattr); + } return status; } -static int nfs4_proc_mkdir(struct inode *dir, struct qstr *name, - struct iattr *sattr, struct nfs_fh *fhandle, - struct nfs_fattr *fattr) +static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, + struct iattr *sattr) { struct nfs4_exception exception = { }; int err; do { err = nfs4_handle_exception(NFS_SERVER(dir), - _nfs4_proc_mkdir(dir, name, sattr, - fhandle, fattr), + _nfs4_proc_mkdir(dir, dentry, sattr), &exception); } while (exception.retry); return err; @@ -1596,6 +1720,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, .pages = &page, .pgbase = 0, .count = count, + .bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask, }; struct nfs4_readdir_res res; struct rpc_message msg = { @@ -1630,22 +1755,23 @@ static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, return err; } -static int _nfs4_proc_mknod(struct inode *dir, struct qstr *name, - struct iattr *sattr, dev_t rdev, struct nfs_fh *fh, - struct nfs_fattr *fattr) +static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, + struct iattr *sattr, dev_t rdev) { struct nfs_server *server = NFS_SERVER(dir); + struct nfs_fh fh; + struct nfs_fattr fattr; struct nfs4_create_arg arg = { .dir_fh = NFS_FH(dir), .server = server, - .name = name, + .name = &dentry->d_name, .attrs = sattr, .bitmask = server->attr_bitmask, }; struct nfs4_create_res res = { .server = server, - .fh = fh, - .fattr = fattr, + .fh = &fh, + .fattr = &fattr, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE], @@ -1655,7 +1781,7 @@ static int _nfs4_proc_mknod(struct inode *dir, struct qstr *name, int status; int mode = sattr->ia_mode; - fattr->valid = 0; + fattr.valid = 0; BUG_ON(!(sattr->ia_valid & ATTR_MODE)); BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode)); @@ -1675,21 +1801,21 @@ static int _nfs4_proc_mknod(struct inode *dir, struct qstr *name, arg.ftype = NF4SOCK; status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); - if (!status) + if (status == 0) { update_changeattr(dir, &res.dir_cinfo); + status = nfs_instantiate(dentry, &fh, &fattr); + } return status; } -static int nfs4_proc_mknod(struct inode *dir, struct qstr *name, - struct iattr *sattr, dev_t rdev, struct nfs_fh *fh, - struct nfs_fattr *fattr) +static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, + struct iattr *sattr, dev_t rdev) { struct nfs4_exception exception = { }; int err; do { err = nfs4_handle_exception(NFS_SERVER(dir), - _nfs4_proc_mknod(dir, name, sattr, rdev, - fh, fattr), + _nfs4_proc_mknod(dir, dentry, sattr, rdev), &exception); } while (exception.retry); return err; @@ -2001,8 +2127,8 @@ nfs4_proc_file_open(struct inode *inode, struct file *filp) /* Find our open stateid */ cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); - if (unlikely(cred == NULL)) - return -ENOMEM; + if (IS_ERR(cred)) + return PTR_ERR(cred); ctx = alloc_nfs_open_context(dentry, cred); put_rpccred(cred); if (unlikely(ctx == NULL)) @@ -2067,7 +2193,7 @@ nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server) return 0; } -int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp) +static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp) { DEFINE_WAIT(wait); sigset_t oldset; @@ -2151,9 +2277,7 @@ int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_ int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short port) { - static nfs4_verifier sc_verifier; - static int initialized; - + nfs4_verifier sc_verifier; struct nfs4_setclientid setclientid = { .sc_verifier = &sc_verifier, .sc_prog = program, @@ -2164,27 +2288,38 @@ int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short p .rpc_resp = clp, .rpc_cred = clp->cl_cred, }; + u32 *p; + int loop = 0; + int status; - if (!initialized) { - struct timespec boot_time; - u32 *p; - - initialized = 1; - boot_time = CURRENT_TIME; - p = (u32*)sc_verifier.data; - *p++ = htonl((u32)boot_time.tv_sec); - *p = htonl((u32)boot_time.tv_nsec); + p = (u32*)sc_verifier.data; + *p++ = htonl((u32)clp->cl_boot_time.tv_sec); + *p = htonl((u32)clp->cl_boot_time.tv_nsec); + + for(;;) { + setclientid.sc_name_len = scnprintf(setclientid.sc_name, + sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u %s %u", + clp->cl_ipaddr, NIPQUAD(clp->cl_addr.s_addr), + clp->cl_cred->cr_ops->cr_name, + clp->cl_id_uniquifier); + setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, + sizeof(setclientid.sc_netid), "tcp"); + setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, + sizeof(setclientid.sc_uaddr), "%s.%d.%d", + clp->cl_ipaddr, port >> 8, port & 255); + + status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); + if (status != -NFS4ERR_CLID_INUSE) + break; + if (signalled()) + break; + if (loop++ & 1) + ssleep(clp->cl_lease_time + 1); + else + if (++clp->cl_id_uniquifier == 0) + break; } - setclientid.sc_name_len = scnprintf(setclientid.sc_name, - sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u", - clp->cl_ipaddr, NIPQUAD(clp->cl_addr.s_addr)); - setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, - sizeof(setclientid.sc_netid), "tcp"); - setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, - sizeof(setclientid.sc_uaddr), "%s.%d.%d", - clp->cl_ipaddr, port >> 8, port & 255); - - return rpc_call_sync(clp->cl_rpcclient, &msg, 0); + return status; } int @@ -2361,6 +2496,25 @@ static int nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock * return err; } +static int do_vfs_lock(struct file *file, struct file_lock *fl) +{ + int res = 0; + switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) { + case FL_POSIX: + res = posix_lock_file_wait(file, fl); + break; + case FL_FLOCK: + res = flock_lock_file_wait(file, fl); + break; + default: + BUG(); + } + if (res < 0) + printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", + __FUNCTION__); + return res; +} + static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) { struct inode *inode = state->inode; @@ -2408,7 +2562,7 @@ static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock out: up(&state->lock_sema); if (status == 0) - posix_lock_file(request->fl_file, request); + do_vfs_lock(request->fl_file, request); up_read(&clp->cl_sem); return status; } @@ -2500,11 +2654,16 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r return status; } -int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request) +static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request) { return _nfs4_do_setlk(state, F_SETLK, request, 1); } +static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request) +{ + return _nfs4_do_setlk(state, F_SETLK, request, 0); +} + static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) { struct nfs4_client *clp = state->owner->so_client; @@ -2517,7 +2676,7 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock if (status == 0) { /* Note: we always want to sleep here! */ request->fl_flags |= FL_SLEEP; - if (posix_lock_file_wait(request->fl_file, request) < 0) + if (do_vfs_lock(request->fl_file, request) < 0) printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); } up_read(&clp->cl_sem); @@ -2574,6 +2733,16 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request) return status; } +struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { + .recover_open = nfs4_open_reclaim, + .recover_lock = nfs4_lock_reclaim, +}; + +struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops = { + .recover_open = nfs4_open_expired, + .recover_lock = nfs4_lock_expired, +}; + struct nfs_rpc_ops nfs_v4_clientops = { .version = 4, /* protocol version */ .dentry_ops = &nfs4_dentry_operations, diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 67b0f4898490..231cebce3c87 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -116,6 +116,7 @@ nfs4_alloc_client(struct in_addr *addr) INIT_LIST_HEAD(&clp->cl_superblocks); init_waitqueue_head(&clp->cl_waitq); rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client"); + clp->cl_boot_time = CURRENT_TIME; clp->cl_state = 1 << NFS4CLNT_OK; return clp; } @@ -205,7 +206,7 @@ nfs4_put_client(struct nfs4_client *clp) nfs4_free_client(clp); } -int nfs4_init_client(struct nfs4_client *clp) +static int __nfs4_init_client(struct nfs4_client *clp) { int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, nfs_callback_tcpport); if (status == 0) @@ -215,6 +216,11 @@ int nfs4_init_client(struct nfs4_client *clp) return status; } +int nfs4_init_client(struct nfs4_client *clp) +{ + return nfs4_map_errors(__nfs4_init_client(clp)); +} + u32 nfs4_alloc_lockowner_id(struct nfs4_client *clp) { @@ -274,8 +280,8 @@ nfs4_alloc_state_owner(void) return sp; } -static void -nfs4_unhash_state_owner(struct nfs4_state_owner *sp) +void +nfs4_drop_state_owner(struct nfs4_state_owner *sp) { struct nfs4_client *clp = sp->so_client; spin_lock(&clp->cl_lock); @@ -441,7 +447,9 @@ nfs4_get_open_state(struct inode *inode, struct nfs4_state_owner *owner) if (state == NULL && new != NULL) { state = new; /* Caller *must* be holding owner->so_sem */ - list_add(&state->open_states, &owner->so_states); + /* Note: The reclaim code dictates that we add stateless + * and read-only stateids to the end of the list */ + list_add_tail(&state->open_states, &owner->so_states); state->owner = owner; atomic_inc(&owner->so_count); list_add(&state->inode_states, &nfsi->open_states); @@ -497,8 +505,12 @@ void nfs4_close_state(struct nfs4_state *state, mode_t mode) state->nreaders--; if (mode & FMODE_WRITE) state->nwriters--; - if (state->nwriters == 0 && state->nreaders == 0) - list_del_init(&state->inode_states); + if (state->nwriters == 0) { + if (state->nreaders == 0) + list_del_init(&state->inode_states); + /* See reclaim code */ + list_move_tail(&state->open_states, &owner->so_states); + } spin_unlock(&inode->i_lock); newstate = 0; if (state->state != 0) { @@ -708,7 +720,7 @@ void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp) sp->so_seqid++; /* If the server returns BAD_SEQID, unhash state_owner here */ if (status == -NFS4ERR_BAD_SEQID) - nfs4_unhash_state_owner(sp); + nfs4_drop_state_owner(sp); } static int reclaimer(void *); @@ -753,7 +765,7 @@ nfs4_schedule_state_recovery(struct nfs4_client *clp) schedule_work(&clp->cl_recoverd); } -static int nfs4_reclaim_locks(struct nfs4_state *state) +static int nfs4_reclaim_locks(struct nfs4_state_recovery_ops *ops, struct nfs4_state *state) { struct inode *inode = state->inode; struct file_lock *fl; @@ -764,7 +776,7 @@ static int nfs4_reclaim_locks(struct nfs4_state *state) continue; if (((struct nfs_open_context *)fl->fl_file->private_data)->state != state) continue; - status = nfs4_lock_reclaim(state, fl); + status = ops->recover_lock(state, fl); if (status >= 0) continue; switch (status) { @@ -786,20 +798,28 @@ out_err: return status; } -static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp) +static int nfs4_reclaim_open_state(struct nfs4_state_recovery_ops *ops, struct nfs4_state_owner *sp) { struct nfs4_state *state; struct nfs4_lock_state *lock; int status = 0; + /* Note: we rely on the sp->so_states list being ordered + * so that we always reclaim open(O_RDWR) and/or open(O_WRITE) + * states first. + * This is needed to ensure that the server won't give us any + * read delegations that we have to return if, say, we are + * recovering after a network partition or a reboot from a + * server that doesn't support a grace period. + */ list_for_each_entry(state, &sp->so_states, open_states) { if (state->state == 0) continue; - status = nfs4_open_reclaim(sp, state); + status = ops->recover_open(sp, state); list_for_each_entry(lock, &state->lock_states, ls_locks) lock->ls_flags &= ~NFS_LOCK_INITIALIZED; if (status >= 0) { - status = nfs4_reclaim_locks(state); + status = nfs4_reclaim_locks(ops, state); if (status < 0) goto out_err; list_for_each_entry(lock, &state->lock_states, ls_locks) { @@ -813,8 +833,7 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp) default: printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", __FUNCTION__, status); - case -NFS4ERR_EXPIRED: - case -NFS4ERR_NO_GRACE: + case -ENOENT: case -NFS4ERR_RECLAIM_BAD: case -NFS4ERR_RECLAIM_CONFLICT: /* @@ -826,6 +845,8 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp) /* Mark the file as being 'closed' */ state->state = 0; break; + case -NFS4ERR_EXPIRED: + case -NFS4ERR_NO_GRACE: case -NFS4ERR_STALE_CLIENTID: goto out_err; } @@ -840,6 +861,7 @@ static int reclaimer(void *ptr) struct reclaimer_args *args = (struct reclaimer_args *)ptr; struct nfs4_client *clp = args->clp; struct nfs4_state_owner *sp; + struct nfs4_state_recovery_ops *ops; int status = 0; daemonize("%u.%u.%u.%u-reclaim", NIPQUAD(clp->cl_addr)); @@ -856,20 +878,34 @@ static int reclaimer(void *ptr) goto out; restart_loop: status = nfs4_proc_renew(clp); - if (status == 0 || status == -NFS4ERR_CB_PATH_DOWN) - goto out; - status = nfs4_init_client(clp); + switch (status) { + case 0: + case -NFS4ERR_CB_PATH_DOWN: + goto out; + case -NFS4ERR_STALE_CLIENTID: + case -NFS4ERR_LEASE_MOVED: + ops = &nfs4_reboot_recovery_ops; + break; + default: + ops = &nfs4_network_partition_recovery_ops; + }; + status = __nfs4_init_client(clp); if (status) goto out_error; - /* Mark all delagations for reclaim */ + /* Mark all delegations for reclaim */ nfs_delegation_mark_reclaim(clp); /* Note: list is protected by exclusive lock on cl->cl_sem */ list_for_each_entry(sp, &clp->cl_state_owners, so_list) { - status = nfs4_reclaim_open_state(sp); + status = nfs4_reclaim_open_state(ops, sp); if (status < 0) { + if (status == -NFS4ERR_NO_GRACE) { + ops = &nfs4_network_partition_recovery_ops; + status = nfs4_reclaim_open_state(ops, sp); + } if (status == -NFS4ERR_STALE_CLIENTID) goto restart_loop; - goto out_error; + if (status == -NFS4ERR_EXPIRED) + goto restart_loop; } } nfs_delegation_reap_unclaimed(clp); diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 481cb039626f..5f4de05763c9 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -1010,8 +1010,13 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg WRITE32(readdir->count >> 1); /* We're not doing readdirplus */ WRITE32(readdir->count); WRITE32(2); - WRITE32(FATTR4_WORD0_FILEID); - WRITE32(0); + if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID) { + WRITE32(0); + WRITE32(FATTR4_WORD1_MOUNTED_ON_FILEID); + } else { + WRITE32(FATTR4_WORD0_FILEID); + WRITE32(0); + } /* set up reply kvec * toplevel_status + taglen + rescount + OP_PUTFH + status @@ -3175,7 +3180,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp) READ_BUF(4); READ32(len); READ_BUF(len); - return -EEXIST; + return -NFSERR_CLID_INUSE; } else return -nfs_stat_to_errno(nfserr); @@ -3857,7 +3862,7 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, void *d uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus) { - uint32_t bitmap[1] = {0}; + uint32_t bitmap[2] = {0}; uint32_t len; if (!*p++) { @@ -3881,13 +3886,18 @@ uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus) entry->ino = 1; len = ntohl(*p++); /* bitmap length */ - if (len > 0) { - bitmap[0] = ntohl(*p); - p += len; + if (len-- > 0) { + bitmap[0] = ntohl(*p++); + if (len-- > 0) { + bitmap[1] = ntohl(*p++); + p += len; + } } len = XDR_QUADLEN(ntohl(*p++)); /* attribute buffer length */ if (len > 0) { - if (bitmap[0] == FATTR4_WORD0_FILEID) + if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID) + xdr_decode_hyper(p, &entry->ino); + else if (bitmap[0] == FATTR4_WORD0_FILEID) xdr_decode_hyper(p, &entry->ino); p += len; } diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 864615916862..fd5bc596fe8a 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -124,7 +124,6 @@ enum { Opt_soft, Opt_hard, Opt_intr, Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac, Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp, - Opt_broken_suid, /* Error token */ Opt_err }; @@ -159,7 +158,6 @@ static match_table_t __initdata tokens = { {Opt_udp, "udp"}, {Opt_tcp, "proto=tcp"}, {Opt_tcp, "tcp"}, - {Opt_broken_suid, "broken_suid"}, {Opt_err, NULL} }; @@ -268,9 +266,6 @@ static int __init root_nfs_parse(char *name, char *buf) case Opt_tcp: nfs_data.flags |= NFS_MOUNT_TCP; break; - case Opt_broken_suid: - nfs_data.flags |= NFS_MOUNT_BROKEN_SUID; - break; default : return 0; } @@ -351,7 +346,7 @@ static void __init root_nfs_print(void) #endif -int __init root_nfs_init(void) +static int __init root_nfs_init(void) { #ifdef NFSROOT_DEBUG nfs_debug |= NFSDBG_ROOT; @@ -379,15 +374,15 @@ int __init root_nfs_init(void) * Parse NFS server and directory information passed on the kernel * command line. */ -int __init nfs_root_setup(char *line) +static int __init nfs_root_setup(char *line) { ROOT_DEV = Root_NFS; if (line[0] == '/' || line[0] == ',' || (line[0] >= '0' && line[0] <= '9')) { strlcpy(nfs_root_name, line, sizeof(nfs_root_name)); } else { - int n = strlen(line) + strlen(NFS_ROOT); + int n = strlen(line) + sizeof(NFS_ROOT) - 1; if (n >= sizeof(nfs_root_name)) - line[sizeof(nfs_root_name) - strlen(NFS_ROOT) - 1] = '\0'; + line[sizeof(nfs_root_name) - sizeof(NFS_ROOT) - 2] = '\0'; sprintf(nfs_root_name, NFS_ROOT, line); } root_server_addr = root_nfs_parse_addr(nfs_root_name); diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 3ddaaa1e9374..d31b4d6e5a5e 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -212,7 +212,7 @@ static int nfs_proc_write(struct nfs_write_data *wdata) return status < 0? status : wdata->res.count; } -static struct inode * +static int nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, int flags) { @@ -233,37 +233,34 @@ nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, fattr.valid = 0; dprintk("NFS call create %s\n", dentry->d_name.name); status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0); + if (status == 0) + status = nfs_instantiate(dentry, &fhandle, &fattr); dprintk("NFS reply create: %d\n", status); - if (status == 0) { - struct inode *inode; - inode = nfs_fhget(dir->i_sb, &fhandle, &fattr); - if (inode) - return inode; - status = -ENOMEM; - } - return ERR_PTR(status); + return status; } /* * In NFSv2, mknod is grafted onto the create call. */ static int -nfs_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr, - dev_t rdev, struct nfs_fh *fhandle, struct nfs_fattr *fattr) +nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, + dev_t rdev) { + struct nfs_fh fhandle; + struct nfs_fattr fattr; struct nfs_createargs arg = { .fh = NFS_FH(dir), - .name = name->name, - .len = name->len, + .name = dentry->d_name.name, + .len = dentry->d_name.len, .sattr = sattr }; struct nfs_diropok res = { - .fh = fhandle, - .fattr = fattr + .fh = &fhandle, + .fattr = &fattr }; - int status, mode; + int status, mode; - dprintk("NFS call mknod %s\n", name->name); + dprintk("NFS call mknod %s\n", dentry->d_name.name); mode = sattr->ia_mode; if (S_ISFIFO(mode)) { @@ -274,14 +271,16 @@ nfs_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr, sattr->ia_size = new_encode_dev(rdev);/* get out your barf bag */ } - fattr->valid = 0; + fattr.valid = 0; status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0); if (status == -EINVAL && S_ISFIFO(mode)) { sattr->ia_mode = mode; - fattr->valid = 0; + fattr.valid = 0; status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0); } + if (status == 0) + status = nfs_instantiate(dentry, &fhandle, &fattr); dprintk("NFS reply mknod: %d\n", status); return status; } @@ -398,24 +397,27 @@ nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, } static int -nfs_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr, - struct nfs_fh *fhandle, struct nfs_fattr *fattr) +nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) { + struct nfs_fh fhandle; + struct nfs_fattr fattr; struct nfs_createargs arg = { .fh = NFS_FH(dir), - .name = name->name, - .len = name->len, + .name = dentry->d_name.name, + .len = dentry->d_name.len, .sattr = sattr }; struct nfs_diropok res = { - .fh = fhandle, - .fattr = fattr + .fh = &fhandle, + .fattr = &fattr }; int status; - dprintk("NFS call mkdir %s\n", name->name); - fattr->valid = 0; + dprintk("NFS call mkdir %s\n", dentry->d_name.name); + fattr.valid = 0; status = rpc_call(NFS_CLIENT(dir), NFSPROC_MKDIR, &arg, &res, 0); + if (status == 0) + status = nfs_instantiate(dentry, &fhandle, &fattr); dprintk("NFS reply mkdir: %d\n", status); return status; } diff --git a/fs/nfs/read.c b/fs/nfs/read.c index cb6f7bfe373b..a0042fb58634 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -370,7 +370,7 @@ out_bad: return -ENOMEM; } -int +static int nfs_pagein_list(struct list_head *head, int rpages) { LIST_HEAD(one_request); diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 2b0a0cc642aa..f732541a3332 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -167,6 +167,11 @@ nfs_async_unlink(struct dentry *dentry) goto out; memset(data, 0, sizeof(*data)); + data->cred = rpcauth_lookupcred(clnt->cl_auth, 0); + if (IS_ERR(data->cred)) { + status = PTR_ERR(data->cred); + goto out_free; + } data->dir = dget(dir); data->dentry = dentry; @@ -183,12 +188,14 @@ nfs_async_unlink(struct dentry *dentry) spin_lock(&dentry->d_lock); dentry->d_flags |= DCACHE_NFSFS_RENAMED; spin_unlock(&dentry->d_lock); - data->cred = rpcauth_lookupcred(clnt->cl_auth, 0); rpc_sleep_on(&nfs_delete_queue, task, NULL, NULL); status = 0; out: return status; +out_free: + kfree(data); + return status; } /** diff --git a/fs/nfs/write.c b/fs/nfs/write.c index ad7eb9bdff46..6f7a4af3bc46 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -80,14 +80,31 @@ static void nfs_writeback_done_partial(struct nfs_write_data *, int); static void nfs_writeback_done_full(struct nfs_write_data *, int); static int nfs_wait_on_write_congestion(struct address_space *, int); static int nfs_wait_on_requests(struct inode *, unsigned long, unsigned int); +static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, + unsigned int npages, int how); static kmem_cache_t *nfs_wdata_cachep; mempool_t *nfs_wdata_mempool; -mempool_t *nfs_commit_mempool; +static mempool_t *nfs_commit_mempool; static DECLARE_WAIT_QUEUE_HEAD(nfs_write_congestion); -void nfs_writedata_release(struct rpc_task *task) +static inline struct nfs_write_data *nfs_commit_alloc(void) +{ + struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, SLAB_NOFS); + if (p) { + memset(p, 0, sizeof(*p)); + INIT_LIST_HEAD(&p->pages); + } + return p; +} + +static inline void nfs_commit_free(struct nfs_write_data *p) +{ + mempool_free(p, nfs_commit_mempool); +} + +static void nfs_writedata_release(struct rpc_task *task) { struct nfs_write_data *wdata = (struct nfs_write_data *)task->tk_calldata; nfs_writedata_free(wdata); @@ -990,7 +1007,7 @@ static int nfs_flush_one(struct list_head *head, struct inode *inode, int how) return -ENOMEM; } -int +static int nfs_flush_list(struct list_head *head, int wpages, int how) { LIST_HEAD(one_request); @@ -1240,7 +1257,7 @@ static void nfs_commit_rpcsetup(struct list_head *head, /* * Commit dirty pages */ -int +static int nfs_commit_list(struct list_head *head, int how) { struct nfs_write_data *data; @@ -1314,8 +1331,8 @@ nfs_commit_done(struct rpc_task *task) } #endif -int nfs_flush_inode(struct inode *inode, unsigned long idx_start, - unsigned int npages, int how) +static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, + unsigned int npages, int how) { struct nfs_inode *nfsi = NFS_I(inode); LIST_HEAD(head); diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 3f5a0df497da..271c231e7ba4 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -446,7 +446,7 @@ nfsd4_probe_callback(struct nfs4_client *clp) atomic_inc(&clp->cl_count); msg.rpc_cred = nfsd4_lookupcred(clp,0); - if (msg.rpc_cred == NULL) + if (IS_ERR(msg.rpc_cred)) goto out_rpciod; status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, nfs4_cb_null, NULL); put_rpccred(msg.rpc_cred); @@ -512,7 +512,7 @@ nfsd4_cb_recall(struct nfs4_delegation *dp) return; msg.rpc_cred = nfsd4_lookupcred(clp, 0); - if (msg.rpc_cred == NULL) + if (IS_ERR(msg.rpc_cred)) goto out; cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */ diff --git a/include/asm-arm/arch-s3c2410/debug-macro.S b/include/asm-arm/arch-s3c2410/debug-macro.S index eab2d12ed4f4..abfbe45cd17c 100644 --- a/include/asm-arm/arch-s3c2410/debug-macro.S +++ b/include/asm-arm/arch-s3c2410/debug-macro.S @@ -11,6 +11,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * + * Modifications: + * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA */ #include <asm/arch/map.h> @@ -24,7 +26,7 @@ mrc p15, 0, \rx, c1, c0 tst \rx, #1 ldreq \rx, = S3C2410_PA_UART - ldrne \rx, = S3C2410_VA_UART + ldrne \rx, = S3C24XX_VA_UART #if CONFIG_DEBUG_S3C2410_UART != 0 add \rx, \rx, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C2410_UART) #endif @@ -43,7 +45,7 @@ mrc p15, 0, \rd, c1, c0 tst \rd, #1 addeq \rd, \rx, #(S3C2410_PA_GPIO - S3C2410_PA_UART) - addne \rd, \rx, #(S3C2410_VA_GPIO - S3C2410_VA_UART) + addne \rd, \rx, #(S3C24XX_VA_GPIO - S3C24XX_VA_UART) bic \rd, \rd, #0xff000 ldr \rd, [ \rd, # S3C2410_GSTATUS1 - S3C2410_GPIOREG(0) ] and \rd, \rd, #0x00ff0000 @@ -74,7 +76,7 @@ mrc p15, 0, \rd, c1, c0 tst \rd, #1 addeq \rd, \rx, #(S3C2410_PA_GPIO - S3C2410_PA_UART) - addne \rd, \rx, #(S3C2410_VA_GPIO - S3C2410_VA_UART) + addne \rd, \rx, #(S3C24XX_VA_GPIO - S3C24XX_VA_UART) bic \rd, \rd, #0xff000 ldr \rd, [ \rd, # S3C2410_GSTATUS1 - S3C2410_GPIOREG(0) ] and \rd, \rd, #0x00ff0000 diff --git a/include/asm-arm/arch-s3c2410/entry-macro.S b/include/asm-arm/arch-s3c2410/entry-macro.S index 4cc886ed1dbb..b7d4d7f4422d 100644 --- a/include/asm-arm/arch-s3c2410/entry-macro.S +++ b/include/asm-arm/arch-s3c2410/entry-macro.S @@ -6,12 +6,15 @@ * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. + + * Modifications: + * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA */ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp - mov \tmp, #S3C2410_VA_IRQ + mov \tmp, #S3C24XX_VA_IRQ ldr \irqnr, [ \tmp, #0x14 ] @ get irq no 30000: teq \irqnr, #4 @@ -45,7 +48,7 @@ .align 4 20004: mov r1, #1 - mov \tmp, #S3C2410_VA_IRQ + mov \tmp, #S3C24XX_VA_IRQ ldmfd r13!, { r0 - r4 , r8-r12, r14 } #endif @@ -83,7 +86,7 @@ @ we get here from no main or external interrupts pending 1002: - add \tmp, \tmp, #S3C2410_VA_GPIO - S3C2410_VA_IRQ + add \tmp, \tmp, #S3C24XX_VA_GPIO - S3C24XX_VA_IRQ ldr \irqstat, [ \tmp, # 0xa8 ] @ EXTINTPEND ldr \irqnr, [ \tmp, # 0xa4 ] @ EXTINTMASK diff --git a/include/asm-arm/arch-s3c2410/io.h b/include/asm-arm/arch-s3c2410/io.h index 291b862e3f56..4d5c08b6e198 100644 --- a/include/asm-arm/arch-s3c2410/io.h +++ b/include/asm-arm/arch-s3c2410/io.h @@ -8,6 +8,7 @@ * Modifications: * 06-Dec-1997 RMK Created. * 02-Sep-2003 BJD Modified for S3C2410 + * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA * */ @@ -26,10 +27,10 @@ #define __PORT_PCIO(x) ((x) < (1<<28)) -#define PCIO_BASE (S3C2410_VA_ISA_WORD) -#define PCIO_BASE_b (S3C2410_VA_ISA_BYTE) -#define PCIO_BASE_w (S3C2410_VA_ISA_WORD) -#define PCIO_BASE_l (S3C2410_VA_ISA_WORD) +#define PCIO_BASE (S3C24XX_VA_ISA_WORD) +#define PCIO_BASE_b (S3C24XX_VA_ISA_BYTE) +#define PCIO_BASE_w (S3C24XX_VA_ISA_WORD) +#define PCIO_BASE_l (S3C24XX_VA_ISA_WORD) /* * Dynamic IO functions - let the compiler * optimize the expressions diff --git a/include/asm-arm/arch-s3c2410/map.h b/include/asm-arm/arch-s3c2410/map.h index 17ea5fcdc38c..a6d03737603e 100644 --- a/include/asm-arm/arch-s3c2410/map.h +++ b/include/asm-arm/arch-s3c2410/map.h @@ -10,9 +10,10 @@ * published by the Free Software Foundation. * * Changelog: - * 12-May-2003 BJD Created file - * 06-Jan-2003 BJD Linux 2.6.0 version, moved bast specifics out - * 10-Feb-2005 BJD Added CAMIF definition from guillaume.gourat@nexvision.tv + * 12-May-2003 BJD Created file + * 06-Jan-2003 BJD Linux 2.6.0 version, moved bast specifics out + * 10-Feb-2005 BJD Added CAMIF definition from guillaume.gourat@nexvision.tv + * 10-Mar-2005 LCVR Added support to S3C2400, changed {VA,SZ} names */ #ifndef __ASM_ARCH_MAP_H @@ -30,100 +31,122 @@ */ #define S3C2410_ADDR(x) (0xF0000000 + (x)) +#define S3C2400_ADDR(x) S3C2410_ADDR(x) /* interrupt controller is the first thing we put in, to make * the assembly code for the irq detection easier */ -#define S3C2410_VA_IRQ S3C2410_ADDR(0x00000000) +#define S3C24XX_VA_IRQ S3C2410_ADDR(0x00000000) +#define S3C2400_PA_IRQ (0x14400000) #define S3C2410_PA_IRQ (0x4A000000) -#define S3C2410_SZ_IRQ SZ_1M +#define S3C24XX_SZ_IRQ SZ_1M /* memory controller registers */ -#define S3C2410_VA_MEMCTRL S3C2410_ADDR(0x00100000) +#define S3C24XX_VA_MEMCTRL S3C2410_ADDR(0x00100000) +#define S3C2400_PA_MEMCTRL (0x14000000) #define S3C2410_PA_MEMCTRL (0x48000000) -#define S3C2410_SZ_MEMCTRL SZ_1M +#define S3C24XX_SZ_MEMCTRL SZ_1M /* USB host controller */ -#define S3C2410_VA_USBHOST S3C2410_ADDR(0x00200000) +#define S3C24XX_VA_USBHOST S3C2410_ADDR(0x00200000) +#define S3C2400_PA_USBHOST (0x14200000) #define S3C2410_PA_USBHOST (0x49000000) -#define S3C2410_SZ_USBHOST SZ_1M +#define S3C24XX_SZ_USBHOST SZ_1M /* DMA controller */ -#define S3C2410_VA_DMA S3C2410_ADDR(0x00300000) +#define S3C24XX_VA_DMA S3C2410_ADDR(0x00300000) +#define S3C2400_PA_DMA (0x14600000) #define S3C2410_PA_DMA (0x4B000000) -#define S3C2410_SZ_DMA SZ_1M +#define S3C24XX_SZ_DMA SZ_1M /* Clock and Power management */ -#define S3C2410_VA_CLKPWR S3C2410_ADDR(0x00400000) +#define S3C24XX_VA_CLKPWR S3C2410_ADDR(0x00400000) +#define S3C2400_PA_CLKPWR (0x14800000) #define S3C2410_PA_CLKPWR (0x4C000000) -#define S3C2410_SZ_CLKPWR SZ_1M +#define S3C24XX_SZ_CLKPWR SZ_1M /* LCD controller */ -#define S3C2410_VA_LCD S3C2410_ADDR(0x00600000) +#define S3C24XX_VA_LCD S3C2410_ADDR(0x00600000) +#define S3C2400_PA_LCD (0x14A00000) #define S3C2410_PA_LCD (0x4D000000) -#define S3C2410_SZ_LCD SZ_1M +#define S3C24XX_SZ_LCD SZ_1M /* NAND flash controller */ -#define S3C2410_VA_NAND S3C2410_ADDR(0x00700000) +#define S3C24XX_VA_NAND S3C2410_ADDR(0x00700000) #define S3C2410_PA_NAND (0x4E000000) -#define S3C2410_SZ_NAND SZ_1M +#define S3C24XX_SZ_NAND SZ_1M + +/* MMC controller - available on the S3C2400 */ +#define S3C2400_VA_MMC S3C2400_ADDR(0x00700000) +#define S3C2400_PA_MMC (0x15A00000) +#define S3C2400_SZ_MMC SZ_1M /* UARTs */ -#define S3C2410_VA_UART S3C2410_ADDR(0x00800000) +#define S3C24XX_VA_UART S3C2410_ADDR(0x00800000) +#define S3C2400_PA_UART (0x15000000) #define S3C2410_PA_UART (0x50000000) -#define S3C2410_SZ_UART SZ_1M +#define S3C24XX_SZ_UART SZ_1M /* Timers */ -#define S3C2410_VA_TIMER S3C2410_ADDR(0x00900000) +#define S3C24XX_VA_TIMER S3C2410_ADDR(0x00900000) +#define S3C2400_PA_TIMER (0x15100000) #define S3C2410_PA_TIMER (0x51000000) -#define S3C2410_SZ_TIMER SZ_1M +#define S3C24XX_SZ_TIMER SZ_1M /* USB Device port */ -#define S3C2410_VA_USBDEV S3C2410_ADDR(0x00A00000) +#define S3C24XX_VA_USBDEV S3C2410_ADDR(0x00A00000) +#define S3C2400_PA_USBDEV (0x15200140) #define S3C2410_PA_USBDEV (0x52000000) -#define S3C2410_SZ_USBDEV SZ_1M +#define S3C24XX_SZ_USBDEV SZ_1M /* Watchdog */ -#define S3C2410_VA_WATCHDOG S3C2410_ADDR(0x00B00000) +#define S3C24XX_VA_WATCHDOG S3C2410_ADDR(0x00B00000) +#define S3C2400_PA_WATCHDOG (0x15300000) #define S3C2410_PA_WATCHDOG (0x53000000) -#define S3C2410_SZ_WATCHDOG SZ_1M +#define S3C24XX_SZ_WATCHDOG SZ_1M /* IIC hardware controller */ -#define S3C2410_VA_IIC S3C2410_ADDR(0x00C00000) +#define S3C24XX_VA_IIC S3C2410_ADDR(0x00C00000) +#define S3C2400_PA_IIC (0x15400000) #define S3C2410_PA_IIC (0x54000000) -#define S3C2410_SZ_IIC SZ_1M +#define S3C24XX_SZ_IIC SZ_1M -#define VA_IIC_BASE (S3C2410_VA_IIC) +#define VA_IIC_BASE (S3C24XX_VA_IIC) /* IIS controller */ -#define S3C2410_VA_IIS S3C2410_ADDR(0x00D00000) +#define S3C24XX_VA_IIS S3C2410_ADDR(0x00D00000) +#define S3C2400_PA_IIS (0x15508000) #define S3C2410_PA_IIS (0x55000000) -#define S3C2410_SZ_IIS SZ_1M +#define S3C24XX_SZ_IIS SZ_1M /* GPIO ports */ -#define S3C2410_VA_GPIO S3C2410_ADDR(0x00E00000) +#define S3C24XX_VA_GPIO S3C2410_ADDR(0x00E00000) +#define S3C2400_PA_GPIO (0x15600000) #define S3C2410_PA_GPIO (0x56000000) -#define S3C2410_SZ_GPIO SZ_1M +#define S3C24XX_SZ_GPIO SZ_1M /* RTC */ -#define S3C2410_VA_RTC S3C2410_ADDR(0x00F00000) +#define S3C24XX_VA_RTC S3C2410_ADDR(0x00F00000) +#define S3C2400_PA_RTC (0x15700040) #define S3C2410_PA_RTC (0x57000000) -#define S3C2410_SZ_RTC SZ_1M +#define S3C24XX_SZ_RTC SZ_1M /* ADC */ -#define S3C2410_VA_ADC S3C2410_ADDR(0x01000000) +#define S3C24XX_VA_ADC S3C2410_ADDR(0x01000000) +#define S3C2400_PA_ADC (0x15800000) #define S3C2410_PA_ADC (0x58000000) -#define S3C2410_SZ_ADC SZ_1M +#define S3C24XX_SZ_ADC SZ_1M /* SPI */ -#define S3C2410_VA_SPI S3C2410_ADDR(0x01100000) +#define S3C24XX_VA_SPI S3C2410_ADDR(0x01100000) +#define S3C2400_PA_SPI (0x15900000) #define S3C2410_PA_SPI (0x59000000) -#define S3C2410_SZ_SPI SZ_1M +#define S3C24XX_SZ_SPI SZ_1M /* SDI */ -#define S3C2410_VA_SDI S3C2410_ADDR(0x01200000) +#define S3C24XX_VA_SDI S3C2410_ADDR(0x01200000) #define S3C2410_PA_SDI (0x5A000000) -#define S3C2410_SZ_SDI SZ_1M +#define S3C24XX_SZ_SDI SZ_1M /* CAMIF */ #define S3C2440_PA_CAMIF (0x4F000000) @@ -133,8 +156,8 @@ * implements it. We reserve two 16M regions for ISA. */ -#define S3C2410_VA_ISA_WORD S3C2410_ADDR(0x02000000) -#define S3C2410_VA_ISA_BYTE S3C2410_ADDR(0x03000000) +#define S3C24XX_VA_ISA_WORD S3C2410_ADDR(0x02000000) +#define S3C24XX_VA_ISA_BYTE S3C2410_ADDR(0x03000000) /* physical addresses of all the chip-select areas */ @@ -149,5 +172,16 @@ #define S3C2410_SDRAM_PA (S3C2410_CS6) +#define S3C2400_CS0 (0x00000000) +#define S3C2400_CS1 (0x02000000) +#define S3C2400_CS2 (0x04000000) +#define S3C2400_CS3 (0x06000000) +#define S3C2400_CS4 (0x08000000) +#define S3C2400_CS5 (0x0A000000) +#define S3C2400_CS6 (0x0C000000) +#define S3C2400_CS7 (0x0E000000) + +#define S3C2400_SDRAM_PA (S3C2400_CS6) + #endif /* __ASM_ARCH_MAP_H */ diff --git a/include/asm-arm/arch-s3c2410/regs-clock.h b/include/asm-arm/arch-s3c2410/regs-clock.h index a6281f464d81..e5e938b79acc 100644 --- a/include/asm-arm/arch-s3c2410/regs-clock.h +++ b/include/asm-arm/arch-s3c2410/regs-clock.h @@ -10,18 +10,19 @@ * S3C2410 clock register definitions * * Changelog: - * 18-Aug-2004 Ben Dooks Added 2440 definitions - * 08-Aug-2004 Herbert Pötzl Added CLKCON definitions - * 19-06-2003 Ben Dooks Created file - * 12-03-2004 Ben Dooks Updated include protection - * 29-Sep-2004 Ben Dooks Fixed usage for assembly inclusion - * 10-Feb-2005 Ben Dooks Fixed CAMDIVN address (Guillaume Gourat) + * 18-Aug-2004 Ben Dooks Added 2440 definitions + * 08-Aug-2004 Herbert Pötzl Added CLKCON definitions + * 19-06-2003 Ben Dooks Created file + * 12-03-2004 Ben Dooks Updated include protection + * 29-Sep-2004 Ben Dooks Fixed usage for assembly inclusion + * 10-Feb-2005 Ben Dooks Fixed CAMDIVN address (Guillaume Gourat) + * 10-Mar-2005 Lucas Villa Real Changed S3C2410_VA to S3C24XX_VA */ #ifndef __ASM_ARM_REGS_CLOCK #define __ASM_ARM_REGS_CLOCK "$Id: clock.h,v 1.4 2003/04/30 14:50:51 ben Exp $" -#define S3C2410_CLKREG(x) ((x) + S3C2410_VA_CLKPWR) +#define S3C2410_CLKREG(x) ((x) + S3C24XX_VA_CLKPWR) #define S3C2410_PLLVAL(_m,_p,_s) ((_m) << 12 | ((_p) << 4) | ((_s))) diff --git a/include/asm-arm/arch-s3c2410/regs-gpio.h b/include/asm-arm/arch-s3c2410/regs-gpio.h index 07c17f95a92b..8ca8c0c922f5 100644 --- a/include/asm-arm/arch-s3c2410/regs-gpio.h +++ b/include/asm-arm/arch-s3c2410/regs-gpio.h @@ -18,6 +18,7 @@ * 17-10-2004 BJD Added GSTATUS1 register definitions * 18-11-2004 BJD Fixed definitions of GPE3, GPE4, GPE5 and GPE6 * 18-11-2004 BJD Added S3C2440 AC97 controls + * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA */ @@ -35,7 +36,7 @@ #define S3C2410_GPIO_BANKG (32*6) #define S3C2410_GPIO_BANKH (32*7) -#define S3C2410_GPIO_BASE(pin) ((((pin) & ~31) >> 1) + S3C2410_VA_GPIO) +#define S3C2410_GPIO_BASE(pin) ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO) #define S3C2410_GPIO_OFFSET(pin) ((pin) & 31) /* general configuration options */ @@ -44,7 +45,7 @@ /* configure GPIO ports A..G */ -#define S3C2410_GPIOREG(x) ((x) + S3C2410_VA_GPIO) +#define S3C2410_GPIOREG(x) ((x) + S3C24XX_VA_GPIO) /* port A - 22bits, zero in bit X makes pin X output * 1 makes port special function, this is default diff --git a/include/asm-arm/arch-s3c2410/regs-iis.h b/include/asm-arm/arch-s3c2410/regs-iis.h index a3fde605f5c8..7ae8e1f45bc1 100644 --- a/include/asm-arm/arch-s3c2410/regs-iis.h +++ b/include/asm-arm/arch-s3c2410/regs-iis.h @@ -13,6 +13,7 @@ * 19-06-2003 BJD Created file * 26-06-2003 BJD Finished off definitions for register addresses * 12-03-2004 BJD Updated include protection + * 07-03-2005 BJD Added FIFO size flags and S3C2440 MPLL */ #ifndef __ASM_ARCH_REGS_IIS_H @@ -20,6 +21,7 @@ #define S3C2410_IISCON (0x00) +#define S3C2440_IISCON_MPLL (1<<9) #define S3C2410_IISCON_LRINDEX (1<<8) #define S3C2410_IISCON_TXFIFORDY (1<<7) #define S3C2410_IISCON_RXFIFORDY (1<<6) @@ -42,6 +44,7 @@ #define S3C2410_IISMOD_MSB (1<<4) #define S3C2410_IISMOD_8BIT (0<<3) #define S3C2410_IISMOD_16BIT (1<<3) +#define S3C2410_IISMOD_BITMASK (1<<3) #define S3C2410_IISMOD_256FS (0<<1) #define S3C2410_IISMOD_384FS (1<<1) #define S3C2410_IISMOD_16FS (0<<0) @@ -50,7 +53,7 @@ #define S3C2410_IISPSR (0x08) #define S3C2410_IISPSR_INTMASK (31<<5) -#define S3C2410_IISPSR_INTSHFIT (5) +#define S3C2410_IISPSR_INTSHIFT (5) #define S3C2410_IISPSR_EXTMASK (31<<0) #define S3C2410_IISPSR_EXTSHFIT (0) @@ -60,8 +63,10 @@ #define S3C2410_IISFCON_RXDMA (1<<14) #define S3C2410_IISFCON_TXENABLE (1<<13) #define S3C2410_IISFCON_RXENABLE (1<<12) +#define S3C2410_IISFCON_TXMASK (0x3f << 6) +#define S3C2410_IISFCON_TXSHIFT (6) +#define S3C2410_IISFCON_RXMASK (0x3f) +#define S3C2410_IISFCON_RXSHIFT (0) #define S3C2410_IISFIFO (0x10) - #endif /* __ASM_ARCH_REGS_IIS_H */ - diff --git a/include/asm-arm/arch-s3c2410/regs-irq.h b/include/asm-arm/arch-s3c2410/regs-irq.h index 87edb61ede09..24b7292df79e 100644 --- a/include/asm-arm/arch-s3c2410/regs-irq.h +++ b/include/asm-arm/arch-s3c2410/regs-irq.h @@ -12,6 +12,7 @@ * Changelog: * 19-06-2003 BJD Created file * 12-03-2004 BJD Updated include protection + * 10-03-2005 LCVR Changed S3C2410_VA to S3C24XX_VA */ @@ -20,8 +21,8 @@ /* interrupt controller */ -#define S3C2410_IRQREG(x) ((x) + S3C2410_VA_IRQ) -#define S3C2410_EINTREG(x) ((x) + S3C2410_VA_GPIO) +#define S3C2410_IRQREG(x) ((x) + S3C24XX_VA_IRQ) +#define S3C2410_EINTREG(x) ((x) + S3C24XX_VA_GPIO) #define S3C2410_SRCPND S3C2410_IRQREG(0x000) #define S3C2410_INTMOD S3C2410_IRQREG(0x004) diff --git a/include/asm-arm/arch-s3c2410/regs-lcd.h b/include/asm-arm/arch-s3c2410/regs-lcd.h index eda2a7b9bf16..7f882ea92b2a 100644 --- a/include/asm-arm/arch-s3c2410/regs-lcd.h +++ b/include/asm-arm/arch-s3c2410/regs-lcd.h @@ -13,13 +13,14 @@ * 12-06-2003 BJD Created file * 26-06-2003 BJD Updated LCDCON register definitions * 12-03-2004 BJD Updated include protection + * 10-03-2005 LCVR Changed S3C2410_VA to S3C24XX_VA */ #ifndef ___ASM_ARCH_REGS_LCD_H #define ___ASM_ARCH_REGS_LCD_H "$Id: lcd.h,v 1.3 2003/06/26 13:25:06 ben Exp $" -#define S3C2410_LCDREG(x) ((x) + S3C2410_VA_LCD) +#define S3C2410_LCDREG(x) ((x) + S3C24XX_VA_LCD) /* LCD control registers */ #define S3C2410_LCDCON1 S3C2410_LCDREG(0x00) diff --git a/include/asm-arm/arch-s3c2410/regs-mem.h b/include/asm-arm/arch-s3c2410/regs-mem.h index 400fbd77d605..29aa625336e1 100644 --- a/include/asm-arm/arch-s3c2410/regs-mem.h +++ b/include/asm-arm/arch-s3c2410/regs-mem.h @@ -11,6 +11,7 @@ * * Changelog: * 29-Sep-2004 BJD Initial include for Linux + * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA * */ @@ -18,7 +19,7 @@ #define __ASM_ARM_MEMREGS_H "$Id: regs.h,v 1.8 2003/05/01 15:55:41 ben Exp $" #ifndef S3C2410_MEMREG -#define S3C2410_MEMREG(x) (S3C2410_VA_MEMCTRL + (x)) +#define S3C2410_MEMREG(x) (S3C24XX_VA_MEMCTRL + (x)) #endif /* bus width, and wait state control */ diff --git a/include/asm-arm/arch-s3c2410/regs-rtc.h b/include/asm-arm/arch-s3c2410/regs-rtc.h index 408cf04266e8..228983f89bc8 100644 --- a/include/asm-arm/arch-s3c2410/regs-rtc.h +++ b/include/asm-arm/arch-s3c2410/regs-rtc.h @@ -12,12 +12,13 @@ * Changelog: * 19-06-2003 BJD Created file * 12-03-2004 BJD Updated include protection + * 15-01-2005 LCVR Changed S3C2410_VA to S3C24XX_VA (s3c2400 support) */ #ifndef __ASM_ARCH_REGS_RTC_H #define __ASM_ARCH_REGS_RTC_H __FILE__ -#define S3C2410_RTCREG(x) ((x) + S3C2410_VA_RTC) +#define S3C2410_RTCREG(x) ((x) + S3C24XX_VA_RTC) #define S3C2410_RTCCON S3C2410_RTCREG(0x40) #define S3C2410_RTCCON_RTCEN (1<<0) diff --git a/include/asm-arm/arch-s3c2410/regs-serial.h b/include/asm-arm/arch-s3c2410/regs-serial.h index 782ce5f5d24d..ce1bbbaad6d3 100644 --- a/include/asm-arm/arch-s3c2410/regs-serial.h +++ b/include/asm-arm/arch-s3c2410/regs-serial.h @@ -27,14 +27,17 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Modifications: + * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA (s3c2400 support) */ #ifndef __ASM_ARM_REGS_SERIAL_H #define __ASM_ARM_REGS_SERIAL_H -#define S3C2410_VA_UART0 (S3C2410_VA_UART) -#define S3C2410_VA_UART1 (S3C2410_VA_UART + 0x4000 ) -#define S3C2410_VA_UART2 (S3C2410_VA_UART + 0x8000 ) +#define S3C24XX_VA_UART0 (S3C24XX_VA_UART) +#define S3C24XX_VA_UART1 (S3C24XX_VA_UART + 0x4000 ) +#define S3C24XX_VA_UART2 (S3C24XX_VA_UART + 0x8000 ) #define S3C2410_PA_UART0 (S3C2410_PA_UART) #define S3C2410_PA_UART1 (S3C2410_PA_UART + 0x4000 ) diff --git a/include/asm-arm/arch-s3c2410/regs-timer.h b/include/asm-arm/arch-s3c2410/regs-timer.h index d93c35d7f690..169064e27520 100644 --- a/include/asm-arm/arch-s3c2410/regs-timer.h +++ b/include/asm-arm/arch-s3c2410/regs-timer.h @@ -14,13 +14,14 @@ * 26-06-2003 BJD Added more timer definitions to mux / control * 12-03-2004 BJD Updated include protection * 10-02-2005 BJD Added S3C2410_TCFG1_MUX4_SHIFT (Guillaume Gourat) + * 10-03-2005 LCVR Changed S3C2410_VA to S3C24XX_VA */ #ifndef __ASM_ARCH_REGS_TIMER_H #define __ASM_ARCH_REGS_TIMER_H "$Id: timer.h,v 1.4 2003/05/06 19:30:50 ben Exp $" -#define S3C2410_TIMERREG(x) (S3C2410_VA_TIMER + (x)) +#define S3C2410_TIMERREG(x) (S3C24XX_VA_TIMER + (x)) #define S3C2410_TIMERREG2(tmr,reg) S3C2410_TIMERREG((reg)+0x0c+((tmr)*0x0c)) #define S3C2410_TCFG0 S3C2410_TIMERREG(0x00) diff --git a/include/asm-arm/arch-s3c2410/regs-udc.h b/include/asm-arm/arch-s3c2410/regs-udc.h index ad550bbf7285..bf315b763252 100644 --- a/include/asm-arm/arch-s3c2410/regs-udc.h +++ b/include/asm-arm/arch-s3c2410/regs-udc.h @@ -11,13 +11,14 @@ * 01-08-2004 Initial creation * 12-09-2004 Cleanup for submission * 24-10-2004 Fixed S3C2410_UDC_MAXP_REG definition + * 10-03-2005 Changed S3C2410_VA to S3C24XX_VA */ #ifndef __ASM_ARCH_REGS_UDC_H #define __ASM_ARCH_REGS_UDC_H -#define S3C2410_USBDREG(x) ((x) + S3C2410_VA_USBDEV) +#define S3C2410_USBDREG(x) ((x) + S3C24XX_VA_USBDEV) #define S3C2410_UDC_FUNC_ADDR_REG S3C2410_USBDREG(0x0140) #define S3C2410_UDC_PWR_REG S3C2410_USBDREG(0x0144) diff --git a/include/asm-arm/arch-s3c2410/regs-watchdog.h b/include/asm-arm/arch-s3c2410/regs-watchdog.h index b09d5107a1eb..d199ca6aff22 100644 --- a/include/asm-arm/arch-s3c2410/regs-watchdog.h +++ b/include/asm-arm/arch-s3c2410/regs-watchdog.h @@ -12,13 +12,14 @@ * Changelog: * 21-06-2003 BJD Created file * 12-03-2004 BJD Updated include protection + * 10-03-2005 LCVR Changed S3C2410_VA to S3C24XX_VA */ #ifndef __ASM_ARCH_REGS_WATCHDOG_H #define __ASM_ARCH_REGS_WATCHDOG_H "$Id: watchdog.h,v 1.2 2003/04/29 13:31:09 ben Exp $" -#define S3C2410_WDOGREG(x) ((x) + S3C2410_VA_WATCHDOG) +#define S3C2410_WDOGREG(x) ((x) + S3C24XX_VA_WATCHDOG) #define S3C2410_WTCON S3C2410_WDOGREG(0x00) #define S3C2410_WTDAT S3C2410_WDOGREG(0x04) diff --git a/include/asm-ppc/uninorth.h b/include/asm-ppc/uninorth.h index 57daf7add022..f737732c3861 100644 --- a/include/asm-ppc/uninorth.h +++ b/include/asm-ppc/uninorth.h @@ -27,13 +27,18 @@ #define UNI_N_CFG_AGP_BASE 0x90 #define UNI_N_CFG_GART_CTRL 0x94 #define UNI_N_CFG_INTERNAL_STATUS 0x98 +#define UNI_N_CFG_GART_DUMMY_PAGE 0xa4 /* UNI_N_CFG_GART_CTRL bits definitions */ -/* Not U3 */ #define UNI_N_CFG_GART_INVAL 0x00000001 #define UNI_N_CFG_GART_ENABLE 0x00000100 #define UNI_N_CFG_GART_2xRESET 0x00010000 #define UNI_N_CFG_GART_DISSBADET 0x00020000 +/* The following seems to only be used only on U3 <j.glisse@gmail.com> */ +#define U3_N_CFG_GART_SYNCMODE 0x00040000 +#define U3_N_CFG_GART_PERFRD 0x00080000 +#define U3_N_CFG_GART_B2BGNT 0x00200000 +#define U3_N_CFG_GART_FASTDDR 0x00400000 /* My understanding of UniNorth AGP as of UniNorth rev 1.0x, * revision 1.5 (x4 AGP) may need further changes. diff --git a/include/asm-ppc64/agp.h b/include/asm-ppc64/agp.h new file mode 100644 index 000000000000..be27cfa8c5b0 --- /dev/null +++ b/include/asm-ppc64/agp.h @@ -0,0 +1,13 @@ +#ifndef AGP_H +#define AGP_H 1 + +#include <asm/io.h> + +/* nothing much needed here */ + +#define map_page_into_agp(page) +#define unmap_page_from_agp(page) +#define flush_agp_mappings() +#define flush_agp_cache() mb() + +#endif diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 5a173a673fc9..0d9d22578212 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -42,7 +42,6 @@ struct nlm_host { struct rpc_clnt * h_rpcclnt; /* RPC client to talk to peer */ char h_name[20]; /* remote hostname */ u32 h_version; /* interface version */ - rpc_authflavor_t h_authflavor; /* RPC authentication type */ unsigned short h_proto; /* transport proto */ unsigned short h_reclaiming : 1, h_server : 1, /* server side, not client side */ @@ -143,8 +142,6 @@ extern unsigned long nlmsvc_timeout; * Lockd client functions */ struct nlm_rqst * nlmclnt_alloc_call(void); -int nlmclnt_call(struct nlm_rqst *, u32); -int nlmclnt_async_call(struct nlm_rqst *, u32, rpc_action); int nlmclnt_block(struct nlm_host *, struct file_lock *, u32 *); int nlmclnt_cancel(struct nlm_host *, struct file_lock *); u32 nlmclnt_grant(struct nlm_lock *); diff --git a/include/linux/namei.h b/include/linux/namei.h index 1bbfa296e11f..7db67b008cac 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -39,12 +39,14 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; * - ending slashes ok even for nonexistent files * - internal "there are more path compnents" flag * - locked when lookup done with dcache_lock held + * - dentry cache is untrusted; force a real lookup */ #define LOOKUP_FOLLOW 1 #define LOOKUP_DIRECTORY 2 #define LOOKUP_CONTINUE 4 #define LOOKUP_PARENT 16 #define LOOKUP_NOALT 32 +#define LOOKUP_REVAL 64 /* * Intent data */ diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 12c46442cc86..dbac7f363e5d 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -345,17 +345,14 @@ extern struct inode_operations nfs_dir_inode_operations; extern struct file_operations nfs_dir_operations; extern struct dentry_operations nfs_dentry_operations; +extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr); + /* * linux/fs/nfs/symlink.c */ extern struct inode_operations nfs_symlink_inode_operations; /* - * linux/fs/nfs/locks.c - */ -extern int nfs_lock(struct file *, int, struct file_lock *); - -/* * linux/fs/nfs/unlink.c */ extern int nfs_async_unlink(struct dentry *); @@ -379,11 +376,8 @@ extern void nfs_commit_done(struct rpc_task *); * return value!) */ extern int nfs_sync_inode(struct inode *, unsigned long, unsigned int, int); -extern int nfs_flush_inode(struct inode *, unsigned long, unsigned int, int); -extern int nfs_flush_list(struct list_head *, int, int); #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) extern int nfs_commit_inode(struct inode *, unsigned long, unsigned int, int); -extern int nfs_commit_list(struct list_head *, int); #else static inline int nfs_commit_inode(struct inode *inode, unsigned long idx_start, unsigned int npages, int how) @@ -424,7 +418,6 @@ static inline int nfs_wb_page(struct inode *inode, struct page* page) * Allocate and free nfs_write_data structures */ extern mempool_t *nfs_wdata_mempool; -extern mempool_t *nfs_commit_mempool; static inline struct nfs_write_data *nfs_writedata_alloc(void) { @@ -441,23 +434,6 @@ static inline void nfs_writedata_free(struct nfs_write_data *p) mempool_free(p, nfs_wdata_mempool); } -extern void nfs_writedata_release(struct rpc_task *task); - -static inline struct nfs_write_data *nfs_commit_alloc(void) -{ - struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, SLAB_NOFS); - if (p) { - memset(p, 0, sizeof(*p)); - INIT_LIST_HEAD(&p->pages); - } - return p; -} - -static inline void nfs_commit_free(struct nfs_write_data *p) -{ - mempool_free(p, nfs_commit_mempool); -} - /* Hack for future NFS swap support */ #ifndef IS_SWAPFILE # define IS_SWAPFILE(inode) (0) @@ -469,7 +445,6 @@ static inline void nfs_commit_free(struct nfs_write_data *p) extern int nfs_readpage(struct file *, struct page *); extern int nfs_readpages(struct file *, struct address_space *, struct list_head *, unsigned); -extern int nfs_pagein_list(struct list_head *, int); extern void nfs_readpage_result(struct rpc_task *); /* @@ -610,6 +585,9 @@ struct nfs4_client { wait_queue_head_t cl_waitq; struct rpc_wait_queue cl_rpcwaitq; + /* used for the setclientid verifier */ + struct timespec cl_boot_time; + /* idmapper */ struct idmap * cl_idmap; @@ -617,6 +595,7 @@ struct nfs4_client { * This is used to generate the clientid, and the callback address. */ char cl_ipaddr[16]; + unsigned char cl_id_uniquifier; }; /* @@ -696,21 +675,26 @@ struct nfs4_exception { int retry; }; +struct nfs4_state_recovery_ops { + int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); + int (*recover_lock)(struct nfs4_state *, struct file_lock *); +}; + extern struct dentry_operations nfs4_dentry_operations; extern struct inode_operations nfs4_dir_inode_operations; /* nfs4proc.c */ +extern int nfs4_map_errors(int err); extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short); extern int nfs4_proc_setclientid_confirm(struct nfs4_client *); -extern int nfs4_open_reclaim(struct nfs4_state_owner *, struct nfs4_state *); extern int nfs4_proc_async_renew(struct nfs4_client *); extern int nfs4_proc_renew(struct nfs4_client *); extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode); -extern int nfs4_wait_clnt_recover(struct rpc_clnt *, struct nfs4_client *); extern struct inode *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); extern int nfs4_open_revalidate(struct inode *, struct dentry *, int); -extern int nfs4_handle_exception(struct nfs_server *, int, struct nfs4_exception *); -extern int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request); + +extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; +extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops; /* nfs4renewd.c */ extern void nfs4_schedule_state_renewal(struct nfs4_client *); @@ -728,6 +712,7 @@ extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *); extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); extern void nfs4_put_state_owner(struct nfs4_state_owner *); +extern void nfs4_drop_state_owner(struct nfs4_state_owner *); extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); extern void nfs4_put_open_state(struct nfs4_state *); extern void nfs4_close_state(struct nfs4_state *, mode_t); diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index a43a38607982..fc51645d61ee 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -53,5 +53,6 @@ struct nfs_server { #define NFS_CAP_HARDLINKS (1U << 1) #define NFS_CAP_SYMLINKS (1U << 2) #define NFS_CAP_ACLS (1U << 3) +#define NFS_CAP_ATOMIC_OPEN (1U << 4) #endif diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index a73f8a990b24..47037d9521cb 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -563,6 +563,7 @@ struct nfs4_readdir_arg { u32 count; struct page ** pages; /* zero-copy data */ unsigned int pgbase; /* zero-copy data */ + const u32 * bitmask; }; struct nfs4_readdir_res { @@ -681,7 +682,7 @@ struct nfs_rpc_ops { int (*read) (struct nfs_read_data *); int (*write) (struct nfs_write_data *); int (*commit) (struct nfs_write_data *); - struct inode * (*create) (struct inode *, struct dentry *, + int (*create) (struct inode *, struct dentry *, struct iattr *, int); int (*remove) (struct inode *, struct qstr *); int (*unlink_setup) (struct rpc_message *, @@ -693,13 +694,12 @@ struct nfs_rpc_ops { int (*symlink) (struct inode *, struct qstr *, struct qstr *, struct iattr *, struct nfs_fh *, struct nfs_fattr *); - int (*mkdir) (struct inode *, struct qstr *, struct iattr *, - struct nfs_fh *, struct nfs_fattr *); + int (*mkdir) (struct inode *, struct dentry *, struct iattr *); int (*rmdir) (struct inode *, struct qstr *); int (*readdir) (struct dentry *, struct rpc_cred *, u64, struct page *, unsigned int, int); - int (*mknod) (struct inode *, struct qstr *, struct iattr *, - dev_t, struct nfs_fh *, struct nfs_fattr *); + int (*mknod) (struct inode *, struct dentry *, struct iattr *, + dev_t); int (*statfs) (struct nfs_server *, struct nfs_fh *, struct nfs_fsstat *); int (*fsinfo) (struct nfs_server *, struct nfs_fh *, @@ -731,7 +731,5 @@ extern struct nfs_rpc_ops nfs_v4_clientops; extern struct rpc_version nfs_version2; extern struct rpc_version nfs_version3; extern struct rpc_version nfs_version4; -extern struct rpc_program nfs_program; -extern struct rpc_stat nfs_rpcstat; #endif diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 2fe68378fbad..1274cdac9cbb 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -876,10 +876,13 @@ #define PCI_DEVICE_ID_APPLE_IPID_ATA100 0x003b #define PCI_DEVICE_ID_APPLE_KEYLARGO_I 0x003e #define PCI_DEVICE_ID_APPLE_K2_ATA100 0x0043 +#define PCI_DEVICE_ID_APPLE_U3_AGP 0x004b #define PCI_DEVICE_ID_APPLE_K2_GMAC 0x004c #define PCI_DEVICE_ID_APPLE_SH_ATA 0x0050 #define PCI_DEVICE_ID_APPLE_SH_SUNGEM 0x0051 #define PCI_DEVICE_ID_APPLE_SH_FW 0x0052 +#define PCI_DEVICE_ID_APPLE_U3L_AGP 0x0058 +#define PCI_DEVICE_ID_APPLE_U3H_AGP 0x0059 #define PCI_DEVICE_ID_APPLE_TIGON3 0x1645 #define PCI_VENDOR_ID_YAMAHA 0x1073 diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index f6d27720962e..04ebc24db348 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -35,8 +35,7 @@ struct auth_cred { * Client user credentials */ struct rpc_cred { - struct list_head cr_hash; /* hash chain */ - struct rpc_auth * cr_auth; + struct hlist_node cr_hash; /* hash chain */ struct rpc_credops * cr_ops; unsigned long cr_expire; /* when to gc */ atomic_t cr_count; /* ref count */ @@ -59,10 +58,13 @@ struct rpc_cred { */ #define RPC_CREDCACHE_NR 8 #define RPC_CREDCACHE_MASK (RPC_CREDCACHE_NR - 1) +struct rpc_cred_cache { + struct hlist_head hashtable[RPC_CREDCACHE_NR]; + unsigned long nextgc; /* next garbage collection */ + unsigned long expire; /* cache expiry interval */ +}; + struct rpc_auth { - struct list_head au_credcache[RPC_CREDCACHE_NR]; - unsigned long au_expire; /* cache expiry interval */ - unsigned long au_nextgc; /* next garbage collection */ unsigned int au_cslack; /* call cred size estimate */ unsigned int au_rslack; /* reply verf size guess */ unsigned int au_flags; /* various flags */ @@ -73,6 +75,7 @@ struct rpc_auth { * case) */ atomic_t au_count; /* Reference counter */ + struct rpc_cred_cache * au_credcache; /* per-flavor data */ }; #define RPC_AUTH_PROC_CREDS 0x0010 /* process creds (including @@ -91,14 +94,16 @@ struct rpc_authops { struct rpc_auth * (*create)(struct rpc_clnt *, rpc_authflavor_t); void (*destroy)(struct rpc_auth *); + struct rpc_cred * (*lookup_cred)(struct rpc_auth *, struct auth_cred *, int); struct rpc_cred * (*crcreate)(struct rpc_auth*, struct auth_cred *, int); }; struct rpc_credops { + const char * cr_name; /* Name of the auth flavour */ void (*crdestroy)(struct rpc_cred *); int (*crmatch)(struct auth_cred *, struct rpc_cred *, int); - u32 * (*crmarshal)(struct rpc_task *, u32 *, int); + u32 * (*crmarshal)(struct rpc_task *, u32 *); int (*crrefresh)(struct rpc_task *); u32 * (*crvalidate)(struct rpc_task *, u32 *); int (*crwrap_req)(struct rpc_task *, kxdrproc_t, @@ -130,7 +135,7 @@ int rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, int rpcauth_refreshcred(struct rpc_task *); void rpcauth_invalcred(struct rpc_task *); int rpcauth_uptodatecred(struct rpc_task *); -void rpcauth_init_credcache(struct rpc_auth *); +int rpcauth_init_credcache(struct rpc_auth *, unsigned long); void rpcauth_free_credcache(struct rpc_auth *); static inline diff --git a/include/linux/sunrpc/auth_gss.h b/include/linux/sunrpc/auth_gss.h index 5bff5a1d45f7..03084dc4bb6a 100644 --- a/include/linux/sunrpc/auth_gss.h +++ b/include/linux/sunrpc/auth_gss.h @@ -68,18 +68,21 @@ struct rpc_gss_init_res { struct gss_cl_ctx { atomic_t count; - u32 gc_proc; + enum rpc_gss_proc gc_proc; u32 gc_seq; spinlock_t gc_seq_lock; struct gss_ctx *gc_gss_ctx; struct xdr_netobj gc_wire_ctx; u32 gc_win; + unsigned long gc_expiry; }; +struct gss_upcall_msg; struct gss_cred { struct rpc_cred gc_base; - u32 gc_flavor; + enum rpc_gss_svc gc_service; struct gss_cl_ctx *gc_ctx; + struct gss_upcall_msg *gc_upcall; }; #define gc_uid gc_base.cr_uid diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 917ec29d789b..2709caf4d128 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -51,7 +51,6 @@ struct rpc_clnt { cl_intr : 1,/* interruptible */ cl_chatty : 1,/* be verbose */ cl_autobind : 1,/* use getport() */ - cl_droppriv : 1,/* enable NFS suid hack */ cl_oneshot : 1,/* dispose after use */ cl_dead : 1;/* abandoned */ @@ -129,6 +128,7 @@ void rpc_restart_call(struct rpc_task *); void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset); void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset); void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); +size_t rpc_max_payload(struct rpc_clnt *); static __inline__ int rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags) diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h index 629957d710a0..689262f63059 100644 --- a/include/linux/sunrpc/gss_api.h +++ b/include/linux/sunrpc/gss_api.h @@ -33,8 +33,9 @@ struct gss_ctx { /* gss-api prototypes; note that these are somewhat simplified versions of * the prototypes specified in RFC 2744. */ -u32 gss_import_sec_context( - struct xdr_netobj *input_token, +int gss_import_sec_context( + const void* input_token, + size_t bufsize, struct gss_api_mech *mech, struct gss_ctx **ctx_id); u32 gss_get_mic( @@ -50,8 +51,6 @@ u32 gss_verify_mic( u32 gss_delete_sec_context( struct gss_ctx **ctx_id); -struct gss_api_mech * gss_mech_get_by_name(char *name); -struct gss_api_mech * gss_mech_get_by_pseudoflavor(u32 pseudoflavor); u32 gss_pseudoflavor_to_service(struct gss_api_mech *, u32 pseudoflavor); char *gss_service_to_auth_domain_name(struct gss_api_mech *, u32 service); @@ -80,8 +79,9 @@ struct gss_api_mech { /* and must provide the following operations: */ struct gss_api_ops { - u32 (*gss_import_sec_context)( - struct xdr_netobj *input_token, + int (*gss_import_sec_context)( + const void *input_token, + size_t bufsize, struct gss_ctx *ctx_id); u32 (*gss_get_mic)( struct gss_ctx *ctx_id, @@ -105,7 +105,7 @@ void gss_mech_unregister(struct gss_api_mech *); struct gss_api_mech * gss_mech_get_by_OID(struct xdr_netobj *); /* Returns a reference to a mechanism, given a name like "krb5" etc. */ -struct gss_api_mech *gss_mech_get_by_name(char *); +struct gss_api_mech *gss_mech_get_by_name(const char *); /* Similar, but get by pseudoflavor. */ struct gss_api_mech *gss_mech_get_by_pseudoflavor(u32); diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 933eeb005f09..99d17ed7cebb 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -53,9 +53,8 @@ struct rpc_task { struct rpc_message tk_msg; /* RPC call info */ __u32 * tk_buffer; /* XDR buffer */ size_t tk_bufsize; - __u8 tk_garb_retry, - tk_cred_retry, - tk_suid_retry; + __u8 tk_garb_retry; + __u8 tk_cred_retry; unsigned long tk_cookie; /* Cookie for batching tasks */ @@ -118,9 +117,7 @@ typedef void (*rpc_action)(struct rpc_task *); */ #define RPC_TASK_ASYNC 0x0001 /* is an async task */ #define RPC_TASK_SWAPPER 0x0002 /* is swapping in/out */ -#define RPC_TASK_SETUID 0x0004 /* is setuid process */ #define RPC_TASK_CHILD 0x0008 /* is child of other task */ -#define RPC_CALL_REALUID 0x0010 /* try using real uid */ #define RPC_CALL_MAJORSEEN 0x0020 /* major timeout seen */ #define RPC_TASK_ROOTCREDS 0x0040 /* force root creds */ #define RPC_TASK_DYNAMIC 0x0080 /* task was kmalloc'ed */ @@ -129,7 +126,6 @@ typedef void (*rpc_action)(struct rpc_task *); #define RPC_TASK_NOINTR 0x0400 /* uninterruptible task */ #define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC) -#define RPC_IS_SETUID(t) ((t)->tk_flags & RPC_TASK_SETUID) #define RPC_IS_CHILD(t) ((t)->tk_flags & RPC_TASK_CHILD) #define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER) #define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS) diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 78dbc7bedd7b..e618c1649814 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -140,6 +140,9 @@ struct rpc_xprt { unsigned int rcvsize, /* socket receive buffer size */ sndsize; /* socket send buffer size */ + size_t max_payload; /* largest RPC payload size, + in bytes */ + struct rpc_wait_queue sending; /* requests waiting to send */ struct rpc_wait_queue resend; /* requests waiting to resend */ struct rpc_wait_queue pending; /* requests in flight */ diff --git a/kernel/printk.c b/kernel/printk.c index 7e36204db952..f5dc23584ff7 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -579,6 +579,7 @@ asmlinkage int vprintk(const char *fmt, va_list args) p[1] <= '7' && p[2] == '>') { loglev_char = p[1]; p += 3; + printed_len += 3; } else { loglev_char = default_message_loglevel + '0'; @@ -591,8 +592,9 @@ asmlinkage int vprintk(const char *fmt, va_list args) (unsigned long)t, nanosec_rem/1000); - for (tp = tbuf; tp< tbuf + tlen; tp++) - emit_log_char (*tp); + for (tp = tbuf; tp < tbuf + tlen; tp++) + emit_log_char(*tp); + printed_len += tlen - 3; } else { if (p[0] != '<' || p[1] < '0' || p[1] > '7' || p[2] != '>') { @@ -601,8 +603,11 @@ asmlinkage int vprintk(const char *fmt, va_list args) + '0'); emit_log_char('>'); } + printed_len += 3; } log_level_unknown = 0; + if (!*p) + break; } emit_log_char(*p); if (*p == '\n') diff --git a/lib/extable.c b/lib/extable.c index e8e77527946e..3f677a8f0c3c 100644 --- a/lib/extable.c +++ b/lib/extable.c @@ -29,7 +29,13 @@ extern struct exception_table_entry __stop___ex_table[]; static int cmp_ex(const void *a, const void *b) { const struct exception_table_entry *x = a, *y = b; - return x->insn - y->insn; + + /* avoid overflow */ + if (x->insn > y->insn) + return 1; + if (x->insn < y->insn) + return -1; + return 0; } void sort_extable(struct exception_table_entry *start, diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 7176c6d37190..9bcec9b927b9 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -67,12 +67,9 @@ rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt) if (flavor >= RPC_AUTH_MAXFLAVOR || !(ops = auth_flavors[flavor])) return NULL; - if (!try_module_get(ops->owner)) - return NULL; auth = ops->create(clnt, pseudoflavor); if (!auth) return NULL; - atomic_set(&auth->au_count, 1); if (clnt->cl_auth) rpcauth_destroy(clnt->cl_auth); clnt->cl_auth = auth; @@ -85,8 +82,6 @@ rpcauth_destroy(struct rpc_auth *auth) if (!atomic_dec_and_test(&auth->au_count)) return; auth->au_ops->destroy(auth); - module_put(auth->au_ops->owner); - kfree(auth); } static DEFINE_SPINLOCK(rpc_credcache_lock); @@ -94,42 +89,35 @@ static DEFINE_SPINLOCK(rpc_credcache_lock); /* * Initialize RPC credential cache */ -void -rpcauth_init_credcache(struct rpc_auth *auth) +int +rpcauth_init_credcache(struct rpc_auth *auth, unsigned long expire) { + struct rpc_cred_cache *new; int i; - for (i = 0; i < RPC_CREDCACHE_NR; i++) - INIT_LIST_HEAD(&auth->au_credcache[i]); - auth->au_nextgc = jiffies + (auth->au_expire >> 1); -} -/* - * Destroy an unreferenced credential - */ -static inline void -rpcauth_crdestroy(struct rpc_cred *cred) -{ -#ifdef RPC_DEBUG - BUG_ON(cred->cr_magic != RPCAUTH_CRED_MAGIC || - atomic_read(&cred->cr_count) || - !list_empty(&cred->cr_hash)); - cred->cr_magic = 0; -#endif - cred->cr_ops->crdestroy(cred); + new = (struct rpc_cred_cache *)kmalloc(sizeof(*new), GFP_KERNEL); + if (!new) + return -ENOMEM; + for (i = 0; i < RPC_CREDCACHE_NR; i++) + INIT_HLIST_HEAD(&new->hashtable[i]); + new->expire = expire; + new->nextgc = jiffies + (expire >> 1); + auth->au_credcache = new; + return 0; } /* * Destroy a list of credentials */ static inline -void rpcauth_destroy_credlist(struct list_head *head) +void rpcauth_destroy_credlist(struct hlist_head *head) { struct rpc_cred *cred; - while (!list_empty(head)) { - cred = list_entry(head->next, struct rpc_cred, cr_hash); - list_del_init(&cred->cr_hash); - rpcauth_crdestroy(cred); + while (!hlist_empty(head)) { + cred = hlist_entry(head->first, struct rpc_cred, cr_hash); + hlist_del_init(&cred->cr_hash); + put_rpccred(cred); } } @@ -140,56 +128,56 @@ void rpcauth_destroy_credlist(struct list_head *head) void rpcauth_free_credcache(struct rpc_auth *auth) { - LIST_HEAD(free); - struct list_head *pos, *next; + struct rpc_cred_cache *cache = auth->au_credcache; + HLIST_HEAD(free); + struct hlist_node *pos, *next; struct rpc_cred *cred; int i; spin_lock(&rpc_credcache_lock); for (i = 0; i < RPC_CREDCACHE_NR; i++) { - list_for_each_safe(pos, next, &auth->au_credcache[i]) { - cred = list_entry(pos, struct rpc_cred, cr_hash); - cred->cr_auth = NULL; - list_del_init(&cred->cr_hash); - if (atomic_read(&cred->cr_count) == 0) - list_add(&cred->cr_hash, &free); + hlist_for_each_safe(pos, next, &cache->hashtable[i]) { + cred = hlist_entry(pos, struct rpc_cred, cr_hash); + __hlist_del(&cred->cr_hash); + hlist_add_head(&cred->cr_hash, &free); } } spin_unlock(&rpc_credcache_lock); rpcauth_destroy_credlist(&free); } -static inline int -rpcauth_prune_expired(struct rpc_cred *cred, struct list_head *free) +static void +rpcauth_prune_expired(struct rpc_auth *auth, struct rpc_cred *cred, struct hlist_head *free) { - if (atomic_read(&cred->cr_count) != 0) - return 0; - if (time_before(jiffies, cred->cr_expire)) - return 0; - cred->cr_auth = NULL; - list_del(&cred->cr_hash); - list_add(&cred->cr_hash, free); - return 1; + if (atomic_read(&cred->cr_count) != 1) + return; + if (time_after(jiffies, cred->cr_expire + auth->au_credcache->expire)) + cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; + if (!(cred->cr_flags & RPCAUTH_CRED_UPTODATE)) { + __hlist_del(&cred->cr_hash); + hlist_add_head(&cred->cr_hash, free); + } } /* * Remove stale credentials. Avoid sleeping inside the loop. */ static void -rpcauth_gc_credcache(struct rpc_auth *auth, struct list_head *free) +rpcauth_gc_credcache(struct rpc_auth *auth, struct hlist_head *free) { - struct list_head *pos, *next; + struct rpc_cred_cache *cache = auth->au_credcache; + struct hlist_node *pos, *next; struct rpc_cred *cred; int i; dprintk("RPC: gc'ing RPC credentials for auth %p\n", auth); for (i = 0; i < RPC_CREDCACHE_NR; i++) { - list_for_each_safe(pos, next, &auth->au_credcache[i]) { - cred = list_entry(pos, struct rpc_cred, cr_hash); - rpcauth_prune_expired(cred, free); + hlist_for_each_safe(pos, next, &cache->hashtable[i]) { + cred = hlist_entry(pos, struct rpc_cred, cr_hash); + rpcauth_prune_expired(auth, cred, free); } } - auth->au_nextgc = jiffies + auth->au_expire; + cache->nextgc = jiffies + cache->expire; } /* @@ -199,8 +187,9 @@ struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, int taskflags) { - LIST_HEAD(free); - struct list_head *pos, *next; + struct rpc_cred_cache *cache = auth->au_credcache; + HLIST_HEAD(free); + struct hlist_node *pos, *next; struct rpc_cred *new = NULL, *cred = NULL; int nr = 0; @@ -209,28 +198,26 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, nr = acred->uid & RPC_CREDCACHE_MASK; retry: spin_lock(&rpc_credcache_lock); - if (time_before(auth->au_nextgc, jiffies)) + if (time_before(cache->nextgc, jiffies)) rpcauth_gc_credcache(auth, &free); - list_for_each_safe(pos, next, &auth->au_credcache[nr]) { + hlist_for_each_safe(pos, next, &cache->hashtable[nr]) { struct rpc_cred *entry; - entry = list_entry(pos, struct rpc_cred, cr_hash); - if (rpcauth_prune_expired(entry, &free)) - continue; + entry = hlist_entry(pos, struct rpc_cred, cr_hash); if (entry->cr_ops->crmatch(acred, entry, taskflags)) { - list_del(&entry->cr_hash); + hlist_del(&entry->cr_hash); cred = entry; break; } + rpcauth_prune_expired(auth, entry, &free); } if (new) { if (cred) - list_add(&new->cr_hash, &free); + hlist_add_head(&new->cr_hash, &free); else cred = new; } if (cred) { - list_add(&cred->cr_hash, &auth->au_credcache[nr]); - cred->cr_auth = auth; + hlist_add_head(&cred->cr_hash, &cache->hashtable[nr]); get_rpccred(cred); } spin_unlock(&rpc_credcache_lock); @@ -239,12 +226,13 @@ retry: if (!cred) { new = auth->au_ops->crcreate(auth, acred, taskflags); - if (new) { + if (!IS_ERR(new)) { #ifdef RPC_DEBUG new->cr_magic = RPCAUTH_CRED_MAGIC; #endif goto retry; - } + } else + cred = new; } return (struct rpc_cred *) cred; @@ -253,18 +241,18 @@ retry: struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *auth, int taskflags) { - struct auth_cred acred; + struct auth_cred acred = { + .uid = current->fsuid, + .gid = current->fsgid, + .group_info = current->group_info, + }; struct rpc_cred *ret; - get_group_info(current->group_info); - acred.uid = current->fsuid; - acred.gid = current->fsgid; - acred.group_info = current->group_info; - dprintk("RPC: looking up %s cred\n", auth->au_ops->au_name); - ret = rpcauth_lookup_credcache(auth, &acred, taskflags); - put_group_info(current->group_info); + get_group_info(acred.group_info); + ret = auth->au_ops->lookup_cred(auth, &acred, taskflags); + put_group_info(acred.group_info); return ret; } @@ -272,21 +260,22 @@ struct rpc_cred * rpcauth_bindcred(struct rpc_task *task) { struct rpc_auth *auth = task->tk_auth; - struct auth_cred acred; + struct auth_cred acred = { + .uid = current->fsuid, + .gid = current->fsgid, + .group_info = current->group_info, + }; struct rpc_cred *ret; - get_group_info(current->group_info); - acred.uid = current->fsuid; - acred.gid = current->fsgid; - acred.group_info = current->group_info; - dprintk("RPC: %4d looking up %s cred\n", task->tk_pid, task->tk_auth->au_ops->au_name); - task->tk_msg.rpc_cred = rpcauth_lookup_credcache(auth, &acred, task->tk_flags); - if (task->tk_msg.rpc_cred == 0) - task->tk_status = -ENOMEM; - ret = task->tk_msg.rpc_cred; - put_group_info(current->group_info); + get_group_info(acred.group_info); + ret = auth->au_ops->lookup_cred(auth, &acred, task->tk_flags); + if (!IS_ERR(ret)) + task->tk_msg.rpc_cred = ret; + else + task->tk_status = PTR_ERR(ret); + put_group_info(acred.group_info); return ret; } @@ -302,16 +291,10 @@ rpcauth_holdcred(struct rpc_task *task) void put_rpccred(struct rpc_cred *cred) { - if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock)) - return; - - if (list_empty(&cred->cr_hash)) { - spin_unlock(&rpc_credcache_lock); - rpcauth_crdestroy(cred); + cred->cr_expire = jiffies; + if (!atomic_dec_and_test(&cred->cr_count)) return; - } - cred->cr_expire = jiffies + cred->cr_auth->au_expire; - spin_unlock(&rpc_credcache_lock); + cred->cr_ops->crdestroy(cred); } void @@ -335,8 +318,7 @@ rpcauth_marshcred(struct rpc_task *task, u32 *p) dprintk("RPC: %4d marshaling %s cred %p\n", task->tk_pid, auth->au_ops->au_name, cred); - return cred->cr_ops->crmarshal(task, p, - task->tk_flags & RPC_CALL_REALUID); + return cred->cr_ops->crmarshal(task, p); } u32 * @@ -357,7 +339,7 @@ rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, struct rpc_cred *cred = task->tk_msg.rpc_cred; dprintk("RPC: %4d using %s cred %p to wrap rpc data\n", - task->tk_pid, cred->cr_auth->au_ops->au_name, cred); + task->tk_pid, cred->cr_ops->cr_name, cred); if (cred->cr_ops->crwrap_req) return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj); /* By default, we encode the arguments normally. */ @@ -371,7 +353,7 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, struct rpc_cred *cred = task->tk_msg.rpc_cred; dprintk("RPC: %4d using %s cred %p to unwrap rpc data\n", - task->tk_pid, cred->cr_auth->au_ops->au_name, cred); + task->tk_pid, cred->cr_ops->cr_name, cred); if (cred->cr_ops->crunwrap_resp) return cred->cr_ops->crunwrap_resp(task, decode, rqstp, data, obj); @@ -384,11 +366,14 @@ rpcauth_refreshcred(struct rpc_task *task) { struct rpc_auth *auth = task->tk_auth; struct rpc_cred *cred = task->tk_msg.rpc_cred; + int err; dprintk("RPC: %4d refreshing %s cred %p\n", task->tk_pid, auth->au_ops->au_name, cred); - task->tk_status = cred->cr_ops->crrefresh(task); - return task->tk_status; + err = cred->cr_ops->crrefresh(task); + if (err < 0) + task->tk_status = err; + return err; } void diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 62960a5603e8..a33b627cbef4 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -85,7 +85,9 @@ static DEFINE_RWLOCK(gss_ctx_lock); struct gss_auth { struct rpc_auth rpc_auth; struct gss_api_mech *mech; + enum rpc_gss_svc service; struct list_head upcalls; + struct rpc_clnt *client; struct dentry *dentry; char path[48]; spinlock_t lock; @@ -175,42 +177,34 @@ gss_cred_is_uptodate_ctx(struct rpc_cred *cred) return res; } -static inline int -simple_get_bytes(char **ptr, const char *end, void *res, int len) +static const void * +simple_get_bytes(const void *p, const void *end, void *res, size_t len) { - char *p, *q; - p = *ptr; - q = p + len; - if (q > end || q < p) - return -1; + const void *q = (const void *)((const char *)p + len); + if (unlikely(q > end || q < p)) + return ERR_PTR(-EFAULT); memcpy(res, p, len); - *ptr = q; - return 0; -} - -static inline int -simple_get_netobj(char **ptr, const char *end, struct xdr_netobj *res) -{ - char *p, *q; - p = *ptr; - if (simple_get_bytes(&p, end, &res->len, sizeof(res->len))) - return -1; - q = p + res->len; - if (q > end || q < p) - return -1; - res->data = p; - *ptr = q; - return 0; + return q; } -static int -dup_netobj(struct xdr_netobj *source, struct xdr_netobj *dest) +static inline const void * +simple_get_netobj(const void *p, const void *end, struct xdr_netobj *dest) { - dest->len = source->len; - if (!(dest->data = kmalloc(dest->len, GFP_KERNEL))) - return -1; - memcpy(dest->data, source->data, dest->len); - return 0; + const void *q; + unsigned int len; + + p = simple_get_bytes(p, end, &len, sizeof(len)); + if (IS_ERR(p)) + return p; + q = (const void *)((const char *)p + len); + if (unlikely(q > end || q < p)) + return ERR_PTR(-EFAULT); + dest->data = kmalloc(len, GFP_KERNEL); + if (unlikely(dest->data == NULL)) + return ERR_PTR(-ENOMEM); + dest->len = len; + memcpy(dest->data, p, len); + return q; } static struct gss_cl_ctx * @@ -226,74 +220,84 @@ gss_cred_get_ctx(struct rpc_cred *cred) return ctx; } -static int -gss_parse_init_downcall(struct gss_api_mech *gm, struct xdr_netobj *buf, - struct gss_cl_ctx **gc, uid_t *uid, int *gss_err) +static struct gss_cl_ctx * +gss_alloc_context(void) { - char *end = buf->data + buf->len; - char *p = buf->data; struct gss_cl_ctx *ctx; - struct xdr_netobj tmp_buf; + + ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); + if (ctx != NULL) { + memset(ctx, 0, sizeof(*ctx)); + ctx->gc_proc = RPC_GSS_PROC_DATA; + ctx->gc_seq = 1; /* NetApp 6.4R1 doesn't accept seq. no. 0 */ + spin_lock_init(&ctx->gc_seq_lock); + atomic_set(&ctx->count,1); + } + return ctx; +} + +#define GSSD_MIN_TIMEOUT (60 * 60) +static const void * +gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct gss_api_mech *gm) +{ + const void *q; + unsigned int seclen; unsigned int timeout; - int err = -EIO; + u32 window_size; + int ret; - if (!(ctx = kmalloc(sizeof(*ctx), GFP_KERNEL))) { - err = -ENOMEM; + /* First unsigned int gives the lifetime (in seconds) of the cred */ + p = simple_get_bytes(p, end, &timeout, sizeof(timeout)); + if (IS_ERR(p)) goto err; - } - ctx->gc_proc = RPC_GSS_PROC_DATA; - ctx->gc_seq = 1; /* NetApp 6.4R1 doesn't accept seq. no. 0 */ - spin_lock_init(&ctx->gc_seq_lock); - atomic_set(&ctx->count,1); - - if (simple_get_bytes(&p, end, uid, sizeof(*uid))) - goto err_free_ctx; - /* FIXME: discarded timeout for now */ - if (simple_get_bytes(&p, end, &timeout, sizeof(timeout))) - goto err_free_ctx; - *gss_err = 0; - if (simple_get_bytes(&p, end, &ctx->gc_win, sizeof(ctx->gc_win))) - goto err_free_ctx; + if (timeout == 0) + timeout = GSSD_MIN_TIMEOUT; + ctx->gc_expiry = jiffies + (unsigned long)timeout * HZ * 3 / 4; + /* Sequence number window. Determines the maximum number of simultaneous requests */ + p = simple_get_bytes(p, end, &window_size, sizeof(window_size)); + if (IS_ERR(p)) + goto err; + ctx->gc_win = window_size; /* gssd signals an error by passing ctx->gc_win = 0: */ - if (!ctx->gc_win) { - /* in which case the next int is an error code: */ - if (simple_get_bytes(&p, end, gss_err, sizeof(*gss_err))) - goto err_free_ctx; - err = 0; - goto err_free_ctx; + if (ctx->gc_win == 0) { + /* in which case, p points to an error code which we ignore */ + p = ERR_PTR(-EACCES); + goto err; } - if (simple_get_netobj(&p, end, &tmp_buf)) - goto err_free_ctx; - if (dup_netobj(&tmp_buf, &ctx->gc_wire_ctx)) { - err = -ENOMEM; - goto err_free_ctx; + /* copy the opaque wire context */ + p = simple_get_netobj(p, end, &ctx->gc_wire_ctx); + if (IS_ERR(p)) + goto err; + /* import the opaque security context */ + p = simple_get_bytes(p, end, &seclen, sizeof(seclen)); + if (IS_ERR(p)) + goto err; + q = (const void *)((const char *)p + seclen); + if (unlikely(q > end || q < p)) { + p = ERR_PTR(-EFAULT); + goto err; } - if (simple_get_netobj(&p, end, &tmp_buf)) - goto err_free_wire_ctx; - if (p != end) - goto err_free_wire_ctx; - if (gss_import_sec_context(&tmp_buf, gm, &ctx->gc_gss_ctx)) - goto err_free_wire_ctx; - *gc = ctx; - return 0; -err_free_wire_ctx: - kfree(ctx->gc_wire_ctx.data); -err_free_ctx: - kfree(ctx); + ret = gss_import_sec_context(p, seclen, gm, &ctx->gc_gss_ctx); + if (ret < 0) { + p = ERR_PTR(ret); + goto err; + } + return q; err: - *gc = NULL; - dprintk("RPC: gss_parse_init_downcall returning %d\n", err); - return err; + dprintk("RPC: gss_fill_context returning %ld\n", -PTR_ERR(p)); + return p; } struct gss_upcall_msg { + atomic_t count; + uid_t uid; struct rpc_pipe_msg msg; struct list_head list; struct gss_auth *auth; - struct rpc_wait_queue waitq; - uid_t uid; - atomic_t count; + struct rpc_wait_queue rpc_waitqueue; + wait_queue_head_t waitqueue; + struct gss_cl_ctx *ctx; }; static void @@ -302,6 +306,8 @@ gss_release_msg(struct gss_upcall_msg *gss_msg) if (!atomic_dec_and_test(&gss_msg->count)) return; BUG_ON(!list_empty(&gss_msg->list)); + if (gss_msg->ctx != NULL) + gss_put_ctx(gss_msg->ctx); kfree(gss_msg); } @@ -320,16 +326,34 @@ __gss_find_upcall(struct gss_auth *gss_auth, uid_t uid) return NULL; } +/* Try to add a upcall to the pipefs queue. + * If an upcall owned by our uid already exists, then we return a reference + * to that upcall instead of adding the new upcall. + */ +static inline struct gss_upcall_msg * +gss_add_msg(struct gss_auth *gss_auth, struct gss_upcall_msg *gss_msg) +{ + struct gss_upcall_msg *old; + + spin_lock(&gss_auth->lock); + old = __gss_find_upcall(gss_auth, gss_msg->uid); + if (old == NULL) { + atomic_inc(&gss_msg->count); + list_add(&gss_msg->list, &gss_auth->upcalls); + } else + gss_msg = old; + spin_unlock(&gss_auth->lock); + return gss_msg; +} + static void __gss_unhash_msg(struct gss_upcall_msg *gss_msg) { if (list_empty(&gss_msg->list)) return; list_del_init(&gss_msg->list); - if (gss_msg->msg.errno < 0) - rpc_wake_up_status(&gss_msg->waitq, gss_msg->msg.errno); - else - rpc_wake_up(&gss_msg->waitq); + rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno); + wake_up_all(&gss_msg->waitqueue); atomic_dec(&gss_msg->count); } @@ -343,76 +367,139 @@ gss_unhash_msg(struct gss_upcall_msg *gss_msg) spin_unlock(&gss_auth->lock); } -static int -gss_upcall(struct rpc_clnt *clnt, struct rpc_task *task, struct rpc_cred *cred) +static void +gss_upcall_callback(struct rpc_task *task) { - struct gss_auth *gss_auth = container_of(clnt->cl_auth, - struct gss_auth, rpc_auth); - struct gss_upcall_msg *gss_msg, *gss_new = NULL; - struct rpc_pipe_msg *msg; - struct dentry *dentry = gss_auth->dentry; - uid_t uid = cred->cr_uid; - int res = 0; + struct gss_cred *gss_cred = container_of(task->tk_msg.rpc_cred, + struct gss_cred, gc_base); + struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall; - dprintk("RPC: %4u gss_upcall for uid %u\n", task->tk_pid, uid); + BUG_ON(gss_msg == NULL); + if (gss_msg->ctx) + gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_get_ctx(gss_msg->ctx)); + else + task->tk_status = gss_msg->msg.errno; + spin_lock(&gss_msg->auth->lock); + gss_cred->gc_upcall = NULL; + rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno); + spin_unlock(&gss_msg->auth->lock); + gss_release_msg(gss_msg); +} -retry: - spin_lock(&gss_auth->lock); - gss_msg = __gss_find_upcall(gss_auth, uid); - if (gss_msg) - goto out_sleep; - if (gss_new == NULL) { - spin_unlock(&gss_auth->lock); - gss_new = kmalloc(sizeof(*gss_new), GFP_KERNEL); - if (!gss_new) { - dprintk("RPC: %4u gss_upcall -ENOMEM\n", task->tk_pid); - return -ENOMEM; +static inline struct gss_upcall_msg * +gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid) +{ + struct gss_upcall_msg *gss_msg; + + gss_msg = kmalloc(sizeof(*gss_msg), GFP_KERNEL); + if (gss_msg != NULL) { + memset(gss_msg, 0, sizeof(*gss_msg)); + INIT_LIST_HEAD(&gss_msg->list); + rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq"); + init_waitqueue_head(&gss_msg->waitqueue); + atomic_set(&gss_msg->count, 1); + gss_msg->msg.data = &gss_msg->uid; + gss_msg->msg.len = sizeof(gss_msg->uid); + gss_msg->uid = uid; + gss_msg->auth = gss_auth; + } + return gss_msg; +} + +static struct gss_upcall_msg * +gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cred *cred) +{ + struct gss_upcall_msg *gss_new, *gss_msg; + + gss_new = gss_alloc_msg(gss_auth, cred->cr_uid); + if (gss_new == NULL) + return ERR_PTR(-ENOMEM); + gss_msg = gss_add_msg(gss_auth, gss_new); + if (gss_msg == gss_new) { + int res = rpc_queue_upcall(gss_auth->dentry->d_inode, &gss_new->msg); + if (res) { + gss_unhash_msg(gss_new); + gss_msg = ERR_PTR(res); } - goto retry; + } else + gss_release_msg(gss_new); + return gss_msg; +} + +static inline int +gss_refresh_upcall(struct rpc_task *task) +{ + struct rpc_cred *cred = task->tk_msg.rpc_cred; + struct gss_auth *gss_auth = container_of(task->tk_client->cl_auth, + struct gss_auth, rpc_auth); + struct gss_cred *gss_cred = container_of(cred, + struct gss_cred, gc_base); + struct gss_upcall_msg *gss_msg; + int err = 0; + + dprintk("RPC: %4u gss_refresh_upcall for uid %u\n", task->tk_pid, cred->cr_uid); + gss_msg = gss_setup_upcall(task->tk_client, gss_auth, cred); + if (IS_ERR(gss_msg)) { + err = PTR_ERR(gss_msg); + goto out; } - gss_msg = gss_new; - memset(gss_new, 0, sizeof(*gss_new)); - INIT_LIST_HEAD(&gss_new->list); - rpc_init_wait_queue(&gss_new->waitq, "RPCSEC_GSS upcall waitq"); - atomic_set(&gss_new->count, 2); - msg = &gss_new->msg; - msg->data = &gss_new->uid; - msg->len = sizeof(gss_new->uid); - gss_new->uid = uid; - gss_new->auth = gss_auth; - list_add(&gss_new->list, &gss_auth->upcalls); - gss_new = NULL; - /* Has someone updated the credential behind our back? */ - if (!gss_cred_is_uptodate_ctx(cred)) { - /* No, so do upcall and sleep */ + spin_lock(&gss_auth->lock); + if (gss_cred->gc_upcall != NULL) + rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL, NULL); + else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) { task->tk_timeout = 0; - rpc_sleep_on(&gss_msg->waitq, task, NULL, NULL); - spin_unlock(&gss_auth->lock); - res = rpc_queue_upcall(dentry->d_inode, msg); - if (res) - gss_unhash_msg(gss_msg); - } else { - /* Yes, so cancel upcall */ - __gss_unhash_msg(gss_msg); + gss_cred->gc_upcall = gss_msg; + /* gss_upcall_callback will release the reference to gss_upcall_msg */ + atomic_inc(&gss_msg->count); + rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback, NULL); + } else + err = gss_msg->msg.errno; + spin_unlock(&gss_auth->lock); + gss_release_msg(gss_msg); +out: + dprintk("RPC: %4u gss_refresh_upcall for uid %u result %d\n", task->tk_pid, + cred->cr_uid, err); + return err; +} + +static inline int +gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) +{ + struct rpc_cred *cred = &gss_cred->gc_base; + struct gss_upcall_msg *gss_msg; + DEFINE_WAIT(wait); + int err = 0; + + dprintk("RPC: gss_upcall for uid %u\n", cred->cr_uid); + gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred); + if (IS_ERR(gss_msg)) { + err = PTR_ERR(gss_msg); + goto out; + } + for (;;) { + prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_INTERRUPTIBLE); + spin_lock(&gss_auth->lock); + if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) { + spin_unlock(&gss_auth->lock); + break; + } spin_unlock(&gss_auth->lock); + if (signalled()) { + err = -ERESTARTSYS; + goto out_intr; + } + schedule(); } + if (gss_msg->ctx) + gss_cred_set_ctx(cred, gss_get_ctx(gss_msg->ctx)); + else + err = gss_msg->msg.errno; +out_intr: + finish_wait(&gss_msg->waitqueue, &wait); gss_release_msg(gss_msg); - dprintk("RPC: %4u gss_upcall for uid %u result %d\n", task->tk_pid, - uid, res); - return res; -out_sleep: - task->tk_timeout = 0; - rpc_sleep_on(&gss_msg->waitq, task, NULL, NULL); - spin_unlock(&gss_auth->lock); - dprintk("RPC: %4u gss_upcall sleeping\n", task->tk_pid); - if (gss_new) - kfree(gss_new); - /* Note: we drop the reference here: we are automatically removed - * from the queue when we're woken up, and we should in any case - * have no further responsabilities w.r.t. the upcall. - */ - gss_release_msg(gss_msg); - return 0; +out: + dprintk("RPC: gss_create_upcall for uid %u result %d\n", cred->cr_uid, err); + return err; } static ssize_t @@ -441,68 +528,75 @@ gss_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg, static ssize_t gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) { - struct xdr_netobj obj = { - .len = mlen, - }; - struct inode *inode = filp->f_dentry->d_inode; - struct rpc_inode *rpci = RPC_I(inode); + const void *p, *end; + void *buf; struct rpc_clnt *clnt; - struct rpc_auth *auth; struct gss_auth *gss_auth; - struct gss_api_mech *mech; - struct auth_cred acred = { 0 }; struct rpc_cred *cred; struct gss_upcall_msg *gss_msg; - struct gss_cl_ctx *ctx = NULL; - ssize_t left; - int err; - int gss_err; + struct gss_cl_ctx *ctx; + uid_t uid; + int err = -EFBIG; if (mlen > MSG_BUF_MAXSIZE) - return -EFBIG; - obj.data = kmalloc(mlen, GFP_KERNEL); - if (!obj.data) - return -ENOMEM; - left = copy_from_user(obj.data, src, mlen); - if (left) { - err = -EFAULT; goto out; - } - clnt = rpci->private; - atomic_inc(&clnt->cl_users); - auth = clnt->cl_auth; - gss_auth = container_of(auth, struct gss_auth, rpc_auth); - mech = gss_auth->mech; - err = gss_parse_init_downcall(mech, &obj, &ctx, &acred.uid, &gss_err); - if (err) + err = -ENOMEM; + buf = kmalloc(mlen, GFP_KERNEL); + if (!buf) + goto out; + + clnt = RPC_I(filp->f_dentry->d_inode)->private; + err = -EFAULT; + if (copy_from_user(buf, src, mlen)) goto err; - cred = rpcauth_lookup_credcache(auth, &acred, 0); - if (!cred) + + end = (const void *)((char *)buf + mlen); + p = simple_get_bytes(buf, end, &uid, sizeof(uid)); + if (IS_ERR(p)) { + err = PTR_ERR(p); goto err; - if (gss_err) - cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; - else - gss_cred_set_ctx(cred, ctx); + } + + err = -ENOMEM; + ctx = gss_alloc_context(); + if (ctx == NULL) + goto err; + err = 0; + gss_auth = container_of(clnt->cl_auth, struct gss_auth, rpc_auth); + p = gss_fill_context(p, end, ctx, gss_auth->mech); + if (IS_ERR(p)) { + err = PTR_ERR(p); + if (err != -EACCES) + goto err_put_ctx; + } spin_lock(&gss_auth->lock); - gss_msg = __gss_find_upcall(gss_auth, acred.uid); + gss_msg = __gss_find_upcall(gss_auth, uid); if (gss_msg) { - if (gss_err) - gss_msg->msg.errno = -EACCES; + if (err == 0 && gss_msg->ctx == NULL) + gss_msg->ctx = gss_get_ctx(ctx); + gss_msg->msg.errno = err; __gss_unhash_msg(gss_msg); spin_unlock(&gss_auth->lock); gss_release_msg(gss_msg); - } else + } else { + struct auth_cred acred = { .uid = uid }; spin_unlock(&gss_auth->lock); - rpc_release_client(clnt); - kfree(obj.data); + cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, 0); + if (IS_ERR(cred)) { + err = PTR_ERR(cred); + goto err_put_ctx; + } + gss_cred_set_ctx(cred, gss_get_ctx(ctx)); + } + gss_put_ctx(ctx); + kfree(buf); dprintk("RPC: gss_pipe_downcall returning length %Zu\n", mlen); return mlen; +err_put_ctx: + gss_put_ctx(ctx); err: - if (ctx) - gss_destroy_ctx(ctx); - rpc_release_client(clnt); + kfree(buf); out: - kfree(obj.data); dprintk("RPC: gss_pipe_downcall returning %d\n", err); return err; } @@ -569,24 +663,32 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) dprintk("RPC: creating GSS authenticator for client %p\n",clnt); + if (!try_module_get(THIS_MODULE)) + return NULL; if (!(gss_auth = kmalloc(sizeof(*gss_auth), GFP_KERNEL))) goto out_dec; + gss_auth->client = clnt; gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor); if (!gss_auth->mech) { printk(KERN_WARNING "%s: Pseudoflavor %d not found!", __FUNCTION__, flavor); goto err_free; } + gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor); + /* FIXME: Will go away once privacy support is merged in */ + if (gss_auth->service == RPC_GSS_SVC_PRIVACY) + gss_auth->service = RPC_GSS_SVC_INTEGRITY; INIT_LIST_HEAD(&gss_auth->upcalls); spin_lock_init(&gss_auth->lock); auth = &gss_auth->rpc_auth; auth->au_cslack = GSS_CRED_SLACK >> 2; auth->au_rslack = GSS_VERF_SLACK >> 2; - auth->au_expire = GSS_CRED_EXPIRE; auth->au_ops = &authgss_ops; auth->au_flavor = flavor; + atomic_set(&auth->au_count, 1); - rpcauth_init_credcache(auth); + if (rpcauth_init_credcache(auth, GSS_CRED_EXPIRE) < 0) + goto err_put_mech; snprintf(gss_auth->path, sizeof(gss_auth->path), "%s/%s", clnt->cl_pathname, @@ -601,6 +703,7 @@ err_put_mech: err_free: kfree(gss_auth); out_dec: + module_put(THIS_MODULE); return NULL; } @@ -617,6 +720,8 @@ gss_destroy(struct rpc_auth *auth) gss_mech_put(gss_auth->mech); rpcauth_free_credcache(auth); + kfree(gss_auth); + module_put(THIS_MODULE); } /* gss_destroy_cred (and gss_destroy_ctx) are used to clean up after failure @@ -630,19 +735,14 @@ gss_destroy_ctx(struct gss_cl_ctx *ctx) if (ctx->gc_gss_ctx) gss_delete_sec_context(&ctx->gc_gss_ctx); - if (ctx->gc_wire_ctx.len > 0) { - kfree(ctx->gc_wire_ctx.data); - ctx->gc_wire_ctx.len = 0; - } - + kfree(ctx->gc_wire_ctx.data); kfree(ctx); - } static void gss_destroy_cred(struct rpc_cred *rc) { - struct gss_cred *cred = (struct gss_cred *)rc; + struct gss_cred *cred = container_of(rc, struct gss_cred, gc_base); dprintk("RPC: gss_destroy_cred \n"); @@ -651,10 +751,21 @@ gss_destroy_cred(struct rpc_cred *rc) kfree(cred); } +/* + * Lookup RPCSEC_GSS cred for the current process + */ +static struct rpc_cred * +gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags) +{ + return rpcauth_lookup_credcache(auth, acred, taskflags); +} + static struct rpc_cred * gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags) { + struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth); struct gss_cred *cred = NULL; + int err = -ENOMEM; dprintk("RPC: gss_create_cred for uid %d, flavor %d\n", acred->uid, auth->au_flavor); @@ -663,7 +774,7 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags) goto out_err; memset(cred, 0, sizeof(*cred)); - atomic_set(&cred->gc_count, 0); + atomic_set(&cred->gc_count, 1); cred->gc_uid = acred->uid; /* * Note: in order to force a call to call_refresh(), we deliberately @@ -671,19 +782,27 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags) */ cred->gc_flags = 0; cred->gc_base.cr_ops = &gss_credops; - cred->gc_flavor = auth->au_flavor; + cred->gc_service = gss_auth->service; + err = gss_create_upcall(gss_auth, cred); + if (err < 0) + goto out_err; - return (struct rpc_cred *) cred; + return &cred->gc_base; out_err: - dprintk("RPC: gss_create_cred failed\n"); - if (cred) gss_destroy_cred((struct rpc_cred *)cred); - return NULL; + dprintk("RPC: gss_create_cred failed with error %d\n", err); + if (cred) gss_destroy_cred(&cred->gc_base); + return ERR_PTR(err); } static int gss_match(struct auth_cred *acred, struct rpc_cred *rc, int taskflags) { + struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); + + /* Don't match with creds that have expired. */ + if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry)) + return 0; return (rc->cr_uid == acred->uid); } @@ -692,7 +811,7 @@ gss_match(struct auth_cred *acred, struct rpc_cred *rc, int taskflags) * Maybe we should keep a cached credential for performance reasons. */ static u32 * -gss_marshal(struct rpc_task *task, u32 *p, int ruid) +gss_marshal(struct rpc_task *task, u32 *p) { struct rpc_cred *cred = task->tk_msg.rpc_cred; struct gss_cred *gss_cred = container_of(cred, struct gss_cred, @@ -704,20 +823,12 @@ gss_marshal(struct rpc_task *task, u32 *p, int ruid) struct xdr_netobj mic; struct kvec iov; struct xdr_buf verf_buf; - u32 service; dprintk("RPC: %4u gss_marshal\n", task->tk_pid); *p++ = htonl(RPC_AUTH_GSS); cred_len = p++; - service = gss_pseudoflavor_to_service(ctx->gc_gss_ctx->mech_type, - gss_cred->gc_flavor); - if (service == 0) { - dprintk("RPC: %4u Bad pseudoflavor %d in gss_marshal\n", - task->tk_pid, gss_cred->gc_flavor); - goto out_put_ctx; - } spin_lock(&ctx->gc_seq_lock); req->rq_seqno = ctx->gc_seq++; spin_unlock(&ctx->gc_seq_lock); @@ -725,7 +836,7 @@ gss_marshal(struct rpc_task *task, u32 *p, int ruid) *p++ = htonl((u32) RPC_GSS_VERSION); *p++ = htonl((u32) ctx->gc_proc); *p++ = htonl((u32) req->rq_seqno); - *p++ = htonl((u32) service); + *p++ = htonl((u32) gss_cred->gc_service); p = xdr_encode_netobj(p, &ctx->gc_wire_ctx); *cred_len = htonl((p - (cred_len + 1)) << 2); @@ -765,11 +876,9 @@ out_put_ctx: static int gss_refresh(struct rpc_task *task) { - struct rpc_clnt *clnt = task->tk_client; - struct rpc_cred *cred = task->tk_msg.rpc_cred; - if (!gss_cred_is_uptodate_ctx(cred)) - return gss_upcall(clnt, task, cred); + if (!gss_cred_is_uptodate_ctx(task->tk_msg.rpc_cred)) + return gss_refresh_upcall(task); return 0; } @@ -785,7 +894,6 @@ gss_validate(struct rpc_task *task, u32 *p) struct xdr_buf verf_buf; struct xdr_netobj mic; u32 flav,len; - u32 service; u32 maj_stat; dprintk("RPC: %4u gss_validate\n", task->tk_pid); @@ -807,9 +915,7 @@ gss_validate(struct rpc_task *task, u32 *p) cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; if (maj_stat) goto out_bad; - service = gss_pseudoflavor_to_service(ctx->gc_gss_ctx->mech_type, - gss_cred->gc_flavor); - switch (service) { + switch (gss_cred->gc_service) { case RPC_GSS_SVC_NONE: /* verifier data, flavor, length: */ task->tk_auth->au_rslack = XDR_QUADLEN(len) + 2; @@ -818,7 +924,7 @@ gss_validate(struct rpc_task *task, u32 *p) /* verifier data, flavor, length, length, sequence number: */ task->tk_auth->au_rslack = XDR_QUADLEN(len) + 4; break; - default: + case RPC_GSS_SVC_PRIVACY: goto out_bad; } gss_put_ctx(ctx); @@ -889,7 +995,6 @@ gss_wrap_req(struct rpc_task *task, gc_base); struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); int status = -EIO; - u32 service; dprintk("RPC: %4u gss_wrap_req\n", task->tk_pid); if (ctx->gc_proc != RPC_GSS_PROC_DATA) { @@ -899,19 +1004,16 @@ gss_wrap_req(struct rpc_task *task, status = encode(rqstp, p, obj); goto out; } - service = gss_pseudoflavor_to_service(ctx->gc_gss_ctx->mech_type, - gss_cred->gc_flavor); - switch (service) { + switch (gss_cred->gc_service) { case RPC_GSS_SVC_NONE: status = encode(rqstp, p, obj); - goto out; + break; case RPC_GSS_SVC_INTEGRITY: status = gss_wrap_req_integ(cred, ctx, encode, rqstp, p, obj); - goto out; - case RPC_GSS_SVC_PRIVACY: - default: - goto out; + break; + case RPC_GSS_SVC_PRIVACY: + break; } out: gss_put_ctx(ctx); @@ -966,23 +1068,19 @@ gss_unwrap_resp(struct rpc_task *task, gc_base); struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); int status = -EIO; - u32 service; if (ctx->gc_proc != RPC_GSS_PROC_DATA) goto out_decode; - service = gss_pseudoflavor_to_service(ctx->gc_gss_ctx->mech_type, - gss_cred->gc_flavor); - switch (service) { + switch (gss_cred->gc_service) { case RPC_GSS_SVC_NONE: - goto out_decode; + break; case RPC_GSS_SVC_INTEGRITY: status = gss_unwrap_resp_integ(cred, ctx, rqstp, &p); if (status) goto out; break; - case RPC_GSS_SVC_PRIVACY: - default: - goto out; + case RPC_GSS_SVC_PRIVACY: + break; } out_decode: status = decode(rqstp, p, obj); @@ -1001,10 +1099,12 @@ static struct rpc_authops authgss_ops = { #endif .create = gss_create, .destroy = gss_destroy, + .lookup_cred = gss_lookup_cred, .crcreate = gss_create_cred }; static struct rpc_credops gss_credops = { + .cr_name = "AUTH_GSS", .crdestroy = gss_destroy_cred, .crmatch = gss_match, .crmarshal = gss_marshal, diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index a734dd869518..cf726510df8e 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c @@ -48,46 +48,48 @@ # define RPCDBG_FACILITY RPCDBG_AUTH #endif -static inline int -get_bytes(char **ptr, const char *end, void *res, int len) +static const void * +simple_get_bytes(const void *p, const void *end, void *res, int len) { - char *p, *q; - p = *ptr; - q = p + len; - if (q > end || q < p) - return -1; + const void *q = (const void *)((const char *)p + len); + if (unlikely(q > end || q < p)) + return ERR_PTR(-EFAULT); memcpy(res, p, len); - *ptr = q; - return 0; + return q; } -static inline int -get_netobj(char **ptr, const char *end, struct xdr_netobj *res) +static const void * +simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res) { - char *p, *q; - p = *ptr; - if (get_bytes(&p, end, &res->len, sizeof(res->len))) - return -1; - q = p + res->len; - if (q > end || q < p) - return -1; - if (!(res->data = kmalloc(res->len, GFP_KERNEL))) - return -1; - memcpy(res->data, p, res->len); - *ptr = q; - return 0; + const void *q; + unsigned int len; + + p = simple_get_bytes(p, end, &len, sizeof(len)); + if (IS_ERR(p)) + return p; + q = (const void *)((const char *)p + len); + if (unlikely(q > end || q < p)) + return ERR_PTR(-EFAULT); + res->data = kmalloc(len, GFP_KERNEL); + if (unlikely(res->data == NULL)) + return ERR_PTR(-ENOMEM); + memcpy(res->data, p, len); + res->len = len; + return q; } -static inline int -get_key(char **p, char *end, struct crypto_tfm **res) +static inline const void * +get_key(const void *p, const void *end, struct crypto_tfm **res) { struct xdr_netobj key; int alg, alg_mode; char *alg_name; - if (get_bytes(p, end, &alg, sizeof(alg))) + p = simple_get_bytes(p, end, &alg, sizeof(alg)); + if (IS_ERR(p)) goto out_err; - if ((get_netobj(p, end, &key))) + p = simple_get_netobj(p, end, &key); + if (IS_ERR(p)) goto out_err; switch (alg) { @@ -105,50 +107,63 @@ get_key(char **p, char *end, struct crypto_tfm **res) goto out_err_free_tfm; kfree(key.data); - return 0; + return p; out_err_free_tfm: crypto_free_tfm(*res); out_err_free_key: kfree(key.data); + p = ERR_PTR(-EINVAL); out_err: - return -1; + return p; } -static u32 -gss_import_sec_context_kerberos(struct xdr_netobj *inbuf, +static int +gss_import_sec_context_kerberos(const void *p, + size_t len, struct gss_ctx *ctx_id) { - char *p = inbuf->data; - char *end = inbuf->data + inbuf->len; + const void *end = (const void *)((const char *)p + len); struct krb5_ctx *ctx; if (!(ctx = kmalloc(sizeof(*ctx), GFP_KERNEL))) goto out_err; memset(ctx, 0, sizeof(*ctx)); - if (get_bytes(&p, end, &ctx->initiate, sizeof(ctx->initiate))) + p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate)); + if (IS_ERR(p)) goto out_err_free_ctx; - if (get_bytes(&p, end, &ctx->seed_init, sizeof(ctx->seed_init))) + p = simple_get_bytes(p, end, &ctx->seed_init, sizeof(ctx->seed_init)); + if (IS_ERR(p)) goto out_err_free_ctx; - if (get_bytes(&p, end, ctx->seed, sizeof(ctx->seed))) + p = simple_get_bytes(p, end, ctx->seed, sizeof(ctx->seed)); + if (IS_ERR(p)) goto out_err_free_ctx; - if (get_bytes(&p, end, &ctx->signalg, sizeof(ctx->signalg))) + p = simple_get_bytes(p, end, &ctx->signalg, sizeof(ctx->signalg)); + if (IS_ERR(p)) goto out_err_free_ctx; - if (get_bytes(&p, end, &ctx->sealalg, sizeof(ctx->sealalg))) + p = simple_get_bytes(p, end, &ctx->sealalg, sizeof(ctx->sealalg)); + if (IS_ERR(p)) goto out_err_free_ctx; - if (get_bytes(&p, end, &ctx->endtime, sizeof(ctx->endtime))) + p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime)); + if (IS_ERR(p)) goto out_err_free_ctx; - if (get_bytes(&p, end, &ctx->seq_send, sizeof(ctx->seq_send))) + p = simple_get_bytes(p, end, &ctx->seq_send, sizeof(ctx->seq_send)); + if (IS_ERR(p)) goto out_err_free_ctx; - if (get_netobj(&p, end, &ctx->mech_used)) + p = simple_get_netobj(p, end, &ctx->mech_used); + if (IS_ERR(p)) goto out_err_free_ctx; - if (get_key(&p, end, &ctx->enc)) + p = get_key(p, end, &ctx->enc); + if (IS_ERR(p)) goto out_err_free_mech; - if (get_key(&p, end, &ctx->seq)) + p = get_key(p, end, &ctx->seq); + if (IS_ERR(p)) goto out_err_free_key1; - if (p != end) + if (p != end) { + p = ERR_PTR(-EFAULT); goto out_err_free_key2; + } ctx_id->internal_ctx_id = ctx; dprintk("RPC: Succesfully imported new context.\n"); @@ -163,7 +178,7 @@ out_err_free_mech: out_err_free_ctx: kfree(ctx); out_err: - return GSS_S_FAILURE; + return PTR_ERR(p); } static void diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index a0db9f5004f1..9dfb68377d69 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c @@ -143,7 +143,7 @@ gss_mech_get(struct gss_api_mech *gm) EXPORT_SYMBOL(gss_mech_get); struct gss_api_mech * -gss_mech_get_by_name(char *name) +gss_mech_get_by_name(const char *name) { struct gss_api_mech *pos, *gm = NULL; @@ -233,8 +233,8 @@ EXPORT_SYMBOL(gss_mech_put); /* The mech could probably be determined from the token instead, but it's just * as easy for now to pass it in. */ -u32 -gss_import_sec_context(struct xdr_netobj *input_token, +int +gss_import_sec_context(const void *input_token, size_t bufsize, struct gss_api_mech *mech, struct gss_ctx **ctx_id) { @@ -244,7 +244,7 @@ gss_import_sec_context(struct xdr_netobj *input_token, (*ctx_id)->mech_type = gss_mech_get(mech); return mech->gm_ops - ->gss_import_sec_context(input_token, *ctx_id); + ->gss_import_sec_context(input_token, bufsize, *ctx_id); } /* gss_get_mic: compute a mic over message and return mic_token. */ diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c index fd213dc36093..dad05994c3eb 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_mech.c +++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c @@ -49,52 +49,51 @@ # define RPCDBG_FACILITY RPCDBG_AUTH #endif -static inline int -get_bytes(char **ptr, const char *end, void *res, int len) +static const void * +simple_get_bytes(const void *p, const void *end, void *res, int len) { - char *p, *q; - p = *ptr; - q = p + len; - if (q > end || q < p) - return -1; + const void *q = (const void *)((const char *)p + len); + if (unlikely(q > end || q < p)) + return ERR_PTR(-EFAULT); memcpy(res, p, len); - *ptr = q; - return 0; + return q; } -static inline int -get_netobj(char **ptr, const char *end, struct xdr_netobj *res) +static const void * +simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res) { - char *p, *q; - p = *ptr; - if (get_bytes(&p, end, &res->len, sizeof(res->len))) - return -1; - q = p + res->len; - if(res->len == 0) - goto out_nocopy; - if (q > end || q < p) - return -1; - if (!(res->data = kmalloc(res->len, GFP_KERNEL))) - return -1; - memcpy(res->data, p, res->len); -out_nocopy: - *ptr = q; - return 0; + const void *q; + unsigned int len; + p = simple_get_bytes(p, end, &len, sizeof(len)); + if (IS_ERR(p)) + return p; + res->len = len; + if (len == 0) { + res->data = NULL; + return p; + } + q = (const void *)((const char *)p + len); + if (unlikely(q > end || q < p)) + return ERR_PTR(-EFAULT); + res->data = kmalloc(len, GFP_KERNEL); + if (unlikely(res->data == NULL)) + return ERR_PTR(-ENOMEM); + memcpy(res->data, p, len); + return q; } -static inline int -get_key(char **p, char *end, struct crypto_tfm **res, int *resalg) +static inline const void * +get_key(const void *p, const void *end, struct crypto_tfm **res, int *resalg) { - struct xdr_netobj key = { - .len = 0, - .data = NULL, - }; + struct xdr_netobj key = { 0 }; int alg_mode,setkey = 0; char *alg_name; - if (get_bytes(p, end, resalg, sizeof(int))) + p = simple_get_bytes(p, end, resalg, sizeof(*resalg)); + if (IS_ERR(p)) goto out_err; - if ((get_netobj(p, end, &key))) + p = simple_get_netobj(p, end, &key); + if (IS_ERR(p)) goto out_err; switch (*resalg) { @@ -111,10 +110,6 @@ get_key(char **p, char *end, struct crypto_tfm **res, int *resalg) alg_mode = 0; setkey = 0; break; - case NID_cast5_cbc: - dprintk("RPC: SPKM3 get_key: case cast5_cbc, UNSUPPORTED \n"); - goto out_err; - break; default: dprintk("RPC: SPKM3 get_key: unsupported algorithm %d", *resalg); goto out_err_free_key; @@ -128,69 +123,81 @@ get_key(char **p, char *end, struct crypto_tfm **res, int *resalg) if(key.len > 0) kfree(key.data); - return 0; + return p; out_err_free_tfm: crypto_free_tfm(*res); out_err_free_key: if(key.len > 0) kfree(key.data); + p = ERR_PTR(-EINVAL); out_err: - return -1; + return p; } -static u32 -gss_import_sec_context_spkm3(struct xdr_netobj *inbuf, +static int +gss_import_sec_context_spkm3(const void *p, size_t len, struct gss_ctx *ctx_id) { - char *p = inbuf->data; - char *end = inbuf->data + inbuf->len; + const void *end = (const void *)((const char *)p + len); struct spkm3_ctx *ctx; if (!(ctx = kmalloc(sizeof(*ctx), GFP_KERNEL))) goto out_err; memset(ctx, 0, sizeof(*ctx)); - if (get_netobj(&p, end, &ctx->ctx_id)) + p = simple_get_netobj(p, end, &ctx->ctx_id); + if (IS_ERR(p)) goto out_err_free_ctx; - if (get_bytes(&p, end, &ctx->qop, sizeof(ctx->qop))) + p = simple_get_bytes(p, end, &ctx->qop, sizeof(ctx->qop)); + if (IS_ERR(p)) goto out_err_free_ctx_id; - if (get_netobj(&p, end, &ctx->mech_used)) + p = simple_get_netobj(p, end, &ctx->mech_used); + if (IS_ERR(p)) goto out_err_free_mech; - if (get_bytes(&p, end, &ctx->ret_flags, sizeof(ctx->ret_flags))) + p = simple_get_bytes(p, end, &ctx->ret_flags, sizeof(ctx->ret_flags)); + if (IS_ERR(p)) goto out_err_free_mech; - if (get_bytes(&p, end, &ctx->req_flags, sizeof(ctx->req_flags))) + p = simple_get_bytes(p, end, &ctx->req_flags, sizeof(ctx->req_flags)); + if (IS_ERR(p)) goto out_err_free_mech; - if (get_netobj(&p, end, &ctx->share_key)) + p = simple_get_netobj(p, end, &ctx->share_key); + if (IS_ERR(p)) goto out_err_free_s_key; - if (get_key(&p, end, &ctx->derived_conf_key, &ctx->conf_alg)) { - dprintk("RPC: SPKM3 confidentiality key will be NULL\n"); - } + p = get_key(p, end, &ctx->derived_conf_key, &ctx->conf_alg); + if (IS_ERR(p)) + goto out_err_free_s_key; - if (get_key(&p, end, &ctx->derived_integ_key, &ctx->intg_alg)) { - dprintk("RPC: SPKM3 integrity key will be NULL\n"); - } + p = get_key(p, end, &ctx->derived_integ_key, &ctx->intg_alg); + if (IS_ERR(p)) + goto out_err_free_key1; - if (get_bytes(&p, end, &ctx->owf_alg, sizeof(ctx->owf_alg))) - goto out_err_free_s_key; + p = simple_get_bytes(p, end, &ctx->keyestb_alg, sizeof(ctx->keyestb_alg)); + if (IS_ERR(p)) + goto out_err_free_key2; - if (get_bytes(&p, end, &ctx->owf_alg, sizeof(ctx->owf_alg))) - goto out_err_free_s_key; + p = simple_get_bytes(p, end, &ctx->owf_alg, sizeof(ctx->owf_alg)); + if (IS_ERR(p)) + goto out_err_free_key2; if (p != end) - goto out_err_free_s_key; + goto out_err_free_key2; ctx_id->internal_ctx_id = ctx; dprintk("Succesfully imported new spkm context.\n"); return 0; +out_err_free_key2: + crypto_free_tfm(ctx->derived_integ_key); +out_err_free_key1: + crypto_free_tfm(ctx->derived_conf_key); out_err_free_s_key: kfree(ctx->share_key.data); out_err_free_mech: @@ -200,7 +207,7 @@ out_err_free_ctx_id: out_err_free_ctx: kfree(ctx); out_err: - return GSS_S_FAILURE; + return PTR_ERR(p); } static void diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index d806bafe106c..5c8fe3bfc494 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -381,7 +381,6 @@ static int rsc_parse(struct cache_detail *cd, else { int N, i; struct gss_api_mech *gm; - struct xdr_netobj tmp_buf; /* gid */ if (get_int(&mesg, &rsci.cred.cr_gid)) @@ -420,9 +419,7 @@ static int rsc_parse(struct cache_detail *cd, gss_mech_put(gm); goto out; } - tmp_buf.len = len; - tmp_buf.data = buf; - if (gss_import_sec_context(&tmp_buf, gm, &rsci.mechctx)) { + if (gss_import_sec_context(buf, len, gm, &rsci.mechctx)) { gss_mech_put(gm); goto out; } diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c index f112f63e3705..aa3dd1098f38 100644 --- a/net/sunrpc/auth_null.c +++ b/net/sunrpc/auth_null.c @@ -18,48 +18,29 @@ # define RPCDBG_FACILITY RPCDBG_AUTH #endif -static struct rpc_credops null_credops; +static struct rpc_auth null_auth; +static struct rpc_cred null_cred; static struct rpc_auth * nul_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) { - struct rpc_auth *auth; - - dprintk("RPC: creating NULL authenticator for client %p\n", clnt); - if (!(auth = (struct rpc_auth *) kmalloc(sizeof(*auth),GFP_KERNEL))) - return NULL; - auth->au_cslack = 4; - auth->au_rslack = 2; - auth->au_ops = &authnull_ops; - auth->au_expire = 1800 * HZ; - rpcauth_init_credcache(auth); - - return (struct rpc_auth *) auth; + atomic_inc(&null_auth.au_count); + return &null_auth; } static void nul_destroy(struct rpc_auth *auth) { - dprintk("RPC: destroying NULL authenticator %p\n", auth); - rpcauth_free_credcache(auth); + atomic_dec(&null_auth.au_count); } /* - * Create NULL creds for current process + * Lookup NULL creds for current process */ static struct rpc_cred * -nul_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) +nul_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) { - struct rpc_cred *cred; - - if (!(cred = (struct rpc_cred *) kmalloc(sizeof(*cred),GFP_KERNEL))) - return NULL; - atomic_set(&cred->cr_count, 0); - cred->cr_flags = RPCAUTH_CRED_UPTODATE; - cred->cr_uid = acred->uid; - cred->cr_ops = &null_credops; - - return cred; + return get_rpccred(&null_cred); } /* @@ -68,7 +49,6 @@ nul_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) static void nul_destroy_cred(struct rpc_cred *cred) { - kfree(cred); } /* @@ -84,7 +64,7 @@ nul_match(struct auth_cred *acred, struct rpc_cred *cred, int taskflags) * Marshal credential. */ static u32 * -nul_marshal(struct rpc_task *task, u32 *p, int ruid) +nul_marshal(struct rpc_task *task, u32 *p) { *p++ = htonl(RPC_AUTH_NULL); *p++ = 0; @@ -125,7 +105,7 @@ nul_validate(struct rpc_task *task, u32 *p) return p; } -struct rpc_authops authnull_ops = { +struct rpc_authops authnull_ops = { .owner = THIS_MODULE, .au_flavor = RPC_AUTH_NULL, #ifdef RPC_DEBUG @@ -133,14 +113,32 @@ struct rpc_authops authnull_ops = { #endif .create = nul_create, .destroy = nul_destroy, - .crcreate = nul_create_cred, + .lookup_cred = nul_lookup_cred, +}; + +static +struct rpc_auth null_auth = { + .au_cslack = 4, + .au_rslack = 2, + .au_ops = &authnull_ops, }; static struct rpc_credops null_credops = { + .cr_name = "AUTH_NULL", .crdestroy = nul_destroy_cred, .crmatch = nul_match, .crmarshal = nul_marshal, .crrefresh = nul_refresh, .crvalidate = nul_validate, }; + +static +struct rpc_cred null_cred = { + .cr_ops = &null_credops, + .cr_count = ATOMIC_INIT(1), + .cr_flags = RPCAUTH_CRED_UPTODATE, +#ifdef RPC_DEBUG + .cr_magic = RPCAUTH_CRED_MAGIC, +#endif +}; diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c index f49ed17fe3fb..4ff297a9b15b 100644 --- a/net/sunrpc/auth_unix.c +++ b/net/sunrpc/auth_unix.c @@ -19,8 +19,6 @@ struct unx_cred { struct rpc_cred uc_base; gid_t uc_gid; - uid_t uc_puid; /* process uid */ - gid_t uc_pgid; /* process gid */ gid_t uc_gids[NFS_NGROUPS]; }; #define uc_uid uc_base.cr_uid @@ -36,24 +34,17 @@ struct unx_cred { # define RPCDBG_FACILITY RPCDBG_AUTH #endif +static struct rpc_auth unix_auth; +static struct rpc_cred_cache unix_cred_cache; static struct rpc_credops unix_credops; static struct rpc_auth * unx_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) { - struct rpc_auth *auth; - dprintk("RPC: creating UNIX authenticator for client %p\n", clnt); - if (!(auth = (struct rpc_auth *) kmalloc(sizeof(*auth), GFP_KERNEL))) - return NULL; - auth->au_cslack = UNX_WRITESLACK; - auth->au_rslack = 2; /* assume AUTH_NULL verf */ - auth->au_expire = UNX_CRED_EXPIRE; - auth->au_ops = &authunix_ops; - - rpcauth_init_credcache(auth); - - return auth; + if (atomic_inc_return(&unix_auth.au_count) == 0) + unix_cred_cache.nextgc = jiffies + (unix_cred_cache.expire >> 1); + return &unix_auth; } static void @@ -63,6 +54,15 @@ unx_destroy(struct rpc_auth *auth) rpcauth_free_credcache(auth); } +/* + * Lookup AUTH_UNIX creds for current process + */ +static struct rpc_cred * +unx_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) +{ + return rpcauth_lookup_credcache(auth, acred, flags); +} + static struct rpc_cred * unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) { @@ -73,13 +73,13 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) acred->uid, acred->gid); if (!(cred = (struct unx_cred *) kmalloc(sizeof(*cred), GFP_KERNEL))) - return NULL; + return ERR_PTR(-ENOMEM); - atomic_set(&cred->uc_count, 0); + atomic_set(&cred->uc_count, 1); cred->uc_flags = RPCAUTH_CRED_UPTODATE; if (flags & RPC_TASK_ROOTCREDS) { - cred->uc_uid = cred->uc_puid = 0; - cred->uc_gid = cred->uc_pgid = 0; + cred->uc_uid = 0; + cred->uc_gid = 0; cred->uc_gids[0] = NOGROUP; } else { int groups = acred->group_info->ngroups; @@ -88,8 +88,6 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) cred->uc_uid = acred->uid; cred->uc_gid = acred->gid; - cred->uc_puid = current->uid; - cred->uc_pgid = current->gid; for (i = 0; i < groups; i++) cred->uc_gids[i] = GROUP_AT(acred->group_info, i); if (i < NFS_NGROUPS) @@ -121,9 +119,7 @@ unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int taskflags) int groups; if (cred->uc_uid != acred->uid - || cred->uc_gid != acred->gid - || cred->uc_puid != current->uid - || cred->uc_pgid != current->gid) + || cred->uc_gid != acred->gid) return 0; groups = acred->group_info->ngroups; @@ -134,8 +130,8 @@ unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int taskflags) return 0; return 1; } - return (cred->uc_uid == 0 && cred->uc_puid == 0 - && cred->uc_gid == 0 && cred->uc_pgid == 0 + return (cred->uc_uid == 0 + && cred->uc_gid == 0 && cred->uc_gids[0] == (gid_t) NOGROUP); } @@ -144,7 +140,7 @@ unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int taskflags) * Maybe we should keep a cached credential for performance reasons. */ static u32 * -unx_marshal(struct rpc_task *task, u32 *p, int ruid) +unx_marshal(struct rpc_task *task, u32 *p) { struct rpc_clnt *clnt = task->tk_client; struct unx_cred *cred = (struct unx_cred *) task->tk_msg.rpc_cred; @@ -160,14 +156,8 @@ unx_marshal(struct rpc_task *task, u32 *p, int ruid) */ p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen); - /* Note: we don't use real uid if it involves raising privilege */ - if (ruid && cred->uc_puid != 0 && cred->uc_pgid != 0) { - *p++ = htonl((u32) cred->uc_puid); - *p++ = htonl((u32) cred->uc_pgid); - } else { - *p++ = htonl((u32) cred->uc_uid); - *p++ = htonl((u32) cred->uc_gid); - } + *p++ = htonl((u32) cred->uc_uid); + *p++ = htonl((u32) cred->uc_gid); hold = p++; for (i = 0; i < 16 && cred->uc_gids[i] != (gid_t) NOGROUP; i++) *p++ = htonl((u32) cred->uc_gids[i]); @@ -223,11 +213,27 @@ struct rpc_authops authunix_ops = { #endif .create = unx_create, .destroy = unx_destroy, + .lookup_cred = unx_lookup_cred, .crcreate = unx_create_cred, }; static +struct rpc_cred_cache unix_cred_cache = { + .expire = UNX_CRED_EXPIRE, +}; + +static +struct rpc_auth unix_auth = { + .au_cslack = UNX_WRITESLACK, + .au_rslack = 2, /* assume AUTH_NULL verf */ + .au_ops = &authunix_ops, + .au_count = ATOMIC_INIT(0), + .au_credcache = &unix_cred_cache, +}; + +static struct rpc_credops unix_credops = { + .cr_name = "AUTH_UNIX", .crdestroy = unx_destroy_cred, .crmatch = unx_match, .crmarshal = unx_marshal, diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 50d58e877b9a..02bc029d46fe 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -23,6 +23,7 @@ #include <asm/system.h> +#include <linux/module.h> #include <linux/types.h> #include <linux/mm.h> #include <linux/slab.h> @@ -406,12 +407,11 @@ rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags, rpc_call_setup(task, msg, 0); /* Set up the call info struct and execute the task */ - if (task->tk_status == 0) - status = rpc_execute(task); - else { - status = task->tk_status; + status = task->tk_status; + if (status == 0) + rpc_execute(task); + else rpc_release_task(task); - } out: rpc_clnt_sigunmask(clnt, &oldset); @@ -426,9 +426,9 @@ rpc_call_setup(struct rpc_task *task, struct rpc_message *msg, int flags) task->tk_msg = *msg; task->tk_flags |= flags; /* Bind the user cred */ - if (task->tk_msg.rpc_cred != NULL) { + if (task->tk_msg.rpc_cred != NULL) rpcauth_holdcred(task); - } else + else rpcauth_bindcred(task); if (task->tk_status == 0) @@ -453,6 +453,20 @@ rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize } /* + * Return size of largest payload RPC client can support, in bytes + * + * For stream transports, this is one RPC record fragment (see RFC + * 1831), as we don't support multi-record requests yet. For datagram + * transports, this is the size of an IP packet minus the IP, UDP, and + * RPC header sizes. + */ +size_t rpc_max_payload(struct rpc_clnt *clnt) +{ + return clnt->cl_xprt->max_payload; +} +EXPORT_SYMBOL(rpc_max_payload); + +/* * Restart an (async) RPC call. Usually called from within the * exit handler. */ @@ -871,21 +885,6 @@ call_decode(struct rpc_task *task) goto out_retry; } - /* - * The following is an NFS-specific hack to cater for setuid - * processes whose uid is mapped to nobody on the server. - */ - if (task->tk_client->cl_droppriv && - (ntohl(*p) == NFSERR_ACCES || ntohl(*p) == NFSERR_PERM)) { - if (RPC_IS_SETUID(task) && task->tk_suid_retry) { - dprintk("RPC: %4d retry squashed uid\n", task->tk_pid); - task->tk_flags ^= RPC_CALL_REALUID; - task->tk_action = call_bind; - task->tk_suid_retry--; - goto out_retry; - } - } - task->tk_action = NULL; if (decode) diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c index 2a5d319eda09..d0b1d2c34a4d 100644 --- a/net/sunrpc/pmap_clnt.c +++ b/net/sunrpc/pmap_clnt.c @@ -3,9 +3,6 @@ * * Portmapper client. * - * FIXME: In a secure environment, we may want to use an authentication - * flavor other than AUTH_NULL. - * * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> */ @@ -212,7 +209,7 @@ pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto) /* printk("pmap: create clnt\n"); */ clnt = rpc_create_client(xprt, hostname, &pmap_program, RPC_PMAP_VERSION, - RPC_AUTH_NULL); + RPC_AUTH_UNIX); if (IS_ERR(clnt)) { xprt_destroy(xprt); } else { diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index be26e4c5b1a7..c06614d0e31d 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -132,9 +132,11 @@ __rpc_add_timer(struct rpc_task *task, rpc_action timer) * Delete any timer for the current task. Because we use del_timer_sync(), * this function should never be called while holding queue->lock. */ -static inline void +static void rpc_delete_timer(struct rpc_task *task) { + if (RPC_IS_QUEUED(task)) + return; if (test_and_clear_bit(RPC_TASK_HAS_TIMER, &task->tk_runstate)) { del_singleshot_timer_sync(&task->tk_timer); dprintk("RPC: %4d deleting timer\n", task->tk_pid); @@ -747,13 +749,10 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, rpc_action call task->tk_client = clnt; task->tk_flags = flags; task->tk_exit = callback; - if (current->uid != current->fsuid || current->gid != current->fsgid) - task->tk_flags |= RPC_TASK_SETUID; /* Initialize retry counters */ task->tk_garb_retry = 2; task->tk_cred_retry = 2; - task->tk_suid_retry = 1; task->tk_priority = RPC_PRIORITY_NORMAL; task->tk_cookie = (unsigned long)current; diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index ed2a19c762e0..a24a29bfdebd 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1460,8 +1460,11 @@ xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to) if (xprt->stream) { xprt->cwnd = RPC_MAXCWND(xprt); xprt->nocong = 1; - } else + xprt->max_payload = (1U << 31) - 1; + } else { xprt->cwnd = RPC_INITCWND; + xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); + } spin_lock_init(&xprt->sock_lock); spin_lock_init(&xprt->xprt_lock); init_waitqueue_head(&xprt->cong_wait); |
