diff options
Diffstat (limited to 'vserver-sources/2.2.0.7/1013_linux-2.6.22.19.patch')
-rw-r--r-- | vserver-sources/2.2.0.7/1013_linux-2.6.22.19.patch | 1031 |
1 files changed, 1031 insertions, 0 deletions
diff --git a/vserver-sources/2.2.0.7/1013_linux-2.6.22.19.patch b/vserver-sources/2.2.0.7/1013_linux-2.6.22.19.patch new file mode 100644 index 0000000..edd7db3 --- /dev/null +++ b/vserver-sources/2.2.0.7/1013_linux-2.6.22.19.patch @@ -0,0 +1,1031 @@ +diff -NurpP linux-2.6.22.18/arch/i386/kernel/entry.S linux-2.6.22.19/arch/i386/kernel/entry.S +--- linux-2.6.22.18/arch/i386/kernel/entry.S 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/arch/i386/kernel/entry.S 2008-02-26 00:59:40.000000000 +0100 +@@ -409,8 +409,6 @@ restore_nocheck_notrace: + 1: INTERRUPT_RETURN + .section .fixup,"ax" + iret_exc: +- TRACE_IRQS_ON +- ENABLE_INTERRUPTS(CLBR_NONE) + pushl $0 # no error code + pushl $do_iret_error + jmp error_code +diff -NurpP linux-2.6.22.18/arch/i386/kernel/ptrace.c linux-2.6.22.19/arch/i386/kernel/ptrace.c +--- linux-2.6.22.18/arch/i386/kernel/ptrace.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/arch/i386/kernel/ptrace.c 2008-02-26 00:59:40.000000000 +0100 +@@ -164,14 +164,22 @@ static unsigned long convert_eip_to_line + u32 *desc; + unsigned long base; + +- down(&child->mm->context.sem); +- desc = child->mm->context.ldt + (seg & ~7); +- base = (desc[0] >> 16) | ((desc[1] & 0xff) << 16) | (desc[1] & 0xff000000); ++ seg &= ~7UL; + +- /* 16-bit code segment? */ +- if (!((desc[1] >> 22) & 1)) +- addr &= 0xffff; +- addr += base; ++ down(&child->mm->context.sem); ++ if (unlikely((seg >> 3) >= child->mm->context.size)) ++ addr = -1L; /* bogus selector, access would fault */ ++ else { ++ desc = child->mm->context.ldt + seg; ++ base = ((desc[0] >> 16) | ++ ((desc[1] & 0xff) << 16) | ++ (desc[1] & 0xff000000)); ++ ++ /* 16-bit code segment? */ ++ if (!((desc[1] >> 22) & 1)) ++ addr &= 0xffff; ++ addr += base; ++ } + up(&child->mm->context.sem); + } + return addr; +diff -NurpP linux-2.6.22.18/arch/i386/kernel/traps.c linux-2.6.22.19/arch/i386/kernel/traps.c +--- linux-2.6.22.18/arch/i386/kernel/traps.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/arch/i386/kernel/traps.c 2008-02-26 00:59:40.000000000 +0100 +@@ -517,10 +517,12 @@ fastcall void do_##name(struct pt_regs * + do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ + } + +-#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ ++#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr, irq) \ + fastcall void do_##name(struct pt_regs * regs, long error_code) \ + { \ + siginfo_t info; \ ++ if (irq) \ ++ local_irq_enable(); \ + info.si_signo = signr; \ + info.si_errno = 0; \ + info.si_code = sicode; \ +@@ -560,13 +562,13 @@ DO_VM86_ERROR( 3, SIGTRAP, "int3", int3) + #endif + DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow) + DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds) +-DO_ERROR_INFO( 6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->eip) ++DO_ERROR_INFO( 6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->eip, 0) + DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) + DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) + DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) + DO_ERROR(12, SIGBUS, "stack segment", stack_segment) +-DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) +-DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0) ++DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0, 0) ++DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0, 1) + + fastcall void __kprobes do_general_protection(struct pt_regs * regs, + long error_code) +diff -NurpP linux-2.6.22.18/arch/x86_64/kernel/ptrace.c linux-2.6.22.19/arch/x86_64/kernel/ptrace.c +--- linux-2.6.22.18/arch/x86_64/kernel/ptrace.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/arch/x86_64/kernel/ptrace.c 2008-02-26 00:59:40.000000000 +0100 +@@ -102,16 +102,25 @@ unsigned long convert_rip_to_linear(stru + u32 *desc; + unsigned long base; + +- down(&child->mm->context.sem); +- desc = child->mm->context.ldt + (seg & ~7); +- base = (desc[0] >> 16) | ((desc[1] & 0xff) << 16) | (desc[1] & 0xff000000); ++ seg &= ~7UL; + +- /* 16-bit code segment? */ +- if (!((desc[1] >> 22) & 1)) +- addr &= 0xffff; +- addr += base; ++ down(&child->mm->context.sem); ++ if (unlikely((seg >> 3) >= child->mm->context.size)) ++ addr = -1L; /* bogus selector, access would fault */ ++ else { ++ desc = child->mm->context.ldt + seg; ++ base = ((desc[0] >> 16) | ++ ((desc[1] & 0xff) << 16) | ++ (desc[1] & 0xff000000)); ++ ++ /* 16-bit code segment? */ ++ if (!((desc[1] >> 22) & 1)) ++ addr &= 0xffff; ++ addr += base; ++ } + up(&child->mm->context.sem); + } ++ + return addr; + } + +diff -NurpP linux-2.6.22.18/drivers/ata/sata_promise.c linux-2.6.22.19/drivers/ata/sata_promise.c +--- linux-2.6.22.18/drivers/ata/sata_promise.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/drivers/ata/sata_promise.c 2008-02-26 00:59:40.000000000 +0100 +@@ -51,6 +51,7 @@ + enum { + PDC_MAX_PORTS = 4, + PDC_MMIO_BAR = 3, ++ PDC_MAX_PRD = LIBATA_MAX_PRD - 1, /* -1 for ASIC PRD bug workaround */ + + /* register offsets */ + PDC_FEATURE = 0x04, /* Feature/Error reg (per port) */ +@@ -157,7 +158,7 @@ static struct scsi_host_template pdc_ata + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, +- .sg_tablesize = LIBATA_MAX_PRD, ++ .sg_tablesize = PDC_MAX_PRD, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, +@@ -330,8 +331,8 @@ static const struct pci_device_id pdc_at + + { PCI_VDEVICE(PROMISE, 0x3318), board_20319 }, + { PCI_VDEVICE(PROMISE, 0x3319), board_20319 }, +- { PCI_VDEVICE(PROMISE, 0x3515), board_20319 }, +- { PCI_VDEVICE(PROMISE, 0x3519), board_20319 }, ++ { PCI_VDEVICE(PROMISE, 0x3515), board_40518 }, ++ { PCI_VDEVICE(PROMISE, 0x3519), board_40518 }, + { PCI_VDEVICE(PROMISE, 0x3d17), board_40518 }, + { PCI_VDEVICE(PROMISE, 0x3d18), board_40518 }, + +@@ -531,6 +532,84 @@ static void pdc_atapi_pkt(struct ata_que + memcpy(buf+31, cdb, cdb_len); + } + ++/** ++ * pdc_fill_sg - Fill PCI IDE PRD table ++ * @qc: Metadata associated with taskfile to be transferred ++ * ++ * Fill PCI IDE PRD (scatter-gather) table with segments ++ * associated with the current disk command. ++ * Make sure hardware does not choke on it. ++ * ++ * LOCKING: ++ * spin_lock_irqsave(host lock) ++ * ++ */ ++static void pdc_fill_sg(struct ata_queued_cmd *qc) ++{ ++ struct ata_port *ap = qc->ap; ++ struct scatterlist *sg; ++ unsigned int idx; ++ const u32 SG_COUNT_ASIC_BUG = 41*4; ++ ++ if (!(qc->flags & ATA_QCFLAG_DMAMAP)) ++ return; ++ ++ WARN_ON(qc->__sg == NULL); ++ WARN_ON(qc->n_elem == 0 && qc->pad_len == 0); ++ ++ idx = 0; ++ ata_for_each_sg(sg, qc) { ++ u32 addr, offset; ++ u32 sg_len, len; ++ ++ /* determine if physical DMA addr spans 64K boundary. ++ * Note h/w doesn't support 64-bit, so we unconditionally ++ * truncate dma_addr_t to u32. ++ */ ++ addr = (u32) sg_dma_address(sg); ++ sg_len = sg_dma_len(sg); ++ ++ while (sg_len) { ++ offset = addr & 0xffff; ++ len = sg_len; ++ if ((offset + sg_len) > 0x10000) ++ len = 0x10000 - offset; ++ ++ ap->prd[idx].addr = cpu_to_le32(addr); ++ ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff); ++ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len); ++ ++ idx++; ++ sg_len -= len; ++ addr += len; ++ } ++ } ++ ++ if (idx) { ++ u32 len = le32_to_cpu(ap->prd[idx - 1].flags_len); ++ ++ if (len > SG_COUNT_ASIC_BUG) { ++ u32 addr; ++ ++ VPRINTK("Splitting last PRD.\n"); ++ ++ addr = le32_to_cpu(ap->prd[idx - 1].addr); ++ ap->prd[idx - 1].flags_len = cpu_to_le32(len - SG_COUNT_ASIC_BUG); ++ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx - 1, addr, SG_COUNT_ASIC_BUG); ++ ++ addr = addr + len - SG_COUNT_ASIC_BUG; ++ len = SG_COUNT_ASIC_BUG; ++ ap->prd[idx].addr = cpu_to_le32(addr); ++ ap->prd[idx].flags_len = cpu_to_le32(len); ++ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len); ++ ++ idx++; ++ } ++ ++ ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); ++ } ++} ++ + static void pdc_qc_prep(struct ata_queued_cmd *qc) + { + struct pdc_port_priv *pp = qc->ap->private_data; +@@ -540,7 +619,7 @@ static void pdc_qc_prep(struct ata_queue + + switch (qc->tf.protocol) { + case ATA_PROT_DMA: +- ata_qc_prep(qc); ++ pdc_fill_sg(qc); + /* fall through */ + + case ATA_PROT_NODATA: +@@ -556,11 +635,11 @@ static void pdc_qc_prep(struct ata_queue + break; + + case ATA_PROT_ATAPI: +- ata_qc_prep(qc); ++ pdc_fill_sg(qc); + break; + + case ATA_PROT_ATAPI_DMA: +- ata_qc_prep(qc); ++ pdc_fill_sg(qc); + /*FALLTHROUGH*/ + case ATA_PROT_ATAPI_NODATA: + pdc_atapi_pkt(qc); +diff -NurpP linux-2.6.22.18/drivers/block/cciss.c linux-2.6.22.19/drivers/block/cciss.c +--- linux-2.6.22.18/drivers/block/cciss.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/drivers/block/cciss.c 2008-02-26 00:59:40.000000000 +0100 +@@ -3225,12 +3225,15 @@ static int alloc_cciss_hba(void) + for (i = 0; i < MAX_CTLR; i++) { + if (!hba[i]) { + ctlr_info_t *p; ++ + p = kzalloc(sizeof(ctlr_info_t), GFP_KERNEL); + if (!p) + goto Enomem; + p->gendisk[0] = alloc_disk(1 << NWD_SHIFT); +- if (!p->gendisk[0]) ++ if (!p->gendisk[0]) { ++ kfree(p); + goto Enomem; ++ } + hba[i] = p; + return i; + } +diff -NurpP linux-2.6.22.18/drivers/char/agp/intel-agp.c linux-2.6.22.19/drivers/char/agp/intel-agp.c +--- linux-2.6.22.18/drivers/char/agp/intel-agp.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/drivers/char/agp/intel-agp.c 2008-02-26 00:59:40.000000000 +0100 +@@ -20,7 +20,9 @@ + #define PCI_DEVICE_ID_INTEL_82965G_IG 0x29A2 + #define PCI_DEVICE_ID_INTEL_82965GM_HB 0x2A00 + #define PCI_DEVICE_ID_INTEL_82965GM_IG 0x2A02 ++#define PCI_DEVICE_ID_INTEL_82965GME_HB 0x2A10 + #define PCI_DEVICE_ID_INTEL_82965GME_IG 0x2A12 ++#define PCI_DEVICE_ID_INTEL_82945GME_HB 0x27AC + #define PCI_DEVICE_ID_INTEL_82945GME_IG 0x27AE + #define PCI_DEVICE_ID_INTEL_G33_HB 0x29C0 + #define PCI_DEVICE_ID_INTEL_G33_IG 0x29C2 +@@ -33,7 +35,8 @@ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_1_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \ +- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB) ++ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \ ++ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB) + + #define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \ +@@ -527,6 +530,7 @@ static void intel_i830_init_gtt_entries( + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || ++ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB || + IS_I965 || IS_G33) + gtt_entries = MB(48) - KB(size); + else +@@ -538,6 +542,7 @@ static void intel_i830_init_gtt_entries( + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || ++ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB || + IS_I965 || IS_G33) + gtt_entries = MB(64) - KB(size); + else +@@ -1848,9 +1853,9 @@ static const struct intel_driver_descrip + NULL, &intel_915_driver }, + { PCI_DEVICE_ID_INTEL_82945G_HB, PCI_DEVICE_ID_INTEL_82945G_IG, 0, "945G", + NULL, &intel_915_driver }, +- { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GM_IG, 1, "945GM", ++ { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GM_IG, 0, "945GM", + NULL, &intel_915_driver }, +- { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GME_IG, 0, "945GME", ++ { PCI_DEVICE_ID_INTEL_82945GME_HB, PCI_DEVICE_ID_INTEL_82945GME_IG, 0, "945GME", + NULL, &intel_915_driver }, + { PCI_DEVICE_ID_INTEL_82946GZ_HB, PCI_DEVICE_ID_INTEL_82946GZ_IG, 0, "946GZ", + NULL, &intel_i965_driver }, +@@ -1860,9 +1865,9 @@ static const struct intel_driver_descrip + NULL, &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_82965G_HB, PCI_DEVICE_ID_INTEL_82965G_IG, 0, "965G", + NULL, &intel_i965_driver }, +- { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GM_IG, 1, "965GM", ++ { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GM_IG, 0, "965GM", + NULL, &intel_i965_driver }, +- { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GME_IG, 0, "965GME/GLE", ++ { PCI_DEVICE_ID_INTEL_82965GME_HB, PCI_DEVICE_ID_INTEL_82965GME_IG, 0, "965GME/GLE", + NULL, &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_7505_0, 0, 0, "E7505", &intel_7505_driver, NULL }, + { PCI_DEVICE_ID_INTEL_7205_0, 0, 0, "E7205", &intel_7505_driver, NULL }, +@@ -2051,11 +2056,13 @@ static struct pci_device_id agp_intel_pc + ID(PCI_DEVICE_ID_INTEL_82915GM_HB), + ID(PCI_DEVICE_ID_INTEL_82945G_HB), + ID(PCI_DEVICE_ID_INTEL_82945GM_HB), ++ ID(PCI_DEVICE_ID_INTEL_82945GME_HB), + ID(PCI_DEVICE_ID_INTEL_82946GZ_HB), + ID(PCI_DEVICE_ID_INTEL_82965G_1_HB), + ID(PCI_DEVICE_ID_INTEL_82965Q_HB), + ID(PCI_DEVICE_ID_INTEL_82965G_HB), + ID(PCI_DEVICE_ID_INTEL_82965GM_HB), ++ ID(PCI_DEVICE_ID_INTEL_82965GME_HB), + ID(PCI_DEVICE_ID_INTEL_G33_HB), + ID(PCI_DEVICE_ID_INTEL_Q35_HB), + ID(PCI_DEVICE_ID_INTEL_Q33_HB), +diff -NurpP linux-2.6.22.18/drivers/char/ipmi/ipmi_si_intf.c linux-2.6.22.19/drivers/char/ipmi/ipmi_si_intf.c +--- linux-2.6.22.18/drivers/char/ipmi/ipmi_si_intf.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/drivers/char/ipmi/ipmi_si_intf.c 2008-02-26 00:59:40.000000000 +0100 +@@ -2214,7 +2214,8 @@ static int ipmi_pci_resume(struct pci_de + + static struct pci_device_id ipmi_pci_devices[] = { + { PCI_DEVICE(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID) }, +- { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) } ++ { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) }, ++ { 0, } + }; + MODULE_DEVICE_TABLE(pci, ipmi_pci_devices); + +diff -NurpP linux-2.6.22.18/drivers/media/video/usbvision/usbvision-cards.c linux-2.6.22.19/drivers/media/video/usbvision/usbvision-cards.c +--- linux-2.6.22.18/drivers/media/video/usbvision/usbvision-cards.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/drivers/media/video/usbvision/usbvision-cards.c 2008-02-26 00:59:40.000000000 +0100 +@@ -1081,6 +1081,7 @@ struct usb_device_id usbvision_table [] + { USB_DEVICE(0x2304, 0x0301), .driver_info=PINNA_LINX_VD_IN_CAB_PAL }, + { USB_DEVICE(0x2304, 0x0419), .driver_info=PINNA_PCTV_BUNGEE_PAL_FM }, + { USB_DEVICE(0x2400, 0x4200), .driver_info=HPG_WINTV }, ++ { }, /* terminate list */ + }; + + MODULE_DEVICE_TABLE (usb, usbvision_table); +diff -NurpP linux-2.6.22.18/drivers/misc/sony-laptop.c linux-2.6.22.19/drivers/misc/sony-laptop.c +--- linux-2.6.22.18/drivers/misc/sony-laptop.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/drivers/misc/sony-laptop.c 2008-02-26 00:59:40.000000000 +0100 +@@ -2056,8 +2056,6 @@ static int sony_pic_remove(struct acpi_d + struct sony_pic_ioport *io, *tmp_io; + struct sony_pic_irq *irq, *tmp_irq; + +- sonypi_compat_exit(); +- + if (sony_pic_disable(device)) { + printk(KERN_ERR DRV_PFX "Couldn't disable device.\n"); + return -ENXIO; +@@ -2067,6 +2065,8 @@ static int sony_pic_remove(struct acpi_d + release_region(spic_dev.cur_ioport->io.minimum, + spic_dev.cur_ioport->io.address_length); + ++ sonypi_compat_exit(); ++ + sony_laptop_remove_input(); + + /* pf attrs */ +@@ -2132,6 +2132,9 @@ static int sony_pic_add(struct acpi_devi + goto err_free_resources; + } + ++ if (sonypi_compat_init()) ++ goto err_remove_input; ++ + /* request io port */ + list_for_each_entry(io, &spic_dev.ioports, list) { + if (request_region(io->io.minimum, io->io.address_length, +@@ -2146,7 +2149,7 @@ static int sony_pic_add(struct acpi_devi + if (!spic_dev.cur_ioport) { + printk(KERN_ERR DRV_PFX "Failed to request_region.\n"); + result = -ENODEV; +- goto err_remove_input; ++ goto err_remove_compat; + } + + /* request IRQ */ +@@ -2186,9 +2189,6 @@ static int sony_pic_add(struct acpi_devi + if (result) + goto err_remove_pf; + +- if (sonypi_compat_init()) +- goto err_remove_pf; +- + return 0; + + err_remove_pf: +@@ -2204,6 +2204,9 @@ err_release_region: + release_region(spic_dev.cur_ioport->io.minimum, + spic_dev.cur_ioport->io.address_length); + ++err_remove_compat: ++ sonypi_compat_exit(); ++ + err_remove_input: + sony_laptop_remove_input(); + +diff -NurpP linux-2.6.22.18/drivers/mtd/nand/cafe_nand.c linux-2.6.22.19/drivers/mtd/nand/cafe_nand.c +--- linux-2.6.22.18/drivers/mtd/nand/cafe_nand.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/drivers/mtd/nand/cafe_nand.c 2008-02-26 00:59:40.000000000 +0100 +@@ -816,7 +816,8 @@ static void __devexit cafe_nand_remove(s + } + + static struct pci_device_id cafe_nand_tbl[] = { +- { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MEMORY_FLASH << 8, 0xFFFF0 } ++ { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MEMORY_FLASH << 8, 0xFFFF0 }, ++ { 0, } + }; + + MODULE_DEVICE_TABLE(pci, cafe_nand_tbl); +diff -NurpP linux-2.6.22.18/drivers/net/via-velocity.c linux-2.6.22.19/drivers/net/via-velocity.c +--- linux-2.6.22.18/drivers/net/via-velocity.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/drivers/net/via-velocity.c 2008-02-26 00:59:40.000000000 +0100 +@@ -1075,6 +1075,9 @@ static int velocity_init_rd_ring(struct + int ret = -ENOMEM; + unsigned int rsize = sizeof(struct velocity_rd_info) * + vptr->options.numrx; ++ int mtu = vptr->dev->mtu; ++ ++ vptr->rx_buf_sz = (mtu <= ETH_DATA_LEN) ? PKT_BUF_SZ : mtu + 32; + + vptr->rd_info = kmalloc(rsize, GFP_KERNEL); + if(vptr->rd_info == NULL) +@@ -1733,8 +1736,6 @@ static int velocity_open(struct net_devi + struct velocity_info *vptr = netdev_priv(dev); + int ret; + +- vptr->rx_buf_sz = (dev->mtu <= 1504 ? PKT_BUF_SZ : dev->mtu + 32); +- + ret = velocity_init_rings(vptr); + if (ret < 0) + goto out; +@@ -1798,6 +1799,11 @@ static int velocity_change_mtu(struct ne + return -EINVAL; + } + ++ if (!netif_running(dev)) { ++ dev->mtu = new_mtu; ++ return 0; ++ } ++ + if (new_mtu != oldmtu) { + spin_lock_irqsave(&vptr->lock, flags); + +@@ -1808,12 +1814,6 @@ static int velocity_change_mtu(struct ne + velocity_free_rd_ring(vptr); + + dev->mtu = new_mtu; +- if (new_mtu > 8192) +- vptr->rx_buf_sz = 9 * 1024; +- else if (new_mtu > 4096) +- vptr->rx_buf_sz = 8192; +- else +- vptr->rx_buf_sz = 4 * 1024; + + ret = velocity_init_rd_ring(vptr); + if (ret < 0) +diff -NurpP linux-2.6.22.18/drivers/pci/hotplug/fakephp.c linux-2.6.22.19/drivers/pci/hotplug/fakephp.c +--- linux-2.6.22.18/drivers/pci/hotplug/fakephp.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/drivers/pci/hotplug/fakephp.c 2008-02-26 00:59:40.000000000 +0100 +@@ -39,6 +39,7 @@ + #include <linux/init.h> + #include <linux/string.h> + #include <linux/slab.h> ++#include <linux/workqueue.h> + #include "../pci.h" + + #if !defined(MODULE) +@@ -63,10 +64,16 @@ struct dummy_slot { + struct list_head node; + struct hotplug_slot *slot; + struct pci_dev *dev; ++ struct work_struct remove_work; ++ unsigned long removed; + }; + + static int debug; + static LIST_HEAD(slot_list); ++static struct workqueue_struct *dummyphp_wq; ++ ++static void pci_rescan_worker(struct work_struct *work); ++static DECLARE_WORK(pci_rescan_work, pci_rescan_worker); + + static int enable_slot (struct hotplug_slot *slot); + static int disable_slot (struct hotplug_slot *slot); +@@ -109,7 +116,7 @@ static int add_slot(struct pci_dev *dev) + slot->name = &dev->dev.bus_id[0]; + dbg("slot->name = %s\n", slot->name); + +- dslot = kmalloc(sizeof(struct dummy_slot), GFP_KERNEL); ++ dslot = kzalloc(sizeof(struct dummy_slot), GFP_KERNEL); + if (!dslot) + goto error_info; + +@@ -164,6 +171,14 @@ static void remove_slot(struct dummy_slo + err("Problem unregistering a slot %s\n", dslot->slot->name); + } + ++/* called from the single-threaded workqueue handler to remove a slot */ ++static void remove_slot_worker(struct work_struct *work) ++{ ++ struct dummy_slot *dslot = ++ container_of(work, struct dummy_slot, remove_work); ++ remove_slot(dslot); ++} ++ + /** + * Rescan slot. + * Tries hard not to re-enable already existing devices +@@ -267,11 +282,17 @@ static inline void pci_rescan(void) { + pci_rescan_buses(&pci_root_buses); + } + ++/* called from the single-threaded workqueue handler to rescan all pci buses */ ++static void pci_rescan_worker(struct work_struct *work) ++{ ++ pci_rescan(); ++} + + static int enable_slot(struct hotplug_slot *hotplug_slot) + { + /* mis-use enable_slot for rescanning of the pci bus */ +- pci_rescan(); ++ cancel_work_sync(&pci_rescan_work); ++ queue_work(dummyphp_wq, &pci_rescan_work); + return -ENODEV; + } + +@@ -306,6 +327,10 @@ static int disable_slot(struct hotplug_s + err("Can't remove PCI devices with other PCI devices behind it yet.\n"); + return -ENODEV; + } ++ if (test_and_set_bit(0, &dslot->removed)) { ++ dbg("Slot already scheduled for removal\n"); ++ return -ENODEV; ++ } + /* search for subfunctions and disable them first */ + if (!(dslot->dev->devfn & 7)) { + for (func = 1; func < 8; func++) { +@@ -328,8 +353,9 @@ static int disable_slot(struct hotplug_s + /* remove the device from the pci core */ + pci_remove_bus_device(dslot->dev); + +- /* blow away this sysfs entry and other parts. */ +- remove_slot(dslot); ++ /* queue work item to blow away this sysfs entry and other parts. */ ++ INIT_WORK(&dslot->remove_work, remove_slot_worker); ++ queue_work(dummyphp_wq, &dslot->remove_work); + + return 0; + } +@@ -340,6 +366,7 @@ static void cleanup_slots (void) + struct list_head *next; + struct dummy_slot *dslot; + ++ destroy_workqueue(dummyphp_wq); + list_for_each_safe (tmp, next, &slot_list) { + dslot = list_entry (tmp, struct dummy_slot, node); + remove_slot(dslot); +@@ -351,6 +378,10 @@ static int __init dummyphp_init(void) + { + info(DRIVER_DESC "\n"); + ++ dummyphp_wq = create_singlethread_workqueue(MY_NAME); ++ if (!dummyphp_wq) ++ return -ENOMEM; ++ + return pci_scan_buses(); + } + +diff -NurpP linux-2.6.22.18/drivers/scsi/sd.c linux-2.6.22.19/drivers/scsi/sd.c +--- linux-2.6.22.18/drivers/scsi/sd.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/drivers/scsi/sd.c 2008-02-26 00:59:40.000000000 +0100 +@@ -895,6 +895,7 @@ static void sd_rw_intr(struct scsi_cmnd + unsigned int xfer_size = SCpnt->request_bufflen; + unsigned int good_bytes = result ? 0 : xfer_size; + u64 start_lba = SCpnt->request->sector; ++ u64 end_lba = SCpnt->request->sector + (xfer_size / 512); + u64 bad_lba; + struct scsi_sense_hdr sshdr; + int sense_valid = 0; +@@ -933,26 +934,23 @@ static void sd_rw_intr(struct scsi_cmnd + goto out; + if (xfer_size <= SCpnt->device->sector_size) + goto out; +- switch (SCpnt->device->sector_size) { +- case 256: ++ if (SCpnt->device->sector_size < 512) { ++ /* only legitimate sector_size here is 256 */ + start_lba <<= 1; +- break; +- case 512: +- break; +- case 1024: +- start_lba >>= 1; +- break; +- case 2048: +- start_lba >>= 2; +- break; +- case 4096: +- start_lba >>= 3; +- break; +- default: +- /* Print something here with limiting frequency. */ +- goto out; +- break; ++ end_lba <<= 1; ++ } else { ++ /* be careful ... don't want any overflows */ ++ u64 factor = SCpnt->device->sector_size / 512; ++ do_div(start_lba, factor); ++ do_div(end_lba, factor); + } ++ ++ if (bad_lba < start_lba || bad_lba >= end_lba) ++ /* the bad lba was reported incorrectly, we have ++ * no idea where the error is ++ */ ++ goto out; ++ + /* This computation should always be done in terms of + * the resolution of the device's medium. + */ +diff -NurpP linux-2.6.22.18/fs/nfs/client.c linux-2.6.22.19/fs/nfs/client.c +--- linux-2.6.22.18/fs/nfs/client.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/fs/nfs/client.c 2008-02-26 00:59:40.000000000 +0100 +@@ -433,9 +433,6 @@ static int nfs_create_rpc_client(struct + */ + static void nfs_destroy_server(struct nfs_server *server) + { +- if (!IS_ERR(server->client_acl)) +- rpc_shutdown_client(server->client_acl); +- + if (!(server->flags & NFS_MOUNT_NONLM)) + lockd_down(); /* release rpc.lockd */ + } +@@ -614,16 +611,6 @@ static int nfs_init_server(struct nfs_se + server->namelen = data->namlen; + /* Create a client RPC handle for the NFSv3 ACL management interface */ + nfs_init_server_aclclient(server); +- if (clp->cl_nfsversion == 3) { +- if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN) +- server->namelen = NFS3_MAXNAMLEN; +- if (!(data->flags & NFS_MOUNT_NORDIRPLUS)) +- server->caps |= NFS_CAP_READDIRPLUS; +- } else { +- if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN) +- server->namelen = NFS2_MAXNAMLEN; +- } +- + dprintk("<-- nfs_init_server() = 0 [new %p]\n", clp); + return 0; + +@@ -781,6 +768,9 @@ void nfs_free_server(struct nfs_server * + + if (server->destroy != NULL) + server->destroy(server); ++ ++ if (!IS_ERR(server->client_acl)) ++ rpc_shutdown_client(server->client_acl); + if (!IS_ERR(server->client)) + rpc_shutdown_client(server->client); + +@@ -820,6 +810,16 @@ struct nfs_server *nfs_create_server(con + error = nfs_probe_fsinfo(server, mntfh, &fattr); + if (error < 0) + goto error; ++ if (server->nfs_client->rpc_ops->version == 3) { ++ if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN) ++ server->namelen = NFS3_MAXNAMLEN; ++ if (!(data->flags & NFS_MOUNT_NORDIRPLUS)) ++ server->caps |= NFS_CAP_READDIRPLUS; ++ } else { ++ if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN) ++ server->namelen = NFS2_MAXNAMLEN; ++ } ++ + if (!(fattr.valid & NFS_ATTR_FATTR)) { + error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr); + if (error < 0) { +@@ -1010,6 +1010,9 @@ struct nfs_server *nfs4_create_server(co + if (error < 0) + goto error; + ++ if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN) ++ server->namelen = NFS4_MAXNAMLEN; ++ + BUG_ON(!server->nfs_client); + BUG_ON(!server->nfs_client->rpc_ops); + BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); +@@ -1082,6 +1085,9 @@ struct nfs_server *nfs4_create_referral_ + if (error < 0) + goto error; + ++ if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN) ++ server->namelen = NFS4_MAXNAMLEN; ++ + dprintk("Referral FSID: %llx:%llx\n", + (unsigned long long) server->fsid.major, + (unsigned long long) server->fsid.minor); +@@ -1141,6 +1147,9 @@ struct nfs_server *nfs_clone_server(stru + if (error < 0) + goto out_free_server; + ++ if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN) ++ server->namelen = NFS4_MAXNAMLEN; ++ + dprintk("Cloned FSID: %llx:%llx\n", + (unsigned long long) server->fsid.major, + (unsigned long long) server->fsid.minor); +diff -NurpP linux-2.6.22.18/fs/nfs/dir.c linux-2.6.22.19/fs/nfs/dir.c +--- linux-2.6.22.18/fs/nfs/dir.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/fs/nfs/dir.c 2008-02-26 00:59:40.000000000 +0100 +@@ -897,14 +897,13 @@ int nfs_is_exclusive_create(struct inode + return (nd->intent.open.flags & O_EXCL) != 0; + } + +-static inline int nfs_reval_fsid(struct vfsmount *mnt, struct inode *dir, +- struct nfs_fh *fh, struct nfs_fattr *fattr) ++static inline int nfs_reval_fsid(struct inode *dir, const struct nfs_fattr *fattr) + { + struct nfs_server *server = NFS_SERVER(dir); + + if (!nfs_fsid_equal(&server->fsid, &fattr->fsid)) +- /* Revalidate fsid on root dir */ +- return __nfs_revalidate_inode(server, mnt->mnt_root->d_inode); ++ /* Revalidate fsid using the parent directory */ ++ return __nfs_revalidate_inode(server, dir); + return 0; + } + +@@ -946,7 +945,7 @@ static struct dentry *nfs_lookup(struct + res = ERR_PTR(error); + goto out_unlock; + } +- error = nfs_reval_fsid(nd->mnt, dir, &fhandle, &fattr); ++ error = nfs_reval_fsid(dir, &fattr); + if (error < 0) { + res = ERR_PTR(error); + goto out_unlock; +@@ -1163,6 +1162,8 @@ static struct dentry *nfs_readdir_lookup + } + if (!desc->plus || !(entry->fattr->valid & NFS_ATTR_FATTR)) + return NULL; ++ if (name.len > NFS_SERVER(dir)->namelen) ++ return NULL; + /* Note: caller is already holding the dir->i_mutex! */ + dentry = d_alloc(parent, &name); + if (dentry == NULL) +diff -NurpP linux-2.6.22.18/fs/nfs/getroot.c linux-2.6.22.19/fs/nfs/getroot.c +--- linux-2.6.22.18/fs/nfs/getroot.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/fs/nfs/getroot.c 2008-02-26 00:59:40.000000000 +0100 +@@ -175,6 +175,9 @@ next_component: + path++; + name.len = path - (const char *) name.name; + ++ if (name.len > NFS4_MAXNAMLEN) ++ return -ENAMETOOLONG; ++ + eat_dot_dir: + while (*path == '/') + path++; +diff -NurpP linux-2.6.22.18/fs/nfs/inode.c linux-2.6.22.19/fs/nfs/inode.c +--- linux-2.6.22.18/fs/nfs/inode.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/fs/nfs/inode.c 2008-02-26 00:59:40.000000000 +0100 +@@ -961,8 +961,8 @@ static int nfs_update_inode(struct inode + goto out_changed; + + server = NFS_SERVER(inode); +- /* Update the fsid if and only if this is the root directory */ +- if (inode == inode->i_sb->s_root->d_inode ++ /* Update the fsid? */ ++ if (S_ISDIR(inode->i_mode) + && !nfs_fsid_equal(&server->fsid, &fattr->fsid)) + server->fsid = fattr->fsid; + +diff -NurpP linux-2.6.22.18/fs/nfs/write.c linux-2.6.22.19/fs/nfs/write.c +--- linux-2.6.22.18/fs/nfs/write.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/fs/nfs/write.c 2008-02-26 00:59:40.000000000 +0100 +@@ -710,6 +710,17 @@ int nfs_flush_incompatible(struct file * + } + + /* ++ * If the page cache is marked as unsafe or invalid, then we can't rely on ++ * the PageUptodate() flag. In this case, we will need to turn off ++ * write optimisations that depend on the page contents being correct. ++ */ ++static int nfs_write_pageuptodate(struct page *page, struct inode *inode) ++{ ++ return PageUptodate(page) && ++ !(NFS_I(inode)->cache_validity & (NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA)); ++} ++ ++/* + * Update and possibly write a cached page of an NFS file. + * + * XXX: Keep an eye on generic_file_read to make sure it doesn't do bad +@@ -730,10 +741,13 @@ int nfs_updatepage(struct file *file, st + (long long)(page_offset(page) +offset)); + + /* If we're not using byte range locks, and we know the page +- * is entirely in cache, it may be more efficient to avoid +- * fragmenting write requests. ++ * is up to date, it may be more efficient to extend the write ++ * to cover the entire page in order to avoid fragmentation ++ * inefficiencies. + */ +- if (PageUptodate(page) && inode->i_flock == NULL && !(file->f_mode & O_SYNC)) { ++ if (nfs_write_pageuptodate(page, inode) && ++ inode->i_flock == NULL && ++ !(file->f_mode & O_SYNC)) { + count = max(count + offset, nfs_page_length(page)); + offset = 0; + } +diff -NurpP linux-2.6.22.18/fs/nfsd/nfs2acl.c linux-2.6.22.19/fs/nfsd/nfs2acl.c +--- linux-2.6.22.18/fs/nfsd/nfs2acl.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/fs/nfsd/nfs2acl.c 2008-02-26 00:59:40.000000000 +0100 +@@ -41,7 +41,7 @@ static __be32 nfsacld_proc_getacl(struct + + fh = fh_copy(&resp->fh, &argp->fh); + if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP))) +- RETURN_STATUS(nfserr_inval); ++ RETURN_STATUS(nfserr); + + if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) + RETURN_STATUS(nfserr_inval); +diff -NurpP linux-2.6.22.18/fs/nfsd/nfs3acl.c linux-2.6.22.19/fs/nfsd/nfs3acl.c +--- linux-2.6.22.18/fs/nfsd/nfs3acl.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/fs/nfsd/nfs3acl.c 2008-02-26 00:59:40.000000000 +0100 +@@ -37,7 +37,7 @@ static __be32 nfsd3_proc_getacl(struct s + + fh = fh_copy(&resp->fh, &argp->fh); + if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP))) +- RETURN_STATUS(nfserr_inval); ++ RETURN_STATUS(nfserr); + + if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) + RETURN_STATUS(nfserr_inval); +diff -NurpP linux-2.6.22.18/fs/nfsd/nfs4xdr.c linux-2.6.22.19/fs/nfsd/nfs4xdr.c +--- linux-2.6.22.18/fs/nfsd/nfs4xdr.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/fs/nfsd/nfs4xdr.c 2008-02-26 00:59:40.000000000 +0100 +@@ -1453,7 +1453,8 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s + err = vfs_getattr(exp->ex_mnt, dentry, &stat); + if (err) + goto out_nfserr; +- if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL)) || ++ if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | ++ FATTR4_WORD0_MAXNAME)) || + (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | + FATTR4_WORD1_SPACE_TOTAL))) { + err = vfs_statfs(dentry, &statfs); +@@ -1699,7 +1700,7 @@ out_acl: + if (bmval0 & FATTR4_WORD0_MAXNAME) { + if ((buflen -= 4) < 0) + goto out_resource; +- WRITE32(~(u32) 0); ++ WRITE32(statfs.f_namelen); + } + if (bmval0 & FATTR4_WORD0_MAXREAD) { + if ((buflen -= 8) < 0) +diff -NurpP linux-2.6.22.18/include/linux/quicklist.h linux-2.6.22.19/include/linux/quicklist.h +--- linux-2.6.22.18/include/linux/quicklist.h 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/include/linux/quicklist.h 2008-02-26 00:59:40.000000000 +0100 +@@ -56,14 +56,6 @@ static inline void __quicklist_free(int + struct page *page) + { + struct quicklist *q; +- int nid = page_to_nid(page); +- +- if (unlikely(nid != numa_node_id())) { +- if (dtor) +- dtor(p); +- __free_page(page); +- return; +- } + + q = &get_cpu_var(quicklist)[nr]; + *(void **)p = q->page; +diff -NurpP linux-2.6.22.18/mm/memory.c linux-2.6.22.19/mm/memory.c +--- linux-2.6.22.18/mm/memory.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/mm/memory.c 2008-02-26 00:59:40.000000000 +0100 +@@ -983,6 +983,8 @@ int get_user_pages(struct task_struct *t + int i; + unsigned int vm_flags; + ++ if (len <= 0) ++ return 0; + /* + * Require read or write permissions. + * If 'force' is set, we only require the "MAY" flags. +diff -NurpP linux-2.6.22.18/mm/quicklist.c linux-2.6.22.19/mm/quicklist.c +--- linux-2.6.22.18/mm/quicklist.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/mm/quicklist.c 2008-02-26 00:59:40.000000000 +0100 +@@ -26,9 +26,17 @@ DEFINE_PER_CPU(struct quicklist, quickli + static unsigned long max_pages(unsigned long min_pages) + { + unsigned long node_free_pages, max; ++ struct zone *zones = NODE_DATA(numa_node_id())->node_zones; ++ ++ node_free_pages = ++#ifdef CONFIG_ZONE_DMA ++ zone_page_state(&zones[ZONE_DMA], NR_FREE_PAGES) + ++#endif ++#ifdef CONFIG_ZONE_DMA32 ++ zone_page_state(&zones[ZONE_DMA32], NR_FREE_PAGES) + ++#endif ++ zone_page_state(&zones[ZONE_NORMAL], NR_FREE_PAGES); + +- node_free_pages = node_page_state(numa_node_id(), +- NR_FREE_PAGES); + max = node_free_pages / FRACTION_OF_NODE_MEM; + return max(max, min_pages); + } +diff -NurpP linux-2.6.22.18/net/netfilter/nf_conntrack_proto_tcp.c linux-2.6.22.19/net/netfilter/nf_conntrack_proto_tcp.c +--- linux-2.6.22.18/net/netfilter/nf_conntrack_proto_tcp.c 2008-02-11 08:31:19.000000000 +0100 ++++ linux-2.6.22.19/net/netfilter/nf_conntrack_proto_tcp.c 2008-02-26 00:59:40.000000000 +0100 +@@ -143,7 +143,7 @@ enum tcp_bit_set { + * CLOSE_WAIT: ACK seen (after FIN) + * LAST_ACK: FIN seen (after FIN) + * TIME_WAIT: last ACK seen +- * CLOSE: closed connection ++ * CLOSE: closed connection (RST) + * + * LISTEN state is not used. + * +@@ -842,8 +842,21 @@ static int tcp_packet(struct nf_conn *co + case TCP_CONNTRACK_SYN_SENT: + if (old_state < TCP_CONNTRACK_TIME_WAIT) + break; +- if ((conntrack->proto.tcp.seen[!dir].flags & +- IP_CT_TCP_FLAG_CLOSE_INIT) ++ /* RFC 1122: "When a connection is closed actively, ++ * it MUST linger in TIME-WAIT state for a time 2xMSL ++ * (Maximum Segment Lifetime). However, it MAY accept ++ * a new SYN from the remote TCP to reopen the connection ++ * directly from TIME-WAIT state, if..." ++ * We ignore the conditions because we are in the ++ * TIME-WAIT state anyway. ++ * ++ * Handle aborted connections: we and the server ++ * think there is an existing connection but the client ++ * aborts it and starts a new one. ++ */ ++ if (((conntrack->proto.tcp.seen[dir].flags ++ | conntrack->proto.tcp.seen[!dir].flags) ++ & IP_CT_TCP_FLAG_CLOSE_INIT) + || (conntrack->proto.tcp.last_dir == dir + && conntrack->proto.tcp.last_index == TCP_RST_SET)) { + /* Attempt to reopen a closed/aborted connection. +@@ -858,16 +871,23 @@ static int tcp_packet(struct nf_conn *co + case TCP_CONNTRACK_IGNORE: + /* Ignored packets: + * ++ * Our connection entry may be out of sync, so ignore ++ * packets which may signal the real connection between ++ * the client and the server. ++ * + * a) SYN in ORIGINAL + * b) SYN/ACK in REPLY + * c) ACK in reply direction after initial SYN in original. ++ * ++ * If the ignored packet is invalid, the receiver will send ++ * a RST we'll catch below. + */ + if (index == TCP_SYNACK_SET + && conntrack->proto.tcp.last_index == TCP_SYN_SET + && conntrack->proto.tcp.last_dir != dir + && ntohl(th->ack_seq) == + conntrack->proto.tcp.last_end) { +- /* This SYN/ACK acknowledges a SYN that we earlier ++ /* b) This SYN/ACK acknowledges a SYN that we earlier + * ignored as invalid. This means that the client and + * the server are both in sync, while the firewall is + * not. We kill this session and block the SYN/ACK so +@@ -892,7 +912,7 @@ static int tcp_packet(struct nf_conn *co + write_unlock_bh(&tcp_lock); + if (LOG_INVALID(IPPROTO_TCP)) + nf_log_packet(pf, 0, skb, NULL, NULL, NULL, +- "nf_ct_tcp: invalid packed ignored "); ++ "nf_ct_tcp: invalid packet ignored "); + return NF_ACCEPT; + case TCP_CONNTRACK_MAX: + /* Invalid packet */ +@@ -948,8 +968,7 @@ static int tcp_packet(struct nf_conn *co + + conntrack->proto.tcp.state = new_state; + if (old_state != new_state +- && (new_state == TCP_CONNTRACK_FIN_WAIT +- || new_state == TCP_CONNTRACK_CLOSE)) ++ && new_state == TCP_CONNTRACK_FIN_WAIT) + conntrack->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT; + timeout = conntrack->proto.tcp.retrans >= nf_ct_tcp_max_retrans + && *tcp_timeouts[new_state] > nf_ct_tcp_timeout_max_retrans |