]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.4.0-test8 2.4.0-test8
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:38:41 +0000 (15:38 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:38:41 +0000 (15:38 -0500)
Ok, as the truncate problems really seem to be fixed, it's time to do an
official test8, the first development kernel in about a year and a half
that should have a working truncate() again. Thanks to everybody who
tested, and especially to Al Viro who did a lot of the heavy lifting.

There are a number of other various changes there too - the truncate fix
itself was fairly small, it was just more complex than most problems that
can be solved in 50 lines of code.

The only one of any note that I'd like to point out directly is the
clarification in the COPYING file, making it clear that it's only _that_
particular version of the GPL that is valid for the kernel. This should
not come as any surprise, as that's the same license that has been there
since 0.12 or so, but I thought I'd make that explicit.

Why? There's been some discussions of a GPL v3 which would limit licensing
to certain "well-behaved" parties, and I'm not sure I'd agree with such
restrictions - and the GPL itself allows for "any version" so I wanted to
make this part unambigious as far as my personal code is concerned.

The reason I wanted to mention that particular issue here explicitly
(rather than as just a one-liner in the changelog) is that code written by
others is obviously under _their_ discretion, and not limited by my
personal foibles, fears and misgivings.

If anybody wants to explicitly state that their code will be valid under
any version of the GPL (current or future - whatever they may look like),
please send patches to say so for the code in question. If you've used the
FSF boiler-place copyright notice, you already have this in place (it says
"v2 or later" - the FSF itself doesn't recommend v1 any more).

(Me, I'm taking the careful "wait and see" approach. I don't know if a GPL
v3 is imminent, and I don't know if the issues discussed will even
_become_ real issues, so you might as well consider me a paranoid, if
careful, bastard).

Linus

 - final:
    - sparc updates
    - routing cleanups
    - fix up warnings
    - USB: dsbr driver update and warning cleanup
    - USB: update the status file timestamps when changes occur
    - USB: clean up module init/exit. No more explicit inits.
    - USB: bluetooth and microtek driver updates
    - serial.c: remove duplicated code. Add SGI serial port signature.
    - /proc/kcore and ncpfs - more care with kernel virtual addresses
    - discontiguous memory initialization fixup
    - sd oom fixes
    - pcmcia state machine fixes.
    - microcode driver update - make sure we get a sane revision level
    - copyright license version clarification (make v2 explicit)
    - epic100, 8139too and tulip driver updates
    - clean up truncate_inode_pages (no, this has nothing to do with the
      rest of the truncate issues)
    - jffs update

93 files changed:
COPYING
CREDITS
Documentation/DMA-mapping.txt
Documentation/cachetlb.txt
Documentation/networking/8139too.txt
Documentation/networking/tulip.txt
arch/arm/mm/init.c
arch/i386/kernel/microcode.c
arch/i386/kernel/mpparse.c
arch/mips64/sgi-ip27/ip27-memory.c
arch/sh/mm/init.c
arch/sparc/kernel/Makefile
arch/sparc/kernel/entry.S
arch/sparc/kernel/irq.c
arch/sparc/kernel/pcic.c
arch/sparc/kernel/process.c
arch/sparc/kernel/setup.c
arch/sparc/kernel/signal.c
arch/sparc/kernel/smp.c
arch/sparc/kernel/solaris.c [deleted file]
arch/sparc/kernel/sparc_ksyms.c
arch/sparc/kernel/sun4d_smp.c
arch/sparc/kernel/sun4m_smp.c
arch/sparc/kernel/sunos_ioctl.c
arch/sparc/kernel/sys_solaris.c
arch/sparc/kernel/traps.c
arch/sparc/mm/init.c
arch/sparc64/kernel/entry.S
arch/sparc64/kernel/irq.c
arch/sparc64/kernel/pci.c
arch/sparc64/kernel/process.c
arch/sparc64/kernel/signal.c
arch/sparc64/kernel/signal32.c
arch/sparc64/mm/init.c
arch/sparc64/solaris/signal.c
drivers/char/serial.c
drivers/net/8139too.c
drivers/net/epic100.c
drivers/net/sunhme.c
drivers/net/tulip/interrupt.c
drivers/net/tulip/tulip_core.c
drivers/pcmcia/cs.c
drivers/sbus/audio/dbri.c
drivers/sbus/char/Makefile
drivers/sbus/char/sab82532.c
drivers/sbus/char/su.c
drivers/sbus/char/vfc_dev.c
drivers/scsi/sd.c
drivers/scsi/sr.c
drivers/usb/bluetooth.c
drivers/usb/dabusb.c
drivers/usb/dsbr100.c
drivers/usb/inode.c
drivers/usb/microtek.c
drivers/usb/serial/whiteheat.c
drivers/usb/uhci.c
drivers/usb/usb-core.c
drivers/usb/usb-ohci.c
drivers/usb/usb-uhci.c
drivers/usb/uss720.c
fs/jffs/inode-v23.c
fs/jffs/intrep.c
fs/jffs/intrep.h
fs/jffs/jffs_fm.c
fs/jffs/jffs_fm.h
fs/ncpfs/dir.c
fs/proc/kcore.c
include/asm-i386/mpspec.h
include/asm-i386/spinlock.h
include/asm-sparc/atomic.h
include/asm-sparc/audioio.h
include/asm-sparc/floppy.h
include/asm-sparc/smp.h
include/linux/mm.h
include/linux/mmzone.h
include/linux/netdevice.h
include/linux/smp.h
include/net/route.h
ipc/shm.c
kernel/ptrace.c
mm/filemap.c
mm/numa.c
mm/page_alloc.c
net/core/dev.c
net/ipv4/igmp.c
net/ipv4/ip_output.c
net/ipv4/netfilter/ip_nat_standalone.c
net/ipv4/netfilter/iptable_mangle.c
net/ipv4/route.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp_input.c
net/ipv4/tcp_minisocks.c
net/netsyms.c

diff --git a/COPYING b/COPYING
index c69cfd8ca427d2b966b41704e0f06cb3f7aa9a30..e84a6886f1b729b1a936ad37e575e9006212c709 100644 (file)
--- a/COPYING
+++ b/COPYING
@@ -6,6 +6,10 @@
  Foundation, but the instance of code that it refers to (the Linux
  kernel) is copyrighted by me and others who actually wrote it.
 
+ Also note that the only valid version of the GPL as far as the kernel
+ is concerned is _this_ license (ie v2), unless explicitly otherwise
+ stated.
+
                        Linus Torvalds
 
 ----------------------------------------
diff --git a/CREDITS b/CREDITS
index 3a2378a96e3e2054e0c030b9ca2d480059113011..9901b1851328f4196b7958be9a51a606cd58186a 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -2126,6 +2126,16 @@ S: 4390 Albany Drive #41A
 S: San Jose, California 95129
 S: USA
 
+N: Juan Quintela
+E: quintela@fi.udc.es
+D: Memory Management hacking
+S: LFCIA
+S: Departamento de Computación
+S: Universidade da Coruña
+S: E-15071
+S: A Coruña
+S: Spain
+
 N: Augusto Cesar Radtke
 E: bishop@sekure.org
 W: http://bishop.sekure.org
index 5dd11a173dca5b58f5b14c5b69a7959df06fe948..0ffccdee23617a59d600947e72f5646addc23b2c 100644 (file)
@@ -345,13 +345,13 @@ to use the pci_dma_sync_*() interfaces.
                         * the DMA transfer with the CPU first
                         * so that we see updated contents.
                         */
-                       pci_dma_sync_single(cp->pdev, cp->rx_buf, cp->rx_len,
+                       pci_dma_sync_single(cp->pdev, cp->rx_dma, cp->rx_len,
                                            PCI_DMA_FROMDEVICE);
 
                        /* Now it is safe to examine the buffer. */
                        hp = (struct my_card_header *) cp->rx_buf;
                        if (header_is_ok(hp)) {
-                               pci_unmap_single(cp->pdev, cp->rx_buf, cp->rx_len,
+                               pci_unmap_single(cp->pdev, cp->rx_dma, cp->rx_len,
                                                 PCI_DMA_FROMDEVICE);
                                pass_to_upper_layers(cp->rx_buf);
                                make_and_setup_new_rx_buf(cp);
index 578dcb3150b711ddcd46e3bb835d54fc9585b42d..3d003463db24896297e0c8aff490fe33f6c3063a 100644 (file)
@@ -47,7 +47,7 @@ changes occur:
 
        This interface is used to handle whole address space
        page table operations such as what happens during
-       fork, exit, and exec.
+       fork, and exec.
 
 3) void flush_tlb_range(struct mm_struct *mm,
                        unsigned long start, unsigned long end)
@@ -272,7 +272,7 @@ Here is the new interface:
        for example, uses this technique.
 
        The "address" parameter tells the virtual address where the
-       user has this page mapped.
+       user will ultimately this page mapped.
 
        If D-cache aliasing is not an issue, these two routines may
        simply call memcpy/memset directly and do nothing more.
index f27811a2a1c7492e05bbaaabc992d59324014195..fc45638c7579b145522fb252bd7e4b881a79deb3 100644 (file)
@@ -188,6 +188,15 @@ User-mode (or maybe optional /proc) diagnostics program.
 
 Change History
 --------------
+Version 0.9.8 - September 7, 2000
+
+* Propagate request_irq error value (andrew morton)
+* Correct potential oops bug in PCI DMA unmap code
+* Fix bugs related to counting/discounting of 32-bit CRC in each Rx packet
+* Fix 16/32-bit bug in interrupt status check
+* Timer cleanups (andrew morton)
+
+
 Version 0.9.7 - June 11, 2000
 
 * Fix support for older chips (RTL8139 early chips should now work again)
index b5a6254228fd0953d2ed2669cdd6cf5f52edab38..5363811cb58c53870b8635859391b063c800b3bf 100644 (file)
@@ -142,6 +142,13 @@ tulip_core.c       - Driver core (a.k.a. where "everything else" goes)
 
 Version history
 ===============
+0.9.10 (September 6, 2000):
+* Simple interrupt mitigation (via jamal)
+* More PCI ids
+
+0.9.9 (August 11, 2000):
+* More PCI ids
+
 0.9.8 (July 13, 2000):
 * Correct signed/unsigned comparison for dummy frame index
 * Remove outdated references to struct enet_statistics
index ba58e8bade42dce48fbfab296d02503d3c619e0e..c66dd3669ddbe6b13fb4631770836316478f9b4d 100644 (file)
@@ -528,7 +528,7 @@ void __init paging_init(struct meminfo *mi)
                        zhole_size[0] -= mi->bank[i].size >> PAGE_SHIFT;
                }
 
-               free_area_init_node(node, pgdat, zone_size,
+               free_area_init_node(node, pgdat, 0, zone_size,
                                bdata->node_boot_start, zhole_size);
        }
 
index 1d5b7b3c89ff1fc47a86444b65f0c41296d0575c..80536a1c4deb2b8c8808b5599d368b97ab66c2a7 100644 (file)
  *             Removed ->release(). Removed exclusive open and status bitmap.
  *             Added microcode_rwsem to serialize read()/write()/ioctl().
  *             Removed global kernel lock usage.
+ *     1.07    07 Sep 2000, Tigran Aivazian <tigran@veritas.com>
+ *             Write 0 to 0x8B msr and then cpuid before reading revision,
+ *             so that it works even if there were no update done by the
+ *             BIOS. Otherwise, reading from 0x8B gives junk (which happened
+ *             to be 0 on my machine which is why it worked even when I
+ *             disabled update by the BIOS)
+ *             Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
  */
 
 #include <linux/init.h>
@@ -51,7 +58,7 @@
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 
-#define MICROCODE_VERSION      "1.06"
+#define MICROCODE_VERSION      "1.07"
 
 MODULE_DESCRIPTION("Intel CPU (P6) microcode update driver");
 MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
@@ -188,7 +195,8 @@ static void do_update_one(void *unused)
                    microcode[i].ldrver == 1 && microcode[i].hdrver == 1) {
 
                        found=1;
-
+                       wrmsr(0x8B, 0, 0);
+                       __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
                        rdmsr(0x8B, val[0], rev);
                        if (microcode[i].rev <= rev) {
                                printk(KERN_ERR 
index 746bea030706e024cf21558529096f61ce94e933..66b70a86b1b87e544c3e608ad9ecac03c8cd00ca 100644 (file)
@@ -35,7 +35,7 @@ int smp_found_config = 0;
  * MP-table.
  */
 int apic_version [MAX_APICS];
-int mp_bus_id_to_type [MAX_MP_BUSSES] = { -1, };
+int mp_bus_id_to_type [MAX_MP_BUSSES];
 int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { -1, };
 int mp_current_pci_id = 0;
 int pic_mode;
@@ -158,19 +158,18 @@ static void __init MP_bus_info (struct mpc_config_bus *m)
        str[6] = 0;
        Dprintk("Bus #%d is %s\n", m->mpc_busid, str);
 
-       if (strncmp(str, "ISA", 3) == 0) {
+       if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA)-1) == 0) {
                mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA;
-       } else if (strncmp(str, "EISA", 4) == 0) {
+       } else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA)-1) == 0) {
                mp_bus_id_to_type[m->mpc_busid] = MP_BUS_EISA;
-       } else if (strncmp(str, "PCI", 3) == 0) {
+       } else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI)-1) == 0) {
                mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI;
                mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id;
                mp_current_pci_id++;
-       } else if (strncmp(str, "MCA", 3) == 0) {
+       } else if (strncmp(str, BUSTYPE_MCA, sizeof(BUSTYPE_MCA)-1) == 0) {
                mp_bus_id_to_type[m->mpc_busid] = MP_BUS_MCA;
        } else {
-               printk("Unknown bustype %s\n", str);
-               panic("cannot handle bus - mail to linux-smp@vger.kernel.org");
+               printk("Unknown bustype %s - ignoring\n", str);
        }
 }
 
index c31e006679b7aa3a551aa07046d40fe1212a6d40..50e03413bed6f69dbb8628a465a6de019571beb9 100644 (file)
@@ -242,7 +242,7 @@ void __init paging_init(void)
                pfn_t end_pfn = node_getmaxclick(node);
 
                zones_size[ZONE_DMA] = end_pfn + 1 - start_pfn;
-               free_area_init_node(node, NODE_DATA(node), zones_size, 
+               free_area_init_node(node, NODE_DATA(node), 0, zones_size, 
                                                start_pfn << PAGE_SHIFT, 0);
                if ((PLAT_NODE_DATA_STARTNR(node) + 
                                        PLAT_NODE_DATA_SIZE(node)) > pagenr)
index 5e0632a86c847f801ccb4489f6893b3c0190e2d7..ccabeb85f050afd32eef274be533fa7bbf451eb5 100644 (file)
@@ -227,7 +227,7 @@ void __init paging_init(void)
                        zones_size[ZONE_DMA] = max_dma - start_pfn;
                        zones_size[ZONE_NORMAL] = low - max_dma;
                }
-               free_area_init_node(0, 0, zones_size, __MEMORY_START, 0);
+               free_area_init_node(0, 0, 0, zones_size, __MEMORY_START, 0);
        }
 }
 
index c8c79591cbb2c21cf6989a1a9734a4426b2c7ab0..d57c23c1f6c1f4eb248edb3a6c7574021192f48f 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.60 2000/08/12 08:35:53 ecd Exp $
+# $Id: Makefile,v 1.61 2000/09/03 13:58:04 anton Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -22,7 +22,7 @@ IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o sun4d_irq.o
 O_OBJS   := entry.o wof.o wuf.o etrap.o rtrap.o traps.o ${IRQ_OBJS} \
            process.o signal.o ioport.o setup.o idprom.o \
            sys_sparc.o sunos_asm.o sparc-stub.o systbls.o \
-           time.o windows.o cpu.o devices.o sclow.o solaris.o \
+           time.o windows.o cpu.o devices.o sclow.o \
            tadpole.o tick14.o ptrace.o sys_solaris.o \
            unaligned.o muldiv.o pcic.o semaphore.o
 
index cd2f3731ab43af45eb383bf46919f3f78c0adb4e..c44fe3196d2e1f702eeebac3ea2ccbf0bf40a925 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.166 2000/06/19 06:24:36 davem Exp $
+/* $Id: entry.S,v 1.167 2000/09/06 00:45:00 davem Exp $
  * arch/sparc/kernel/entry.S:  Sparc trap low-level entry points.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index a08842491500a1181f109871ebb30000d7760595..eaa7fc4a3e0aee8deff7549b0781201758541e2d 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: irq.c,v 1.107 2000/08/26 02:42:28 anton Exp $
+/*  $Id: irq.c,v 1.109 2000/08/31 10:00:39 anton Exp $
  *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
  *                            Sparc the IRQ's are basically 'cast in stone'
  *                            and you are supposed to probe the prom's device
@@ -197,7 +197,7 @@ void free_irq(unsigned int irq, void *dev_id)
 
 #ifdef CONFIG_SMP
 
-/* Who has global_irq_lock. */
+/* Who has the global irq brlock */
 unsigned char global_irq_holder = NO_PROC_ID;
 
 void smp_show_backtrace_all_cpus(void);
@@ -329,7 +329,8 @@ void __global_sti(void)
  */
 unsigned long __global_save_flags(void)
 {
-       unsigned long flags, local_enabled, retval;
+       unsigned long flags, retval;
+       unsigned long local_enabled = 0;
 
        __save_flags(flags);
 
index d5ce7038ad28d47d9df094147946c5cd6031f008..293cf43f9598f81b84d772b1a1cf74a742bc38f2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pcic.c,v 1.16 2000/07/11 01:38:57 davem Exp $
+/* $Id: pcic.c,v 1.17 2000/09/05 06:49:44 anton Exp $
  * pcic.c: Sparc/PCI controller support
  *
  * Copyright (C) 1998 V. Roganov and G. Raiko
@@ -940,7 +940,6 @@ asmlinkage int sys_pciconfig_read(unsigned long bus,
        if(!suser())
                return -EPERM;
 
-       lock_kernel();
        switch(len) {
        case 1:
                pcibios_read_config_byte(bus, dfn, off, &ubyte);
@@ -959,7 +958,6 @@ asmlinkage int sys_pciconfig_read(unsigned long bus,
                err = -EINVAL;
                break;
        };
-       unlock_kernel();
 
        return err;
 }
index f730f850bb0bfc8cbd3000af9c4b8bde015401bc..fe45f1f3c21ff972d586e217774bedc6adc9aaba 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.151 2000/07/11 23:22:17 davem Exp $
+/*  $Id: process.c,v 1.153 2000/09/06 00:45:01 davem Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -234,7 +234,6 @@ void show_backtrace(void)
 void smp_show_backtrace_all_cpus(void)
 {
        xc0((smpfunc_t) show_backtrace);
-       show_backtrace();
 }
 #endif
 
index 5398a93818ab4fb7e9522bdc671f946c37866df6..bce4ffcdfd76c8574cac7d31c901bca007d47c5f 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.118 2000/05/09 17:40:13 davem Exp $
+/*  $Id: setup.c,v 1.119 2000/08/31 10:24:17 anton Exp $
  *  linux/arch/sparc/kernel/setup.c
  *
  *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
@@ -80,12 +80,7 @@ void prom_sync_me(void)
 {
        unsigned long prom_tbr, flags;
 
-#ifdef CONFIG_SMP
-       global_irq_holder = NO_PROC_ID;
-       *((unsigned char *)&global_irq_lock) = 0;
-       *((unsigned char *)&global_bh_lock) = 0;
-#endif
-       __save_and_cli(flags);
+       save_and_cli(flags);
        __asm__ __volatile__("rd %%tbr, %0\n\t" : "=r" (prom_tbr));
        __asm__ __volatile__("wr %0, 0x0, %%tbr\n\t"
                             "nop\n\t"
@@ -99,9 +94,9 @@ void prom_sync_me(void)
        prom_printf("PROM SYNC COMMAND...\n");
        show_free_areas();
        if(current->pid != 0) {
-               __sti();
+               sti();
                sys_sync();
-               __cli();
+               cli();
        }
        prom_printf("Returning to prom\n");
 
@@ -109,7 +104,7 @@ void prom_sync_me(void)
                             "nop\n\t"
                             "nop\n\t"
                             "nop\n\t" : : "r" (prom_tbr));
-       __restore_flags(flags);
+       restore_flags(flags);
 
        return;
 }
index 012d19effe8059c5ead0438ca54796ddda4a4e84..6ac8c4b00fa0c654df9bec72c544ac003dae78fb 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.106 2000/07/07 04:25:17 davem Exp $
+/*  $Id: signal.c,v 1.107 2000/09/05 21:44:54 davem Exp $
  *  linux/arch/sparc/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
index 677b2c8117c99e7baf4aeb1fdbc51d680a752666..0e1944411412c0344a784f1cb531721e14a7b739 100644 (file)
@@ -145,35 +145,33 @@ void __init smp_boot_cpus(void)
 void smp_flush_cache_all(void)
 {
        xc0((smpfunc_t) BTFIXUP_CALL(local_flush_cache_all));
-       local_flush_cache_all();
 }
 
 void smp_flush_tlb_all(void)
 {
        xc0((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_all));
-       local_flush_tlb_all();
 }
 
 void smp_flush_cache_mm(struct mm_struct *mm)
 {
        if(mm->context != NO_CONTEXT) {
-               if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+               if(mm->cpu_vm_mask == (1 << smp_processor_id()))
+                       local_flush_cache_mm(mm);
+               else
                        xc1((smpfunc_t) BTFIXUP_CALL(local_flush_cache_mm), (unsigned long) mm);
-
-               local_flush_cache_mm(mm);
        }
 }
 
 void smp_flush_tlb_mm(struct mm_struct *mm)
 {
        if(mm->context != NO_CONTEXT) {
-               if(mm->cpu_vm_mask != (1 << smp_processor_id())) {
+               if(mm->cpu_vm_mask == (1 << smp_processor_id())) {
+                       local_flush_tlb_mm(mm);
+               } else {
                        xc1((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_mm), (unsigned long) mm);
                        if(atomic_read(&mm->mm_users) == 1 && current->active_mm == mm)
                                mm->cpu_vm_mask = (1 << smp_processor_id());
                }
-
-               local_flush_tlb_mm(mm);
        }
 }
 
@@ -181,10 +179,10 @@ void smp_flush_cache_range(struct mm_struct *mm, unsigned long start,
                           unsigned long end)
 {
        if(mm->context != NO_CONTEXT) {
-               if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+               if(mm->cpu_vm_mask == (1 << smp_processor_id()))
+                       local_flush_cache_range(mm, start, end);
+               else
                        xc3((smpfunc_t) BTFIXUP_CALL(local_flush_cache_range), (unsigned long) mm, start, end);
-
-               local_flush_cache_range(mm, start, end);
        }
 }
 
@@ -192,10 +190,10 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
                         unsigned long end)
 {
        if(mm->context != NO_CONTEXT) {
-               if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+               if(mm->cpu_vm_mask == (1 << smp_processor_id()))
+                               local_flush_tlb_range(mm, start, end);
+               else
                        xc3((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_range), (unsigned long) mm, start, end);
-
-               local_flush_tlb_range(mm, start, end);
        }
 }
 
@@ -204,10 +202,10 @@ void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
        struct mm_struct *mm = vma->vm_mm;
 
        if(mm->context != NO_CONTEXT) {
-               if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+               if(mm->cpu_vm_mask == (1 << smp_processor_id()))
+                       local_flush_cache_page(vma, page);
+               else
                        xc2((smpfunc_t) BTFIXUP_CALL(local_flush_cache_page), (unsigned long) vma, page);
-
-               local_flush_cache_page(vma, page);
        }
 }
 
@@ -216,10 +214,10 @@ void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
        struct mm_struct *mm = vma->vm_mm;
 
        if(mm->context != NO_CONTEXT) {
-               if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+               if(mm->cpu_vm_mask == (1 << smp_processor_id()))
+                       local_flush_tlb_page(vma, page);
+               else
                        xc2((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_page), (unsigned long) vma, page);
-
-               local_flush_tlb_page(vma, page);
        }
 }
 
@@ -233,7 +231,6 @@ void smp_flush_page_to_ram(unsigned long page)
         */
 #if 1
        xc1((smpfunc_t) BTFIXUP_CALL(local_flush_page_to_ram), page);
-       local_flush_page_to_ram(page);
 #else
        local_flush_page_to_ram(page);
 #endif
@@ -241,10 +238,10 @@ void smp_flush_page_to_ram(unsigned long page)
 
 void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
 {
-       if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+       if(mm->cpu_vm_mask == (1 << smp_processor_id()))
+               local_flush_sig_insns(mm, insn_addr);
+       else
                xc2((smpfunc_t) BTFIXUP_CALL(local_flush_sig_insns), (unsigned long) mm, insn_addr);
-
-       local_flush_sig_insns(mm, insn_addr);
 }
 
 /* Reschedule call back. */
diff --git a/arch/sparc/kernel/solaris.c b/arch/sparc/kernel/solaris.c
deleted file mode 100644 (file)
index bcebd92..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/* solaris.c: Solaris binary emulation, whee...
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-
-#include <asm/errno.h>
-#include <asm/solerrno.h>
-
-asmlinkage int solaris_open(const char *filename, int flags, int mode)
-{
-       int newflags;
-       int ret;
-
-       lock_kernel();
-       newflags = flags & 0xf;
-       flags &= ~0xf;
-       if(flags & 0x8050)
-               newflags |= FASYNC;
-       if(flags & 0x80)
-               newflags |= O_NONBLOCK;
-       if(flags & 0x100)
-               newflags |= O_CREAT;
-       if(flags & 0x200)
-               newflags |= O_TRUNC;
-       if(flags & 0x400)
-               newflags |= O_EXCL;
-       if(flags & 0x800)
-               newflags |= O_NOCTTY;
-       ret = sys_open(filename, newflags, mode);
-       unlock_kernel();
-       return ret;
-}
index a1742c21d3f29549072df7ac08fd3d2c37f876cb..997e4d0ced62a8ea5bb2a74a1c307a7eae66d00f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.103 2000/08/26 02:42:28 anton Exp $
+/* $Id: sparc_ksyms.c,v 1.104 2000/09/06 05:43:00 anton Exp $
  * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -141,6 +141,11 @@ EXPORT_SYMBOL(__global_cli);
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
+
+/* Misc SMP information */
+EXPORT_SYMBOL(smp_num_cpus);
+EXPORT_SYMBOL(__cpu_number_map);
+EXPORT_SYMBOL(__cpu_logical_map);
 #endif
 
 EXPORT_SYMBOL(udelay);
index 2803926296e3c120912bbfe7be109acd4a524d62..3a4e93eb869138e1af2d7dee44d9b54b06e8ccb5 100644 (file)
@@ -376,6 +376,9 @@ void smp4d_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
                        }
                }
 
+               /* First, run local copy. */
+               func(arg1, arg2, arg3, arg4, arg5);  
+
                {
                        register int i;
 
@@ -393,6 +396,8 @@ void smp4d_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
                }
 
                spin_unlock_irqrestore(&cross_call_lock, flags);
+       } else {
+               func(arg1, arg2, arg3, arg4, arg5); /* Just need to run local copy. */
        }
 }
 
index d6c126d00c1a897ebae19bdb82dc2782c344e82f..52c37f51bf9027671bcd16d91b6769a690d27300 100644 (file)
@@ -405,6 +405,9 @@ void smp4m_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
                        }
                }
 
+               /* First, run local copy. */
+               func(arg1, arg2, arg3, arg4, arg5);  
+
                {
                        register int i;
 
@@ -422,6 +425,8 @@ void smp4m_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
                }
 
                spin_unlock_irqrestore(&cross_call_lock, flags);
+       } else {
+               func(arg1, arg2, arg3, arg4, arg5); /* Just need to run local copy. */
        }
 }
 
index dc26d2cc231955cf4a1a306c898998385ac88ad4..61df3ea6dc9f13d0a1201a01d335e2d2e191f189 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunos_ioctl.c,v 1.33 1999/07/28 12:59:03 anton Exp $
+/* $Id: sunos_ioctl.c,v 1.34 2000/09/03 14:10:56 anton Exp $
  * sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility.
  * 
  * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -39,7 +39,6 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg)
 {
        int ret = -EBADF;
 
-       lock_kernel();
        if (fd >= SUNOS_NR_OPEN || !fcheck(fd))
                goto out;
 
@@ -227,7 +226,6 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg)
        /* so stupid... */
        ret = (ret == -EINVAL ? -EOPNOTSUPP : ret);
 out:
-       unlock_kernel();
        return ret;
 }
 
index d099c4e8acc8af35677a0a76941694014d6d1788..fb7578554c78346a2d49703a9577743f90d878cb 100644 (file)
 #include <linux/smp_lock.h>
 #include <linux/module.h>
 
-/* CHECKME: this stuff looks rather bogus */
 asmlinkage int
 do_solaris_syscall (struct pt_regs *regs)
 {
-       int ret;
-
-       lock_kernel();
-       set_personality(PER_SVR4);
-
-       if (current->exec_domain && current->exec_domain->handler){
-               current->exec_domain->handler (0, regs);
-
-               /* What is going on here?  Why do we do this? */
-
-               /* XXX current->exec_domain->use_count = 0; XXX */
-
-               ret = regs->u_regs [UREG_I0];
-       } else {
-               printk ("No solaris handler\n");
-               send_sig (SIGSEGV, current, 1);
-               ret = 0;
-       }
-       unlock_kernel();
-       return ret;
+       static int cnt = 0;
+       if (++cnt < 10) printk ("No solaris handler\n");
+       force_sig(SIGSEGV, current);
+       return 0;
 }
 
 #ifndef CONFIG_SUNOS_EMUL
@@ -48,9 +31,7 @@ do_sunos_syscall (struct pt_regs *regs)
 {
        static int cnt = 0;
        if (++cnt < 10) printk ("SunOS binary emulation not compiled in\n");
-       lock_kernel();
        force_sig (SIGSEGV, current);
-       unlock_kernel();
        return 0;
 }
 #endif
