Commit 57afa237 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.1.100pre2

parent 5892de9e
This diff is collapsed.
MTRR (Memory Type Range Register) control MTRR (Memory Type Range Register) control
17 Dec 1997 2 May 1998
Richard Gooch Richard Gooch
<rgooch@atnf.csiro.au> <rgooch@atnf.csiro.au>
On Intel Pentium Pro systems the Memory Type Range Registers (MTRRs) On Intel Pentium Pro/Pentium II systems the Memory Type Range
may be used to control processor access to memory ranges. This is Registers (MTRRs) may be used to control processor access to memory
most useful when you have a video (VGA) card on the PCI ranges. This is most useful when you have a video (VGA) card on a
bus. Enabling write-combining allows PCI write transfers to be PCI or AGP bus. Enabling write-combining allows bus write transfers
combined into a larger transfer before bursting over the PCI to be combined into a larger transfer before bursting over the
bus. This can increase performance of image write operations 2.5 PCI/AGP bus. This can increase performance of image write operations
times or more. 2.5 times or more.
The CONFIG_MTRR option creates a /proc/mtrr file which may be used The CONFIG_MTRR option creates a /proc/mtrr file which may be used
to manipulate your MTRRs. Typically the X server should use to manipulate your MTRRs. Typically the X server should use
...@@ -30,13 +30,40 @@ Reading MTRRs from the shell: ...@@ -30,13 +30,40 @@ Reading MTRRs from the shell:
% cat /proc/mtrr % cat /proc/mtrr
reg00: base=0x00000000 ( 0MB), size= 128MB: write-back, count=1 reg00: base=0x00000000 ( 0MB), size= 128MB: write-back, count=1
reg01: base=0x08000000 ( 128MB), size= 64MB: write-back, count=1 reg01: base=0x08000000 ( 128MB), size= 64MB: write-back, count=1
reg05: base=0x80000000 (2048MB), size= 4MB: write-combining, count=1
=============================================================================== ===============================================================================
Creating MTRRs from the shell: Creating MTRRs from the shell:
% echo "base=0x80000000 size=0x400000 type=write-combining" >! /proc/mtrr # echo "base=0xf8000000 size=0x400000 type=write-combining" >! /proc/mtrr
And the result thereof:
% cat /proc/mtrr
reg00: base=0x00000000 ( 0MB), size= 128MB: write-back, count=1
reg01: base=0x08000000 ( 128MB), size= 64MB: write-back, count=1
reg02: base=0xf8000000 (3968MB), size= 4MB: write-combining, count=1
This is for videoram at base address 0xf8000000 and size 4 MBytes. To
find out your base address, you need to look at the output of your X
server, which tells you where the linear framebuffer address is. A
typical line that you may get is:
(--) S3: PCI: 968 rev 0, Linear FB @ 0xf8000000
Note that you should only use the value from the X server, as it may
move the framebuffer base address, so the only value you can trust is
that reported by the X server.
To find out the size of your framebuffer (what, you don't actually
know?), the following line will tell you:
(--) S3: videoram: 4096k
That's 4 MBytes, which is 0x400000 bytes (in hexadecimal).
A patch is being written for XFree86 which will make this automatic:
in other words the X server will manipulate /proc/mtrr using the
ioctl() interface, so users won't have to do anything. If you use a
commercial X server, lobby your vendor to add support for MTRRs.
=============================================================================== ===============================================================================
Removing MTRRs from the shell: Removing MTRRs from the shell:
% echo "disable=5" >! /proc/mtrr % echo "disable=2" >! /proc/mtrr
=============================================================================== ===============================================================================
Reading MTRRs from a C programme using ioctl()'s: Reading MTRRs from a C programme using ioctl()'s:
...@@ -44,7 +71,7 @@ Reading MTRRs from a C programme using ioctl()'s: ...@@ -44,7 +71,7 @@ Reading MTRRs from a C programme using ioctl()'s:
Source file for mtrr-show (example programme to show MTRRs using ioctl()'s) Source file for mtrr-show (example programme to show MTRRs using ioctl()'s)
Copyright (C) 1997 Richard Gooch Copyright (C) 1997-1998 Richard Gooch
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -72,7 +99,7 @@ Reading MTRRs from a C programme using ioctl()'s: ...@@ -72,7 +99,7 @@ Reading MTRRs from a C programme using ioctl()'s:
Written by Richard Gooch 17-DEC-1997 Written by Richard Gooch 17-DEC-1997
Last updated by Richard Gooch 17-DEC-1997 Last updated by Richard Gooch 2-MAY-1998
*/ */
...@@ -84,7 +111,7 @@ Reading MTRRs from a C programme using ioctl()'s: ...@@ -84,7 +111,7 @@ Reading MTRRs from a C programme using ioctl()'s:
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <errno.h> #include <errno.h>
#define MTRR_NEED_STRINGS #define MTRR_NEED_STRINGS
#include <linux/mtrr.h> #include <asm/mtrr.h>
#define TRUE 1 #define TRUE 1
#define FALSE 0 #define FALSE 0
...@@ -130,7 +157,7 @@ Creating MTRRs from a C programme using ioctl()'s: ...@@ -130,7 +157,7 @@ Creating MTRRs from a C programme using ioctl()'s:
Source file for mtrr-add (example programme to add an MTRRs using ioctl()) Source file for mtrr-add (example programme to add an MTRRs using ioctl())
Copyright (C) 1997 Richard Gooch Copyright (C) 1997-1998 Richard Gooch
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -158,7 +185,7 @@ Creating MTRRs from a C programme using ioctl()'s: ...@@ -158,7 +185,7 @@ Creating MTRRs from a C programme using ioctl()'s:
Written by Richard Gooch 17-DEC-1997 Written by Richard Gooch 17-DEC-1997
Last updated by Richard Gooch 17-DEC-1997 Last updated by Richard Gooch 2-MAY-1998
*/ */
...@@ -172,7 +199,7 @@ Creating MTRRs from a C programme using ioctl()'s: ...@@ -172,7 +199,7 @@ Creating MTRRs from a C programme using ioctl()'s:
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <errno.h> #include <errno.h>
#define MTRR_NEED_STRINGS #define MTRR_NEED_STRINGS
#include <linux/mtrr.h> #include <asm/mtrr.h>
#define TRUE 1 #define TRUE 1
#define FALSE 0 #define FALSE 0
......
...@@ -18,6 +18,7 @@ Currently, these files are in /proc/sys/vm: ...@@ -18,6 +18,7 @@ Currently, these files are in /proc/sys/vm:
- bdflush - bdflush
- buffermem - buffermem
- freepages - freepages
- kswapd
- overcommit_memory - overcommit_memory
- pagecache - pagecache
- swapctl - swapctl
...@@ -112,9 +113,58 @@ freepages: ...@@ -112,9 +113,58 @@ freepages:
This file contains the values in the struct freepages. That This file contains the values in the struct freepages. That
struct contains three members: min, low and high. struct contains three members: min, low and high.
These variables are currently unused (?), but they're Although the goal of the Linux memory management subsystem
very likely to be abused for something else in the near is to avoid fragmentation and make large chunks of free
future, so don't yet remove it from the source... memory (so that we can hand out DMA buffers and such), there
still are some page-based limits in the system, mainly to
make sure we don't waste too much memory trying to get large
free area's.
The meaning of the numbers is:
freepages.min When the number of free pages in the system
reaches this number, only the kernel can
allocate more memory.
freepages.low If memory is too fragmented, the swapout
daemon is started, except when the number
of free pages is larger than freepages.low.
freepages.high The swapping daemon exits when memory is
sufficiently defragmented, when the number
of free pages reaches freepages.high or when
it has tried the maximum number of times.
==============================================================
kswapd:
Kswapd is the kernel swapout daemon. That is, kswapd is that
piece of the kernel that frees memory when it get's fragmented
or full. Since every system is different, you'll probably want
some control over this piece of the system.
The numbers in this page correspond to the numbers in the
struct pager_daemon {tries_base, tries_min, swap_cluster
}; The tries_base and swap_cluster probably have the
largest influence on system performance.
tries_base The maximum number of pages kswapd tries to
free in one round is calculated from this
number. Usually this number will be divided
by 4 or 8 (see mm/vmscan.c), so it isn't as
big as it looks.
When you need to increase the bandwith to/from
swap, you'll want to increase this number.
tries_min This is the minimum number of times kswapd
tries to free a page each time it is called.
Basically it's just there to make sure that
kswapd frees some pages even when it's being
called with minimum priority.
swap_cluster This is the number of pages kswapd writes in
one turn. You want this large so that kswapd
does it's I/O in large chunks and the disk
doesn't have to seek often, but you don't want
it to be too large since that would flood the
request queue.
============================================================== ==============================================================
......
/* /*
* bios32.c - Low-Level PCI Access * bios32.c - Low-Level PCI Access
* *
* $Id: bios32.c,v 1.29 1998/04/17 16:31:15 mj Exp $ * $Id: bios32.c,v 1.32 1998/05/02 12:03:05 davem Exp $
* *
* Sponsored by * Sponsored by
* iX Multiuser Multitasking Magazine * iX Multiuser Multitasking Magazine
...@@ -66,6 +66,8 @@ ...@@ -66,6 +66,8 @@
* and cleaned it up... Martin Mares <mj@atrey.karlin.mff.cuni.cz> * and cleaned it up... Martin Mares <mj@atrey.karlin.mff.cuni.cz>
* *
* Feb 6, 1998 : No longer using BIOS to find devices and device classes. [mj] * Feb 6, 1998 : No longer using BIOS to find devices and device classes. [mj]
*
* May 1, 1998 : Support for peer host bridges. [mj]
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -74,6 +76,7 @@ ...@@ -74,6 +76,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/malloc.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/segment.h> #include <asm/segment.h>
...@@ -832,7 +835,10 @@ __initfunc(static struct pci_access *pci_find_bios(void)) ...@@ -832,7 +835,10 @@ __initfunc(static struct pci_access *pci_find_bios(void))
} }
/* /*
* Sort the device list according to PCI BIOS. * Sort the device list according to PCI BIOS. Nasty hack, but since some
* fool forgot to define the `correct' device order in the PCI BIOS specs
* and we want to be (possibly bug-to-bug ;-]) compatible with older kernels
* which used BIOS ordering, we are bound to do this...
*/ */
__initfunc(void pcibios_sort(void)) __initfunc(void pcibios_sort(void))
...@@ -924,11 +930,41 @@ __initfunc(void pcibios_fixup_io_addr(struct pci_dev *dev, int idx)) ...@@ -924,11 +930,41 @@ __initfunc(void pcibios_fixup_io_addr(struct pci_dev *dev, int idx))
} }
/* /*
* Arch-dependent fixups. We need to fix here base addresses, I/O * In case there are peer host bridges, scan bus behind each of them.
* and memory enables and IRQ's as the PCI BIOS'es are buggy as hell. * Although several sources claim that the host bridges should have
* header type 1 and be assigned a bus number as for PCI2PCI bridges,
* the reality doesn't pass this test and the bus number is usually
* hard-wired to 1.
*/ */
__initfunc(void pcibios_fixup_peer_bridges(void))
{
struct pci_dev *dev;
int cnt = 0;
for(dev=pci_root.devices; dev; dev=dev->sibling)
if ((dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) {
DBG("PCI: Host bridge at %02x\n", dev->devfn);
if (cnt) {
struct pci_bus *b = kmalloc(sizeof(struct pci_bus), GFP_KERNEL);
memset(b, 0, sizeof(*b));
b->parent = &pci_root;
b->next = pci_root.next;
pci_root.next = b;
b->self = dev;
b->number = b->secondary = cnt;
b->subordinate = 0xff;
b->subordinate = pci_scan_bus(b);
}
cnt++;
}
}
__initfunc(void pcibios_fixup(void)) /*
* Fix base addresses, I/O and memory enables and IRQ's (mostly work-arounds
* for buggy PCI BIOS'es :-[).
*/
__initfunc(void pcibios_fixup_devices(void))
{ {
struct pci_dev *dev; struct pci_dev *dev;
int i, has_io, has_mem; int i, has_io, has_mem;
...@@ -991,6 +1027,16 @@ __initfunc(void pcibios_fixup(void)) ...@@ -991,6 +1027,16 @@ __initfunc(void pcibios_fixup(void))
if (dev->irq >= NR_IRQS) if (dev->irq >= NR_IRQS)
dev->irq = 0; dev->irq = 0;
} }
}
/*
* Arch-dependent fixups.
*/
__initfunc(void pcibios_fixup(void))
{
pcibios_fixup_peer_bridges();
pcibios_fixup_devices();
#ifdef CONFIG_PCI_BIOS #ifdef CONFIG_PCI_BIOS
if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT)) if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
......
This diff is collapsed.
...@@ -735,7 +735,11 @@ static void do_8259A_IRQ(unsigned int irq, int cpu, struct pt_regs * regs) ...@@ -735,7 +735,11 @@ static void do_8259A_IRQ(unsigned int irq, int cpu, struct pt_regs * regs)
static void enable_ioapic_irq(unsigned int irq) static void enable_ioapic_irq(unsigned int irq)
{ {
irq_desc_t *desc = irq_desc + irq; irq_desc_t *desc = irq_desc + irq;
#if 0
enable_IO_APIC_irq(irq);
#endif
if (desc->events && !desc->ipi) { if (desc->events && !desc->ipi) {
ack_APIC_irq();
desc->ipi = 1; desc->ipi = 1;
send_IPI(APIC_DEST_SELF, IO_APIC_VECTOR(irq)); send_IPI(APIC_DEST_SELF, IO_APIC_VECTOR(irq));
} }
...@@ -746,6 +750,9 @@ static void enable_ioapic_irq(unsigned int irq) ...@@ -746,6 +750,9 @@ static void enable_ioapic_irq(unsigned int irq)
*/ */
static void disable_ioapic_irq(unsigned int irq) static void disable_ioapic_irq(unsigned int irq)
{ {
#if 0
disable_IO_APIC_irq(irq);
#endif
} }
static void do_ioapic_IRQ(unsigned int irq, int cpu, struct pt_regs * regs) static void do_ioapic_IRQ(unsigned int irq, int cpu, struct pt_regs * regs)
...@@ -754,13 +761,15 @@ static void do_ioapic_IRQ(unsigned int irq, int cpu, struct pt_regs * regs) ...@@ -754,13 +761,15 @@ static void do_ioapic_IRQ(unsigned int irq, int cpu, struct pt_regs * regs)
spin_lock(&irq_controller_lock); spin_lock(&irq_controller_lock);
/* Ack the irq inside the lock! */
ack_APIC_irq();
desc->ipi = 0; desc->ipi = 0;
/* If the irq is disabled for whatever reason, just set a flag and return */ /*
* If the irq is disabled for whatever reason, just
* set a flag and return
*/
if (desc->status & (IRQ_DISABLED | IRQ_INPROGRESS)) { if (desc->status & (IRQ_DISABLED | IRQ_INPROGRESS)) {
desc->events = 1; desc->events = 1;
ack_APIC_irq();
spin_unlock(&irq_controller_lock); spin_unlock(&irq_controller_lock);
return; return;
} }
...@@ -790,6 +799,7 @@ static void do_ioapic_IRQ(unsigned int irq, int cpu, struct pt_regs * regs) ...@@ -790,6 +799,7 @@ static void do_ioapic_IRQ(unsigned int irq, int cpu, struct pt_regs * regs)
spin_unlock(&irq_controller_lock); spin_unlock(&irq_controller_lock);
no_handler: no_handler:
ack_APIC_irq();
hardirq_exit(cpu); hardirq_exit(cpu);
release_irqlock(cpu); release_irqlock(cpu);
} }
......
...@@ -104,6 +104,12 @@ ...@@ -104,6 +104,12 @@
Moved register-setting macros into this file. Moved register-setting macros into this file.
Moved setup code from init/main.c to i386-specific areas. Moved setup code from init/main.c to i386-specific areas.
v1.18 v1.18
19980502 Richard Gooch <rgooch@atnf.csiro.au>
Moved MTRR detection outside conditionals in <mtrr_init>.
v1.19
19980502 Richard Gooch <rgooch@atnf.csiro.au>
Documentation improvement: mention Pentium II and AGP.
v1.20
*/ */
#include <linux/types.h> #include <linux/types.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -137,7 +143,7 @@ ...@@ -137,7 +143,7 @@
#include <asm/atomic.h> #include <asm/atomic.h>
#include <linux/smp.h> #include <linux/smp.h>
#define MTRR_VERSION "1.18 (19980429)" #define MTRR_VERSION "1.20 (19980502)"
#define TRUE 1 #define TRUE 1
#define FALSE 0 #define FALSE 0
...@@ -801,7 +807,7 @@ int mtrr_add (unsigned long base, unsigned long size, unsigned int type, ...@@ -801,7 +807,7 @@ int mtrr_add (unsigned long base, unsigned long size, unsigned int type,
if (ltype != type) if (ltype != type)
{ {
spin_unlock (&main_lock); spin_unlock (&main_lock);
printk ( "mtrr: type missmatch for %lx,%lx old: %s new: %s\n", printk ( "mtrr: type mismatch for %lx,%lx old: %s new: %s\n",
base, size, attrib_to_str (ltype), attrib_to_str (type) ); base, size, attrib_to_str (ltype), attrib_to_str (type) );
return -EINVAL; return -EINVAL;
} }
...@@ -1193,8 +1199,8 @@ int init_module (void) ...@@ -1193,8 +1199,8 @@ int init_module (void)
__initfunc(int mtrr_init(void)) __initfunc(int mtrr_init(void))
#endif #endif
{ {
# if !defined(__SMP__) || defined(MODULE)
if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return 0; if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return 0;
# if !defined(__SMP__) || defined(MODULE)
printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION); printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION);
#endif #endif
......
...@@ -297,9 +297,9 @@ void machine_restart(char * __unused) ...@@ -297,9 +297,9 @@ void machine_restart(char * __unused)
int i; int i;
for (i=0; i<100; i++) { for (i=0; i<100; i++) {
kb_wait(); kb_wait();
udelay(10); udelay(50);
outb(0xfe,0x64); /* pulse reset low */ outb(0xfe,0x64); /* pulse reset low */
udelay(10); udelay(50);
} }
/* That didn't work - force a triple fault.. */ /* That didn't work - force a triple fault.. */
__asm__ __volatile__("lidt %0": :"m" (no_idt)); __asm__ __volatile__("lidt %0": :"m" (no_idt));
......
...@@ -627,20 +627,29 @@ __initfunc(void smp_commence(void)) ...@@ -627,20 +627,29 @@ __initfunc(void smp_commence(void))
smp_commenced=1; smp_commenced=1;
} }
__initfunc(void enable_local_APIC(void))
{
unsigned long value;
value = apic_read(APIC_SPIV);
value |= (1<<8); /* Enable APIC (bit==1) */
value &= ~(1<<9); /* Enable focus processor (bit==0) */
apic_write(APIC_SPIV,value);
udelay(100); /* B safe */
}
__initfunc(void smp_callin(void)) __initfunc(void smp_callin(void))
{ {
extern void calibrate_delay(void); extern void calibrate_delay(void);
int cpuid=GET_APIC_ID(apic_read(APIC_ID)); int cpuid=GET_APIC_ID(apic_read(APIC_ID));
unsigned long l;
/* /*
* Activate our APIC * Activate our APIC
*/ */
SMP_PRINTK(("CALLIN %d %d\n",hard_smp_processor_id(), smp_processor_id())); SMP_PRINTK(("CALLIN %d %d\n",hard_smp_processor_id(), smp_processor_id()));
l=apic_read(APIC_SPIV); enable_local_APIC();
l|=(1<<8); /* Enable */
apic_write(APIC_SPIV,l);
/* /*
* Set up our APIC timer. * Set up our APIC timer.
...@@ -1004,15 +1013,7 @@ __initfunc(void smp_boot_cpus(void)) ...@@ -1004,15 +1013,7 @@ __initfunc(void smp_boot_cpus(void))
} }
#endif #endif
/* enable_local_APIC();
* Enable the local APIC
*/
cfg=apic_read(APIC_SPIV);
cfg|=(1<<8); /* Enable APIC */
apic_write(APIC_SPIV,cfg);
udelay(10);
/* /*
* Set up our local APIC timer: * Set up our local APIC timer:
...@@ -1561,7 +1562,7 @@ __initfunc(static unsigned int get_8254_timer_count (void)) ...@@ -1561,7 +1562,7 @@ __initfunc(static unsigned int get_8254_timer_count (void))
* APIC double write bug. * APIC double write bug.
*/ */
#define APIC_DIVISOR 16 #define APIC_DIVISOR 1
void setup_APIC_timer (unsigned int clocks) void setup_APIC_timer (unsigned int clocks)
{ {
...@@ -1585,7 +1586,7 @@ void setup_APIC_timer (unsigned int clocks) ...@@ -1585,7 +1586,7 @@ void setup_APIC_timer (unsigned int clocks)
*/ */
tmp_value = apic_read(APIC_TDCR); tmp_value = apic_read(APIC_TDCR);
apic_write(APIC_TDCR , (tmp_value & ~APIC_TDR_DIV_1 ) apic_write(APIC_TDCR , (tmp_value & ~APIC_TDR_DIV_1 )
| APIC_TDR_DIV_16); | APIC_TDR_DIV_1);
tmp_value = apic_read(APIC_TMICT); tmp_value = apic_read(APIC_TMICT);
apic_write(APIC_TMICT, clocks/APIC_DIVISOR); apic_write(APIC_TMICT, clocks/APIC_DIVISOR);
......
...@@ -1209,6 +1209,14 @@ static int raid5_make_request (struct md_dev *mddev, int rw, struct buffer_head ...@@ -1209,6 +1209,14 @@ static int raid5_make_request (struct md_dev *mddev, int rw, struct buffer_head
sh->pd_idx = pd_idx; sh->pd_idx = pd_idx;
if (sh->phase != PHASE_COMPLETE && sh->phase != PHASE_BEGIN) if (sh->phase != PHASE_COMPLETE && sh->phase != PHASE_BEGIN)
PRINTK(("stripe %lu catching the bus!\n", sh->sector)); PRINTK(("stripe %lu catching the bus!\n", sh->sector));
if (sh->bh_new[dd_idx]) {
printk("raid5: bug: stripe->bh_new[%d], sector %lu exists\n", dd_idx, sh->sector);
printk("raid5: bh %p, bh_new %p\n", bh, sh->bh_new[dd_idx]);
lock_stripe(sh);
md_wakeup_thread(raid_conf->thread);
wait_on_stripe(sh);
goto repeat;
}
add_stripe_bh(sh, bh, dd_idx, rw); add_stripe_bh(sh, bh, dd_idx, rw);
md_wakeup_thread(raid_conf->thread); md_wakeup_thread(raid_conf->thread);
......
...@@ -37,8 +37,8 @@ static int irq_write_proc(struct file *file, const char *buffer, ...@@ -37,8 +37,8 @@ static int irq_write_proc(struct file *file, const char *buffer,
int retval = -EINVAL; int retval = -EINVAL;
int newirq = PARPORT_IRQ_NONE; int newirq = PARPORT_IRQ_NONE;
struct parport *pp = (struct parport *)data; struct parport *pp = (struct parport *)data;
struct pardevice *cad = pp->cad;
int oldirq = pp->irq; int oldirq = pp->irq;
unsigned long flags;
/* /*
* We can have these valid cases: * We can have these valid cases:
...@@ -70,36 +70,31 @@ static int irq_write_proc(struct file *file, const char *buffer, ...@@ -70,36 +70,31 @@ static int irq_write_proc(struct file *file, const char *buffer,
if (oldirq == newirq) if (oldirq == newirq)
goto out; goto out;
spin_lock_irqsave(&port->lock, flags);
if (pp->flags & PARPORT_FLAG_COMA) if (pp->flags & PARPORT_FLAG_COMA)
goto out_ok; goto out_ok;
if (newirq != PARPORT_IRQ_NONE) { retval = -EBUSY;
void (*handler)(int, void *, struct pt_regs *); if (pp->cad)
goto out_unlock;
if (cad && cad->irq_func)
handler = cad->irq_func;
else
handler = parport_null_intr_func;
retval = request_irq(newirq, handler, if (newirq != PARPORT_IRQ_NONE) {
SA_INTERRUPT, retval = request_irq(newirq, parport_null_intr_func,
cad ? cad->name : pp->name, SA_INTERRUPT, pp->name, NULL);
cad ? cad->private : NULL);
if (retval) if (retval)
goto out; goto out_unlock;
else retval = count; else retval = count;
} }
if (oldirq != PARPORT_IRQ_NONE) { if (oldirq != PARPORT_IRQ_NONE)
if (cad && cad->irq_func)
free_irq(oldirq, cad->private);
else
free_irq(oldirq, NULL); free_irq(oldirq, NULL);
}
out_ok: out_ok:
pp->irq = newirq; pp->irq = newirq;
out_unlock:
spin_unlock_irqrestore (&pp->lock, flags);
out: out:
return retval; return retval;
} }
......
...@@ -308,7 +308,9 @@ int parport_claim(struct pardevice *dev) ...@@ -308,7 +308,9 @@ int parport_claim(struct pardevice *dev)
} }
/* Now we do the change of devices */ /* Now we do the change of devices */
spin_lock_irqsave(&port->lock, flags);
port->cad = dev; port->cad = dev;
spin_unlock_irqrestore(&port->lock, flags);
/* Swap the IRQ handlers. */ /* Swap the IRQ handlers. */
if (port->irq != PARPORT_IRQ_NONE) { if (port->irq != PARPORT_IRQ_NONE) {
...@@ -346,9 +348,8 @@ int parport_claim(struct pardevice *dev) ...@@ -346,9 +348,8 @@ int parport_claim(struct pardevice *dev)
dev->waitprev = port->waittail; dev->waitprev = port->waittail;
if (port->waittail) if (port->waittail)
port->waittail->waitnext = dev; port->waittail->waitnext = dev;
else { else
port->waithead = dev->port->waittail = dev; port->waithead = port->waittail = dev;
}
} }
spin_unlock_irqrestore (&port->lock, flags); spin_unlock_irqrestore (&port->lock, flags);
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Dynamic PPP devices by Jim Freeman <jfree@caldera.com>. * Dynamic PPP devices by Jim Freeman <jfree@caldera.com>.
* ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid <ewerlid@syscon.uu.se> * ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid <ewerlid@syscon.uu.se>
* *
* ==FILEVERSION 980319== * ==FILEVERSION 980501==
* *
* NOTE TO MAINTAINERS: * NOTE TO MAINTAINERS:
* If you modify this file at all, please set the number above to the * If you modify this file at all, please set the number above to the
...@@ -107,8 +107,10 @@ typedef struct sk_buff sk_buff; ...@@ -107,8 +107,10 @@ typedef struct sk_buff sk_buff;
#define PPP_LQR 0xc025 /* Link Quality Reporting Protocol */ #define PPP_LQR 0xc025 /* Link Quality Reporting Protocol */
#endif #endif
#ifdef CONFIG_MODULES
static int ppp_register_compressor (struct compressor *cp); static int ppp_register_compressor (struct compressor *cp);
static void ppp_unregister_compressor (struct compressor *cp); static void ppp_unregister_compressor (struct compressor *cp);
#endif
/* /*
* Local functions * Local functions
...@@ -3210,6 +3212,7 @@ static struct compressor *find_compressor (int type) ...@@ -3210,6 +3212,7 @@ static struct compressor *find_compressor (int type)
return (struct compressor *) 0; return (struct compressor *) 0;
} }
#ifdef CONFIG_MODULES
static int ppp_register_compressor (struct compressor *cp) static int ppp_register_compressor (struct compressor *cp)
{ {
struct compressor_link *new; struct compressor_link *new;
...@@ -3261,6 +3264,7 @@ static void ppp_unregister_compressor (struct compressor *cp) ...@@ -3261,6 +3264,7 @@ static void ppp_unregister_compressor (struct compressor *cp)
} }
restore_flags(flags); restore_flags(flags);
} }
#endif
/************************************************************* /*************************************************************
* Module support routines * Module support routines
......
This diff is collapsed.
/* /*
* $Id: pci.c,v 1.79 1998/04/17 16:25:24 mj Exp $ * $Id: pci.c,v 1.84 1998/05/02 19:22:06 mj Exp $
* *
* PCI Bus Services * PCI Bus Services
* *
...@@ -68,11 +68,48 @@ pci_find_class(unsigned int class, struct pci_dev *from) ...@@ -68,11 +68,48 @@ pci_find_class(unsigned int class, struct pci_dev *from)
} }
int
pci_read_config_byte(struct pci_dev *dev, u8 where, u8 *val)
{
return pcibios_read_config_byte(dev->bus->number, dev->devfn, where, val);
}
int
pci_read_config_word(struct pci_dev *dev, u8 where, u16 *val)
{
return pcibios_read_config_word(dev->bus->number, dev->devfn, where, val);
}
int
pci_read_config_dword(struct pci_dev *dev, u8 where, u32 *val)
{
return pcibios_read_config_dword(dev->bus->number, dev->devfn, where, val);
}
int
pci_write_config_byte(struct pci_dev *dev, u8 where, u8 val)
{
return pcibios_write_config_byte(dev->bus->number, dev->devfn, where, val);
}
int
pci_write_config_word(struct pci_dev *dev, u8 where, u16 val)
{
return pcibios_write_config_word(dev->bus->number, dev->devfn, where, val);
}
int
pci_write_config_dword(struct pci_dev *dev, u8 where, u32 val)
{
return pcibios_write_config_dword(dev->bus->number, dev->devfn, where, val);
}
void void
pci_set_master(struct pci_dev *dev) pci_set_master(struct pci_dev *dev)
{ {
unsigned short cmd; u16 cmd;
unsigned char lat; u8 lat;
pci_read_config_word(dev, PCI_COMMAND, &cmd); pci_read_config_word(dev, PCI_COMMAND, &cmd);
if (! (cmd & PCI_COMMAND_MASTER)) { if (! (cmd & PCI_COMMAND_MASTER)) {
...@@ -89,16 +126,43 @@ pci_set_master(struct pci_dev *dev) ...@@ -89,16 +126,43 @@ pci_set_master(struct pci_dev *dev)
} }
} }
__initfunc(void pci_read_bases(struct pci_dev *dev, unsigned int howmany))
{
unsigned int reg;
u32 l;
for(reg=0; reg<howmany; reg++) {
pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &l);
if (l == 0xffffffff)
continue;
dev->base_address[reg] = l;
if ((l & PCI_MEMORY_RANGE_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64) {
reg++;
pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &l);
if (l) {
#if BITS_PER_LONG == 64
dev->base_address[reg-1] |= ((unsigned long) l) << 32;
#else
printk("PCI: Unable to handle 64-bit address for device %02x:%02x\n",
dev->bus->number, dev->devfn);
dev->base_address[reg-1] = 0;
#endif
}
}
}
}
__initfunc(unsigned int pci_scan_bus(struct pci_bus *bus)) __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus))
{ {
unsigned int devfn, l, max, class; unsigned int devfn, l, max, class;
unsigned char cmd, irq, tmp, hdr_type, is_multi = 0; unsigned char cmd, irq, tmp, hdr_type, is_multi = 0;
struct pci_dev *dev; struct pci_dev *dev, **bus_last;
struct pci_bus *child; struct pci_bus *child;
int reg; int reg;
DBG("pci_scan_bus for bus %d\n", bus->number); DBG("pci_scan_bus for bus %d\n", bus->number);
bus_last = &bus->devices;
max = bus->secondary; max = bus->secondary;
for (devfn = 0; devfn < 0xff; ++devfn) { for (devfn = 0; devfn < 0xff; ++devfn) {
if (PCI_FUNC(devfn) && !is_multi) { if (PCI_FUNC(devfn) && !is_multi) {
...@@ -111,8 +175,8 @@ __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus)) ...@@ -111,8 +175,8 @@ __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus))
pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &l); pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &l);
/* some broken boards return 0 if a slot is empty: */ /* some broken boards return 0 if a slot is empty: */
if (l == 0xffffffff || l == 0x00000000) { if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000) {
hdr_type = 0; is_multi = 0;
continue; continue;
} }
...@@ -133,11 +197,12 @@ __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus)) ...@@ -133,11 +197,12 @@ __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus))
pcibios_read_config_dword(bus->number, devfn, PCI_CLASS_REVISION, &class); pcibios_read_config_dword(bus->number, devfn, PCI_CLASS_REVISION, &class);
class >>= 8; /* upper 3 bytes */ class >>= 8; /* upper 3 bytes */
dev->class = class; dev->class = class;
class >>= 8;
dev->hdr_type = hdr_type; dev->hdr_type = hdr_type;
switch (hdr_type & 0x7f) { /* header type */ switch (hdr_type & 0x7f) { /* header type */
case PCI_HEADER_TYPE_NORMAL: /* standard header */ case PCI_HEADER_TYPE_NORMAL: /* standard header */
if (class >> 8 == PCI_CLASS_BRIDGE_PCI) if (class == PCI_CLASS_BRIDGE_PCI)
goto bad; goto bad;
/* /*
* If the card generates interrupts, read IRQ number * If the card generates interrupts, read IRQ number
...@@ -151,25 +216,19 @@ __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus)) ...@@ -151,25 +216,19 @@ __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus))
* read base address registers, again pcibios_fixup() can * read base address registers, again pcibios_fixup() can
* tweak these * tweak these
*/ */
for (reg = 0; reg < 6; reg++) { pci_read_bases(dev, 6);
pcibios_read_config_dword(bus->number, devfn, PCI_BASE_ADDRESS_0 + (reg << 2), &l);
dev->base_address[reg] = (l == 0xffffffff) ? 0 : l;
}
pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS, &l); pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS, &l);
dev->rom_address = (l == 0xffffffff) ? 0 : l; dev->rom_address = (l == 0xffffffff) ? 0 : l;
break; break;
case PCI_HEADER_TYPE_BRIDGE: /* bridge header */ case PCI_HEADER_TYPE_BRIDGE: /* bridge header */
if (class >> 8 != PCI_CLASS_BRIDGE_PCI) if (class != PCI_CLASS_BRIDGE_PCI)
goto bad; goto bad;
for (reg = 0; reg < 2; reg++) { pci_read_bases(dev, 2);
pcibios_read_config_dword(bus->number, devfn, PCI_BASE_ADDRESS_0 + (reg << 2), &l);
dev->base_address[reg] = (l == 0xffffffff) ? 0 : l;
}
pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS1, &l); pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS1, &l);
dev->rom_address = (l == 0xffffffff) ? 0 : l; dev->rom_address = (l == 0xffffffff) ? 0 : l;
break; break;
case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */ case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */
if (class >> 16 != PCI_BASE_CLASS_BRIDGE) if (class != PCI_CLASS_BRIDGE_CARDBUS)
goto bad; goto bad;
for (reg = 0; reg < 2; reg++) { for (reg = 0; reg < 2; reg++) {
pcibios_read_config_dword(bus->number, devfn, PCI_CB_MEMORY_BASE_0 + (reg << 3), &l); pcibios_read_config_dword(bus->number, devfn, PCI_CB_MEMORY_BASE_0 + (reg << 3), &l);
...@@ -201,8 +260,8 @@ __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus)) ...@@ -201,8 +260,8 @@ __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus))
* Now insert it into the list of devices held * Now insert it into the list of devices held
* by the parent bus. * by the parent bus.
*/ */
dev->sibling = bus->devices; *bus_last = dev;
bus->devices = dev; bus_last = &dev->sibling;
#if 0 #if 0
/* /*
...@@ -217,7 +276,7 @@ __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus)) ...@@ -217,7 +276,7 @@ __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus))
/* /*
* If it's a bridge, scan the bus behind it. * If it's a bridge, scan the bus behind it.
*/ */
if (class >> 8 == PCI_CLASS_BRIDGE_PCI) { if (class == PCI_CLASS_BRIDGE_PCI) {
unsigned int buses; unsigned int buses;
unsigned short cr; unsigned short cr;
......
/* /*
* $Id: pcisyms.c,v 1.4 1998/04/17 16:34:19 mj Exp $ * $Id: pcisyms.c,v 1.7 1998/05/02 19:20:06 mj Exp $
* *
* PCI Bus Services -- Exported Symbols * PCI Bus Services -- Exported Symbols
* *
...@@ -16,6 +16,12 @@ EXPORT_SYMBOL(pcibios_read_config_dword); ...@@ -16,6 +16,12 @@ EXPORT_SYMBOL(pcibios_read_config_dword);
EXPORT_SYMBOL(pcibios_write_config_byte); EXPORT_SYMBOL(pcibios_write_config_byte);
EXPORT_SYMBOL(pcibios_write_config_word); EXPORT_SYMBOL(pcibios_write_config_word);
EXPORT_SYMBOL(pcibios_write_config_dword); EXPORT_SYMBOL(pcibios_write_config_dword);
EXPORT_SYMBOL(pci_read_config_byte);
EXPORT_SYMBOL(pci_read_config_word);
EXPORT_SYMBOL(pci_read_config_dword);
EXPORT_SYMBOL(pci_write_config_byte);
EXPORT_SYMBOL(pci_write_config_word);
EXPORT_SYMBOL(pci_write_config_dword);
EXPORT_SYMBOL(pci_devices); EXPORT_SYMBOL(pci_devices);
EXPORT_SYMBOL(pci_root); EXPORT_SYMBOL(pci_root);
EXPORT_SYMBOL(pci_find_class); EXPORT_SYMBOL(pci_find_class);
......
/* /*
* $Id: quirks.c,v 1.3 1998/02/06 19:51:42 mj Exp $ * $Id: quirks.c,v 1.5 1998/05/02 19:24:14 mj Exp $
* *
* PCI Chipset-Specific Quirks * PCI Chipset-Specific Quirks
* *
...@@ -7,8 +7,7 @@ ...@@ -7,8 +7,7 @@
* *
* This is the right place for all special fixups for on-board * This is the right place for all special fixups for on-board
* devices not depending on system architecture -- for example * devices not depending on system architecture -- for example
* bus bridges. The only thing implemented in this release is * bus bridges.
* the bridge optimization, but others might appear later.
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -88,21 +87,19 @@ __initfunc(static void quirk_bridge(struct pci_dev *dev, int pos)) ...@@ -88,21 +87,19 @@ __initfunc(static void quirk_bridge(struct pci_dev *dev, int pos))
printk(" %s: ", bridge_optimization[i].type); printk(" %s: ", bridge_optimization[i].type);
bmap = &bridge_mapping[pos + i]; bmap = &bridge_mapping[pos + i];
if (!bmap->addr) { if (!bmap->addr) {
printk("Not supported."); printk("Not supported.\n");
} else { } else {
pcibios_read_config_byte(dev->bus->number, dev->devfn, bmap->addr, &val); pci_read_config_byte(dev, bmap->addr, &val);
if ((val & bmap->mask) == bmap->value) if ((val & bmap->mask) == bmap->value)
printk("%s.", bridge_optimization[i].on); printk("%s.\n", bridge_optimization[i].on);
else { else {
printk("%s.", bridge_optimization[i].off); printk("%s", bridge_optimization[i].off);
pcibios_write_config_byte(dev->bus->number, dev->devfn, pci_write_config_byte(dev,
bmap->addr, bmap->addr,
(val & (0xff - bmap->mask)) (val & (0xff - bmap->mask)) + bmap->value);
+ bmap->value); printk(" -> %s.\n", bridge_optimization[i].on);
printk("Changed! Now %s.", bridge_optimization[i].on);
} }
} }
printk("\n");
} }
} }
...@@ -113,27 +110,18 @@ __initfunc(static void quirk_bridge(struct pci_dev *dev, int pos)) ...@@ -113,27 +110,18 @@ __initfunc(static void quirk_bridge(struct pci_dev *dev, int pos))
which can cause problems in combination with the 82441FX/PPro MTRRs */ which can cause problems in combination with the 82441FX/PPro MTRRs */
__initfunc(static void quirk_passive_release(struct pci_dev *dev, int arg)) __initfunc(static void quirk_passive_release(struct pci_dev *dev, int arg))
{ {
struct pci_dev *piix3; struct pci_dev *d = NULL;
unsigned char dlc; unsigned char dlc;
/* We have to make sure a particular bit is set in the PIIX3 /* We have to make sure a particular bit is set in the PIIX3
ISA bridge, so we have to go out and find it. */ ISA bridge, so we have to go out and find it. */
for (piix3 = pci_devices; ; piix3 = piix3->next) { while ((d = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, d))) {
if (!piix3) pci_read_config_byte(d, 0x82, &dlc);
return;
if (piix3->vendor == PCI_VENDOR_ID_INTEL
&& piix3->device == PCI_DEVICE_ID_INTEL_82371SB_0)
break;
}
pcibios_read_config_byte(piix3->bus->number, piix3->devfn, 0x82, &dlc);
if (!(dlc & 1<<1)) { if (!(dlc & 1<<1)) {
printk("PIIX3: Enabling Passive Release\n"); printk("PIIX3: Enabling Passive Release\n");
dlc |= 1<<1; dlc |= 1<<1;
pcibios_write_config_byte(piix3->bus->number, piix3->devfn, pci_write_config_byte(d, 0x82, dlc);
0x82, dlc); }
} }
} }
...@@ -141,7 +129,7 @@ __initfunc(static void quirk_passive_release(struct pci_dev *dev, int arg)) ...@@ -141,7 +129,7 @@ __initfunc(static void quirk_passive_release(struct pci_dev *dev, int arg))
typedef void (*quirk_handler)(struct pci_dev *, int); typedef void (*quirk_handler)(struct pci_dev *, int);
/* /*
* Mpping from quirk handler functions to names. * Mapping from quirk handler functions to names.
*/ */
struct quirk_name { struct quirk_name {
...@@ -185,6 +173,7 @@ static struct quirk_info quirk_list[] __initdata = { ...@@ -185,6 +173,7 @@ static struct quirk_info quirk_list[] __initdata = {
{ PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8891A, quirk_bridge, 0x01 }, { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8891A, quirk_bridge, 0x01 },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82424, quirk_bridge, 0x00 }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82424, quirk_bridge, 0x00 },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82434, quirk_bridge, 0x00 }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82434, quirk_bridge, 0x00 },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82430, quirk_bridge, 0x00 },
#endif #endif
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release, 0x00 }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release, 0x00 },
}; };
......
...@@ -260,7 +260,7 @@ static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup) ...@@ -260,7 +260,7 @@ static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
struct request *rq = hwgroup->rq; struct request *rq = hwgroup->rq;
idescsi_pc_t *pc = (idescsi_pc_t *) rq->buffer; idescsi_pc_t *pc = (idescsi_pc_t *) rq->buffer;
int log = test_bit(IDESCSI_LOG_CMD, &scsi->log); int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
u8 *scsi_buf = pc->scsi_cmd->request_buffer; u8 *scsi_buf;
if (rq->cmd != IDESCSI_PC_RQ) { if (rq->cmd != IDESCSI_PC_RQ) {
ide_end_request (uptodate, hwgroup); ide_end_request (uptodate, hwgroup);
...@@ -282,6 +282,7 @@ static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup) ...@@ -282,6 +282,7 @@ static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
printk ("ide-scsi: %s: suc %lu", drive->name, pc->scsi_cmd->serial_number); printk ("ide-scsi: %s: suc %lu", drive->name, pc->scsi_cmd->serial_number);
if (!test_bit(PC_WRITING, &pc->flags) && pc->actually_transferred && pc->actually_transferred <= 1024 && pc->buffer) { if (!test_bit(PC_WRITING, &pc->flags) && pc->actually_transferred && pc->actually_transferred <= 1024 && pc->buffer) {
printk(", rst = "); printk(", rst = ");
scsi_buf = pc->scsi_cmd->request_buffer;
hexdump(scsi_buf, IDE_MIN(16, pc->scsi_cmd->request_bufflen)); hexdump(scsi_buf, IDE_MIN(16, pc->scsi_cmd->request_bufflen));
} else printk("\n"); } else printk("\n");
} }
...@@ -345,7 +346,18 @@ static void idescsi_pc_intr (ide_drive_t *drive) ...@@ -345,7 +346,18 @@ static void idescsi_pc_intr (ide_drive_t *drive)
if ( temp > pc->request_transfer) { if ( temp > pc->request_transfer) {
if (temp > pc->buffer_size) { if (temp > pc->buffer_size) {
printk (KERN_ERR "ide-scsi: The scsi wants to send us more data than expected - discarding data\n"); printk (KERN_ERR "ide-scsi: The scsi wants to send us more data than expected - discarding data\n");
idescsi_discard_data (drive,bcount); temp = pc->buffer_size - pc->actually_transferred;
if (temp) {
clear_bit(PC_WRITING, &pc->flags);
if (pc->sg)
idescsi_input_buffers(drive, pc, temp);
else
atapi_input_bytes(drive, pc->current_position, temp);
printk(KERN_ERR "ide-scsi: transferred %d of %d bytes\n", temp, bcount);
}
pc->actually_transferred += temp;
pc->current_position += temp;
idescsi_discard_data (drive,bcount - temp);
ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc)); ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc));
return; return;
} }
......
...@@ -1605,6 +1605,7 @@ void scsi_bottom_half_handler(void) ...@@ -1605,6 +1605,7 @@ void scsi_bottom_half_handler(void)
if( SCpnt == NULL ) if( SCpnt == NULL )
return; return;
spin_lock_irqsave(&io_request_lock, flags);
atomic_inc(&recursion_depth); atomic_inc(&recursion_depth);
SCnext = SCpnt->bh_next; SCnext = SCpnt->bh_next;
...@@ -1696,6 +1697,7 @@ void scsi_bottom_half_handler(void) ...@@ -1696,6 +1697,7 @@ void scsi_bottom_half_handler(void)
} /* for(; SCpnt...) */ } /* for(; SCpnt...) */
atomic_dec(&recursion_depth); atomic_dec(&recursion_depth);
spin_unlock_irqrestore(&io_request_lock, flags);
} /* while(1==1) */ } /* while(1==1) */
......
...@@ -159,7 +159,7 @@ scsi_delete_timer(Scsi_Cmnd * SCset) ...@@ -159,7 +159,7 @@ scsi_delete_timer(Scsi_Cmnd * SCset)
* *
* Notes: * Notes:
*/ */
void scsi_times_out (Scsi_Cmnd * SCpnt) static void do_scsi_times_out (Scsi_Cmnd * SCpnt)
{ {
/* /*
...@@ -222,6 +222,15 @@ void scsi_times_out (Scsi_Cmnd * SCpnt) ...@@ -222,6 +222,15 @@ void scsi_times_out (Scsi_Cmnd * SCpnt)
} }
} }
void scsi_times_out (Scsi_Cmnd * SCpnt)
{
unsigned long flags;
spin_lock_irqsave(&io_request_lock, flags);
do_scsi_times_out(SCpnt);
spin_unlock_irqrestore(&io_request_lock, flags);
}
/* /*
* Function scsi_block_when_processing_errors * Function scsi_block_when_processing_errors
* *
...@@ -264,6 +273,9 @@ scsi_block_when_processing_errors(Scsi_Device * SDpnt) ...@@ -264,6 +273,9 @@ scsi_block_when_processing_errors(Scsi_Device * SDpnt)
STATIC STATIC
void scsi_eh_times_out (Scsi_Cmnd * SCpnt) void scsi_eh_times_out (Scsi_Cmnd * SCpnt)
{ {
unsigned long flags;
spin_lock_irqsave(&io_request_lock, flags);
SCpnt->request.rq_status = RQ_SCSI_DONE; SCpnt->request.rq_status = RQ_SCSI_DONE;
SCpnt->owner = SCSI_OWNER_ERROR_HANDLER; SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
SCpnt->eh_state = SCSI_STATE_TIMEOUT; SCpnt->eh_state = SCSI_STATE_TIMEOUT;
...@@ -273,7 +285,8 @@ void scsi_eh_times_out (Scsi_Cmnd * SCpnt) ...@@ -273,7 +285,8 @@ void scsi_eh_times_out (Scsi_Cmnd * SCpnt)
if (SCpnt->host->eh_action != NULL) if (SCpnt->host->eh_action != NULL)
up(SCpnt->host->eh_action); up(SCpnt->host->eh_action);
else else
panic("Missing scsi error handler thread"); printk("Missing scsi error handler thread\n");
spin_unlock_irqrestore(&io_request_lock, flags);
} }
...@@ -446,6 +459,11 @@ scsi_test_unit_ready(Scsi_Cmnd * SCpnt) ...@@ -446,6 +459,11 @@ scsi_test_unit_ready(Scsi_Cmnd * SCpnt)
return SCpnt->eh_state; return SCpnt->eh_state;
} }
/*
* This would normally need to get the IO request lock,
* but as it doesn't actually touch anything that needs
* to be locked we can avoid the lock here..
*/
STATIC STATIC
void scsi_sleep_done (struct semaphore * sem) void scsi_sleep_done (struct semaphore * sem)
{ {
......
...@@ -65,6 +65,7 @@ EXPORT_SYMBOL(scsi_release_command); ...@@ -65,6 +65,7 @@ EXPORT_SYMBOL(scsi_release_command);
EXPORT_SYMBOL(print_Scsi_Cmnd); EXPORT_SYMBOL(print_Scsi_Cmnd);
EXPORT_SYMBOL(scsi_block_when_processing_errors); EXPORT_SYMBOL(scsi_block_when_processing_errors);
EXPORT_SYMBOL(scsi_mark_host_reset); EXPORT_SYMBOL(scsi_mark_host_reset);
EXPORT_SYMBOL(scsi_ioctl_send_command);
#if defined(CONFIG_SCSI_LOGGING) /* { */ #if defined(CONFIG_SCSI_LOGGING) /* { */
EXPORT_SYMBOL(scsi_logging_level); EXPORT_SYMBOL(scsi_logging_level);
#endif #endif
......
...@@ -106,8 +106,8 @@ int sr_do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned bufl ...@@ -106,8 +106,8 @@ int sr_do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned bufl
break; break;
case ILLEGAL_REQUEST: case ILLEGAL_REQUEST:
if (!quiet) if (!quiet)
printk("sr%d: CDROM (ioctl) reports ILLEGAL REQUEST.\n", printk(KERN_ERR "sr%d: CDROM (ioctl) reports ILLEGAL "
target); "REQUEST.\n", target);
if (SCpnt->sense_buffer[12] == 0x20 && if (SCpnt->sense_buffer[12] == 0x20 &&
SCpnt->sense_buffer[13] == 0x00) { SCpnt->sense_buffer[13] == 0x00) {
/* sense: Invalid command operation code */ /* sense: Invalid command operation code */
...@@ -121,7 +121,7 @@ int sr_do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned bufl ...@@ -121,7 +121,7 @@ int sr_do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned bufl
#endif #endif
break; break;
default: default:
printk("sr%d: CDROM (ioctl) error, command: ", target); printk(KERN_ERR "sr%d: CDROM (ioctl) error, command: ", target);
print_command(sr_cmd); print_command(sr_cmd);
print_sense("sr", SCpnt); print_sense("sr", SCpnt);
err = -EIO; err = -EIO;
......
...@@ -26,6 +26,7 @@ EXPORT_SYMBOL(num_audiodevs); ...@@ -26,6 +26,7 @@ EXPORT_SYMBOL(num_audiodevs);
EXPORT_SYMBOL(note_to_freq); EXPORT_SYMBOL(note_to_freq);
EXPORT_SYMBOL(compute_finetune); EXPORT_SYMBOL(compute_finetune);
EXPORT_SYMBOL(seq_copy_to_input); EXPORT_SYMBOL(seq_copy_to_input);
EXPORT_SYMBOL(seq_input_event);
EXPORT_SYMBOL(sequencer_init); EXPORT_SYMBOL(sequencer_init);
EXPORT_SYMBOL(sequencer_timer); EXPORT_SYMBOL(sequencer_timer);
...@@ -61,6 +62,7 @@ EXPORT_SYMBOL(conf_printf2); ...@@ -61,6 +62,7 @@ EXPORT_SYMBOL(conf_printf2);
EXPORT_SYMBOL(sound_timer_init); EXPORT_SYMBOL(sound_timer_init);
EXPORT_SYMBOL(sound_timer_interrupt); EXPORT_SYMBOL(sound_timer_interrupt);
EXPORT_SYMBOL(sound_timer_syncinterval); EXPORT_SYMBOL(sound_timer_syncinterval);
EXPORT_SYMBOL(sound_timer_devs);
/* Locking */ /* Locking */
EXPORT_SYMBOL(sound_locker); EXPORT_SYMBOL(sound_locker);
......
...@@ -970,7 +970,7 @@ void cleanup_module(void) ...@@ -970,7 +970,7 @@ void cleanup_module(void)
if (mss) if (mss)
unload_ss_ms_sound(&config); unload_ss_ms_sound(&config);
SOUND_LOCK_END; SOUND_LOCK_END;
unload_sscape(&config); unload_sscape(&mpu_config);
} }
#endif #endif
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
O_TARGET := coda.o O_TARGET := coda.o
O_OBJS := psdev.o cache.o cnode.o inode.o dir.o file.o upcall.o coda_linux.o\ O_OBJS := psdev.o cache.o cnode.o inode.o dir.o file.o upcall.o coda_linux.o\
symlink.o pioctl.o sysctl.o symlink.o pioctl.o sysctl.o stats.o
M_OBJS := $(O_TARGET) M_OBJS := $(O_TARGET)
# If you want debugging output, please uncomment the following line # If you want debugging output, please uncomment the following line
......
...@@ -32,9 +32,6 @@ static void coda_cache_create(struct inode *inode, int mask); ...@@ -32,9 +32,6 @@ static void coda_cache_create(struct inode *inode, int mask);
static struct coda_cache * coda_cache_find(struct inode *inode); static struct coda_cache * coda_cache_find(struct inode *inode);
/* Keep various stats */
struct cfsnc_statistics cfsnc_stat;
/* insert a acl-cache entry in sb list */ /* insert a acl-cache entry in sb list */
static void coda_ccinsert(struct coda_cache *el, struct super_block *sb) static void coda_ccinsert(struct coda_cache *el, struct super_block *sb)
{ {
...@@ -295,41 +292,3 @@ void coda_flag_inode(struct inode *inode, int flag) ...@@ -295,41 +292,3 @@ void coda_flag_inode(struct inode *inode, int flag)
int
cfsnc_nc_info(char *buffer, char **start, off_t offset, int length, int dummy)
{
int len=0;
off_t begin;
/* cfsnc_gather_stats(); */
/* this works as long as we are below 1024 characters! */
len += sprintf(buffer,"Coda minicache statistics\n\n");
len += sprintf(buffer+len, "cfsnc_hits : %d\n", cfsnc_stat.hits);
len += sprintf(buffer+len, "cfsnc_misses : %d\n", cfsnc_stat.misses);
len += sprintf(buffer+len, "cfsnc_enters : %d\n", cfsnc_stat.enters);
len += sprintf(buffer+len, "cfsnc_dbl_enters : %d\n", cfsnc_stat.dbl_enters);
len += sprintf(buffer+len, "cfsnc_long_name_enters : %d\n", cfsnc_stat.long_name_enters);
len += sprintf(buffer+len, "cfsnc_long_name_lookups : %d\n", cfsnc_stat.long_name_lookups);
len += sprintf(buffer+len, "cfsnc_long_remove : %d\n", cfsnc_stat.long_remove);
len += sprintf(buffer+len, "cfsnc_lru_rm : %d\n", cfsnc_stat.lru_rm);
len += sprintf(buffer+len, "cfsnc_zapPfids : %d\n", cfsnc_stat.zapPfids);
len += sprintf(buffer+len, "cfsnc_zapFids : %d\n", cfsnc_stat.zapFids);
len += sprintf(buffer+len, "cfsnc_zapFile : %d\n", cfsnc_stat.zapFile);
len += sprintf(buffer+len, "cfsnc_zapUsers : %d\n", cfsnc_stat.zapUsers);
len += sprintf(buffer+len, "cfsnc_Flushes : %d\n", cfsnc_stat.Flushes);
len += sprintf(buffer+len, "cfsnc_SumLen : %d\n", cfsnc_stat.Sum_bucket_len);
len += sprintf(buffer+len, "cfsnc_Sum2Len : %d\n", cfsnc_stat.Sum2_bucket_len);
len += sprintf(buffer+len, "cfsnc_# 0 len : %d\n", cfsnc_stat.Num_zero_len);
len += sprintf(buffer+len, "cfsnc_MaxLen : %d\n", cfsnc_stat.Max_bucket_len);
len += sprintf(buffer+len, "cfsnc_SearchLen : %d\n", cfsnc_stat.Search_len);
begin = offset;
*start = buffer + begin;
len -= begin;
if(len>length)
len = length;
if (len< 0)
len = 0;
return len;
}
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* the Coda project. Contact Peter Braam (coda@cs.cmu.edu). * the Coda project. Contact Peter Braam (coda@cs.cmu.edu).
*/ */
#include <linux/version.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/coda_psdev.h> #include <linux/coda_psdev.h>
#include <linux/coda_fs_i.h> #include <linux/coda_fs_i.h>
#include <linux/coda_cache.h> #include <linux/coda_cache.h>
#include <linux/coda_proc.h>
/* dir inode-ops */ /* dir inode-ops */
static int coda_create(struct inode *dir, struct dentry *new, int mode); static int coda_create(struct inode *dir, struct dentry *new, int mode);
...@@ -179,6 +180,8 @@ int coda_permission(struct inode *inode, int mask) ...@@ -179,6 +180,8 @@ int coda_permission(struct inode *inode, int mask)
int error; int error;
ENTRY; ENTRY;
coda_vfs_stat.permission++;
coda_permission_stat.count++;
if ( mask == 0 ) { if ( mask == 0 ) {
EXIT; EXIT;
...@@ -187,6 +190,7 @@ int coda_permission(struct inode *inode, int mask) ...@@ -187,6 +190,7 @@ int coda_permission(struct inode *inode, int mask)
if ( coda_access_cache == 1 ) { if ( coda_access_cache == 1 ) {
if ( coda_cache_check(inode, mask) ) { if ( coda_cache_check(inode, mask) ) {
coda_permission_stat.hit_count++;
return 0; return 0;
} }
} }
...@@ -221,6 +225,8 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode) ...@@ -221,6 +225,8 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode)
struct ViceFid newfid; struct ViceFid newfid;
struct coda_vattr attrs; struct coda_vattr attrs;
coda_vfs_stat.create++;
CDEBUG(D_INODE, "name: %s, length %d, mode %o\n",name, length, mode); CDEBUG(D_INODE, "name: %s, length %d, mode %o\n",name, length, mode);
if (!dir || !S_ISDIR(dir->i_mode)) { if (!dir || !S_ISDIR(dir->i_mode)) {
...@@ -274,6 +280,8 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode) ...@@ -274,6 +280,8 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
struct ViceFid newfid; struct ViceFid newfid;
coda_vfs_stat.mkdir++;
if (!dir || !S_ISDIR(dir->i_mode)) { if (!dir || !S_ISDIR(dir->i_mode)) {
printk("coda_mkdir: inode is NULL or not a directory\n"); printk("coda_mkdir: inode is NULL or not a directory\n");
return -ENOENT; return -ENOENT;
...@@ -329,6 +337,7 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode, ...@@ -329,6 +337,7 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
int error; int error;
ENTRY; ENTRY;
coda_vfs_stat.link++;
if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
return -EPERM; return -EPERM;
...@@ -373,6 +382,7 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de, ...@@ -373,6 +382,7 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de,
int error=0; int error=0;
ENTRY; ENTRY;
coda_vfs_stat.symlink++;
if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
return -EPERM; return -EPERM;
...@@ -414,6 +424,7 @@ int coda_unlink(struct inode *dir, struct dentry *de) ...@@ -414,6 +424,7 @@ int coda_unlink(struct inode *dir, struct dentry *de)
int len = de->d_name.len; int len = de->d_name.len;
ENTRY; ENTRY;
coda_vfs_stat.unlink++;
dircnp = ITOC(dir); dircnp = ITOC(dir);
CHECK_CNODE(dircnp); CHECK_CNODE(dircnp);
...@@ -446,6 +457,8 @@ int coda_rmdir(struct inode *dir, struct dentry *de) ...@@ -446,6 +457,8 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
int len = de->d_name.len; int len = de->d_name.len;
int error, rehash = 0; int error, rehash = 0;
coda_vfs_stat.rmdir++;
if (!dir || !S_ISDIR(dir->i_mode)) { if (!dir || !S_ISDIR(dir->i_mode)) {
printk("coda_rmdir: inode is NULL or not a directory\n"); printk("coda_rmdir: inode is NULL or not a directory\n");
return -ENOENT; return -ENOENT;
...@@ -502,6 +515,8 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -502,6 +515,8 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
struct coda_inode_info *new_cnp, *old_cnp; struct coda_inode_info *new_cnp, *old_cnp;
int error, rehash = 0, update = 1; int error, rehash = 0, update = 1;
ENTRY; ENTRY;
coda_vfs_stat.rename++;
old_cnp = ITOC(old_dir); old_cnp = ITOC(old_dir);
CHECK_CNODE(old_cnp); CHECK_CNODE(old_cnp);
new_cnp = ITOC(new_dir); new_cnp = ITOC(new_dir);
...@@ -565,6 +580,7 @@ int coda_readdir(struct file *file, void *dirent, filldir_t filldir) ...@@ -565,6 +580,7 @@ int coda_readdir(struct file *file, void *dirent, filldir_t filldir)
struct inode *inode=file->f_dentry->d_inode; struct inode *inode=file->f_dentry->d_inode;
ENTRY; ENTRY;
coda_vfs_stat.readdir++;
if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode)) { if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode)) {
printk("coda_readdir: inode is NULL or not a directory\n"); printk("coda_readdir: inode is NULL or not a directory\n");
...@@ -606,6 +622,7 @@ int coda_open(struct inode *i, struct file *f) ...@@ -606,6 +622,7 @@ int coda_open(struct inode *i, struct file *f)
unsigned short coda_flags = coda_flags_to_cflags(flags); unsigned short coda_flags = coda_flags_to_cflags(flags);
ENTRY; ENTRY;
coda_vfs_stat.open++;
CDEBUG(D_SPECIAL, "OPEN inode number: %ld, flags %o.\n", CDEBUG(D_SPECIAL, "OPEN inode number: %ld, flags %o.\n",
f->f_dentry->d_inode->i_ino, flags); f->f_dentry->d_inode->i_ino, flags);
...@@ -659,6 +676,7 @@ int coda_release(struct inode *i, struct file *f) ...@@ -659,6 +676,7 @@ int coda_release(struct inode *i, struct file *f)
unsigned short cflags = coda_flags_to_cflags(flags); unsigned short cflags = coda_flags_to_cflags(flags);
ENTRY; ENTRY;
coda_vfs_stat.release++;
cnp =ITOC(i); cnp =ITOC(i);
CHECK_CNODE(cnp); CHECK_CNODE(cnp);
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/coda_fs_i.h> #include <linux/coda_fs_i.h>
#include <linux/coda_psdev.h> #include <linux/coda_psdev.h>
#include <linux/coda_cache.h> #include <linux/coda_cache.h>
#include <linux/coda_proc.h>
/* file operations */ /* file operations */
static int coda_readpage(struct file *file, struct page * page); static int coda_readpage(struct file *file, struct page * page);
...@@ -83,6 +84,7 @@ static int coda_readpage(struct file * coda_file, struct page * page) ...@@ -83,6 +84,7 @@ static int coda_readpage(struct file * coda_file, struct page * page)
struct coda_inode_info *cii; struct coda_inode_info *cii;
ENTRY; ENTRY;
coda_vfs_stat.readpage++;
cii = ITOC(coda_inode); cii = ITOC(coda_inode);
...@@ -108,6 +110,8 @@ static int coda_file_mmap(struct file * file, struct vm_area_struct * vma) ...@@ -108,6 +110,8 @@ static int coda_file_mmap(struct file * file, struct vm_area_struct * vma)
struct coda_inode_info *cii; struct coda_inode_info *cii;
int res; int res;
coda_vfs_stat.file_mmap++;
ENTRY; ENTRY;
cii = ITOC(file->f_dentry->d_inode); cii = ITOC(file->f_dentry->d_inode);
cii->c_mmcount++; cii->c_mmcount++;
...@@ -126,7 +130,9 @@ static ssize_t coda_file_read(struct file *coda_file, char *buff, ...@@ -126,7 +130,9 @@ static ssize_t coda_file_read(struct file *coda_file, char *buff,
struct file cont_file; struct file cont_file;
struct dentry cont_dentry; struct dentry cont_dentry;
int result = 0; int result = 0;
ENTRY; ENTRY;
coda_vfs_stat.file_read++;
cnp = ITOC(coda_inode); cnp = ITOC(coda_inode);
CHECK_CNODE(cnp); CHECK_CNODE(cnp);
...@@ -167,6 +173,7 @@ static ssize_t coda_file_write(struct file *coda_file, const char *buff, ...@@ -167,6 +173,7 @@ static ssize_t coda_file_write(struct file *coda_file, const char *buff,
int result = 0; int result = 0;
ENTRY; ENTRY;
coda_vfs_stat.file_write++;
cnp = ITOC(coda_inode); cnp = ITOC(coda_inode);
CHECK_CNODE(cnp); CHECK_CNODE(cnp);
...@@ -205,6 +212,7 @@ int coda_fsync(struct file *coda_file, struct dentry *coda_dentry) ...@@ -205,6 +212,7 @@ int coda_fsync(struct file *coda_file, struct dentry *coda_dentry)
struct dentry cont_dentry; struct dentry cont_dentry;
int result = 0; int result = 0;
ENTRY; ENTRY;
coda_vfs_stat.fsync++;
if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) || if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) ||
S_ISLNK(coda_inode->i_mode))) S_ISLNK(coda_inode->i_mode)))
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
#include <linux/coda_fs_i.h> #include <linux/coda_fs_i.h>
#include <linux/coda_psdev.h> #include <linux/coda_psdev.h>
#include <linux/coda_cache.h> #include <linux/coda_cache.h>
#include <linux/coda_sysctl.h> #include <linux/coda_proc.h>
/* /*
...@@ -401,19 +401,106 @@ static struct file_operations coda_psdev_fops = { ...@@ -401,19 +401,106 @@ static struct file_operations coda_psdev_fops = {
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
struct proc_dir_entry proc_coda = { struct proc_dir_entry proc_sys_root = {
PROC_SYS, 3, "sys", /* inode, name */
S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, /* mode, nlink, uid, gid */
0, &proc_dir_inode_operations, /* size, ops */
NULL, NULL, /* get_info, fill_inode */
NULL, /* next */
NULL, NULL /* parent, subdir */
};
struct proc_dir_entry proc_fs_coda = {
PROC_FS_CODA, 4, "coda",
S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
0, &proc_dir_inode_operations,
NULL, NULL,
NULL,
NULL, NULL
};
struct proc_dir_entry proc_sys_coda = {
0, 4, "coda", 0, 4, "coda",
S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR, 2, 0, 0, S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
0, &proc_net_inode_operations, 0, &proc_dir_inode_operations,
NULL, NULL,
NULL,
NULL, NULL
};
struct proc_dir_entry proc_fs = {
PROC_FS, 2, "fs",
S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
0, &proc_dir_inode_operations,
NULL, NULL,
NULL,
NULL, NULL
}; };
#if 0
struct proc_dir_entry proc_coda_ncstats = { struct proc_dir_entry proc_coda_ncstats = {
0 , 12, "coda-ncstats", 0 , 12, "coda-ncstats",
S_IFREG | S_IRUGO, 1, 0, 0, S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations, 0, &proc_net_inode_operations,
cfsnc_nc_info cfsnc_nc_info
}; };
#endif
struct proc_dir_entry proc_coda_vfs = {
PROC_VFS_STATS , 9, "vfs_stats",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations,
coda_vfs_stats_get_info
};
struct proc_dir_entry proc_coda_vfs_control = {
0 , 9, "vfs_stats",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations,
coda_vfs_stats_get_info
};
struct proc_dir_entry proc_coda_upcall = {
PROC_UPCALL_STATS , 12, "upcall_stats",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations,
coda_upcall_stats_get_info
};
struct proc_dir_entry proc_coda_upcall_control = {
0 , 12, "upcall_stats",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations,
coda_upcall_stats_get_info
};
struct proc_dir_entry proc_coda_permission = {
PROC_PERMISSION_STATS , 16, "permission_stats",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations,
coda_permission_stats_get_info
};
struct proc_dir_entry proc_coda_permission_control = {
0 , 16, "permission_stats",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations,
coda_permission_stats_get_info
};
struct proc_dir_entry proc_coda_cache_inv = {
PROC_CACHE_INV_STATS , 15, "cache_inv_stats",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations,
coda_cache_inv_stats_get_info
};
struct proc_dir_entry proc_coda_cache_inv_control = {
0 , 15, "cache_inv_stats",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations,
coda_cache_inv_stats_get_info
};
#endif #endif
...@@ -429,9 +516,27 @@ int init_coda_psdev(void) ...@@ -429,9 +516,27 @@ int init_coda_psdev(void)
memset(coda_super_info, 0, sizeof(coda_super_info)); memset(coda_super_info, 0, sizeof(coda_super_info));
memset(&coda_callstats, 0, sizeof(coda_callstats)); memset(&coda_callstats, 0, sizeof(coda_callstats));
reset_coda_vfs_stats();
reset_coda_upcall_stats();
reset_coda_permission_stats();
reset_coda_cache_inv_stats();
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
proc_register(&proc_root,&proc_coda); proc_register(&proc_root,&proc_fs);
proc_register(&proc_coda, &proc_coda_ncstats); proc_register(&proc_fs,&proc_fs_coda);
proc_register(&proc_fs_coda,&proc_coda_vfs);
proc_register(&proc_fs_coda,&proc_coda_upcall);
proc_register(&proc_fs_coda,&proc_coda_permission);
proc_register(&proc_fs_coda,&proc_coda_cache_inv);
#if 0
proc_register(&proc_fs_coda, &proc_coda_ncstats);
#endif
proc_register(&proc_sys_root,&proc_sys_coda);
proc_register(&proc_sys_coda,&proc_coda_vfs_control);
proc_register(&proc_sys_coda,&proc_coda_upcall_control);
proc_register(&proc_sys_coda,&proc_coda_permission_control);
proc_register(&proc_sys_coda,&proc_coda_cache_inv_control);
coda_sysctl_init(); coda_sysctl_init();
#endif #endif
return 0; return 0;
...@@ -476,8 +581,22 @@ void cleanup_module(void) ...@@ -476,8 +581,22 @@ void cleanup_module(void)
#if CONFIG_PROC_FS #if CONFIG_PROC_FS
coda_sysctl_clean(); coda_sysctl_clean();
proc_unregister(&proc_coda, proc_coda_ncstats.low_ino);
proc_unregister(&proc_root, proc_coda.low_ino); proc_unregister(&proc_sys_coda, proc_coda_cache_inv_control.low_ino);
proc_unregister(&proc_sys_coda, proc_coda_permission_control.low_ino);
proc_unregister(&proc_sys_coda, proc_coda_upcall_control.low_ino);
proc_unregister(&proc_sys_coda,proc_coda_vfs_control.low_ino);
proc_unregister(&proc_sys_root, proc_sys_coda.low_ino);
#if 0
proc_unregister(&proc_fs_coda, proc_coda_ncstats.low_ino);
#endif
proc_unregister(&proc_fs_coda, proc_coda_cache_inv.low_ino);
proc_unregister(&proc_fs_coda, proc_coda_permission.low_ino);
proc_unregister(&proc_fs_coda, proc_coda_upcall.low_ino);
proc_unregister(&proc_fs_coda, proc_coda_vfs.low_ino);
proc_unregister(&proc_fs, proc_fs_coda.low_ino);
proc_unregister(&proc_root, proc_fs.low_ino);
#endif #endif
} }
......
/*
* stats.c
*
* CODA operation statistics
*
* (c) March, 1998 Zhanyong Wan <zhanyong.wan@yale.edu>
*
*/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/sysctl.h>
#include <linux/swapctl.h>
#include <linux/proc_fs.h>
#include <linux/malloc.h>
#include <linux/stat.h>
#include <linux/ctype.h>
#include <asm/bitops.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/utsname.h>
#include <linux/coda.h>
#include <linux/coda_linux.h>
#include <linux/coda_fs_i.h>
#include <linux/coda_psdev.h>
#include <linux/coda_cache.h>
#include <linux/coda_proc.h>
struct coda_vfs_stats coda_vfs_stat;
struct coda_permission_stats coda_permission_stat;
struct coda_cache_inv_stats coda_cache_inv_stat;
struct coda_upcall_stats_entry coda_upcall_stat[CFS_NCALLS];
/* keep this in sync with coda.h! */
char *coda_upcall_names[] = {
"totals ", /* 0 */
"noop ", /* 1 */
"root ", /* 2 */
"sync ", /* 3 */
"open ", /* 4 */
"close ", /* 5 */
"ioctl ", /* 6 */
"getattr ", /* 7 */
"setattr ", /* 8 */
"access ", /* 9 */
"lookup ", /* 10 */
"create ", /* 11 */
"remove ", /* 12 */
"link ", /* 13 */
"rename ", /* 14 */
"mkdir ", /* 15 */
"rmdir ", /* 16 */
"readdir ", /* 17 */
"symlink ", /* 18 */
"readlink ", /* 19 */
"fsync ", /* 20 */
"inactive ", /* 21 */
"vget ", /* 22 */
"signal ", /* 23 */
"replace ", /* 24 */
"flush ", /* 25 */
"purgeuser ", /* 26 */
"zapfile ", /* 27 */
"zapdir ", /* 28 */
"zapvnode ", /* 28 */
"purgefid ", /* 30 */
"open_by_path" /* 31 */
};
void reset_coda_vfs_stats( void )
{
memset( &coda_vfs_stat, 0, sizeof( coda_vfs_stat ) );
}
#if 0
static void reset_upcall_entry( struct coda_upcall_stats_entry * pentry )
{
pentry->count = 0;
pentry->time_sum = pentry->time_squared_sum = 0;
}
#endif
void reset_coda_upcall_stats( void )
{
memset( &coda_upcall_stat, 0, sizeof( coda_upcall_stat ) );
}
void reset_coda_permission_stats( void )
{
memset( &coda_permission_stat, 0, sizeof( coda_permission_stat ) );
}
void reset_coda_cache_inv_stats( void )
{
memset( &coda_cache_inv_stat, 0, sizeof( coda_cache_inv_stat ) );
}
void do_time_stats( struct coda_upcall_stats_entry * pentry,
unsigned long runtime )
{
unsigned long time = runtime * 1000 /HZ; /* time in ms */
CDEBUG(D_SPECIAL, "time: %ld\n", time);
if ( pentry->count == 0 ) {
pentry->time_sum = pentry->time_squared_sum = 0;
}
pentry->count++;
pentry->time_sum += time;
pentry->time_squared_sum += time*time;
}
void coda_upcall_stats(int opcode, long unsigned runtime)
{
struct coda_upcall_stats_entry * pentry;
if ( opcode < 0 || opcode > CFS_NCALLS - 1) {
printk("Nasty opcode %d passed to coda_upcall_stats\n",
opcode);
return;
}
pentry = &coda_upcall_stat[opcode];
do_time_stats(pentry, runtime);
/* fill in the totals */
pentry = &coda_upcall_stat[0];
do_time_stats(pentry, runtime);
}
unsigned long get_time_average( const struct coda_upcall_stats_entry * pentry )
{
return ( pentry->count == 0 ) ? 0 : pentry->time_sum / pentry->count;
}
static inline unsigned long absolute( unsigned long x )
{
return x >= 0 ? x : -x;
}
static unsigned long sqr_root( unsigned long x )
{
unsigned long y = x, r;
int n_bit = 0;
if ( x == 0 )
return 0;
if ( x < 0)
x = -x;
while ( y ) {
y >>= 1;
n_bit++;
}
r = 1 << (n_bit/2);
while ( 1 ) {
r = (r + x/r)/2;
if ( r*r <= x && x < (r+1)*(r+1) )
break;
}
return r;
}
unsigned long get_time_std_deviation( const struct coda_upcall_stats_entry * pentry )
{
unsigned long time_avg;
if ( pentry->count <= 1 )
return 0;
time_avg = get_time_average( pentry );
return
sqr_root( (pentry->time_squared_sum / pentry->count) -
time_avg * time_avg );
}
int do_reset_coda_vfs_stats( ctl_table * table, int write, struct file * filp,
void * buffer, size_t * lenp )
{
if ( write ) {
reset_coda_vfs_stats();
}
*lenp = 0;
return 0;
}
int do_reset_coda_upcall_stats( ctl_table * table, int write,
struct file * filp, void * buffer,
size_t * lenp )
{
if ( write ) {
reset_coda_upcall_stats();
}
*lenp = 0;
return 0;
}
int do_reset_coda_permission_stats( ctl_table * table, int write,
struct file * filp, void * buffer,
size_t * lenp )
{
if ( write ) {
reset_coda_permission_stats();
}
*lenp = 0;
return 0;
}
int do_reset_coda_cache_inv_stats( ctl_table * table, int write,
struct file * filp, void * buffer,
size_t * lenp )
{
if ( write ) {
reset_coda_cache_inv_stats();
}
*lenp = 0;
return 0;
}
int coda_vfs_stats_get_info( char * buffer, char ** start, off_t offset,
int length, int dummy )
{
int len=0;
off_t begin;
struct coda_vfs_stats * ps = & coda_vfs_stat;
/* this works as long as we are below 1024 characters! */
len += sprintf( buffer,
"Coda VFS statistics\n"
"===================\n\n"
"File Operations:\n"
"\tfile_read\t%9d\n"
"\tfile_write\t%9d\n"
"\tfile_mmap\t%9d\n"
"\topen\t\t%9d\n"
"\trelase\t\t%9d\n"
"\tfsync\t\t%9d\n\n"
"Dir Operations:\n"
"\treaddir\t\t%9d\n\n"
"Inode Operations\n"
"\tcreate\t\t%9d\n"
"\tlookup\t\t%9d\n"
"\tlink\t\t%9d\n"
"\tunlink\t\t%9d\n"
"\tsymlink\t\t%9d\n"
"\tmkdir\t\t%9d\n"
"\trmdir\t\t%9d\n"
"\trename\t\t%9d\n"
"\tpermission\t%9d\n"
"\treadpage\t%9d\n",
/* file operations */
ps->file_read,
ps->file_write,
ps->file_mmap,
ps->open,
ps->release,
ps->fsync,
/* dir operations */
ps->readdir,
/* inode operations */
ps->create,
ps->lookup,
ps->link,
ps->unlink,
ps->symlink,
ps->mkdir,
ps->rmdir,
ps->rename,
ps->permission,
ps->readpage );
begin = offset;
*start = buffer + begin;
len -= begin;
if ( len > length )
len = length;
if ( len < 0 )
len = 0;
return len;
}
int coda_upcall_stats_get_info( char * buffer, char ** start, off_t offset,
int length, int dummy )
{
int len=0;
int i;
off_t begin;
off_t pos = 0;
char tmpbuf[80];
int tmplen = 0;
ENTRY;
/* this works as long as we are below 1024 characters! */
if ( offset < 80 )
len += sprintf( buffer,"%-79s\n", "Coda upcall statistics");
if ( offset < 160)
len += sprintf( buffer + len,"%-79s\n", "======================");
if ( offset < 240)
len += sprintf( buffer + len,"%-79s\n", "upcall\t\t count\tavg time(ms)\tstd deviation(ms)");
if ( offset < 320)
len += sprintf( buffer + len,"%-79s\n", "------\t\t -----\t------------\t-----------------");
pos = 320;
for ( i = 0 ; i < CFS_NCALLS ; i++ ) {
tmplen += sprintf(tmpbuf,"%s\t%9d\t%10ld\t%10ld",
coda_upcall_names[i],
coda_upcall_stat[i].count,
get_time_average(&coda_upcall_stat[i]),
coda_upcall_stat[i].time_squared_sum);
pos += 80;
if ( pos < offset )
continue;
len += sprintf(buffer + len, "%-79s\n", tmpbuf);
if ( len >= length )
break;
}
begin = len- (pos - offset);
*start = buffer + begin;
len -= begin;
if ( len > length )
len = length;
if ( len < 0 )
len = 0;
EXIT;
return len;
}
int coda_permission_stats_get_info( char * buffer, char ** start, off_t offset,
int length, int dummy )
{
int len=0;
off_t begin;
struct coda_permission_stats * ps = & coda_permission_stat;
/* this works as long as we are below 1024 characters! */
len += sprintf( buffer,
"Coda permission statistics\n"
"==========================\n\n"
"count\t\t%9d\n"
"hit count\t%9d\n",
ps->count,
ps->hit_count );
begin = offset;
*start = buffer + begin;
len -= begin;
if ( len > length )
len = length;
if ( len < 0 )
len = 0;
return len;
}
int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset,
int length, int dummy )
{
int len=0;
off_t begin;
struct coda_cache_inv_stats * ps = & coda_cache_inv_stat;
/* this works as long as we are below 1024 characters! */
len += sprintf( buffer,
"Coda cache invalidation statistics\n"
"==================================\n\n"
"flush\t\t%9d\n"
"purge user\t%9d\n"
"zap_dir\t\t%9d\n"
"zap_file\t%9d\n"
"zap_vnode\t%9d\n"
"purge_fid\t%9d\n"
"replace\t\t%9d\n",
ps->flush,
ps->purge_user,
ps->zap_dir,
ps->zap_file,
ps->zap_vnode,
ps->purge_fid,
ps->replace );
begin = offset;
*start = buffer + begin;
len -= begin;
if ( len > length )
len = length;
if ( len < 0 )
len = 0;
return len;
}
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/coda_psdev.h> #include <linux/coda_psdev.h>
#include <linux/coda_fs_i.h> #include <linux/coda_fs_i.h>
#include <linux/coda_cache.h> #include <linux/coda_cache.h>
#include <linux/coda_proc.h>
static int coda_readlink(struct dentry *de, char *buffer, int length); static int coda_readlink(struct dentry *de, char *buffer, int length);
static struct dentry *coda_follow_link(struct dentry *, struct dentry *); static struct dentry *coda_follow_link(struct dentry *, struct dentry *);
...@@ -60,7 +61,7 @@ static int coda_readlink(struct dentry *de, char *buffer, int length) ...@@ -60,7 +61,7 @@ static int coda_readlink(struct dentry *de, char *buffer, int length)
ENTRY; ENTRY;
cp = ITOC(inode); cp = ITOC(inode);
CHECK_CNODE(cp); coda_vfs_stat.readlink++;
/* the maximum length we receive is len */ /* the maximum length we receive is len */
if ( length > CFS_MAXPATHLEN ) if ( length > CFS_MAXPATHLEN )
...@@ -93,11 +94,11 @@ static struct dentry *coda_follow_link(struct dentry *de, ...@@ -93,11 +94,11 @@ static struct dentry *coda_follow_link(struct dentry *de,
unsigned int len; unsigned int len;
char mem[CFS_MAXPATHLEN]; char mem[CFS_MAXPATHLEN];
char *path; char *path;
ENTRY; ENTRY;
CDEBUG(D_INODE, "(%x/%ld)\n", inode->i_dev, inode->i_ino); CDEBUG(D_INODE, "(%x/%ld)\n", inode->i_dev, inode->i_ino);
cnp = ITOC(inode); cnp = ITOC(inode);
CHECK_CNODE(cnp); coda_vfs_stat.follow_link++;
len = CFS_MAXPATHLEN; len = CFS_MAXPATHLEN;
error = venus_readlink(inode->i_sb, &(cnp->c_fid), mem, &len); error = venus_readlink(inode->i_sb, &(cnp->c_fid), mem, &len);
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <linux/coda_fs_i.h> #include <linux/coda_fs_i.h>
#include <linux/coda_psdev.h> #include <linux/coda_psdev.h>
#include <linux/coda_cache.h> #include <linux/coda_cache.h>
#include <linux/coda_sysctl.h> #include <linux/coda_proc.h>
extern int coda_debug; extern int coda_debug;
/* extern int cfsnc_use; */ /* extern int cfsnc_use; */
extern int coda_print_entry; extern int coda_print_entry;
...@@ -47,6 +47,10 @@ struct ctl_table_header *fs_table_header, *coda_table_header; ...@@ -47,6 +47,10 @@ struct ctl_table_header *fs_table_header, *coda_table_header;
#define CODA_TIMEOUT 3 /* timeout on upcalls to become intrble */ #define CODA_TIMEOUT 3 /* timeout on upcalls to become intrble */
#define CODA_MC 4 /* use/do not use the access cache */ #define CODA_MC 4 /* use/do not use the access cache */
#define CODA_HARD 5 /* mount type "hard" or "soft" */ #define CODA_HARD 5 /* mount type "hard" or "soft" */
#define CODA_VFS 6 /* vfs statistics */
#define CODA_UPCALL 7 /* upcall statistics */
#define CODA_PERMISSION 8 /* permission statistics */
#define CODA_CACHE_INV 9 /* cache invalidation statistics */
...@@ -56,6 +60,10 @@ static ctl_table coda_table[] = { ...@@ -56,6 +60,10 @@ static ctl_table coda_table[] = {
{CODA_MC, "accesscache", &coda_access_cache, sizeof(int), 0644, NULL, &coda_dointvec}, {CODA_MC, "accesscache", &coda_access_cache, sizeof(int), 0644, NULL, &coda_dointvec},
{CODA_TIMEOUT, "timeout", &coda_timeout, sizeof(int), 0644, NULL, &coda_dointvec}, {CODA_TIMEOUT, "timeout", &coda_timeout, sizeof(int), 0644, NULL, &coda_dointvec},
{CODA_HARD, "hard", &coda_hard, sizeof(int), 0644, NULL, &coda_dointvec}, {CODA_HARD, "hard", &coda_hard, sizeof(int), 0644, NULL, &coda_dointvec},
{CODA_VFS, "vfs_stats", NULL, 0, 0644, NULL, &do_reset_coda_vfs_stats},
{CODA_UPCALL, "upcall_stats", NULL, 0, 0644, NULL, &do_reset_coda_upcall_stats},
{CODA_PERMISSION, "permission_stats", NULL, 0, 0644, NULL, &do_reset_coda_permission_stats},
{CODA_CACHE_INV, "cache_inv_stats", NULL, 0, 0644, NULL, &do_reset_coda_cache_inv_stats},
{ 0 } { 0 }
}; };
......
...@@ -37,6 +37,11 @@ ...@@ -37,6 +37,11 @@
#include <linux/coda_psdev.h> #include <linux/coda_psdev.h>
#include <linux/coda_fs_i.h> #include <linux/coda_fs_i.h>
#include <linux/coda_cache.h> #include <linux/coda_cache.h>
#include <linux/coda_proc.h>
static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize,
union inputArgs *buffer);
#define UPARG(op)\ #define UPARG(op)\
do {\ do {\
...@@ -68,10 +73,11 @@ int venus_rootfid(struct super_block *sb, ViceFid *fidp) ...@@ -68,10 +73,11 @@ int venus_rootfid(struct super_block *sb, ViceFid *fidp)
union inputArgs *inp; union inputArgs *inp;
union outputArgs *outp; union outputArgs *outp;
int insize, outsize, error; int insize, outsize, error;
ENTRY; ENTRY;
insize = SIZE(root); insize = SIZE(root);
UPARG(CFS_ROOT); UPARG(CFS_ROOT);
error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
if (error) { if (error) {
...@@ -583,11 +589,13 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid, ...@@ -583,11 +589,13 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
* reply and return Venus' error, also POSITIVE. * reply and return Venus' error, also POSITIVE.
* *
*/ */
static inline void coda_waitfor_upcall(struct vmsg *vmp) static inline unsigned long coda_waitfor_upcall(struct vmsg *vmp)
{ {
struct wait_queue wait = { current, NULL }; struct wait_queue wait = { current, NULL };
unsigned long posttime;
vmp->vm_posttime = jiffies; vmp->vm_posttime = jiffies;
posttime = jiffies;
add_wait_queue(&vmp->vm_sleep, &wait); add_wait_queue(&vmp->vm_sleep, &wait);
for (;;) { for (;;) {
...@@ -616,13 +624,17 @@ static inline void coda_waitfor_upcall(struct vmsg *vmp) ...@@ -616,13 +624,17 @@ static inline void coda_waitfor_upcall(struct vmsg *vmp)
remove_wait_queue(&vmp->vm_sleep, &wait); remove_wait_queue(&vmp->vm_sleep, &wait);
current->state = TASK_RUNNING; current->state = TASK_RUNNING;
return; CDEBUG(D_SPECIAL, "posttime: %ld, returned: %ld\n", posttime, jiffies-posttime);
return (jiffies - posttime);
} }
int coda_upcall(struct coda_sb_info *sbi, int inSize, int *outSize, static int coda_upcall(struct coda_sb_info *sbi,
int inSize, int *outSize,
union inputArgs *buffer) union inputArgs *buffer)
{ {
unsigned long runtime;
struct vcomm *vcommp; struct vcomm *vcommp;
union outputArgs *out; union outputArgs *out;
struct vmsg *vmp; struct vmsg *vmp;
...@@ -635,7 +647,6 @@ ENTRY; ...@@ -635,7 +647,6 @@ ENTRY;
} }
vcommp = sbi->sbi_vcomm; vcommp = sbi->sbi_vcomm;
clstats(((union inputArgs *)buffer)->ih.opcode);
if (!vcomm_open(vcommp)) if (!vcomm_open(vcommp))
return(ENODEV); return(ENODEV);
...@@ -670,7 +681,8 @@ ENTRY; ...@@ -670,7 +681,8 @@ ENTRY;
* ENODEV. */ * ENODEV. */
/* Go to sleep. Wake up on signals only after the timeout. */ /* Go to sleep. Wake up on signals only after the timeout. */
coda_waitfor_upcall(vmp); runtime = coda_waitfor_upcall(vmp);
coda_upcall_stats(((union inputArgs *)buffer)->ih.opcode, runtime);
CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n", CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n",
vmp->vm_opcode, jiffies - vmp->vm_posttime, vmp->vm_opcode, jiffies - vmp->vm_posttime,
......
...@@ -109,7 +109,11 @@ extern inline void get_mmu_context(struct task_struct *p) ...@@ -109,7 +109,11 @@ extern inline void get_mmu_context(struct task_struct *p)
#endif #endif
} }
#define init_new_context(mm) do { } while(0) extern inline void init_new_context(struct mm_struct *mm)
{
mm->context = 0;
}
#define destroy_context(mm) do { } while(0) #define destroy_context(mm) do { } while(0)
#endif #endif
......
/*
* coda_statis.h
*
* CODA operation statistics
*
* (c) March, 1998
* by Michihiro Kuramochi, Zhenyu Xia and Zhanyong Wan
* zhanyong.wan@yale.edu
*
*/
#ifndef _CODA_PROC_H
#define _CODA_PROC_H
void coda_sysctl_init(void);
void coda_sysctl_clean(void);
void coda_upcall_stats(int opcode, unsigned long jiffies);
#include <linux/sysctl.h>
#include <linux/coda_fs_i.h>
#include <linux/coda.h>
/* these four files are presented to show the result of the statistics:
*
* /proc/fs/coda/vfs_stats
* upcall_stats
* permission_stats
* cache_inv_stats
*
* these four files are presented to reset the statistics to 0:
*
* /proc/sys/coda/vfs_stats
* upcall_stats
* permission_stats
* cache_inv_stats
*/
/* VFS operation statistics */
struct coda_vfs_stats
{
/* file operations */
int file_read;
int file_write;
int file_mmap;
int open;
int release;
int fsync;
/* dir operations */
int readdir;
/* inode operations */
int create;
int lookup;
int link;
int unlink;
int symlink;
int mkdir;
int rmdir;
int rename;
int permission;
int readpage;
/* symlink operatoins*/
int follow_link;
int readlink;
};
struct coda_upcall_stats_entry
{
int count;
unsigned long time_sum;
unsigned long time_squared_sum;
};
/* cache hits for permissions statistics */
struct coda_permission_stats
{
int count;
int hit_count;
};
/* cache invalidation statistics */
struct coda_cache_inv_stats
{
int flush;
int purge_user;
int zap_dir;
int zap_file;
int zap_vnode;
int purge_fid;
int replace;
};
/* these global variables hold the actual statistics data */
extern struct coda_vfs_stats coda_vfs_stat;
extern struct coda_permission_stats coda_permission_stat;
extern struct coda_cache_inv_stats coda_cache_inv_stat;
/* reset statistics to 0 */
void reset_coda_vfs_stats( void );
void reset_coda_upcall_stats( void );
void reset_coda_permission_stats( void );
void reset_coda_cache_inv_stats( void );
/* some utitlities to make it easier for you to do statistics for time */
void do_time_stats( struct coda_upcall_stats_entry * pentry,
unsigned long jiffy );
/*
double get_time_average( const struct coda_upcall_stats_entry * pentry );
double get_time_std_deviation( const struct coda_upcall_stats_entry * pentry );
*/
unsigned long get_time_average( const struct coda_upcall_stats_entry * pentry );
unsigned long get_time_std_deviation( const struct coda_upcall_stats_entry * pentry );
/* like coda_dointvec, these functions are to be registered in the ctl_table
* data structure for /proc/sys/... files
*/
int do_reset_coda_vfs_stats( ctl_table * table, int write, struct file * filp,
void * buffer, size_t * lenp );
int do_reset_coda_upcall_stats( ctl_table * table, int write,
struct file * filp, void * buffer,
size_t * lenp );
int do_reset_coda_permission_stats( ctl_table * table, int write,
struct file * filp, void * buffer,
size_t * lenp );
int do_reset_coda_cache_inv_stats( ctl_table * table, int write,
struct file * filp, void * buffer,
size_t * lenp );
/* these functions are called to form the content of /proc/fs/coda/... files */
int coda_vfs_stats_get_info( char * buffer, char ** start, off_t offset,
int length, int dummy );
int coda_upcall_stats_get_info( char * buffer, char ** start, off_t offset,
int length, int dummy );
int coda_permission_stats_get_info( char * buffer, char ** start, off_t offset,
int length, int dummy );
int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset,
int length, int dummy );
#endif /* _CODA_PROC_H */
...@@ -94,8 +94,6 @@ int venus_access(struct super_block *sb, struct ViceFid *fid, int mask); ...@@ -94,8 +94,6 @@ int venus_access(struct super_block *sb, struct ViceFid *fid, int mask);
int venus_pioctl(struct super_block *sb, struct ViceFid *fid, int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
unsigned int cmd, struct PioctlData *data); unsigned int cmd, struct PioctlData *data);
int coda_downcall(int opcode, union outputArgs *out, struct super_block *sb); int coda_downcall(int opcode, union outputArgs *out, struct super_block *sb);
int coda_upcall(struct coda_sb_info *mntinfo, int inSize,
int *outSize, union inputArgs *buffer);
int venus_fsync(struct super_block *sb, struct ViceFid *fid); int venus_fsync(struct super_block *sb, struct ViceFid *fid);
......
/*
* Sysctl operations for Coda.
* Original version: (C) 1996 Peter Braam
* Rewritten for Linux 2.1: (C) 1997 Carnegie Mellon University
*
* Carnegie Mellon encourages users of this code to contribute improvements
* to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
*/
void coda_sysctl_init(void);
void coda_sysctl_clean(void);
...@@ -131,7 +131,7 @@ extern int d_invalidate(struct dentry *); ...@@ -131,7 +131,7 @@ extern int d_invalidate(struct dentry *);
/* dcache memory management */ /* dcache memory management */
extern int select_dcache(int, int); extern int select_dcache(int, int);
extern void shrink_dcache_memory(void); extern void shrink_dcache_memory(int, unsigned int);
extern void check_dcache_memory(void); extern void check_dcache_memory(void);
extern void free_inode_memory(int); /* defined in fs/inode.c */ extern void free_inode_memory(int); /* defined in fs/inode.c */
......
This diff is collapsed.
...@@ -51,6 +51,7 @@ enum root_directory_inos { ...@@ -51,6 +51,7 @@ enum root_directory_inos {
PROC_PPC_HTAB, PROC_PPC_HTAB,
PROC_SOUND, PROC_SOUND,
PROC_MTRR, /* whether enabled or not */ PROC_MTRR, /* whether enabled or not */
PROC_FS
}; };
enum pid_directory_inos { enum pid_directory_inos {
...@@ -205,6 +206,19 @@ enum bus_directory_inos { ...@@ -205,6 +206,19 @@ enum bus_directory_inos {
PROC_BUS_LAST PROC_BUS_LAST
}; };
enum fs_directory_inos {
PROC_FS_CODA = PROC_MCA_LAST,
PROC_FS_LAST
};
enum fs_coda_directory_inos {
PROC_VFS_STATS = PROC_MCA_LAST,
PROC_UPCALL_STATS,
PROC_PERMISSION_STATS,
PROC_CACHE_INV_STATS,
PROC_CODA_FS_LAST
};
/* Finally, the dynamically allocatable proc entries are reserved: */ /* Finally, the dynamically allocatable proc entries are reserved: */
#define PROC_DYNAMIC_FIRST 4096 #define PROC_DYNAMIC_FIRST 4096
......
...@@ -50,6 +50,15 @@ typedef struct freepages_v1 ...@@ -50,6 +50,15 @@ typedef struct freepages_v1
typedef freepages_v1 freepages_t; typedef freepages_v1 freepages_t;
extern freepages_t freepages; extern freepages_t freepages;
typedef struct pager_daemon_v1
{
unsigned int tries_base;
unsigned int tries_min;
unsigned int swap_cluster;
} pager_daemon_v1;
typedef pager_daemon_v1 pager_daemon_t;
extern pager_daemon_t pager_daemon;
#define SC_VERSION 1 #define SC_VERSION 1
#define SC_MAX_VERSION 1 #define SC_MAX_VERSION 1
......
...@@ -84,7 +84,8 @@ enum ...@@ -84,7 +84,8 @@ enum
VM_BDFLUSH, /* struct: Control buffer cache flushing */ VM_BDFLUSH, /* struct: Control buffer cache flushing */
VM_OVERCOMMIT_MEMORY, /* Turn off the virtual memory safety limit */ VM_OVERCOMMIT_MEMORY, /* Turn off the virtual memory safety limit */
VM_BUFFERMEM, /* struct: Set buffer memory thresholds */ VM_BUFFERMEM, /* struct: Set buffer memory thresholds */
VM_PAGECACHE /* struct: Set cache memory thresholds */ VM_PAGECACHE, /* struct: Set cache memory thresholds */
VM_PAGERDAEMON /* struct: Control kswapd behaviour */
}; };
......
...@@ -255,12 +255,12 @@ struct ufs_superblock { ...@@ -255,12 +255,12 @@ struct ufs_superblock {
__s32 fs_contigsumsize;/* size of cluster summary array */ __s32 fs_contigsumsize;/* size of cluster summary array */
__s32 fs_maxsymlinklen;/* max length of an internal symlink */ __s32 fs_maxsymlinklen;/* max length of an internal symlink */
__s32 fs_inodefmt; /* format of on-disk inodes */ __s32 fs_inodefmt; /* format of on-disk inodes */
__u64 fs_maxfilesize; /* max representable file size */ __u32 fs_maxfilesize[2];/* max representable file size */
__u32 fs_qbmask[2]; /* ~usb_bmask */ __u32 fs_qbmask[2]; /* ~usb_bmask */
__u32 fs_qfmask[2]; /* ~usb_fmask */ __u32 fs_qfmask[2]; /* ~usb_fmask */
__s32 fs_state; /* file system state time stamp */ __s32 fs_state; /* file system state time stamp */
} fs_44; } fs_44;
} fs_u __attribute__ ((packed)); } fs_u;
__s32 fs_postblformat; /* format of positional layout tables */ __s32 fs_postblformat; /* format of positional layout tables */
__s32 fs_nrpos; /* number of rotational positions */ __s32 fs_nrpos; /* number of rotational positions */
__s32 fs_postbloff; /* (__s16) rotation block list head */ __s32 fs_postbloff; /* (__s16) rotation block list head */
......
...@@ -189,20 +189,22 @@ static ctl_table kern_table[] = { ...@@ -189,20 +189,22 @@ static ctl_table kern_table[] = {
static ctl_table vm_table[] = { static ctl_table vm_table[] = {
{VM_SWAPCTL, "swapctl", {VM_SWAPCTL, "swapctl",
&swap_control, sizeof(swap_control_t), 0600, NULL, &proc_dointvec}, &swap_control, sizeof(swap_control_t), 0644, NULL, &proc_dointvec},
{VM_SWAPOUT, "swapout_interval", {VM_SWAPOUT, "swapout_interval",
&swapout_interval, sizeof(int), 0600, NULL, &proc_dointvec}, &swapout_interval, sizeof(int), 0644, NULL, &proc_dointvec},
{VM_FREEPG, "freepages", {VM_FREEPG, "freepages",
&freepages, sizeof(freepages_t), 0600, NULL, &proc_dointvec}, &freepages, sizeof(freepages_t), 0644, NULL, &proc_dointvec},
{VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL, {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL,
&proc_dointvec_minmax, &sysctl_intvec, NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
&bdflush_min, &bdflush_max}, &bdflush_min, &bdflush_max},
{VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory, {VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory,
sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec}, sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec},
{VM_BUFFERMEM, "buffermem", {VM_BUFFERMEM, "buffermem",
&buffer_mem, sizeof(buffer_mem_t), 0600, NULL, &proc_dointvec}, &buffer_mem, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
{VM_PAGECACHE, "pagecache", {VM_PAGECACHE, "pagecache",
&page_cache, sizeof(buffer_mem_t), 0600, NULL, &proc_dointvec}, &page_cache, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
{VM_PAGERDAEMON, "kswapd",
&pager_daemon, sizeof(pager_daemon_t), 0644, NULL, &proc_dointvec},
{0} {0}
}; };
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
O_TARGET := mm.o O_TARGET := mm.o
O_OBJS := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \ O_OBJS := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \
vmalloc.o slab.o simp.o\ vmalloc.o slab.o \
swap.o vmscan.o page_io.o page_alloc.o swap_state.o swapfile.o swap.o vmscan.o page_io.o page_alloc.o swap_state.o swapfile.o
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
...@@ -125,7 +125,7 @@ int free_memory_available(int nr) ...@@ -125,7 +125,7 @@ int free_memory_available(int nr)
* free unfragmented memory. * free unfragmented memory.
* Added low/high water marks to avoid thrashing -- Rik. * Added low/high water marks to avoid thrashing -- Rik.
*/ */
if (nr_free_pages > (num_physpages >> 5) + (nr ? 0 : num_physpages >> 6)) if (nr_free_pages > (nr ? freepages.low : freepages.high))
return nr+1; return nr+1;
list = free_area + NR_MEM_LISTS; list = free_area + NR_MEM_LISTS;
...@@ -282,7 +282,6 @@ unsigned long __get_free_pages(int gfp_mask, unsigned long order) ...@@ -282,7 +282,6 @@ unsigned long __get_free_pages(int gfp_mask, unsigned long order)
spin_unlock_irqrestore(&page_alloc_lock, flags); spin_unlock_irqrestore(&page_alloc_lock, flags);
if (!(gfp_mask & __GFP_WAIT)) if (!(gfp_mask & __GFP_WAIT))
break; break;
shrink_dcache();
if (!try_to_free_pages(gfp_mask, SWAP_CLUSTER_MAX)) if (!try_to_free_pages(gfp_mask, SWAP_CLUSTER_MAX))
break; break;
gfp_mask &= ~__GFP_WAIT; /* go through this only once */ gfp_mask &= ~__GFP_WAIT; /* go through this only once */
...@@ -335,15 +334,19 @@ __initfunc(unsigned long free_area_init(unsigned long start_mem, unsigned long e ...@@ -335,15 +334,19 @@ __initfunc(unsigned long free_area_init(unsigned long start_mem, unsigned long e
int i; int i;
/* /*
* select nr of pages we try to keep free for important stuff * Select nr of pages we try to keep free for important stuff
* with a minimum of 48 pages. This is totally arbitrary * with a minimum of 48 pages and a maximum of 256 pages, so
* that we don't waste too much memory on large systems.
* This is totally arbitrary.
*/ */
i = (end_mem - PAGE_OFFSET) >> (PAGE_SHIFT+7); i = (end_mem - PAGE_OFFSET) >> (PAGE_SHIFT+7);
if (i < 48) if (i < 48)
i = 48; i = 48;
if (i > 256)
i = 256;
freepages.min = i; freepages.min = i;
freepages.low = i + (i>>1); freepages.low = i << 1;
freepages.high = i + i; freepages.high = freepages.low + i;
mem_map = (mem_map_t *) LONG_ALIGN(start_mem); mem_map = (mem_map_t *) LONG_ALIGN(start_mem);
p = mem_map + MAP_NR(end_mem); p = mem_map + MAP_NR(end_mem);
start_mem = LONG_ALIGN((unsigned long) p); start_mem = LONG_ALIGN((unsigned long) p);
......
...@@ -44,8 +44,8 @@ ...@@ -44,8 +44,8 @@
*/ */
freepages_t freepages = { freepages_t freepages = {
48, /* freepages.min */ 48, /* freepages.min */
72, /* freepages.low */ 96, /* freepages.low */
96 /* freepages.high */ 144 /* freepages.high */
}; };
/* We track the number of pages currently being asynchronously swapped /* We track the number of pages currently being asynchronously swapped
...@@ -77,3 +77,9 @@ buffer_mem_t page_cache = { ...@@ -77,3 +77,9 @@ buffer_mem_t page_cache = {
30, /* borrow percent page cache */ 30, /* borrow percent page cache */
75 /* maximum */ 75 /* maximum */
}; };
pager_daemon_t pager_daemon = {
512, /* base number for calculating the number of tries */
SWAP_CLUSTER_MAX, /* minimum number of tries */
SWAP_CLUSTER_MAX, /* do swap I/O in clusters of this size */
};
...@@ -553,22 +553,23 @@ int kswapd(void *unused) ...@@ -553,22 +553,23 @@ int kswapd(void *unused)
* more aggressive if we're really * more aggressive if we're really
* low on free memory. * low on free memory.
* *
* The number of tries is 512 divided by an * We try page_daemon.tries_base times, divided by
* 'urgency factor'. In practice this will mean * an 'urgency factor'. In practice this will mean
* a value of 512 / 8 = 64 pages at a time, * a value of pager_daemon.tries_base / 8 or 4 = 64
* giving 64 * 4 (times/sec) * 4k (pagesize) = * or 128 pages at a time.
* 1 MB/s in lowest-priority background * This gives us 64 (or 128) * 4k * 4 (times/sec) =
* paging. This number rises to 8 MB/s when the * 1 (or 2) MB/s swapping bandwidth in low-priority
* priority is highest (but then we'll be woken * background paging. This number rises to 8 MB/s
* up more often and the rate will be even higher). * when the priority is highest (but then we'll be
* -- Should make this sysctl tunable... * woken up more often and the rate will be even
* higher).
*/ */
tries = (512) >> free_memory_available(3); tries = pager_daemon.tries_base >> free_memory_available(3);
while (tries--) { while (tries--) {
int gfp_mask; int gfp_mask;
if (++tried > SWAP_CLUSTER_MAX && free_memory_available(0)) if (++tried > pager_daemon.tries_min && free_memory_available(0))
break; break;
gfp_mask = __GFP_IO; gfp_mask = __GFP_IO;
try_to_free_page(gfp_mask); try_to_free_page(gfp_mask);
...@@ -576,7 +577,7 @@ int kswapd(void *unused) ...@@ -576,7 +577,7 @@ int kswapd(void *unused)
* Syncing large chunks is faster than swapping * Syncing large chunks is faster than swapping
* synchronously (less head movement). -- Rik. * synchronously (less head movement). -- Rik.
*/ */
if (atomic_read(&nr_async_pages) >= SWAP_CLUSTER_MAX) if (atomic_read(&nr_async_pages) >= pager_daemon.swap_cluster)
run_task_queue(&tq_disk); run_task_queue(&tq_disk);
} }
......
...@@ -53,10 +53,6 @@ ...@@ -53,10 +53,6 @@
# #
# 090398 Axel Boldt (boldt@math.ucsb.edu) - allow for empty lines in help # 090398 Axel Boldt (boldt@math.ucsb.edu) - allow for empty lines in help
# texts. # texts.
#
# 100498 Riley Williams (rhw@bigfoot.com) - added ability to display
# blank lines in help texts: Any line consisting only of a single dot
# will be displayed blank.
# #
# Make sure we're really running bash. # Make sure we're really running bash.
...@@ -107,7 +103,7 @@ ${var}:\\ ...@@ -107,7 +103,7 @@ ${var}:\\
then then
echo; echo " Sorry, no help available for this option yet.";echo echo; echo " Sorry, no help available for this option yet.";echo
else else
(echo; echo "$text") | sed 's/^\.$//' | ${PAGER:-more} (echo; echo "$text") | ${PAGER:-more}
fi fi
else else
echo; echo;
......
...@@ -47,13 +47,6 @@ ...@@ -47,13 +47,6 @@
# #
# 090398 Axel Boldt (boldt@math.ucsb.edu) - allow for empty lines in help # 090398 Axel Boldt (boldt@math.ucsb.edu) - allow for empty lines in help
# texts. # texts.
#----------------------------------------------------------------------------
#
# 10 Apr 1998 - Added ability to display blank lines in help text: Any line
# which only contains a single dot will be displayed blank.
# Author: Riley Williams <rhw@bigfoot.com>
#
#----------------------------------------------------------------------------
# #
...@@ -301,7 +294,7 @@ ${var}:\\ ...@@ -301,7 +294,7 @@ ${var}:\\
echo "There is no help available for this kernel option." echo "There is no help available for this kernel option."
return 1 return 1
else else
echo "$text" | sed 's/^\.$//' echo "$text"
fi fi
else else
echo "There is no help available for this kernel option." echo "There is no help available for this kernel option."
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment