summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-08-29 05:27:07 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-08-29 05:27:07 +0000
commita60c6812feb6ba35b5b8a9ee8a5ca3d01d1fcd5f (patch)
tree2290ff15f280314a063f3dfc523742c8934c4259
parent1a1d77dd589de5a567fa95e36aa6999c704ceca4 (diff)
Merge with Linux 2.4.0-test8-pre1.
-rw-r--r--Documentation/Configure.help2
-rw-r--r--Documentation/cachetlb.txt319
-rw-r--r--Makefile2
-rw-r--r--arch/i386/kernel/apic.c18
-rw-r--r--arch/i386/kernel/mca.c2
-rw-r--r--arch/sparc64/defconfig8
-rw-r--r--drivers/char/nvram.c10
-rw-r--r--drivers/char/pc_keyb.c16
-rw-r--r--drivers/char/stallion.c (renamed from drivers/media/video/stallion.c)0
-rw-r--r--drivers/scsi/esp.c9
-rw-r--r--drivers/scsi/qlogicpti.c1
-rw-r--r--drivers/sound/sound_core.c6
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/storage/Makefile81
-rw-r--r--drivers/usb/storage/debug.c4
-rw-r--r--drivers/usb/storage/debug.h4
-rw-r--r--drivers/usb/storage/dpcm.c5
-rw-r--r--drivers/usb/storage/dpcm.h4
-rw-r--r--drivers/usb/storage/freecom.c375
-rw-r--r--drivers/usb/storage/freecom.h35
-rw-r--r--drivers/usb/storage/protocol.c4
-rw-r--r--drivers/usb/storage/protocol.h4
-rw-r--r--drivers/usb/storage/scsiglue.c4
-rw-r--r--drivers/usb/storage/scsiglue.h4
-rw-r--r--drivers/usb/storage/sddr09.c176
-rw-r--r--drivers/usb/storage/sddr09.h16
-rw-r--r--drivers/usb/storage/shuttle_usbat.c10
-rw-r--r--drivers/usb/storage/shuttle_usbat.h5
-rw-r--r--drivers/usb/storage/transport.c86
-rw-r--r--drivers/usb/storage/transport.h10
-rw-r--r--drivers/usb/storage/usb.c173
-rw-r--r--drivers/usb/storage/usb.h4
-rw-r--r--fs/exec.c23
-rw-r--r--fs/ncpfs/ioctl.c11
-rw-r--r--fs/smbfs/inode.c2
-rw-r--r--fs/umsdos/emd.c4
-rw-r--r--include/linux/pagemap.h1
-rw-r--r--include/linux/sched.h9
-rw-r--r--include/linux/wait.h7
-rw-r--r--kernel/exit.c75
-rw-r--r--kernel/fork.c6
-rw-r--r--kernel/sched.c40
-rw-r--r--kernel/signal.c266
-rw-r--r--kernel/timer.c2
-rw-r--r--mm/bootmem.c2
-rw-r--r--mm/filemap.c3
-rw-r--r--net/ipv4/ip_gre.c6
-rw-r--r--net/ipv4/ip_output.c3
-rw-r--r--net/ipv4/ipip.c8
-rw-r--r--net/ipv6/sit.c8
-rw-r--r--net/packet/af_packet.c4
-rw-r--r--net/socket.c5
52 files changed, 1503 insertions, 381 deletions
diff --git a/Documentation/Configure.help b/Documentation/Configure.help
index b10ade9cd..153a6878e 100644
--- a/Documentation/Configure.help
+++ b/Documentation/Configure.help
@@ -2329,7 +2329,7 @@ CONFIG_AGP_VIA
AMD Irongate support
CONFIG_AGP_AMD
This option gives you AGP support for the GLX component of the
- XFree86 4.x on Intel AMD Irongate chipset.
+ XFree86 4.x on AMD Irongate chipset.
For the moment, you should probably say N, unless you want to test
the GLX component for XFree86 3.3.6, which can be downloaded from
diff --git a/Documentation/cachetlb.txt b/Documentation/cachetlb.txt
new file mode 100644
index 000000000..578dcb315
--- /dev/null
+++ b/Documentation/cachetlb.txt
@@ -0,0 +1,319 @@
+ Cache and TLB Flushing
+ Under Linux
+
+ David S. Miller <davem@redhat.com>
+
+This document describes the cache/tlb flushing interfaces called
+by the Linux VM subsystem. It enumerates over each interface,
+describes it's intended purpose, and what side effect is expected
+after the interface is invoked.
+
+The side effects described below are stated for a uniprocessor
+implementation, and what is to happen on that single processor. The
+SMP cases are a simple extension, in that you just extend the
+definition such that the side effect for a particular interface occurs
+on all processors in the system. Don't let this scare you into
+thinking SMP cache/tlb flushing must be so inefficient, this is in
+fact an area where many optimizations are possible. For example,
+if it can be proven that a user address space has never executed
+on a cpu (see vma->cpu_vm_mask), one need not perform a flush
+for this address space on that cpu.
+
+First, the TLB flushing interfaces, since they are the simplest. The
+"TLB" is abstracted under Linux as something the cpu uses to cache
+virtual-->physical address translations obtained from the software
+page tables. Meaning that if the software page tables change, it is
+possible for stale translations to exist in this "TLB" cache.
+Therefore when software page table changes occur, the kernel will
+invoke one of the following flush methods _after_ the page table
+changes occur:
+
+1) void flush_tlb_all(void)
+
+ The most severe flush of all. After this interface runs,
+ any previous page table modification whatsoever will be
+ visible to the cpu.
+
+ This is usually invoked when the kernel page tables are
+ changed, since such translations are "global" in nature.
+
+2) void flush_tlb_mm(struct mm_struct *mm)
+
+ This interface flushes an entire user address space from
+ the TLB. After running, this interface must make sure that
+ any previous page table modifications for the address space
+ 'mm' will be visible to the cpu. That is, after running,
+ there will be no entries in the TLB for 'mm'.
+
+ This interface is used to handle whole address space
+ page table operations such as what happens during
+ fork, exit, and exec.
+
+3) void flush_tlb_range(struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+
+ Here we are flushing a specific range of (user) virtual
+ address translations from the TLB. After running, this
+ interface must make sure that any previous page table
+ modifications for the address space 'mm' in the range 'start'
+ to 'end' will be visible to the cpu. That is, after running,
+ there will be no entries in the TLB for 'mm' for virtual
+ addresses in the range 'start' to 'end'.
+
+ Primarily, this is used for munmap() type operations.
+
+ The interface is provided in hopes that the port can find
+ a suitably efficient method for removing multiple page
+ sized translations from the TLB, instead of having the kernel
+ call flush_tlb_page (see below) for each entry which may be
+ modified.
+
+4) void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+
+ This time we need to remove the PAGE_SIZE sized translation
+ from the TLB. The 'vma' is the backing structure used by
+ Linux to keep track of mmap'd regions for a process, the
+ address space is available via vma->vm_mm. Also, one may
+ test (vma->vm_flags & VM_EXEC) to see if this region is
+ executable (and thus could be in the 'instruction TLB' in
+ split-tlb type setups).
+
+ After running, this interface must make sure that any previous
+ page table modification for address space 'vma->vm_mm' for
+ user virtual address 'page' will be visible to the cpu. That
+ is, after running, there will be no entries in the TLB for
+ 'vma->vm_mm' for virtual address 'page'.
+
+ This is used primarily during fault processing.
+
+5) void flush_tlb_pgtables(struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+
+ The software page tables for address space 'mm' for virtual
+ addresses in the range 'start' to 'end' are being torn down.
+
+ Some platforms cache the lowest level of the software page tables
+ in a linear virtually mapped array, to make TLB miss processing
+ more efficient. On such platforms, since the TLB is caching the
+ software page table structure, it needs to be flushed when parts
+ of the software page table tree are unlinked/freed.
+
+ Sparc64 is one example of a platform which does this.
+
+ Usually, when munmap()'ing an area of user virtual address
+ space, the kernel leaves the page table parts around and just
+ marks the individual pte's as invalid. However, if very large
+ portions of the address space are unmapped, the kernel frees up
+ those portions of the software page tables to prevent potential
+ excessive kernel memory usage caused by erratic mmap/mmunmap
+ sequences. It is at these times that flush_tlb_pgtables will
+ be invoked.
+
+6) void update_mmu_cache(struct vm_area_struct *vma,
+ unsigned long address, pte_t pte)
+
+ At the end of every page fault, this routine is invoked to
+ tell the architecture specific code that a translation
+ described by "pte" now exists at virtual address "address"
+ for address space "vma->vm_mm", in the software page tables.
+
+ A port may use this information in any way it so chooses.
+ For example, it could use this event to pre-load TLB
+ translations for software managed TLB configurations.
+ The sparc64 port currently does this.
+
+Next, we have the cache flushing interfaces. In general, when Linux
+is changing an existing virtual-->physical mapping to a new value,
+the sequence will be in one of the following forms:
+
+ 1) flush_cache_mm(mm);
+ change_all_page_tables_of(mm);
+ flush_tlb_mm(mm);
+
+ 2) flush_cache_range(mm, start, end);
+ change_range_of_page_tables(mm, start, end);
+ flush_tlb_range(mm, start, end);
+
+ 3) flush_cache_page(vma, page);
+ set_pte(pte_pointer, new_pte_val);
+ flush_tlb_page(vma, page);
+
+The cache level flush will always be first, because this allows
+us to properly handle systems whose caches are strict and require
+a virtual-->physical translation to exist for a virtual address
+when that virtual address is flushed from the cache. The HyperSparc
+cpu is one such cpu with this attribute.
+
+The cache flushing routines below need only deal with cache flushing
+to the extent that it is necessary for a particular cpu. Mostly,
+these routines must be implemented for cpus which have virtually
+indexed caches which must be flushed when virtual-->physical
+translations are changed or removed. So, for example, the physically
+indexed physically tagged caches of IA32 processors have no need to
+implement these interfaces since the caches are fully synchronized
+and have no dependency on translation information.
+
+Here are the routines, one by one:
+
+1) void flush_cache_all(void)
+
+ The most severe flush of all. After this interface runs,
+ the entire cpu cache is flushed.
+
+ This is usually invoked when the kernel page tables are
+ changed, since such translations are "global" in nature.
+
+2) void flush_cache_mm(struct mm_struct *mm)
+
+ This interface flushes an entire user address space from
+ the caches. That is, after running, there will be no cache
+ lines assosciated with 'mm'.
+
+ This interface is used to handle whole address space
+ page table operations such as what happens during
+ fork, exit, and exec.
+
+3) void flush_cache_range(struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+
+ Here we are flushing a specific range of (user) virtual
+ addresses from the cache. After running, there will be no
+ entries in the cache for 'mm' for virtual addresses in the
+ range 'start' to 'end'.
+
+ Primarily, this is used for munmap() type operations.
+
+ The interface is provided in hopes that the port can find
+ a suitably efficient method for removing multiple page
+ sized regions from the cache, instead of having the kernel
+ call flush_cache_page (see below) for each entry which may be
+ modified.
+
+4) void flush_cache_page(struct vm_area_struct *vma, unsigned long page)
+
+ This time we need to remove a PAGE_SIZE sized range
+ from the cache. The 'vma' is the backing structure used by
+ Linux to keep track of mmap'd regions for a process, the
+ address space is available via vma->vm_mm. Also, one may
+ test (vma->vm_flags & VM_EXEC) to see if this region is
+ executable (and thus could be in the 'instruction cache' in
+ "Harvard" type cache layouts).
+
+ After running, there will be no entries in the cache for
+ 'vma->vm_mm' for virtual address 'page'.
+
+ This is used primarily during fault processing.
+
+There exists another whole class of cpu cache issues which currently
+require a whole different set of interfaces to handle properly.
+The biggest problem is that of virtual aliasing in the data cache
+of a processor.
+
+Is your port subsceptible to virtual aliasing in it's D-cache?
+Well, if your D-cache is virtually indexed, is larger in size than
+PAGE_SIZE, and does not prevent multiple cache lines for the same
+physical address from existing at once, you have this problem.
+
+If your D-cache has this problem, first define asm/shmparam.h SHMLBA
+properly, it should essentially be the size of your virtually
+addressed D-cache (or if the size is variable, the largest possible
+size). This setting will force the SYSv IPC layer to only allow user
+processes to mmap shared memory at address which are a multiple of
+this value.
+
+Next, you have two methods to solve the D-cache aliasing issue for all
+other cases. Please keep in mind that fact that, for a given page
+mapped into some user address space, there is always at least one more
+mapping, that of the kernel in it's linear mapping starting at
+PAGE_OFFSET. So immediately, once the first user maps a given
+physical page into it's address space, by implication the D-cache
+aliasing problem has the potential to exist since the kernel already
+maps this page at it's virtual address.
+
+First, I describe the old method to deal with this problem. I am
+describing it for documentation purposes, but it is deprecated and the
+latter method I describe next should be used by all new ports and all
+existing ports should move over to the new mechanism as well.
+
+ flush_page_to_ram(struct page *page)
+
+ The physical page 'page' is about to be place into the
+ user address space of a process. If it is possible for
+ stores done recently by the kernel into this physical
+ page, to not be visible to an arbitray mapping in userspace,
+ you must flush this page from the D-cache.
+
+ If the D-cache is writeback in nature, the dirty data (if
+ any) for this physical page must be written back to main
+ memory before the cache lines are invalidated.
+
+Admittedly, the author did not think very much when designing this
+interface. It does not give the architecture enough information about
+what exactly is going on, and there is not context with which to base
+any judgment about whether an alias is possible at all. The new
+interfaces to deal with D-cache aliasing are meant to address this by
+telling the architecture specific code exactly which is going on at
+the proper points in time.
+
+Here is the new interface:
+
+ void copy_user_page(void *from, void *to, unsigned long address)
+ void clear_user_page(void *to, unsigned long address)
+
+ These two routines store data in user anonymous or COW
+ pages. It allows a port to efficiently avoid D-cache alias
+ issues between userspace and the kernel.
+
+ For example, a port may temporarily map 'from' and 'to' to
+ kernel virtual addresses during the copy. The virtual address
+ for these two pages is choosen in such a way that the kernel
+ load/store instructions happen to virtual addresses which are
+ of the same "color" as the user mapping of the page. Sparc64
+ for example, uses this technique.
+
+ The "address" parameter tells the virtual address where the
+ user has this page mapped.
+
+ If D-cache aliasing is not an issue, these two routines may
+ simply call memcpy/memset directly and do nothing more.
+
+ void flush_dcache_page(struct page *page)
+
+ Any time the kernel writes to a page cache page, _OR_
+ the kernel is about to read from a page cache page and
+ user space shared/writable mappings of this page potentially
+ exist, this routine is called.
+
+ The phrase "kernel writes to a page cache page" means,
+ specifically, that the kernel executes store instructions
+ that dirty data in that page at the page->virtual mapping
+ of that page. It is important to flush here to handle
+ D-cache aliasing, to make sure these kernel stores are
+ visible to user space mappings of that page.
+
+ The corollary case is just as important, if there are users
+ which have shared+writable mappings of this file, we must make
+ sure that kernel reads of these pages will see the most recent
+ stores done by the user.
+
+ If D-cache aliasing is not an issue, this routine may
+ simply be defined as a nop on that architecture.
+
+ TODO: If we set aside a few bits in page->flags as
+ "architecture private", these interfaces could
+ be implemented much more efficiently. This would
+ allow one to "defer" (perhaps indefinitely) the
+ actual flush if there are currently no user processes
+ mapping this page.
+
+ The idea is, first at flush_dcache_page() time, if
+ page->mapping->i_mmap is an empty list, just mark
+ one of the architecture private page flag bits.
+ Later, in update_mmu_cache(), a check could be made
+ of this flag bit, and if set the flush is done
+ and the flag bit is cleared.
+
+XXX Not documented: flush_icache_page(), need to talk to Paul
+ Mackerras, David Mosberger-Tang, et al.
+ to see what the expected semantics of this
+ interface are. -DaveM
diff --git a/Makefile b/Makefile
index 49a7d58cd..fc154916c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 0
-EXTRAVERSION = -test7
+EXTRAVERSION = -test8-pre1
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index aed275365..1626761fb 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -671,14 +671,7 @@ inline void smp_local_timer_interrupt(struct pt_regs * regs)
}
#ifdef CONFIG_SMP
- /*
- * update_process_times() expects us to have done irq_enter().
- * Besides, if we don't timer interrupts ignore the global
- * interrupt lock, which is the WrongThing (tm) to do.
- */
- irq_enter(cpu, 0);
update_process_times(user);
- irq_exit(cpu, 0);
#endif
}
@@ -706,17 +699,26 @@ unsigned int apic_timer_irqs [NR_CPUS] = { 0, };
void smp_apic_timer_interrupt(struct pt_regs * regs)
{
+ int cpu = smp_processor_id();
+
/*
* the NMI deadlock-detector uses this.
*/
- apic_timer_irqs[smp_processor_id()]++;
+ apic_timer_irqs[cpu]++;
/*
* NOTE! We'd better ACK the irq immediately,
* because timer handling can be slow.
*/
ack_APIC_irq();
+ /*
+ * update_process_times() expects us to have done irq_enter().
+ * Besides, if we don't timer interrupts ignore the global
+ * interrupt lock, which is the WrongThing (tm) to do.
+ */
+ irq_enter(cpu, 0);
smp_local_timer_interrupt(regs);
+ irq_exit(cpu, 0);
}
/*
diff --git a/arch/i386/kernel/mca.c b/arch/i386/kernel/mca.c
index e9c8377cd..104ae9e9e 100644
--- a/arch/i386/kernel/mca.c
+++ b/arch/i386/kernel/mca.c
@@ -546,7 +546,7 @@ unsigned char mca_read_pos(int slot, int reg)
outb_p(0x7f, MCA_MOTHERBOARD_SETUP_REG);
byte = inb_p(MCA_POS_REG(reg));
- outp_b(0xff, MCA_MOTHERBOARD_SETUP_REG);
+ outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
} else if(slot < MCA_MAX_SLOT_NR) {
/* Make sure motherboard setup is off */
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index cbbe20614..b2088bc86 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -158,11 +158,9 @@ CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_PNP is not set
-# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
-# CONFIG_INET_ECN is not set
+CONFIG_INET_ECN=y
# CONFIG_SYN_COOKIES is not set
CONFIG_IPV6=m
# CONFIG_IPV6_EUI64 is not set
@@ -345,6 +343,7 @@ CONFIG_IEEE1394_RAWIO=m
CONFIG_NETDEVICES=y
CONFIG_DUMMY=m
CONFIG_BONDING=m
+CONFIG_TUN=m
CONFIG_PPP=m
# CONFIG_PPP_ASYNC is not set
# CONFIG_PPP_SYNC_TTY is not set
@@ -453,8 +452,7 @@ CONFIG_NFSD_V3=y
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
-CONFIG_SMB_FS=m
-CONFIG_SMB_NLS_REMOTE=""
+# CONFIG_SMB_FS is not set
# CONFIG_NCP_FS is not set
# CONFIG_NCPFS_PACKET_SIGNING is not set
# CONFIG_NCPFS_IOCTL_LOCKING is not set
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index 6fa72fc8e..a8c29311f 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -246,7 +246,8 @@ static ssize_t nvram_read(struct file * file,
spin_unlock_irq (&rtc_lock);
- copy_to_user_ret (buf, contents, tmp - contents, -EFAULT);
+ if (copy_to_user (buf, contents, tmp - contents))
+ return -EFAULT;
*ppos = i;
@@ -264,10 +265,9 @@ static ssize_t nvram_write(struct file * file,
unsigned i = *ppos;
char * tmp;
- /* could comebody please help me indent this better? */
- copy_from_user_ret (contents, buf, (NVRAM_BYTES - i) < count ?
- (NVRAM_BYTES - i) : count,
- -EFAULT);
+ if (copy_from_user (contents, buf, (NVRAM_BYTES - i) < count ?
+ (NVRAM_BYTES - i) : count))
+ return -EFAULT;
spin_lock_irq (&rtc_lock);
diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c
index 34e13c97f..d9276b753 100644
--- a/drivers/char/pc_keyb.c
+++ b/drivers/char/pc_keyb.c
@@ -62,6 +62,7 @@ static void kbd_write_command_w(int data);
static void kbd_write_output_w(int data);
#ifdef CONFIG_PSMOUSE
static void aux_write_ack(int val);
+static void __aux_write_ack(int val);
#endif
spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
@@ -404,7 +405,7 @@ static inline void handle_mouse_event(unsigned char scancode)
}
else if(scancode == AUX_RECONNECT){
queue->head = queue->tail = 0; /* Flush input queue */
- aux_write_ack(AUX_ENABLE_DEV); /* ping the mouse :) */
+ __aux_write_ack(AUX_ENABLE_DEV); /* ping the mouse :) */
return;
}
@@ -822,11 +823,8 @@ static void aux_write_dev(int val)
/*
* Send a byte to the mouse & handle returned ack
*/
-static void aux_write_ack(int val)
+static void __aux_write_ack(int val)
{
- unsigned long flags;
-
- spin_lock_irqsave(&kbd_controller_lock, flags);
kb_wait();
kbd_write_command(KBD_CCMD_WRITE_MOUSE);
kb_wait();
@@ -834,6 +832,14 @@ static void aux_write_ack(int val)
/* we expect an ACK in response. */
mouse_reply_expected++;
kb_wait();
+}
+
+static void aux_write_ack(int val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&kbd_controller_lock, flags);
+ __aux_write_ack(val);
spin_unlock_irqrestore(&kbd_controller_lock, flags);
}
diff --git a/drivers/media/video/stallion.c b/drivers/char/stallion.c
index a0faeada4..a0faeada4 100644
--- a/drivers/media/video/stallion.c
+++ b/drivers/char/stallion.c
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
index 1dcc8acb8..6339d1e90 100644
--- a/drivers/scsi/esp.c
+++ b/drivers/scsi/esp.c
@@ -1,4 +1,4 @@
-/* $Id: esp.c,v 1.94 2000/03/30 02:09:10 davem Exp $
+/* $Id: esp.c,v 1.95 2000/08/23 22:32:37 davem Exp $
* esp.c: EnhancedScsiProcessor Sun SCSI driver code.
*
* Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
@@ -32,13 +32,16 @@
#include <asm/sbus.h>
#include <asm/dma.h>
#include <asm/system.h>
-#include <asm/machines.h>
#include <asm/ptrace.h>
#include <asm/pgtable.h>
#include <asm/oplib.h>
#include <asm/io.h>
#include <asm/irq.h>
+
+#ifndef __sparc_v9__
+#include <asm/machines.h>
#include <asm/idprom.h>
+#endif
#include <linux/module.h>
@@ -1634,6 +1637,7 @@ do_sync_known:
*/
int cdrom_hwbug_wkaround = 0;
+#ifndef __sparc_v9__
/* Never allow disconnects or synchronous transfers on
* SparcStation1 and SparcStation1+. Allowing those
* to be enabled seems to lockup the machine completely.
@@ -1654,6 +1658,7 @@ do_sync_known:
esp->snip = 0;
goto do_sync_known;
}
+#endif /* !(__sparc_v9__) */
/* We've talked to this guy before,
* but never negotiated. Let's try,
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index d61c832c5..b510231be 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -32,7 +32,6 @@
#include <asm/sbus.h>
#include <asm/dma.h>
#include <asm/system.h>
-#include <asm/machines.h>
#include <asm/ptrace.h>
#include <asm/pgtable.h>
#include <asm/oplib.h>
diff --git a/drivers/sound/sound_core.c b/drivers/sound/sound_core.c
index aa2890f05..8a85d4c42 100644
--- a/drivers/sound/sound_core.c
+++ b/drivers/sound/sound_core.c
@@ -456,7 +456,11 @@ static int soundcore_open(struct inode *, struct file *);
static struct file_operations soundcore_fops=
{
- owner: THIS_MODULE,
+/* owner: THIS_MODULE, * this is a bug: if we have an owner, the kernel
+ generates a MOD_INC_USE_COUNT - thus
+ the module cannot be unloaded since the device
+ is never released here ! - solution: owner
+ has to be NULL. Patch by Peter Wahl <Peter.Wahl@epost.de> */
open: soundcore_open,
};
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 7112ae635..d011f206b 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -79,7 +79,7 @@ endif
ifeq ($(CONFIG_USB_STORAGE),y)
SUB_DIRS += storage
- obj-y += storage/usb-storage.o
+ obj-y += storage/storage.o
else
ifeq ($(CONFIG_USB_STORAGE),m)
MOD_IN_SUB_DIRS += storage
diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile
index e7761863e..e09a8cac1 100644
--- a/drivers/usb/storage/Makefile
+++ b/drivers/usb/storage/Makefile
@@ -1,47 +1,44 @@
#
# Makefile for the USB Mass Storage device drivers.
#
+# 15 Aug 2000, Christoph Hellwig <hch@caldera.de>
+# Rewritten to use lists instead of if-statements.
+#
+
+O_TARGET := storage.o
+EXTRA_CFLAGS := -I../../scsi/
+
+list-multi := usb-storage.o
+
+obj-$(CONFIG_USB_STORAGE) += usb-storage.o
+
+usb-storage-obj-$(CONFIG_USB_STORAGE_DEBUG) += debug.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_HP8200e) += shuttle_usbat.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR09) += sddr09.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_FREECOM) += freecom.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_SHUTTLE_SMARTMEDIA) += shuttle_sm.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_SHUTTLE_COMPACTFLASH) += shuttle_cf.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_DPCM) += dpcm.o
+
+usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \
+ $(usb-storage-obj-y)
+
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
+multi-y := $(filter $(list-multi), $(obj-y))
+multi-m := $(filter $(list-multi), $(obj-m))
+int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Take multi-part drivers out of obj-y and put components in.
+obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y)
+
+# Translate to Rules.make lists.
+O_OBJS := $(obj-y)
+M_OBJS := $(obj-m)
+MI_OBJS := $(int-m)
-O_TARGET := usb-storage.o
-M_OBJS := usb-storage.o
-O_OBJS := scsiglue.o protocol.o transport.o usb.o
-MOD_LIST_NAME := USB_STORAGE_MODULES
-
-CFLAGS_scsiglue.o:= -I../../scsi/
-CFLAGS_protocol.o:= -I../../scsi/
-CFLAGS_transport.o:= -I../../scsi/
-CFLAGS_debug.o:= -I../../scsi/
-CFLAGS_usb.o:= -I../../scsi/
-CFLAGS_shuttle_usbat.o:= -I../../scsi/
-CFLAGS_sddr09.o:= -I../../scsi/
-CFLAGS_dpcm.o:= -I../../scsi/
-
-ifeq ($(CONFIG_USB_STORAGE_DEBUG),y)
- O_OBJS += debug.o
-endif
-
-ifeq ($(CONFIG_USB_STORAGE_HP8200e),y)
- O_OBJS += shuttle_usbat.o
-endif
-
-ifeq ($(CONFIG_USB_STORAGE_SDDR09),y)
- O_OBJS += sddr09.o
-endif
-
-ifeq ($(CONFIG_USB_STORAGE_FREECOM),y)
- O_OBJS += freecom.o
-endif
-
-ifeq ($(CONFIG_USB_STORAGE_SHUTTLE_SMARTMEDIA),y)
- O_OBJS += shuttle_sm.o
-endif
-
-ifeq ($(CONFIG_USB_STORAGE_SHUTTLE_COMPACTFLASH),y)
- O_OBJS += shuttle_cf.o
-endif
-
-ifeq ($(CONFIG_USB_STORAGE_DPCM),y)
- O_OBJS += dpcm.o
-endif
-
include $(TOPDIR)/Rules.make
+
+usb-storage.o: $(usb-storage-objs)
+ $(LD) -r -o $@ $(usb-storage-objs)
diff --git a/drivers/usb/storage/debug.c b/drivers/usb/storage/debug.c
index 2a5127bb6..9f4693b95 100644
--- a/drivers/usb/storage/debug.c
+++ b/drivers/usb/storage/debug.c
@@ -1,9 +1,9 @@
/* Driver for USB Mass Storage compliant devices
* Debugging Functions Source Code File
*
- * $Id: debug.c,v 1.2 2000/07/19 17:21:39 groovyjava Exp $
+ * $Id: debug.c,v 1.3 2000/08/25 00:13:51 mdharm Exp $
*
- * Current development and maintainance by:
+ * Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
* Initial work by:
diff --git a/drivers/usb/storage/debug.h b/drivers/usb/storage/debug.h
index 04a08be2e..f03c53351 100644
--- a/drivers/usb/storage/debug.h
+++ b/drivers/usb/storage/debug.h
@@ -1,9 +1,9 @@
/* Driver for USB Mass Storage compliant devices
* Debugging Functions Header File
*
- * $Id: debug.h,v 1.3 2000/07/19 19:34:48 groovyjava Exp $
+ * $Id: debug.h,v 1.4 2000/08/25 00:13:51 mdharm Exp $
*
- * Current development and maintainance by:
+ * Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
* Initial work by:
diff --git a/drivers/usb/storage/dpcm.c b/drivers/usb/storage/dpcm.c
index 8b7195bfc..33cb674e2 100644
--- a/drivers/usb/storage/dpcm.c
+++ b/drivers/usb/storage/dpcm.c
@@ -1,12 +1,12 @@
/* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader
*
- * $Id: dpcm.c,v 1.1 2000/08/08 01:26:12 webbb Exp $
+ * $Id: dpcm.c,v 1.3 2000/08/25 00:13:51 mdharm Exp $
*
* DPCM driver v0.1:
*
* First release
*
- * Current development and maintainance by:
+ * Current development and maintenance by:
* (c) 2000 Brian Webb (webbb@earthlink.net)
*
* This device contains both a CompactFlash card reader, which
@@ -37,7 +37,6 @@
#include "dpcm.h"
#include "sddr09.h"
-
/*
* Transport for the Microtech DPCM-USB
*
diff --git a/drivers/usb/storage/dpcm.h b/drivers/usb/storage/dpcm.h
index d6e5f86ad..e6e5637d6 100644
--- a/drivers/usb/storage/dpcm.h
+++ b/drivers/usb/storage/dpcm.h
@@ -1,12 +1,12 @@
/* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader
*
- * $Id: dpcm.h,v 1.1 2000/08/08 01:26:12 webbb Exp $
+ * $Id: dpcm.h,v 1.2 2000/08/25 00:13:51 mdharm Exp $
*
* DPCM driver v0.1:
*
* First release
*
- * Current development and maintainance by:
+ * Current development and maintenance by:
* (c) 2000 Brian Webb (webbb@earthlink.net)
*
* See dpcm.c for more explanation
diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
new file mode 100644
index 000000000..6b0914cf6
--- /dev/null
+++ b/drivers/usb/storage/freecom.c
@@ -0,0 +1,375 @@
+/* Driver for Freecom USB/IDE adaptor
+ *
+ * $Id: freecom.c,v 1.7 2000/08/25 00:13:51 mdharm Exp $
+ *
+ * Freecom v0.1:
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ * (C) 2000 David Brown <usb-storage@davidb.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This driver was developed with information provided in FREECOM's USB
+ * Programmers Reference Guide. For further information contact Freecom
+ * (http://www.freecom.de/)
+ */
+
+#include <linux/config.h>
+#include "transport.h"
+#include "protocol.h"
+#include "usb.h"
+#include "debug.h"
+#include "freecom.h"
+
+static void pdump (void *, int);
+
+struct freecom_udata {
+ __u8 buffer[64]; /* Common command block. */
+};
+typedef struct freecom_udata *freecom_udata_t;
+
+/* All of the outgoing packets are 64 bytes long. */
+struct freecom_cb_wrap {
+ __u8 Type; /* Command type. */
+ __u8 Timeout; /* Timeout in seconds. */
+ __u8 Atapi[12]; /* An ATAPI packet. */
+ __u8 Filler[50]; /* Padding Data. */
+};
+
+struct freecom_xfer_wrap {
+ __u8 Type; /* Command type. */
+ __u8 Timeout; /* Timeout in seconds. */
+ __u32 Count; /* Number of bytes to transfer. */
+ __u8 Pad[58];
+};
+
+struct freecom_status {
+ __u8 Status;
+ __u8 Reason;
+ __u16 Count;
+ __u8 Pad[60];
+};
+
+/* These are the packet types. The low bit indicates that this command
+ * should wait for an interrupt. */
+#define FCM_PACKET_ATAPI 0x21
+
+/* Receive data from the IDE interface. The ATAPI packet has already
+ * waited, so the data should be immediately available. */
+#define FCM_PACKET_INPUT 0x90
+
+/* All packets (except for status) are 64 bytes long. */
+#define FCM_PACKET_LENGTH 64
+
+static int
+freecom_readdata (Scsi_Cmnd *srb, struct us_data *us,
+ int ipipe, int opipe, int count)
+{
+ freecom_udata_t extra = (freecom_udata_t) us->extra;
+ struct freecom_xfer_wrap *fxfr =
+ (struct freecom_xfer_wrap *) extra->buffer;
+ int result, partial;
+ int offset;
+ __u8 *buffer = extra->buffer;
+
+ fxfr->Type = FCM_PACKET_INPUT | 0x00;
+ fxfr->Timeout = 0; /* Short timeout for debugging. */
+ fxfr->Count = cpu_to_le32 (count);
+ memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
+
+ printk (KERN_DEBUG "Read data Freecom! (c=%d)\n", count);
+
+ /* Issue the transfer command. */
+ result = usb_stor_bulk_msg (us, fxfr, opipe,
+ FCM_PACKET_LENGTH, &partial);
+ if (result != 0) {
+ US_DEBUGP ("Freecom readdata xpot failure: r=%d, p=%d\n",
+ result, partial);
+
+ /* -ENOENT -- we canceled this transfer */
+ if (result == -ENOENT) {
+ US_DEBUGP("us_transfer_partial(): transfer aborted\n");
+ return US_BULK_TRANSFER_ABORTED;
+ }
+
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ printk (KERN_DEBUG "Done issuing read request: %d %d\n",
+ result, partial);
+
+ /* Now transfer all of our blocks. */
+ if (srb->use_sg) {
+ US_DEBUGP ("Need to implement scatter-gather\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ } else {
+ offset = 0;
+
+ while (offset < count) {
+ printk (KERN_DEBUG "Start of read\n");
+ /* Use the given buffer directly, but only if there
+ * is space for an entire packet. */
+
+ if (offset + 64 <= srb->request_bufflen) {
+ result = usb_stor_bulk_msg (
+ us, srb->request_buffer+offset,
+ ipipe, 64, &partial);
+ printk (KERN_DEBUG "Read111 = %d, %d\n",
+ result, partial);
+ pdump (srb->request_buffer+offset,
+ partial);
+ } else {
+ result = usb_stor_bulk_msg (
+ us, buffer,
+ ipipe, 64, &partial);
+ printk (KERN_DEBUG "Read112 = %d, %d\n",
+ result, partial);
+ memcpy (srb->request_buffer+offset,
+ buffer,
+ srb->request_bufflen - offset);
+ pdump (srb->request_buffer+offset,
+ srb->request_bufflen - offset);
+ }
+
+ if (result != 0) {
+ US_DEBUGP ("Freecom readblock r=%d, p=%d\n",
+ result, partial);
+
+ /* -ENOENT -- we canceled this transfer */
+ if (result == -ENOENT) {
+ US_DEBUGP("us_transfer_partial(): transfer aborted\n");
+ return US_BULK_TRANSFER_ABORTED;
+ }
+
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ offset += 64;
+ }
+ }
+
+ printk (KERN_DEBUG "freecom_readdata done!\n");
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Transport for the Freecom USB/IDE adaptor.
+ *
+ */
+int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+ struct freecom_cb_wrap *fcb;
+ struct freecom_status *fst;
+ int ipipe, opipe; /* We need both pipes. */
+ int result;
+ int partial;
+ int length;
+ freecom_udata_t extra;
+
+ /* Allocate a buffer for us. The upper usb transport code will
+ * free this for us when cleaning up. */
+ if (us->extra == NULL) {
+ us->extra = kmalloc (sizeof (struct freecom_udata),
+ GFP_KERNEL);
+ if (us->extra == NULL) {
+ printk (KERN_WARNING USB_STORAGE "Out of memory\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ }
+
+ extra = (freecom_udata_t) us->extra;
+
+ fcb = (struct freecom_cb_wrap *) extra->buffer;
+ fst = (struct freecom_status *) extra->buffer;
+
+ printk (KERN_DEBUG "Freecom TRANSPORT STARTED\n");
+
+ /* Get handles for both transports. */
+ opipe = usb_sndbulkpipe (us->pusb_dev, us->ep_out);
+ ipipe = usb_rcvbulkpipe (us->pusb_dev, us->ep_in);
+
+#if 0
+ /* Yuck, let's see if this helps us. Artificially increase the
+ * length on this. */
+ if (srb->cmnd[0] == 0x03 && srb->cmnd[4] == 0x12)
+ srb->cmnd[4] = 0x0E;
+#endif
+
+ /* The ATAPI Command always goes out first. */
+ fcb->Type = FCM_PACKET_ATAPI;
+ fcb->Timeout = 0;
+ memcpy (fcb->Atapi, srb->cmnd, 12);
+ memset (fcb->Filler, 0, sizeof (fcb->Filler));
+
+ pdump (srb->cmnd, 12);
+
+ /* Send it out. */
+ result = usb_stor_bulk_msg (us, fcb, opipe,
+ FCM_PACKET_LENGTH, &partial);
+
+ /* The Freecom device will only fail if there is something wrong in
+ * USB land. It returns the status in its own registers, which
+ * come back in the bulk pipe. */
+ if (result != 0) {
+ US_DEBUGP ("freecom xport failure: r=%d, p=%d\n",
+ result, partial);
+
+ /* -ENOENT -- we canceled this transfer */
+ if (result == -ENOENT) {
+ US_DEBUGP("us_transfer_partial(): transfer aborted\n");
+ return US_BULK_TRANSFER_ABORTED;
+ }
+
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* There are times we can optimize out this status read, but it
+ * doesn't hurt us to always do it now. */
+ result = usb_stor_bulk_msg (us, fst, ipipe,
+ FCM_PACKET_LENGTH, &partial);
+ printk (KERN_DEBUG "foo Status result %d %d\n", result, partial);
+ /* -ENOENT -- we canceled this transfer */
+ if (result == -ENOENT) {
+ US_DEBUGP("us_transfer_partial(): transfer aborted\n");
+ return US_BULK_TRANSFER_ABORTED;
+ }
+
+ pdump ((void *) fst, partial);
+ if (partial != 4 || result != 0) {
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ if ((fst->Reason & 1) != 0) {
+ printk (KERN_DEBUG "operation failed\n");
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+
+ /* The device might not have as much data available as we
+ * requested. If you ask for more than the device has, this reads
+ * and such will hang. */
+ printk (KERN_DEBUG "Device indicates that it has %d bytes available\n",
+ le16_to_cpu (fst->Count));
+
+ /* Find the length we desire to read. It is the lesser of the SCSI
+ * layer's requested length, and the length the device claims to
+ * have available. */
+ length = us_transfer_length (srb);
+ printk (KERN_DEBUG "SCSI requested %d\n", length);
+ if (length > le16_to_cpu (fst->Count))
+ length = le16_to_cpu (fst->Count);
+
+ /* What we do now depends on what direction the data is supposed to
+ * move in. */
+
+ switch (us->srb->sc_data_direction) {
+ case SCSI_DATA_READ:
+ result = freecom_readdata (srb, us, ipipe, opipe, length);
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ return result;
+ break;
+
+ default:
+ US_DEBUGP ("freecom unimplemented direction: %d\n",
+ us->srb->sc_data_direction);
+ // Return fail, SCSI seems to handle this better.
+ return USB_STOR_TRANSPORT_FAILED;
+ break;
+ }
+
+#if 0
+ /* After the transfer, we can read our status register. */
+ printk (KERN_DEBUG "Going to read status register\n");
+ result = usb_stor_bulk_msg (us, &fst, ipipe,
+ FCM_PACKET_LENGTH, &partial);
+ printk (KERN_DEBUG "Result from read %d %d\n", result, partial);
+ if (result != 0) {
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ if ((fst.Reason & 1) != 0) {
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+#endif
+
+ return USB_STOR_TRANSPORT_GOOD;
+
+ printk (KERN_DEBUG "Freecom: transfer_length = %d\n",
+ us_transfer_length (srb));
+
+ printk (KERN_DEBUG "Freecom: direction = %d\n",
+ srb->sc_data_direction);
+
+ return USB_STOR_TRANSPORT_ERROR;
+}
+
+int usb_stor_freecom_reset(struct us_data *us)
+{
+ printk (KERN_DEBUG "freecom reset called\n");
+
+ /* We don't really have this feature. */
+ return USB_STOR_TRANSPORT_ERROR;
+}
+
+static void pdump (void *ibuffer, int length)
+{
+ static char line[80];
+ int offset = 0;
+ unsigned char *buffer = (unsigned char *) ibuffer;
+ int i, j;
+ int from, base;
+
+ offset = 0;
+ for (i = 0; i < length; i++) {
+ if ((i & 15) == 0) {
+ if (i > 0) {
+ offset += sprintf (line+offset, " - ");
+ for (j = i - 16; j < i; j++) {
+ if (buffer[j] >= 32 && buffer[j] <= 126)
+ line[offset++] = buffer[j];
+ else
+ line[offset++] = '.';
+ }
+ line[offset] = 0;
+ printk (KERN_DEBUG "%s\n", line);
+ offset = 0;
+ }
+ offset += sprintf (line+offset, "%08x:", i);
+ }
+ else if ((i & 7) == 0) {
+ offset += sprintf (line+offset, " -");
+ }
+ offset += sprintf (line+offset, " %02x", buffer[i] & 0xff);
+ }
+
+ /* Add the last "chunk" of data. */
+ from = (length - 1) % 16;
+ base = ((length - 1) / 16) * 16;
+
+ for (i = from + 1; i < 16; i++)
+ offset += sprintf (line+offset, " ");
+ if (from < 8)
+ offset += sprintf (line+offset, " ");
+ offset += sprintf (line+offset, " - ");
+
+ for (i = 0; i <= from; i++) {
+ if (buffer[base+i] >= 32 && buffer[base+i] <= 126)
+ line[offset++] = buffer[base+i];
+ else
+ line[offset++] = '.';
+ }
+ line[offset] = 0;
+ printk (KERN_DEBUG "%s\n", line);
+ offset = 0;
+}
+
diff --git a/drivers/usb/storage/freecom.h b/drivers/usb/storage/freecom.h
new file mode 100644
index 000000000..98ac919fa
--- /dev/null
+++ b/drivers/usb/storage/freecom.h
@@ -0,0 +1,35 @@
+/* Driver for Freecom USB/IDE adaptor
+ *
+ * $Id: freecom.h,v 1.3 2000/08/25 00:13:51 mdharm Exp $
+ *
+ * Freecom v0.1:
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ * (c) 2000 David Brown <usb-storage@davidb.org>
+ *
+ * See freecom.c for more explanation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _FREECOM_USB_H
+#define _FREECOM_USB_H
+
+extern int freecom_transport(Scsi_Cmnd *srb, struct us_data *us);
+extern int usb_stor_freecom_reset(struct us_data *us);
+
+#endif
diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
index aee6b420e..2aa83ea6d 100644
--- a/drivers/usb/storage/protocol.c
+++ b/drivers/usb/storage/protocol.c
@@ -1,8 +1,8 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: protocol.c,v 1.4 2000/08/01 22:01:19 mdharm Exp $
+ * $Id: protocol.c,v 1.5 2000/08/25 00:13:51 mdharm Exp $
*
- * Current development and maintainance by:
+ * Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
* Developed with the assistance of:
diff --git a/drivers/usb/storage/protocol.h b/drivers/usb/storage/protocol.h
index 239d37983..a9306e6c9 100644
--- a/drivers/usb/storage/protocol.h
+++ b/drivers/usb/storage/protocol.h
@@ -1,9 +1,9 @@
/* Driver for USB Mass Storage compliant devices
* Protocol Functions Header File
*
- * $Id: protocol.h,v 1.2 2000/08/01 22:01:19 mdharm Exp $
+ * $Id: protocol.h,v 1.3 2000/08/25 00:13:51 mdharm Exp $
*
- * Current development and maintainance by:
+ * Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
* This driver is based on the 'USB Mass Storage Class' document. This
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index c823aaed1..9d4f983fc 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -1,9 +1,9 @@
/* Driver for USB Mass Storage compliant devices
* SCSI layer glue code
*
- * $Id: scsiglue.c,v 1.8 2000/08/11 23:15:05 mdharm Exp $
+ * $Id: scsiglue.c,v 1.9 2000/08/25 00:13:51 mdharm Exp $
*
- * Current development and maintainance by:
+ * Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
* Developed with the assistance of:
diff --git a/drivers/usb/storage/scsiglue.h b/drivers/usb/storage/scsiglue.h
index f81787678..13b9f3bec 100644
--- a/drivers/usb/storage/scsiglue.h
+++ b/drivers/usb/storage/scsiglue.h
@@ -1,9 +1,9 @@
/* Driver for USB Mass Storage compliant devices
* SCSI Connecting Glue Header File
*
- * $Id: scsiglue.h,v 1.3 2000/07/25 23:04:47 mdharm Exp $
+ * $Id: scsiglue.h,v 1.4 2000/08/25 00:13:51 mdharm Exp $
*
- * Current development and maintainance by:
+ * Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
* This driver is based on the 'USB Mass Storage Class' document. This
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
index 6bf9f1477..5641a751a 100644
--- a/drivers/usb/storage/sddr09.c
+++ b/drivers/usb/storage/sddr09.c
@@ -1,10 +1,12 @@
/* Driver for SanDisk SDDR-09 SmartMedia reader
*
+ * $Id: sddr09.c,v 1.10 2000/08/25 00:13:51 mdharm Exp $
+ *
* SDDR09 driver v0.1:
*
* First release
*
- * Current development and maintainance by:
+ * Current development and maintenance by:
* (c) 2000 Robert Baruch (autophile@dol.net)
*
* The SanDisk SDDR-09 SmartMedia reader uses the Shuttle EUSB-01 chip.
@@ -316,9 +318,9 @@ int sddr09_read_data(struct us_data *us,
// Figure out the initial LBA and page
- pba = (address/info->pagesize)>>4;
+ pba = address >> (info->pageshift + info->blockshift);
lba = info->pba_to_lba[pba];
- page = (address/info->pagesize)&0x0F;
+ page = (address >> info->pageshift) & info->blockmask;
// This could be made much more efficient by checking for
// contiguous LBA's. Another exercise left to the student.
@@ -329,15 +331,16 @@ int sddr09_read_data(struct us_data *us,
// Read as many sectors as possible in this block
- pages = 0x10-page;
+ pages = info->blocksize - page;
if (pages > sectors)
pages = sectors;
- US_DEBUGP("Read %01X pages, from PBA %04X"
- " (LBA %04X) page %01X\n",
+ US_DEBUGP("Read %02X pages, from PBA %04X"
+ " (LBA %04X) page %02X\n",
pages, pba, lba, page);
- address = ((pba<<4)+page)*info->pagesize;
+ address = ( (pba << info->blockshift) + page ) <<
+ info->pageshift;
// Unlike in the documentation, the address is in
// words of 2 bytes.
@@ -370,7 +373,7 @@ int sddr09_read_data(struct us_data *us,
result = sddr09_bulk_transport(us,
SCSI_DATA_READ, ptr,
- pages*info->pagesize, 0);
+ pages<<info->pageshift, 0);
if (result != USB_STOR_TRANSPORT_GOOD) {
if (use_sg)
@@ -381,7 +384,7 @@ int sddr09_read_data(struct us_data *us,
page = 0;
lba++;
sectors -= pages;
- ptr += pages*info->pagesize;
+ ptr += (pages << info->pageshift);
}
if (use_sg) {
@@ -435,7 +438,7 @@ int sddr09_read_control(struct us_data *us,
result = sddr09_bulk_transport(us,
SCSI_DATA_READ, content,
- blocks*0x40, use_sg);
+ blocks<<6, use_sg); // 0x40 bytes per block
US_DEBUGP("Result for bulk read in read_control %d\n",
result);
@@ -525,7 +528,7 @@ int sddr09_reset(struct us_data *us) {
}
unsigned long sddr09_get_capacity(struct us_data *us,
- unsigned int *pagesize) {
+ unsigned int *pagesize, unsigned int *blocksize) {
unsigned char manufacturerID;
unsigned char deviceID;
@@ -547,6 +550,7 @@ unsigned long sddr09_get_capacity(struct us_data *us,
US_DEBUGP("Manuf ID = %02X\n", manufacturerID);
*pagesize = 512;
+ *blocksize = 16;
switch (deviceID) {
@@ -556,8 +560,8 @@ unsigned long sddr09_get_capacity(struct us_data *us,
*pagesize = 256;
return 0x00100000;
- case 0x5d: // 2MB
- case 0xea:
+ case 0xea: // 2MB
+ case 0x5d: // 5d is a ROM card with pagesize 512.
case 0x64:
if (deviceID!=0x5D)
*pagesize = 256;
@@ -574,9 +578,11 @@ unsigned long sddr09_get_capacity(struct us_data *us,
return 0x00800000;
case 0x73: // 16MB
+ *blocksize = 32;
return 0x01000000;
case 0x75: // 32MB
+ *blocksize = 32;
return 0x02000000;
default: // unknown
@@ -587,7 +593,7 @@ unsigned long sddr09_get_capacity(struct us_data *us,
int sddr09_read_map(struct us_data *us) {
- unsigned char *control;
+ struct scatterlist *sg;
struct sddr09_card_info *info = (struct sddr09_card_info *)(us->extra);
int numblocks;
int i;
@@ -599,25 +605,60 @@ int sddr09_read_map(struct us_data *us) {
1, 0, 0, 1, 0, 1, 1, 0
};
int result;
+ int alloc_len;
+ int alloc_blocks;
if (!info->capacity)
return -1;
- /* read 64 (2^6) bytes for every block (8192 (2^13) bytes)
- of capacity:
- 64*(capacity/8192) = capacity*(2^6)*(2^-13) =
- capacity*2^(6-13) = capacity*(2^-7)
- */
-
- control = kmalloc(info->capacity>>7, GFP_KERNEL);
+ // read 64 (1<<6) bytes for every block
+ // ( 1 << ( blockshift + pageshift ) bytes)
+ // of capacity:
+ // (1<<6)*capacity/(1<<(b+p)) =
+ // ((1<<6)*capacity)>>(b+p) =
+ // capacity>>(b+p-6)
+
+ alloc_len = info->capacity >>
+ (info->blockshift + info->pageshift - 6);
+
+ // Allocate a number of scatterlist structures according to
+ // the number of 128k blocks in the alloc_len. Adding 128k-1
+ // and then dividing by 128k gives the correct number of blocks.
+ // 128k = 1<<17
+
+ alloc_blocks = (alloc_len + (1<<17) - 1) >> 17;
+ sg = kmalloc(alloc_blocks*sizeof(struct scatterlist),
+ GFP_KERNEL);
+ if (sg == NULL)
+ return 0;
+ for (i=0; i<alloc_blocks; i++) {
+ if (i<alloc_blocks-1) {
+ sg[i].address = kmalloc( (1<<17), GFP_KERNEL );
+ sg[i].length = (1<<17);
+ } else {
+ sg[i].address = kmalloc(alloc_len, GFP_KERNEL);
+ sg[i].length = alloc_len;
+ }
+ alloc_len -= sg[i].length;
+ }
+ for (i=0; i<alloc_blocks; i++)
+ if (sg[i].address == NULL) {
+ for (i=0; i<alloc_blocks; i++)
+ if (sg[i].address != NULL)
+ kfree(sg[i].address);
+ kfree(sg);
+ return 0;
+ }
- numblocks = info->capacity>>13;
+ numblocks = info->capacity >> (info->blockshift + info->pageshift);
if ( (result = sddr09_read_control(us, 0, numblocks,
- control, 0)) !=
+ (unsigned char *)sg, alloc_blocks)) !=
USB_STOR_TRANSPORT_GOOD) {
- kfree(control);
+ for (i=0; i<alloc_blocks; i++)
+ kfree(sg[i].address);
+ kfree(sg);
return -1;
}
@@ -629,11 +670,28 @@ int sddr09_read_map(struct us_data *us) {
kfree(info->pba_to_lba);
info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_KERNEL);
info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_KERNEL);
+
+ if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) {
+ if (info->lba_to_pba != NULL)
+ kfree(info->lba_to_pba);
+ if (info->pba_to_lba != NULL)
+ kfree(info->pba_to_lba);
+ info->lba_to_pba = NULL;
+ info->pba_to_lba = NULL;
+ for (i=0; i<alloc_blocks; i++)
+ kfree(sg[i].address);
+ kfree(sg);
+ return 0;
+ }
+
memset(info->lba_to_pba, 0, numblocks*sizeof(int));
memset(info->pba_to_lba, 0, numblocks*sizeof(int));
+ // Each block is 64 bytes of control data, so block i is located in
+ // scatterlist block i*64/128k = i*(2^6)*(2^-17) = i*(2^-11)
+
for (i=0; i<numblocks; i++) {
- ptr = control+64*i;
+ ptr = sg[i>>11].address+(i<<6);
if (ptr[0]!=0xFF || ptr[1]!=0xFF || ptr[2]!=0xFF ||
ptr[3]!=0xFF || ptr[4]!=0xFF || ptr[5]!=0xFF)
continue;
@@ -655,20 +713,30 @@ int sddr09_read_map(struct us_data *us) {
lba = (lba&0x07FF)>>1;
+ /* Every 1024 physical blocks, the LBA numbers
+ * go back to zero, but are within a higher
+ * block of LBA's. In other words, in blocks
+ * 1024-2047 you will find LBA 0-1023 which are
+ * really LBA 1024-2047.
+ */
+
+ lba += (i&~0x3FF);
+
if (lba>=numblocks) {
US_DEBUGP("Bad LBA %04X for block %04X\n", lba, i);
continue;
}
- if (i<0x10)
- US_DEBUGP("LBA %04X <-> PBA %04X\n",
- lba, i);
+ if (lba<0x10)
+ US_DEBUGP("LBA %04X <-> PBA %04X\n", lba, i);
info->pba_to_lba[i] = lba;
info->lba_to_pba[lba] = i;
}
- kfree(control);
+ for (i=0; i<alloc_blocks; i++)
+ kfree(sg[i].address);
+ kfree(sg);
return 0;
}
@@ -687,6 +755,9 @@ static int init_sddr09(struct us_data *us) {
0x03, 0x20, 0, 0, 0x0e, 0, 0, 0, 0, 0, 0, 0
};
+ // What the hey is all this for? Doesn't seem to
+ // affect the device, so we won't do device inits.
+
if ( (result = sddr09_send_control(us, command, data, 2)) !=
USB_STOR_TRANSPORT_GOOD)
return result;
@@ -741,11 +812,7 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
int i;
char string[64];
unsigned char inquiry_response[36] = {
- 0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00,
- 'S', 'a', 'n', 'D', 'i', 's', 'k', ' ',
- 'I', 'm', 'a', 'g', 'e', 'M', 'a', 't',
- 'e', ' ', 'S', 'D', 'D', 'R', '0', '9',
- ' ', ' ', ' ', ' '
+ 0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00
};
unsigned char mode_page_01[12] = {
0x01, 0x0a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
@@ -758,17 +825,11 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
unsigned short pages;
struct sddr09_card_info *info = (struct sddr09_card_info *)(us->extra);
-/*
- if (us->flags & US_FL_NEED_INIT) {
- US_DEBUGP("SDDR-09: initializing\n");
- init_sddr09(us);
- us->flags &= ~US_FL_NEED_INIT;
- }
-*/
-
if (!us->extra) {
us->extra = kmalloc(
sizeof(struct sddr09_card_info), GFP_KERNEL);
+ if (!us->extra)
+ return USB_STOR_TRANSPORT_ERROR;
memset(us->extra, 0, sizeof(struct sddr09_card_info));
us->extra_destructor = sddr09_card_info_destructor;
}
@@ -779,14 +840,29 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
respond to INQUIRY commands */
if (srb->cmnd[0] == INQUIRY) {
- memcpy(ptr, inquiry_response, 36);
+ memset(inquiry_response+8, 0, 28);
+ fill_inquiry_response(us, inquiry_response, 36);
return USB_STOR_TRANSPORT_GOOD;
}
if (srb->cmnd[0] == READ_CAPACITY) {
- capacity = sddr09_get_capacity(us, &info->pagesize);
+ capacity = sddr09_get_capacity(us, &info->pagesize,
+ &info->blocksize);
+
+ if (!capacity)
+ return USB_STOR_TRANSPORT_FAILED;
+
info->capacity = capacity;
+ for (info->pageshift=1;
+ (info->pagesize>>info->pageshift);
+ info->pageshift++);
+ info->pageshift--;
+ for (info->blockshift=1;
+ (info->blocksize>>info->blockshift);
+ info->blockshift++);
+ info->blockshift--;
+ info->blockmask = (1<<info->blockshift)-1;
// Last page in the card
@@ -836,12 +912,14 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
// convert page to block and page-within-block
- lba = page>>4;
- page = page&0x0F;
+ lba = page >> info->blockshift;
+ page = page & info->blockmask;
// locate physical block corresponding to logical block
- if (lba>=(info->capacity>>13)) {
+ if (lba >=
+ (info->capacity >>
+ (info->pageshift + info->blockshift) ) ) {
// FIXME: sense buffer?
@@ -866,8 +944,8 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
pba, lba, page, pages);
return sddr09_read_data(us,
- ((pba<<4)+page)*info->pagesize, pages,
- ptr, srb->use_sg);
+ ( (pba << info->blockshift) + page) << info->pageshift,
+ pages, ptr, srb->use_sg);
}
// Pass TEST_UNIT_READY and REQUEST_SENSE through
diff --git a/drivers/usb/storage/sddr09.h b/drivers/usb/storage/sddr09.h
index ecd9b7611..ac984469f 100644
--- a/drivers/usb/storage/sddr09.h
+++ b/drivers/usb/storage/sddr09.h
@@ -1,7 +1,9 @@
/* Driver for SanDisk SDDR-09 SmartMedia reader
* Header File
*
- * Current development and maintainance by:
+ * $Id: sddr09.h,v 1.5 2000/08/25 00:13:51 mdharm Exp $
+ *
+ * Current development and maintenance by:
* (c) 2000 Robert Baruch (autophile@dol.net)
*
* See sddr09.c for more explanation
@@ -29,10 +31,14 @@
extern int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us);
struct sddr09_card_info {
- unsigned long capacity; /* Size of card in bytes */
- int pagesize; /* Size of page in bytes */
- int *lba_to_pba; /* logical to physical map */
- int *pba_to_lba; /* physical to logical map */
+ unsigned long capacity; /* Size of card in bytes */
+ int pagesize; /* Size of page in bytes */
+ int pageshift; /* log2 of pagesize */
+ int blocksize; /* Size of block in pages */
+ int blockshift; /* log2 of blocksize */
+ int blockmask; /* 2^blockshift - 1 */
+ int *lba_to_pba; /* logical to physical map */
+ int *pba_to_lba; /* physical to logical map */
};
#endif
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
index 492bc7259..6a96ad0a7 100644
--- a/drivers/usb/storage/shuttle_usbat.c
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -1,6 +1,6 @@
/* Driver for SCM Microsystems USB-ATAPI cable
*
- * $Id: shuttle_usbat.c,v 1.2 2000/08/03 00:03:39 groovyjava Exp $
+ * $Id: shuttle_usbat.c,v 1.4 2000/08/25 00:13:51 mdharm Exp $
*
* SCM driver v0.2:
*
@@ -14,7 +14,7 @@
*
* First release - hp8200e.
*
- * Current development and maintainance by:
+ * Current development and maintenance by:
* (c) 2000 Robert Baruch (autophile@dol.net)
*
* Many originally ATAPI devices were slightly modified to meet the USB
@@ -734,7 +734,7 @@ static int hp_8200e_select_and_test_registers(struct us_data *us) {
return result;
}
-static int init_8200e(struct us_data *us) {
+int init_8200e(struct us_data *us) {
int result;
unsigned char status;
@@ -895,11 +895,11 @@ int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us)
"XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* C0-DF */
"XDXXXXXXXXXXXXXX" "XXW00HXXXXXXXXXX"; /* E0-FF */
- if (us->flags & US_FL_NEED_INIT) {
+/* if (us->flags & US_FL_NEED_INIT) {
US_DEBUGP("8200e: initializing\n");
init_8200e(us);
us->flags &= ~US_FL_NEED_INIT;
- }
+ } */
len = srb->request_bufflen;
diff --git a/drivers/usb/storage/shuttle_usbat.h b/drivers/usb/storage/shuttle_usbat.h
index ff5c07541..4bd2673c6 100644
--- a/drivers/usb/storage/shuttle_usbat.h
+++ b/drivers/usb/storage/shuttle_usbat.h
@@ -1,9 +1,9 @@
/* Driver for SCM Microsystems USB-ATAPI cable
* Header File
*
- * $Id: shuttle_usbat.h,v 1.2 2000/08/03 00:03:39 groovyjava Exp $
+ * $Id: shuttle_usbat.h,v 1.4 2000/08/25 00:13:51 mdharm Exp $
*
- * Current development and maintainance by:
+ * Current development and maintenance by:
* (c) 2000 Robert Baruch (autophile@dol.net)
*
* See scm.c for more explanation
@@ -74,5 +74,6 @@ extern int usbat_write_user_io(struct us_data *us,
/* HP 8200e stuff */
extern int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us);
+extern int init_8200e(struct us_data *us);
#endif
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index dd3c489f1..cad9253b3 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -1,8 +1,8 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: transport.c,v 1.12 2000/08/08 15:22:38 gowdy Exp $
+ * $Id: transport.c,v 1.18 2000/08/25 00:13:51 mdharm Exp $
*
- * Current development and maintainance by:
+ * Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
* Developed with the assistance of:
@@ -59,43 +59,7 @@
/* Calculate the length of the data transfer (not the command) for any
* given SCSI command
*/
-static unsigned int us_transfer_length(Scsi_Cmnd *srb, struct us_data *us)
-{
- int i;
- unsigned int total = 0;
- struct scatterlist *sg;
-
- /* support those devices which need the length calculated
- * differently
- */
- if (srb->cmnd[0] == INQUIRY) {
- srb->cmnd[4] = 36;
- }
-
- if ((srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE))
- return srb->cmnd[4];
-
- if (srb->cmnd[0] == TEST_UNIT_READY)
- return 0;
-
- /* Are we going to scatter gather? */
- if (srb->use_sg) {
- /* Add up the sizes of all the scatter-gather segments */
- sg = (struct scatterlist *) srb->request_buffer;
- for (i = 0; i < srb->use_sg; i++)
- total += sg[i].length;
-
- return total;
- }
- else
- /* Just return the length of the buffer */
- return srb->request_bufflen;
-}
-
-/* Calculate the length of the data transfer (not the command) for any
- * given SCSI command
- */
-static unsigned int us_transfer_length_new(Scsi_Cmnd *srb, struct us_data *us)
+static unsigned int us_transfer_length(Scsi_Cmnd *srb)
{
int i;
int doDefault = 0;
@@ -245,10 +209,6 @@ static unsigned int us_transfer_length_new(Scsi_Cmnd *srb, struct us_data *us)
WRITE_SAME 41
*/
- /* Not sure this is right as an INQUIRY can contain nonstandard info */
- if (srb->cmnd[0] == INQUIRY)
- srb->cmnd[4] = 36;
-
if (srb->sc_data_direction == SCSI_DATA_WRITE) {
doDefault = 1;
}
@@ -611,6 +571,16 @@ static void us_transfer(Scsi_Cmnd *srb, struct us_data* us)
int i;
int result = -1;
struct scatterlist *sg;
+ unsigned int total_transferred = 0;
+ unsigned int transfer_amount;
+
+ /* calculate how much we want to transfer */
+ transfer_amount = us_transfer_length(srb);
+
+ /* was someone foolish enough to request more data than available
+ * buffer space? */
+ if (transfer_amount > srb->request_bufflen)
+ transfer_amount = srb->request_bufflen;
/* are we scatter-gathering? */
if (srb->use_sg) {
@@ -620,8 +590,19 @@ static void us_transfer(Scsi_Cmnd *srb, struct us_data* us)
*/
sg = (struct scatterlist *) srb->request_buffer;
for (i = 0; i < srb->use_sg; i++) {
- result = us_transfer_partial(us, sg[i].address,
- sg[i].length);
+
+ /* transfer the lesser of the next buffer or the
+ * remaining data */
+ if (transfer_amount - total_transferred >=
+ sg[i].length) {
+ result = us_transfer_partial(us, sg[i].address,
+ sg[i].length);
+ total_transferred += sg[i].length;
+ } else
+ result = us_transfer_partial(us, sg[i].address,
+ transfer_amount - total_transferred);
+
+ /* if we get an error, end the loop here */
if (result)
break;
}
@@ -629,7 +610,7 @@ static void us_transfer(Scsi_Cmnd *srb, struct us_data* us)
else
/* no scatter-gather, just make the request */
result = us_transfer_partial(us, srb->request_buffer,
- srb->request_bufflen);
+ transfer_amount);
/* return the result in the data structure itself */
srb->result = result;
@@ -874,7 +855,7 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
/* DATA STAGE */
/* transfer the data payload for this command, if one exists*/
- if (us_transfer_length(srb, us)) {
+ if (us_transfer_length(srb)) {
us_transfer(srb, us);
US_DEBUGP("CBI data stage result is 0x%x\n", srb->result);
@@ -975,7 +956,7 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us)
/* DATA STAGE */
/* transfer the data payload for this command, if one exists*/
- if (us_transfer_length(srb, us)) {
+ if (us_transfer_length(srb)) {
us_transfer(srb, us);
US_DEBUGP("CB data stage result is 0x%x\n", srb->result);
@@ -1039,10 +1020,12 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* set up the command wrapper */
bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
- bcb.DataTransferLength = cpu_to_le32(us_transfer_length(srb, us));
+ bcb.DataTransferLength = cpu_to_le32(us_transfer_length(srb));
bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0;
bcb.Tag = srb->serial_number;
bcb.Lun = srb->cmnd[1] >> 5;
+ if (us->flags & US_FL_SCM_MULT_TARG)
+ bcb.Lun |= srb->target << 4;
bcb.Length = srb->cmd_len;
/* construct the pipe handle */
@@ -1053,8 +1036,9 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
memcpy(bcb.CDB, srb->cmnd, bcb.Length);
/* send it to out endpoint */
- US_DEBUGP("Bulk command S 0x%x T 0x%x LUN %d L %d F %d CL %d\n",
- le32_to_cpu(bcb.Signature), bcb.Tag, bcb.Lun,
+ US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n",
+ le32_to_cpu(bcb.Signature), bcb.Tag,
+ (bcb.Lun >> 4), (bcb.Lun & 0xFF),
bcb.DataTransferLength, bcb.Flags, bcb.Length);
result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN,
&partial);
diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
index 4615569f3..3f300053d 100644
--- a/drivers/usb/storage/transport.h
+++ b/drivers/usb/storage/transport.h
@@ -1,9 +1,9 @@
/* Driver for USB Mass Storage compliant devices
* Transport Functions Header File
*
- * $Id: transport.h,v 1.8 2000/08/08 01:23:55 webbb Exp $
+ * $Id: transport.h,v 1.11 2000/08/25 00:13:51 mdharm Exp $
*
- * Current development and maintainance by:
+ * Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
* This driver is based on the 'USB Mass Storage Class' document. This
@@ -41,8 +41,8 @@
#ifndef _TRANSPORT_H_
#define _TRANSPORT_H_
-#include <linux/config.h>
#include <linux/blk.h>
+#include <linux/config.h>
#include "usb.h"
#include "scsi.h"
@@ -60,6 +60,10 @@
#endif
#define US_PR_DPCM_USB 0xf0 /* Combination CB/SDDR09 */
+#ifdef CONFIG_USB_STORAGE_FREECOM
+#define US_PR_FREECOM 0xf1 /* Freecom */
+#endif
+
/*
* Bulk only data structures
*/
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 50ebddd6f..07f0598e5 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -1,8 +1,8 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: usb.c,v 1.23 2000/08/08 20:46:45 mdharm Exp $
+ * $Id: usb.c,v 1.33 2000/08/25 00:13:51 mdharm Exp $
*
- * Current development and maintainance by:
+ * Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
* Developed with the assistance of:
@@ -43,7 +43,6 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include "usb.h"
#include "scsiglue.h"
#include "transport.h"
@@ -58,12 +57,16 @@
#ifdef CONFIG_USB_STORAGE_DPCM
#include "dpcm.h"
#endif
+#ifdef CONFIG_USB_STORAGE_FREECOM
+#include "freecom.h"
+#endif
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/malloc.h>
+#include <linux/config.h>
/* Some informational data */
MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
@@ -213,8 +216,20 @@ static int usb_stor_control_thread(void * __us)
/* reject if target != 0 or if LUN is higher than
* the maximum known LUN
*/
- if (us->srb->target || (us->srb->lun > us->max_lun)) {
- US_DEBUGP("Bad device number (%d/%d)\n",
+ if (us->srb->target &&
+ !(us->flags & US_FL_SCM_MULT_TARG)) {
+ US_DEBUGP("Bad target number (%d/%d)\n",
+ us->srb->target, us->srb->lun);
+ us->srb->result = DID_BAD_TARGET << 16;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ us->srb->scsi_done(us->srb);
+ us->srb = NULL;
+ break;
+ }
+
+ if (us->srb->lun > us->max_lun) {
+ US_DEBUGP("Bad LUN (%d/%d)\n",
us->srb->target, us->srb->lun);
us->srb->result = DID_BAD_TARGET << 16;
@@ -314,6 +329,19 @@ static int usb_stor_control_thread(void * __us)
* are free to use as many characters as you like.
*/
+int euscsi_init(struct us_data *us)
+{
+ unsigned char bar = 0x1;
+ int result;
+
+ US_DEBUGP("Attempting to init eUSCSI bridge...\n");
+ result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
+ 0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR,
+ 0x01, 0x0, &bar, 0x1, 5*HZ);
+ US_DEBUGP("-- result is %d\n", result);
+ US_DEBUGP("-- bar afterwards is %d\n", bar);
+}
+
static struct us_unusual_dev us_unusual_dev_list[] = {
{ 0x03f0, 0x0107, 0x0200, 0x0200,
@@ -339,15 +367,61 @@ static struct us_unusual_dev us_unusual_dev_list[] = {
{ 0x04e6, 0x0002, 0x0100, 0x0100,
"Shuttle",
"eUSCSI Bridge",
- US_SC_SCSI, US_PR_BULK, NULL,
- 0 },
+ US_SC_SCSI, US_PR_BULK, euscsi_init,
+ US_FL_SCM_MULT_TARG },
+
+#ifdef CONFIG_USB_STORAGE_SDDR09
+ { 0x04e6, 0x0003, 0x0000, 0x9999,
+ "Sandisk",
+ "ImageMate SDDR09",
+ US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
+ US_FL_SINGLE_LUN | US_FL_START_STOP },
+#endif
+
+#ifdef CONFIG_USB_STORAGE_DPCM
+ { 0x0436, 0x0005, 0x0100, 0x0100,
+ "Microtech",
+ "CameraMate (DPCM_USB)",
+ US_SC_SCSI, US_PR_DPCM_USB, NULL,
+ US_FL_START_STOP },
+#endif
- { 0x04e6, 0x0006, 0x0100, 0x0100,
+ { 0x04e6, 0x0006, 0x0100, 0x0200,
"Shuttle",
"eUSB MMC Adapter",
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN},
+ { 0x04e6, 0x0009, 0x0200, 0x0200,
+ "Shuttle",
+ "ATA/ATAPI Bridge",
+ US_SC_8020, US_PR_CB, NULL,
+ US_FL_SINGLE_LUN},
+
+ { 0x04e6, 0x000A, 0x0200, 0x0200,
+ "Shuttle",
+ "Compact Flash Reader",
+ US_SC_8020, US_PR_CB, NULL,
+ US_FL_SINGLE_LUN},
+
+ { 0x04e6, 0x000B, 0x0100, 0x0100,
+ "Shuttle",
+ "eUSCSI Bridge",
+ US_SC_SCSI, US_PR_BULK, euscsi_init,
+ US_FL_SCM_MULT_TARG },
+
+ { 0x04e6, 0x000C, 0x0100, 0x0100,
+ "Shuttle",
+ "eUSCSI Bridge",
+ US_SC_SCSI, US_PR_BULK, euscsi_init,
+ US_FL_SCM_MULT_TARG },
+
+ { 0x04e6, 0x0101, 0x0200, 0x0200,
+ "Shuttle",
+ "CD-RW Device",
+ US_SC_8020, US_PR_CB, NULL,
+ US_FL_SINGLE_LUN},
+
{ 0x054c, 0x0010, 0x0210, 0x0210,
"Sony",
"DSC-S30/S70",
@@ -372,6 +446,24 @@ static struct us_unusual_dev us_unusual_dev_list[] = {
US_SC_UFI, US_PR_CBI, NULL,
US_FL_SINGLE_LUN},
+ { 0x059f, 0xa601, 0x0200, 0x0200,
+ "LaCie",
+ "USB Hard Disk",
+ US_SC_RBC, US_PR_CB, NULL,
+ 0 },
+
+ { 0x05ab, 0x0031, 0x0100, 0x0100,
+ "In-System",
+ "USB/IDE Bridge",
+ US_SC_8070, US_PR_BULK, NULL,
+ 0 },
+
+ { 0x0693, 0x0005, 0x0100, 0x0100,
+ "Hagiwara",
+ "Flashgate",
+ US_SC_SCSI, US_PR_BULK, NULL,
+ 0 },
+
{ 0x0693, 0x0002, 0x0100, 0x0100,
"Hagiwara",
"FlashGate SmartMedia",
@@ -401,14 +493,21 @@ static struct us_unusual_dev us_unusual_dev_list[] = {
{ 0x07af, 0x0004, 0x0100, 0x0100,
"Microtech",
"USB-SCSI-DB25",
- US_SC_SCSI, US_PR_BULK, NULL,
- 0 },
+ US_SC_SCSI, US_PR_BULK, euscsi_init,
+ US_FL_SCM_MULT_TARG },
+
+#ifdef CONFIG_USB_STORAGE_FREECOM
+ { 0x07ab, 0xfc01, 0x0921, 0x0921,
+ "Freecom",
+ "USB-IDE",
+ US_SC_8070, US_PR_FREECOM, NULL, US_FL_SINGLE_LUN },
+#endif
- { 0x059f, 0xa601, 0x0200, 0x0200,
- "LaCie",
- "USB Hard Disk",
- US_SC_RBC, US_PR_CB, NULL,
- 0 },
+ { 0x07af, 0x0005, 0x0100, 0x0100,
+ "Microtech",
+ "USB-SCSI-HD50",
+ US_SC_SCSI, US_PR_BULK, euscsi_init,
+ US_FL_SCM_MULT_TARG },
#ifdef CONFIG_USB_STORAGE_DPCM
{ 0x07af, 0x0006, 0x0100, 0x0100,
@@ -417,25 +516,6 @@ static struct us_unusual_dev us_unusual_dev_list[] = {
US_SC_SCSI, US_PR_DPCM_USB, NULL,
US_FL_START_STOP },
#endif
-
- { 0x07af, 0x0005, 0x0100, 0x0100,
- "Microtech",
- "USB-SCSI-HD50",
- US_SC_SCSI, US_PR_BULK, NULL,
- 0 },
-
- { 0x05ab, 0x0031, 0x0100, 0x0100,
- "In-System",
- "USB/IDE Bridge",
- US_SC_8070, US_PR_BULK, NULL,
- 0 },
-
- { 0x0693, 0x0005, 0x0100, 0x0100,
- "Hagiwara",
- "Flashgate",
- US_SC_SCSI, US_PR_BULK, NULL,
- 0 },
-
{ 0 }
};
@@ -615,15 +695,10 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
/* set the interface -- STALL is an acceptable response here */
#ifdef CONFIG_USB_STORAGE_SDDR09
- if (protocol != US_PR_EUSB_SDDR09)
- result = usb_set_interface(dev,
- altsetting->bInterfaceNumber, 0);
- else
+ if (protocol == US_PR_EUSB_SDDR09)
result = usb_set_configuration(dev, 1);
-#else
- result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0);
-#endif
- US_DEBUGP("Result from usb_set_interface is %d\n", result);
+
+ US_DEBUGP("Result from usb_set_configuration is %d\n", result);
if (result == -EPIPE) {
US_DEBUGP("-- clearing stall on control interface\n");
usb_clear_halt(dev, usb_sndctrlpipe(dev, 0));
@@ -632,6 +707,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
US_DEBUGP("-- Unknown error. Rejecting device\n");
return NULL;
}
+#endif
/* Do some basic sanity checks, and bail if we find a problem */
if (!ep_in || !ep_out || (protocol == US_PR_CBI && !ep_int)) {
@@ -702,7 +778,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
/* Re-Initialize the device if it needs it */
if (unusual_dev && unusual_dev->initFunction)
- (*unusual_dev->initFunction)(ss);
+ (unusual_dev->initFunction)(ss);
} else {
/* New device -- allocate memory and initialize */
@@ -828,6 +904,15 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
ss->max_lun = 1;
break;
#endif
+
+#ifdef CONFIG_USB_STORAGE_FREECOM
+ case US_PR_FREECOM:
+ ss->transport_name = "Freecom";
+ ss->transport = freecom_transport;
+ ss->transport_reset = usb_stor_freecom_reset;
+ ss->max_lun = 0;
+ break;
+#endif
default:
ss->transport_name = "Unknown";
@@ -909,7 +994,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
/* Just before we start our control thread, initialize
* the device if it needs initialization */
if (unusual_dev && unusual_dev->initFunction)
- (*unusual_dev->initFunction)(ss);
+ (unusual_dev->initFunction)(ss);
/* start up our control thread */
ss->pid = kernel_thread(usb_stor_control_thread, ss,
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index 435ad9777..38b0d420a 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -1,9 +1,9 @@
/* Driver for USB Mass Storage compliant devices
* Main Header File
*
- * $Id: usb.h,v 1.7 2000/08/15 00:06:38 mdharm Exp $
+ * $Id: usb.h,v 1.8 2000/08/25 00:13:51 mdharm Exp $
*
- * Current development and maintainance by:
+ * Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
* Initial work by:
diff --git a/fs/exec.c b/fs/exec.c
index c0df3a68b..f0c64b43a 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -496,6 +496,27 @@ static inline void flush_old_files(struct files_struct * files)
write_unlock(&files->file_lock);
}
+/*
+ * An execve() will automatically "de-thread" the process.
+ * Note: we don't have to hold the tasklist_lock to test
+ * whether we migth need to do this. If we're not part of
+ * a thread group, there is no way we can become one
+ * dynamically. And if we are, we only need to protect the
+ * unlink - even if we race with the last other thread exit,
+ * at worst the list_del_init() might end up being a no-op.
+ */
+static inline void de_thread(struct task_struct *tsk)
+{
+ if (!list_empty(&tsk->thread_group)) {
+ write_lock_irq(&tasklist_lock);
+ list_del_init(&tsk->thread_group);
+ write_unlock_irq(&tasklist_lock);
+ }
+
+ /* Minor oddity: this might stay the same. */
+ tsk->tgid = tsk->pid;
+}
+
int flush_old_exec(struct linux_binprm * bprm)
{
char * name;
@@ -534,6 +555,8 @@ int flush_old_exec(struct linux_binprm * bprm)
flush_thread();
+ de_thread(current);
+
if (bprm->e_uid != current->euid || bprm->e_gid != current->egid ||
permission(bprm->file->f_dentry->d_inode,MAY_READ))
current->dumpable = 0;
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index 24e616396..f1c9099bc 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -16,6 +16,7 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/highuid.h>
+#include <linux/vmalloc.h>
#include <linux/ncp_fs.h>
@@ -25,6 +26,8 @@
#define NCP_OBJECT_NAME_MAX_LEN 4096
/* maximum limit for ncp_privatedata_ioctl */
#define NCP_PRIVATE_DATA_MAX_LEN 8192
+/* maximum negotiable packet size */
+#define NCP_PACKET_SIZE_INTERNAL 65536
int ncp_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
@@ -50,11 +53,11 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
NCP_PACKET_SIZE - sizeof(struct ncp_request_header))) {
return -EINVAL;
}
- bouncebuffer = kmalloc(NCP_PACKET_SIZE, GFP_NFS);
+ bouncebuffer = vmalloc(NCP_PACKET_SIZE_INTERNAL);
if (!bouncebuffer)
return -ENOMEM;
if (copy_from_user(bouncebuffer, request.data, request.size)) {
- kfree(bouncebuffer);
+ vfree(bouncebuffer);
return -EFAULT;
}
ncp_lock_server(server);
@@ -67,7 +70,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
memcpy(server->packet, bouncebuffer, request.size);
result = ncp_request2(server, request.function,
- bouncebuffer, NCP_PACKET_SIZE);
+ bouncebuffer, NCP_PACKET_SIZE_INTERNAL);
if (result < 0)
result = -EIO;
else
@@ -78,7 +81,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
if (result >= 0)
if (copy_to_user(request.data, bouncebuffer, result))
result = -EFAULT;
- kfree(bouncebuffer);
+ vfree(bouncebuffer);
return result;
case NCP_IOC_CONN_LOGGED_IN:
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 708951949..b063860ee 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -445,7 +445,7 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent)
memset(mnt, 0, sizeof(struct smb_mount_data_kernel));
strncpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT,
SMB_NLS_MAXNAMELEN);
- strncpy(mnt->codepage.local_name, CONFIG_SMB_NLS_REMOTE,
+ strncpy(mnt->codepage.remote_name, CONFIG_SMB_NLS_REMOTE,
SMB_NLS_MAXNAMELEN);
if (ver == SMB_MOUNT_OLDVERSION) {
diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c
index a8de0def8..48515aa5f 100644
--- a/fs/umsdos/emd.c
+++ b/fs/umsdos/emd.c
@@ -142,7 +142,7 @@ int umsdos_emd_dir_readentry (struct dentry *demd, loff_t *pos, struct umsdos_di
recsize = umsdos_evalrecsize(p->name_len);
if (offs + recsize > PAGE_CACHE_SIZE) {
struct page *page2;
- int part = (page_address(page) + PAGE_CACHE_SIZE) - p->spare;
+ int part = (char *)(page_address(page) + PAGE_CACHE_SIZE) - p->spare;
page2 = read_cache_page(mapping, 1+(*pos>>PAGE_CACHE_SHIFT),
(filler_t*)mapping->a_ops->readpage, NULL);
if (IS_ERR(page2)) {
@@ -261,7 +261,7 @@ int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info,
p->rdev = cpu_to_le16(entry->rdev);
p->mode = cpu_to_le16(entry->mode);
memcpy(p->name,entry->name,
- (page_address(page) + PAGE_CACHE_SIZE) - p->spare);
+ (char *)(page_address(page) + PAGE_CACHE_SIZE) - p->spare);
memcpy(page_address(page2),
entry->spare+PAGE_CACHE_SIZE-offs,
offs+info->recsize-PAGE_CACHE_SIZE);
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index a3b897378..89054f8fe 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -62,7 +62,6 @@ extern inline unsigned long _page_hashfn(struct address_space * mapping, unsigne
#define s(x) ((x)+((x)>>PAGE_HASH_BITS))
return s(i+index) & (PAGE_HASH_SIZE-1);
#undef i
-#undef o
#undef s
}
diff --git a/include/linux/sched.h b/include/linux/sched.h
index db6ec43cd..4357bb6fe 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -38,6 +38,7 @@ extern unsigned long event;
#define CLONE_PTRACE 0x00002000 /* set if we want to let tracing continue on the child too */
#define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */
#define CLONE_PARENT 0x00008000 /* set if we want to have the same parent as the cloner */
+#define CLONE_THREAD 0x00010000 /* set if we want to clone the "thread group" */
/*
* These are the constant used to fake the fixed-point load-average
@@ -311,6 +312,7 @@ struct task_struct {
pid_t pgrp;
pid_t tty_old_pgrp;
pid_t session;
+ pid_t tgid;
/* boolean value for session group leader */
int leader;
/*
@@ -319,6 +321,7 @@ struct task_struct {
* p->p_pptr->pid)
*/
struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
+ struct list_head thread_group;
/* PID hash table linkage. */
struct task_struct *pidhash_next;
@@ -435,6 +438,7 @@ struct task_struct {
prev_task: &tsk, \
p_opptr: &tsk, \
p_pptr: &tsk, \
+ thread_group: LIST_HEAD_INIT(tsk.thread_group), \
wait_chldexit: __WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\
real_timer: { \
function: it_real_fn \
@@ -558,8 +562,8 @@ extern int force_sig_info(int, struct siginfo *, struct task_struct *);
extern int kill_pg_info(int, struct siginfo *, pid_t);
extern int kill_sl_info(int, struct siginfo *, pid_t);
extern int kill_proc_info(int, struct siginfo *, pid_t);
-extern int kill_something_info(int, struct siginfo *, int);
extern void notify_parent(struct task_struct *, int);
+extern void do_notify_parent(struct task_struct *, int);
extern void force_sig(int, struct task_struct *);
extern int send_sig(int, struct task_struct *, int);
extern int kill_pg(pid_t, int, int);
@@ -800,6 +804,8 @@ do { \
#define for_each_task(p) \
for (p = &init_task ; (p = p->next_task) != &init_task ; )
+#define next_thread(p) \
+ list_entry((p)->thread_group.next, struct task_struct, thread_group)
static inline void del_from_runqueue(struct task_struct * p)
{
@@ -820,6 +826,7 @@ static inline void unhash_process(struct task_struct *p)
nr_threads--;
unhash_pid(p);
REMOVE_LINKS(p);
+ list_del(&p->thread_group);
write_unlock_irq(&tasklist_lock);
}
diff --git a/include/linux/wait.h b/include/linux/wait.h
index 222923aca..a3687bf53 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -4,8 +4,9 @@
#define WNOHANG 0x00000001
#define WUNTRACED 0x00000002
-#define __WALL 0x40000000
-#define __WCLONE 0x80000000
+#define __WNOTHREAD 0x20000000 /* Don't wait on children of other threads in this group */
+#define __WALL 0x40000000 /* Wait on all children, regardless of type */
+#define __WCLONE 0x80000000 /* Wait only on non-SIGCHLD children */
#ifdef __KERNEL__
@@ -184,7 +185,7 @@ extern inline void __add_wait_queue_tail(wait_queue_head_t *head,
if (!head->task_list.next || !head->task_list.prev)
WQ_BUG();
#endif
- list_add(&new->task_list, head->task_list.prev);
+ list_add_tail(&new->task_list, &head->task_list);
}
extern inline void __remove_wait_queue(wait_queue_head_t *head,
diff --git a/kernel/exit.c b/kernel/exit.c
index 74d2cf5f1..6eb4d568a 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -144,17 +144,29 @@ static inline int has_stopped_jobs(int pgrp)
return retval;
}
+/*
+ * When we die, we re-parent all our children.
+ * Try to give them to another thread in our process
+ * group, and if no such member exists, give it to
+ * the global child reaper process (ie "init")
+ */
static inline void forget_original_parent(struct task_struct * father)
{
- struct task_struct * p;
+ struct task_struct * p, *reaper;
read_lock(&tasklist_lock);
+
+ /* Next in our thread group */
+ reaper = next_thread(father);
+ if (reaper == father)
+ reaper = child_reaper;
+
for_each_task(p) {
if (p->p_opptr == father) {
/* We dont want people slaying init */
p->exit_signal = SIGCHLD;
p->self_exec_id++;
- p->p_opptr = child_reaper; /* init */
+ p->p_opptr = reaper;
if (p->pdeath_signal) send_sig(p->pdeath_signal, p, 0);
}
}
@@ -378,7 +390,6 @@ static void exit_notify(void)
&& !capable(CAP_KILL))
current->exit_signal = SIGCHLD;
- notify_parent(current, current->exit_signal);
/*
* This loop does two things:
@@ -390,6 +401,7 @@ static void exit_notify(void)
*/
write_lock_irq(&tasklist_lock);
+ do_notify_parent(current, current->exit_signal);
while (current->p_cptr != NULL) {
p = current->p_cptr;
current->p_cptr = p->p_osptr;
@@ -402,7 +414,7 @@ static void exit_notify(void)
p->p_osptr->p_ysptr = p;
p->p_pptr->p_cptr = p;
if (p->state == TASK_ZOMBIE)
- notify_parent(p, p->exit_signal);
+ do_notify_parent(p, p->exit_signal);
/*
* process group orphan check
* Case ii: Our child is in a different pgrp
@@ -483,9 +495,9 @@ asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struc
{
int flag, retval;
DECLARE_WAITQUEUE(wait, current);
- struct task_struct *p;
+ struct task_struct *tsk;
- if (options & ~(WNOHANG|WUNTRACED|__WCLONE|__WALL))
+ if (options & ~(WNOHANG|WUNTRACED|__WNOTHREAD|__WCLONE|__WALL))
return -EINVAL;
add_wait_queue(&current->wait_chldexit,&wait);
@@ -493,27 +505,30 @@ repeat:
flag = 0;
current->state = TASK_INTERRUPTIBLE;
read_lock(&tasklist_lock);
- for (p = current->p_cptr ; p ; p = p->p_osptr) {
- if (pid>0) {
- if (p->pid != pid)
- continue;
- } else if (!pid) {
- if (p->pgrp != current->pgrp)
- continue;
- } else if (pid != -1) {
- if (p->pgrp != -pid)
+ tsk = current;
+ do {
+ struct task_struct *p;
+ for (p = tsk->p_cptr ; p ; p = p->p_osptr) {
+ if (pid>0) {
+ if (p->pid != pid)
+ continue;
+ } else if (!pid) {
+ if (p->pgrp != current->pgrp)
+ continue;
+ } else if (pid != -1) {
+ if (p->pgrp != -pid)
+ continue;
+ }
+ /* Wait for all children (clone and not) if __WALL is set;
+ * otherwise, wait for clone children *only* if __WCLONE is
+ * set; otherwise, wait for non-clone children *only*. (Note:
+ * A "clone" child here is one that reports to its parent
+ * using a signal other than SIGCHLD.) */
+ if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
+ && !(options & __WALL))
continue;
- }
- /* Wait for all children (clone and not) if __WALL is set;
- * otherwise, wait for clone children *only* if __WCLONE is
- * set; otherwise, wait for non-clone children *only*. (Note:
- * A "clone" child here is one that reports to its parent
- * using a signal other than SIGCHLD.) */
- if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
- && !(options & __WALL))
- continue;
- flag = 1;
- switch (p->state) {
+ flag = 1;
+ switch (p->state) {
case TASK_STOPPED:
if (!p->exit_code)
continue;
@@ -543,15 +558,19 @@ repeat:
REMOVE_LINKS(p);
p->p_pptr = p->p_opptr;
SET_LINKS(p);
+ do_notify_parent(p, SIGCHLD);
write_unlock_irq(&tasklist_lock);
- notify_parent(p, SIGCHLD);
} else
release(p);
goto end_wait4;
default:
continue;
+ }
}
- }
+ if (options & __WNOTHREAD)
+ break;
+ tsk = next_thread(tsk);
+ } while (tsk != current);
read_unlock(&tasklist_lock);
if (flag) {
retval = 0;
diff --git a/kernel/fork.c b/kernel/fork.c
index 4ab0976b1..64dd0f995 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -661,7 +661,13 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
* Let it rip!
*/
retval = p->pid;
+ p->tgid = retval;
+ INIT_LIST_HEAD(&p->thread_group);
write_lock_irq(&tasklist_lock);
+ if (clone_flags & CLONE_THREAD) {
+ p->tgid = current->tgid;
+ list_add(&p->thread_group, &current->thread_group);
+ }
SET_LINKS(p);
hash_pid(p);
nr_threads++;
diff --git a/kernel/sched.c b/kernel/sched.c
index fda8b5eea..8b47b558a 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -455,17 +455,35 @@ signed long schedule_timeout(signed long timeout)
static inline void __schedule_tail(struct task_struct *prev)
{
#ifdef CONFIG_SMP
- if ((prev->state == TASK_RUNNING) &&
- (prev != idle_task(smp_processor_id()))) {
- unsigned long flags;
-
- spin_lock_irqsave(&runqueue_lock, flags);
- prev->has_cpu = 0;
- reschedule_idle(prev, flags); // spin_unlocks runqueue
- } else {
- wmb();
- prev->has_cpu = 0;
- }
+ unsigned long flags;
+
+ /*
+ * fast path falls through. We have to take the runqueue lock
+ * unconditionally to make sure that the test of prev->state
+ * and setting has_cpu is atomic wrt. interrupts. It's not
+ * a big problem in the common case because we recently took
+ * the runqueue lock so it's likely to be in this processor's
+ * cache.
+ */
+ spin_lock_irqsave(&runqueue_lock, flags);
+ prev->has_cpu = 0;
+ if (prev->state == TASK_RUNNING)
+ goto running_again;
+out_unlock:
+ spin_unlock_irqrestore(&runqueue_lock, flags);
+ return;
+
+ /*
+ * Slow path - we 'push' the previous process and
+ * reschedule_idle() will attempt to find a new
+ * processor for it. (but it might preempt the
+ * current process as well.)
+ */
+running_again:
+ if (prev == idle_task(smp_processor_id()))
+ goto out_unlock;
+ reschedule_idle(prev, flags); // spin_unlocks runqueue
+ return;
#endif /* CONFIG_SMP */
}
diff --git a/kernel/signal.c b/kernel/signal.c
index b64225778..7b256a954 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -180,7 +180,7 @@ printk("SIG dequeue (%s:%d): %d ", current->comm, current->pid,
if (!(current->notifier)(current->notifier_data)) {
current->sigpending = 0;
return 0;
- }
+ }
}
}
@@ -288,6 +288,18 @@ static int rm_sig_from_queue(int sig, struct task_struct *t)
}
/*
+ * Bad permissions for sending the signal
+ */
+int bad_signal(int sig, struct siginfo *info, struct task_struct *t)
+{
+ return (!info || ((unsigned long)info != 1 && SI_FROMUSER(info)))
+ && ((sig != SIGCONT) || (current->session != t->session))
+ && (current->euid ^ t->suid) && (current->euid ^ t->uid)
+ && (current->uid ^ t->suid) && (current->uid ^ t->uid)
+ && !capable(CAP_KILL);
+}
+
+/*
* Determine whether a signal should be posted or not.
*
* Signals with SIG_IGN can be ignored, except for the
@@ -328,37 +340,13 @@ static int ignored_signal(int sig, struct task_struct *t)
return 1;
}
-int
-send_sig_info(int sig, struct siginfo *info, struct task_struct *t)
+/*
+ * Handle TASK_STOPPED.
+ * Also, return true for the unblockable signals that we
+ * should deliver to all threads..
+ */
+static void handle_stop_signal(int sig, struct task_struct *t)
{
- unsigned long flags;
- int ret;
- struct signal_queue *q = 0;
-
-
-#if DEBUG_SIG
-printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
-#endif
-
- ret = -EINVAL;
- if (sig < 0 || sig > _NSIG)
- goto out_nolock;
- /* The somewhat baroque permissions check... */
- ret = -EPERM;
- if ((!info || ((unsigned long)info != 1 && SI_FROMUSER(info)))
- && ((sig != SIGCONT) || (current->session != t->session))
- && (current->euid ^ t->suid) && (current->euid ^ t->uid)
- && (current->uid ^ t->suid) && (current->uid ^ t->uid)
- && !capable(CAP_KILL))
- goto out_nolock;
-
- /* The null signal is a permissions and process existance probe.
- No signal is actually delivered. Same goes for zombies. */
- ret = 0;
- if (!sig || !t->sig)
- goto out_nolock;
-
- spin_lock_irqsave(&t->sigmask_lock, flags);
switch (sig) {
case SIGKILL: case SIGCONT:
/* Wake up the process if stopped. */
@@ -377,19 +365,12 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
recalc_sigpending(t);
break;
}
+ return 0;
+}
- /* Optimize away the signal, if it's a signal that can be
- handled immediately (ie non-blocked and untraced) and
- that is ignored (either explicitly or by default). */
-
- if (ignored_signal(sig, t))
- goto out;
-
- /* Support queueing exactly one non-rt signal, so that we
- can get more detailed information about the cause of
- the signal. */
- if (sig < SIGRTMIN && sigismember(&t->signal, sig))
- goto out;
+static int deliver_signal(int sig, struct siginfo *info, struct task_struct *t)
+{
+ struct signal_queue * q = NULL;
/* Real-time signals must be queued if sent by sigqueue, or
some other real-time mechanism. It is implementation
@@ -400,8 +381,7 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
pass on the info struct. */
if (atomic_read(&nr_queued_signals) < max_queued_signals) {
- q = (struct signal_queue *)
- kmem_cache_alloc(signal_queue_cachep, GFP_ATOMIC);
+ q = kmem_cache_alloc(signal_queue_cachep, GFP_ATOMIC);
}
if (q) {
@@ -434,8 +414,7 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
* Queue overflow, abort. We may abort if the signal was rt
* and sent by user using something other than kill().
*/
- ret = -EAGAIN;
- goto out;
+ return -EAGAIN;
}
sigaddset(&t->signal, sig);
@@ -460,12 +439,118 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
spin_unlock(&runqueue_lock);
#endif /* CONFIG_SMP */
}
+ return 0;
+}
+
+
+/*
+ * Send a thread-group-wide signal.
+ *
+ * Rule: SIGSTOP and SIGKILL get delivered to _everybody_.
+ *
+ * Others get delivered to the thread that doesn't have them
+ * blocked (just one such thread).
+ *
+ * If all threads have it blocked, it gets delievered to the
+ * thread group leader.
+ */
+static int send_tg_sig_info(int sig, struct siginfo *info, struct task_struct *p)
+{
+ int retval = 0;
+ struct task_struct *tsk;
+
+ if (sig < 0 || sig > _NSIG)
+ return -EINVAL;
+
+ if (bad_signal(sig, info, p))
+ return -EPERM;
+
+ if (!sig)
+ return 0;
+
+ tsk = p;
+ do {
+ unsigned long flags;
+ tsk = next_thread(tsk);
+
+ /* Zombie? Ignore */
+ if (!tsk->sig)
+ continue;
+
+ spin_lock_irqsave(&tsk->sigmask_lock, flags);
+ handle_stop_signal(sig, tsk);
+
+ /* Is the signal ignored by this thread? */
+ if (ignored_signal(sig, tsk))
+ goto next;
+
+ /* Have we already delivered this non-queued signal? */
+ if (sig < SIGRTMIN && sigismember(&tsk->signal, sig))
+ goto next;
+
+ /* Not blocked? Go, girl, go! */
+ if (tsk == p || !sigismember(&tsk->blocked, sig)) {
+ retval = deliver_signal(sig, info, tsk);
+
+ /* Signals other than SIGKILL and SIGSTOP have "once" semantics */
+ if (sig != SIGKILL && sig != SIGSTOP)
+ tsk = p;
+ }
+next:
+ spin_unlock_irqrestore(&tsk->sigmask_lock, flags);
+ if ((tsk->state & TASK_INTERRUPTIBLE) && signal_pending(tsk))
+ wake_up_process(tsk);
+ } while (tsk != p);
+ return retval;
+}
+
+
+int
+send_sig_info(int sig, struct siginfo *info, struct task_struct *t)
+{
+ unsigned long flags;
+ int ret;
+
+
+#if DEBUG_SIG
+printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
+#endif
+
+ ret = -EINVAL;
+ if (sig < 0 || sig > _NSIG)
+ goto out_nolock;
+ /* The somewhat baroque permissions check... */
+ ret = -EPERM;
+ if (bad_signal(sig, info, t))
+ goto out_nolock;
+
+ /* The null signal is a permissions and process existance probe.
+ No signal is actually delivered. Same goes for zombies. */
+ ret = 0;
+ if (!sig || !t->sig)
+ goto out_nolock;
+
+ spin_lock_irqsave(&t->sigmask_lock, flags);
+ handle_stop_signal(sig, t);
+
+ /* Optimize away the signal, if it's a signal that can be
+ handled immediately (ie non-blocked and untraced) and
+ that is ignored (either explicitly or by default). */
+
+ if (ignored_signal(sig, t))
+ goto out;
+
+ /* Support queueing exactly one non-rt signal, so that we
+ can get more detailed information about the cause of
+ the signal. */
+ if (sig < SIGRTMIN && sigismember(&t->signal, sig))
+ goto out;
+ ret = deliver_signal(sig, info, t);
out:
spin_unlock_irqrestore(&t->sigmask_lock, flags);
- if ((t->state & TASK_INTERRUPTIBLE) && signal_pending(t))
- wake_up_process(t);
-
+ if ((t->state & TASK_INTERRUPTIBLE) && signal_pending(t))
+ wake_up_process(t);
out_nolock:
#if DEBUG_SIG
printk(" %d -> %d\n", signal_pending(t), ret);
@@ -510,22 +595,17 @@ kill_pg_info(int sig, struct siginfo *info, pid_t pgrp)
int retval = -EINVAL;
if (pgrp > 0) {
struct task_struct *p;
- int found = 0;
retval = -ESRCH;
read_lock(&tasklist_lock);
for_each_task(p) {
if (p->pgrp == pgrp) {
int err = send_sig_info(sig, info, p);
- if (err != 0)
+ if (retval)
retval = err;
- else
- found++;
}
}
read_unlock(&tasklist_lock);
- if (found)
- retval = 0;
}
return retval;
}
@@ -542,22 +622,17 @@ kill_sl_info(int sig, struct siginfo *info, pid_t sess)
int retval = -EINVAL;
if (sess > 0) {
struct task_struct *p;
- int found = 0;
retval = -ESRCH;
read_lock(&tasklist_lock);
for_each_task(p) {
if (p->leader && p->session == sess) {
int err = send_sig_info(sig, info, p);
- if (err)
+ if (retval)
retval = err;
- else
- found++;
}
}
read_unlock(&tasklist_lock);
- if (found)
- retval = 0;
}
return retval;
}
@@ -577,6 +652,33 @@ kill_proc_info(int sig, struct siginfo *info, pid_t pid)
return error;
}
+
+/*
+ * Send a signal to a thread group..
+ *
+ * If the pid is the thread group ID, we consider this
+ * a "thread group" signal. Otherwise it degenerates into
+ * a thread-specific signal.
+ */
+static int kill_tg_info(int sig, struct siginfo *info, pid_t pid)
+{
+ int error;
+ struct task_struct *p;
+
+ read_lock(&tasklist_lock);
+ p = find_task_by_pid(pid);
+ error = -ESRCH;
+ if (p) {
+ /* Is it the leader? Otherwise it degenerates into a per-thread thing */
+ if (p->tgid == pid)
+ error = send_tg_sig_info(sig, info, p);
+ else
+ error = send_sig_info(sig, info, p);
+ }
+ read_unlock(&tasklist_lock);
+ return error;
+}
+
/*
* kill_something_info() interprets pid in interesting ways just like kill(2).
*
@@ -584,8 +686,7 @@ kill_proc_info(int sig, struct siginfo *info, pid_t pid)
* is probably wrong. Should make it like BSD or SYSV.
*/
-int
-kill_something_info(int sig, struct siginfo *info, int pid)
+static int kill_something_info(int sig, struct siginfo *info, int pid)
{
if (!pid) {
return kill_pg_info(sig, info, current->pgrp);
@@ -607,7 +708,7 @@ kill_something_info(int sig, struct siginfo *info, int pid)
} else if (pid < 0) {
return kill_pg_info(sig, info, -pid);
} else {
- return kill_proc_info(sig, info, pid);
+ return kill_tg_info(sig, info, pid);
}
}
@@ -646,11 +747,24 @@ kill_proc(pid_t pid, int sig, int priv)
}
/*
+ * Joy. Or not. Pthread wants us to wake up every thread
+ * in our parent group.
+ */
+static void wake_up_parent(struct task_struct *parent)
+{
+ struct task_struct *tsk = parent;
+
+ do {
+ wake_up_interruptible(&tsk->wait_chldexit);
+ tsk = next_thread(tsk);
+ } while (tsk != parent);
+}
+
+/*
* Let a parent know about a status change of a child.
*/
-void
-notify_parent(struct task_struct *tsk, int sig)
+void do_notify_parent(struct task_struct *tsk, int sig)
{
struct siginfo info;
int why, status;
@@ -694,7 +808,23 @@ notify_parent(struct task_struct *tsk, int sig)
info.si_status = status;
send_sig_info(sig, &info, tsk->p_pptr);
- wake_up_interruptible(&tsk->p_pptr->wait_chldexit);
+ wake_up_parent(tsk->p_pptr);
+}
+
+
+/*
+ * We need the tasklist lock because it's the only
+ * thing that protects out "parent" pointer.
+ *
+ * exit.c calls "do_notify_parent()" directly, because
+ * it already has the tasklist lock.
+ */
+void
+notify_parent(struct task_struct *tsk, int sig)
+{
+ read_lock(&tasklist_lock);
+ do_notify_parent(tsk, sig);
+ read_unlock(&tasklist_lock);
}
EXPORT_SYMBOL(dequeue_signal);
diff --git a/kernel/timer.c b/kernel/timer.c
index 00ab398b4..044ba492e 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -724,7 +724,7 @@ asmlinkage unsigned long sys_alarm(unsigned int seconds)
asmlinkage long sys_getpid(void)
{
/* This is SMP safe - current->pid doesn't change */
- return current->pid;
+ return current->tgid;
}
/*
diff --git a/mm/bootmem.c b/mm/bootmem.c
index fbcb2bb06..0a8d37ba2 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -205,7 +205,7 @@ found:
bdata->last_pos = start+areasize-1;
bdata->last_offset = remaining_size;
}
- bdata->last_offset &= ~PAGE_MASK;
+ bdata->last_offset &= ~PAGE_MASK;
} else {
bdata->last_pos = start + areasize - 1;
bdata->last_offset = size & ~PAGE_MASK;
diff --git a/mm/filemap.c b/mm/filemap.c
index 107f9d8a9..977225432 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -895,7 +895,7 @@ static void generic_file_readahead(int reada_ok,
* page only.
*/
if (PageLocked(page)) {
- if (!filp->f_ralen || index >= raend || index + filp->f_ralen < raend) {
+ if (!filp->f_ralen || index >= raend || index + filp->f_rawin < raend) {
raend = index;
if (raend < end_index)
max_ahead = filp->f_ramax;
@@ -1072,6 +1072,7 @@ found_page:
if (!Page_Uptodate(page))
goto page_not_up_to_date;
+ generic_file_readahead(reada_ok, filp, inode, page);
page_ok:
/*
* Ok, we have the page, and it's up-to-date, so
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index c2a3ea271..e7167aa65 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -632,6 +632,9 @@ int ipgre_rcv(struct sk_buff *skb, unsigned short len)
#ifdef CONFIG_NETFILTER
nf_conntrack_put(skb->nfct);
skb->nfct = NULL;
+#ifdef CONFIG_NETFILTER_DEBUG
+ skb->nf_debug = 0;
+#endif
#endif
ipgre_ecn_decapsulate(iph, skb);
netif_rx(skb);
@@ -858,6 +861,9 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
#ifdef CONFIG_NETFILTER
nf_conntrack_put(skb->nfct);
skb->nfct = NULL;
+#ifdef CONFIG_NETFILTER_DEBUG
+ skb->nf_debug = 0;
+#endif
#endif
IPTUNNEL_XMIT();
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 5792c5de7..3d0e2b4aa 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -5,7 +5,7 @@
*
* The Internet Protocol (IP) output module.
*
- * Version: $Id: ip_output.c,v 1.83 2000/03/25 01:52:08 davem Exp $
+ * Version: $Id: ip_output.c,v 1.84 2000/08/25 02:15:47 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -327,6 +327,7 @@ static inline int ip_queue_xmit2(struct sk_buff *skb)
kfree_skb(skb);
return -EHOSTUNREACH;
}
+ rt = (struct rtable *)skb->dst;
}
#endif
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 02af22ff9..eae29c0b0 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -1,7 +1,7 @@
/*
* Linux NET3: IP/IP protocol decoder.
*
- * Version: $Id: ipip.c,v 1.38 2000/08/02 06:03:59 davem Exp $
+ * Version: $Id: ipip.c,v 1.39 2000/08/25 02:15:47 davem Exp $
*
* Authors:
* Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95
@@ -496,6 +496,9 @@ int ipip_rcv(struct sk_buff *skb, unsigned short len)
#ifdef CONFIG_NETFILTER
nf_conntrack_put(skb->nfct);
skb->nfct = NULL;
+#ifdef CONFIG_NETFILTER_DEBUG
+ skb->nf_debug = 0;
+#endif
#endif
ipip_ecn_decapsulate(iph, skb);
netif_rx(skb);
@@ -639,6 +642,9 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
#ifdef CONFIG_NETFILTER
nf_conntrack_put(skb->nfct);
skb->nfct = NULL;
+#ifdef CONFIG_NETFILTER_DEBUG
+ skb->nf_debug = 0;
+#endif
#endif
IPTUNNEL_XMIT();
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index b77f8789d..59048a22b 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -6,7 +6,7 @@
* Pedro Roque <roque@di.fc.ul.pt>
* Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
*
- * $Id: sit.c,v 1.42 2000/08/02 06:03:59 davem Exp $
+ * $Id: sit.c,v 1.43 2000/08/25 02:15:47 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -401,6 +401,9 @@ int ipip6_rcv(struct sk_buff *skb, unsigned short len)
#ifdef CONFIG_NETFILTER
nf_conntrack_put(skb->nfct);
skb->nfct = NULL;
+#ifdef CONFIG_NETFILTER_DEBUG
+ skb->nf_debug = 0;
+#endif
#endif
ipip6_ecn_decapsulate(iph, skb);
netif_rx(skb);
@@ -567,6 +570,9 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
#ifdef CONFIG_NETFILTER
nf_conntrack_put(skb->nfct);
skb->nfct = NULL;
+#ifdef CONFIG_NETFILTER_DEBUG
+ skb->nf_debug = 0;
+#endif
#endif
IPTUNNEL_XMIT();
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 617519846..990431eb8 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1585,7 +1585,7 @@ static void free_pg_vec(unsigned long *pg_vec, unsigned order, unsigned len)
pend = virt_to_page(pg_vec[i] + (PAGE_SIZE << order) - 1);
for (page = virt_to_page(pg_vec[i]); page <= pend; page++)
- clear_bit(PG_reserved, &page->flags);
+ ClearPageReserved(page);
free_pages(pg_vec[i], order);
}
}
@@ -1640,7 +1640,7 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing
pend = virt_to_page(pg_vec[i] + (PAGE_SIZE << order) - 1);
for (page = virt_to_page(pg_vec[i]); page <= pend; page++)
- set_bit(PG_reserved, &page->flags);
+ SetPageReserved(page);
}
/* Page vector is allocated */
diff --git a/net/socket.c b/net/socket.c
index 015630d2e..5691718c9 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -855,7 +855,7 @@ int sock_create(int family, int type, int protocol, struct socket **res)
net_family_read_lock();
if (net_families[family] == NULL) {
- i = -EINVAL;
+ i = -EAFNOSUPPORT;
goto out;
}
@@ -1710,10 +1710,9 @@ void __init sock_init(void)
* Initialize the protocols module.
*/
- proto_init();
-
register_filesystem(&sock_fs_type);
sock_mnt = kern_mount(&sock_fs_type);
+ proto_init();
/*
* The netlink device handler may be needed early.