index 3564a4517526f76cee9d4b59e659be76e039dbf1..5c361f9335e4a03b2db21acfc6fb6f3860dcd00e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.63 2000/06/04 06:23:52 anton Exp $
+/* $Id: traps.c,v 1.64 2000/09/03 15:00:49 anton Exp $
  * arch/sparc/kernel/traps.c
  *
  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -132,7 +132,6 @@ void do_hw_interrupt(unsigned long type, unsigned long psr, unsigned long pc)
 {
        siginfo_t info;
 
-       lock_kernel();
        if(type < 0x80) {
                /* Sun OS's puke from bad traps, Linux survives! */
                printk("Unimplemented Sparc TRAP, type = %02lx\n", type);
@@ -148,7 +147,6 @@ void do_hw_interrupt(unsigned long type, unsigned long psr, unsigned long pc)
        info.si_addr = (void *)pc;
        info.si_trapno = type - 0x80;
        force_sig_info(SIGILL, &info, current);
-       unlock_kernel();
 }
 
 void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
@@ -156,7 +154,6 @@ void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned lon
 {
        siginfo_t info;
 
-       lock_kernel();
        if(psr & PSR_PS)
                die_if_kernel("Kernel illegal instruction", regs);
 #ifdef TRAP_DEBUG
@@ -166,7 +163,7 @@ void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned lon
        if (sparc_cpu_model == sun4c || sparc_cpu_model == sun4) {
                extern int do_user_muldiv (struct pt_regs *, unsigned long);
                if (!do_user_muldiv (regs, pc))
-                       goto out;
+                       return;
        }
        info.si_signo = SIGILL;
        info.si_errno = 0;
@@ -174,8 +171,6 @@ void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned lon
        info.si_addr = (void *)pc;
        info.si_trapno = 0;
        send_sig_info(SIGILL, &info, current);
-out:
-       unlock_kernel();
 }
 
 void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
@@ -183,7 +178,6 @@ void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long n
 {
        siginfo_t info;
 
-       lock_kernel();
        if(psr & PSR_PS)
                die_if_kernel("Penguin instruction from Penguin mode??!?!", regs);
        info.si_signo = SIGILL;
@@ -192,7 +186,6 @@ void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long n
        info.si_addr = (void *)pc;
        info.si_trapno = 0;
        send_sig_info(SIGILL, &info, current);
-       unlock_kernel();
 }
 
 /* XXX User may want to be allowed to do this. XXX */
@@ -202,7 +195,6 @@ void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned lon
 {
        siginfo_t info;
 
-       lock_kernel();
        if(regs->psr & PSR_PS) {
                printk("KERNEL MNA at pc %08lx npc %08lx called by %08lx\n", pc, npc,
                       regs->u_regs[UREG_RETPC]);
@@ -220,7 +212,6 @@ void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned lon
        info.si_addr = /* FIXME: Should dig out mna address */ (void *)0;
        info.si_trapno = 0;
        send_sig_info(SIGBUS, &info, current);
-       unlock_kernel();
 }
 
 extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
@@ -237,7 +228,6 @@ static unsigned long init_fregs[32] __attribute__ ((aligned (8))) =
 void do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
                 unsigned long psr)
 {
-       lock_kernel();
        /* Sanity check... */
        if(psr & PSR_PS)
                die_if_kernel("Kernel gets FloatingPenguinUnit disabled trap", regs);
@@ -246,7 +236,7 @@ void do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
        regs->psr |= PSR_EF;
 #ifndef CONFIG_SMP
        if(last_task_used_math == current)
-               goto out;
+               return;
        if(last_task_used_math) {
                /* Other processes fpu state, save away */
                struct task_struct *fptask = last_task_used_math;
@@ -270,10 +260,6 @@ void do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
        }
        current->flags |= PF_USEDFPU;
 #endif
-#ifndef CONFIG_SMP
-out:
-#endif
-       unlock_kernel();
 }
 
 static unsigned long fake_regs[32] __attribute__ ((aligned (8)));
@@ -295,7 +281,6 @@ void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 #else
        struct task_struct *fpt = current;
 #endif
-       lock_kernel();
        put_psr(get_psr() | PSR_EF);
        /* If nobody owns the fpu right now, just clear the
         * error into our fake static buffer and hope it don't
@@ -308,7 +293,7 @@ void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 #endif
                fpsave(&fake_regs[0], &fake_fsr, &fake_queue[0], &fake_depth);
                regs->psr &= ~PSR_EF;
-               goto out;
+               return;
        }
        fpsave(&fpt->thread.float_regs[0], &fpt->thread.fsr,
               &fpt->thread.fpqueue[0], &fpt->thread.fpqdepth);
@@ -361,7 +346,7 @@ void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
                if(calls > 2)
                        die_if_kernel("Too many Penguin-FPU traps from kernel mode",
                                      regs);
-               goto out;
+               return;
        }
 
        fsr = fpt->thread.fsr;
@@ -389,8 +374,6 @@ void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
        regs->psr &= ~PSR_EF;
        if(calls > 0)
                calls=0;
-out:
-       unlock_kernel();
 }
 
 void handle_tag_overflow(struct pt_regs *regs, unsigned long pc, unsigned long npc,
@@ -398,7 +381,6 @@ void handle_tag_overflow(struct pt_regs *regs, unsigned long pc, unsigned long n
 {
        siginfo_t info;
 
-       lock_kernel();
        if(psr & PSR_PS)
                die_if_kernel("Penguin overflow trap from kernel mode", regs);
        info.si_signo = SIGEMT;
@@ -407,13 +389,11 @@ void handle_tag_overflow(struct pt_regs *regs, unsigned long pc, unsigned long n
        info.si_addr = (void *)pc;
        info.si_trapno = 0;
        send_sig_info(SIGEMT, &info, current);
-       unlock_kernel();
 }
 
 void handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc,
                       unsigned long psr)
 {
-       lock_kernel();
 #ifdef TRAP_DEBUG
        printk("Watchpoint detected at PC %08lx NPC %08lx PSR %08lx\n",
               pc, npc, psr);
@@ -421,7 +401,6 @@ void handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc
        if(psr & PSR_PS)
                panic("Tell me what a watchpoint trap is, and I'll then deal "
                      "with such a beast...");
-       unlock_kernel();
 }
 
 void handle_reg_access(struct pt_regs *regs, unsigned long pc, unsigned long npc,
@@ -429,7 +408,6 @@ void handle_reg_access(struct pt_regs *regs, unsigned long pc, unsigned long npc
 {
        siginfo_t info;
 
-       lock_kernel();
 #ifdef TRAP_DEBUG
        printk("Register Access Exception at PC %08lx NPC %08lx PSR %08lx\n",
               pc, npc, psr);
@@ -440,7 +418,6 @@ void handle_reg_access(struct pt_regs *regs, unsigned long pc, unsigned long npc
        info.si_addr = (void *)pc;
        info.si_trapno = 0;
        force_sig_info(SIGBUS, &info, current);
-       unlock_kernel();
 }
 
 void handle_cp_disabled(struct pt_regs *regs, unsigned long pc, unsigned long npc,
@@ -448,14 +425,12 @@ void handle_cp_disabled(struct pt_regs *regs, unsigned long pc, unsigned long np
 {
        siginfo_t info;
 
-       lock_kernel();
        info.si_signo = SIGILL;
        info.si_errno = 0;
        info.si_code = ILL_COPROC;
        info.si_addr = (void *)pc;
        info.si_trapno = 0;
        send_sig_info(SIGILL, &info, current);
-       unlock_kernel();
 }
 
 void handle_cp_exception(struct pt_regs *regs, unsigned long pc, unsigned long npc,
@@ -463,7 +438,6 @@ void handle_cp_exception(struct pt_regs *regs, unsigned long pc, unsigned long n
 {
        siginfo_t info;
 
-       lock_kernel();
 #ifdef TRAP_DEBUG
        printk("Co-Processor Exception at PC %08lx NPC %08lx PSR %08lx\n",
               pc, npc, psr);
@@ -474,7 +448,6 @@ void handle_cp_exception(struct pt_regs *regs, unsigned long pc, unsigned long n
        info.si_addr = (void *)pc;
        info.si_trapno = 0;
        send_sig_info(SIGILL, &info, current);
-       unlock_kernel();
 }
 
 void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
@@ -482,15 +455,12 @@ void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc
 {
        siginfo_t info;
 
-       lock_kernel();
        info.si_signo = SIGFPE;
        info.si_errno = 0;
        info.si_code = FPE_INTDIV;
        info.si_addr = (void *)pc;
        info.si_trapno = 0;
        send_sig_info(SIGFPE, &info, current);
-
-       unlock_kernel();
 }
 
 /* Since we have our mappings set up, on multiprocessors we can spin them
index b323ccacdfebe725a11441db97485d9742d06c20..642c986bd3776e2c664e47f1aa5eb550eef9679f 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.91 2000/08/09 23:10:19 anton Exp $
+/*  $Id: init.c,v 1.93 2000/08/31 11:40:55 anton Exp $
  *  linux/arch/sparc/mm/init.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -89,8 +89,6 @@ pgprot_t kmap_prot;
 
 void __init kmap_init(void)
 {
-       unsigned long pteval;
-
        /* cache the first kmap pte */
        kmap_pte = kmap_get_fixed_pte(FIX_KMAP_BEGIN);
        kmap_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV | SRMMU_CACHE);
@@ -583,6 +581,6 @@ void flush_page_to_ram(struct page *page)
 {
        unsigned long vaddr;
        vaddr = kmap(page);
-       __flush_page_to_ram(page_address(page));
+       __flush_page_to_ram((unsigned long)page_address(page));
        kunmap(page);
 }
index 9d946df0a4efcf4e68633b4473559101c26dfab6..f4535622fab8550a7c858b11c3536a3609d046d7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.118 2000/08/01 00:11:31 davem Exp $
+/* $Id: entry.S,v 1.119 2000/09/06 00:45:01 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
index 9e1c652461a41441192930b84990f02267b28903..daefe6d4386f0b3003a989ba134ed46aa00e0392 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.92 2000/08/26 02:42:28 anton Exp $
+/* $Id: irq.c,v 1.93 2000/08/31 10:00:39 anton Exp $
  * irq.c: UltraSparc IRQ handling/init/registry.
  *
  * Copyright (C) 1997  David S. Miller  (davem@caip.rutgers.edu)
@@ -550,7 +550,7 @@ out:
 
 #ifdef CONFIG_SMP
 
-/* Who has global_irq_lock. */
+/* Who has the global irq brlock */
 unsigned char global_irq_holder = NO_PROC_ID;
 
 static void show(char * str)
index cd28d9392f644dd3dd51a1d3a621abf63d56b08b..8af0c0f1caf905883ab70c5d8897a3ea76ddaeab 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pci.c,v 1.16 2000/03/01 02:53:33 davem Exp $
+/* $Id: pci.c,v 1.17 2000/09/05 06:49:44 anton Exp $
  * pci.c: UltraSparc PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -274,7 +274,6 @@ asmlinkage int sys_pciconfig_read(unsigned long bus,
                goto out;
        }
 
-       lock_kernel();
        switch(len) {
        case 1:
                pci_read_config_byte(dev, off, &byte);
@@ -293,7 +292,6 @@ asmlinkage int sys_pciconfig_read(unsigned long bus,
                err = -EINVAL;
                break;
        };
-       unlock_kernel();
 out:
        return err;
 }
index 82679eef070e980bb7b2d8040f8f4e5a951fb96e..1f3386d533bb4ac19f058057d05424ccf0c571c0 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.111 2000/08/16 11:13:12 davem Exp $
+/*  $Id: process.c,v 1.112 2000/09/06 00:45:01 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
index 043524ea942a1da93d4854c9a15c9022a0a62913..c2a7833fbdbc258ce84fa507674e367d5d669eaf 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.53 2000/07/30 23:12:24 davem Exp $
+/*  $Id: signal.c,v 1.54 2000/09/05 21:44:54 davem Exp $
  *  arch/sparc64/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
index 51b1e41a8b56ab75cedec80ca21f86d63564c192..6d06328dd012f0540fb55be641f9bcb51733f149 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: signal32.c,v 1.66 2000/07/27 01:05:15 davem Exp $
+/*  $Id: signal32.c,v 1.67 2000/09/05 21:44:54 davem Exp $
  *  arch/sparc64/kernel/signal32.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
index 7eef978365c5c46dc7f67a69494083ae0c74fd1b..deca03485df4ae4b67d16a94501ffba265cc2568 100644 (file)
@@ -1029,7 +1029,7 @@ void __init paging_init(void)
                zones_size[ZONE_DMA] = npages;
                zholes_size[ZONE_DMA] = npages - pages_avail;
 
-               free_area_init_node(0, NULL, zones_size,
+               free_area_init_node(0, NULL, NULL, zones_size,
                                    phys_base, zholes_size);
        }
 
index d7de503be75b4f6eca0ea43e8c61ead292e24358..8a6ecd916d02d9f98676b7d7cc12e648d7ca388e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.6 2000/08/29 07:01:54 davem Exp $
+/* $Id: signal.c,v 1.7 2000/09/05 21:44:54 davem Exp $
  * signal.c: Signal emulation for Solaris
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
index f23f911ad88f7cb45dd2b14e74d9f8ed19231b87..7b11c8f84001c7585a46033e74b1ddfb98eb320c 100644 (file)
@@ -4560,6 +4560,9 @@ static struct pci_board pci_boards[] __initdata = {
        {       PCI_VENDOR_ID_ROCKWELL, 0x1004,
                0x1048, 0x1500, 
                SPCI_FL_BASE1, 1, 115200 },
+       {       PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
+               0xFF00, 0, SPCI_FL_BASE0 | SPCI_FL_IRQRESOURCE,
+               1, 458333, 0, 0, 0, 0x20178 },
 #if CONFIG_DDB5074
        /*
         * NEC Vrc-5074 (Nile 4) builtin UART.
@@ -5281,12 +5284,6 @@ int register_serial(struct serial_struct *req)
                    (rs_table[i].iomem_base == req->iomem_base))
                        break;
        }
-       if (i == NR_PORTS) {
-               for (i = 4; i < NR_PORTS; i++)
-                       if ((rs_table[i].type == PORT_UNKNOWN) &&
-                           (rs_table[i].count == 0))
-                               break;
-       }
        if (i == NR_PORTS) {
                for (i = 0; i < NR_PORTS; i++)
                        if ((rs_table[i].type == PORT_UNKNOWN) &&
index 6d06b0a5fc92f70375bf79f09dc764d7c4d13a00..ff96f714c027705d6d0ea303cbffbe5cb6e8b965 100644 (file)
@@ -97,7 +97,7 @@ an MMIO register read.
 #include <asm/io.h>
 
 
-#define RTL8139_VERSION "0.9.7"
+#define RTL8139_VERSION "0.9.8"
 #define RTL8139_MODULE_NAME "8139too"
 #define RTL8139_DRIVER_NAME   RTL8139_MODULE_NAME " Fast Ethernet driver " RTL8139_VERSION
 #define PFX RTL8139_MODULE_NAME ": "
@@ -1061,6 +1061,7 @@ static void mdio_write (struct net_device *dev, int phy_id, int location,
 static int rtl8139_open (struct net_device *dev)
 {
        struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+       int retval;
 #ifdef RTL8139_DEBUG
        void *ioaddr = tp->mmio_addr;
 #endif
@@ -1069,10 +1070,11 @@ static int rtl8139_open (struct net_device *dev)
 
        MOD_INC_USE_COUNT;
 
-       if (request_irq (dev->irq, &rtl8139_interrupt, SA_SHIRQ, dev->name, dev)) {
-               DPRINTK ("EXIT, returning -EBUSY\n");
+       retval = request_irq (dev->irq, rtl8139_interrupt, SA_SHIRQ, dev->name, dev);
+       if (retval) {
+               DPRINTK ("EXIT, returning %d\n", retval);
                MOD_DEC_USE_COUNT;
-               return -EBUSY;
+               return retval;
        }
 
        tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
@@ -1339,7 +1341,6 @@ static void rtl8139_timer (unsigned long data)
 
        mii_reg5 = mdio_read (dev, tp->phys[0], 5);
 
-#if 0
        if (!tp->duplex_lock && mii_reg5 != 0xffff) {
                void *ioaddr = tp->mmio_addr;
                int duplex = (mii_reg5 & 0x0100)
@@ -1356,7 +1357,6 @@ static void rtl8139_timer (unsigned long data)
                        RTL_W8 (Cfg9346, Cfg9346_Lock);
                }
        }
-#endif
 
        rtl8139_tune_twister (dev, tp);
 
@@ -1417,15 +1417,15 @@ static void rtl8139_tx_timeout (struct net_device *dev)
        /* Dump the unsent Tx packets. */
        for (i = 0; i < NUM_TX_DESC; i++) {
                struct ring_info *rp = &tp->tx_info[i];
+               if (rp->mapping != 0) {
+                       pci_unmap_single (tp->pci_dev, rp->mapping, rp->skb->len, PCI_DMA_TODEVICE);
+                       rp->mapping = 0;
+               }
                if (rp->skb) {
                        dev_kfree_skb (rp->skb);
                        rp->skb = NULL;
                        tp->stats.tx_dropped++;
                }
-               if (rp->mapping != 0) {
-                       pci_unmap_single (tp->pci_dev, rp->mapping, rp->skb->len, PCI_DMA_TODEVICE);
-                       rp->mapping = 0;
-               }
        }
        
        spin_unlock_irq (&tp->lock);
@@ -1527,7 +1527,13 @@ static inline void rtl8139_tx_interrupt (struct net_device *dev,
                }
 
                /* Free the original skb. */
-               dev_kfree_skb_irq (tp->tx_info[entry].skb);
+               if (tp->tx_info[entry].mapping != 0) {
+                       pci_unmap_single(tp->pci_dev,
+                                        tp->tx_info[entry].mapping,
+                                        tp->tx_info[entry].skb->len,
+                                        PCI_DMA_TODEVICE);
+                       tp->tx_info[entry].mapping = 0;
+               }                                                                                                                       dev_kfree_skb_irq (tp->tx_info[entry].skb);
                tp->tx_info[entry].skb = NULL;
                dirty_tx++;
                if (netif_queue_stopped (dev) &&
@@ -1575,8 +1581,7 @@ static void rtl8139_rx_interrupt (struct net_device *dev,
 
        while ((RTL_R8 (ChipCmd) & RxBufEmpty) == 0) {
                int ring_offset = cur_rx % RX_BUF_LEN;
-               u32 rx_status =
-                   le32_to_cpu (*(u32 *) (rx_ring + ring_offset));
+               u32 rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset));
                int rx_size = rx_status >> 16;
 
                DPRINTK ("%s:  rtl8139_rx() status %4.4x, size %4.4x,"
@@ -1654,11 +1659,12 @@ static void rtl8139_rx_interrupt (struct net_device *dev,
                        /* Malloc up new buffer, compatible with net-2e. */
                        /* Omit the four octet CRC from the length. */
                        struct sk_buff *skb;
+                       int pkt_size = rx_size - 4;
 
-                       skb = dev_alloc_skb (rx_size + 2);
+                       skb = dev_alloc_skb (pkt_size + 2);
                        if (skb == NULL) {
                                printk (KERN_WARNING
-                                       "%s: Memory squeeze, deferring packet.\n",
+                                       "%s: Memory squeeze, dropping packet.\n",
                                        dev->name);
                                /* We should check that some rx space is free.
                                   If not, free one and mark stats->rx_dropped++. */
@@ -1675,8 +1681,8 @@ static void rtl8139_rx_interrupt (struct net_device *dev,
                                memcpy (skb_put (skb, semi_count),
                                        &rx_ring[ring_offset + 4],
                                        semi_count);
-                               memcpy (skb_put (skb, rx_size - semi_count),
-                                       rx_ring, rx_size - semi_count);
+                               memcpy (skb_put (skb, pkt_size - semi_count),
+                                       rx_ring, pkt_size - semi_count);
 #ifdef RTL8139_DEBUG
                                {
                                int i;
@@ -1692,12 +1698,12 @@ static void rtl8139_rx_interrupt (struct net_device *dev,
                        } else {
                                eth_copy_and_sum (skb,
                                                  &rx_ring[ring_offset + 4],
-                                                 rx_size - 4, 0);
-                               skb_put (skb, rx_size - 4);
+                                                 pkt_size, 0);
+                               skb_put (skb, pkt_size);
                        }
                        skb->protocol = eth_type_trans (skb, dev);
                        netif_rx (skb);
-                       tp->stats.rx_bytes += rx_size;
+                       tp->stats.rx_bytes += pkt_size;
                        tp->stats.rx_packets++;
                }
 
@@ -1784,7 +1790,7 @@ static void rtl8139_interrupt (int irq, void *dev_instance,
                status = RTL_R16 (IntrStatus);
 
                /* h/w no longer present (hotplug?) or major error, bail */
-               if (status == 0xFFFFFFFF)
+               if (status == 0xFFFF)
                        break;
                
                /* Acknowledge all of the current interrupt sources ASAP, but
@@ -1868,6 +1874,8 @@ static int rtl8139_close (struct net_device *dev)
        DPRINTK ("%s: Shutting down ethercard, status was 0x%4.4x.\n",
                        dev->name, RTL_R16 (IntrStatus));
 
+       del_timer_sync (&tp->timer);
+       
        spin_lock_irqsave (&tp->lock, flags);
 
        /* Disable interrupts by clearing the interrupt mask. */
@@ -1882,8 +1890,6 @@ static int rtl8139_close (struct net_device *dev)
 
        spin_unlock_irqrestore (&tp->lock, flags);
        
-       del_timer (&tp->timer);
-       
        /* snooze for a small bit */
        if (current->need_resched)
                schedule ();
index bdf5a4839410f35923328b66e34a27e7094755b2..e55e83e3664cdd84ebd0d8bba10576053bcc64fa 100644 (file)
        LK1.1.4 (jgarzik):
        * Merge becker test version 1.09 (5/29/2000)
 
+       LK1.1.5 (jgarzik):
+       * Fix locking
+       * Limit 83c175 probe to ethernet-class PCI devices
+
 */
 
 /* These identify the driver base version and may not be removed. */
@@ -41,7 +45,7 @@ static const char version[] =
 static const char version2[] =
 "  http://www.scyld.com/network/epic100.html\n";
 static const char version3[] =
-" (unofficial 2.4.x kernel port, version 1.1.4, August 10, 2000)\n";
+" (unofficial 2.4.x kernel port, version 1.1.5, September 7, 2000)\n";
 
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
@@ -489,13 +493,11 @@ 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));
index 23ba505c3dae4edb317625adde05593d10e7e638..44a759c9f3e24433fc8fcebecc29fb31dbe3f0f1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunhme.c,v 1.96 2000/06/09 07:35:27 davem Exp $
+/* $Id: sunhme.c,v 1.97 2000/09/05 23:12:36 davem Exp $
  * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
  *           auto carrier detecting ethernet driver.  Also known as the
  *           "Happy Meal Ethernet" found on SunSwift SBUS cards.
@@ -2759,7 +2759,7 @@ static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pd
        }               
 
        hpreg_base = pci_resource_start(pdev, 0);
-       if ((pdev->resource[0].flags & IORESOURCE_IO) != 0) {
+       if ((pci_resource_flags(pdev, 0) & IORESOURCE_IO) != 0) {
                printk(KERN_ERR "happymeal(PCI): Cannot find proper PCI device base address.\n");
                return -ENODEV;
        }
@@ -2887,22 +2887,17 @@ static int __init happy_meal_sbus_probe(struct net_device *dev)
 #ifdef CONFIG_PCI
 static int __init happy_meal_pci_probe(struct net_device *dev)
 {
+       struct pci_dev *pdev = NULL;
        int cards = 0;
 
-       if (pci_present()) {
-               struct pci_dev *pdev;
-
-               pdev = pci_find_device(PCI_VENDOR_ID_SUN,
-                                      PCI_DEVICE_ID_SUN_HAPPYMEAL, 0);
-               while (pdev != NULL) {
-                       if (cards)
-                               dev = NULL;
-                       cards++;
-                       happy_meal_pci_init(dev, pdev);
-                       pdev = pci_find_device(PCI_VENDOR_ID_SUN,
-                                              PCI_DEVICE_ID_SUN_HAPPYMEAL,
-                                              pdev);
-               }
+       while ((pdev = pci_find_device(PCI_VENDOR_ID_SUN,
+                                      PCI_DEVICE_ID_SUN_HAPPYMEAL, pdev)) != NULL) {
+               if (pci_enable_device(pdev))
+                       continue;
+               if (cards)
+                       dev = NULL;
+               cards++;
+               happy_meal_pci_init(dev, pdev);
        }
        return cards;
 }
index 39f87f7b7198217a1f40871d2b04585c6fe2a08a..2a4a7c2012a6b7857de922da4f6a3391ebc62802 100644 (file)
@@ -314,12 +314,11 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                        oi++;
                }
                if (csr5 & TimerInt) {
-#if 0
+
                        if (tulip_debug > 2)
                                printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n",
                                           dev->name, csr5);
                        outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
-#endif
                        tp->ttimer = 0;
                        oi++;
                }
@@ -327,14 +326,19 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                        if (tulip_debug > 1)
                                printk(KERN_WARNING "%s: Too much work during an interrupt, "
                                           "csr5=0x%8.8x. (%lu) (%d,%d,%d)\n", dev->name, csr5, tp->nir, tx, rx, oi);
-                       /* Acknowledge all interrupt sources. */
-#if 0
-                       /* Clear all interrupting sources, set timer to re-enable. */
-                       outl(((~csr5) & 0x0001ebef) | NormalIntr | AbnormalIntr | TimerInt,
-                                ioaddr + CSR7);
-                       outl(12, ioaddr + CSR11);
-                       tp->ttimer = 1;
-#endif
+
+                       /* Acknowledge all interrupt sources. */
+                        outl(0x8001ffff, ioaddr + CSR5);
+                        if (tp->flags & HAS_INTR_MITIGATION) {
+                     /* Josip Loncaric at ICASE did extensive experimentation 
+                       to develop a good interrupt mitigation setting.*/
+                                outl(0x8b240000, ioaddr + CSR11);
+                        } else {
+                          /* Mask all interrupting sources, set timer to 
+                               re-enable. */
+                                outl(((~csr5) & 0x0001ebef) | AbnormalIntr | TimerInt, ioaddr + CSR7);
+                                outl(0x0012, ioaddr + CSR11);
+                        }
                        break;
                }
        } while (work_count-- > 0);
@@ -366,4 +370,3 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                           dev->name, inl(ioaddr + CSR5));
 
 }
-
index 4e2338bb376b97e2bc7e67d71abe84d16ce69840..c371ce046a696c4c458e617de02b712f20e14ba8 100644 (file)
@@ -28,7 +28,7 @@
 #include <asm/unaligned.h>
 
 static char version[] __devinitdata =
-       "Linux Tulip driver version 0.9.9 (August 11, 2000)\n";
+       "Linux Tulip driver version 0.9.10 (September 6, 2000)\n";
 
 
 /* A few user-configurable values. */
