Commit 1b6d23c1 authored by Linus Torvalds's avatar Linus Torvalds

Linux 2.1.99pre1

a cleanup of my previous patches wrt irq handling, and also fixes
a real bug (we used to ACK the io-apic outside the irq-controller lock,
which meant that the ack's we did and "ipi_pending[]" might have gotten
out of sync - which could certainly have resulted in bad behaviour).
This also re-enables the code that replays interrupts in enable_irq(),
because it should be ok now that the rest of the code is cleaned up.
People that had the earlier problem with locking up with floppies, please
test: if this re-introduces the lockup, please just #if 0 out all the code
inside trigger_pending_irqs(), and send me a note telling me that that
code still doesn't work.

                Linus
parent 61cb5dec
...@@ -4,19 +4,19 @@ Kirk Petersen ...@@ -4,19 +4,19 @@ Kirk Petersen
Kmod is a simple replacement for kerneld. It consists of a Kmod is a simple replacement for kerneld. It consists of a
request_module() replacement and a kernel thread called kmod. When the request_module() replacement and a kernel thread called kmod. When the
kernel requests a module, the kmod wakes up and execve()s modprobe, kernel requests a module, the kmod wakes up and execve()s modprobe,
passing it the name that was requested. After a configurable period of passing it the name that was requested.
time, kmod will have delete_module() remove any unused modules.
Kmod is configurable through two entries in /proc/sys/kernel. You can If you have the /proc filesystem mounted, you can set the path of
set the path of modprobe (where the kernel looks for it) by doing: modprobe (where the kernel looks for it) by doing:
echo "/sbin/modprobe" > /proc/sys/kernel/modprobe echo "/sbin/modprobe" > /proc/sys/kernel/modprobe
To tell kmod when to unload unused modules, do something like: To periodically unload unused modules, put something like the following
in root's crontab entry:
echo "120" > /proc/sys/kernel/kmod_unload_delay 0-59/5 * * * * /sbin/rmmod -a
Kmod only loads and unloads modules. Kerneld could do more (although Kmod only loads modules. Kerneld could do more (although
nothing in the standard kernel used its other features). If you nothing in the standard kernel used its other features). If you
require features such as request_route, we suggest that you take require features such as request_route, we suggest that you take
a similar approach. A simple request_route function could be called, a similar approach. A simple request_route function could be called,
......
...@@ -25,7 +25,6 @@ Currently, these files are in /proc/sys/kernel: ...@@ -25,7 +25,6 @@ Currently, these files are in /proc/sys/kernel:
- inode-max - inode-max
- inode-nr - inode-nr
- inode-state - inode-state
- kmod_unload_delay ==> Documentation/kmod.txt
- modprobe ==> Documentation/kmod.txt - modprobe ==> Documentation/kmod.txt
- osrelease - osrelease
- ostype - ostype
......
VERSION = 2 VERSION = 2
PATCHLEVEL = 1 PATCHLEVEL = 1
SUBLEVEL = 98 SUBLEVEL = 99
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
......
...@@ -27,11 +27,18 @@ ...@@ -27,11 +27,18 @@
*/ */
/* Allow an exception for an insn; exit if we get one. */ /* Allow an exception for an insn; exit if we get one. */
#define EX(x,y...) \ #define EXI(x,y...) \
99: x,##y; \ 99: x,##y; \
.section __ex_table,"a"; \ .section __ex_table,"a"; \
.gprel32 99b; \ .gprel32 99b; \
lda $31, $exit-99b($31); \ lda $31, $exitin-99b($31); \
.previous
#define EXO(x,y...) \
99: x,##y; \
.section __ex_table,"a"; \
.gprel32 99b; \
lda $31, $exitout-99b($31); \
.previous .previous
.set noat .set noat
...@@ -45,14 +52,14 @@ __copy_user: ...@@ -45,14 +52,14 @@ __copy_user:
subq $3,8,$3 subq $3,8,$3
.align 5 .align 5
$37: $37:
EX( ldq_u $1,0($7) ) EXI( ldq_u $1,0($7) )
EX( ldq_u $2,0($6) ) EXO( ldq_u $2,0($6) )
extbl $1,$7,$1 extbl $1,$7,$1
mskbl $2,$6,$2 mskbl $2,$6,$2
insbl $1,$6,$1 insbl $1,$6,$1
addq $3,1,$3 addq $3,1,$3
bis $1,$2,$1 bis $1,$2,$1
EX( stq_u $1,0($6) ) EXO( stq_u $1,0($6) )
subq $0,1,$0 subq $0,1,$0
addq $6,1,$6 addq $6,1,$6
addq $7,1,$7 addq $7,1,$7
...@@ -63,10 +70,10 @@ $36: ...@@ -63,10 +70,10 @@ $36:
bic $0,7,$4 bic $0,7,$4
beq $1,$43 beq $1,$43
beq $4,$48 beq $4,$48
EX( ldq_u $3,0($7) ) EXI( ldq_u $3,0($7) )
.align 5 .align 5
$50: $50:
EX( ldq_u $2,8($7) ) EXI( ldq_u $2,8($7) )
subq $4,8,$4 subq $4,8,$4
extql $3,$7,$3 extql $3,$7,$3
extqh $2,$7,$1 extqh $2,$7,$1
...@@ -81,13 +88,13 @@ $48: ...@@ -81,13 +88,13 @@ $48:
beq $0,$41 beq $0,$41
.align 5 .align 5
$57: $57:
EX( ldq_u $1,0($7) ) EXI( ldq_u $1,0($7) )
EX( ldq_u $2,0($6) ) EXO( ldq_u $2,0($6) )
extbl $1,$7,$1 extbl $1,$7,$1
mskbl $2,$6,$2 mskbl $2,$6,$2
insbl $1,$6,$1 insbl $1,$6,$1
bis $1,$2,$1 bis $1,$2,$1
EX( stq_u $1,0($6) ) EXO( stq_u $1,0($6) )
subq $0,1,$0 subq $0,1,$0
addq $6,1,$6 addq $6,1,$6
addq $7,1,$7 addq $7,1,$7
...@@ -98,7 +105,7 @@ $43: ...@@ -98,7 +105,7 @@ $43:
beq $4,$65 beq $4,$65
.align 5 .align 5
$66: $66:
EX( ldq $1,0($7) ) EXI( ldq $1,0($7) )
subq $4,8,$4 subq $4,8,$4
stq $1,0($6) stq $1,0($6)
addq $7,8,$7 addq $7,8,$7
...@@ -107,15 +114,31 @@ $66: ...@@ -107,15 +114,31 @@ $66:
bne $4,$66 bne $4,$66
$65: $65:
beq $0,$41 beq $0,$41
EX( ldq $2,0($7) ) EXI( ldq $2,0($7) )
EX( ldq $1,0($6) ) EXO( ldq $1,0($6) )
mskql $2,$0,$2 mskql $2,$0,$2
mskqh $1,$0,$1 mskqh $1,$0,$1
bis $2,$1,$2 bis $2,$1,$2
EX( stq $2,0($6) ) EXO( stq $2,0($6) )
bis $31,$31,$0 bis $31,$31,$0
$41: $41:
$35: $35:
$exit: $exitout:
ret $31,($28),1 ret $31,($28),1
$exitin:
/* A stupid byte-by-byte zeroing of the rest of the output
buffer. This cures security holes by never leaving
random kernel data around to be copied elsewhere. */
mov $0,$1
$101:
EXO ( ldq_u $2,0($6) )
subq $1,1,$1
mskbl $2,$6,$2
EXO ( stq_u $2,0($6) )
addq $6,1,$6
bgt $1,$101
ret $31,($28),1
.end __copy_user .end __copy_user
...@@ -70,9 +70,6 @@ spinlock_t irq_controller_lock; ...@@ -70,9 +70,6 @@ spinlock_t irq_controller_lock;
static unsigned int irq_events [NR_IRQS] = { -1, }; static unsigned int irq_events [NR_IRQS] = { -1, };
static int disabled_irq [NR_IRQS] = { 0, }; static int disabled_irq [NR_IRQS] = { 0, };
#ifdef __SMP__
static int ipi_pending [NR_IRQS] = { 0, };
#endif
/* /*
* Not all IRQs can be routed through the IO-APIC, eg. on certain (older) * Not all IRQs can be routed through the IO-APIC, eg. on certain (older)
...@@ -651,18 +648,6 @@ static int handle_IRQ_event(unsigned int irq, struct pt_regs * regs) ...@@ -651,18 +648,6 @@ static int handle_IRQ_event(unsigned int irq, struct pt_regs * regs)
return status; return status;
} }
void disable_irq(unsigned int irq)
{
unsigned long flags;
spin_lock_irqsave(&irq_controller_lock, flags);
irq_handles[irq]->disable(irq);
spin_unlock_irqrestore(&irq_controller_lock, flags);
synchronize_irq();
}
/* /*
* disable/enable_irq() wait for all irq contexts to finish * disable/enable_irq() wait for all irq contexts to finish
* executing. Also it's recursive. * executing. Also it's recursive.
...@@ -673,55 +658,10 @@ static void disable_8259A_irq(unsigned int irq) ...@@ -673,55 +658,10 @@ static void disable_8259A_irq(unsigned int irq)
set_8259A_irq_mask(irq); set_8259A_irq_mask(irq);
} }
#ifdef __SMP__
static void disable_ioapic_irq(unsigned int irq)
{
disabled_irq[irq] = 1;
/*
* We do not disable IO-APIC irqs in hardware ...
*/
}
#endif
void enable_8259A_irq (unsigned int irq) void enable_8259A_irq (unsigned int irq)
{ {
unsigned long flags;
spin_lock_irqsave(&irq_controller_lock, flags);
cached_irq_mask &= ~(1 << irq); cached_irq_mask &= ~(1 << irq);
set_8259A_irq_mask(irq); set_8259A_irq_mask(irq);
spin_unlock_irqrestore(&irq_controller_lock, flags);
}
#ifdef __SMP__
void enable_ioapic_irq (unsigned int irq)
{
unsigned long flags, should_handle_irq;
int cpu = smp_processor_id();
spin_lock_irqsave(&irq_controller_lock, flags);
disabled_irq[irq] = 0;
/*
* In the SMP+IOAPIC case it might happen that there are an unspecified
* number of pending IRQ events unhandled. These cases are very rare,
* so we 'resend' these IRQs via IPIs, to the same CPU. It's much
* better to do it this way as thus we dont have to be aware of
* 'pending' interrupts in the IRQ path, except at this point.
*/
if (irq_events[irq]) {
if (!ipi_pending[irq]) {
ipi_pending[irq] = 1;
--irq_events[irq];
send_IPI(cpu,IO_APIC_VECTOR(irq));
}
}
spin_unlock_irqrestore(&irq_controller_lock, flags);
}
#endif
void enable_irq(unsigned int irq)
{
irq_handles[irq]->enable(irq);
} }
void make_8259A_irq (unsigned int irq) void make_8259A_irq (unsigned int irq)
...@@ -771,41 +711,107 @@ static void do_8259A_IRQ(unsigned int irq, int cpu, struct pt_regs * regs) ...@@ -771,41 +711,107 @@ static void do_8259A_IRQ(unsigned int irq, int cpu, struct pt_regs * regs)
} }
#ifdef __SMP__ #ifdef __SMP__
static int ipi_pending [NR_IRQS] = { 0, };
/*
* In the SMP+IOAPIC case it might happen that there are an unspecified
* number of pending IRQ events unhandled. These cases are very rare,
* so we 'resend' these IRQs via IPIs, to the same CPU. It's much
* better to do it this way as thus we dont have to be aware of
* 'pending' interrupts in the IRQ path, except at this point.
*/
static inline void trigger_pending_irqs(unsigned int irq)
{
if (irq_events[irq] && !ipi_pending[irq]) {
ipi_pending[irq] = 1;
send_IPI(smp_processor_id(), IO_APIC_VECTOR(irq));
}
}
void enable_ioapic_irq (unsigned int irq)
{
disabled_irq[irq] = 0;
trigger_pending_irqs(irq);
}
/*
* We do not actually disable IO-APIC irqs in hardware ...
*/
static void disable_ioapic_irq(unsigned int irq)
{
disabled_irq[irq] = 1;
}
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)
{ {
int should_handle_irq = 0; spin_lock(&irq_controller_lock);
/* Ack the irq inside the lock! */
ack_APIC_irq(); ack_APIC_irq();
ipi_pending[irq] = 0;
spin_lock(&irq_controller_lock); /* If the irq is disabled, just set a flag and return */
if (ipi_pending[irq]) if (disabled_irq[irq]) {
ipi_pending[irq] = 0; irq_events[irq] = 1;
spin_unlock(&irq_controller_lock);
return;
}
if (!irq_events[irq]++ && !disabled_irq[irq]) disabled_irq[irq] = 1;
should_handle_irq = 1; irq_events[irq] = 0;
hardirq_enter(cpu); hardirq_enter(cpu);
spin_unlock(&irq_controller_lock); spin_unlock(&irq_controller_lock);
if (should_handle_irq) { while (test_bit(0,&global_irq_lock)) barrier();
while (test_bit(0,&global_irq_lock)) mb();
again: for (;;) {
int pending;
handle_IRQ_event(irq, regs); handle_IRQ_event(irq, regs);
spin_lock(&irq_controller_lock); spin_lock(&irq_controller_lock);
should_handle_irq=0; pending = irq_events[irq];
if (--irq_events[irq] && !disabled_irq[irq]) irq_events[irq] = 0;
should_handle_irq=1; disabled_irq[irq] = pending;
spin_unlock(&irq_controller_lock); spin_unlock(&irq_controller_lock);
if (should_handle_irq) if (!pending)
goto again; break;
} }
hardirq_exit(cpu); hardirq_exit(cpu);
release_irqlock(cpu); release_irqlock(cpu);
} }
#endif #endif
/*
* Generic enable/disable code: this just calls
* down into the PIC-specific version after having
* gotten the irq controller lock.
*/
void disable_irq(unsigned int irq)
{
unsigned long flags;
spin_lock_irqsave(&irq_controller_lock, flags);
irq_handles[irq]->disable(irq);
spin_unlock_irqrestore(&irq_controller_lock, flags);
synchronize_irq();
}
void enable_irq(unsigned int irq)
{
unsigned long flags;
spin_lock_irqsave(&irq_controller_lock, flags);
irq_handles[irq]->enable(irq);
spin_unlock_irqrestore(&irq_controller_lock, flags);
}
/* /*
* do_IRQ handles all normal device IRQ's (the special * do_IRQ handles all normal device IRQ's (the special
* SMP cross-CPU interrupts have their own specific * SMP cross-CPU interrupts have their own specific
......
...@@ -90,7 +90,6 @@ void show_mem(void) ...@@ -90,7 +90,6 @@ void show_mem(void)
shared += atomic_read(&mem_map[i].count) - 1; shared += atomic_read(&mem_map[i].count) - 1;
} }
printk("%d pages of RAM\n",total); printk("%d pages of RAM\n",total);
printk("%d free pages\n",free);
printk("%d reserved pages\n",reserved); printk("%d reserved pages\n",reserved);
printk("%d pages shared\n",shared); printk("%d pages shared\n",shared);
printk("%d pages swap cached\n",cached); printk("%d pages swap cached\n",cached);
......
...@@ -4211,7 +4211,6 @@ static int floppy_grab_irq_and_dma(void) ...@@ -4211,7 +4211,6 @@ static int floppy_grab_irq_and_dma(void)
if (FDCS->address != -1) if (FDCS->address != -1)
fd_outb(FDCS->dor, FD_DOR); fd_outb(FDCS->dor, FD_DOR);
fdc = 0; fdc = 0;
fd_enable_irq();
return 0; return 0;
} }
...@@ -4235,7 +4234,6 @@ static void floppy_release_irq_and_dma(void) ...@@ -4235,7 +4234,6 @@ static void floppy_release_irq_and_dma(void)
INT_ON; INT_ON;
fd_disable_dma(); fd_disable_dma();
fd_free_dma(); fd_free_dma();
fd_disable_irq();
fd_free_irq(); fd_free_irq();
set_dor(0, ~0, 8); set_dor(0, ~0, 8);
......
...@@ -18,6 +18,10 @@ ...@@ -18,6 +18,10 @@
********************** **********************
v3.01 (98/04/17)
- Interrupt handler now also checks dev->[se]dev are non-NULL
to avoid crashes in interrupts during card init. [dw]
v3.00 (97/11/09) v3.00 (97/11/09)
- Minor cleanup of debugging messages. [mj] - Minor cleanup of debugging messages. [mj]
...@@ -41,10 +45,10 @@ ...@@ -41,10 +45,10 @@
v2.80 ALPHA (97/08/01) v2.80 ALPHA (97/08/01)
- Split source into multiple files; generic arcnet support and - Split source into multiple files; generic arcnet support and
individual chipset drivers. <dwmw2@cam.ac.uk> individual chipset drivers. <Dave@imladris.demon.co.uk>
v2.61 ALPHA (97/07/30) by David Woodhouse (dwmw2@cam.ac.uk) for v2.61 ALPHA (97/07/30) by David Woodhouse (Dave@imladris.demon.co.uk)
Nortel (Northern Telecom). for Nortel (Northern Telecom).
- Added support for IO-mapped modes and for SMC COM20020 chipset. - Added support for IO-mapped modes and for SMC COM20020 chipset.
- Fixed (avoided) race condition in send_packet routines which was - Fixed (avoided) race condition in send_packet routines which was
discovered when the buffer copy routines got slow (?). discovered when the buffer copy routines got slow (?).
...@@ -170,7 +174,7 @@ ...@@ -170,7 +174,7 @@
*/ */
static const char *version = static const char *version =
"arcnet.c: v3.00 97/11/09 Avery Pennarun <apenwarr@bond.net> et al.\n"; "arcnet.c: v3.01 98/04/24 Avery Pennarun <apenwarr@bond.net> et al.\n";
#include <linux/module.h> #include <linux/module.h>
#include <linux/config.h> #include <linux/config.h>
...@@ -956,20 +960,24 @@ arcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs) ...@@ -956,20 +960,24 @@ arcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs)
return; /* don't even try. */ return; /* don't even try. */
} }
#ifdef CONFIG_ARCNET_1051 #ifdef CONFIG_ARCNET_1051
lp->sdev->interrupt=1; if (lp->sdev)
lp->sdev->interrupt=1;
#endif #endif
#ifdef CONFIG_ARCNET_ETH #ifdef CONFIG_ARCNET_ETH
lp->edev->interrupt=1; if (lp->edev)
lp->edev->interrupt=1;
#endif #endif
/* Call the "real" interrupt handler. */ /* Call the "real" interrupt handler. */
(*lp->inthandler)(dev); (*lp->inthandler)(dev);
#ifdef CONFIG_ARCNET_ETH #ifdef CONFIG_ARCNET_ETH
lp->edev->interrupt=0; if (lp->edev)
lp->edev->interrupt=0;
#endif #endif
#ifdef CONFIG_ARCNET_1051 #ifdef CONFIG_ARCNET_1051
lp->sdev->interrupt=0; if (lp->sdev)
lp->sdev->interrupt=0;
#endif #endif
if (!test_and_clear_bit(0, (int *)&dev->interrupt)) if (!test_and_clear_bit(0, (int *)&dev->interrupt))
BUGMSG(D_NORMAL, "Someone cleared our dev->interrupt flag!\n"); BUGMSG(D_NORMAL, "Someone cleared our dev->interrupt flag!\n");
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/config.h> #include <linux/config.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/blk.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/ioport.h> #include <linux/ioport.h>
...@@ -1204,10 +1205,13 @@ static boolean BusLogic_Failure(BusLogic_HostAdapter_T *HostAdapter, ...@@ -1204,10 +1205,13 @@ static boolean BusLogic_Failure(BusLogic_HostAdapter_T *HostAdapter,
{ {
BusLogic_AnnounceDriver(HostAdapter); BusLogic_AnnounceDriver(HostAdapter);
if (HostAdapter->HostAdapterBusType == BusLogic_PCI_Bus) if (HostAdapter->HostAdapterBusType == BusLogic_PCI_Bus)
BusLogic_Error("While configuring BusLogic PCI Host Adapter at\n" {
"Bus %d Device %d I/O Address 0x%X PCI Address 0x%X:\n", BusLogic_Error("While configuring BusLogic PCI Host Adapter at\n",
HostAdapter, HostAdapter->Bus, HostAdapter->Device, HostAdapter);
HostAdapter->IO_Address, HostAdapter->PCI_Address); BusLogic_Error("Bus %d Device %d I/O Address 0x%X PCI Address 0x%X:\n",
HostAdapter, HostAdapter->Bus, HostAdapter->Device,
HostAdapter->IO_Address, HostAdapter->PCI_Address);
}
else BusLogic_Error("While configuring BusLogic Host Adapter at " else BusLogic_Error("While configuring BusLogic Host Adapter at "
"I/O Address 0x%X:\n", HostAdapter, "I/O Address 0x%X:\n", HostAdapter,
HostAdapter->IO_Address); HostAdapter->IO_Address);
......
...@@ -1532,7 +1532,6 @@ static inline ...@@ -1532,7 +1532,6 @@ static inline
void BusLogic_AcquireHostAdapterLockIH(BusLogic_HostAdapter_T *HostAdapter, void BusLogic_AcquireHostAdapterLockIH(BusLogic_HostAdapter_T *HostAdapter,
ProcessorFlags_T *ProcessorFlags) ProcessorFlags_T *ProcessorFlags)
{ {
extern spinlock_t io_request_lock;
spin_lock_irqsave(&io_request_lock, *ProcessorFlags); spin_lock_irqsave(&io_request_lock, *ProcessorFlags);
} }
...@@ -1546,7 +1545,6 @@ static inline ...@@ -1546,7 +1545,6 @@ static inline
void BusLogic_ReleaseHostAdapterLockIH(BusLogic_HostAdapter_T *HostAdapter, void BusLogic_ReleaseHostAdapterLockIH(BusLogic_HostAdapter_T *HostAdapter,
ProcessorFlags_T *ProcessorFlags) ProcessorFlags_T *ProcessorFlags)
{ {
extern spinlock_t io_request_lock;
spin_unlock_irqrestore(&io_request_lock, *ProcessorFlags); spin_unlock_irqrestore(&io_request_lock, *ProcessorFlags);
} }
......
...@@ -167,7 +167,7 @@ static int ioctl_internal_command(Scsi_Device *dev, char * cmd) ...@@ -167,7 +167,7 @@ static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
* interface instead, as this is a more flexible approach to performing * interface instead, as this is a more flexible approach to performing
* generic SCSI commands on a device. * generic SCSI commands on a device.
*/ */
static int ioctl_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic) int scsi_ioctl_send_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
{ {
unsigned long flags; unsigned long flags;
char * buf; char * buf;
...@@ -387,7 +387,8 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) ...@@ -387,7 +387,8 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
return ioctl_probe(dev->host, arg); return ioctl_probe(dev->host, arg);
case SCSI_IOCTL_SEND_COMMAND: case SCSI_IOCTL_SEND_COMMAND:
if(!suser()) return -EACCES; if(!suser()) return -EACCES;
return ioctl_command((Scsi_Device *) dev, (Scsi_Ioctl_Command *) arg); return scsi_ioctl_send_command((Scsi_Device *) dev,
(Scsi_Ioctl_Command *) arg);
case SCSI_IOCTL_DOORLOCK: case SCSI_IOCTL_DOORLOCK:
if (!dev->removable || !dev->lockable) return 0; if (!dev->removable || !dev->lockable) return 0;
scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
......
...@@ -97,6 +97,13 @@ static int sg_ioctl(struct inode * inode,struct file * file, ...@@ -97,6 +97,13 @@ static int sg_ioctl(struct inode * inode,struct file * file,
return scsi_generics[dev].timeout; return scsi_generics[dev].timeout;
case SG_EMULATED_HOST: case SG_EMULATED_HOST:
return put_user(scsi_generics[dev].device->host->hostt->emulated, (int *) arg); return put_user(scsi_generics[dev].device->host->hostt->emulated, (int *) arg);
case SCSI_IOCTL_SEND_COMMAND:
/*
Allow SCSI_IOCTL_SEND_COMMAND without checking suser() since the
user already has read/write access to the generic device and so
can execute arbitrary SCSI commands.
*/
return scsi_ioctl_send_command(scsi_generics[dev].device, (void *) arg);
default: default:
return scsi_ioctl(scsi_generics[dev].device, cmd_in, (void *) arg); return scsi_ioctl(scsi_generics[dev].device, cmd_in, (void *) arg);
} }
......
...@@ -517,9 +517,10 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) ...@@ -517,9 +517,10 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
retval = PTR_ERR(interpreter_dentry); retval = PTR_ERR(interpreter_dentry);
if (IS_ERR(interpreter_dentry)) if (IS_ERR(interpreter_dentry))
goto out_free_interp; goto out_free_interp;
retval = permission(interpreter_dentry->d_inode, MAY_EXEC);
retval = read_exec(interpreter_dentry, 0, bprm->buf, if (retval < 0)
128, 1); goto out_free_dentry;
retval = read_exec(interpreter_dentry, 0, bprm->buf, 128, 1);
if (retval < 0) if (retval < 0)
goto out_free_dentry; goto out_free_dentry;
......
...@@ -426,42 +426,16 @@ void shrink_dcache_parent(struct dentry * parent) ...@@ -426,42 +426,16 @@ void shrink_dcache_parent(struct dentry * parent)
} }
/* /*
* This is called from do_try_to_free_page() to indicate * This is called from kswapd when we think we need some
* that we should reduce the dcache and inode cache memory. * more memory, but aren't really sure how much. So we
* carefully try to free a _bit_ of our dcache, but not
* too much.
*/ */
void shrink_dcache_memory() void shrink_dcache_memory(void)
{ {
dentry_stat.want_pages++; int count = select_dcache(32, 8);
} if (count)
prune_dcache(count);
/*
* This carries out the request received by the above routine.
*/
void check_dcache_memory()
{
if (dentry_stat.want_pages) {
unsigned int count, goal = 0;
/*
* Set the page goal. We don't necessarily need to trim
* the dcache just because the system needs memory ...
*/
if (page_cache_size > (num_physpages >> 1))
goal = (dentry_stat.want_pages * page_cache_size)
/ num_physpages;
dentry_stat.want_pages = 0;
if (goal) {
if (goal > 50)
goal = 50;
count = select_dcache(32, goal);
#ifdef DCACHE_DEBUG
printk(KERN_DEBUG "check_dcache_memory: goal=%d, count=%d\n", goal, count);
#endif
if (count) {
prune_dcache(count);
free_inode_memory(count);
}
}
}
} }
#define NAME_ALLOC_LEN(len) ((len+16) & ~15) #define NAME_ALLOC_LEN(len) ((len+16) & ~15)
......
...@@ -454,7 +454,6 @@ struct dentry * __namei(const char *pathname, int follow_link) ...@@ -454,7 +454,6 @@ struct dentry * __namei(const char *pathname, int follow_link)
char *name; char *name;
struct dentry *dentry; struct dentry *dentry;
check_dcache_memory();
name = getname(pathname); name = getname(pathname);
dentry = (struct dentry *) name; dentry = (struct dentry *) name;
if (!IS_ERR(name)) { if (!IS_ERR(name)) {
...@@ -528,7 +527,6 @@ struct dentry * open_namei(const char * pathname, int flag, int mode) ...@@ -528,7 +527,6 @@ struct dentry * open_namei(const char * pathname, int flag, int mode)
struct inode *inode; struct inode *inode;
struct dentry *dentry; struct dentry *dentry;
check_dcache_memory();
mode &= S_IALLUGO & ~current->fs->umask; mode &= S_IALLUGO & ~current->fs->umask;
mode |= S_IFREG; mode |= S_IFREG;
......
...@@ -72,7 +72,6 @@ enum ...@@ -72,7 +72,6 @@ enum
KERN_STATINODE, KERN_STATINODE,
KERN_DENTRY, /* dentry statistics */ KERN_DENTRY, /* dentry statistics */
KERN_MODPROBE, KERN_MODPROBE,
KERN_KMOD_UNLOAD_DELAY
}; };
......
...@@ -15,9 +15,6 @@ ...@@ -15,9 +15,6 @@
#ifdef __KERNEL__ #ifdef __KERNEL__
extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
extern int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
/* /*
* Structures used for scsi_ioctl et al. * Structures used for scsi_ioctl et al.
*/ */
...@@ -33,6 +30,11 @@ typedef struct scsi_idlun { ...@@ -33,6 +30,11 @@ typedef struct scsi_idlun {
__u32 host_unique_id; __u32 host_unique_id;
} Scsi_Idlun; } Scsi_Idlun;
extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
extern int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
extern int scsi_ioctl_send_command(Scsi_Device *dev,
Scsi_Ioctl_Command *arg);
#endif #endif
#endif #endif
......
...@@ -1162,13 +1162,6 @@ static int init(void * unused) ...@@ -1162,13 +1162,6 @@ static int init(void * unused)
smp_begin(); smp_begin();
#endif #endif
#ifdef CONFIG_KMOD
{
extern int kmod_init(void);
kmod_init();
}
#endif
#ifdef CONFIG_UMSDOS_FS #ifdef CONFIG_UMSDOS_FS
{ {
/* /*
......
/* /*
kmod, the new module loader (replaces kerneld) kmod, the new module loader (replaces kerneld)
Kirk Petersen Kirk Petersen
Reorganized not to be a daemon by Adam Richter, with guidance
from Greg Zornetzer.
Modified to avoid chroot and file sharing problems.
Mikael Pettersson
*/ */
#define __KERNEL_SYSCALLS__ #define __KERNEL_SYSCALLS__
...@@ -8,147 +14,88 @@ ...@@ -8,147 +14,88 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/unistd.h> #include <linux/unistd.h>
#include <asm/smp_lock.h>
#include <asm/uaccess.h>
/* /*
kmod_unload_delay and modprobe_path are set via /proc/sys. modprobe_path is set via /proc/sys.
*/ */
int kmod_unload_delay = 60;
char modprobe_path[256] = "/sbin/modprobe"; char modprobe_path[256] = "/sbin/modprobe";
static char module_name[64] = "";
static char * argv[] = { modprobe_path, "-s", "-k", module_name, NULL };
static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL }; static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL };
/* /*
kmod_queue synchronizes the kmod thread and the rest of the system exec_modprobe is spawned from a kernel-mode user process,
kmod_unload_timer is what we use to unload modules then changes its state to behave _as_if_ it was spawned
after kmod_unload_delay seconds from the kernel's init process
(ppid and {e,}gid are not adjusted, but that shouldn't
be a problem since we trust modprobe)
*/ */
static struct wait_queue * kmod_queue = NULL; #define task_init task[smp_num_cpus]
static struct timer_list kmod_unload_timer;
/*
It is not easy to implement a full fork in kernel-space on some
systems (Alpha), and it is not necessary for us here. This is
a new thread that does the exec.
*/
static int kmod_exec_modprobe(void * data)
{
sigemptyset(&current->blocked);
execve(modprobe_path, argv, envp);
printk(KERN_ERR "kmod: failed to load module %s\n", module_name);
return 0;
}
/* static inline void
kmod_thread is the thread that does most of the work. kmod_unload and use_init_file_context(void) {
request_module tell it to wake up and do work. lock_kernel();
*/
static int kmod_thread(void * data)
{
int pid;
/* /* don't use the user's root, use init's root instead */
Initialize basic thread information exit_fs(current); /* current->fs->count--; */
*/ current->fs = task_init->fs;
current->session = 1; current->fs->count++;
current->pgrp = 1;
sprintf(current->comm, "kmod");
sigfillset(&current->blocked);
/*
This is the main kmod_thread loop. It first sleeps, then
handles requests from request_module or kmod_unload.
*/
while (1) { /* don't use the user's files, use init's files instead */
interruptible_sleep_on(&kmod_queue); exit_files(current); /* current->files->count--; */
current->files = task_init->files;
/* current->files->count++;
If request_module woke us up, we should try to
load module_name. If not, kmod_unload woke us up,
do call delete_module.
(if somehow both want us to do something, ignore the
delete_module request)
*/
if (module_name[0] == '\0') {
delete_module(NULL);
} else {
pid = kernel_thread(kmod_exec_modprobe, NULL, SIGCHLD);
if (pid > 0) {
waitpid(pid, NULL, 0);
module_name[0] = '\0';
wake_up(&kmod_queue);
} else {
printk(KERN_ERR "kmod: fork failed, errno %d\n", -pid);
}
}
}
return 0; /* Never reached. */ unlock_kernel();
} }
/* static int exec_modprobe(void * module_name)
kmod_unload is the function that the kernel calls when
the kmod_unload_timer expires
*/
void kmod_unload(unsigned long x)
{ {
/* char *argv[] = { modprobe_path, "-s", "-k", (char*)module_name, NULL};
wake up the kmod thread, which does the work
(we can't call delete_module, as it locks the kernel and
we are in the bottom half of the kernel (right?))
once it is awake, reset the timer
*/
wake_up(&kmod_queue);
kmod_unload_timer.expires = jiffies + (kmod_unload_delay * HZ);
add_timer(&kmod_unload_timer);
}
int kmod_init(void) use_init_file_context();
{
printk("Starting kmod\n");
/*
* CLONE_FS means that our "cwd" will follow that of init.
* CLONE_FILES just saves some space (we don't need any
* new file descriptors). Ditto for CLONE_SIGHAND.
*/
kernel_thread(kmod_thread, NULL, CLONE_FILES | CLONE_FS | CLONE_SIGHAND);
kmod_unload_timer.next = NULL;
kmod_unload_timer.prev = NULL;
kmod_unload_timer.expires = jiffies + (5 * 60 * HZ);
kmod_unload_timer.data = 0L;
kmod_unload_timer.function = kmod_unload;
add_timer(&kmod_unload_timer);
/* Prevent parent user process from sending signals to child.
Otherwise, if the modprobe program does not exist, it might
be possible to get a user defined signal handler to execute
as the super user right after the execve fails if you time
the signal just right.
*/
spin_lock_irq(&current->sigmask_lock);
flush_signals(current);
flush_signal_handlers(current);
spin_unlock_irq(&current->sigmask_lock);
set_fs(KERNEL_DS); /* Allow execve args to be in kernel space. */
current->uid = current->euid = 0;
if (execve(modprobe_path, argv, envp) < 0) {
printk(KERN_ERR
"kmod: failed to exec %s -s -k %s, errno = %d\n",
modprobe_path, (char*) module_name, errno);
return -errno;
}
return 0; return 0;
} }
/* /*
request_module, the function that everyone calls when they need a request_module: the function that everyone calls when they need
module to be loaded a module.
*/ */
int request_module(const char * name) int request_module(const char * module_name)
{ {
/* first, copy the name of the module into module_name */ int pid;
/* then wake_up() the kmod daemon */ int waitpid_result;
/* wait for the kmod daemon to finish (it will wake us up) */
pid = kernel_thread(exec_modprobe, (void*) module_name,
/* CLONE_FS | CLONE_FILES | SIGCHLD);
kmod_thread is sleeping, so start by copying the name of if (pid < 0) {
the module into module_name. Once that is done, wake up printk(KERN_ERR "kmod: fork failed, errno %d\n", -pid);
kmod_thread. return pid;
*/ }
strncpy(module_name, name, sizeof(module_name)); waitpid_result = waitpid(pid, NULL, 0);
module_name[sizeof(module_name)-1] = '\0'; if (waitpid_result != pid) {
wake_up(&kmod_queue); printk (KERN_ERR "kmod: waitpid(%d,NULL,0) failed, returning %d.\n",
pid, waitpid_result);
/* }
Now that we have told kmod_thread what to do, we want to
go to sleep and let it do its work. It will wake us up,
at which point we will be done (the module will be loaded).
*/
interruptible_sleep_on(&kmod_queue);
return 0; return 0;
} }
...@@ -43,7 +43,6 @@ extern char binfmt_java_interpreter[], binfmt_java_appletviewer[]; ...@@ -43,7 +43,6 @@ extern char binfmt_java_interpreter[], binfmt_java_appletviewer[];
extern int sysctl_overcommit_memory; extern int sysctl_overcommit_memory;
#ifdef CONFIG_KMOD #ifdef CONFIG_KMOD
extern char modprobe_path[]; extern char modprobe_path[];
extern int kmod_unload_delay;
#endif #endif
#ifdef CONFIG_CHR_DEV_SG #ifdef CONFIG_CHR_DEV_SG
extern int sg_big_buff; extern int sg_big_buff;
...@@ -180,8 +179,6 @@ static ctl_table kern_table[] = { ...@@ -180,8 +179,6 @@ static ctl_table kern_table[] = {
#ifdef CONFIG_KMOD #ifdef CONFIG_KMOD
{KERN_MODPROBE, "modprobe", &modprobe_path, 256, {KERN_MODPROBE, "modprobe", &modprobe_path, 256,
0644, NULL, &proc_dostring, &sysctl_string }, 0644, NULL, &proc_dostring, &sysctl_string },
{KERN_KMOD_UNLOAD_DELAY, "kmod_unload_delay", &kmod_unload_delay,
sizeof(int), 0644, NULL, &proc_dointvec},
#endif #endif
#ifdef CONFIG_CHR_DEV_SG #ifdef CONFIG_CHR_DEV_SG
{KERN_NRFILE, "sg-big-buff", &sg_big_buff, sizeof (int), {KERN_NRFILE, "sg-big-buff", &sg_big_buff, sizeof (int),
......
...@@ -286,16 +286,17 @@ unsigned long __get_free_pages(int gfp_mask, unsigned long order) ...@@ -286,16 +286,17 @@ unsigned long __get_free_pages(int gfp_mask, unsigned long order)
} }
} }
repeat: for (;;) {
spin_lock_irqsave(&page_alloc_lock, flags); spin_lock_irqsave(&page_alloc_lock, flags);
RMQUEUE(order, maxorder, (gfp_mask & GFP_DMA)); RMQUEUE(order, maxorder, (gfp_mask & GFP_DMA));
spin_unlock_irqrestore(&page_alloc_lock, flags); spin_unlock_irqrestore(&page_alloc_lock, flags);
if (gfp_mask & __GFP_WAIT) { if (!(gfp_mask & __GFP_WAIT))
int freed = try_to_free_pages(gfp_mask,SWAP_CLUSTER_MAX); break;
shrink_dcache();
if (!try_to_free_pages(gfp_mask, SWAP_CLUSTER_MAX))
break;
gfp_mask &= ~__GFP_WAIT; /* go through this only once */ gfp_mask &= ~__GFP_WAIT; /* go through this only once */
maxorder = NR_MEM_LISTS; /* Allow anything this time */ maxorder = NR_MEM_LISTS; /* Allow anything this time */
if (freed)
goto repeat;
} }
nopage: nopage:
return 0; return 0;
......
...@@ -442,7 +442,7 @@ static inline int do_try_to_free_page(int gfp_mask) ...@@ -442,7 +442,7 @@ static inline int do_try_to_free_page(int gfp_mask)
int stop; int stop;
/* Let the dcache know we're looking for memory ... */ /* Let the dcache know we're looking for memory ... */
shrink_dcache_memory(); shrink_dcache();
/* Always trim SLAB caches when memory gets low. */ /* Always trim SLAB caches when memory gets low. */
kmem_cache_reap(gfp_mask); kmem_cache_reap(gfp_mask);
...@@ -547,6 +547,9 @@ int kswapd(void *unused) ...@@ -547,6 +547,9 @@ int kswapd(void *unused)
run_task_queue(&tq_disk); run_task_queue(&tq_disk);
schedule(); schedule();
swapstats.wakeups++; swapstats.wakeups++;
/* This will gently shrink the dcache.. */
shrink_dcache_memory();
/* /*
* Do the background pageout: be * Do the background pageout: be
......
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