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
----------------------------------------
@@ -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
@@ -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);
@@ -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.
@@ -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)
@@ -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
@@ -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);
}
* 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>
#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
@@ -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);
}
}
@@ -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)
@@ -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);
}
}
-# $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
-/* $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)
-/* $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);
-/* $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;
}
-/* $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
-/* $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;
}
-/* $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
@@ -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. */
+++ /dev/null
-/* 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;
-}
-/* $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);
@@ -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. */
}
}
@@ -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. */
}
}
-/* $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;
}
#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
-/* $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
-/* $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);
}
-/* $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)
-/* $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)
#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)
-/* $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;
}
-/* $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)
-/* $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
-/* $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
@@ -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);
}
-/* $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)
@@ -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.
@@ -5282,12+5285,6 @@ int register_serial(struct serial_struct *req) 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) &&
(rs_table[i].count == 0))
@@ -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 ();
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));
-/* $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;
}
@@ -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));
}
-
#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 },
@@ -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;
}
-/* $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;
}
@@ -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
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)
-/* $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;
#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 */
-
-/* $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
*/
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;
#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";
* 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);
#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>
*
* 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");
@@ -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
-
/* --------------------------------------------------------------------- */
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;
@@ -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();
}
* 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;
}
@@ -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__);
#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
@@ -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;
}
@@ -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>");
@@ -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
+
@@ -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
}
/* --------------------------------------------------------------------- */
* 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();
}
* 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;
*/
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(¤t->sigmask_lock);
- siginitsetinv (¤t->blocked, sigmask(SIGHUP) | sigmask(SIGQUIT) | sigmask(SIGSTOP) | sigmask(SIGCONT));
+ siginitsetinv (¤t->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
recalc_sigpending(current);
spin_unlock_irq(¤t->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() */
-
* 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;
+ }
}
}
* 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));
* 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
#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
@@ -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 ...
* 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 */
@@ -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
@@ -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");
}
/*
@@ -18,8+18,6 @@ typedef struct { int counter; } atomic_t; #endif
#ifdef __KERNEL__
-#include <asm/system.h>
-#include <asm/psr.h>
#ifndef CONFIG_SMP
@@ -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
#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.
@@ -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];
@@ -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);
@@ -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
@@ -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);
#ifdef CONFIG_SMP
+#include <linux/kernel.h>
#include <asm/smp.h>
/*
@@ -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)
{
@@ -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(¤t->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(¤t->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;
@@ -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) {
@@ -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);
}
@@ -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;
/*
@@ -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)
@@ -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
* 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);
}
*
* 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
@@ -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. */
*/
#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[]
*
* 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
/*
* 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",
*
* 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;
*
* 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
@@ -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);