@@ -167,6 +167,8 @@ static struct pci_device_id tulip_pci_tbl[] __devinitdata = {
        { 0x1317, 0x1985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
        { 0x13D1, 0xAB02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
        { 0x13D1, 0xAB03, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+       { 0x104A, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+       { 0x104A, 0x2774, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
        { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 },
        { 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 },
        { 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 },
index 547a18076a3220906286b8ffde4d3100580429ad..cfe1a93a0a937010a95734fce49e2e14384cdbe0 100644 (file)
@@ -303,7 +303,7 @@ static int proc_read_clients(char *buf, char **start, off_t pos,
     
 ======================================================================*/
 
-static void setup_socket(socket_info_t *);
+static int setup_socket(socket_info_t *);
 static void shutdown_socket(socket_info_t *);
 static void reset_socket(socket_info_t *);
 static void unreset_socket(socket_info_t *);
@@ -490,9 +490,12 @@ static void shutdown_socket(socket_info_t *s)
     free_regions(&s->c_region);
 } /* shutdown_socket */
 
-static void setup_socket(socket_info_t *s)
+/*
+ * Return zero if we think the card isn't actually present
+ */
+static int setup_socket(socket_info_t *s)
 {
-       int val;
+       int val, ret;
        int setup_timeout = 100;
 
        /* Wait for "not pending" */
@@ -506,7 +509,8 @@ static void setup_socket(socket_info_t *s)
                }
                printk(KERN_NOTICE "cs: socket %p voltage interrogation"
                        " timed out\n", s);
-               return;
+               ret = 0;
+               goto out;
        }
 
        if (val & SS_DETECT) {
@@ -531,8 +535,13 @@ static void setup_socket(socket_info_t *s)
                set_socket(s, &s->socket);
                msleep(vcc_settle);
                reset_socket(s);
-       } else
+               ret = 1;
+       } else {
                DEBUG(0, "cs: setup_socket(%p): no card!\n", s);
+               ret = 0;
+       }
+out:
+       return ret;
 } /* setup_socket */
 
 /*======================================================================
@@ -569,7 +578,7 @@ static void unreset_socket(socket_info_t *s)
                get_socket_status(s, &val);
                if (val & SS_READY)
                        break;
-               DEBUG(2, "cs: socket %ld not ready yet\n", i);
+               DEBUG(2, "cs: socket %d not ready yet\n", s->sock);
                if (--setup_timeout) {
                        msleep(unreset_check);
                        continue;
@@ -673,7 +682,8 @@ static void parse_events(void *info, u_int events)
                msleep(resume_delay);
            else
                msleep(setup_delay);
-           setup_socket(s);
+           if (setup_socket(s) == 0)
+               s->state &= ~SOCKET_SETUP_PENDING;
        }
     }
     if (events & SS_BATDEAD)
@@ -1415,7 +1425,8 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
        if ((status & SS_DETECT) &&
            !(s->state & SOCKET_SETUP_PENDING)) {
            s->state |= SOCKET_SETUP_PENDING;
-           setup_socket(s);
+           if (setup_socket(s) == 0)
+                   s->state &= ~SOCKET_SETUP_PENDING;
        }
     }
 
@@ -2106,9 +2117,7 @@ int pcmcia_insert_card(client_handle_t handle, client_req_t *req)
        s->state |= SOCKET_SETUP_PENDING;
        spin_unlock_irqrestore(&s->lock, flags);
        get_socket_status(s, &status);
-       if (status & SS_DETECT)
-           setup_socket(s);
-       else {
+       if ((status & SS_DETECT) == 0 || (setup_socket(s) == 0)) {
            s->state &= ~SOCKET_SETUP_PENDING;
            return CS_NO_CARD;
        }
index 45ee9dd1b4f24666b4155771e343d28c641e97cf..b3a53b4a7d4358f9dfb0ceb1eba3791c2d37aa95 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: dbri.c,v 1.19 2000/02/18 13:49:42 davem Exp $
+/* $Id: dbri.c,v 1.21 2000/08/31 23:44:17 davem Exp $
  * drivers/sbus/audio/dbri.c
  *
  * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de)
@@ -226,7 +226,7 @@ static void dbri_detach(struct dbri *dbri)
         free_irq(dbri->irq, dbri);
         sbus_iounmap(dbri->regs, dbri->regs_size);
         sbus_free_consistent(dbri->sdev, sizeof(struct dbri_dma),
-                             dbri->dma, dbri->dma_dvma);
+                             (void *)dbri->dma, dbri->dma_dvma);
         kfree(dbri);
 }
 
@@ -2079,7 +2079,9 @@ void dbri_liu_activate(int dev, int priority)
 void dbri_liu_deactivate(int dev)
 {
        struct dbri *dbri;
+#if 0
        u32 tmp;
+#endif
 
        if (dev >= num_drivers)
                return;
@@ -2228,7 +2230,6 @@ static int dbri_attach(struct sparcaudio_driver *drv,
 {
        struct dbri *dbri;
        struct linux_prom_irqs irq;
-        __u32 dma_dvma;
        int err;
 
        if (sdev->prom_name[9] < 'e') {
@@ -2265,7 +2266,7 @@ static int dbri_attach(struct sparcaudio_driver *drv,
        if (!dbri->regs) {
                printk(KERN_ERR "DBRI: could not allocate registers\n");
                 sbus_free_consistent(sdev, sizeof(struct dbri_dma),
-                                     dbri->dma, dbri->dma_dvma);
+                                     (void *)dbri->dma, dbri->dma_dvma);
                kfree(drv->private);
                return -EIO;
        }
@@ -2279,7 +2280,7 @@ static int dbri_attach(struct sparcaudio_driver *drv,
                printk(KERN_ERR "DBRI: Can't get irq %d\n", dbri->irq);
                 sbus_iounmap(dbri->regs, dbri->regs_size);
                 sbus_free_consistent(sdev, sizeof(struct dbri_dma),
-                                     dbri->dma, dbri->dma_dvma);
+                                     (void *)dbri->dma, dbri->dma_dvma);
                kfree(drv->private);
                return err;
        }
index 84ee1ad22a8db129af00ec93f3fc319dc14a2338..7c5a21b2cacd78c9d5d83bfb98ddfcc653dba4f3 100644 (file)
@@ -19,7 +19,8 @@ ifeq ($(ARCH),sparc64)
 
 ifeq ($(CONFIG_PCI),y)
 
-O_OBJS += su.o pcikbd.o
+OX_OBJS += su.o
+O_OBJS += pcikbd.o
 
 ifeq ($(CONFIG_SAB82532),y)
 O_OBJS += sab82532.o
@@ -58,7 +59,8 @@ endif
 else # !eq($(ARCH),sparc64)
 
 ifeq ($(CONFIG_PCI),y)
-O_OBJS += su.o pcikbd.o
+OX_OBJS += su.o
+O_OBJS += pcikbd.o
 endif
 
 endif # !eq($(ARCH),sparc64)
index 05a92c82cc4e08dcac16eb2315cfc94d994fa99c..7d010f0359729d438a1256becd827466694f481e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sab82532.c,v 1.47 2000/08/16 21:12:14 ecd Exp $
+/* $Id: sab82532.c,v 1.51 2000/09/04 19:41:26 ecd Exp $
  * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -55,9 +55,11 @@ static int sab82532_refcount;
 /* Set of debugging defines */
 #undef SERIAL_DEBUG_OPEN
 #undef SERIAL_DEBUG_FLOW
+#undef SERIAL_DEBUG_MODEM
 #undef SERIAL_DEBUG_WAIT_UNTIL_SENT
 #undef SERIAL_DEBUG_SEND_BREAK
 #undef SERIAL_DEBUG_INTR
+#define SERIAL_DEBUG_OVERFLOW 1
 
 /* Trace things on serial device, useful for console debugging: */
 #undef SERIAL_LOG_DEVICE
@@ -79,10 +81,15 @@ static struct tty_struct *sab82532_table[NR_PORTS];
 static struct termios *sab82532_termios[NR_PORTS];
 static struct termios *sab82532_termios_locked[NR_PORTS];
 
+#ifdef MODULE
+#undef CONFIG_SERIAL_CONSOLE
+#endif
+
 #ifdef CONFIG_SERIAL_CONSOLE
 extern int serial_console;
 static struct console sab82532_console;
 static int sab82532_console_init(void);
+static void batten_down_hatches(struct sab82532 *info);
 #endif
 
 #ifndef MIN
@@ -208,7 +215,10 @@ static __inline__ void sab82532_start_tx(struct sab82532 *info)
        if (!(readb(&info->regs->r.star) & SAB82532_STAR_XFW))
                goto out;
 
+       info->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS);
+       writeb(info->interrupt_mask1, &info->regs->w.imr1);
        info->all_sent = 0;
+
        for (i = 0; i < info->xmit_fifo_size; i++) {
                u8 val = info->xmit_buf[info->xmit_tail++];
                writeb(val, &info->regs->w.xfifo[i]);
@@ -264,47 +274,6 @@ static void sab82532_start(struct tty_struct *tty)
        restore_flags(flags);
 }
 
-static void batten_down_hatches(struct sab82532 *info)
-{
-       unsigned char saved_rfc, tmp;
-
-       if (!stop_a_enabled)
-               return;
-
-       /* If we are doing kadb, we call the debugger
-        * else we just drop into the boot monitor.
-        * Note that we must flush the user windows
-        * first before giving up control.
-        */
-       printk("\n");
-       flush_user_windows();
-
-       /*
-        * Set FIFO to single character mode.
-        */
-       saved_rfc = readb(&info->regs->r.rfc);
-       tmp = readb(&info->regs->rw.rfc);
-       tmp &= ~(SAB82532_RFC_RFDF);
-       writeb(tmp, &info->regs->rw.rfc);
-       sab82532_cec_wait(info);
-       writeb(SAB82532_CMDR_RRES, &info->regs->w.cmdr);
-
-#ifndef __sparc_v9__
-       if ((((unsigned long)linux_dbvec) >= DEBUG_FIRSTVADDR) &&
-           (((unsigned long)linux_dbvec) <= DEBUG_LASTVADDR))
-               sp_enter_debugger();
-       else
-#endif
-               prom_cmdline();
-
-       /*
-        * Reset FIFO to character + status mode.
-        */
-       writeb(saved_rfc, &info->regs->w.rfc);
-       sab82532_cec_wait(info);
-       writeb(SAB82532_CMDR_RRES, &info->regs->w.cmdr);
-}
-
 /*
  * ----------------------------------------------------------------------
  *
@@ -361,12 +330,11 @@ static inline void receive_chars(struct sab82532 *info,
        if (stat->sreg.isr0 & SAB82532_ISR0_TIME) {
                sab82532_cec_wait(info);
                writeb(SAB82532_CMDR_RFRD, &info->regs->w.cmdr);
-               /* Wait for command execution, to catch the TCD below. */
-               sab82532_cec_wait(info);
+               return;
        }
 
        if (stat->sreg.isr0 & SAB82532_ISR0_RFO) {
-#if 1
+#ifdef SERIAL_DEBUG_OVERFLOW
                printk("sab82532: receive_chars: RFO");
 #endif
                free_fifo++;
@@ -382,14 +350,16 @@ static inline void receive_chars(struct sab82532 *info,
                writeb(SAB82532_CMDR_RMC, &info->regs->w.cmdr);
        }
 
+#ifdef CONFIG_SERIAL_CONSOLE
        if (info->is_console)
                wake_up(&keypress_wait);
+#endif
        if (!tty)
                return;
 
        for (i = 0; i < count; ) {
                if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-#if 1
+#ifdef SERIAL_DEBUG_OVERFLOW
                        printk("sab82532: receive_chars: tty overrun\n");
 #endif
                        info->icount.buf_overrun++;
@@ -424,9 +394,13 @@ static inline void transmit_chars(struct sab82532 *info,
 {
        int i;
 
-       if (stat->sreg.isr1 & SAB82532_ISR1_ALLS)
+       if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) {
+               info->interrupt_mask1 |= SAB82532_IMR1_ALLS;
+               writeb(info->interrupt_mask1, &info->regs->w.imr1);
                info->all_sent = 1;
-       if (!(readb(&info->regs->r.star) & SAB82532_STAR_XFW))
+       }
+
+       if (!(stat->sreg.isr1 & SAB82532_ISR1_XPR))
                return;
 
        if (!info->tty) {
@@ -442,8 +416,11 @@ static inline void transmit_chars(struct sab82532 *info,
                return;
        }
 
-       /* Stuff 32 bytes into Transmit FIFO. */
+       info->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS);
+       writeb(info->interrupt_mask1, &info->regs->w.imr1);
        info->all_sent = 0;
+
+       /* Stuff 32 bytes into Transmit FIFO. */
        for (i = 0; i < info->xmit_fifo_size; i++) {
                u8 val = info->xmit_buf[info->xmit_tail++];
                writeb(val, &info->regs->w.xfifo[i]);
@@ -476,10 +453,12 @@ static inline void check_status(struct sab82532 *info,
        int modem_change = 0;
 
        if (stat->sreg.isr1 & SAB82532_ISR1_BRK) {
+#ifdef CONFIG_SERIAL_CONSOLE
                if (info->is_console) {
                        batten_down_hatches(info);
                        return;
                }
+#endif
                if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
                        info->icount.buf_overrun++;
                        goto check_modem;
@@ -509,7 +488,7 @@ check_modem:
                info->dcd = (readb(&info->regs->r.vstr) & SAB82532_VSTR_CD) ? 0 : 1;
                info->icount.dcd++;
                modem_change++;
-#if 0
+#ifdef SERIAL_DEBUG_MODEM
                printk("DCD change: %d\n", info->icount.dcd);
 #endif
        }
@@ -517,7 +496,7 @@ check_modem:
                info->cts = readb(&info->regs->r.star) & SAB82532_STAR_CTS;
                info->icount.cts++;
                modem_change++;
-#if 0
+#ifdef SERIAL_DEBUG_MODEM
                printk("CTS change: %d, CTS %s\n", info->icount.cts, info->cts ? "on" : "off");
 #endif
        }
@@ -525,7 +504,7 @@ check_modem:
                info->dsr = (readb(&info->regs->r.pvr) & info->pvr_dsr_bit) ? 0 : 1;
                info->icount.dsr++;
                modem_change++;
-#if 0
+#ifdef SERIAL_DEBUG_MODEM
                printk("DSR change: %d\n", info->icount.dsr);
 #endif
        }
@@ -828,10 +807,12 @@ static int startup(struct sab82532 *info)
        info->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR |
                                SAB82532_IMR0_PLLA;
        writeb(info->interrupt_mask0, &info->regs->w.imr0);
-       info->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_XOFF |
-                               SAB82532_IMR1_TIN | SAB82532_IMR1_CSC |
-                               SAB82532_IMR1_XON | SAB82532_IMR1_XPR;
+       info->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS |
+                               SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN |
+                               SAB82532_IMR1_CSC | SAB82532_IMR1_XON |
+                               SAB82532_IMR1_XPR;
        writeb(info->interrupt_mask1, &info->regs->w.imr1);
+       info->all_sent = 1;
 
        if (info->tty)
                clear_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -880,6 +861,7 @@ static void shutdown(struct sab82532 *info)
                info->xmit_buf = 0;
        }
 
+#ifdef CONFIG_SERIAL_CONSOLE
        if (info->is_console) {
                info->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR |
                                        SAB82532_IMR0_PLLA | SAB82532_IMR0_CDSC;
@@ -895,6 +877,7 @@ static void shutdown(struct sab82532 *info)
                restore_flags(flags);
                return;
        }
+#endif
 
        /* Disable Interrupts */
        info->interrupt_mask0 = 0xff;
@@ -1238,10 +1221,6 @@ static void sab82532_throttle(struct tty_struct * tty)
        
        if (I_IXOFF(tty))
                sab82532_send_xchar(tty, STOP_CHAR(tty));
-#if 0
-       if (tty->termios->c_cflag & CRTSCTS)
-               writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RTS, &info->regs->rw.mode);
-#endif
 }
 
 static void sab82532_unthrottle(struct tty_struct * tty)
@@ -1263,11 +1242,6 @@ static void sab82532_unthrottle(struct tty_struct * tty)
                else
                        sab82532_send_xchar(tty, START_CHAR(tty));
        }
-
-#if 0
-       if (tty->termios->c_cflag & CRTSCTS)
-               writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_RTS), &info->regs->rw.mode);
-#endif
 }
 
 /*
@@ -1562,18 +1536,6 @@ static void sab82532_set_termios(struct tty_struct *tty,
                tty->hw_stopped = 0;
                sab82532_start(tty);
        }
-
-#if 0
-       /*
-        * No need to wake up processes in open wait, since they
-        * sample the CLOCAL flag once, and don't recheck it.
-        * XXX  It's not clear whether the current behavior is correct
-        * or not.  Hence, this may change.....
-        */
-       if (!(old_termios->c_cflag & CLOCAL) &&
-           (tty->termios->c_cflag & CLOCAL))
-               wake_up_interruptible(&info->open_wait);
-#endif
 }
 
 /*
@@ -1651,9 +1613,6 @@ static void sab82532_close(struct tty_struct *tty, struct file * filp)
         */
        info->interrupt_mask0 |= SAB82532_IMR0_TCD;
        writeb(info->interrupt_mask0, &info->regs->w.imr0);
-#if 0
-       writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_RAC), &info->regs->rw.mode);
-#endif
        if (info->flags & ASYNC_INITIALIZED) {
                /*
                 * Before we drop DTR, make sure the UART transmitter
@@ -1722,7 +1681,6 @@ static void sab82532_wait_until_sent(struct tty_struct *tty, int timeout)
                if (timeout && time_after(jiffies, orig_jiffies + timeout))
                        break;
        }
-       current->state = TASK_RUNNING;
 #ifdef SERIAL_DEBUG_WAIT_UNTIL_SENT
        printk("xmit_cnt = %d, alls = %d (jiff=%lu)...done\n", info->xmit_cnt, info->all_sent, jiffies);
 #endif
@@ -1738,8 +1696,10 @@ static void sab82532_hangup(struct tty_struct *tty)
        if (serial_paranoia_check(info, tty->device, "sab82532_hangup"))
                return;
 
+#ifdef CONFIG_SERIAL_CONSOLE
        if (info->is_console)
                return;
+#endif
 
        sab82532_flush_buffer(tty);
        shutdown(info);
@@ -1873,7 +1833,6 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
 #endif
                schedule();
        }
-       current->state = TASK_RUNNING;
        remove_wait_queue(&info->open_wait, &wait);
        if (!tty_hung_up_p(filp))
                info->count++;
@@ -2010,7 +1969,7 @@ line_info(char *buf, struct sab82532 *info)
        char stat_buf[30];
        int ret;
 
-       ret = sprintf(buf, "%d: uart:SAB82532 ", info->line);
+       ret = sprintf(buf, "%u: uart:SAB82532 ", info->line);
        switch (info->type) {
                case 0:
                        ret += sprintf(buf+ret, "V1.0 ");
@@ -2056,19 +2015,22 @@ line_info(char *buf, struct sab82532 *info)
        restore_flags(flags);
 
        if (info->baud)
-               ret += sprintf(buf+ret, " baud:%d", info->baud);
+               ret += sprintf(buf+ret, " baud:%u", info->baud);
+
+       ret += sprintf(buf+ret, " tx:%u rx:%u",
+                      info->icount.tx, info->icount.rx);
 
        if (info->icount.frame)
-               ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
+               ret += sprintf(buf+ret, " fe:%u", info->icount.frame);
 
        if (info->icount.parity)
-               ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
+               ret += sprintf(buf+ret, " pe:%u", info->icount.parity);
 
        if (info->icount.brk)
-               ret += sprintf(buf+ret, " brk:%d", info->icount.brk);
+               ret += sprintf(buf+ret, " brk:%u", info->icount.brk);
 
        if (info->icount.overrun)
-               ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+               ret += sprintf(buf+ret, " oe:%u", info->icount.overrun);
 
        /*
         * Last thing is the RS-232 status lines.
@@ -2161,15 +2123,17 @@ ebus_done:
        return 0;
 }
 
+#ifndef MODULE
 static void __init sab82532_kgdb_hook(int line)
 {
        prom_printf("sab82532: kgdb support is not implemented, yet\n");
        prom_halt();
 }
+#endif
 
 static inline void __init show_serial_version(void)
 {
-       char *revision = "$Revision: 1.47 $";
+       char *revision = "$Revision: 1.51 $";
        char *version, *p;
 
        version = strchr(revision, ' ');
@@ -2246,7 +2210,11 @@ int __init sab82532_init(void)
         * major number and the subtype code.
         */
        callout_driver = serial_driver;
+#ifdef CONFIG_DEVFS_FS
        callout_driver.name = "cua/%d";
+#else
+       callout_driver.name = "cua";
+#endif
        callout_driver.major = TTYAUX_MAJOR;
        callout_driver.subtype = SERIAL_TYPE_CALLOUT;
        callout_driver.read_proc = 0;
@@ -2364,8 +2332,10 @@ found:
 #ifdef CONFIG_SERIAL_CONSOLE
        sunserial_setinitfunc(sab82532_console_init);
 #endif
+#ifndef MODULE
        sunserial_setinitfunc(sab82532_init);
        rs_ops.rs_kgdb_hook = sab82532_kgdb_hook;
+#endif
        return 0;
 }
 
@@ -2400,12 +2370,56 @@ void cleanup_module(void)
                free_page((unsigned long) tmp_buf);
                tmp_buf = NULL;
        }
-       for (sab = sab82532_chain; sab; sab = sab->next)
+       for (sab = sab82532_chain; sab; sab = sab->next) {
+               if (!(sab->line & 0x01))
+                       free_irq(sab->irq, sab);
                iounmap(sab->regs);
+       }
 }
 #endif /* MODULE */
 
 #ifdef CONFIG_SERIAL_CONSOLE
+static void
+batten_down_hatches(struct sab82532 *info)
+{
+       unsigned char saved_rfc, tmp;
+
+       if (!stop_a_enabled)
+               return;
+
+       /* If we are doing kadb, we call the debugger
+        * else we just drop into the boot monitor.
+        * Note that we must flush the user windows
+        * first before giving up control.
+        */
+       printk("\n");
+       flush_user_windows();
+
+       /*
+        * Set FIFO to single character mode.
+        */
+       saved_rfc = readb(&info->regs->r.rfc);
+       tmp = readb(&info->regs->rw.rfc);
+       tmp &= ~(SAB82532_RFC_RFDF);
+       writeb(tmp, &info->regs->rw.rfc);
+       sab82532_cec_wait(info);
+       writeb(SAB82532_CMDR_RRES, &info->regs->w.cmdr);
+
+#ifndef __sparc_v9__
+       if ((((unsigned long)linux_dbvec) >= DEBUG_FIRSTVADDR) &&
+           (((unsigned long)linux_dbvec) <= DEBUG_LASTVADDR))
+               sp_enter_debugger();
+       else
+#endif
+               prom_cmdline();
+
+       /*
+        * Reset FIFO to character + status mode.
+        */
+       writeb(saved_rfc, &info->regs->w.rfc);
+       sab82532_cec_wait(info);
+       writeb(SAB82532_CMDR_RRES, &info->regs->w.cmdr);
+}
 
 static __inline__ void
 sab82532_console_putchar(struct sab82532 *info, char c)
@@ -2645,4 +2659,3 @@ dprintf(const char *fmt, ...)
 }
 #endif /* SERIAL_LOG_DEVICE */
 #endif /* CONFIG_SERIAL_CONSOLE */
-
index 6df7d99119f6100d0792b5f68a23582590403169..c6e90328ece137be394db3e387da540cb555aaa4 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: su.c,v 1.38 2000/04/22 00:45:16 davem Exp $
+/* $Id: su.c,v 1.41 2000/09/04 19:41:27 ecd Exp $
  * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -1851,7 +1851,6 @@ su_wait_until_sent(struct tty_struct *tty, int timeout)
                if (timeout && time_after(jiffies, orig_jiffies + timeout))
                        break;
        }
-       current->state = TASK_RUNNING;
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
        printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
 #endif
@@ -2002,7 +2001,6 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
 #endif
                schedule();
        }
-       current->state = TASK_RUNNING;
        remove_wait_queue(&info->open_wait, &wait);
        if (extra_count)
                info->count++;
@@ -2125,14 +2123,12 @@ line_info(char *buf, struct su_struct *info)
        int             ret;
        unsigned long   flags;
 
-       ret = sprintf(buf, "%d: uart:%s port:%X irq:%s",
-                     info->line, uart_config[info->type].name, 
-                     (int)info->port, __irq_itoa(info->irq));
+       if (info->port == 0 || info->type == PORT_UNKNOWN)
+               return 0;
 
-       if (info->port == 0 || info->type == PORT_UNKNOWN) {
-               ret += sprintf(buf+ret, "\n");
-               return ret;
-       }
+       ret = sprintf(buf, "%u: uart:%s port:%lX irq:%s",
+                     info->line, uart_config[info->type].name, 
+                     (unsigned long)info->port, __irq_itoa(info->irq));
 
        /*
         * Figure out the current RS-232 lines
@@ -2158,24 +2154,24 @@ line_info(char *buf, struct su_struct *info)
                strcat(stat_buf, "|RI");
 
        if (info->quot) {
-               ret += sprintf(buf+ret, " baud:%d",
+               ret += sprintf(buf+ret, " baud:%u",
                               info->baud_base / info->quot);
        }
 
-       ret += sprintf(buf+ret, " tx:%d rx:%d",
-                     info->icount.tx, info->icount.rx);
+       ret += sprintf(buf+ret, " tx:%u rx:%u",
+                      info->icount.tx, info->icount.rx);
 
        if (info->icount.frame)
-               ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
+               ret += sprintf(buf+ret, " fe:%u", info->icount.frame);
 
        if (info->icount.parity)
-               ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
+               ret += sprintf(buf+ret, " pe:%u", info->icount.parity);
 
        if (info->icount.brk)
-               ret += sprintf(buf+ret, " brk:%d", info->icount.brk);   
+               ret += sprintf(buf+ret, " brk:%u", info->icount.brk);   
 
        if (info->icount.overrun)
-               ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+               ret += sprintf(buf+ret, " oe:%u", info->icount.overrun);
 
        /*
         * Last thing is the RS-232 status lines
@@ -2223,7 +2219,7 @@ done:
  */
 static __inline__ void __init show_su_version(void)
 {
-       char *revision = "$Revision: 1.38 $";
+       char *revision = "$Revision: 1.41 $";
        char *version, *p;
 
        version = strchr(revision, ' ');
@@ -2425,6 +2421,7 @@ ebus_done:
  * numbers start, we always are probed for first.
  */
 int su_num_ports = 0;
+EXPORT_SYMBOL(su_num_ports);
 
 /*
  * The serial driver boot-time initialization code!
@@ -2442,7 +2439,11 @@ int __init su_serial_init(void)
        memset(&serial_driver, 0, sizeof(struct tty_driver));
        serial_driver.magic = TTY_DRIVER_MAGIC;
        serial_driver.driver_name = "su";
-       serial_driver.name = "ttys/%d";
+#ifdef CONFIG_DEVFS_FS
+       serial_driver.name = "tts/%d";
+#else
+       serial_driver.name = "ttyS";
+#endif
        serial_driver.major = TTY_MAJOR;
        serial_driver.minor_start = 64;
        serial_driver.num = NR_PORTS;
@@ -2482,7 +2483,11 @@ int __init su_serial_init(void)
         * major number and the subtype code.
         */
        callout_driver = serial_driver;
+#ifdef CONFIG_DEVFS_FS
        callout_driver.name = "cua/%d";
+#else
+       callout_driver.name = "cua";
+#endif
        callout_driver.major = TTYAUX_MAJOR;
        callout_driver.subtype = SERIAL_TYPE_CALLOUT;
        callout_driver.read_proc = 0;
@@ -2598,6 +2603,17 @@ void __init su_probe_any(struct su_probe_scan *t, int sunode)
                                t->msx = t->devices;
                                info->port_type = SU_PORT_MS;
                        } else {
+#ifdef __sparc_v9__
+                               /*
+                                * Do not attempt to use the truncated
+                                * keyboard/mouse ports as serial ports
+                                * on Ultras with PC keyboard attached.
+                                */
+                               if (prom_getbool(sunode, "mouse"))
+                                       continue;
+                               if (prom_getbool(sunode, "keyboard"))
+                                       continue;
+#endif
                                info->port_type = SU_PORT_PORT;
                        }
                        info->is_console = 0;
index 554a15676a37915897b5d4a18942e5ad19ebdd41..77b849ef026da6b793df0b2e517bda404502bb08 100644 (file)
@@ -42,6 +42,7 @@
 #include "vfc.h"
 #include <asm/vfc_ioctls.h>
 
+static struct file_operations vfc_fops;
 static devfs_handle_t devfs_handle = NULL;  /*  For the directory  */
 struct vfc_dev **vfc_dev_lst;
 static char vfcstr[]="vfc";
index 295066797e0e81f378757367a9ec128cc32f6b06..0efe86cf2c3e4c23969e32d4e46d783ce21fcf20 100644 (file)
@@ -19,6 +19,9 @@
  *       scsi disks using eight major numbers.
  *
  *       Modified by Richard Gooch rgooch@atnf.csiro.au to support devfs.
+ *     
+ *      Modified by Torben Mathiasen tmm@image.dk
+ *       Resource allocation fixes in sd_init and cleanups.
  */
 
 #include <linux/config.h>
@@ -1039,16 +1042,24 @@ static int sd_init()
        if (rscsi_disks)
                return 0;
 
-       rscsi_disks = (Scsi_Disk *)
-           kmalloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC);
+       rscsi_disks = kmalloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC);
+       if (!rscsi_disks)
+               goto cleanup_devfs;
        memset(rscsi_disks, 0, sd_template.dev_max * sizeof(Scsi_Disk));
 
        /* for every (necessary) major: */
-       sd_sizes = (int *) kmalloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC);
+       sd_sizes = kmalloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC);
+       if (!sd_sizes)
+               goto cleanup_disks;
        memset(sd_sizes, 0, (sd_template.dev_max << 4) * sizeof(int));
 
-       sd_blocksizes = (int *) kmalloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC);
-       sd_hardsizes = (int *) kmalloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC);
+       sd_blocksizes = kmalloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC);
+       if (!sd_blocksizes)
+               goto cleanup_sizes;
+       
+       sd_hardsizes = kmalloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC);
+       if (!sd_hardsizes)
+               goto cleanup_blocksizes;
 
        for (i = 0; i < sd_template.dev_max << 4; i++) {
                sd_blocksizes[i] = 1024;
@@ -1059,22 +1070,29 @@ static int sd_init()
                blksize_size[SD_MAJOR(i)] = sd_blocksizes + i * (SCSI_DISKS_PER_MAJOR << 4);
                hardsect_size[SD_MAJOR(i)] = sd_hardsizes + i * (SCSI_DISKS_PER_MAJOR << 4);
        }
-       sd = (struct hd_struct *) kmalloc((sd_template.dev_max << 4) *
+       sd = kmalloc((sd_template.dev_max << 4) *
                                          sizeof(struct hd_struct),
                                          GFP_ATOMIC);
+       if (!sd)
+               goto cleanup_sd;
        memset(sd, 0, (sd_template.dev_max << 4) * sizeof(struct hd_struct));
 
        if (N_USED_SD_MAJORS > 1)
-               sd_gendisks = (struct gendisk *)
-                   kmalloc(N_USED_SD_MAJORS * sizeof(struct gendisk), GFP_ATOMIC);
+               sd_gendisks = kmalloc(N_USED_SD_MAJORS * sizeof(struct gendisk), GFP_ATOMIC);
+               if (!sd_gendisks)
+                       goto cleanup_sd_gendisks;
        for (i = 0; i < N_USED_SD_MAJORS; i++) {
                sd_gendisks[i] = sd_gendisk;
                sd_gendisks[i].de_arr = kmalloc (SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].de_arr,
                                                  GFP_ATOMIC);
+               if (!sd_gendisks[i].de_arr)
+                       goto cleanup_gendisks_de_arr;
                 memset (sd_gendisks[i].de_arr, 0,
                         SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].de_arr);
                sd_gendisks[i].flags = kmalloc (SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].flags,
                                                 GFP_ATOMIC);
+               if (!sd_gendisks[i].flags)
+                       goto cleanup_gendisks_flags;
                 memset (sd_gendisks[i].flags, 0,
                         SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].flags);
                sd_gendisks[i].major = SD_MAJOR(i);
@@ -1091,6 +1109,31 @@ static int sd_init()
 
        LAST_SD_GENDISK.next = NULL;
        return 0;
+
+cleanup_gendisks_flags:
+       kfree(sd_gendisks[i].de_arr);
+cleanup_gendisks_de_arr:
+       while (--i >= 0 ) {
+               kfree(sd_gendisks[i].de_arr);
+               kfree(sd_gendisks[i].flags);
+       }
+       kfree(sd_gendisks);
+cleanup_sd_gendisks:
+       kfree(sd);
+cleanup_sd:
+       kfree(sd_hardsizes);
+cleanup_blocksizes:
+       kfree(sd_blocksizes);
+cleanup_sizes:
+       kfree(sd_sizes);
+cleanup_disks:
+       kfree(rscsi_disks);
+cleanup_devfs:
+       for (i = 0; i < N_USED_SD_MAJORS; i++) {
+               devfs_unregister_blkdev(SD_MAJOR(i), "sd");
+       }
+       sd_registered--;
+       return 1;
 }
 
 
