From 1fa1abac2517c833842e3807e231badf69619d83 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:38:38 -0500 Subject: [PATCH] - pre6: - truncate - the never-ending story. Makes me feel like a long Kurosawa movie. But in this one the hero _will_ survive, or my name isn't Maxwell. - SCSI tape driver potential memory leak. - XMM FP handler bug fix: we really must not change the FP error mask on exceptions. People care. --- arch/i386/kernel/setup.c | 7 ++- arch/i386/kernel/traps.c | 1 - drivers/ide/via82cxxx.c | 2 +- drivers/net/epic100.c | 20 ++++--- drivers/pcmcia/yenta.c | 11 +++- drivers/scsi/st.c | 2 + fs/buffer.c | 51 ++++++++++++---- fs/ext2/inode.c | 5 +- include/asm-i386/bugs.h | 122 +++++++++------------------------------ include/linux/fs.h | 2 +- kernel/ksyms.c | 2 +- 11 files changed, 99 insertions(+), 126 deletions(-) diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index e79572f90c85..00e5c7b44a85 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -1650,6 +1650,7 @@ int get_cpuinfo(char * buffer) int i, n; for (n = 0; n < NR_CPUS; n++, c++) { + int fpu_exception; #ifdef CONFIG_SMP if (!(cpu_online_map & (1<x86_capability & X86_FEATURE_SEP) && c->x86_model < 3 && c->x86_mask < 3; - + + /* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */ + fpu_exception = c->hard_math && (ignore_irq13 | (c->x86_capability & X86_FEATURE_FPU)); p += sprintf(p, "fdiv_bug\t: %s\n" "hlt_bug\t\t: %s\n" "sep_bug\t\t: %s\n" @@ -1739,7 +1742,7 @@ int get_cpuinfo(char * buffer) c->f00f_bug ? "yes" : "no", c->coma_bug ? "yes" : "no", c->hard_math ? "yes" : "no", - (c->hard_math && ignore_irq13) ? "yes" : "no", + fpu_exception ? "yes" : "no", c->cpuid_level, c->wp_works_ok ? "yes" : "no"); diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 7bd8a04d0523..2fae8b5163e5 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -641,7 +641,6 @@ void simd_math_error(void *eip) */ task = current; save_init_fpu(task); - load_mxcsr(0x1f80); task->thread.trap_no = 19; task->thread.error_code = 0; info.si_signo = SIGFPE; diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c index ef21c2cb7cd7..3780750a9d01 100644 --- a/drivers/ide/via82cxxx.c +++ b/drivers/ide/via82cxxx.c @@ -278,7 +278,7 @@ static int via_get_info(char *buffer, char **addr, off_t offset, int count) #endif -#define FIT(v,min,max) (((v)>(max)?(max):(v))<(min)?(min):(v)) +#define FIT(v,min,max) ((v)>(max)?(max):((v)<(min)?(min):(v))) #define ENOUGH(v,un) (((v)-1)/(un)+1) #ifdef DEBUG diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index afa7538af189..bdf5a4839410 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -199,7 +199,8 @@ static struct epic_chip_info epic_chip_info[] __devinitdata = { static struct pci_device_id epic_pci_tbl[] __devinitdata = { { 0x10B8, 0x0005, 0x1092, 0x0AB4, 0, 0, SMSC_83C170_0 }, { 0x10B8, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMSC_83C170 }, - { 0x10B8, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMSC_83C175 }, + { 0x10B8, 0x0006, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, SMSC_83C175 }, { 0,} }; MODULE_DEVICE_TABLE (pci, epic_pci_tbl); @@ -401,6 +402,12 @@ static int __devinit epic_init_one (struct pci_dev *pdev, dev->base_addr = ioaddr; dev->irq = pdev->irq; + + ep = dev->priv; + ep->pci_dev = pdev; + ep->chip_flags = ci->drv_flags; + spin_lock_init (&ep->lock); + printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", dev->name, ci->name, ioaddr, dev->irq); @@ -430,10 +437,6 @@ static int __devinit epic_init_one (struct pci_dev *pdev, i % 16 == 15 ? "\n" : ""); } - ep = dev->priv; - ep->pci_dev = pdev; - ep->chip_flags = ci->drv_flags; - /* Find the connected MII xcvrs. Doing this in open() would allow detecting external xcvrs later, but takes much time and no cards have external MII. */ @@ -486,11 +489,13 @@ static int __devinit epic_init_one (struct pci_dev *pdev, return 0; +err_out_iounmap: #ifndef USE_IO_OPS + iounmap ((void*) ioaddr); err_out_free_mmio: +#endif release_mem_region (pci_resource_start (pdev, 1), pci_resource_len (pdev, 1)); -#endif err_out_free_pio: release_region (pci_resource_start (pdev, 0), pci_resource_len (pdev, 0)); @@ -936,8 +941,7 @@ static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) long ioaddr = dev->base_addr; int status, boguscnt = max_interrupt_work; - if (!spin_trylock(&ep->lock)) - return; + spin_lock(&ep->lock); do { status = inl(ioaddr + INTSTAT); diff --git a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c index 4d3aa947e850..367bfc2dfebf 100644 --- a/drivers/pcmcia/yenta.c +++ b/drivers/pcmcia/yenta.c @@ -438,7 +438,7 @@ static unsigned int yenta_events(pci_socket_t *socket) u8 csc; u32 cb_event; unsigned int events; - + /* Clear interrupt status for the event */ cb_event = cb_readl(socket, CB_SOCKET_EVENT); cb_writel(socket, CB_SOCKET_EVENT, cb_event); @@ -552,6 +552,12 @@ static int yenta_socket_thread(void * data) daemonize(); strcpy(current->comm, "CardBus Watcher"); + if (request_irq(socket->cb_irq, yenta_interrupt, SA_SHIRQ, socket->dev->name, socket)) { + printk ("Yenta: unable to register irq %d\n", socket->cb_irq); + MOD_DEC_USE_COUNT; + return (1); + } + /* Figure out what the dang thing can do for the PCMCIA layer... */ yenta_get_socket_capabilities(socket, isa_interrupts); printk("Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE)); @@ -808,8 +814,7 @@ static int yenta_open(pci_socket_t *socket) /* Set up the bridge regions.. */ yenta_allocate_resources(socket); - if (dev->irq && !request_irq(dev->irq, yenta_interrupt, SA_SHIRQ, dev->name, socket)) - socket->cb_irq = dev->irq; + socket->cb_irq = dev->irq; /* Do we have special options for the device? */ for (i = 0; i < NR_OVERRIDES; i++) { diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index dd5d1786651c..333f4a55ee13 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -3486,6 +3486,8 @@ static int st_attach(Scsi_Device * SDp) if (tmp_da == NULL || tmp_ba == NULL) { if (tmp_da != NULL) kfree(tmp_da); + if (tmp_ba != NULL) + kfree(tmp_ba); SDp->attached--; write_unlock_irqrestore(&st_dev_arr_lock, flags); printk(KERN_ERR "st: Can't extend device array.\n"); diff --git a/fs/buffer.c b/fs/buffer.c index 58083e2b37c9..b43767835d65 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1518,9 +1518,6 @@ static int __block_commit_write(struct inode *inode, struct page *page, if (!buffer_uptodate(bh)) partial = 1; } else { - /* This can happen for the truncate case */ - if (!buffer_mapped(bh)) - continue; set_bit(BH_Uptodate, &bh->b_state); if (!atomic_set_buffer_dirty(bh)) { __mark_dirty(bh); @@ -1724,31 +1721,63 @@ int generic_commit_write(struct file *file, struct page *page, return 0; } -int block_zero_page(struct address_space *mapping, loff_t from, unsigned length) +int block_truncate_page(struct address_space *mapping, loff_t from, get_block_t *get_block) { unsigned long index = from >> PAGE_CACHE_SHIFT; unsigned offset = from & (PAGE_CACHE_SIZE-1); + unsigned blocksize, iblock, length, pos; struct inode *inode = (struct inode *)mapping->host; struct page *page; + struct buffer_head *bh; int err; + blocksize = inode->i_sb->s_blocksize; + length = offset & (blocksize - 1); + + /* Block boundary? Nothing to do */ if (!length) return 0; - page = read_cache_page(mapping, index, - (filler_t *)mapping->a_ops->readpage, NULL); + length = blocksize - length; + iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); + + page = grab_cache_page(mapping, index); err = PTR_ERR(page); if (IS_ERR(page)) goto out; - lock_page(page); - err = -EIO; - if (!Page_Uptodate(page)) - goto unlock; + + if (!page->buffers) + create_empty_buffers(page, inode, blocksize); + + /* Find the buffer that contains "offset" */ + bh = page->buffers; + pos = blocksize; + while (offset >= pos) { + bh = bh->b_this_page; + iblock++; + pos += blocksize; + } + + if (!buffer_uptodate(bh)) { + err = 0; + if (!buffer_mapped(bh)) { + get_block(inode, iblock, bh, 0); + if (!buffer_mapped(bh)) + goto unlock; + } + err = -EIO; + bh->b_end_io = end_buffer_io_sync; + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (!buffer_uptodate(bh)) + goto unlock; + } memset((char *) kmap(page) + offset, 0, length); flush_dcache_page(page); - __block_commit_write(inode, page, offset, offset+length); kunmap(page); + + mark_buffer_dirty(bh); err = 0; unlock: diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 720597b36a3d..0f3fec62c06d 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -874,7 +874,7 @@ void ext2_truncate (struct inode * inode) int nr = 0; int n; long iblock; - unsigned blocksize, tail; + unsigned blocksize; if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) @@ -887,9 +887,8 @@ void ext2_truncate (struct inode * inode) blocksize = inode->i_sb->s_blocksize; iblock = (inode->i_size + blocksize-1) >> EXT2_BLOCK_SIZE_BITS(inode->i_sb); - tail = (iblock << EXT2_BLOCK_SIZE_BITS(inode->i_sb)) - inode->i_size; - block_zero_page(inode->i_mapping, inode->i_size, tail); + block_truncate_page(inode->i_mapping, inode->i_size, ext2_get_block); n = ext2_block_to_path(inode, iblock, offsets); if (n == 0) diff --git a/include/asm-i386/bugs.h b/include/asm-i386/bugs.h index 0ec21d98aa7a..008a3d47d68f 100644 --- a/include/asm-i386/bugs.h +++ b/include/asm-i386/bugs.h @@ -50,32 +50,22 @@ static int __init no_387(char *s) __setup("no387", no_387); -static char __initdata fpu_error = 0; - -static struct timer_list copro_timer __initdata = {{0, 0}, 0}; - -static void __init copro_timeout(unsigned long dummy) -{ - fpu_error = 1; - mod_timer(&copro_timer, jiffies+HZ); - printk(KERN_ERR "387 failed: trying to reset\n"); - send_sig(SIGFPE, current, 1); - outb_p(0,0xf1); - outb_p(0,0xf0); -} - static double __initdata x = 4195835.0; static double __initdata y = 3145727.0; -#ifdef CONFIG_X86_XMM -static float __initdata zero[4] = { 0.0, 0.0, 0.0, 0.0 }; -static float __initdata one[4] = { 1.0, 1.0, 1.0, 1.0 }; -#endif - +/* + * This used to check for exceptions.. + * However, it turns out that to support that, + * the XMM trap handlers basically had to + * be buggy. So let's have a correct XMM trap + * handler, and forget about printing out + * some status at boot. + * + * We should really only care about bugs here + * anyway. Not features. + */ static void __init check_fpu(void) { - unsigned short control_word; - if (!boot_cpu_data.hard_math) { #ifndef CONFIG_MATH_EMULATION printk(KERN_EMERG "No coprocessor found and no math emulation present.\n"); @@ -84,72 +74,8 @@ static void __init check_fpu(void) #endif return; } - if (mca_pentium_flag) { - /* The IBM Model 95 machines with pentiums lock up on - * fpu test, so we avoid it. All pentiums have inbuilt - * FPU and thus should use exception 16. We still do - * the FDIV test, although I doubt there where ever any - * MCA boxes built with non-FDIV-bug cpus. - */ - __asm__("fninit\n\t" - "fldl %1\n\t" - "fdivl %2\n\t" - "fmull %2\n\t" - "fldl %1\n\t" - "fsubp %%st,%%st(1)\n\t" - "fistpl %0\n\t" - "fwait\n\t" - "fninit" - : "=m" (*&boot_cpu_data.fdiv_bug) - : "m" (*&x), "m" (*&y)); - printk("mca-pentium specified, avoiding FPU coupling test... "); - if (!boot_cpu_data.fdiv_bug) - printk("??? No FDIV bug? Lucky you...\n"); - else - printk("detected FDIV bug though.\n"); - return; - } - /* - * check if exception 16 works correctly.. This is truly evil - * code: it disables the high 8 interrupts to make sure that - * the irq13 doesn't happen. But as this will lead to a lockup - * if no exception16 arrives, it depends on the fact that the - * high 8 interrupts will be re-enabled by the next timer tick. - * So the irq13 will happen eventually, but the exception 16 - * should get there first.. - */ - printk(KERN_INFO "Checking 386/387 coupling... "); - init_timer(&copro_timer); - copro_timer.function = copro_timeout; - mod_timer(&copro_timer, jiffies+HZ/2); - __asm__("clts ; fninit ; fnstcw %0 ; fwait":"=m" (*&control_word)); - control_word &= 0xffc0; - __asm__("fldcw %0 ; fwait": :"m" (*&control_word)); - outb_p(inb_p(0x21) | (1 << 2), 0x21); - __asm__("fldz ; fld1 ; fdiv %st,%st(1) ; fwait"); - del_timer(&copro_timer); - if (fpu_error) - return; - if (!ignore_irq13) { - printk("OK, FPU using old IRQ 13 error reporting\n"); - return; - } - __asm__("fninit\n\t" - "fldl %1\n\t" - "fdivl %2\n\t" - "fmull %2\n\t" - "fldl %1\n\t" - "fsubp %%st,%%st(1)\n\t" - "fistpl %0\n\t" - "fwait\n\t" - "fninit" - : "=m" (*&boot_cpu_data.fdiv_bug) - : "m" (*&x), "m" (*&y)); - if (!boot_cpu_data.fdiv_bug) - printk("OK, FPU using exception 16 error reporting.\n"); - else - printk("Hmm, FPU using exception 16 error reporting with FDIV bug.\n"); +/* Enable FXSR and company _before_ testing for FP problems. */ #if defined(CONFIG_X86_FXSR) || defined(CONFIG_X86_RUNTIME_FXSR) /* * Verify that the FXSAVE/FXRSTOR data will be 16-byte aligned. @@ -168,18 +94,24 @@ static void __init check_fpu(void) printk(KERN_INFO "Enabling unmasked SIMD FPU exception support... "); set_in_cr4(X86_CR4_OSXMMEXCPT); printk("done.\n"); - - /* Check if exception 19 works okay. */ - load_mxcsr(0x0000); - printk(KERN_INFO "Checking SIMD FPU exceptions... "); - __asm__("movups %0,%%xmm0\n\t" - "movups %1,%%xmm1\n\t" - "divps %%xmm0,%%xmm1\n\t" - : : "m" (*&zero), "m" (*&one)); - printk("OK, SIMD FPU using exception 19 error reporting.\n"); load_mxcsr(0x1f80); } #endif + + /* Test for the divl bug.. */ + __asm__("fninit\n\t" + "fldl %1\n\t" + "fdivl %2\n\t" + "fmull %2\n\t" + "fldl %1\n\t" + "fsubp %%st,%%st(1)\n\t" + "fistpl %0\n\t" + "fwait\n\t" + "fninit" + : "=m" (*&boot_cpu_data.fdiv_bug) + : "m" (*&x), "m" (*&y)); + if (boot_cpu_data.fdiv_bug) + printk("Hmm, FPU with FDIV bug.\n"); } static void __init check_hlt(void) diff --git a/include/linux/fs.h b/include/linux/fs.h index c0157ad6d7d8..a759d8a6ab0b 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1173,7 +1173,7 @@ extern int block_sync_page(struct page *); int generic_block_bmap(struct address_space *, long, get_block_t *); int generic_commit_write(struct file *, struct page *, unsigned, unsigned); -int block_zero_page(struct address_space *, loff_t, unsigned); +int block_truncate_page(struct address_space *, loff_t, get_block_t *); extern int generic_file_mmap(struct file *, struct vm_area_struct *); extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *); diff --git a/kernel/ksyms.c b/kernel/ksyms.c index 7d7290c221e7..78527a70172f 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -203,7 +203,7 @@ EXPORT_SYMBOL(block_prepare_write); EXPORT_SYMBOL(block_sync_page); EXPORT_SYMBOL(cont_prepare_write); EXPORT_SYMBOL(generic_commit_write); -EXPORT_SYMBOL(block_zero_page); +EXPORT_SYMBOL(block_truncate_page); EXPORT_SYMBOL(generic_block_bmap); EXPORT_SYMBOL(generic_file_read); EXPORT_SYMBOL(do_generic_file_read); -- 2.39.5