@@ -1292,14 +1335,12 @@ static void sd_detach(Scsi_Device * SDp)
        return;
 }
 
-#ifdef MODULE
-
-int init_module(void)
+int init_sd(void)
 {
-       sd_template.module = &__this_module;
+       sd_template.module = THIS_MODULE;
        return scsi_register_module(MODULE_SCSI_DEV, &sd_template);
 }
-void cleanup_module(void)
+void exit_sd(void)
 {
        struct gendisk **prev_sdgd_link;
        struct gendisk *sdgd;
@@ -1313,10 +1354,10 @@ void cleanup_module(void)
 
        sd_registered--;
        if (rscsi_disks != NULL) {
-               kfree((char *) rscsi_disks);
-               kfree((char *) sd_sizes);
-               kfree((char *) sd_blocksizes);
-               kfree((char *) sd_hardsizes);
+               kfree(rscsi_disks);
+               kfree(sd_sizes);
+               kfree(sd_blocksizes);
+               kfree(sd_hardsizes);
                kfree((char *) sd);
 
                /*
@@ -1346,23 +1387,6 @@ void cleanup_module(void)
        if (sd_gendisks != &sd_gendisk)
                kfree(sd_gendisks);
 }
-#endif                         /* MODULE */
 
-/*
- * Overrides for Emacs so that we almost follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
+module_init(init_sd);
+module_exit(exit_sd);
index b18a96bf4634b4f16680fce4200a06330c7e3b07..da89d29c52676e89cead10c2c78cfa451a530d6e 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/errno.h>
 #include <linux/cdrom.h>
 #include <linux/interrupt.h>
+#include <linux/init.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
index fd239671b07c098f3f44e8caceee846e179e5927..0100595cbb7d8459fadf2fd81703e9c3e93c0d6d 100644 (file)
@@ -6,6 +6,9 @@
  *
  * USB Bluetooth driver, based on the Bluetooth Spec version 1.0B
  *
+ * (08/06/2000) Version 0.5 gkh
+ *     Fixed problem of not resubmitting the bulk read urb if there is
+ *     an error in the callback.  Ericsson devices seem to need this.
  *
  * (07/11/2000) Version 0.4 gkh
  *     Fixed bug in disconnect for when we call tty_hangup
@@ -796,17 +799,17 @@ static void bluetooth_read_bulk_callback (struct urb *urb)
 
        if (!bluetooth) {
                dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
-               return;
+               goto exit;
        }
 
        if (urb->status) {
                dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
-               return;
+               goto exit;
        }
 
        if (!count) {
                dbg(__FUNCTION__ " - zero length read bulk");
-               return;
+               goto exit;
        }
 
 #ifdef DEBUG
@@ -832,9 +835,7 @@ static void bluetooth_read_bulk_callback (struct urb *urb)
        if (bluetooth->bulk_packet_pos + count > ACL_BUFFER_SIZE) {
                err(__FUNCTION__ " - exceeded ACL_BUFFER_SIZE");
                bluetooth->bulk_packet_pos = 0;
-               if (usb_submit_urb(urb))
-                       dbg(__FUNCTION__ " - failed resubmitting read urb");
-               return;
+               goto exit;
        }
 
        memcpy (&bluetooth->bulk_buffer[bluetooth->bulk_packet_pos],
@@ -845,17 +846,13 @@ static void bluetooth_read_bulk_callback (struct urb *urb)
        if (bluetooth->bulk_packet_pos >= ACL_HDR_SIZE) {
                packet_size = CHAR2INT16(bluetooth->bulk_buffer[4],bluetooth->bulk_buffer[3]);
        } else {
-               if (usb_submit_urb(urb))
-                       dbg(__FUNCTION__ " - failed resubmitting read urb");
-               return;
+               goto exit;
        }
 
        if (packet_size + ACL_HDR_SIZE < bluetooth->bulk_packet_pos) {
                err(__FUNCTION__ " - packet was too long");
                bluetooth->bulk_packet_pos = 0;
-               if (usb_submit_urb(urb))
-                       dbg(__FUNCTION__ " - failed resubmitting read urb");
-               return;
+               goto exit;
        }
 
        if (packet_size + ACL_HDR_SIZE == bluetooth->bulk_packet_pos) {
@@ -865,6 +862,7 @@ static void bluetooth_read_bulk_callback (struct urb *urb)
                bluetooth->bulk_packet_pos = 0;
        }       
 
+exit:
        if (usb_submit_urb(urb))
                dbg(__FUNCTION__ " - failed resubmitting read urb");
 
index a9982288bbca67c73c03df6488d938d789e0d129..d14e8e97b22b74dd6b1c2aa95a80d85fdafdc8a5 100644 (file)
@@ -837,7 +837,6 @@ static void __exit dabusb_cleanup (void)
 
 /* --------------------------------------------------------------------- */
 
-#ifdef MODULE
 MODULE_AUTHOR ("Deti Fliegl, deti@fliegl.de");
 MODULE_DESCRIPTION ("DAB-USB Interface Driver for Linux (c)1999");
 MODULE_PARM (buffers, "i");
@@ -846,7 +845,4 @@ MODULE_PARM_DESC (buffers, "Number of buffers (default=256)");
 module_init (dabusb_init);
 module_exit (dabusb_cleanup);
 
-
-#endif
-
 /* --------------------------------------------------------------------- */
index ca1d8abba4b14a1c018ae5be7673cf31e22e2cc5..aa6372b915406a8e3a6ce5891cb5531f6206c912 100644 (file)
 
  History:
 
+ Version 0.24:
+       Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
+       right.  Some minor cleanup, improved standalone compilation
+
  Version 0.23:
        Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
 
@@ -135,11 +139,11 @@ static int dsbr100_stop(usb_dsbr100 *radio)
 
 static int dsbr100_setfreq(usb_dsbr100 *radio, int freq)
 {
-       freq = (freq*80)/16+856;
+       freq = (freq/16*80)/1000+856;
        if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
-               0x01, 0xC0, (freq&0xff00)>>8, freq&0xff, 
-               radio->transfer_buffer, 8, 300)<0
-        || usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
+               0x01, 0xC0, (freq>>8)&0x00ff, freq&0xff, 
+               radio->transfer_buffer, 8, 300)<0 ||
+           usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
                0x00, 0xC0, 0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 ||
            usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
                0x00, 0xC0, 0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
@@ -172,7 +176,7 @@ static void *usb_dsbr100_probe(struct usb_device *dev, unsigned int ifnum)
        usb_dsbr100_radio.priv = radio;
        radio->dev = dev;
        radio->ifnum = ifnum;
-       radio->curfreq = 1454;
+       radio->curfreq = 1454000;
        return (void*)radio;
 }
 
@@ -218,8 +222,8 @@ static int usb_dsbr100_ioctl(struct video_device *dev, unsigned int cmd,
                                return -EFAULT;
                        if(v.tuner)     /* Only 1 tuner */ 
                                return -EINVAL;
-                       v.rangelow = 87*16;
-                       v.rangehigh = 108*16;
+                       v.rangelow = 87*16000;
+                       v.rangehigh = 108*16000;
                        v.flags = VIDEO_TUNER_LOW;
                        v.mode = VIDEO_MODE_AUTO;
                        v.signal = radio->stereo*0x7000;
index b55073398a174b73a52e068bca65e7b6ada018ca..a242db7fce6f61f7c508e6b1a92ab2126dbf1637 100644 (file)
@@ -48,6 +48,7 @@ static LIST_HEAD(superlist);
 struct special {
        const char *name;
        struct file_operations *fops;
+       struct inode *inode;
        struct list_head inodes;
 };
 
@@ -572,6 +573,7 @@ struct super_block *usbdevfs_read_super(struct super_block *s, void *data, int s
                inode->i_uid = listuid;
                inode->i_gid = listgid;
                inode->i_mode = listmode | S_IFREG;
+               special[i].inode = inode;
                list_add_tail(&inode->u.usbdev_i.slist, &s->u.usbdevfs_sb.ilist);
                list_add_tail(&inode->u.usbdev_i.dlist, &special[i].inodes);
        }
@@ -598,6 +600,17 @@ static DECLARE_FSTYPE(usbdevice_fs_type, "usbdevfs", usbdevfs_read_super, 0);
 
 /* --------------------------------------------------------------------- */
 
+static void update_special_inodes (void)
+{
+       int i;
+       for (i = 0; i < NRSPECIAL; i++) {
+               struct inode *inode = special[i].inode;
+               if (inode)
+                       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       }
+}
+
+
 void usbdevfs_add_bus(struct usb_bus *bus)
 {
        struct list_head *slist;
@@ -605,6 +618,7 @@ void usbdevfs_add_bus(struct usb_bus *bus)
        lock_kernel();
        for (slist = superlist.next; slist != &superlist; slist = slist->next)
                new_bus_inode(bus, list_entry(slist, struct super_block, u.usbdevfs_sb.slist));
+       update_special_inodes();
        unlock_kernel();
        usbdevfs_conn_disc_event();
 }
@@ -614,6 +628,7 @@ void usbdevfs_remove_bus(struct usb_bus *bus)
        lock_kernel();
        while (!list_empty(&bus->inodes))
                free_inode(list_entry(bus->inodes.next, struct inode, u.usbdev_i.dlist));
+       update_special_inodes();
        unlock_kernel();
        usbdevfs_conn_disc_event();
 }
@@ -625,6 +640,7 @@ void usbdevfs_add_device(struct usb_device *dev)
        lock_kernel();
        for (slist = superlist.next; slist != &superlist; slist = slist->next)
                new_dev_inode(dev, list_entry(slist, struct super_block, u.usbdevfs_sb.slist));
+       update_special_inodes();
        unlock_kernel();
        usbdevfs_conn_disc_event();
 }
@@ -652,6 +668,8 @@ void usbdevfs_remove_device(struct usb_device *dev)
                        send_sig_info(ds->discsignr, &sinfo, ds->disctask);
                }
        }
+
+       update_special_inodes();
        unlock_kernel();
        usbdevfs_conn_disc_event();
 }
index b8eb74c771447c1467e6fdf520fd2a996848b995..fdfe5f379ed8d404507eb6563c5a6bf7d6912762 100644 (file)
  *     20000603 Version 0.2.1
  *     20000620 minor cosmetic changes
  *     20000620 Version 0.2.2
+ *  20000822 Hopefully fixed deadlock in mts_remove_nolock()
+ *  20000822 Fixed minor race in mts_transfer_cleanup()
+ *  20000822 Fixed deadlock on submission error in queuecommand
+ *  20000822 Version 0.2.3
  */
 
 #include <linux/module.h>
 
 /* Should we do debugging? */
 
-#define MTS_DO_DEBUG
+// #define MTS_DO_DEBUG
 
 
 /* USB layer driver interface */
@@ -147,7 +151,7 @@ static struct usb_driver mts_usb_driver = {
 
 /* Internal driver stuff */
 
-#define MTS_VERSION    "0.2.2"
+#define MTS_VERSION    "0.2.3"
 #define MTS_NAME       "microtek usb (rev " MTS_VERSION "): "
 
 #define MTS_WARNING(x...) \
@@ -332,9 +336,8 @@ void mts_remove_nolock( struct mts_desc* to_remove )
        MTS_DEBUG( "removing 0x%x from list\n",
                   (int)to_remove );
 
+       lock_kernel();
        mts_wait_abort(to_remove);
-       
-       down( &to_remove->lock );
 
        MTS_DEBUG_GOT_HERE();
        
@@ -358,6 +361,7 @@ void mts_remove_nolock( struct mts_desc* to_remove )
 
        MTS_DEBUG_GOT_HERE();
        scsi_unregister_module(MODULE_SCSI_HA, &(to_remove->ctempl));
+       unlock_kernel();
        
        kfree( to_remove );
 }
@@ -391,7 +395,7 @@ static int mts_scsi_release(struct Scsi_Host *psh)
 }
 
 static int mts_scsi_abort (Scsi_Cmnd *srb)
-/* interrupt context (!) */
+/* interrupt context (!) */ /* FIXME this is about to become task context */
 {
        struct mts_desc* desc = (struct mts_desc*)(srb->host->hostdata[0]);
 
@@ -508,9 +512,9 @@ static void mts_transfer_cleanup( struct urb *transfer )
 {
        struct mts_transfer_context* context = (struct mts_transfer_context*)transfer->context;
        
-       up( &context->instance->lock );
        if ( context->final_callback )
                context->final_callback(context->srb);
+       up( &context->instance->lock );
 
 }
 
@@ -708,6 +712,7 @@ int mts_scsi_queuecommand( Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback )
 
                if(callback)
                        callback(srb);
+       up(&desc->lock); /* no further cleanup is done */
 
                goto out;
        }       
index b8b5993587a10db4d9d1fa50c94f4b245bc8cba3..0fba2ff94d958ee64515e676799dacadd3740705 100644 (file)
@@ -130,9 +130,9 @@ static inline void set_break        (struct usb_serial_port *port, unsigned char brk);
  *****************************************************************************/
 static void command_port_write_callback (struct urb *urb)
 {
-       unsigned char *data = urb->transfer_buffer;
 #ifdef DEBUG
        int i;
+       unsigned char *data = urb->transfer_buffer;
 #endif
 
        dbg (__FUNCTION__);
index 8423b448ab3386e3d4f239d847b93607002cfd3c..db13c252b0e80d943820bc45ab101b6dfad6d507 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/sched.h>
@@ -2425,7 +2426,7 @@ static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data)
        return 0;
 }
 
-int uhci_init(void)
+static int __init uhci_init(void)
 {
        int retval;
        struct pci_dev *dev;
@@ -2531,19 +2532,15 @@ void uhci_cleanup(void)
                printk(KERN_INFO "uhci: not all TD's were freed\n");
 }
 
-#ifdef MODULE
-int init_module(void)
-{
-       return uhci_init();
-}
-
-void cleanup_module(void)
+static void __exit uhci_exit(void)
 {
        pm_unregister_all(handle_pm_event);
        uhci_cleanup();
 }
 
+module_init(uhci_init);
+module_exit(uhci_exit);
+
 MODULE_AUTHOR("Linus Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber");
 MODULE_DESCRIPTION("USB Universal Host Controller Interface driver");
-#endif //MODULE
 
index 7f124b897dace9e41b540db88bb8d5cf355cb0ea..a1875608b3f2588919a908b262a16945dc185e93 100644 (file)
@@ -54,17 +54,6 @@ static int __init usb_init(void)
        usbdevfs_init();
        usb_hub_init();
 
-#ifndef CONFIG_USB_MODULE
-#ifdef CONFIG_USB_UHCI
-       uhci_init();
-#endif
-#ifdef CONFIG_USB_UHCI_ALT
-       uhci_init();
-#endif
-#ifdef CONFIG_USB_OHCI
-       ohci_hcd_init(); 
-#endif
-#endif
        return 0;
 }
 
index 316394a840f18bc4ab7c238cbefc5a1d4b15b837..ab042c42ea803d87d6d6c900a18a2abacb7bf22b 100644 (file)
@@ -2375,7 +2375,7 @@ static struct pmu_sleep_notifier ohci_sleep_notifier = {
 
 /*-------------------------------------------------------------------------*/
 
-int __init ohci_hcd_init (void) 
+static int __init ohci_hcd_init (void) 
 {
        int ret = pci_module_init (&ohci_pci_driver);
 
@@ -2386,11 +2386,10 @@ int __init ohci_hcd_init (void)
        return ret;
 }
 
-#ifdef MODULE
 
 /*-------------------------------------------------------------------------*/
 
-void __exit ohci_hcd_cleanup (void) 
+static void __exit ohci_hcd_cleanup (void) 
 {      
 #ifdef CONFIG_PMAC_PBOOK
        pmu_unregister_sleep_notifier (&ohci_sleep_notifier);
@@ -2401,7 +2400,6 @@ void __exit ohci_hcd_cleanup (void)
 module_init (ohci_hcd_init);
 module_exit (ohci_hcd_cleanup);
 
-#endif /* MODULE */
 
 
 MODULE_AUTHOR ("Roman Weissgaerber <weissg@vienna.at>");
index 14c6e649e44b1274ab54ab0d697ba4f7cf6e22ea..709fc028d5746849e1b3705828d55fcba5dea6e9 100644 (file)
@@ -2822,7 +2822,7 @@ _static int __init start_uhci (struct pci_dev *dev)
        return -1;
 }
 
-int __init uhci_init (void)
+static int __init uhci_init (void)
 {
        int retval = -ENODEV;
        struct pci_dev *dev = NULL;
@@ -2879,7 +2879,7 @@ int __init uhci_init (void)
        return retval;
 }
 
-void __exit uhci_cleanup (void)
+static void __exit uhci_cleanup (void)
 {
        uhci_t *s;
        while ((s = devs)) {
@@ -2895,18 +2895,15 @@ void __exit uhci_cleanup (void)
 #endif
 }
 
-#ifdef MODULE
-int init_module (void)
-{
-       return uhci_init ();
-}
-
-void cleanup_module (void)
+static void __exit uhci_exit (void)
 {
        pm_unregister_all (handle_pm_event);
        uhci_cleanup ();
 }
 
+module_init(uhci_init);
+module_exit(uhci_exit);
+
 MODULE_AUTHOR("Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber");
 MODULE_DESCRIPTION("USB Universal Host Controller Interface driver");
-#endif //MODULE
+
index 12cb880e4b81a6397e5d836bbe9ec88a28050f62..da61b52149e4852dd078f345fba3b4aa385acf2e 100644 (file)
@@ -484,16 +484,12 @@ static size_t parport_uss720_write_compat(struct parport *pp, const void *buffer
 
 void parport_uss720_inc_use_count(void)
 {
-#ifdef MODULE
        MOD_INC_USE_COUNT;
-#endif
 }
 
 void parport_uss720_dec_use_count(void)
 {
-#ifdef MODULE
        MOD_DEC_USE_COUNT;
-#endif
 }
 
 /* --------------------------------------------------------------------- */
index 266e7bf642d3684076dce7fa7c9fdee164a4f1b9..3ac27df920a3de648fddfa8c9ce544fcf97ff85d 100644 (file)
@@ -10,7 +10,7 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * $Id: inode-v23.c,v 1.34 2000/08/10 08:58:00 dwmw2 Exp $
+ * $Id: inode-v23.c,v 1.43 2000/08/22 08:00:22 dwmw2 Exp $
  *
  *
  * Ported to Linux 2.3.x and MTD:
@@ -151,10 +151,9 @@ jffs_put_super(struct super_block *sb)
 
        D2(printk("jffs_put_super()\n"));
 
-       D1(printk (KERN_NOTICE "jffs_put_super(): Telling gc thread to die.\n"));
        if (c->gc_task) {
-               send_sig(SIGQUIT, c->gc_task, 1);
-               send_sig(SIGCONT, c->gc_task, 1);
+               D1(printk (KERN_NOTICE "jffs_put_super(): Telling gc thread to die.\n"));
+               send_sig(SIGKILL, c->gc_task, 1);
        }
        down (&c->gc_thread_sem);
 
@@ -179,54 +178,56 @@ jffs_setattr(struct dentry *dentry, struct iattr *iattr)
        struct jffs_fmcontrol *fmc;
        struct jffs_file *f;
        struct jffs_node *new_node;
-       char *name = 0;
        int update_all;
        int res;
+       int recoverable = 0;
+
+       if ((res = inode_change_ok(inode, iattr)))
+               return res;
+
+       c = (struct jffs_control *)inode->i_sb->u.generic_sbp;
+       fmc = c->fmc;
+
+       D3(printk (KERN_NOTICE "notify_change(): down biglock\n"));
+       down(&fmc->biglock);
+
+       f = jffs_find_file(c, inode->i_ino);
 
-       f = (struct jffs_file *)inode->u.generic_ip;
        ASSERT(if (!f) {
                printk("jffs_setattr(): Invalid inode number: %lu\n",
                       inode->i_ino);
-               return -1;
+               D3(printk (KERN_NOTICE "notify_change(): up biglock\n"));
+               up(&fmc->biglock);
+               return -EINVAL;
        });
 
        D1(printk("***jffs_setattr(): file: \"%s\", ino: %u\n",
                  f->name, f->ino));
 
-       c = f->c;
-       fmc = c->fmc;
        update_all = iattr->ia_valid & ATTR_FORCE;
 
-       if (!JFFS_ENOUGH_SPACE(c)) {
-               if ( (update_all || iattr->ia_valid & ATTR_SIZE)
-                    && (iattr->ia_size < f->size) ) {
-                       /* See this case where someone is trying to
-                          shrink the size of a file as an exception.
-                          Accept it.  */
-                       /* TODO: Might just shrink it a bit?
-                          check f->size - ia_size */
-               } else {
-                       D1(printk("jffs_setattr(): Free size = %u\n",
-                                 jffs_free_size1(fmc)
-                                 + jffs_free_size2(fmc)));
-                       D(printk(KERN_NOTICE "JFFS: No space left on "
-                                "device\n"));
-                       return -ENOSPC;
-               }
-       }
+       if ( (update_all || iattr->ia_valid & ATTR_SIZE)
+            && (iattr->ia_size + 128 < f->size) ) {
+               /* We're shrinking the file by more than 128 bytes.
+                  We'll be able to GC and recover this space, so
+                  allow it to go into the reserved space. */
+               recoverable = 1;
+        }
 
        if (!(new_node = (struct jffs_node *)
                         kmalloc(sizeof(struct jffs_node), GFP_KERNEL))) {
                D(printk("jffs_setattr(): Allocation failed!\n"));
+               D3(printk (KERN_NOTICE "notify_change(): up biglock\n"));
+               up(&fmc->biglock);
                return -ENOMEM;
        }
+
        DJM(no_jffs_node++);
        new_node->data_offset = 0;
        new_node->removed_size = 0;
        raw_inode.magic = JFFS_MAGIC_BITMASK;
        raw_inode.ino = f->ino;
        raw_inode.pino = f->pino;
-       raw_inode.version = f->highest_version + 1;
        raw_inode.mode = f->mode;
        raw_inode.uid = f->uid;
        raw_inode.gid = f->gid;
@@ -237,7 +238,7 @@ jffs_setattr(struct dentry *dentry, struct iattr *iattr)
        raw_inode.offset = 0;
        raw_inode.rsize = 0;
        raw_inode.dsize = 0;
-       raw_inode.nsize = 0;
+       raw_inode.nsize = f->nsize;
        raw_inode.nlink = f->nlink;
        raw_inode.spare = 0;
        raw_inode.rename = 0;
@@ -278,12 +279,8 @@ jffs_setattr(struct dentry *dentry, struct iattr *iattr)
                new_node->data_offset = iattr->ia_size;
                new_node->removed_size = len;
                inode->i_size = iattr->ia_size;
+               inode->i_blocks = (inode->i_size + 511) >> 9;
 
-               /* If we truncate a file we want to add the name.  If we
-                  always do that, we could perhaps free more space on
-                  the flash (and besides it doesn't hurt).  */
-               name = f->name;
-               raw_inode.nsize = f->nsize;
                if (len) {
                        invalidate_inode_pages(inode);
                }
@@ -304,17 +301,20 @@ jffs_setattr(struct dentry *dentry, struct iattr *iattr)
        }
 
        /* Write this node to the flash.  */
-       if ((res = jffs_write_node(c, new_node, &raw_inode, name, 0)) < 0) {
+       if ((res = jffs_write_node(c, new_node, &raw_inode, f->name, 0, recoverable, f)) < 0) {
                D(printk("jffs_notify_change(): The write failed!\n"));
                kfree(new_node);
                DJM(no_jffs_node--);
+               D3(printk (KERN_NOTICE "n_c(): up biglock\n"));
+               up(&c->fmc->biglock);
                return res;
        }
 
        jffs_insert_node(c, f, &raw_inode, 0, new_node);
 
        mark_inode_dirty(inode);
-
+       D3(printk (KERN_NOTICE "n_c(): up biglock\n"));
+       up(&c->fmc->biglock);
        return 0;
 } /* jffs_notify_change()  */
 
@@ -403,7 +403,7 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry,
        __u32 rename_data = 0;
 
        D2(printk("***jffs_rename()\n"));
-
+       
        D(printk("jffs_rename(): old_dir: 0x%p, old name: 0x%p, "
                 "new_dir: 0x%p, new name: 0x%p\n",
                 old_dir, old_dentry->d_name.name,
@@ -413,17 +413,9 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry,
        ASSERT(if (!c) {
                printk(KERN_ERR "jffs_rename(): The old_dir inode "
                       "didn't have a reference to a jffs_file struct\n");
-               return -1;
+               return -EIO;
        });
 
-       if (!JFFS_ENOUGH_SPACE(c)) {
-               D1(printk("jffs_rename(): Free size = %u\n",
-                         jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc)));
-               D(printk(KERN_NOTICE "JFFS: No space left on device\n"));
-               return -ENOSPC;
-       }
-
-       /* Find the old directory.  */
        result = -ENOTDIR;
        if (!(old_dir_f = (struct jffs_file *)old_dir->u.generic_ip)) {
                D(printk("jffs_rename(): Old dir invalid.\n"));
@@ -443,7 +435,8 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry,
                D(printk("jffs_rename(): New dir invalid.\n"));
                goto jffs_rename_end;
        }
-
+       D3(printk (KERN_NOTICE "rename(): down biglock\n"));
+       down(&c->fmc->biglock);
        /* Create a node and initialize as much as needed.  */
        result = -ENOMEM;
        if (!(node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node),
@@ -459,7 +452,7 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry,
        raw_inode.magic = JFFS_MAGIC_BITMASK;
        raw_inode.ino = f->ino;
        raw_inode.pino = new_dir_f->ino;
-       raw_inode.version = f->highest_version + 1;
+/*     raw_inode.version = f->highest_version + 1; */
        raw_inode.mode = f->mode;
        raw_inode.uid = current->fsuid;
        raw_inode.gid = current->fsgid;
@@ -491,7 +484,7 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry,
        /* Write the new node to the flash memory.  */
        if ((result = jffs_write_node(c, node, &raw_inode,
                                      new_dentry->d_name.name,
-                                     (unsigned char*)&rename_data)) < 0) {
+                                     (unsigned char*)&rename_data, 0, f)) < 0) {
                D(printk("jffs_rename(): Failed to write node to flash.\n"));
                kfree(node);
                DJM(no_jffs_node--);
@@ -501,14 +494,14 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        if (raw_inode.rename) {
                /* The file with the same name must be deleted.  */
-               down(&c->fmc->gclock);
+               //FIXME deadlock                down(&c->fmc->gclock);
                if ((result = jffs_remove(new_dir, new_dentry,
                                          del_f->mode)) < 0) {
                        /* This is really bad.  */
                        printk(KERN_ERR "JFFS: An error occurred in "
                               "rename().\n");
                }
-               up(&c->fmc->gclock);
+               //              up(&c->fmc->gclock);
        }
 
        if (old_dir_f != new_dir_f) {
@@ -539,6 +532,8 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry,
        }
 
 jffs_rename_end:
+       D3(printk (KERN_NOTICE "rename(): up biglock\n"));
+       up(&c->fmc->biglock);
        return result;
 } /* jffs_rename()  */
 
@@ -551,13 +546,18 @@ jffs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        struct jffs_file *f;
        struct dentry *dentry = filp->f_dentry;
        struct inode *inode = dentry->d_inode;
+       struct jffs_control *c = (struct jffs_control *)inode->i_sb->u.generic_sbp;
        int j;
        int ddino;
+       D3(printk (KERN_NOTICE "readdir(): down biglock\n"));
+       down(&c->fmc->biglock);
 
        D2(printk("jffs_readdir(): inode: 0x%p, filp: 0x%p\n", inode, filp));
        if (filp->f_pos == 0) {
                D3(printk("jffs_readdir(): \".\" %lu\n", inode->i_ino));
                if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0) {
+                 D3(printk (KERN_NOTICE "readdir(): up biglock\n"));
+                       up(&c->fmc->biglock);
                        return 0;
                }
                filp->f_pos = 1;
@@ -571,8 +571,11 @@ jffs_readdir(struct file *filp, void *dirent, filldir_t filldir)
                                 inode->u.generic_ip)->pino;
                }
                D3(printk("jffs_readdir(): \"..\" %u\n", ddino));
-               if (filldir(dirent, "..", 2, filp->f_pos, ddino, DT_DIR) < 0)
+               if (filldir(dirent, "..", 2, filp->f_pos, ddino, DT_DIR) < 0) {
+                 D3(printk (KERN_NOTICE "readdir(): up biglock\n"));
+                       up(&c->fmc->biglock);
                        return 0;
+               }
                filp->f_pos++;
        }
        f = ((struct jffs_file *)inode->u.generic_ip)->children;
@@ -583,11 +586,15 @@ jffs_readdir(struct file *filp, void *dirent, filldir_t filldir)
                D3(printk("jffs_readdir(): \"%s\" ino: %u\n",
                          (f->name ? f->name : ""), f->ino));
                if (filldir(dirent, f->name, f->nsize,
-                           filp->f_pos , f->ino, DT_UNKNOWN) < 0)
+                           filp->f_pos , f->ino, DT_UNKNOWN) < 0) {
+                       D3(printk (KERN_NOTICE "readdir(): up biglock\n"));
+                       up(&c->fmc->biglock);
                        return 0;
+               }
                filp->f_pos++;
        }
-
+       D3(printk (KERN_NOTICE "readdir(): up biglock\n"));
+       up(&c->fmc->biglock);
        return filp->f_pos;
 } /* jffs_readdir()  */
 
@@ -599,6 +606,7 @@ jffs_lookup(struct inode *dir, struct dentry *dentry)
 {
        struct jffs_file *d;
        struct jffs_file *f;
+       struct jffs_control *c = (struct jffs_control *)dir->i_sb->u.generic_sbp;
        int len;
        int r = 0;
        const char *name;
@@ -615,6 +623,9 @@ jffs_lookup(struct inode *dir, struct dentry *dentry)
                kfree(s);
        });
 
+       D3(printk (KERN_NOTICE "lookup(): down biglock\n"));
+       down(&c->fmc->biglock);
+
        r = -ENAMETOOLONG;
        if (len > JFFS_MAX_NAME_LEN) {
                goto jffs_lookup_end;
@@ -628,21 +639,39 @@ jffs_lookup(struct inode *dir, struct dentry *dentry)
        }
 
        /* Get the corresponding inode to the file.  */
+
+       /* iget calls jffs_read_inode, so we need to drop the biglock
+           before calling iget.  Unfortunately, the GC has a tendency
+           to sneak in here, because iget sometimes calls schedule (). 
+         */
+
        if ((len == 1) && (name[0] == '.')) {
+                D3(printk (KERN_NOTICE "lookup(): up biglock\n"));
+               up(&c->fmc->biglock);
                if (!(inode = iget(dir->i_sb, d->ino))) {
                        D(printk("jffs_lookup(): . iget() ==> NULL\n"));
-                       goto jffs_lookup_end;
+                       goto jffs_lookup_end_no_biglock;
                }
+               D3(printk (KERN_NOTICE "lookup(): down biglock\n"));
+               down(&c->fmc->biglock);
        } else if ((len == 2) && (name[0] == '.') && (name[1] == '.')) {
-               if (!(inode = iget(dir->i_sb, d->pino))) {
+               D3(printk (KERN_NOTICE "lookup(): up biglock\n"));
+               up(&c->fmc->biglock);
+               if (!(inode = iget(dir->i_sb, d->pino))) {
                        D(printk("jffs_lookup(): .. iget() ==> NULL\n"));
-                       goto jffs_lookup_end;
+                       goto jffs_lookup_end_no_biglock;
                }
+               D3(printk (KERN_NOTICE "lookup(): down biglock\n"));
+               down(&c->fmc->biglock);
        } else if ((f = jffs_find_child(d, name, len))) {
+               D3(printk (KERN_NOTICE "lookup(): up biglock\n"));
+               up(&c->fmc->biglock);
                if (!(inode = iget(dir->i_sb, f->ino))) {
                        D(printk("jffs_lookup(): iget() ==> NULL\n"));
-                       goto jffs_lookup_end;
+                       goto jffs_lookup_end_no_biglock;
                }
+               D3(printk (KERN_NOTICE "lookup(): down biglock\n"));
+               down(&c->fmc->biglock);
        } else {
                D3(printk("jffs_lookup(): Couldn't find the file. "
                          "f = 0x%p, name = \"%s\", d = 0x%p, d->ino = %u\n",
@@ -651,9 +680,15 @@ jffs_lookup(struct inode *dir, struct dentry *dentry)
        }
 
        d_add(dentry, inode);
+       D3(printk (KERN_NOTICE "lookup(): up biglock\n"));
+       up(&c->fmc->biglock);
        return NULL;
 
 jffs_lookup_end:
+       D3(printk (KERN_NOTICE "lookup(): up biglock\n"));
+       up(&c->fmc->biglock);
+
+jffs_lookup_end_no_biglock:
        return ERR_PTR(r);
 } /* jffs_lookup()  */
 
@@ -667,6 +702,7 @@ jffs_readpage(struct file *file, struct page *page)
        int result = -EIO;
        struct inode *inode = (struct inode*)page->mapping->host;
        struct jffs_file *f = (struct jffs_file *)inode->u.generic_ip;
+       struct jffs_control *c = (struct jffs_control *)inode->i_sb->u.generic_sbp;
        int r;
        loff_t offset;
 
@@ -679,6 +715,9 @@ jffs_readpage(struct file *file, struct page *page)
        ClearPageUptodate(page);
        ClearPageError(page);
 
+       D3(printk (KERN_NOTICE "readpage(): down biglock\n"));
+       down(&c->fmc->biglock);
+
        offset = page->index << PAGE_CACHE_SHIFT;
        if (offset < inode->i_size) {
                read_len = jffs_min(inode->i_size - offset, PAGE_SIZE);
@@ -697,6 +736,10 @@ jffs_readpage(struct file *file, struct page *page)
                               "read %d bytes.\n", read_len, r);
                });
        }
+
+       D3(printk (KERN_NOTICE "readpage(): up biglock\n"));
+       up(&c->fmc->biglock);
+       
        if (result) {
                memset(buf, 0, PAGE_SIZE);
                SetPageError(page);
@@ -737,22 +780,16 @@ jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        });
 
        dir_f = (struct jffs_file *)dir->u.generic_ip;
+
        ASSERT(if (!dir_f) {
                printk(KERN_ERR "jffs_mkdir(): No reference to a "
                       "jffs_file struct in inode.\n");
-               result = -1;
-               goto jffs_mkdir_end;
+               return -EIO;
        });
 
        c = dir_f->c;
-
-       if (!JFFS_ENOUGH_SPACE(c)) {
-               D1(printk("jffs_mkdir(): Free size = %u\n",
-                         jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc)));
-               D(printk(KERN_NOTICE "JFFS: No space left on device\n"));
-               result = -ENOSPC;
-               goto jffs_mkdir_end;
-       }
+       D3(printk (KERN_NOTICE "mkdir(): down biglock\n"));
+       down(&c->fmc->biglock);
 
        dir_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX)
                              & ~current->fs->umask);
@@ -794,7 +831,7 @@ jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 
        /* Write the new node to the flash.  */
        if ((result = jffs_write_node(c, node, &raw_inode,
-                                     dentry->d_name.name, 0)) < 0) {
+                                     dentry->d_name.name, 0, 0, NULL)) < 0) {
                D(printk("jffs_mkdir(): jffs_write_node() failed.\n"));
                kfree(node);
                DJM(no_jffs_node--);
@@ -821,6 +858,8 @@ jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 
        result = 0;
 jffs_mkdir_end:
+       D3(printk (KERN_NOTICE "mkdir(): up biglock\n"));
+       up(&c->fmc->biglock);
        return result;
 } /* jffs_mkdir()  */
 
@@ -829,8 +868,15 @@ jffs_mkdir_end:
 static int
 jffs_rmdir(struct inode *dir, struct dentry *dentry)
 {
+       struct jffs_control *c = (struct jffs_control *)dir->i_sb->u.generic_sbp;
+       int ret;
        D3(printk("***jffs_rmdir()\n"));
-       return jffs_remove(dir, dentry, S_IFDIR);
+       D3(printk (KERN_NOTICE "rmdir(): down biglock\n"));
+       down(&c->fmc->biglock);
+       ret = jffs_remove(dir, dentry, S_IFDIR);
+       D3(printk (KERN_NOTICE "rmdir(): up biglock\n"));
+       up(&c->fmc->biglock);
+       return ret;
 }
 
 
@@ -838,8 +884,16 @@ jffs_rmdir(struct inode *dir, struct dentry *dentry)
 static int
 jffs_unlink(struct inode *dir, struct dentry *dentry)
 {
+       struct jffs_control *c = (struct jffs_control *)dir->i_sb->u.generic_sbp;
+       int ret; 
+
        D3(printk("***jffs_unlink()\n"));
-       return jffs_remove(dir, dentry, 0);
+       D3(printk (KERN_NOTICE "unlink(): down biglock\n"));
+       down(&c->fmc->biglock);
+       ret = jffs_remove(dir, dentry, 0);
+       D3(printk (KERN_NOTICE "unlink(): up biglock\n"));
+       up(&c->fmc->biglock);
+       return ret;
 }
 
 
@@ -862,7 +916,7 @@ jffs_remove(struct inode *dir, struct dentry *dentry, int type)
                char *_name = (char *) kmalloc(len + 1, GFP_KERNEL);
                memcpy(_name, name, len);
                _name[len] = '\0';
-               printk("***jffs_remove(): file = \"%s\"\n", _name);
+               printk("***jffs_remove(): file = \"%s\", ino = %ld\n", _name, dentry->d_inode->i_ino);
                kfree(_name);
        });
 
@@ -916,7 +970,7 @@ jffs_remove(struct inode *dir, struct dentry *dentry, int type)
        raw_inode.magic = JFFS_MAGIC_BITMASK;
        raw_inode.ino = del_f->ino;
        raw_inode.pino = del_f->pino;
-       raw_inode.version = del_f->highest_version + 1;
+/*     raw_inode.version = del_f->highest_version + 1; */
        raw_inode.mode = del_f->mode;
        raw_inode.uid = current->fsuid;
        raw_inode.gid = current->fsgid;
@@ -933,7 +987,7 @@ jffs_remove(struct inode *dir, struct dentry *dentry, int type)
        raw_inode.deleted = 1;
 
        /* Write the new node to the flash memory.  */
-       if (jffs_write_node(c, del_node, &raw_inode, 0, 0) < 0) {
+       if (jffs_write_node(c, del_node, &raw_inode, 0, 0, 1, del_f) < 0) {
                kfree(del_node);
                DJM(no_jffs_node--);
                result = -EIO;
@@ -979,13 +1033,8 @@ jffs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
        dir_f = (struct jffs_file *)dir->u.generic_ip;
        c = dir_f->c;
 
-       if (!JFFS_ENOUGH_SPACE(c)) {
-               D1(printk("jffs_mknod(): Free size = %u\n",
-                         jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc)));
-               D(printk(KERN_NOTICE "JFFS: No space left on device\n"));
-               result = -ENOSPC;
-               goto jffs_mknod_end;
-       }
+       D3(printk (KERN_NOTICE "mknod(): down biglock\n"));
+       down(&c->fmc->biglock);
 
        /* Create and initialize a new node.  */
        if (!(node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node),
@@ -1021,7 +1070,7 @@ jffs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
 
        /* Write the new node to the flash.  */
        if ((err = jffs_write_node(c, node, &raw_inode, dentry->d_name.name,
-                                 (unsigned char *)&dev)) < 0) {
+                                 (unsigned char *)&dev, 0, NULL)) < 0) {
                D(printk("jffs_mknod(): jffs_write_node() failed.\n"));
                result = err;
                goto jffs_mknod_err;
@@ -1053,6 +1102,8 @@ jffs_mknod_err:
        }
 
 jffs_mknod_end:
+       D3(printk (KERN_NOTICE "mknod(): up biglock\n"));
+       up(&c->fmc->biglock);
        return result;
 } /* jffs_mknod()  */
 
@@ -1088,24 +1139,20 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
        ASSERT(if (!dir_f) {
                printk(KERN_ERR "jffs_symlink(): No reference to a "
                       "jffs_file struct in inode.\n");
-               return -1;
+               return -EIO;
        });
 
        c = dir_f->c;
 
-       if (!JFFS_ENOUGH_SPACE(c)) {
-               D1(printk("jffs_symlink(): Free size = %u\n",
-                         jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc)));
-               D(printk(KERN_NOTICE "JFFS: No space left on device\n"));
-               return -ENOSPC;
-       }
-
        /* Create a node and initialize it as much as needed.  */
        if (!(node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node),
                                                  GFP_KERNEL))) {
                D(printk("jffs_symlink(): Allocation failed: node = NULL\n"));
                return -ENOMEM;
        }
+       D3(printk (KERN_NOTICE "symlink(): down biglock\n"));
+       down(&c->fmc->biglock);
+
        DJM(no_jffs_node++);
        node->data_offset = 0;
        node->removed_size = 0;
@@ -1132,30 +1179,32 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
 
        /* Write the new node to the flash.  */
        if ((err = jffs_write_node(c, node, &raw_inode, dentry->d_name.name,
-                                  (const unsigned char *)symname)) < 0) {
+                                  (const unsigned char *)symname, 0, NULL)) < 0) {
                D(printk("jffs_symlink(): jffs_write_node() failed.\n"));
                kfree(node);
                DJM(no_jffs_node--);
-               return err;
+               goto jffs_symlink_end;
        }
 
        /* Insert the new node into the file system.  */
        if ((err = jffs_insert_node(c, 0, &raw_inode, dentry->d_name.name,
                                    node)) < 0) {
-               return err;
+               goto jffs_symlink_end;
        }
 
        inode = jffs_new_inode(dir, &raw_inode, &err);
        if (inode == NULL) {
-               return err;
+               goto jffs_symlink_end;
        }
-
+       err = 0;
        inode->i_op = &page_symlink_inode_operations;
        inode->i_mapping->a_ops = &jffs_address_operations;
 
        d_instantiate(dentry, inode);
-
-       return 0;
+ jffs_symlink_end:
+       D3(printk (KERN_NOTICE "symlink(): up biglock\n"));
+       up(&c->fmc->biglock);
+       return err;
 } /* jffs_symlink()  */
 
 
@@ -1191,24 +1240,20 @@ jffs_create(struct inode *dir, struct dentry *dentry, int mode)
        ASSERT(if (!dir_f) {
                printk(KERN_ERR "jffs_create(): No reference to a "
                       "jffs_file struct in inode.\n");
-               return -1;
+               return -EIO;
        });
 
        c = dir_f->c;
 
-       if (!JFFS_ENOUGH_SPACE(c)) {
-               D1(printk("jffs_create(): Free size = %u\n",
-                         jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc)));
-               D(printk(KERN_NOTICE "JFFS: No space left on device\n"));
-               return -ENOSPC;
-       }
-
        /* Create a node and initialize as much as needed.  */
        if (!(node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node),
                                                  GFP_KERNEL))) {
                D(printk("jffs_create(): Allocation failed: node == 0\n"));
                return -ENOMEM;
        }
+       D3(printk (KERN_NOTICE "create(): down biglock\n"));
+       down(&c->fmc->biglock);
+
        DJM(no_jffs_node++);
        node->data_offset = 0;
        node->removed_size = 0;
@@ -1235,33 +1280,35 @@ jffs_create(struct inode *dir, struct dentry *dentry, int mode)
 
        /* Write the new node to the flash.  */
        if ((err = jffs_write_node(c, node, &raw_inode,
-                                  dentry->d_name.name, 0)) < 0) {
+                                  dentry->d_name.name, 0, 0, NULL)) < 0) {
                D(printk("jffs_create(): jffs_write_node() failed.\n"));
                kfree(node);
                DJM(no_jffs_node--);
-               return err;
+               goto jffs_create_end;
        }
 
        /* Insert the new node into the file system.  */
        if ((err = jffs_insert_node(c, 0, &raw_inode, dentry->d_name.name,
                                    node)) < 0) {
-               return err;
+               goto jffs_create_end;
        }
 
        /* Initialize an inode.  */
        inode = jffs_new_inode(dir, &raw_inode, &err);
        if (inode == NULL) {
-               return err;
+               goto jffs_create_end;
        }
-
+       err = 0;
        inode->i_op = &jffs_file_inode_operations;
        inode->i_fop = &jffs_file_operations;
        inode->i_mapping->a_ops = &jffs_address_operations;
        inode->i_mapping->nrpages = 0;
 
        d_instantiate(dentry, inode);
-
-       return 0;
+ jffs_create_end:
+       D3(printk (KERN_NOTICE "create(): up biglock\n"));
+       up(&c->fmc->biglock);
+       return err;
 } /* jffs_create()  */
 
 
@@ -1277,7 +1324,9 @@ jffs_file_write(struct file *filp, const char *buf, size_t count,
        struct dentry *dentry = filp->f_dentry;
        struct inode *inode = dentry->d_inode;
        unsigned char *vbuf;
-       int written = 0;
+       int recoverable = 0;
+       size_t written = 0;
+       __u32 thiscount = count;
        loff_t pos;
        int err;
 
@@ -1287,147 +1336,176 @@ jffs_file_write(struct file *filp, const char *buf, size_t count,
                  "filp: 0x%p, buf: 0x%p, count: %d\n",
                  inode, inode->i_ino, filp, buf, count));
 
-       down(&inode->i_sem);
-
-       pos = *ppos;
-       err = -EINVAL;
-       if (pos < 0)
-               goto out;
-
        err = filp->f_error;
        if (err) {
                filp->f_error = 0;
-               goto out;
+               return err;
        }
 
+       down(&inode->i_sem);
+
        if (inode->i_sb->s_flags & MS_RDONLY) {
                D(printk("jffs_file_write(): MS_RDONLY\n"));
-               err = -ENOSPC;
-               goto out;
+               err = -EROFS;
+               goto out_isem;
        }
 
+       err = -EINVAL;
+
        if (!S_ISREG(inode->i_mode)) {
                D(printk("jffs_file_write(): inode->i_mode == 0x%08x\n",
                         inode->i_mode));
-               err = -EINVAL;
-               goto out;
+               goto out_isem;
        }
 
        if (!(f = (struct jffs_file *)inode->u.generic_ip)) {
                D(printk("jffs_file_write(): inode->u.generic_ip = 0x%p\n",
                         inode->u.generic_ip));
-               err = -EINVAL;
-               goto out;
+               goto out_isem;
        }
 
        c = f->c;
 
-       if (!JFFS_ENOUGH_SPACE(c)) {
-               D1(printk("jffs_file_write(): Free size = %u\n",
-                         jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc)));
-               D(printk(KERN_NOTICE "JFFS: No space left on device\n"));
-               err = -ENOSPC;
-               goto out;
-       }
-
        if (filp->f_flags & O_APPEND)
                pos = inode->i_size;
+       else
+               pos = *ppos;
+       
+       if (pos < 0) {
+               goto out_isem;
+       }
+       
+       thiscount = jffs_min(c->fmc->max_chunk_size - sizeof(struct jffs_raw_inode), count);
 
-
-       if (!(vbuf = kmalloc(count, GFP_KERNEL))) {
+       if (!(vbuf = kmalloc(thiscount, GFP_KERNEL))) {
                D(printk("jffs_file_write(): failed to allocate bounce buffer. Fix me to use page cache\n"));
                err = -ENOMEM;
-               goto out;
+               goto out_isem;
        }
 
-       /* FIXME: This is entirely gratuitous use of bounce buffers.
-          Get a clue and use the page cache. 
-          /me wanders off to get a crash course on Linux VFS
-          dwmw2
-       */
-       if (copy_from_user(vbuf, buf, count)) {
-               kfree(vbuf);
-               return -EFAULT;
-       }
-               
-
-       /* Things are going to be written so we could allocate and
-          initialize the necessary data structures now.  */
-       if (!(node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node),
-                                                 GFP_KERNEL))) {
-               D(printk("jffs_file_write(): node == 0\n"));
-               err = -ENOMEM;
-               kfree(vbuf);
-               goto out;
-       }
-       DJM(no_jffs_node++);
-       node->data_offset = pos;
-       node->removed_size = 0;
+       D3(printk (KERN_NOTICE "file_write(): down biglock\n"));
+       down(&c->fmc->biglock);
 
-       /* Initialize the raw inode.  */
-       raw_inode.magic = JFFS_MAGIC_BITMASK;
-       raw_inode.ino = f->ino;
-       raw_inode.pino = f->pino;
-       raw_inode.version = f->highest_version + 1;
-       raw_inode.mode = f->mode;
+       /* Urgh. POSIX says we can do short writes if we feel like it. 
+        * In practice, we can't. Nothing will cope. So we loop until
+        * we're done.
+        *
+        * <_Anarchy_> posix and reality are not interconnected on this issue
+        */
+       while (count) {
+
+               /* FIXME: This is entirely gratuitous use of bounce buffers.
+                  Get a clue and use the page cache. 
+                  /me wanders off to get a crash course on Linux VFS
+                  dwmw2
+               */
+               if (copy_from_user(vbuf, buf, thiscount)) {
+                       err = -EFAULT;
+                       goto out;
+               }
+               
+               /* Things are going to be written so we could allocate and
+                  initialize the necessary data structures now.  */
+               if (!(node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node),
+                                                         GFP_KERNEL))) {
+                       D(printk("jffs_file_write(): node == 0\n"));
+                       err = -ENOMEM;
+                       goto out;
+               }
+               DJM(no_jffs_node++);
+               
+               node->data_offset = pos;
+               node->removed_size = 0;
+               
+               /* Initialize the raw inode.  */
+               raw_inode.magic = JFFS_MAGIC_BITMASK;
+               raw_inode.ino = f->ino;
+               raw_inode.pino = f->pino;
 
-       raw_inode.uid = f->uid;
-       raw_inode.gid = f->gid;
-       /*
-       raw_inode.uid = current->fsuid;
-       raw_inode.gid = current->fsgid;
-       */
-       raw_inode.atime = CURRENT_TIME;
-       raw_inode.mtime = raw_inode.atime;
-       raw_inode.ctime = f->ctime;
-       raw_inode.offset = pos;
-       raw_inode.dsize = count;
-       raw_inode.rsize = 0;
-       raw_inode.nsize = 0;
-       raw_inode.nlink = f->nlink;
-       raw_inode.spare = 0;
-       raw_inode.rename = 0;
-       raw_inode.deleted = 0;
+               raw_inode.mode = f->mode;
+               
+               raw_inode.uid = f->uid;
+               raw_inode.gid = f->gid;
+               raw_inode.atime = CURRENT_TIME;
+               raw_inode.mtime = raw_inode.atime;
+               raw_inode.ctime = f->ctime;
+               raw_inode.offset = pos;
+               raw_inode.dsize = thiscount;
+               raw_inode.rsize = 0;
+               raw_inode.nsize = f->nsize;
+               raw_inode.nlink = f->nlink;
+               raw_inode.spare = 0;
+               raw_inode.rename = 0;
+               raw_inode.deleted = 0;
+               
+               if (pos < f->size) {
+                       node->removed_size = raw_inode.rsize = jffs_min(thiscount, f->size - pos);
+                       
+                       /* If this node is going entirely over the top of old data, 
+                          we can allow it to go into the reserved space, because 
+                          we can that GC can reclaim the space later.
+                       */
+                       if (pos + thiscount < f->size) {
+                               /* If all the data we're overwriting are _real_,
+                                  not just holes, then:
+                                  recoverable = 1;
+                               */
+                       }
+               }
+               
+               /* Write the new node to the flash.  */
+               /* NOTE: We would be quite happy if jffs_write_node() wrote a 
+                  smaller node than we were expecting. There's no need for it 
+                  to waste the space at the end of the flash just because it's 
+                  a little smaller than what we asked for. But that's a whole
+                  new can of worms which I'm not going to open this week. dwmw2.
+               */
+               if ((err = jffs_write_node(c, node, &raw_inode, f->name,
+                                          (const unsigned char *)vbuf,
+                                          recoverable, f)) < 0) {
+                       D(printk("jffs_file_write(): jffs_write_node() failed.\n"));
+                       kfree(node);
+                       DJM(no_jffs_node--);
+                       goto out;
+               }
 
-       if (pos < f->size) {
-               node->removed_size = raw_inode.rsize = jffs_min(count, f->size - pos);
-       }
+               written += err;
+               buf += err;
+               count -= err;
+               pos += err;
 
-       /* Write the new node to the flash.  */
-       if ((written = jffs_write_node(c, node, &raw_inode, 0,
-                                      (const unsigned char *)vbuf)) < 0) {
-               D(printk("jffs_file_write(): jffs_write_node() failed.\n"));
-               kfree(node);
-               kfree(vbuf);
-               DJM(no_jffs_node--);
-               err = written;
-               goto out;
-       }
+               /* Insert the new node into the file system.  */
+               if ((err = jffs_insert_node(c, f, &raw_inode, 0, node)) < 0) {
+                       goto out;
+               }
 
-       kfree(vbuf);
+               D3(printk("jffs_file_write(): new f_pos %ld.\n", (long)pos));
 
-       /* Insert the new node into the file system.  */
-       if ((err = jffs_insert_node(c, f, &raw_inode, 0, node)) < 0) {
-               goto out;
+               thiscount = jffs_min(c->fmc->max_chunk_size - sizeof(struct jffs_raw_inode), count);
        }
-
-       pos += written;
+ out:
+       D3(printk (KERN_NOTICE "file_write(): up biglock\n"));
+       up(&c->fmc->biglock);
        *ppos = pos;
-
-       D3(printk("jffs_file_write(): new f_pos %ld.\n", (long)pos));
+       kfree(vbuf);
 
        /* Fix things in the real inode.  */
        if (pos > inode->i_size) {
                inode->i_size = pos;
+               inode->i_blocks = (inode->i_size + 511) >> 9;
        }
        inode->i_ctime = inode->i_mtime = CURRENT_TIME;
        mark_inode_dirty(inode);
        invalidate_inode_pages(inode);
 
-       err = written;
-out:
+ out_isem:
        up(&inode->i_sem);
-       return err;
+       
+       /* What if there was an error, _and_ we've written some data. */
+       if (written)
+               return written;
+       else
+               return err;
 } /* jffs_file_write()  */
 
 
@@ -1437,6 +1515,7 @@ jffs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
           unsigned long arg)
 {
        struct jffs_control *c;
+       int ret = 0;
 
        D2(printk("***jffs_ioctl(): cmd = 0x%08x, arg = 0x%08lx\n",
                  cmd, arg));
@@ -1446,6 +1525,8 @@ jffs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                       "(cmd = 0x%08x)\n", cmd);
                return -EIO;
        }
+       D3(printk (KERN_NOTICE "ioctl(): down biglock\n"));
+       down(&c->fmc->biglock);
 
        switch (cmd) {
        case JFFS_PRINT_HASH:
@@ -1464,7 +1545,8 @@ jffs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                                       sizeof(struct jffs_flash_status))) {
                                D(printk("jffs_ioctl(): Bad arg in "
                                         "JFFS_GET_STATUS ioctl!\n"));
-                               return -EFAULT;
+                               ret = -EFAULT;
+                               break;
                        }
                        fst.size = fmc->flash_size;
                        fst.used = fmc->used_size;
@@ -1478,15 +1560,16 @@ jffs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                        if (copy_to_user((struct jffs_flash_status *)arg,
                                         &fst,
                                         sizeof(struct jffs_flash_status))) {
-                         return -EFAULT;
+                         ret = -EFAULT;
                        }
                }
                break;
        default:
-               return -ENOTTY;
+               ret = -ENOTTY;
        }
-
-       return 0;
+       D3(printk (KERN_NOTICE "ioctl(): up biglock\n"));
+       up(&c->fmc->biglock);
+       return ret;
 } /* jffs_ioctl()  */
 
 
@@ -1555,9 +1638,13 @@ jffs_read_inode(struct inode *inode)
                return;
        }
        c = (struct jffs_control *)inode->i_sb->u.generic_sbp;
+       D3(printk (KERN_NOTICE "read_inode(): down biglock\n"));
+       down(&c->fmc->biglock);
        if (!(f = jffs_find_file(c, inode->i_ino))) {
                D(printk("jffs_read_inode(): No such inode (%lu).\n",
                         inode->i_ino));
+               D3(printk (KERN_NOTICE "read_inode(): up biglock\n"));
+               up(&c->fmc->biglock);
                return;
        }
        inode->u.generic_ip = (void *)f;
@@ -1592,6 +1679,8 @@ jffs_read_inode(struct inode *inode)
                jffs_read_data(f, (char *)&rdev, 0, sizeof(kdev_t));
                init_special_inode(inode, inode->i_mode, kdev_t_to_nr(rdev));
        }
+       D3(printk (KERN_NOTICE "read_inode(): up biglock\n"));
+       up(&c->fmc->biglock);
 }
 
 
@@ -1603,6 +1692,7 @@ jffs_delete_inode(struct inode *inode)
 
        lock_kernel();
        inode->i_size = 0;
+       inode->i_blocks = 0;
        clear_inode(inode);
        unlock_kernel();
 }
index adb2e0c46b5d7141eb1e81e11962162de80aa10e..5cf82f46886eb2441b08bf0d1428d5bf4e04fa49 100644 (file)
@@ -10,7 +10,7 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * $Id: intrep.c,v 1.39 2000/08/09 13:23:36 dwmw2 Exp $
+ * $Id: intrep.c,v 1.69 2000/08/24 09:35:47 dwmw2 Exp $
  *
  * Ported to Linux 2.3.x and MTD:
  * Copyright (C) 2000  Alexander Larsson (alex@cendio.se), Cendio Systems AB
@@ -191,12 +191,13 @@ flash_safe_read(struct mtd_info *mtd, loff_t from,
                u_char *buf, size_t count)
 {
        size_t retlen;
+       int res;
 
-       MTD_READ(mtd, from, count, &retlen, buf);
+       res = MTD_READ(mtd, from, count, &retlen, buf);
        if (retlen != count) {
-               printk("Didn't read all bytes in flash_safe_read()\n");
+               printk("Didn't read all bytes in flash_safe_read(). Returned %d\n", res);
        }
-       return retlen;
+       return res?res:retlen;
 }
 
 
@@ -205,10 +206,11 @@ flash_read_u32(struct mtd_info *mtd, loff_t from)
 {
        size_t retlen;
        __u32 ret;
+       int res;
 
-       MTD_READ(mtd, from, 4, &retlen, (unsigned char *)&ret);
+       res = MTD_READ(mtd, from, 4, &retlen, (unsigned char *)&ret);
        if (retlen != 4) {
-               printk("Didn't read all bytes in flash_read_u32()\n");
+               printk("Didn't read all bytes in flash_read_u32(). Returned %d\n", res);
                return 0;
        }
 
@@ -221,10 +223,11 @@ flash_read_u8(struct mtd_info *mtd, loff_t from)
 {
        size_t retlen;
        __u8 ret;
+       int res;
 
-       MTD_READ(mtd, from, 1, &retlen, &ret);
+       res = MTD_READ(mtd, from, 1, &retlen, &ret);
        if (retlen != 1) {
-               printk("Didn't read a byte in flash_read_u8()\n");
+               printk("Didn't read a byte in flash_read_u8(). Returned %d\n", res);
                return 0;
        }
 
@@ -237,12 +240,13 @@ flash_safe_write(struct mtd_info *mtd, loff_t to,
                 const u_char *buf, size_t count)
 {
        size_t retlen;
+       int res;
 
-       MTD_WRITE(mtd, to, count, &retlen, buf);
+       res = MTD_WRITE(mtd, to, count, &retlen, buf);
        if (retlen != count) {
-               printk("Didn't write all bytes in flash_safe_write()\n");
+               printk("Didn't write all bytes in flash_safe_write(). Returned %d\n", res);
        }
-       return retlen;
+       return res?res:retlen;
 }
 
 
@@ -306,7 +310,8 @@ flash_erase_region(struct mtd_info *mtd, loff_t start,
        erase->len = size;
        erase->priv = (u_long)&wait_q;
 
-       set_current_state(TASK_INTERRUPTIBLE);
+       /* FIXME: Use TASK_INTERRUPTIBLE and deal with being interrupted */
+       set_current_state(TASK_UNINTERRUPTIBLE);
        add_wait_queue(&wait_q, &wait);
 
        if (MTD_ERASE(mtd, erase) < 0) {
@@ -321,7 +326,6 @@ flash_erase_region(struct mtd_info *mtd, loff_t start,
        }
 
        schedule(); /* Wait for flash to finish. */
-       /* FIXME: We could have been interrupted here. We don't deal with it */
        remove_wait_queue(&wait_q, &wait);
 
        kfree(erase);
@@ -369,15 +373,14 @@ jffs_checksum_flash(struct mtd_info *mtd, loff_t start, int size)
        D3(printk("checksum result: 0x%08x\n", sum));
        return sum;
 }
-
 static __inline__ void jffs_fm_write_lock(struct jffs_fmcontrol *fmc)
 {
-       down(&fmc->wlock);
+  //   down(&fmc->wlock);
 }
 
 static __inline__ void jffs_fm_write_unlock(struct jffs_fmcontrol *fmc)
 {
-       up(&fmc->wlock);
+  //   up(&fmc->wlock);
 }
 
 
@@ -421,6 +424,7 @@ jffs_create_control(kdev_t dev)
        }
        DJM(no_jffs_control++);
        c->root = 0;
+       c->gc_task = 0;
        c->hash_len = JFFS_HASH_SIZE;
        s = sizeof(struct list_head) * c->hash_len;
        if (!(c->hash = (struct list_head *)kmalloc(s, GFP_KERNEL))) {
@@ -640,6 +644,16 @@ jffs_scan_flash(struct jffs_control *c)
                           a single kernel thread will fix the original problem.
                        */
                        if ((__u32) pos % fmc->sector_size) {
+                               /* If there was free space in previous 
+                                  sectors, don't mark that dirty too - 
+                                  only from the beginning of this sector
+                                  (or from start) 
+                               */
+                               if (start < (pos & ~(fmc->sector_size-1))) {
+                                       D1(printk("Reducing start to 0x%x from 0x%x\n", pos & ~(fmc->sector_size-1), start));
+                                       start = pos & ~(fmc->sector_size-1);
+                               }
+                               D1(printk("Dirty space: 0x%x for 0x%x bytes\n", start, (pos - start)));
                                jffs_fmalloced(fmc, (__u32) start,
                                               (__u32) (pos - start), 0);
                        }
@@ -672,6 +686,7 @@ jffs_scan_flash(struct jffs_control *c)
                                  "hexdump(pos = 0x%lx, len = 128):\n",
                                  (long)pos));
                        D1(jffs_hexdump(fmc->mtd, pos, 128));
+               cont_dirty:
                        for (pos += 4; pos < end; pos += 4) {
                                switch (flash_read_u32(fmc->mtd, pos)) {
                                case JFFS_MAGIC_BITMASK:
@@ -679,6 +694,46 @@ jffs_scan_flash(struct jffs_control *c)
                                                       (__u32) (pos - start),
                                                       0);
                                        goto cont_scan;
+                               case JFFS_EMPTY_BITMASK:
+                                       /* First, mark as dirty the region
+                                          which really does contain crap. */
+                                       jffs_fmalloced(fmc, (__u32) start,
+                                                      (__u32) (pos - start),
+                                                      0);
+
+                                       /* Then, scan the region which looks free.
+                                          Depending on how large it is, we may
+                                          mark it dirty too.
+                                       */
+                                       start = pos;
+                                       for (; pos < end ; pos += 4) {
+                                               switch (flash_read_u32(fmc->mtd, pos)) {
+                                               case JFFS_MAGIC_BITMASK:
+                                                       if (pos - start < fmc->max_chunk_size) {
+                                                               /* Not much free space. Mark it dirty. */
+                                                               jffs_fmalloced(fmc, (__u32)start,
+                                                                              (__u32)pos-start, 0);
+                                                       }
+                                                       goto cont_scan;
+
+                                               case JFFS_EMPTY_BITMASK:
+                                                       /* More empty space */
+                                                       continue;
+                               
+                                               default: 
+                                                       /* i.e. more dirt */
+                                                       if (pos - start < fmc->max_chunk_size) {
+                                                               /* There wasn't much before the dirt
+                                                                  started again. Just mark it all dirty
+                                                               */
+                                                               goto cont_dirty;
+                                                       }
+                                                       /* There was quite a lot of free space. Leave it
+                                                          free.
+                                                       */
+                                                       goto cont_scan;
+                                               }
+                                       }
                                default:
                                        break;
                                }
@@ -734,6 +789,8 @@ jffs_scan_flash(struct jffs_control *c)
                /* Check the raw inode read so far.  Start with the
                   maximum length of the filename.  */
                if (raw_inode.nsize > JFFS_MAX_NAME_LEN) {
+                       printk(KERN_WARNING "jffs_scan_flash: Found a "
+                              "JFFS node with name too large\n");
                        goto bad_inode;
                }
 
@@ -748,6 +805,9 @@ jffs_scan_flash(struct jffs_control *c)
                /* The node's data segment should not exceed a
                   certain length.  */
                if (raw_inode.dsize > fmc->max_chunk_size) {
+                       printk(KERN_WARNING "jffs_scan_flash: Found a "
+                              "JFFS node with dsize (0x%x) > max_chunk_size (0x%x)\n",
+                              raw_inode.dsize, fmc->max_chunk_size);
                        goto bad_inode;
                }
 
@@ -895,9 +955,9 @@ jffs_insert_node(struct jffs_control *c, struct jffs_file *f,
        int insert_into_tree = 0;
 
        D2(printk("jffs_insert_node(): ino = %u, version = %u, "
-                 "name = \"%s\"\n",
+                 "name = \"%s\", deleted = %d\n",
                  raw_inode->ino, raw_inode->version,
-                 ((name && *name) ? name : "")));
+                 ((name && *name) ? name : ""), raw_inode->deleted));
 
        /* If there doesn't exist an associated jffs_file, then
           create, initialize and insert one into the file system.  */
@@ -908,7 +968,6 @@ jffs_insert_node(struct jffs_control *c, struct jffs_file *f,
                jffs_insert_file_into_hash(f);
                insert_into_tree = 1;
        }
-
        node->ino = raw_inode->ino;
        node->version = raw_inode->version;
        node->data_size = raw_inode->dsize;
@@ -1345,18 +1404,30 @@ jffs_write_dummy_node(struct jffs_control *c, struct jffs_fm *dirty_fm)
 int
 jffs_write_node(struct jffs_control *c, struct jffs_node *node,
                struct jffs_raw_inode *raw_inode,
-               const char *name, const unsigned char *data)
+               const char *name, const unsigned char *data,
+               int recoverable,
+               struct jffs_file *f)
 {
        struct jffs_fmcontrol *fmc = c->fmc;
        struct jffs_fm *fm = NULL;
        __u32 pos;
        int err;
+       __u32 slack = 0;
+
        __u32 total_name_size = raw_inode->nsize
                                + JFFS_GET_PAD_BYTES(raw_inode->nsize);
        __u32 total_data_size = raw_inode->dsize
                                + JFFS_GET_PAD_BYTES(raw_inode->dsize);
        __u32 total_size = sizeof(struct jffs_raw_inode)
                           + total_name_size + total_data_size;
+       
+       /* If this node isn't something that will eventually let
+          GC free even more space, then don't allow it unless
+          there's at least max_chunk_size space still available
+       */
+       if (!recoverable)
+               slack = fmc->max_chunk_size;
+               
 
        /* Fire the retrorockets and shoot the fruiton torpedoes, sir!  */
 
@@ -1371,14 +1442,22 @@ jffs_write_node(struct jffs_control *c, struct jffs_node *node,
        });
 
        D1(printk("jffs_write_node(): filename = \"%s\", ino = %u, "
-                 "version = %u, total_size = %u\n",
+                 "total_size = %u\n",
                  (name ? name : ""), raw_inode->ino,
-                 raw_inode->version, total_size));
+                 total_size));
 
        jffs_fm_write_lock(fmc);
 
        while (!fm) {
 
+               /* Deadlocks suck. */
+               while(fmc->free_size < fmc->min_free_size + total_size + slack) {
+                       jffs_fm_write_unlock(fmc);
+                       if (!JFFS_ENOUGH_SPACE(c, total_size + slack))
+                               return -ENOSPC;
+                       jffs_fm_write_lock(fmc);
+               }
+
                /* First try to allocate some flash memory.  */
                err = jffs_fmalloc(fmc, total_size, node, &fm);
                
@@ -1431,6 +1510,15 @@ jffs_write_node(struct jffs_control *c, struct jffs_node *node,
 
        pos = node->fm->offset;
 
+       /* Increment the version number here. We can't let the caller
+          set it beforehand, because we might have had to do GC on a node
+          of this file - and we'd end up reusing version numbers.
+       */
+       if (f) {
+               raw_inode->version = f->highest_version + 1;
+               D1(printk (KERN_NOTICE "jffs_write_node(): setting version of %s to %d\n", f->name, raw_inode->version));
+       }
+
        /* Compute the checksum for the data and name chunks.  */
        raw_inode->dchksum = jffs_checksum(data, raw_inode->dsize);
        raw_inode->nchksum = jffs_checksum(name, raw_inode->nsize);
@@ -1496,8 +1584,9 @@ jffs_write_node(struct jffs_control *c, struct jffs_node *node,
    shouldn't be read again.  'max_size' is how much space there is in
    the buffer.  */
 static int
-jffs_get_node_data(struct jffs_file *f, struct jffs_node *node, char *buf,
-                  __u32 node_offset, __u32 max_size, kdev_t dev)
+jffs_get_node_data(struct jffs_file *f, struct jffs_node *node, 
+                  unsigned char *buf,__u32 node_offset, __u32 max_size,
+                  kdev_t dev)
 {
        struct jffs_fmcontrol *fmc = f->c->fmc;
        __u32 pos = node->fm->offset + node->fm_offset + node_offset;
@@ -1521,14 +1610,15 @@ jffs_get_node_data(struct jffs_file *f, struct jffs_node *node, char *buf,
 /* Read data from the file's nodes.  Write the data to the buffer
    'buf'.  'read_offset' tells how much data we should skip.  */
 int
-jffs_read_data(struct jffs_file *f, char *buf, __u32 read_offset, __u32 size)
+jffs_read_data(struct jffs_file *f, unsigned char *buf, __u32 read_offset,
+              __u32 size)
 {
        struct jffs_node *node;
        __u32 read_data = 0; /* Total amount of read data.  */
        __u32 node_offset = 0;
        __u32 pos = 0; /* Number of bytes traversed.  */
 
-       D1(printk("jffs_read_data(): file = \"%s\", read_offset = %d, "
+       D2(printk("jffs_read_data(): file = \"%s\", read_offset = %d, "
                  "size = %u\n",
                  (f->name ? f->name : ""), read_offset, size));
 
@@ -1842,7 +1932,21 @@ jffs_delete_data(struct jffs_file *f, struct jffs_node *node)
                n = n->range_next;
        }
 
-       f->size -= node->removed_size;
+       if (node->removed_size > (f->size - node->data_offset)) {
+               /* It's possible that the removed_size is in fact
+                * greater than the amount of data we actually thought
+                * were present in the first place - some of the nodes 
+                * which this node originally obsoleted may already have
+                * been deleted from the flash by subsequent garbage 
+                * collection.
+                *
+                * If this is the case, don't let f->size go negative.
+                * Bad things would happen :)
+                */
+               f->size = node->data_offset;
+       } else {
+               f->size -= node->removed_size;
+       }
        D3(printk("jffs_delete_data(): f->size = %d\n", f->size));
        return 0;
 } /* jffs_delete_data()  */
@@ -1881,7 +1985,7 @@ jffs_insert_data(struct jffs_file *f, struct jffs_node *node)
                /* Find the correct place for the insertion and then insert
                   the node.  */
                for (n = f->range_head; n; n = n->range_next) {
-                       D1(printk("Cool stuff's happening!\n"));
+                       D2(printk("Cool stuff's happening!\n"));
 
                        if (n->data_offset == node->data_offset) {
                                node->range_prev = n->range_prev;
@@ -2223,7 +2327,7 @@ jffs_rewrite_data(struct jffs_file *f, struct jffs_node *node, int size)
        int err;
 
        D1(printk("***jffs_rewrite_data(): node: %u, name: \"%s\", size: %u\n",
-                 f->ino, (f->name ? f->name : ""), size));
+                 f->ino, (f->name ? f->name : "(null)"), size));
 
        /* Create and initialize the new node.  */
        if (!(new_node = (struct jffs_node *)
@@ -2235,8 +2339,8 @@ jffs_rewrite_data(struct jffs_file *f, struct jffs_node *node, int size)
        DJM(no_jffs_node++);
        new_node->data_offset = node->data_offset;
        new_node->removed_size = size;
-       total_name_size = f->nsize + JFFS_GET_PAD_BYTES(f->nsize);
-       total_data_size = size + JFFS_GET_PAD_BYTES(size);
+       total_name_size = JFFS_PAD(f->nsize);
+       total_data_size = JFFS_PAD(size);
        total_size = sizeof(struct jffs_raw_inode)
                     + total_name_size + total_data_size;
        new_node->fm_offset = sizeof(struct jffs_raw_inode)
@@ -2252,31 +2356,24 @@ jffs_rewrite_data(struct jffs_file *f, struct jffs_node *node, int size)
                return err;
        }
        else if (!fm->nodes) {
-               /* The jffs_fm struct that we got is not good enough.  */
+               /* The jffs_fm struct that we got is not big enough.  */
+               /* This should never happen, because we deal with this case
+                  in jffs_garbage_collect_next().*/
+               printk(KERN_WARNING "jffs_rewrite_data(): Allocated node is too small (%d bytes of %d)\n", fm->size, total_size);
                if ((err = jffs_write_dummy_node(c, fm)) < 0) {
-                       DJM(no_jffs_fm--);
-                       jffs_fm_write_unlock(fmc);
                        D(printk("jffs_rewrite_data(): "
                                 "jffs_write_dummy_node() Failed!\n"));
-                       kfree(fm);
-                       return err;
-               }
-               /* Get a new one.  */
-               if ((err = jffs_fmalloc(fmc, total_size, node, &fm)) < 0) {
-                       jffs_fm_write_unlock(fmc);
-                       D(printk("jffs_rewrite_data(): Second "
-                                "jffs_fmalloc(0x%p, %u) failed!\n",
-                                fmc, total_size));
-                       return err;
+               } else {
+                       err = -ENOSPC;
                }
+               DJM(no_jffs_fm--);
+               jffs_fm_write_unlock(fmc);
+               kfree(fm);
+               
+               return err;
        }
        new_node->fm = fm;
 
-       ASSERT(if (new_node->fm->nodes == 0) {
-               printk(KERN_ERR "jffs_rewrite_data(): "
-                      "new_node->fm->nodes == 0\n");
-       });
-
        /* Initialize the raw inode.  */
        raw_inode.magic = JFFS_MAGIC_BITMASK;
        raw_inode.ino = f->ino;
@@ -2418,10 +2515,11 @@ jffs_garbage_collect_next(struct jffs_control *c)
        struct jffs_fmcontrol *fmc = c->fmc;
        struct jffs_node *node;
        struct jffs_file *f;
-       int size;
+       int size, err = 0;
        int data_size;
        int total_name_size;
-       int free_size = fmc->flash_size - (fmc->used_size + fmc->dirty_size);
+       __u32 extra_available;
+       __u32 space_needed;
        __u32 free_chunk_size1 = jffs_free_size1(fmc);
        D2(__u32 free_chunk_size2 = jffs_free_size2(fmc));
 
@@ -2430,47 +2528,64 @@ jffs_garbage_collect_next(struct jffs_control *c)
        ASSERT(if (!node) {
                printk(KERN_ERR "JFFS: jffs_garbage_collect_next: "
                       "No oldest node found!\n");
-               return -1;
+                err = -1;
+                goto jffs_garbage_collect_next_end;
+               
+
        });
 
        /* Find its corresponding file too.  */
        f = jffs_find_file(c, node->ino);
-       ASSERT(if (!f) {
-               printk(KERN_ERR "JFFS: jffs_garbage_collect_next: "
-                      "No file to garbage collect! "
-                      "(ino = 0x%08x)\n", node->ino);
-               return -1;
-       });
+
+       if (!f) {
+         printk (KERN_ERR "JFFS: jffs_garbage_collect_next: "
+                  "No file to garbage collect! "
+                 "(ino = 0x%08x)\n", node->ino);
+          /* FIXME: Free the offending node and recover. */
+          err = -1;
+          goto jffs_garbage_collect_next_end;
+       }
+
+       /* We always write out the name. Theoretically, we don't need
+          to, but for now it's easier - because otherwise we'd have
+          to keep track of how many times the current name exists on
+          the flash and make sure it never reaches zero.
+
+          The current approach means that would be possible to cause
+          the GC to end up eating its tail by writing lots of nodes
+          with no name for it to garbage-collect. Hence the change in
+          inode.c to write names with _every_ node.
+
+          It sucks, but it _should_ work.
+       */
+       total_name_size = JFFS_PAD(f->nsize);
 
        D1(printk("jffs_garbage_collect_next(): \"%s\", "
-                 "ino: %u, version: %u\n",
-                 (f->name ? f->name : ""), node->ino, node->version));
+                 "ino: %u, version: %u, location 0x%x, dsize %u\n",
+                 (f->name ? f->name : ""), node->ino, node->version, 
+                 node->fm->offset, node->data_size));
 
-       /* Compute how much we want to rewrite at the moment.  */
+       /* Compute how many data it's possible to rewrite at the moment.  */
        data_size = f->size - node->data_offset;
-       total_name_size = f->nsize + JFFS_GET_PAD_BYTES(f->nsize);
+
+       /* And from that, the total size of the chunk we want to write */
        size = sizeof(struct jffs_raw_inode) + total_name_size
               + data_size + JFFS_GET_PAD_BYTES(data_size);
 
-       D2(printk("  total_name_size: %u\n", total_name_size));
-       D2(printk("  data_size: %u\n", data_size));
-       D2(printk("  size: %u\n", size));
-       D2(printk("  f->nsize: %u\n", f->nsize));
-       D2(printk("  f->size: %u\n", f->size));
-       D2(printk("  node->data_offset: %u\n", node->data_offset));
-       D2(printk("  free_chunk_size1: %u\n", free_chunk_size1));
-       D2(printk("  free_chunk_size2: %u\n", free_chunk_size2));
-       D2(printk("  node->fm->offset: 0x%08x\n", node->fm->offset));
-
+       /* If that's more than max_chunk_size, reduce it accordingly */
        if (size > fmc->max_chunk_size) {
                size = fmc->max_chunk_size;
                data_size = size - sizeof(struct jffs_raw_inode)
                            - total_name_size;
        }
+
+       /* If we're asking to take up more space than free_chunk_size1
+          but we _could_ fit in it, shrink accordingly.
+       */
        if (size > free_chunk_size1) {
 
                if (free_chunk_size1 <
-                   (sizeof(struct jffs_raw_inode) + f->nsize + BLOCK_SIZE)) {
+                   (sizeof(struct jffs_raw_inode) + total_name_size + BLOCK_SIZE)){
                        /* The space left is too small to be of any
                           use really.  */
                        struct jffs_fm *dirty_fm
@@ -2482,32 +2597,81 @@ jffs_garbage_collect_next(struct jffs_control *c)
                                       "jffs_garbage_collect_next: "
                                       "Failed to allocate `dirty' "
                                       "flash memory!\n");
-                               return -1;
+                               err = -1;
+                                goto jffs_garbage_collect_next_end;
                        }
+                       D1(printk("Dirtying end of flash - too small\n"));
                        jffs_write_dummy_node(c, dirty_fm);
+                        err = 0;
                        goto jffs_garbage_collect_next_end;
                }
+               D1(printk("Reducing size of new node from %d to %d to avoid "
+                         " exceeding free_chunk_size1\n",
+                         size, free_chunk_size1));
 
                size = free_chunk_size1;
                data_size = size - sizeof(struct jffs_raw_inode)
                            - total_name_size;
        }
 
-       D2(printk("  size: %u (again)\n", size));
 
-       if (free_size - size < fmc->sector_size) {
-               /* Just rewrite that node (or even less).  */
-               jffs_rewrite_data(f, node,
-                                 jffs_min(node->data_size, data_size));
-       }
-       else {
-               size -= (sizeof(struct jffs_raw_inode) + f->nsize);
-               jffs_rewrite_data(f, node, data_size);
-       }
+       /* Calculate the amount of space needed to hold the nodes
+          which are remaining in the tail */
+       space_needed = fmc->min_free_size - (node->fm->offset % fmc->sector_size);
+
+       /* From that, calculate how much 'extra' space we can use to
+          increase the size of the node we're writing from the size
+          of the node we're obsoleting
+       */
+       if (space_needed > fmc->free_size) {
+               /* If we've gone below min_free_size for some reason,
+                  don't fuck up. This is why we have 
+                  min_free_size > sector_size. Whinge about it though,
+                  just so I can convince myself my maths is right.
+               */
+               D1(printk(KERN_WARNING "jffs_garbage_collect_next(): "
+                         "space_needed %d exceeded free_size %d\n",
+                         space_needed, fmc->free_size));
+               extra_available = 0;
+       } else {
+               extra_available = fmc->free_size - space_needed;
+       }
+
+       /* Check that we don't use up any more 'extra' space than
+          what's available */
+       if (size > JFFS_PAD(node->data_size) + total_name_size + 
+           sizeof(struct jffs_raw_inode) + extra_available) {
+               D1(printk("Reducing size of new node from %d to %ld to avoid "
+                      "catching our tail\n", size, 
+                         JFFS_PAD(node->data_size) + JFFS_PAD(node->name_size) + 
+                         sizeof(struct jffs_raw_inode) + extra_available));
+               D1(printk("space_needed = %d, extra_available = %d\n", 
+                         space_needed, extra_available));
+
+               size = JFFS_PAD(node->data_size) + total_name_size + 
+                 sizeof(struct jffs_raw_inode) + extra_available;
+               data_size = size - sizeof(struct jffs_raw_inode)
+                       - total_name_size;
+       };
 
+       D2(printk("  total_name_size: %u\n", total_name_size));
+       D2(printk("  data_size: %u\n", data_size));
+       D2(printk("  size: %u\n", size));
+       D2(printk("  f->nsize: %u\n", f->nsize));
+       D2(printk("  f->size: %u\n", f->size));
+       D2(printk("  node->data_offset: %u\n", node->data_offset));
+       D2(printk("  free_chunk_size1: %u\n", free_chunk_size1));
+       D2(printk("  free_chunk_size2: %u\n", free_chunk_size2));
+       D2(printk("  node->fm->offset: 0x%08x\n", node->fm->offset));
+
+       if ((err = jffs_rewrite_data(f, node, data_size))) {
+               printk(KERN_WARNING "jffs_rewrite_data() failed: %d\n", err);
+               return err;
+       }
+         
 jffs_garbage_collect_next_end:
        D3(printk("jffs_garbage_collect_next: Leaving...\n"));
-       return 0;
+       return err;
 } /* jffs_garbage_collect_next */
 
 
@@ -2683,75 +2847,75 @@ jffs_try_to_erase(struct jffs_control *c)
    for exemple).  Of course there is a limit on how intelligent this garbage
    collection can be.  */
 
+
 int
 jffs_garbage_collect_now(struct jffs_control *c)
 {
        struct jffs_fmcontrol *fmc = c->fmc;
-       long erased_total = 0;
-       long erased;
+       long erased = 0;
        int result = 0;
        D1(int i = 1);
-       D2(printk("***jffs_garbage_collect_now(): fmc->dirty_size = %u\n",
-                 fmc->dirty_size));
+       D2(printk("***jffs_garbage_collect_now(): fmc->dirty_size = %u, fmc->free_size = 0x%x\n, fcs1=0x%x, fcs2=0x%x",
+                 fmc->dirty_size, fmc->free_size, jffs_free_size1(fmc), jffs_free_size2(fmc)));
        D2(jffs_print_fmcontrol(fmc));
 
-       down(&fmc->gclock);
+       //      down(&fmc->gclock);
 
        /* If it is possible to garbage collect, do so.  */
-
-       if (fmc->dirty_size >= fmc->sector_size) {
-
+       
+       while (erased == 0) {
                D1(printk("***jffs_garbage_collect_now(): round #%u, "
-                        "fmc->dirty_size = %u\n", i++, fmc->dirty_size));
+                         "fmc->dirty_size = %u\n", i++, fmc->dirty_size));
                D2(jffs_print_fmcontrol(fmc));
 
-               /* At least one sector should be able to free now.  */
                if ((erased = jffs_try_to_erase(c)) < 0) {
                        printk(KERN_WARNING "JFFS: Error in "
                               "garbage collector.\n");
                        result = erased;
                        goto gc_end;
                }
-               else if (erased == 0) {
-                       __u32 free_size = fmc->flash_size
-                                         - (fmc->used_size
-                                            + fmc->dirty_size);
-
-                       if (free_size > 0) {
-                               /* Let's dare to make a garbage collect.  */
-                               if ((result = jffs_garbage_collect_next(c))
-                                   < 0) {
-                                       printk(KERN_ERR "JFFS: Something "
-                                              "has gone seriously wrong "
-                                              "with a garbage collect.\n");
-                                       goto gc_end;
-                               }
-                       }
-                       else {
-                               /* What should we do here?  */
-                               D(printk("   jffs_garbage_collect_now(): "
-                                        "erased: %ld, free_size: %u\n",
-                                        erased, free_size));
-                               result = -1;
-                               goto gc_end;
-                       }
+               if (erased)
+                       break;
+               
+               if (fmc->free_size == 0) {
+                       /* Argh */
+                       printk(KERN_ERR "jffs_garbage_collect_now(): free_size == 0. This is BAD.\n");
+                       result = -ENOSPC;
+                       break;
+               }
+
+               if (fmc->dirty_size < fmc->sector_size) {
+                       /* Actually, we _may_ have been able to free some, 
+                        * if there are many overlapping nodes which aren't
+                        * actually marked dirty because they still have
+                        * some valid data in each.
+                        */
+                       result = -ENOSPC;
+                       break;
+               }
+
+               /* Let's dare to make a garbage collect.  */
+               if ((result = jffs_garbage_collect_next(c)) < 0) {
+                       printk(KERN_ERR "JFFS: Something "
+                              "has gone seriously wrong "
+                              "with a garbage collect.\n");
+                       goto gc_end;
                }
 
                D1(printk("   jffs_garbage_collect_now(): erased: %ld\n", erased));
-               erased_total += erased;
                DJM(jffs_print_memory_allocation_statistics());
        }
-
+       
 gc_end:
-       up(&fmc->gclock);
+       //      up(&fmc->gclock);
 
        D3(printk("   jffs_garbage_collect_now(): Leaving...\n"));
-       D1(if (erased_total) {
-               printk("erased_total = %ld\n", erased_total);
+       D1(if (erased) {
+               printk("jffs_g_c_now(): erased = %ld\n", erased);
                jffs_print_fmcontrol(fmc);
        });
 
-       if (!erased_total && !result)
+       if (!erased && !result)
                return -ENOSPC;
 
        return result;
@@ -2766,17 +2930,15 @@ gc_end:
 */
 static inline int thread_should_wake (struct jffs_control *c)
 {
-       __u32 nfree = c->fmc->flash_size - c->fmc->used_size - c->fmc->dirty_size;
-
        D1(printk (KERN_NOTICE "thread_should_wake(): free=%d, dirty=%d, blocksize=%d.\n",
-                  nfree, c->fmc->dirty_size, c->fmc->sector_size));
+                  c->fmc->free_size, c->fmc->dirty_size, c->fmc->sector_size));
 
        /* If there's not enough dirty space to free a block, there's no point. */
        if (c->fmc->dirty_size < c->fmc->sector_size)
                return 0;
 
        /* If there are fewer free bytes than the threshold, GC */
-       if (nfree < c->gc_minfree_threshold)
+       if (c->fmc->dirty_size < c->gc_minfree_threshold)
                return 1;
 
        /* If there are more dirty bytes than the threshold, GC */
@@ -2807,7 +2969,6 @@ jffs_garbage_collect_thread(void *ptr)
 {
         struct jffs_control *c = (struct jffs_control *) ptr;
        struct jffs_fmcontrol *fmc = c->fmc;
-       long erased_total = 0;
        long erased;
        int result = 0;
        D1(int i = 1);
@@ -2821,7 +2982,7 @@ jffs_garbage_collect_thread(void *ptr)
        current->pgrp = 1;
        init_MUTEX_LOCKED(&c->gc_thread_sem); /* barrier */ 
        spin_lock_irq(&current->sigmask_lock);
-       siginitsetinv (&current->blocked, sigmask(SIGHUP) | sigmask(SIGQUIT) | sigmask(SIGSTOP) | sigmask(SIGCONT));
+       siginitsetinv (&current->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
        recalc_sigpending(current);
        spin_unlock_irq(&current->sigmask_lock);
        strcpy(current->comm, "jffs_gcd");
@@ -2829,6 +2990,7 @@ jffs_garbage_collect_thread(void *ptr)
        D1(printk (KERN_NOTICE "jffs_garbage_collect_thread(): Starting infinite loop.\n"));
 
        for (;;) {
+
                /* See if we need to start gc.  If we don't, go to sleep.
                   
                   Current implementation is a BAD THING(tm).  If we try 
@@ -2836,7 +2998,7 @@ jffs_garbage_collect_thread(void *ptr)
                   for this thread to exit.  We need to arrange to send it a
                   sig before the umount process sleeps.
                */
-               
+
                if (!thread_should_wake(c))
                        set_current_state (TASK_INTERRUPTIBLE);
                
@@ -2844,7 +3006,7 @@ jffs_garbage_collect_thread(void *ptr)
                                       on immediately - we're a low priority 
                                       background task. */
 
-               /* Put_super will send a SIGQUIT and then wait on the sem. 
+               /* Put_super will send a SIGKILL and then wait on the sem. 
                 */
                while (signal_pending(current)) {
                        siginfo_t info;
@@ -2861,8 +3023,8 @@ jffs_garbage_collect_thread(void *ptr)
                                schedule();
                                break;
 
-                       case SIGQUIT:
-                               D1(printk("jffs_garbage_collect_thread(): SIGQUIT received.\n"));
+                       case SIGKILL:
+                               D1(printk("jffs_garbage_collect_thread(): SIGKILL received.\n"));
                                c->gc_task = NULL;
                                up(&c->gc_thread_sem);
                                unlock_kernel();
@@ -2872,69 +3034,44 @@ jffs_garbage_collect_thread(void *ptr)
 
 
                D1(printk (KERN_NOTICE "jffs_garbage_collect_thread(): collecting.\n"));
-//             printk (KERN_NOTICE "free=%d, dirty=%d, blocksize=%ld.\n", count_free_bytes(c), count_dirty_bytes(c), c->sb->s_blocksize);
 
-               D2(printk("***jffs_garbage_collect_thread(): fmc->dirty_size = %u\n",
-                         fmc->dirty_size));
-               D2(jffs_print_fmcontrol(fmc));
-               
                if (fmc->dirty_size < fmc->sector_size) {
-                       printk(KERN_WARNING "jffs_garbage_collect_thread with insufficient dirty space (0x%x)\n", fmc->dirty_size);
+                       D1(printk(KERN_WARNING "jffs_garbage_collect_thread with insufficient dirty space (0x%x)\n", fmc->dirty_size));
                        continue;
                }
 
-               down(&c->fmc->gclock);
-                       
+               D3(printk (KERN_NOTICE "g_c_thread(): down biglock\n"));
+               down(&fmc->biglock);
+               
                D1(printk("***jffs_garbage_collect_thread(): round #%u, "
                          "fmc->dirty_size = %u\n", i++, fmc->dirty_size));
                D2(jffs_print_fmcontrol(fmc));
-               
-               /* At least one sector should be able to free now.  */
+
                if ((erased = jffs_try_to_erase(c)) < 0) {
                        printk(KERN_WARNING "JFFS: Error in "
-                              "garbage collector.\n");
-                       result = erased;
+                              "garbage collector: %ld.\n", erased);
+               }
+
+               if (erased)
+                       goto gc_end;
+
+               if (fmc->free_size == 0) {
+                       /* Argh. Might as well commit suicide. */
+                       printk(KERN_ERR "jffs_garbage_collect_thread(): free_size == 0. This is BAD.\n");
+                       send_sig(SIGQUIT, c->gc_task, 1);
+                       // panic()
                        goto gc_end;
                }
-               else if (erased == 0) {
-                       __u32 free_size = fmc->flash_size
-                               - (fmc->used_size
-                                  + fmc->dirty_size);
-                       
-                       if (free_size > 0) {
-                               /* Let's dare to make a garbage collect.  */
-                               if ((result = jffs_garbage_collect_next(c))
-                                   < 0) {
-                                       printk(KERN_ERR "JFFS: Something "
-                                              "has gone seriously wrong "
-                                              "with a garbage collect.\n");
-                                       goto gc_end;
-                               }
-                       }
-                       else {
-                               /* What should we do here?  */
-                               D(printk("   jffs_garbage_collect(): "
-                                        "erased: %ld, free_size: %u\n",
-                                        erased, free_size));
-                               result = -1;
-                               goto gc_end;
-                       }
+               
+               /* Let's dare to make a garbage collect.  */
+               if ((result = jffs_garbage_collect_next(c)) < 0) {
+                       printk(KERN_ERR "JFFS: Something "
+                              "has gone seriously wrong "
+                              "with a garbage collect: %d\n", result);
                }
-
-               D1(printk("   jffs_garbage_collect(): erased: %ld\n", erased));
-               erased_total += erased;
-               DJM(jffs_print_memory_allocation_statistics());
-       
                
        gc_end:
-               up(&c->fmc->gclock);
-               
-               D3(printk("   jffs_garbage_collect(): Leaving...\n"));
-               D1(if (erased_total) {
-                       printk("erased_total = %ld\n", erased_total);
-                       jffs_print_fmcontrol(fmc);
-               });
-       
+               D3(printk (KERN_NOTICE "g_c_thread(): up biglock\n"));
+               up(&fmc->biglock);
        } /* for (;;) */
 } /* jffs_garbage_collect_thread() */
-
index d4638af201f51d1531c6911e4a2f4eef49808162..f10a994b4e06ffb41d355053fca991836f95acd8 100644 (file)
@@ -10,7 +10,7 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * $Id: intrep.h,v 1.6 2000/08/04 14:29:17 dwmw2 Exp $
+ * $Id: intrep.h,v 1.11 2000/08/17 22:46:46 bmatthews Exp $
  *
  */
 
@@ -46,8 +46,9 @@ int jffs_file_count(struct jffs_file *f);
 
 int jffs_write_node(struct jffs_control *c, struct jffs_node *node,
                    struct jffs_raw_inode *raw_inode,
-                   const char *name, const unsigned char *buf);
-int jffs_read_data(struct jffs_file *f, char *buf, __u32 read_offset, __u32 size);
+                   const char *name, const unsigned char *buf,
+                   int recoverable, struct jffs_file *f);
+int jffs_read_data(struct jffs_file *f, unsigned char *buf, __u32 read_offset, __u32 size);
 
 /* Garbage collection stuff.  */
 int jffs_garbage_collect_thread(void *c);
@@ -55,19 +56,22 @@ void jffs_garbage_collect_trigger(struct jffs_control *c);
 int jffs_garbage_collect_now(struct jffs_control *c);
 
 /* Is there enough space on the flash?  */
-static inline int JFFS_ENOUGH_SPACE(struct jffs_control *c)
+static inline int JFFS_ENOUGH_SPACE(struct jffs_control *c, __u32 space)
 {
        struct jffs_fmcontrol *fmc = c->fmc;
 
        while (1) {
                if ((fmc->flash_size - (fmc->used_size + fmc->dirty_size)) 
-                       >= fmc->min_free_size) {
+                       >= fmc->min_free_size + space) {
                        return 1;
                }
                if (fmc->dirty_size < fmc->sector_size)
                        return 0;
 
-               jffs_garbage_collect_now(c);
+               if (jffs_garbage_collect_now(c)) {
+                 D1(printk("JFFS_ENOUGH_SPACE: jffs_garbage_collect_now() failed.\n"));
+                 return 0;
+               }
        }
 }
 
index 3140b8a53bc0b615265c7d76db32c45e64e248bd..b9bbeb4a9386f34f292009127bf2a2df8a805d23 100644 (file)
@@ -10,7 +10,7 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * $Id: jffs_fm.c,v 1.14 2000/08/09 14:26:35 dwmw2 Exp $
+ * $Id: jffs_fm.c,v 1.18 2000/08/21 10:41:45 dwmw2 Exp $
  *
  * Ported to Linux 2.3.x and MTD:
  * Copyright (C) 2000  Alexander Larsson (alex@cendio.se), Cendio Systems AB
@@ -57,17 +57,26 @@ jffs_build_begin(struct jffs_control *c, kdev_t dev)
 
        fmc->used_size = 0;
        fmc->dirty_size = 0;
+       fmc->free_size = mtd->size;
        fmc->sector_size = mtd->erasesize;
        fmc->max_chunk_size = fmc->sector_size >> 1;
-       fmc->min_free_size = (fmc->sector_size << 1) - fmc->max_chunk_size;
+       /* min_free_size:
+          1 sector, obviously.
+          + 1 x max_chunk_size, for when a nodes overlaps the end of a sector
+          + 1 x max_chunk_size again, which ought to be enough to handle 
+                  the case where a rename causes a name to grow, and GC has
+                  to write out larger nodes than the ones it's obsoleting.
+                  We should fix it so it doesn't have to write the name
+                  _every_ time. Later.
+       */
+       fmc->min_free_size = fmc->sector_size << 1;
        fmc->mtd = mtd;
-       init_MUTEX(&fmc->gclock);
        fmc->c = c;
        fmc->head = 0;
        fmc->tail = 0;
        fmc->head_extra = 0;
        fmc->tail_extra = 0;
-       init_MUTEX(&fmc->wlock);
+       init_MUTEX(&fmc->biglock);
        return fmc;
 }
 
@@ -203,6 +212,11 @@ jffs_fmalloc(struct jffs_fmcontrol *fmc, __u32 size, struct jffs_node *node,
 
        free_chunk_size1 = jffs_free_size1(fmc);
        free_chunk_size2 = jffs_free_size2(fmc);
+       if (free_chunk_size1 + free_chunk_size2 != fmc->free_size) {
+               printk(KERN_WARNING "Free size accounting screwed\n");
+               printk(KERN_WARNING "free_chunk_size1 == 0x%x, free_chunk_size2 == 0x%x, fmc->free_size == 0x%x\n", free_chunk_size1, free_chunk_size2, fmc->free_size);
+       }
+
        D3(printk("jffs_fmalloc(): free_chunk_size1 = %u, "
                  "free_chunk_size2 = %u\n",
                  free_chunk_size1, free_chunk_size2));
@@ -240,6 +254,7 @@ jffs_fmalloc(struct jffs_fmcontrol *fmc, __u32 size, struct jffs_node *node,
                        fm->offset = fmc->flash_start;
                }
                fm->size = size;
+               fmc->free_size -= size;
                fmc->used_size += size;
        }
        else if (size > free_chunk_size2) {
@@ -253,6 +268,7 @@ jffs_fmalloc(struct jffs_fmcontrol *fmc, __u32 size, struct jffs_node *node,
                fm->offset = fmc->tail->offset + fmc->tail->size;
                fm->size = free_chunk_size1;
                fm->nodes = 0;
+               fmc->free_size -= fm->size;
                fmc->dirty_size += fm->size; /* Changed by simonk. This seemingly fixes a 
                                                bug that caused infinite garbage collection.
                                                It previously set fmc->dirty_size to size (which is the
@@ -380,10 +396,12 @@ jffs_fmalloced(struct jffs_fmcontrol *fmc, __u32 offset, __u32 size,
                fm->nodes->node = node;
                fm->nodes->next = 0;
                fmc->used_size += size;
+               fmc->free_size -= size;
        }
        else {
                /* If there is no node, then this is just a chunk of dirt.  */
                fmc->dirty_size += size;
+               fmc->free_size -= size;
        }
 
        if (fmc->head_extra) {
@@ -505,6 +523,7 @@ jffs_sync_erase(struct jffs_fmcontrol *fmc, int erased_size)
        });
 
        fmc->dirty_size -= erased_size;
+       fmc->free_size += erased_size;
 
        for (fm = fmc->head; fm && (erased_size > 0);) {
                if (erased_size >= fm->size) {
@@ -701,6 +720,7 @@ jffs_print_fmcontrol(struct jffs_fmcontrol *fmc)
        D(printk("        %u, /* flash_size  */\n", fmc->flash_size));
        D(printk("        %u, /* used_size  */\n", fmc->used_size));
        D(printk("        %u, /* dirty_size  */\n", fmc->dirty_size));
+       D(printk("        %u, /* free_size  */\n", fmc->free_size));
        D(printk("        %u, /* sector_size  */\n", fmc->sector_size));
        D(printk("        %u, /* min_free_size  */\n", fmc->min_free_size));
        D(printk("        %u, /* max_chunk_size  */\n", fmc->max_chunk_size));
index 82077d9d1ca6b94d3c5de96df77c93a33c81d21d..2bac0cb012d2b395d3a48f81080c561e412ea31b 100644 (file)
@@ -10,7 +10,7 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * $Id: jffs_fm.h,v 1.7 2000/08/08 09:10:39 dwmw2 Exp $
+ * $Id: jffs_fm.h,v 1.10 2000/08/17 15:42:44 dwmw2 Exp $
  *
  * Ported to Linux 2.3.x and MTD:
  * Copyright (C) 2000  Alexander Larsson (alex@cendio.se), Cendio Systems AB
@@ -62,7 +62,7 @@
 #define JFFS_GET_PAD_BYTES(size) ((JFFS_ALIGN_SIZE                     \
                                  - ((__u32)(size) % JFFS_ALIGN_SIZE)) \
                                  % JFFS_ALIGN_SIZE)
-
+#define JFFS_PAD(size) ( (size + (JFFS_ALIGN_SIZE-1)) & ~(JFFS_ALIGN_SIZE-1) )
 struct jffs_node_ref
 {
        struct jffs_node *node;
@@ -86,18 +86,18 @@ struct jffs_fmcontrol
        __u32 flash_size;
        __u32 used_size;
        __u32 dirty_size;
+       __u32 free_size;
        __u32 sector_size;
        __u32 min_free_size;  /* The minimum free space needed to be able
                                 to perform garbage collections.  */
        __u32 max_chunk_size; /* The maximum size of a chunk of data.  */
        struct mtd_info *mtd;
-       struct semaphore gclock;
        struct jffs_control *c;
        struct jffs_fm *head;
        struct jffs_fm *tail;
        struct jffs_fm *head_extra;
        struct jffs_fm *tail_extra;
-       struct semaphore wlock;  
+       struct semaphore biglock;
 };
 
 /* Notice the two members head_extra and tail_extra in the jffs_control
index 1c0f13e3be1056a4019d10e6902ddd61c9ff50af..eda3fe6af4214bd765f1dfc798493e3067b67f71 100644 (file)
@@ -342,7 +342,8 @@ ncp_d_validate(struct dentry *dentry)
                goto bad_addr;
        if ((dent_addr & ~align_mask) != dent_addr)
                goto bad_align;
-       if (!kern_addr_valid(dent_addr))
+       if ((!kern_addr_valid(dent_addr)) || (!kern_addr_valid(dent_addr -1 +
+                                               sizeof(struct dentry))))
                goto bad_addr;
        /*
         * Looks safe enough to dereference ...
index fe944bab6d79d4f6d2b4e68207359e75cc04a693..00c16769e0029c9dc42a5788d4f653848f30e53e 100644 (file)
@@ -4,8 +4,9 @@
  *     Modelled on fs/exec.c:aout_core_dump()
  *     Jeremy Fitzhardinge <jeremy@sw.oz.au>
  *     ELF version written by David Howells <David.Howells@nexor.co.uk>
- *     Modified and incorporated into 2.3.x by Tigran Aivazian <tigran@sco.com>
- *     Support to dump vmalloc'd areas (ELF only), Tigran Aivazian <tigran@sco.com>
+ *     Modified and incorporated into 2.3.x by Tigran Aivazian <tigran@veritas.com>
+ *     Support to dump vmalloc'd areas (ELF only), Tigran Aivazian <tigran@veritas.com>
+ *     Safe accesses to vmalloc/direct-mapped discontiguous areas, Kanoj Sarcar <kanoj@sgi.com>
  */
 
 #include <linux/config.h>
@@ -112,18 +113,17 @@ extern char saved_command_line[];
 
 static size_t get_kcore_size(int *num_vma, size_t *elf_buflen)
 {
-       size_t try, size = 0;
+       size_t try, size;
        struct vm_struct *m;
 
        *num_vma = 0;
+       size = ((size_t)high_memory - PAGE_OFFSET + PAGE_SIZE);
        if (!vmlist) {
                *elf_buflen = PAGE_SIZE;
-               return ((size_t)high_memory - PAGE_OFFSET + PAGE_SIZE);
+               return (size);
        }
 
        for (m=vmlist; m; m=m->next) {
-               if (m->flags & VM_IOREMAP) /* don't dump ioremap'd stuff! (TA) */
-                       continue;
                try = (size_t)m->addr + m->size;
                if (try > size)
                        size = try;
@@ -315,6 +315,7 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t
        size_t size, tsz;
        size_t elf_buflen;
        int num_vma;
+       unsigned long start;
 
        read_lock(&vmlist_lock);
        proc_root_kcore->size = size = get_kcore_size(&num_vma, &elf_buflen);
@@ -380,11 +381,77 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t
        }
 #endif
        /* fill the remainder of the buffer from kernel VM space */
-       if (copy_to_user(buffer, __va(*fpos - elf_buflen), buflen))
-               return -EFAULT;
+       start = (unsigned long)__va(*fpos - elf_buflen);
+       if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen)
+               tsz = buflen;
+               
+       while (buflen) {
+               if ((start >= VMALLOC_START) && (start < VMALLOC_END)) {
+                       char * elf_buf;
+                       struct vm_struct *m;
+                       unsigned long curstart = start;
+                       unsigned long cursize = tsz;
+
+                       elf_buf = kmalloc(tsz, GFP_KERNEL);
+                       if (!elf_buf)
+                               return -ENOMEM;
+                       memset(elf_buf, 0, tsz);
+
+                       read_lock(&vmlist_lock);
+                       for (m=vmlist; m && cursize; m=m->next) {
+                               unsigned long vmstart;
+                               unsigned long vmsize;
+                               unsigned long msize = m->size - PAGE_SIZE;
+
+                               if (((unsigned long)m->addr + msize) < 
+                                                               curstart)
+                                       continue;
+                               if ((unsigned long)m->addr > (curstart + 
+                                                               cursize))
+                                       break;
+                               vmstart = (curstart < (unsigned long)m->addr ? 
+                                       (unsigned long)m->addr : curstart);
+                               if (((unsigned long)m->addr + msize) > 
+                                                       (curstart + cursize))
+                                       vmsize = curstart + cursize - vmstart;
+                               else
+                                       vmsize = (unsigned long)m->addr + 
+                                                       msize - vmstart;
+                               curstart = vmstart + vmsize;
+                               cursize -= vmsize;
+                               /* don't dump ioremap'd stuff! (TA) */
+                               if (m->flags & VM_IOREMAP)
+                                       continue;
+                               memcpy(elf_buf + (vmstart - start),
+                                       (char *)vmstart, vmsize);
+                       }
+                       read_unlock(&vmlist_lock);
+                       if (copy_to_user(buffer, elf_buf, tsz)) {
+                               kfree(elf_buf);
+                               return -EFAULT;
+                       }
+                       kfree(elf_buf);
+               } else if ((start > PAGE_OFFSET) && (start < 
+                                               (unsigned long)high_memory)) {
+                       if (kern_addr_valid(start)) {
+                               if (copy_to_user(buffer, (char *)start, tsz))
+                                       return -EFAULT;
+                       } else {
+                               if (clear_user(buffer, tsz))
+                                       return -EFAULT;
+                       }
+               } else {
+                       if (clear_user(buffer, tsz))
+                               return -EFAULT;
+               }
+               buflen -= tsz;
+               *fpos += tsz;
+               buffer += tsz;
+               acc += tsz;
+               start += tsz;
+               tsz = (buflen > PAGE_SIZE ? PAGE_SIZE : buflen);
+       }
 
-       acc += buflen;
-       *fpos += buflen;
        return acc;
 }
 #endif /* CONFIG_KCORE_AOUT */
index 2956def6b33955c2f8706bd58fd51457944f51e5..c856efe54162440342a1c2f4ff3aaf94f80574b3 100644 (file)
@@ -79,6 +79,7 @@ struct mpc_config_bus
        unsigned char mpc_bustype[6] __attribute((packed));
 };
 
+/* List of Bus Type string values, Intel MP Spec. */
 #define BUSTYPE_EISA   "EISA"
 #define BUSTYPE_ISA    "ISA"
 #define BUSTYPE_INTERN "INTERN"        /* Internal BUS */
@@ -86,6 +87,17 @@ struct mpc_config_bus
 #define BUSTYPE_VL     "VL"            /* Local bus */
 #define BUSTYPE_PCI    "PCI"
 #define BUSTYPE_PCMCIA "PCMCIA"
+#define BUSTYPE_CBUS   "CBUS"
+#define BUSTYPE_CBUSII "CBUSII"
+#define BUSTYPE_FUTURE "FUTURE"
+#define BUSTYPE_MBI    "MBI"
+#define BUSTYPE_MBII   "MBII"
+#define BUSTYPE_MPI    "MPI"
+#define BUSTYPE_MPSA   "MPSA"
+#define BUSTYPE_NUBUS  "NUBUS"
+#define BUSTYPE_TC     "TC"
+#define BUSTYPE_VME    "VME"
+#define BUSTYPE_XPRESS "XPRESS"
 
 struct mpc_config_ioapic
 {
@@ -147,7 +159,7 @@ struct mpc_config_lintsrc
 #define MAX_IRQ_SOURCES 128
 #define MAX_MP_BUSSES 32
 enum mp_bustype {
-       MP_BUS_ISA,
+       MP_BUS_ISA = 1,
        MP_BUS_EISA,
        MP_BUS_PCI,
        MP_BUS_MCA
index 5d5b67ab2db038763f6dc6f4942bab2d1bd07718..a67aaf412b8d8fc47e386078b91854077c816652 100644 (file)
@@ -71,7 +71,8 @@ static inline int spin_trylock(spinlock_t *lock)
        __asm__ __volatile__(
                "xchgb %b0,%1"
                :"=q" (oldval), "=m" (__dummy_lock(lock))
-               :"0" (0));
+               :"0" (0)
+               :"memory");
        return oldval > 0;
 }
 
@@ -87,7 +88,8 @@ printk("eip: %p\n", &&here);
 #endif
        __asm__ __volatile__(
                spin_lock_string
-               :"=m" (__dummy_lock(lock)));
+               :"=m" (__dummy_lock(lock))
+               : :"memory");
 }
 
 extern inline void spin_unlock(spinlock_t *lock)
@@ -100,7 +102,8 @@ extern inline void spin_unlock(spinlock_t *lock)
 #endif
        __asm__ __volatile__(
                spin_unlock_string
-               :"=m" (__dummy_lock(lock)));
+               :"=m" (__dummy_lock(lock))
+               : :"memory");
 }
 
 /*
index dc29a13cdf9c193880c98bd184884d70c7e292ed..9e7f4a5b05a8a82ec03419d4cacf808642433ede 100644 (file)
@@ -18,8 +18,6 @@ typedef struct { int counter; } atomic_t;
 #endif
 
 #ifdef __KERNEL__
-#include <asm/system.h>
-#include <asm/psr.h>
 
 #ifndef CONFIG_SMP
 
index fc545894906858a46e8f52c1d555dac622a3c75c..ed50485d290a14852b60ec3d6424672d7ced84e8 100644 (file)
@@ -431,6 +431,7 @@ extern void sparcaudio_input_done(struct sparcaudio_driver *, int);
 extern int sparcaudio_init(void);
 extern int amd7930_init(void);
 extern int cs4231_init(void);
+extern int dbri_init(void);
 
 #endif
 
index 0c54061f9e486bf88917bb347f0d6bc9946e429f..5a84229264cfff5d6bb007c353ab776791453de7 100644 (file)
@@ -21,7 +21,7 @@
 #undef request_region
 #define release_region(X, Y)   do { } while(0)
 #define check_region(X, Y)     (0)
-#define request_region(X, Y, Z)        do { } while(0)
+#define request_region(X, Y, Z)        (1)
 
 /* References:
  * 1) Netbsd Sun floppy driver.
index f6504165d03ff4610d73b3dd145d14462d58548e..5f7040345f10c00f58c63ffcaeb8646d65a19540 100644 (file)
@@ -93,12 +93,6 @@ extern __inline__ void xc5(smpfunc_t func, unsigned long arg1, unsigned long arg
                           unsigned long arg3, unsigned long arg4, unsigned long arg5)
 { smp_cross_call(func, arg1, arg2, arg3, arg4, arg5); }
 
-extern __inline__ int smp_call_function(void (*func)(void *info), void *info, int nonatomic, int wait)
-{
-       xc1((smpfunc_t)func, (unsigned long)info);
-       return 0;
-}
-
 extern __volatile__ int __cpu_number_map[NR_CPUS];
 extern __volatile__ int __cpu_logical_map[NR_CPUS];
 extern unsigned long smp_proc_in_lock[NR_CPUS];
index bac6318ab6b19cf2dd83fcf8b613f5f7a46e043f..d46799b0cfddd1dd6160cb8c050e9731dd8e3c78 100644 (file)
@@ -376,7 +376,7 @@ extern int pgt_cache_water[2];
 extern int check_pgt_cache(void);
 
 extern void free_area_init(unsigned long * zones_size);
-extern void free_area_init_node(int nid, pg_data_t *pgdat, 
+extern void free_area_init_node(int nid, pg_data_t *pgdat, struct page *pmap,
        unsigned long * zones_size, unsigned long zone_start_paddr, 
        unsigned long *zholes_size);
 extern void mem_init(void);
index 61f672a3c0429bf660e7372146516b4ddd1675f3..5c318441db21be2165957ec1fc24c7332687ead6 100644 (file)
@@ -99,9 +99,11 @@ extern pg_data_t *pgdat_list;
  * The following two are not meant for general usage. They are here as
  * prototypes for the discontig memory code.
  */
+struct page;
 extern void show_free_areas_core(int);
 extern void free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap,
-  unsigned long *zones_size, unsigned long paddr, unsigned long *zholes_size);
+  unsigned long *zones_size, unsigned long paddr, unsigned long *zholes_size,
+  struct page *pmap);
 
 #ifndef CONFIG_DISCONTIGMEM
 
index ebe8428da0fa31afb45f954798da7733476c778f..95c0e130b41ce90c0a6307654682529073e8f974 100644 (file)
@@ -416,7 +416,6 @@ extern int          dev_alloc_name(struct net_device *dev, const char *name);
 extern int             dev_open(struct net_device *dev);
 extern int             dev_close(struct net_device *dev);
 extern int             dev_queue_xmit(struct sk_buff *skb);
-extern void            dev_loopback_xmit(struct sk_buff *skb);
 extern int             register_netdevice(struct net_device *dev);
 extern int             unregister_netdevice(struct net_device *dev);
 extern int             register_netdevice_notifier(struct notifier_block *nb);
index 33e2ee28ac61aa55beea37489ff7f02caa65a082..cf20a8bd6ed80cb189ab2b46504cb6a90bdc87a0 100644 (file)
@@ -10,6 +10,7 @@
 
 #ifdef CONFIG_SMP
 
+#include <linux/kernel.h>
 #include <asm/smp.h>
 
 /*
index 20536ca63912070d4a281a5c9139cfbaf3e7198a..650d1f058c686da0674826aa260169dafe410347 100644 (file)
@@ -94,12 +94,13 @@ struct ip_rt_acct
 
 extern struct ip_rt_acct *ip_rt_acct;
 
+struct in_device;
 extern void            ip_rt_init(void);
 extern void            ip_rt_redirect(u32 old_gw, u32 dst, u32 new_gw,
                                       u32 src, u8 tos, struct net_device *dev);
 extern void            ip_rt_advice(struct rtable **rp, int advice);
 extern void            rt_cache_flush(int how);
-extern int             ip_route_output(struct rtable **, u32 dst, u32 src, u32 tos, int oif);
+extern int             ip_route_output_key(struct rtable **, const struct rt_key *key);
 extern int             ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin);
 extern unsigned short  ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu);
 extern void            ip_rt_update_pmtu(struct dst_entry *dst, unsigned mtu);
@@ -111,6 +112,15 @@ extern int         ip_rt_ioctl(unsigned int cmd, void *arg);
 extern void            ip_rt_get_source(u8 *src, struct rtable *rt);
 extern int             ip_rt_dump(struct sk_buff *skb,  struct netlink_callback *cb);
 
+/* Deprecated: use ip_route_output_key directly */
+extern __inline__ int ip_route_output(struct rtable **rp,
+                                     u32 daddr, u32 saddr, u32 tos, int oif)
+{
+       struct rt_key key = { dst:daddr, src:saddr, oif:oif, tos:tos };
+
+       return ip_route_output_key(rp, &key);
+}
+
 
 extern __inline__ void ip_rt_put(struct rtable * rt)
 {
index 87f37c3ed9df445e8bd043ba6735f3566cf80bff..458a20a867c364b4e24e0064df1981e97f061169 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -1201,6 +1201,7 @@ asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
        int acc_mode;
        struct dentry *dentry;
        char   name[SHM_FMT_LEN+1];
+       void *user_addr;
 
        if (!shm_sb || (shmid % SEQ_MULTIPLIER) == zero_id)
                return -EINVAL;
@@ -1254,13 +1255,12 @@ asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
        if (IS_ERR (file))
                goto bad_file1;
        down(&current->mm->mmap_sem);
-       *raddr = do_mmap (file, addr, file->f_dentry->d_inode->i_size,
-                         prot, flags, 0);
+       user_addr = (void *) do_mmap (file, addr, file->f_dentry->d_inode->i_size, prot, flags, 0);
        up(&current->mm->mmap_sem);
-       if (IS_ERR(*raddr))
-               err = PTR_ERR(*raddr);
-       else
-               err = 0;
+       *raddr = (unsigned long) user_addr;
+       err = 0;
+       if (IS_ERR(user_addr))
+               err = PTR_ERR(user_addr);
        fput (file);
        return err;
 
index 9ab02a4cca2bc6a1eebbc83e2eadcaf7906831cc..1d5bbe5c236223f46d301c72bd9f2633464579aa 100644 (file)
@@ -44,8 +44,12 @@ repeat:
        if (write && (!pte_write(*pgtable) || !pte_dirty(*pgtable)))
                goto fault_in_page;
        page = pte_page(*pgtable);
-       if ((!VALID_PAGE(page)) || PageReserved(page))
-               return 0;
+
+       /* ZERO_PAGE is special: reads from it are ok even though it's marked reserved */
+       if (page != ZERO_PAGE(addr) || write) {
+               if ((!VALID_PAGE(page)) || PageReserved(page))
+                       return 0;
+       }
        flush_cache_page(vma, addr);
 
        if (write) {
index 750421a5b5209dac00a53e7d428eb9f8913be35f..9c59e3d3d29eae56251ea59721ce5130b276e120 100644 (file)
@@ -146,9 +146,40 @@ void invalidate_inode_pages(struct inode * inode)
        spin_unlock(&pagecache_lock);
 }
 
-/*
+static inline void truncate_partial_page(struct page *page, unsigned partial)
+{
+       memclear_highpage_flush(page, partial, PAGE_CACHE_SIZE-partial);
+                               
+       if (page->buffers)
+               block_flushpage(page, partial);
+
+}
+
+static inline void truncate_complete_page(struct page *page)
+{
+       if (!page->buffers || block_flushpage(page, 0))
+               lru_cache_del(page);
+
+       /*
+        * We remove the page from the page cache _after_ we have
+        * destroyed all buffer-cache references to it. Otherwise some
+        * other process might think this inode page is not in the
+        * page cache and creates a buffer-cache alias to it causing
+        * all sorts of fun problems ...  
+        */
+       ClearPageDirty(page);
+       remove_inode_page(page);
+       page_cache_release(page);
+}
+
+/**
+ * truncate_inode_pages - truncate *all* the pages from an offset
+ * @mapping: mapping to truncate
+ * @lstart: offset from with to truncate
+ *
  * Truncate the page cache at a set offset, removing the pages
  * that are beyond that offset (and zeroing out partial pages).
+ * If any page is locked we wait for it to become unlocked.
  */
 void truncate_inode_pages(struct address_space * mapping, loff_t lstart)
 {
@@ -168,11 +199,10 @@ repeat:
 
                page = list_entry(curr, struct page, list);
                curr = curr->next;
-
                offset = page->index;
 
-               /* page wholly truncated - free it */
-               if (offset >= start) {
+               /* Is one of the pages to truncate? */
+               if ((offset >= start) || (partial && (offset + 1) == start)) {
                        if (TryLockPage(page)) {
                                page_cache_get(page);
                                spin_unlock(&pagecache_lock);
@@ -183,23 +213,14 @@ repeat:
                        page_cache_get(page);
                        spin_unlock(&pagecache_lock);
 
-                       if (!page->buffers || block_flushpage(page, 0))
-                               lru_cache_del(page);
-
-                       /*
-                        * We remove the page from the page cache
-                        * _after_ we have destroyed all buffer-cache
-                        * references to it. Otherwise some other process
-                        * might think this inode page is not in the
-                        * page cache and creates a buffer-cache alias
-                        * to it causing all sorts of fun problems ...
-                        */
-                       remove_inode_page(page);
-                       ClearPageDirty(page);
+                       if (partial && (offset + 1) == start) {
+                               truncate_partial_page(page, partial);
+                               partial = 0;
+                       } else 
+                               truncate_complete_page(page);
 
                        UnlockPage(page);
                        page_cache_release(page);
-                       page_cache_release(page);
 
                        /*
                         * We have done things without the pagecache lock,
@@ -210,37 +231,6 @@ repeat:
                         */
                        goto repeat;
                }
-               /*
-                * there is only one partial page possible.
-                */
-               if (!partial)
-                       continue;
-
-               /* and it's the one preceeding the first wholly truncated page */
-               if ((offset + 1) != start)
-                       continue;
-
-               /* partial truncate, clear end of page */
-               if (TryLockPage(page)) {
-                       spin_unlock(&pagecache_lock);
-                       goto repeat;
-               }
-               page_cache_get(page);
-               spin_unlock(&pagecache_lock);
-
-               memclear_highpage_flush(page, partial, PAGE_CACHE_SIZE-partial);
-               if (page->buffers)
-                       block_flushpage(page, partial);
-
-               partial = 0;
-
-               /*
-                * we have dropped the spinlock so we have to
-                * restart.
-                */
-               UnlockPage(page);
-               page_cache_release(page);
-               goto repeat;
        }
        spin_unlock(&pagecache_lock);
 }
index bbe9ec6fb14974d481aeb93c33e445106315d553..06ad9ec63490c852d79d6161005bbc63091b8ba6 100644 (file)
--- a/mm/numa.c
+++ b/mm/numa.c
@@ -21,12 +21,12 @@ pg_data_t contig_page_data = { bdata: &contig_bootmem_data };
  * at a considerably higher value than 0. Examples are Super-H, ARM, m68k.
  * Should be invoked with paramters (0, 0, unsigned long *[], start_paddr).
  */
-void __init free_area_init_node(int nid, pg_data_t *pgdat, 
+void __init free_area_init_node(int nid, pg_data_t *pgdat, struct page *pmap,
        unsigned long *zones_size, unsigned long zone_start_paddr, 
        unsigned long *zholes_size)
 {
        free_area_init_core(0, NODE_DATA(0), &mem_map, zones_size, 
-                                               zone_start_paddr, zholes_size);
+                               zone_start_paddr, zholes_size, pmap);
 }
 
 #endif /* !CONFIG_DISCONTIGMEM */
@@ -55,7 +55,7 @@ void show_free_areas_node(int nid)
 /*
  * Nodes can be initialized parallely, in no particular order.
  */
-void __init free_area_init_node(int nid, pg_data_t *pgdat, 
+void __init free_area_init_node(int nid, pg_data_t *pgdat, struct page *pmap,
        unsigned long *zones_size, unsigned long zone_start_paddr, 
        unsigned long *zholes_size)
 {
@@ -66,7 +66,7 @@ void __init free_area_init_node(int nid, pg_data_t *pgdat,
                mem_map = (mem_map_t *)PAGE_OFFSET;
 
        free_area_init_core(nid, pgdat, &discard, zones_size, zone_start_paddr,
-                                               zholes_size);
+                                       zholes_size, pmap);
        pgdat->node_id = nid;
 
        /*
index 8b74a73db388db5e6f085056010ed7c9d9822f10..a7e93457a75cbf5bf63e7cbff25a03caad7c6fb5 100644 (file)
@@ -532,9 +532,9 @@ static inline void build_zonelists(pg_data_t *pgdat)
  */
 void __init free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap,
        unsigned long *zones_size, unsigned long zone_start_paddr, 
-       unsigned long *zholes_size)
+       unsigned long *zholes_size, struct page *lmem_map)
 {
-       struct page *p, *lmem_map;
+       struct page *p;
        unsigned long i, j;
        unsigned long map_size;
        unsigned long totalpages, offset, realtotalpages;
@@ -580,9 +580,11 @@ void __init free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap,
         * boundary, so that MAP_NR works.
         */
        map_size = (totalpages + 1)*sizeof(struct page);
-       lmem_map = (struct page *) alloc_bootmem_node(nid, map_size);
-       lmem_map = (struct page *)(PAGE_OFFSET + 
+       if (lmem_map == (struct page *)0) {
+               lmem_map = (struct page *) alloc_bootmem_node(nid, map_size);
+               lmem_map = (struct page *)(PAGE_OFFSET + 
                        MAP_ALIGN((unsigned long)lmem_map - PAGE_OFFSET));
+       }
        *gmap = pgdat->node_mem_map = lmem_map;
        pgdat->node_size = totalpages;
        pgdat->node_start_paddr = zone_start_paddr;
@@ -664,7 +666,7 @@ void __init free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap,
 
 void __init free_area_init(unsigned long *zones_size)
 {
-       free_area_init_core(0, NODE_DATA(0), &mem_map, zones_size, 0, 0);
+       free_area_init_core(0, NODE_DATA(0), &mem_map, zones_size, 0, 0, 0);
 }
 
 static int __init setup_mem_frac(char *str)
index a6ee7367aa6f558205e946de8446e1918a1436fd..c670dd521f872fce0f8ccdf55a6f617331a9d036 100644 (file)
@@ -868,25 +868,6 @@ void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
        br_read_unlock(BR_NETPROTO_LOCK);
 }
 
-/*
- *     Fast path for loopback frames.
- */
-void dev_loopback_xmit(struct sk_buff *skb)
-{
-       struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC);
-       if (newskb==NULL)
-               return;
-
-       newskb->mac.raw = newskb->data;
-       skb_pull(newskb, newskb->nh.raw - newskb->data);
-       newskb->pkt_type = PACKET_LOOPBACK;
-       newskb->ip_summed = CHECKSUM_UNNECESSARY;
-       if (newskb->dst==NULL)
-               printk(KERN_DEBUG "BUG: packet without dst looped back 1\n");
-       netif_rx(newskb);
-}
-
 /**
  *     dev_queue_xmit - transmit a buffer
  *     @skb: buffer to transmit
index 0af9ec321f83c20176ae86fded0986e2b2fc41d0..1d8002bdd818c39ab4d9c4d1c0948c6bc95867e8 100644 (file)
@@ -8,7 +8,7 @@
  *     the older version didn't come out right using gcc 2.5.8, the newer one
  *     seems to fall out with gcc 2.6.2.
  *
- *     Version: $Id: igmp.c,v 1.40 2000/07/26 01:04:16 davem Exp $
+ *     Version: $Id: igmp.c,v 1.41 2000/08/31 23:39:12 davem Exp $
  *
  *     Authors:
  *             Alan Cox <Alan.Cox@linux.org>
@@ -184,7 +184,10 @@ static void igmp_mod_timer(struct ip_mc_list *im, int max_delay)
 
 #define IGMP_SIZE (sizeof(struct igmphdr)+sizeof(struct iphdr)+4)
 
-static inline int igmp_send_report2(struct sk_buff *skb)
+/* Don't just hand NF_HOOK skb->dst->output, in case netfilter hook
+   changes route */
+static inline int
+output_maybe_reroute(struct sk_buff *skb)
 {
        return skb->dst->output(skb);
 }
@@ -247,7 +250,7 @@ static int igmp_send_report(struct net_device *dev, u32 group, int type)
        ih->csum=ip_compute_csum((void *)ih, sizeof(struct igmphdr));
 
        return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
-                      igmp_send_report2);
+                      output_maybe_reroute);
 }
 
 
index 3d0e2b4aa266bf9ac8181b371101e67d09b0e3be..05676789097402a99b8e8574dca4a71f610a6ca2 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             The Internet Protocol (IP) output module.
  *
- * Version:    $Id: ip_output.c,v 1.84 2000/08/25 02:15:47 davem Exp $
+ * Version:    $Id: ip_output.c,v 1.85 2000/08/31 23:39:12 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -107,42 +107,11 @@ static int ip_dev_loopback_xmit(struct sk_buff *newskb)
        return 0;
 }
 
-#ifdef CONFIG_NETFILTER
-/* To preserve the cute illusion that a locally-generated packet can
-   be mangled before routing, we actually reroute if a hook altered
-   the packet. -RR */
-static int route_me_harder(struct sk_buff *skb)
-{
-       struct iphdr *iph = skb->nh.iph;
-       struct rtable *rt;
-
-       if (ip_route_output(&rt, iph->daddr, iph->saddr,
-                           RT_TOS(iph->tos) | RTO_CONN,
-                           skb->sk ? skb->sk->bound_dev_if : 0)) {
-               printk("route_me_harder: No more route.\n");
-               return -EINVAL;
-       }
-
-       /* Drop old route. */
-       dst_release(skb->dst);
-
-       skb->dst = &rt->u.dst;
-       return 0;
-}
-#endif
-
-/* Do route recalc if netfilter changes skb. */
+/* Don't just hand NF_HOOK skb->dst->output, in case netfilter hook
+   changes route */
 static inline int
 output_maybe_reroute(struct sk_buff *skb)
 {
-#ifdef CONFIG_NETFILTER
-       if (skb->nfcache & NFC_ALTERED) {
-               if (route_me_harder(skb) != 0) {
-                       kfree_skb(skb);
-                       return -EINVAL;
-               }
-       }
-#endif
        return skb->dst->output(skb);
 }
 
@@ -312,25 +281,6 @@ static inline int ip_queue_xmit2(struct sk_buff *skb)
        struct net_device *dev;
        struct iphdr *iph = skb->nh.iph;
 
-#ifdef CONFIG_NETFILTER
-       /* BLUE-PEN-FOR-ALEXEY.  I don't understand; you mean I can't
-           hold the route as I pass the packet to userspace? -- RR
-
-          You may hold it, if you really hold it. F.e. if netfilter
-          does not destroy handed skb with skb->dst attached, it
-          will be held. When it was stored in info->arg, then
-          it was not held apparently. Now (without second arg) it is evident,
-          that it is clean.                               --ANK
-        */
-       if (rt==NULL || (skb->nfcache & NFC_ALTERED)) {
-               if (route_me_harder(skb) != 0) {
-                       kfree_skb(skb);
-                       return -EHOSTUNREACH;
-               }
-               rt = (struct rtable *)skb->dst;
-       }
-#endif
-
        dev = rt->u.dst.dev;
 
        /* This can happen when the transport layer has segments queued
index 3334a64c28da83a69f88e7ce803a9f0658c32371..c6de039e638fd7f347411f133f99e39fe72fb0f0 100644 (file)
@@ -161,6 +161,34 @@ ip_nat_out(unsigned int hooknum,
        return ip_nat_fn(hooknum, pskb, in, out, okfn);
 }
 
+/* FIXME: change in oif may mean change in hh_len.  Check and realloc
+   --RR */
+static int
+route_me_harder(struct sk_buff *skb)
+{
+       struct iphdr *iph = skb->nh.iph;
+       struct rtable *rt;
+       struct rt_key key = { dst:iph->daddr,
+                             src:iph->saddr,
+                             oif:skb->sk ? skb->sk->bound_dev_if : 0,
+                             tos:RT_TOS(iph->tos)|RTO_CONN,
+#ifdef CONFIG_IP_ROUTE_FWMARK
+                             fwmark:skb->nfmark
+#endif
+                           };
+
+       if (ip_route_output_key(&rt, &key) != 0) {
+               printk("route_me_harder: No more route.\n");
+               return -EINVAL;
+       }
+
+       /* Drop old route. */
+       dst_release(skb->dst);
+
+       skb->dst = &rt->u.dst;
+       return 0;
+}
+
 static unsigned int
 ip_nat_local_fn(unsigned int hooknum,
                struct sk_buff **pskb,
@@ -168,12 +196,23 @@ ip_nat_local_fn(unsigned int hooknum,
                const struct net_device *out,
                int (*okfn)(struct sk_buff *))
 {
+       u_int32_t saddr, daddr;
+       unsigned int ret;
+
        /* root is playing with raw sockets. */
        if ((*pskb)->len < sizeof(struct iphdr)
            || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
                return NF_ACCEPT;
 
-       return ip_nat_fn(hooknum, pskb, in, out, okfn);
+       saddr = (*pskb)->nh.iph->saddr;
+       daddr = (*pskb)->nh.iph->daddr;
+
+       ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
+       if (ret != NF_DROP && ret != NF_STOLEN
+           && ((*pskb)->nh.iph->saddr != saddr
+               || (*pskb)->nh.iph->daddr != daddr))
+               return route_me_harder(*pskb) == 0 ? ret : NF_DROP;
+       return ret;
 }
 
 /* We must be after connection tracking and before packet filtering. */
index cb9f18da317f9b122247074d5aff29fa2376276d..f58cd8b331e57126d2c1ac18b6734086ee0c9a2f 100644 (file)
@@ -5,6 +5,11 @@
  */
 #include <linux/module.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/route.h>
+#include <linux/ip.h>
 
 #define MANGLE_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))
 
@@ -86,6 +91,34 @@ ipt_hook(unsigned int hook,
        return ipt_do_table(pskb, hook, in, out, &packet_mangler, NULL);
 }
 
+/* FIXME: change in oif may mean change in hh_len.  Check and realloc
+   --RR */
+static int
+route_me_harder(struct sk_buff *skb)
+{
+       struct iphdr *iph = skb->nh.iph;
+       struct rtable *rt;
+       struct rt_key key = { dst:iph->daddr,
+                             src:iph->saddr,
+                             oif:skb->sk ? skb->sk->bound_dev_if : 0,
+                             tos:RT_TOS(iph->tos)|RTO_CONN,
+#ifdef CONFIG_IP_ROUTE_FWMARK
+                             fwmark:skb->nfmark
+#endif
+                           };
+
+       if (ip_route_output_key(&rt, &key) != 0) {
+               printk("route_me_harder: No more route.\n");
+               return -EINVAL;
+       }
+
+       /* Drop old route. */
+       dst_release(skb->dst);
+
+       skb->dst = &rt->u.dst;
+       return 0;
+}
+
 static unsigned int
 ipt_local_out_hook(unsigned int hook,
                   struct sk_buff **pskb,
@@ -93,6 +126,11 @@ ipt_local_out_hook(unsigned int hook,
                   const struct net_device *out,
                   int (*okfn)(struct sk_buff *))
 {
+       unsigned int ret;
+       u_int8_t tos;
+       u_int32_t saddr, daddr;
+       unsigned long nfmark;
+
        /* root is playing with raw sockets. */
        if ((*pskb)->len < sizeof(struct iphdr)
            || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
@@ -101,7 +139,22 @@ ipt_local_out_hook(unsigned int hook,
                return NF_ACCEPT;
        }
 
-       return ipt_do_table(pskb, hook, in, out, &packet_mangler, NULL);
+       /* Save things which could affect route */
+       nfmark = (*pskb)->nfmark;
+       saddr = (*pskb)->nh.iph->saddr;
+       daddr = (*pskb)->nh.iph->daddr;
+       tos = (*pskb)->nh.iph->tos;
+
+       ret = ipt_do_table(pskb, hook, in, out, &packet_mangler, NULL);
+       /* Reroute for ANY change. */
+       if (ret != NF_DROP && ret != NF_STOLEN
+           && ((*pskb)->nh.iph->saddr != saddr
+               || (*pskb)->nh.iph->daddr != daddr
+               || (*pskb)->nfmark != nfmark
+               || (*pskb)->nh.iph->tos != tos))
+               return route_me_harder(*pskb) == 0 ? ret : NF_DROP;
+
+       return ret;
 }
 
 static struct nf_hook_ops ipt_ops[]
index d4e9806a0ff2ce2110efefdd368a12f52cf8e799..4b7f0768fa4cae7f1c224af1c08e14e5ae6d6721 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             ROUTE - implementation of the IP router.
  *
- * Version:    $Id: route.c,v 1.89 2000/08/09 11:59:04 davem Exp $
+ * Version:    $Id: route.c,v 1.90 2000/08/31 23:39:12 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1610,7 +1610,7 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
  * Major route resolver routine.
  */
 
-int ip_route_output_slow(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int oif)
+int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
 {
        struct rt_key key;
        struct fib_result res;
@@ -1620,25 +1620,31 @@ int ip_route_output_slow(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int
        unsigned hash;
        int free_res = 0;
        int err;
+       u32 tos;
 
-       tos &= IPTOS_RT_MASK|RTO_ONLINK;
-       key.dst = daddr;
-       key.src = saddr;
+       tos = oldkey->tos & (IPTOS_RT_MASK|RTO_ONLINK);
+       key.dst = oldkey->dst;
+       key.src = oldkey->src;
        key.tos = tos&IPTOS_RT_MASK;
        key.iif = loopback_dev.ifindex;
-       key.oif = oif;
+       key.oif = oldkey->oif;
+#ifdef CONFIG_IP_ROUTE_FWMARK
+       key.fwmark = oldkey->fwmark;
+#endif
        key.scope = (tos&RTO_ONLINK) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
        res.fi = NULL;
 #ifdef CONFIG_IP_MULTIPLE_TABLES
        res.r = NULL;
 #endif
 
-       if (saddr) {
-               if (MULTICAST(saddr) || BADCLASS(saddr) || ZERONET(saddr))
+       if (oldkey->src) {
+               if (MULTICAST(oldkey->src)
+                   || BADCLASS(oldkey->src)
+                   || ZERONET(oldkey->src))
                        return -EINVAL;
 
                /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
-               dev_out = ip_dev_find(saddr);
+               dev_out = ip_dev_find(oldkey->src);
                if (dev_out == NULL)
                        return -EINVAL;
 
@@ -1650,8 +1656,8 @@ int ip_route_output_slow(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int
                      of another iface. --ANK
                 */
 
-               if (oif == 0 &&
-                       (MULTICAST(daddr) || daddr == 0xFFFFFFFF)) {
+               if (oldkey->oif == 0
+                   && (MULTICAST(oldkey->dst) || oldkey->dst == 0xFFFFFFFF)) {
                        /* Special hack: user can direct multicasts
                           and limited broadcast via necessary interface
                           without fiddling with IP_MULTICAST_IF or IP_PKTINFO.
@@ -1674,8 +1680,8 @@ int ip_route_output_slow(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int
                        dev_put(dev_out);
                dev_out = NULL;
        }
-       if (oif) {
-               dev_out = dev_get_by_index(oif);
+       if (oldkey->oif) {
+               dev_out = dev_get_by_index(oldkey->oif);
                if (dev_out == NULL)
                        return -ENODEV;
                if (__in_dev_get(dev_out) == NULL) {
@@ -1683,15 +1689,15 @@ int ip_route_output_slow(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int
                        return -ENODEV; /* Wrong error code */
                }
 
-               if (LOCAL_MCAST(daddr) || daddr == 0xFFFFFFFF) {
+               if (LOCAL_MCAST(oldkey->dst) || oldkey->dst == 0xFFFFFFFF) {
                        if (!key.src)
                                key.src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK);
                        goto make_route;
                }
                if (!key.src) {
-                       if (MULTICAST(daddr))
+                       if (MULTICAST(oldkey->dst))
                                key.src = inet_select_addr(dev_out, 0, key.scope);
-                       else if (!daddr)
+                       else if (!oldkey->dst)
                                key.src = inet_select_addr(dev_out, 0, RT_SCOPE_HOST);
                }
        }
@@ -1712,7 +1718,7 @@ int ip_route_output_slow(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int
 
        if (fib_lookup(&key, &res)) {
                res.fi = NULL;
-               if (oif) {
+               if (oldkey->oif) {
                        /* Apparently, routing tables are wrong. Assume,
                           that the destination is on link.
 
@@ -1800,7 +1806,7 @@ make_route:
        } else if (res.type == RTN_MULTICAST) {
                flags |= RTCF_MULTICAST|RTCF_LOCAL;
                read_lock(&inetdev_lock);
-               if (!__in_dev_get(dev_out) || !ip_check_mc(__in_dev_get(dev_out), daddr))
+               if (!__in_dev_get(dev_out) || !ip_check_mc(__in_dev_get(dev_out), oldkey->dst))
                        flags &= ~RTCF_LOCAL;
                read_unlock(&inetdev_lock);
                /* If multicast route do not exist use
@@ -1819,18 +1825,21 @@ make_route:
 
        atomic_set(&rth->u.dst.__refcnt, 1);
        rth->u.dst.flags= DST_HOST;
-       rth->key.dst    = daddr;
+       rth->key.dst    = oldkey->dst;
        rth->key.tos    = tos;
-       rth->key.src    = saddr;
+       rth->key.src    = oldkey->src;
        rth->key.iif    = 0;
-       rth->key.oif    = oif;
+       rth->key.oif    = oldkey->oif;
+#ifdef CONFIG_IP_ROUTE_FWMARK
+       rth->key.fwmark = oldkey->fwmark;
+#endif
        rth->rt_dst     = key.dst;
        rth->rt_src     = key.src;
 #ifdef CONFIG_IP_ROUTE_NAT
        rth->rt_dst_map = key.dst;
        rth->rt_src_map = key.src;
 #endif
-       rth->rt_iif     = oif ? : dev_out->ifindex;
+       rth->rt_iif     = oldkey->oif ? : dev_out->ifindex;
        rth->u.dst.dev  = dev_out;
        dev_hold(dev_out);
        rth->rt_gateway = key.dst;
@@ -1850,7 +1859,7 @@ make_route:
                if (res.type == RTN_MULTICAST) {
                        struct in_device *in_dev = in_dev_get(dev_out);
                        if (in_dev) {
-                               if (IN_DEV_MFORWARD(in_dev) && !LOCAL_MCAST(daddr)) {
+                               if (IN_DEV_MFORWARD(in_dev) && !LOCAL_MCAST(oldkey->dst)) {
                                        rth->u.dst.input = ip_mr_input;
                                        rth->u.dst.output = ip_mc_output;
                                }
@@ -1864,7 +1873,7 @@ make_route:
 
        rth->rt_flags = flags;
 
-       hash = rt_hash_code(daddr, saddr^(oif<<5), tos);
+       hash = rt_hash_code(oldkey->dst, oldkey->src^(oldkey->oif<<5), tos);
        err = rt_intern_hash(hash, rth, rp);
 done:
        if (free_res)
@@ -1881,21 +1890,24 @@ e_nobufs:
        goto done;
 }
 
-int ip_route_output(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int oif)
+int ip_route_output_key(struct rtable **rp, const struct rt_key *key)
 {
        unsigned hash;
        struct rtable *rth;
 
-       hash = rt_hash_code(daddr, saddr^(oif<<5), tos);
+       hash = rt_hash_code(key->dst, key->src^(key->oif<<5), key->tos);
 
        read_lock_bh(&rt_hash_table[hash].lock);
        for (rth=rt_hash_table[hash].chain; rth; rth=rth->u.rt_next) {
-               if (rth->key.dst == daddr &&
-                   rth->key.src == saddr &&
+               if (rth->key.dst == key->dst &&
+                   rth->key.src == key->src &&
                    rth->key.iif == 0 &&
-                   rth->key.oif == oif &&
-                   !((rth->key.tos^tos)&(IPTOS_RT_MASK|RTO_ONLINK)) &&
-                   ((tos&RTO_TPROXY) || !(rth->rt_flags&RTCF_TPROXY))
+                   rth->key.oif == key->oif &&
+#ifdef CONFIG_IP_ROUTE_FWMARK
+                   rth->key.fwmark == key->fwmark &&
+#endif
+                   !((rth->key.tos^key->tos)&(IPTOS_RT_MASK|RTO_ONLINK)) &&
+                   ((key->tos&RTO_TPROXY) || !(rth->rt_flags&RTCF_TPROXY))
                ) {
                        rth->u.dst.lastuse = jiffies;
                        dst_hold(&rth->u.dst);
@@ -1907,8 +1919,8 @@ int ip_route_output(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int oif)
        }
        read_unlock_bh(&rt_hash_table[hash].lock);
 
-       return ip_route_output_slow(rp, daddr, saddr, tos, oif);
-}
+       return ip_route_output_slow(rp, key);
+}      
 
 #ifdef CONFIG_RTNETLINK
 
index 4274045e875e7fc6e4b8d23c87b52fba83798922..187fbbc3b0f16450899eb975fb95b637e9780064 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
  *
- * $Id: sysctl_net_ipv4.c,v 1.44 2000/08/09 11:59:04 davem Exp $
+ * $Id: sysctl_net_ipv4.c,v 1.45 2000/09/06 23:30:29 davem Exp $
  *
  * Begun April 1, 1996, Mike Shaver.
  * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
@@ -213,8 +213,10 @@ ctl_table ipv4_table[] = {
         &sysctl_tcp_fack, sizeof(int), 0644, NULL, &proc_dointvec},
        {NET_TCP_REORDERING, "tcp_reordering",
         &sysctl_tcp_reordering, sizeof(int), 0644, NULL, &proc_dointvec},
+#ifdef CONFIG_INET_ECN
        {NET_TCP_ECN, "tcp_ecn",
         &sysctl_tcp_ecn, sizeof(int), 0644, NULL, &proc_dointvec},
+#endif
        {NET_TCP_DSACK, "tcp_dsack",
         &sysctl_tcp_dsack, sizeof(int), 0644, NULL, &proc_dointvec},
        {NET_TCP_MEM, "tcp_mem",
index 76791d724512796ef571acc81393288509e42197..ff40ffbf852f90a5f10368da4a801d94a211a818 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_input.c,v 1.198 2000/08/15 20:15:23 davem Exp $
+ * Version:    $Id: tcp_input.c,v 1.199 2000/09/06 23:30:29 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -73,7 +73,11 @@ int sysctl_tcp_window_scaling = 1;
 int sysctl_tcp_sack = 1;
 int sysctl_tcp_fack = 1;
 int sysctl_tcp_reordering = TCP_FASTRETRANS_THRESH;
+#ifdef CONFIG_INET_ECN
 int sysctl_tcp_ecn = 1;
+#else
+int sysctl_tcp_ecn = 0;
+#endif
 int sysctl_tcp_dsack = 1;
 int sysctl_tcp_app_win = 31;
 int sysctl_tcp_adv_win_scale = 2;
index cf39195c39a85975fb81f2602e986764fc87a70b..f8cf5e5f92ca25443bbb4586cf97c14254d09bb3 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_minisocks.c,v 1.2 2000/08/28 04:32:52 davem Exp $
+ * Version:    $Id: tcp_minisocks.c,v 1.3 2000/09/05 23:13:48 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -673,6 +673,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req,
                newsk->done = 0;
                newsk->proc = 0;
                newsk->backlog.head = newsk->backlog.tail = NULL;
+               newsk->callback_lock = RW_LOCK_UNLOCKED;
                skb_queue_head_init(&newsk->error_queue);
                newsk->write_space = tcp_write_space;
 #ifdef CONFIG_FILTER
index a7be82cbd1a7ddd2da739137282748ff4a2ef254..8579c5b2f94a4ae380b7601257c66ff4a36c3f91 100644 (file)
@@ -212,7 +212,7 @@ EXPORT_SYMBOL(br_ioctl_hook);
 EXPORT_SYMBOL(inetdev_lock);
 EXPORT_SYMBOL(inet_add_protocol);
 EXPORT_SYMBOL(inet_del_protocol);
-EXPORT_SYMBOL(ip_route_output);
+EXPORT_SYMBOL(ip_route_output_key);
 EXPORT_SYMBOL(ip_route_input);
 EXPORT_SYMBOL(icmp_send);
 EXPORT_SYMBOL(icmp_reply);
@@ -364,7 +364,6 @@ EXPORT_SYMBOL(tcp_cwnd_application_limited);
 EXPORT_SYMBOL(xrlim_allow);
 
 EXPORT_SYMBOL(tcp_write_xmit);
-EXPORT_SYMBOL(dev_loopback_xmit);
 
 EXPORT_SYMBOL(tcp_v4_remember_stamp);