aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@klaava.Helsinki.FI>1992-10-27 19:49:52 +0000
committerNicolas Pitre <nico@cam.org>2007-08-19 14:19:09 -0400
commit73795752dade564a88db44bdcfd7c5a946322de1 (patch)
tree7503515d32b5104c3c20fb6710ff69e167980e07
parent4c212a02429139af48301686ce7cd24ce1a0b47f (diff)
downloadarchive-73795752dade564a88db44bdcfd7c5a946322de1.tar.gz
ANNOUNCE: linux-0.98.3v0.98-pl3
Ok, I already sent out an announcement last night, but due to the time (6AM over here) I wasn't really in a mood to write a real annoucement. Here it is. linux-0.98.3 is available by anonymous ftp at least on nic.funet.fi: pub/OS/Linux/testing/Linus, both as context diffs against 0.98.2 and the pre-version of 0.98.3 and as complete source. The complete source package was done by directly applying the diffs - this means that the Makefile dependancies are probably not 100% up-to-date as I remove those from the diffs. It shouldn't be any problem, and you can always do a "make dep ; make clean" before actually compiling the kernel. 0.98 pl3 fixes several bugs, and should remove all known NULL-pointer problems that made 0.98.2 unusable for most people. In addition to the NULL pointer fixes, the following things have changed: - removed most of the cli-sti pairs in the filesystem code by rewriting the locking routines to use a different algorithm, possible due to the rewritten wait-queue code that I did back in 0.96c or so. Interrupt latency should be better on slow machines, but I don't know if it's noticeable. - Minor 387-emulation fixes by Bill Metzenthen - only noticeable under special conditions. - Corrected various error-returns in the fs (thanks to Bruce Evans for running some error diagnostics). Error messages when opening (and renaming etc) files that had a non-directory in the path were wrong, and should be ok now (ie giving ENOTDIR instead of EACCESS or ENOENT). Some other problems reported by Bruce fixed. - Changed the interface for some fs-related functions due to cleaning up super-block handling. Most noticeably, iget() and related functions no longer specify the inode with a device and inode number, but instead with a super-block pointer and inode number. This is more logical, and should make unnamed devices (ie internal filesystems like nfs and /proc) cleaner. Also note that the calling sequence for sb->s_op->put_inode() also has changed since 0.98. This is of interest only if you are writing filesystem drivers.. - ASK_SVGA was broken in 0.98.2 - it should be ok now. Also, various minor fixes as usual. No new features, but I hope 0.98.3 will be a lot less bug-prone due to the changes since 0.98.1. Some minor tcp/ip corrections (but most of them were in the pre-release), and I removed a race-condition in the tty-handling code. Note that people who use math without a co-processor should certainly upgrade to 0.98.3: the new emulator is much better than my original one both in speed and accuracy/exception handling. x11perf is very much bearable now even without a 387, and things like ray-tracing etc shouldn't be a problem any more. It's slower than hardware fp, of course, but at least it works. The new emulator also means there is no reason for a separate soft-float library, so I'd assume that will be gone in the next gcc release for linux. As usual, a new kernel version probably means you'll have to recompile 'ps' and friends. But at least the same 'ps' sources that worked for 0.97.6 should still work. Linus ----- From: torvalds@klaava.Helsinki.FI (Linus Torvalds) Subject: 0.98.3 finally available Date: 27 Oct 1992 04:01:01 GMT 0.98.3 is available at nic.funet.fi: pub/OS/Linux/testing/Linus as diffs against 0.98.2 (linux-0.98.patch3.Z) and against the pre-release that was announced on the mailing-lists (pre-final.diff.Z). I haven't uploaded the complete sources yet, so diffs are all there is: I'll upload the full sources once I've gotten some more sleep. 0.98.3 corrects a lot of NULL-pointer bugs, as well as some other problems (notably serial lines). Hope this release will be stable, Linus ----- From: torvalds@klaava.Helsinki.FI (Linus Torvalds) Subject: 0.98.3 is late ... Date: 26 Oct 1992 05:07:26 GMT ... as you probably all have noticed. I've been up all night writing this report for the "CS Course from Hell" (*), and haven't had time to play with linux. I'll get it done tonight if I can keep awake that long. In case anybody still wonders, 0.98.3 mainly fixes the NULL pointer and most of the serial line problems. I also started to remove some of the more unnecessary cli-sti pairs (where races could be avoided by doing it some other way), so it's possible interrupt latency is better, but I doubt it's noticeable. Linus (*) Well, they call it "ATK-suunnittelun laboratorioty|", but they aren't fooling anybody. ----- From: torvalds@klaava.Helsinki.FI (Linus Torvalds) Subject: Re: ANNOUNCE: 0.98.pl2 is out Date: 18 Oct 1992 22:42:02 GMT In article <1992Oct18.144546.28249@klaava.Helsinki.FI> I wrote: > [ deleted ] > > - various minor mm fixes by me: trapping kernel NULL dereferences, ... Oh, boy. Talk about a feature that proved itself. I have never gotten so many bug-reports so fast: it seems there were quite a few NULL-pointer problems in the code I hadn't been able to test. Thus 0.98.2 isn't actually very useable unless you have a system very close to my setup - I don't recommend the faint-of-hearted to try it out. I guess I should be happy the new feature found problems in the kernel sources, but I could well have lived with a couple less problems. Main problem areas seem to be: - the vhangup() system call - used by newer login-binaries, and resulting in login getting killed. - some scsi driver problems (but they should be fixed by the patch eric already sent out) - tcp/ip problems - at least three different places where NULL gets dereferenced (and one is particularly ugly: it does test for NULL, but does so *after* dereferencing it...) The vhangup() problem was easy to correct (and excusable: it broke at least partly due to the new dynamic tty-routines). I'll make some preliminary testing-patches available that fix that problem, and includes the scsi fixes. But the tcp/ip code is a bit worse: I fixed two of the known problems, but I'd rather use patches from the persons who wrote the code originally, as there are some other problems in there.. And I can't be sure I find them all anyway, as I'll never see the problems first-hand. Just wanted to warn everybody about this aspect of pl2 - the NULL-pointer finding code is working a bit too well for my taste. I had hoped there wouldn't be quite this many NULL pointer problems, but at least they'll be found this way. Linus
-rw-r--r--Makefile8
-rw-r--r--boot/head.S12
-rw-r--r--boot/setup.S70
-rw-r--r--fs/buffer.c75
-rw-r--r--fs/ext/file.c9
-rw-r--r--fs/ext/freelists.c76
-rw-r--r--fs/ext/inode.c50
-rw-r--r--fs/ext/namei.c27
-rw-r--r--fs/ext/truncate.c10
-rw-r--r--fs/inode.c101
-rw-r--r--fs/minix/bitmap.c28
-rw-r--r--fs/minix/file.c9
-rw-r--r--fs/minix/inode.c47
-rw-r--r--fs/minix/namei.c23
-rw-r--r--fs/minix/truncate.c8
-rw-r--r--fs/msdos/inode.c35
-rw-r--r--fs/msdos/misc.c2
-rw-r--r--fs/msdos/namei.c28
-rw-r--r--fs/namei.c16
-rw-r--r--fs/open.c64
-rw-r--r--fs/proc/base.c2
-rw-r--r--fs/proc/fd.c9
-rw-r--r--fs/proc/inode.c14
-rw-r--r--fs/proc/root.c2
-rw-r--r--fs/super.c126
-rw-r--r--include/asm/dma.h192
-rw-r--r--include/asm/segment.h4
-rw-r--r--include/linux/config.h5
-rw-r--r--include/linux/ext_fs.h6
-rw-r--r--include/linux/fs.h48
-rw-r--r--include/linux/kernel.h1
-rw-r--r--include/linux/locks.h56
-rw-r--r--include/linux/lp.h73
-rw-r--r--include/linux/minix_fs.h6
-rw-r--r--include/linux/sched.h42
-rw-r--r--include/linux/string.h22
-rw-r--r--init/main.c102
-rw-r--r--kernel/FPU-emu/Makefile24
-rw-r--r--kernel/FPU-emu/errors.c21
-rw-r--r--kernel/FPU-emu/reg_ld_str.c8
-rw-r--r--kernel/FPU-emu/reg_mul.c3
-rw-r--r--kernel/FPU-emu/reg_u_add.S5
-rw-r--r--kernel/FPU-emu/reg_u_sub.S13
-rw-r--r--kernel/FPU-emu/version.h2
-rw-r--r--kernel/Makefile2
-rw-r--r--kernel/blk_drv/blk.h10
-rw-r--r--kernel/blk_drv/floppy.c216
-rw-r--r--kernel/blk_drv/ll_rw_blk.c58
-rw-r--r--kernel/blk_drv/ramdisk.c1
-rw-r--r--kernel/blk_drv/scsi/7000fasst.h2
-rw-r--r--kernel/blk_drv/scsi/aha1542.c5
-rw-r--r--kernel/blk_drv/scsi/aha1542.h2
-rw-r--r--kernel/blk_drv/scsi/fdomain.h2
-rw-r--r--kernel/blk_drv/scsi/hosts.h5
-rw-r--r--kernel/blk_drv/scsi/scsi.c9
-rw-r--r--kernel/blk_drv/scsi/scsi.h2
-rw-r--r--kernel/blk_drv/scsi/scsi_ioctl.c20
-rw-r--r--kernel/blk_drv/scsi/sd.c87
-rw-r--r--kernel/blk_drv/scsi/sd.h2
-rw-r--r--kernel/blk_drv/scsi/seagate.h2
-rw-r--r--kernel/blk_drv/scsi/sr.c15
-rw-r--r--kernel/blk_drv/scsi/sr.h2
-rw-r--r--kernel/blk_drv/scsi/st.c4
-rw-r--r--kernel/blk_drv/scsi/st.h2
-rw-r--r--kernel/blk_drv/scsi/ultrastor.h2
-rw-r--r--kernel/chr_drv/keyboard.c15
-rw-r--r--kernel/chr_drv/lp.c118
-rw-r--r--kernel/chr_drv/mem.c64
-rw-r--r--kernel/chr_drv/serial.c35
-rw-r--r--kernel/chr_drv/tty_io.c84
-rw-r--r--kernel/chr_drv/tty_ioctl.c1
-rw-r--r--kernel/dma.c87
-rw-r--r--kernel/exit.c24
-rw-r--r--kernel/sched.c32
-rw-r--r--kernel/signal.c45
-rw-r--r--kernel/sys.c4
-rw-r--r--kernel/vsprintf.c26
-rw-r--r--lib/malloc.c12
-rw-r--r--mm/memory.c4
-rw-r--r--net/tcp/arp.c24
-rw-r--r--net/tcp/dev.c1
-rw-r--r--net/tcp/eth.c1
-rw-r--r--net/tcp/loopback.c2
-rw-r--r--net/tcp/sock.c56
-rw-r--r--net/tcp/tcp.c44
-rw-r--r--net/tcp/udp.c14
-rw-r--r--net/tcp/we.c2
87 files changed, 1679 insertions, 950 deletions
diff --git a/Makefile b/Makefile
index c271517..723dd23 100644
--- a/Makefile
+++ b/Makefile
@@ -45,7 +45,7 @@ KEYBOARD = -DKBD_FINNISH -DKBDFLAGS=0
# KEYBOARD = -DKBD_SG_LATIN1 -DKBDFLAGS=0x9F
# KEYBOARD = -DKBD_SF -DKBDFLAGS=0
# KEYBOARD = -DKBD_SF_LATIN1 -DKBDFLAGS=0x9F
-# KEYBOARD = -DKDB_NO
+# KEYBOARD = -DKBD_NO -DKBDFLAGS=0
#
# comment this line if you don't want the emulation-code
@@ -127,7 +127,7 @@ linuxsubdirs: dummy
Version:
@./makever.sh
- @echo \#define UTS_RELEASE \"0.98.pl2-`cat .version`\" > tools/version.h
+ @echo \#define UTS_RELEASE \"0.98.pl3-`cat .version`\" > tools/version.h
@echo \#define UTS_VERSION \"`date +%D`\" >> tools/version.h
@echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> tools/version.h
@echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h
@@ -170,10 +170,10 @@ boot/setup: boot/setup.s
$(AS86) -o boot/setup.o boot/setup.s
$(LD86) -s -o boot/setup boot/setup.o
-boot/setup.s: boot/setup.S include/linux/config.h
+boot/setup.s: boot/setup.S include/linux/config.h Makefile
$(CPP) -traditional $(SVGA_MODE) boot/setup.S -o boot/setup.s
-boot/bootsect.s: boot/bootsect.S include/linux/config.h
+boot/bootsect.s: boot/bootsect.S include/linux/config.h
$(CPP) -traditional boot/bootsect.S -o boot/bootsect.s
boot/bootsect: boot/bootsect.s
diff --git a/boot/head.S b/boot/head.S
index 47355cb..aef714a 100644
--- a/boot/head.S
+++ b/boot/head.S
@@ -12,9 +12,11 @@
* the page directory.
*/
.text
-.globl _idt,_gdt,_swapper_pg_dir,_tmp_floppy_area,_floppy_track_buffer
+.globl _idt,_gdt,
+.globl _swapper_pg_dir,_pg0
.globl _empty_bad_page
.globl _empty_bad_page_table
+.globl _tmp_floppy_area,_floppy_track_buffer
/*
* swapper_pg_dir is the main page directory, address 0x00001000
@@ -125,7 +127,7 @@ _swapper_pg_dir:
* tables are set up later depending on memory size.
*/
.org 0x2000
-pg0:
+_pg0:
.org 0x3000
_empty_bad_page:
@@ -232,10 +234,10 @@ setup_paging:
movl $_swapper_pg_dir,%edi /* swapper_pg_dir is at 0x1000 */
cld;rep;stosl
/* Identity-map the kernel in low 4MB memory for ease of transition */
- movl $pg0+7,_swapper_pg_dir /* set present bit/user r/w */
+ movl $_pg0+7,_swapper_pg_dir /* set present bit/user r/w */
/* But the real place is at 0xC0000000 */
- movl $pg0+7,_swapper_pg_dir+3072 /* set present bit/user r/w */
- movl $pg0+4092,%edi
+ movl $_pg0+7,_swapper_pg_dir+3072 /* set present bit/user r/w */
+ movl $_pg0+4092,%edi
movl $0x03ff007,%eax /* 4Mb - 4096 + 7 (r/w user,p) */
std
1: stosl /* fill the page backwards - more efficient :-) */
diff --git a/boot/setup.S b/boot/setup.S
index 320c0cf..5316dcf 100644
--- a/boot/setup.S
+++ b/boot/setup.S
@@ -1,5 +1,5 @@
!
-! setup.s Copyright (C) 1991, 1992 Linus Torvalds
+! setup.S Copyright (C) 1991, 1992 Linus Torvalds
!
! setup.s is responsible for getting the system data from the BIOS,
! and putting them into the appropriate places in system memory.
@@ -17,7 +17,10 @@
! NOTE! These had better be the same as in bootsect.s!
#include <linux/config.h>
-#define NORMAL_VGA 0xffff
+
+#ifndef SVGA_MODE
+#define SVGA_MODE ASK_VGA
+#endif
INITSEG = DEF_INITSEG ! we move boot here - out of the way
SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536).
@@ -265,8 +268,14 @@ chsvga: cld
pop ds
mov ax,#0xc000
mov es,ax
+ mov ax,modesave
+ cmp ax,#NORMAL_VGA
+ je defvga
+ cmp ax,#EXTENDED_VGA
+ je extvga
+ cmp ax,#ASK_VGA
+ jne svga
lea si,msg1
-#ifndef SVGA_MODE
call prtstr
flush: in al,#0x60 ! Flush the keyboard buffer
cmp al,#0x82
@@ -277,12 +286,27 @@ nokey: call getkey
je svga ! yes - svga selection
cmp al,#0xb9 ! space ?
jne nokey ! no - repeat
-#endif
-#if !defined(SVGA_MODE) || SVGA_MODE == NORMAL_VGA
- mov ax,#0x5019
+defvga: mov ax,#0x5019
pop ds
ret
-#endif
+/* extended vga mode: 80x50 */
+extvga:
+ mov ax,#0x1112
+ mov bl,#0
+ int 0x10 ! use 8x8 font set (50 lines on VGA)
+ mov ax,#0x1200
+ mov bl,#0x20
+ int 0x10 ! use alternate print screen
+ mov ax,#0x1201
+ mov bl,#0x34
+ int 0x10 ! turn off cursor emulation
+ mov ah,#0x01
+ mov cx,#0x0607
+ int 0x10 ! turn on cursor (scan lines 6 to 7)
+ pop ds
+ mov ax,#0x5032 ! return 80x50
+ ret
+/* svga modes */
svga: cld
lea si,idati ! Check ATI 'clues'
mov di,#0x31
@@ -532,9 +556,11 @@ tbl: pop bx
call prtstr
pop si
add cl,#0x80
-#if defined(SVGA_MODE) && SVGA_MODE != NORMAL_VGA
- mov al,#SVGA_MODE ! Preset SVGA mode
-#else
+ mov ax,modesave
+ cmp ax,#ASK_VGA
+ je nonum
+ cmp ax,#NORMAL_VGA
+ jne gotmode
nonum: call getkey
cmp al,#0x82
jb nonum
@@ -546,8 +572,7 @@ nonum: call getkey
zero: sub al,#0x0a
nozero: sub al,#0x80
dec al
-#endif
- xor ah,ah
+gotmode: xor ah,ah
add di,ax
inc di
push ax
@@ -560,25 +585,7 @@ nozero: sub al,#0x80
pop ds
ret
novid7:
- mov ax,#0x1112
- mov bl,#0
- int 0x10 ! use 8x8 font set (50 lines on VGA)
-
- mov ax,#0x1200
- mov bl,#0x20
- int 0x10 ! use alternate print screen
-
- mov ax,#0x1201
- mov bl,#0x34
- int 0x10 ! turn off cursor emulation
-
- mov ah,#0x01
- mov cx,#0x0607
- int 0x10 ! turn on cursor (scan lines 6 to 7)
-
- pop ds
- mov ax,#0x5032 ! return 80x50
- ret
+ br extvga
! Routine that 'tabs' to next col.
@@ -712,6 +719,7 @@ dsctrident: .word 0x501e, 0x502b, 0x503c, 0x8419, 0x841e, 0x842b, 0x843c
dsctseng: .word 0x503c, 0x6428, 0x8419, 0x841c, 0x842c
dscvideo7: .word 0x502b, 0x503c, 0x643c, 0x8419, 0x842c, 0x841c
dscoakvga: .word 0x2819, 0x5019, 0x843c, 0x8419, 0x842C
+modesave: .word SVGA_MODE
.text
endtext:
diff --git a/fs/buffer.c b/fs/buffer.c
index 7203b65..d02e39f 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -7,9 +7,7 @@
/*
* 'buffer.c' implements the buffer-cache functions. Race-conditions have
* been avoided by NEVER letting a interrupt change a buffer (except for the
- * data, of course), but instead letting the caller do it. NOTE! As interrupts
- * can wake up a caller, some cli-sti sequences are needed to check for
- * sleep-on-calls. These should be extremely quick, though (I hope).
+ * data, of course), but instead letting the caller do it.
*/
/*
@@ -24,6 +22,7 @@
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/string.h>
+#include <linux/locks.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -46,15 +45,29 @@ static struct wait_queue * buffer_wait = NULL;
int nr_buffers = 0;
int nr_buffer_heads = 0;
-static inline void wait_on_buffer(struct buffer_head * bh)
+/*
+ * Rewrote the wait-routines to use the "new" wait-queue functionality,
+ * and getting rid of the cli-sti pairs. The wait-queue routines still
+ * need cli-sti, but now it's just a couple of 386 instructions or so.
+ *
+ * Note that the real wait_on_buffer() is an inline function that checks
+ * if 'b_wait' is set before calling this, so that the queues aren't set
+ * up unnecessarily.
+ */
+void __wait_on_buffer(struct buffer_head * bh)
{
- cli();
- while (bh->b_lock)
- sleep_on(&bh->b_wait);
- sti();
+ add_wait_queue(&bh->b_wait,&current->wait);
+repeat:
+ current->state = TASK_UNINTERRUPTIBLE;
+ if (bh->b_lock) {
+ schedule();
+ goto repeat;
+ }
+ remove_wait_queue(&bh->b_wait,&current->wait);
+ current->state = TASK_RUNNING;
}
-static void sync_buffers(int dev)
+static void sync_buffers(dev_t dev)
{
int i;
struct buffer_head * bh;
@@ -69,35 +82,21 @@ static void sync_buffers(int dev)
}
}
-int sys_sync(void)
+void sync_dev(dev_t dev)
{
- int i;
-
- for (i=0 ; i<NR_SUPER ; i++)
- if (super_block[i].s_dev
- && super_block[i].s_op
- && super_block[i].s_op->write_super
- && super_block[i].s_dirt)
- super_block[i].s_op->write_super(&super_block[i]);
- sync_inodes(); /* write out inodes into buffers */
- sync_buffers(0);
- return 0;
+ sync_buffers(dev);
+ sync_supers(dev);
+ sync_inodes(dev);
+ sync_buffers(dev);
}
-int sync_dev(int dev)
+int sys_sync(void)
{
- struct super_block * sb;
-
- if (sb = get_super (dev))
- if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
- sb->s_op->write_super (sb);
- sync_buffers(dev);
- sync_inodes();
- sync_buffers(dev);
+ sync_dev(0);
return 0;
}
-void invalidate_buffers(int dev)
+void invalidate_buffers(dev_t dev)
{
int i;
struct buffer_head * bh;
@@ -126,7 +125,7 @@ void invalidate_buffers(int dev)
* and that mount/open needn't know that floppies/whatever are
* special.
*/
-void check_disk_change(int dev)
+void check_disk_change(dev_t dev)
{
int i;
struct buffer_head * bh;
@@ -251,7 +250,7 @@ static inline void insert_into_queues(struct buffer_head * bh)
bh->b_next->b_prev = bh;
}
-static struct buffer_head * find_buffer(int dev, int block, int size)
+static struct buffer_head * find_buffer(dev_t dev, int block, int size)
{
struct buffer_head * tmp;
@@ -273,7 +272,7 @@ static struct buffer_head * find_buffer(int dev, int block, int size)
* will force it bad). This shouldn't really happen currently, but
* the code is ready.
*/
-struct buffer_head * get_hash_table(int dev, int block, int size)
+struct buffer_head * get_hash_table(dev_t dev, int block, int size)
{
struct buffer_head * bh;
@@ -301,7 +300,7 @@ struct buffer_head * get_hash_table(int dev, int block, int size)
* when the filesystem starts to get full of dirty blocks (I hope).
*/
#define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock)
-struct buffer_head * getblk(int dev, int block, int size)
+struct buffer_head * getblk(dev_t dev, int block, int size)
{
struct buffer_head * bh, * tmp;
int buffers;
@@ -377,7 +376,7 @@ void brelse(struct buffer_head * buf)
* bread() reads a specified block and returns the buffer that contains
* it. It returns NULL if the block was unreadable.
*/
-struct buffer_head * bread(int dev, int block, int size)
+struct buffer_head * bread(dev_t dev, int block, int size)
{
struct buffer_head * bh;
@@ -408,7 +407,7 @@ __asm__("cld\n\t" \
* all at the same time, not waiting for one to be read, and then another
* etc.
*/
-void bread_page(unsigned long address,int dev,int b[4])
+void bread_page(unsigned long address, dev_t dev, int b[4])
{
struct buffer_head * bh[4];
int i;
@@ -434,7 +433,7 @@ void bread_page(unsigned long address,int dev,int b[4])
* blocks for reading as well. End the argument list with a negative
* number.
*/
-struct buffer_head * breada(int dev,int first, ...)
+struct buffer_head * breada(dev_t dev,int first, ...)
{
va_list args;
struct buffer_head * bh, *tmp;
diff --git a/fs/ext/file.c b/fs/ext/file.c
index 39d3348..fb7bb2b 100644
--- a/fs/ext/file.c
+++ b/fs/ext/file.c
@@ -21,6 +21,7 @@
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
+#include <linux/locks.h>
#define NBUF 16
@@ -30,14 +31,6 @@
#include <linux/fs.h>
#include <linux/ext_fs.h>
-static inline void wait_on_buffer(struct buffer_head * bh)
-{
- cli();
- while (bh->b_lock)
- sleep_on(&bh->b_wait);
- sti();
-}
-
static int ext_file_read(struct inode *, struct file *, char *, int);
static int ext_file_write(struct inode *, struct file *, char *, int);
diff --git a/fs/ext/freelists.c b/fs/ext/freelists.c
index 8486528..81b54f1 100644
--- a/fs/ext/freelists.c
+++ b/fs/ext/freelists.c
@@ -34,6 +34,7 @@
#include <linux/ext_fs.h>
#include <linux/kernel.h>
#include <linux/string.h>
+#include <linux/locks.h>
#define clear_block(addr) \
__asm__("cld\n\t" \
@@ -41,13 +42,12 @@ __asm__("cld\n\t" \
"stosl" \
::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di")
-void ext_free_block(int dev, int block)
+void ext_free_block(struct super_block * sb, int block)
{
- struct super_block * sb;
struct buffer_head * bh;
struct ext_free_block * efb;
- if (!(sb = get_super(dev)))
+ if (!sb)
panic("trying to free block on nonexistent device");
lock_super (sb);
if (block < sb->u.ext_sb.s_firstdatazone ||
@@ -55,7 +55,7 @@ void ext_free_block(int dev, int block)
printk("trying to free block not in datazone\n");
return;
}
- bh = get_hash_table(dev, block, sb->s_blocksize);
+ bh = get_hash_table(sb->s_dev, block, sb->s_blocksize);
if (bh)
bh->b_dirt=0;
brelse(bh);
@@ -67,7 +67,7 @@ printk("ext_free_block: block full, skipping to %d\n", block);
#endif
if (sb->u.ext_sb.s_firstfreeblock)
brelse (sb->u.ext_sb.s_firstfreeblock);
- if (!(sb->u.ext_sb.s_firstfreeblock = bread (dev,
+ if (!(sb->u.ext_sb.s_firstfreeblock = bread (sb->s_dev,
block, sb->s_blocksize)))
panic ("ext_free_block: unable to read block to free\n");
efb = (struct ext_free_block *) sb->u.ext_sb.s_firstfreeblock->b_data;
@@ -80,18 +80,17 @@ printk("ext_free_block: block full, skipping to %d\n", block);
sb->u.ext_sb.s_freeblockscount ++;
sb->s_dirt = 1;
sb->u.ext_sb.s_firstfreeblock->b_dirt = 1;
- free_super (sb);
+ unlock_super (sb);
return;
}
-int ext_new_block(int dev)
+int ext_new_block(struct super_block * sb)
{
struct buffer_head * bh;
- struct super_block * sb;
struct ext_free_block * efb;
int j;
- if (!(sb = get_super(dev)))
+ if (!sb)
panic("trying to get new block from nonexistant device");
if (!sb->u.ext_sb.s_firstfreeblock)
return 0;
@@ -110,7 +109,7 @@ printk("ext_new_block: block empty, skipping to %d\n", efb->next);
if (!sb->u.ext_sb.s_firstfreeblocknumber) {
sb->u.ext_sb.s_firstfreeblock = NULL;
} else {
- if (!(sb->u.ext_sb.s_firstfreeblock = bread (dev,
+ if (!(sb->u.ext_sb.s_firstfreeblock = bread (sb->s_dev,
sb->u.ext_sb.s_firstfreeblocknumber,
sb->s_blocksize)))
panic ("ext_new_block: unable to read next free block\n");
@@ -123,7 +122,7 @@ printk("ext_new_block: block empty, skipping to %d\n", efb->next);
sb->u.ext_sb.s_freeblockscount --;
sb->s_dirt = 1;
- if (!(bh=getblk(dev, j, sb->s_blocksize)))
+ if (!(bh=getblk(sb->s_dev, j, sb->s_blocksize)))
panic("new_block: cannot get block");
if (bh->b_count != 1)
panic("new block: count is != 1");
@@ -134,7 +133,7 @@ printk("ext_new_block: block empty, skipping to %d\n", efb->next);
#ifdef EXTFS_DEBUG
printk("ext_new_block: allocating block %d\n", j);
#endif
- free_super (sb);
+ unlock_super (sb);
return j;
}
@@ -166,7 +165,7 @@ unsigned long ext_count_free_blocks(struct super_block *sb)
}
printk("ext_count_free_blocks: stored = %d, computed = %d\n",
sb->u.ext_sb.s_freeblockscount, count);
- free_super (sb);
+ unlock_super (sb);
return count;
#else
return sb->u.ext_sb.s_freeblockscount;
@@ -200,7 +199,7 @@ void ext_free_inode(struct inode * inode)
lock_super (inode->i_sb);
if (inode->i_ino < 1 || inode->i_ino > inode->i_sb->u.ext_sb.s_ninodes) {
printk("free_inode: inode 0 or nonexistent inode\n");
- free_super (inode->i_sb);
+ unlock_super (inode->i_sb);
return;
}
if (inode->i_sb->u.ext_sb.s_firstfreeinodeblock)
@@ -227,57 +226,54 @@ printk("ext_free_inode: inode full, skipping to %d\n", inode->i_ino);
inode->i_sb->u.ext_sb.s_freeinodescount ++;
inode->i_sb->s_dirt = 1;
inode->i_sb->u.ext_sb.s_firstfreeinodeblock->b_dirt = 1;
- free_super (inode->i_sb);
+ unlock_super (inode->i_sb);
memset(inode,0,sizeof(*inode));
}
-struct inode * ext_new_inode(int dev)
+struct inode * ext_new_inode(struct super_block * sb)
{
struct inode * inode;
struct ext_free_inode * efi;
unsigned long block;
int j;
- if (!(inode=get_empty_inode()))
+ if (!sb || !(inode=get_empty_inode()))
return NULL;
- if (!(inode->i_sb = get_super(dev))) {
- printk("new_inode: unknown device\n");
- iput(inode);
- return NULL;
- }
- inode->i_flags = inode->i_sb->s_flags;
- if (!inode->i_sb->u.ext_sb.s_firstfreeinodeblock)
+ inode->i_sb = sb;
+ inode->i_flags = sb->s_flags;
+ if (!sb->u.ext_sb.s_firstfreeinodeblock)
return 0;
- lock_super (inode->i_sb);
- efi = ((struct ext_free_inode *) inode->i_sb->u.ext_sb.s_firstfreeinodeblock->b_data) +
- (inode->i_sb->u.ext_sb.s_firstfreeinodenumber-1)%EXT_INODES_PER_BLOCK;
+ lock_super (sb);
+ efi = ((struct ext_free_inode *) sb->u.ext_sb.s_firstfreeinodeblock->b_data) +
+ (sb->u.ext_sb.s_firstfreeinodenumber-1)%EXT_INODES_PER_BLOCK;
if (efi->count) {
j = efi->free[--efi->count];
- inode->i_sb->u.ext_sb.s_firstfreeinodeblock->b_dirt = 1;
+ sb->u.ext_sb.s_firstfreeinodeblock->b_dirt = 1;
} else {
#ifdef EXTFS_DEBUG
printk("ext_free_inode: inode empty, skipping to %d\n", efi->next);
#endif
- j = inode->i_sb->u.ext_sb.s_firstfreeinodenumber;
- if (efi->next > inode->i_sb->u.ext_sb.s_ninodes) {
+ j = sb->u.ext_sb.s_firstfreeinodenumber;
+ if (efi->next > sb->u.ext_sb.s_ninodes) {
printk ("efi->next = %d\n", efi->next);
panic ("ext_new_inode: bad inode number in free list\n");
}
- inode->i_sb->u.ext_sb.s_firstfreeinodenumber = efi->next;
+ sb->u.ext_sb.s_firstfreeinodenumber = efi->next;
block = 2 + (((unsigned long) efi->next) - 1) / EXT_INODES_PER_BLOCK;
- brelse (inode->i_sb->u.ext_sb.s_firstfreeinodeblock);
- if (!inode->i_sb->u.ext_sb.s_firstfreeinodenumber) {
- inode->i_sb->u.ext_sb.s_firstfreeinodeblock = NULL;
+ brelse (sb->u.ext_sb.s_firstfreeinodeblock);
+ if (!sb->u.ext_sb.s_firstfreeinodenumber) {
+ sb->u.ext_sb.s_firstfreeinodeblock = NULL;
} else {
- if (!(inode->i_sb->u.ext_sb.s_firstfreeinodeblock = bread (dev, block, inode->i_sb->s_blocksize)))
+ if (!(sb->u.ext_sb.s_firstfreeinodeblock =
+ bread(sb->s_dev, block, sb->s_blocksize)))
panic ("ext_new_inode: unable to read next free inode block\n");
}
}
- inode->i_sb->u.ext_sb.s_freeinodescount --;
- inode->i_sb->s_dirt = 1;
+ sb->u.ext_sb.s_freeinodescount --;
+ sb->s_dirt = 1;
inode->i_count = 1;
inode->i_nlink = 1;
- inode->i_dev = dev;
+ inode->i_dev = sb->s_dev;
inode->i_uid = current->euid;
inode->i_gid = current->egid;
inode->i_dirt = 1;
@@ -288,7 +284,7 @@ printk("ext_free_inode: inode empty, skipping to %d\n", efi->next);
#ifdef EXTFS_DEBUG
printk("ext_new_inode : allocating inode %d\n", inode->i_ino);
#endif
- free_super (inode->i_sb);
+ unlock_super (sb);
return inode;
}
@@ -328,7 +324,7 @@ unsigned long ext_count_free_inodes(struct super_block *sb)
}
printk("ext_count_free_inodes: stored = %d, computed = %d\n",
sb->u.ext_sb.s_freeinodescount, count);
- free_super (sb);
+ unlock_super (sb);
return count;
#else
return sb->u.ext_sb.s_freeinodescount;
diff --git a/fs/ext/inode.c b/fs/ext/inode.c
index 7998402..fe52dfb 100644
--- a/fs/ext/inode.c
+++ b/fs/ext/inode.c
@@ -16,22 +16,15 @@
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
+#include <linux/locks.h>
#include <asm/system.h>
#include <asm/segment.h>
-int sync_dev(int dev);
-
-static inline void wait_on_buffer(struct buffer_head * bh)
-{
- cli();
- while (bh->b_lock)
- sleep_on(&bh->b_wait);
- sti();
-}
-
void ext_put_inode(struct inode *inode)
{
+ if (inode->i_nlink)
+ return;
inode->i_size = 0;
ext_truncate(inode);
ext_free_inode(inode);
@@ -46,7 +39,7 @@ void ext_put_super(struct super_block *sb)
brelse (sb->u.ext_sb.s_firstfreeinodeblock);
if (sb->u.ext_sb.s_firstfreeblock)
brelse (sb->u.ext_sb.s_firstfreeblock);
- free_super(sb);
+ unlock_super(sb);
return;
}
@@ -68,7 +61,7 @@ struct super_block *ext_read_super(struct super_block *s,void *data)
lock_super(s);
if (!(bh = bread(dev, 1, BLOCK_SIZE))) {
s->s_dev=0;
- free_super(s);
+ unlock_super(s);
printk("bread failed\n");
return NULL;
}
@@ -87,7 +80,7 @@ struct super_block *ext_read_super(struct super_block *s,void *data)
brelse(bh);
if (s->s_magic != EXT_SUPER_MAGIC) {
s->s_dev = 0;
- free_super(s);
+ unlock_super(s);
printk("magic match failed\n");
return NULL;
}
@@ -98,7 +91,7 @@ struct super_block *ext_read_super(struct super_block *s,void *data)
s->u.ext_sb.s_firstfreeblocknumber, BLOCK_SIZE))) {
printk ("ext_read_super: unable to read first free block\n");
s->s_dev = 0;
- free_super(s);
+ unlock_super(s);
return NULL;
}
if (!s->u.ext_sb.s_firstfreeinodenumber)
@@ -109,15 +102,15 @@ struct super_block *ext_read_super(struct super_block *s,void *data)
printk ("ext_read_super: unable to read first free inode block\n");
brelse(s->u.ext_sb.s_firstfreeblock);
s->s_dev = 0;
- free_super (s);
+ unlock_super (s);
return NULL;
}
}
- free_super(s);
+ unlock_super(s);
/* set up enough so that it can read an inode */
s->s_dev = dev;
s->s_op = &ext_sops;
- if (!(s->s_mounted = iget(dev,EXT_ROOT_INO))) {
+ if (!(s->s_mounted = iget(s,EXT_ROOT_INO))) {
s->s_dev=0;
printk("get root inode failed\n");
return NULL;
@@ -235,12 +228,12 @@ repeat:
}
if (!create)
return NULL;
- tmp = ext_new_block(inode->i_dev);
+ tmp = ext_new_block(inode->i_sb);
if (!tmp)
return NULL;
result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
if (*p) {
- ext_free_block(inode->i_dev,tmp);
+ ext_free_block(inode->i_sb,tmp);
brelse(result);
goto repeat;
}
@@ -250,7 +243,8 @@ repeat:
return result;
}
-static struct buffer_head * block_getblk(struct buffer_head * bh, int nr, int create)
+static struct buffer_head * block_getblk(struct inode * inode,
+ struct buffer_head * bh, int nr, int create)
{
int tmp;
unsigned long * p;
@@ -282,14 +276,14 @@ repeat:
brelse(bh);
return NULL;
}
- tmp = ext_new_block(bh->b_dev);
+ tmp = ext_new_block(inode->i_sb);
if (!tmp) {
brelse(bh);
return NULL;
}
result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
if (*p) {
- ext_free_block(bh->b_dev,tmp);
+ ext_free_block(inode->i_sb,tmp);
brelse(result);
goto repeat;
}
@@ -316,19 +310,19 @@ struct buffer_head * ext_getblk(struct inode * inode, int block, int create)
block -= 9;
if (block<256) {
bh = inode_getblk(inode,9,create);
- return block_getblk(bh,block,create);
+ return block_getblk(inode,bh,block,create);
}
block -= 256;
if (block<256*256) {
bh = inode_getblk(inode,10,create);
- bh = block_getblk(bh,block>>8,create);
- return block_getblk(bh,block & 255,create);
+ bh = block_getblk(inode,bh,block>>8,create);
+ return block_getblk(inode,bh,block & 255,create);
}
block -= 256*256;
bh = inode_getblk(inode,11,create);
- bh = block_getblk(bh,block>>16,create);
- bh = block_getblk(bh,(block>>8) & 255,create);
- return block_getblk(bh,block & 255,create);
+ bh = block_getblk(inode,bh,block>>16,create);
+ bh = block_getblk(inode,bh,(block>>8) & 255,create);
+ return block_getblk(inode,bh,block & 255,create);
}
struct buffer_head * ext_bread(struct inode * inode, int block, int create)
diff --git a/fs/ext/namei.c b/fs/ext/namei.c
index 6be0c48..d92cab8 100644
--- a/fs/ext/namei.c
+++ b/fs/ext/namei.c
@@ -169,7 +169,7 @@ int ext_lookup(struct inode * dir,const char * name, int len,
}
ino = de->inode;
brelse(bh);
- if (!(*result = iget(dir->i_dev,ino))) {
+ if (!(*result = iget(dir->i_sb,ino))) {
iput(dir);
return -EACCES;
}
@@ -307,7 +307,7 @@ int ext_create(struct inode * dir,const char * name, int len, int mode,
*result = NULL;
if (!dir)
return -ENOENT;
- inode = ext_new_inode(dir->i_dev);
+ inode = ext_new_inode(dir->i_sb);
if (!inode) {
iput(dir);
return -ENOSPC;
@@ -345,7 +345,7 @@ int ext_mknod(struct inode * dir, const char * name, int len, int mode, int rdev
iput(dir);
return -EEXIST;
}
- inode = ext_new_inode(dir->i_dev);
+ inode = ext_new_inode(dir->i_sb);
if (!inode) {
iput(dir);
return -ENOSPC;
@@ -403,7 +403,7 @@ int ext_mkdir(struct inode * dir, const char * name, int len, int mode)
iput(dir);
return -EEXIST;
}
- inode = ext_new_inode(dir->i_dev);
+ inode = ext_new_inode(dir->i_sb);
if (!inode) {
iput(dir);
return -ENOSPC;
@@ -509,9 +509,9 @@ static int empty_dir(struct inode * inode)
static inline void ext_merge_entries (struct ext_dir_entry * de,
struct ext_dir_entry * pde, struct ext_dir_entry * nde)
{
- if (! nde->inode)
+ if (nde && !nde->inode)
de->rec_len += nde->rec_len;
- if (! pde->inode)
+ if (pde && !pde->inode)
pde->rec_len += de->rec_len;
}
@@ -528,7 +528,7 @@ int ext_rmdir(struct inode * dir, const char * name, int len)
if (!bh)
goto end_rmdir;
retval = -EPERM;
- if (!(inode = iget(dir->i_dev, de->inode)))
+ if (!(inode = iget(dir->i_sb, de->inode)))
goto end_rmdir;
if ((dir->i_mode & S_ISVTX) && current->euid &&
inode->i_uid != current->euid)
@@ -580,7 +580,7 @@ int ext_unlink(struct inode * dir, const char * name, int len)
bh = ext_find_entry(dir,name,len,&de,&pde,&nde);
if (!bh)
goto end_unlink;
- if (!(inode = iget(dir->i_dev, de->inode)))
+ if (!(inode = iget(dir->i_sb, de->inode)))
goto end_unlink;
retval = -EPERM;
if ((dir->i_mode & S_ISVTX) && !suser() &&
@@ -617,7 +617,7 @@ int ext_symlink(struct inode * dir, const char * name, int len, const char * sym
int i;
char c;
- if (!(inode = ext_new_inode(dir->i_dev))) {
+ if (!(inode = ext_new_inode(dir->i_sb))) {
iput(dir);
return -ENOSPC;
}
@@ -674,6 +674,11 @@ int ext_link(struct inode * oldinode, struct inode * dir, const char * name, int
iput(dir);
return -EPERM;
}
+ if (oldinode->i_nlink > 32000) {
+ iput(oldinode);
+ iput(dir);
+ return -EMLINK;
+ }
bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
if (bh) {
brelse(bh);
@@ -768,7 +773,7 @@ start_up:
retval = -ENOENT;
if (!old_bh)
goto end_rename;
- old_inode = iget(old_dir->i_dev, old_de->inode);
+ old_inode = iget(old_dir->i_sb, old_de->inode);
if (!old_inode)
goto end_rename;
retval = -EPERM;
@@ -778,7 +783,7 @@ start_up:
goto end_rename;
new_bh = ext_find_entry(new_dir,new_name,new_len,&new_de,NULL,NULL);
if (new_bh) {
- new_inode = iget(new_dir->i_dev, new_de->inode);
+ new_inode = iget(new_dir->i_sb, new_de->inode);
if (!new_inode) {
brelse(new_bh);
new_bh = NULL;
diff --git a/fs/ext/truncate.c b/fs/ext/truncate.c
index 9d94f64..d7a6506 100644
--- a/fs/ext/truncate.c
+++ b/fs/ext/truncate.c
@@ -56,7 +56,7 @@ repeat:
*p = 0;
inode->i_dirt = 1;
brelse(bh);
- ext_free_block(inode->i_dev,tmp);
+ ext_free_block(inode->i_sb,tmp);
}
return retry;
}
@@ -105,7 +105,7 @@ repeat:
*ind = 0;
ind_bh->b_dirt = 1;
brelse(bh);
- ext_free_block(inode->i_dev,tmp);
+ ext_free_block(inode->i_sb,tmp);
}
ind = (unsigned long *) ind_bh->b_data;
for (i = 0; i < 256; i++)
@@ -118,7 +118,7 @@ repeat:
tmp = *p;
*p = 0;
inode->i_dirt = 1;
- ext_free_block(inode->i_dev,tmp);
+ ext_free_block(inode->i_sb,tmp);
}
brelse(ind_bh);
return retry;
@@ -168,7 +168,7 @@ repeat:
tmp = *p;
*p = 0;
inode->i_dirt = 1;
- ext_free_block(inode->i_dev,tmp);
+ ext_free_block(inode->i_sb,tmp);
}
brelse(dind_bh);
return retry;
@@ -215,7 +215,7 @@ repeat:
tmp = *p;
*p = 0;
inode->i_dirt = 1;
- ext_free_block(inode->i_dev,tmp);
+ ext_free_block(inode->i_sb,tmp);
}
brelse(tind_bh);
return retry;
diff --git a/fs/inode.c b/fs/inode.c
index b30fca0..30e2e70 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -12,28 +12,74 @@
#include <asm/system.h>
-struct inode inode_table[NR_INODE]={{0,},};
+static struct inode inode_table[NR_INODE];
+
+void inode_init(void)
+{
+ memset(inode_table,0,sizeof(inode_table));
+}
+
+int fs_may_mount(dev_t dev)
+{
+ struct inode * inode;
+
+ for (inode = inode_table+0 ; inode < inode_table+NR_INODE ; inode++) {
+ if (inode->i_dev != dev)
+ continue;
+ if (inode->i_count || inode->i_dirt || inode->i_lock)
+ return 0;
+ inode->i_dev = 0;
+ }
+ return 1;
+}
+
+int fs_may_umount(dev_t dev, struct inode * mount_root)
+{
+ struct inode * inode;
+
+ for (inode = inode_table+0 ; inode < inode_table+NR_INODE ; inode++)
+ if (inode->i_dev==dev && inode->i_count)
+ if (inode == mount_root && inode->i_count == 1)
+ continue;
+ else
+ return 0;
+ return 1;
+}
+
+/*
+ * The "new" scheduling primitives (new as of 0.97 or so) allow this to
+ * be done without disabling interrupts (other than in the actual queue
+ * updating things: only a couple of 386 instructions). This should be
+ * much better for interrupt latency.
+ */
+static void __wait_on_inode(struct inode * inode)
+{
+ add_wait_queue(&inode->i_wait,&current->wait);
+repeat:
+ current->state = TASK_UNINTERRUPTIBLE;
+ if (inode->i_lock) {
+ schedule();
+ goto repeat;
+ }
+ remove_wait_queue(&inode->i_wait,&current->wait);
+ current->state = TASK_RUNNING;
+}
static inline void wait_on_inode(struct inode * inode)
{
- cli();
- while (inode->i_lock)
- sleep_on(&inode->i_wait);
- sti();
+ if (inode->i_lock)
+ __wait_on_inode(inode);
}
static inline void lock_inode(struct inode * inode)
{
- cli();
- while (inode->i_lock)
- sleep_on(&inode->i_wait);
- inode->i_lock=1;
- sti();
+ wait_on_inode(inode);
+ inode->i_lock = 1;
}
static inline void unlock_inode(struct inode * inode)
{
- inode->i_lock=0;
+ inode->i_lock = 0;
wake_up(&inode->i_wait);
}
@@ -41,8 +87,8 @@ static void write_inode(struct inode * inode)
{
if (!inode->i_dirt)
return;
- inode->i_dirt = 0;
lock_inode(inode);
+ inode->i_dirt = 0;
if (inode->i_dev && inode->i_sb &&
inode->i_sb->s_op && inode->i_sb->s_op->write_inode)
inode->i_sb->s_op->write_inode(inode);
@@ -74,7 +120,7 @@ int bmap(struct inode * inode, int block)
return 0;
}
-void invalidate_inodes(int dev)
+void invalidate_inodes(dev_t dev)
{
int i;
struct inode * inode;
@@ -92,7 +138,7 @@ void invalidate_inodes(int dev)
}
}
-void sync_inodes(void)
+void sync_inodes(dev_t dev)
{
int i;
struct inode * inode;
@@ -134,11 +180,10 @@ repeat:
inode->i_count--;
return;
}
- if (!inode->i_nlink) {
- if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->put_inode) {
- inode->i_sb->s_op->put_inode(inode);
+ if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->put_inode) {
+ inode->i_sb->s_op->put_inode(inode);
+ if (!inode->i_nlink)
return;
- }
}
if (inode->i_dirt) {
write_inode(inode); /* we can sleep - so do again */
@@ -201,21 +246,21 @@ struct inode * get_pipe_inode(void)
return inode;
}
-struct inode * iget(int dev,int nr)
+struct inode * iget(struct super_block * sb,int nr)
{
struct inode * inode, * empty;
- if (!dev)
- panic("iget with dev==0");
+ if (!sb)
+ panic("iget with sb==NULL");
empty = get_empty_inode();
inode = inode_table;
while (inode < NR_INODE+inode_table) {
- if (inode->i_dev != dev || inode->i_ino != nr) {
+ if (inode->i_sb != sb || inode->i_ino != nr) {
inode++;
continue;
}
wait_on_inode(inode);
- if (inode->i_dev != dev || inode->i_ino != nr) {
+ if (inode->i_sb != sb || inode->i_ino != nr) {
inode = inode_table;
continue;
}
@@ -247,14 +292,10 @@ struct inode * iget(int dev,int nr)
if (!empty)
return (NULL);
inode = empty;
- if (!(inode->i_sb = get_super(dev))) {
- printk("iget: gouldn't get super-block\n\t");
- iput(inode);
- return NULL;
- }
- inode->i_dev = dev;
+ inode->i_sb = sb;
+ inode->i_dev = sb->s_dev;
inode->i_ino = nr;
- inode->i_flags = inode->i_sb->s_flags;
+ inode->i_flags = sb->s_flags;
read_inode(inode);
return inode;
}
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index cc66d7f..c1cf6a1 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -73,13 +73,12 @@ static unsigned long count_used(struct buffer_head *map[], unsigned numblocks,
return(sum);
}
-void minix_free_block(int dev, int block)
+void minix_free_block(struct super_block * sb, int block)
{
- struct super_block * sb;
struct buffer_head * bh;
unsigned int bit,zone;
- if (!(sb = get_super(dev))) {
+ if (!sb) {
printk("trying to free block on nonexistent device\n");
return;
}
@@ -88,7 +87,7 @@ void minix_free_block(int dev, int block)
printk("trying to free block not in datazone\n");
return;
}
- bh = get_hash_table(dev,block,BLOCK_SIZE);
+ bh = get_hash_table(sb->s_dev,block,BLOCK_SIZE);
if (bh)
bh->b_dirt=0;
brelse(bh);
@@ -101,18 +100,17 @@ void minix_free_block(int dev, int block)
return;
}
if (clear_bit(bit,bh->b_data))
- printk("free_block (%04x:%d): bit already cleared\n",dev,block);
+ printk("free_block (%04x:%d): bit already cleared\n",sb->s_dev,block);
bh->b_dirt = 1;
return;
}
-int minix_new_block(int dev)
+int minix_new_block(struct super_block * sb)
{
struct buffer_head * bh;
- struct super_block * sb;
int i,j;
- if (!(sb = get_super(dev))) {
+ if (!sb) {
printk("trying to get new block from nonexistant device\n");
return 0;
}
@@ -132,7 +130,7 @@ repeat:
j += i*8192 + sb->u.minix_sb.s_firstdatazone-1;
if (j >= sb->u.minix_sb.s_nzones)
return 0;
- if (!(bh=getblk(dev,j,BLOCK_SIZE))) {
+ if (!(bh = getblk(sb->s_dev,j,BLOCK_SIZE))) {
printk("new_block: cannot get block");
return 0;
}
@@ -189,19 +187,15 @@ void minix_free_inode(struct inode * inode)
memset(inode,0,sizeof(*inode));
}
-struct inode * minix_new_inode(int dev)
+struct inode * minix_new_inode(struct super_block * sb)
{
struct inode * inode;
struct buffer_head * bh;
int i,j;
- if (!(inode=get_empty_inode()))
+ if (!sb || !(inode = get_empty_inode()))
return NULL;
- if (!(inode->i_sb = get_super(dev))) {
- printk("new_inode: unknown device\n");
- iput(inode);
- return NULL;
- }
+ inode->i_sb = sb;
inode->i_flags = inode->i_sb->s_flags;
j = 8192;
for (i=0 ; i<8 ; i++)
@@ -220,7 +214,7 @@ struct inode * minix_new_inode(int dev)
bh->b_dirt = 1;
inode->i_count = 1;
inode->i_nlink = 1;
- inode->i_dev = dev;
+ inode->i_dev = sb->s_dev;
inode->i_uid = current->euid;
inode->i_gid = current->egid;
inode->i_dirt = 1;
diff --git a/fs/minix/file.c b/fs/minix/file.c
index 48ca216..57fb4d5 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -15,6 +15,7 @@
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
+#include <linux/locks.h>
#define NBUF 16
@@ -24,14 +25,6 @@
#include <linux/fs.h>
#include <linux/minix_fs.h>
-static inline void wait_on_buffer(struct buffer_head * bh)
-{
- cli();
- while (bh->b_lock)
- sleep_on(&bh->b_wait);
- sti();
-}
-
static int minix_file_read(struct inode *, struct file *, char *, int);
static int minix_file_write(struct inode *, struct file *, char *, int);
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 7a188f1..651f397 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -10,22 +10,15 @@
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
+#include <linux/locks.h>
#include <asm/system.h>
#include <asm/segment.h>
-int sync_dev(int dev);
-
-static inline void wait_on_buffer(struct buffer_head * bh)
-{
- cli();
- while (bh->b_lock)
- sleep_on(&bh->b_wait);
- sti();
-}
-
void minix_put_inode(struct inode *inode)
{
+ if (inode->i_nlink)
+ return;
inode->i_size = 0;
minix_truncate(inode);
minix_free_inode(inode);
@@ -41,7 +34,7 @@ void minix_put_super(struct super_block *sb)
brelse(sb->u.minix_sb.s_imap[i]);
for(i = 0 ; i < MINIX_Z_MAP_SLOTS ; i++)
brelse(sb->u.minix_sb.s_zmap[i]);
- free_super(sb);
+ unlock_super(sb);
return;
}
@@ -63,7 +56,7 @@ struct super_block *minix_read_super(struct super_block *s,void *data)
lock_super(s);
if (!(bh = bread(dev,1,BLOCK_SIZE))) {
s->s_dev=0;
- free_super(s);
+ unlock_super(s);
printk("bread failed\n");
return NULL;
}
@@ -80,7 +73,7 @@ struct super_block *minix_read_super(struct super_block *s,void *data)
brelse(bh);
if (s->s_magic != MINIX_SUPER_MAGIC) {
s->s_dev = 0;
- free_super(s);
+ unlock_super(s);
printk("magic match failed\n");
return NULL;
}
@@ -105,25 +98,26 @@ struct super_block *minix_read_super(struct super_block *s,void *data)
for(i=0;i<MINIX_Z_MAP_SLOTS;i++)
brelse(s->u.minix_sb.s_zmap[i]);
s->s_dev=0;
- free_super(s);
+ unlock_super(s);
printk("block failed\n");
return NULL;
}
s->u.minix_sb.s_imap[0]->b_data[0] |= 1;
s->u.minix_sb.s_zmap[0]->b_data[0] |= 1;
- free_super(s);
/* set up enough so that it can read an inode */
s->s_dev = dev;
s->s_op = &minix_sops;
- if (!(s->s_mounted = iget(dev,MINIX_ROOT_INO))) {
- s->s_dev=0;
+ s->s_mounted = iget(s,MINIX_ROOT_INO);
+ unlock_super(s);
+ if (!s->s_mounted) {
+ s->s_dev = 0;
printk("get root inode failed\n");
return NULL;
}
return s;
}
-void minix_statfs (struct super_block *sb, struct statfs *buf)
+void minix_statfs(struct super_block *sb, struct statfs *buf)
{
long tmp;
@@ -200,12 +194,12 @@ repeat:
}
if (!create)
return NULL;
- tmp = minix_new_block(inode->i_dev);
+ tmp = minix_new_block(inode->i_sb);
if (!tmp)
return NULL;
result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
if (*p) {
- minix_free_block(inode->i_dev,tmp);
+ minix_free_block(inode->i_sb,tmp);
brelse(result);
goto repeat;
}
@@ -215,7 +209,8 @@ repeat:
return result;
}
-static struct buffer_head * block_getblk(struct buffer_head * bh, int nr, int create)
+static struct buffer_head * block_getblk(struct inode * inode,
+ struct buffer_head * bh, int nr, int create)
{
int tmp;
unsigned short *p;
@@ -247,14 +242,14 @@ repeat:
brelse(bh);
return NULL;
}
- tmp = minix_new_block(bh->b_dev);
+ tmp = minix_new_block(inode->i_sb);
if (!tmp) {
brelse(bh);
return NULL;
}
result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
if (*p) {
- minix_free_block(bh->b_dev,tmp);
+ minix_free_block(inode->i_sb,tmp);
brelse(result);
goto repeat;
}
@@ -281,12 +276,12 @@ struct buffer_head * minix_getblk(struct inode * inode, int block, int create)
block -= 7;
if (block < 512) {
bh = inode_getblk(inode,7,create);
- return block_getblk(bh,block,create);
+ return block_getblk(inode, bh, block, create);
}
block -= 512;
bh = inode_getblk(inode,8,create);
- bh = block_getblk(bh,block>>9,create);
- return block_getblk(bh,block & 511,create);
+ bh = block_getblk(inode, bh, block>>9, create);
+ return block_getblk(inode, bh, block & 511, create);
}
struct buffer_head * minix_bread(struct inode * inode, int block, int create)
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index bcc5f3f..a5e098d 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -119,7 +119,7 @@ int minix_lookup(struct inode * dir,const char * name, int len,
}
ino = de->inode;
brelse(bh);
- if (!(*result = iget(dir->i_dev,ino))) {
+ if (!(*result = iget(dir->i_sb,ino))) {
iput(dir);
return -EACCES;
}
@@ -200,7 +200,7 @@ int minix_create(struct inode * dir,const char * name, int len, int mode,
*result = NULL;
if (!dir)
return -ENOENT;
- inode = minix_new_inode(dir->i_dev);
+ inode = minix_new_inode(dir->i_sb);
if (!inode) {
iput(dir);
return -ENOSPC;
@@ -238,7 +238,7 @@ int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rd
iput(dir);
return -EEXIST;
}
- inode = minix_new_inode(dir->i_dev);
+ inode = minix_new_inode(dir->i_sb);
if (!inode) {
iput(dir);
return -ENOSPC;
@@ -296,7 +296,7 @@ int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
iput(dir);
return -EEXIST;
}
- inode = minix_new_inode(dir->i_dev);
+ inode = minix_new_inode(dir->i_sb);
if (!inode) {
iput(dir);
return -ENOSPC;
@@ -396,7 +396,7 @@ int minix_rmdir(struct inode * dir, const char * name, int len)
if (!bh)
goto end_rmdir;
retval = -EPERM;
- if (!(inode = iget(dir->i_dev, de->inode)))
+ if (!(inode = iget(dir->i_sb, de->inode)))
goto end_rmdir;
if ((dir->i_mode & S_ISVTX) && current->euid &&
inode->i_uid != current->euid)
@@ -446,7 +446,7 @@ int minix_unlink(struct inode * dir, const char * name, int len)
bh = minix_find_entry(dir,name,len,&de);
if (!bh)
goto end_unlink;
- if (!(inode = iget(dir->i_dev, de->inode)))
+ if (!(inode = iget(dir->i_sb, de->inode)))
goto end_unlink;
retval = -EPERM;
if ((dir->i_mode & S_ISVTX) && !suser() &&
@@ -481,7 +481,7 @@ int minix_symlink(struct inode * dir, const char * name, int len, const char * s
int i;
char c;
- if (!(inode = minix_new_inode(dir->i_dev))) {
+ if (!(inode = minix_new_inode(dir->i_sb))) {
iput(dir);
return -ENOSPC;
}
@@ -538,6 +538,11 @@ int minix_link(struct inode * oldinode, struct inode * dir, const char * name, i
iput(dir);
return -EPERM;
}
+ if (oldinode->i_nlink > 126) {
+ iput(oldinode);
+ iput(dir);
+ return -EMLINK;
+ }
bh = minix_find_entry(dir,name,len,&de);
if (bh) {
brelse(bh);
@@ -630,7 +635,7 @@ start_up:
retval = -ENOENT;
if (!old_bh)
goto end_rename;
- old_inode = iget(old_dir->i_dev, old_de->inode);
+ old_inode = iget(old_dir->i_sb, old_de->inode);
if (!old_inode)
goto end_rename;
retval = -EPERM;
@@ -640,7 +645,7 @@ start_up:
goto end_rename;
new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de);
if (new_bh) {
- new_inode = iget(new_dir->i_dev, new_de->inode);
+ new_inode = iget(new_dir->i_sb, new_de->inode);
if (!new_inode) {
brelse(new_bh);
new_bh = NULL;
diff --git a/fs/minix/truncate.c b/fs/minix/truncate.c
index 276e5df..29f4c6d 100644
--- a/fs/minix/truncate.c
+++ b/fs/minix/truncate.c
@@ -50,7 +50,7 @@ repeat:
*p = 0;
inode->i_dirt = 1;
brelse(bh);
- minix_free_block(inode->i_dev,tmp);
+ minix_free_block(inode->i_sb,tmp);
}
return retry;
}
@@ -99,7 +99,7 @@ repeat:
*ind = 0;
ind_bh->b_dirt = 1;
brelse(bh);
- minix_free_block(inode->i_dev,tmp);
+ minix_free_block(inode->i_sb,tmp);
}
ind = (unsigned short *) ind_bh->b_data;
for (i = 0; i < 512; i++)
@@ -111,7 +111,7 @@ repeat:
else {
tmp = *p;
*p = 0;
- minix_free_block(inode->i_dev,tmp);
+ minix_free_block(inode->i_sb,tmp);
}
brelse(ind_bh);
return retry;
@@ -158,7 +158,7 @@ repeat:
tmp = *p;
*p = 0;
inode->i_dirt = 1;
- minix_free_block(inode->i_dev,tmp);
+ minix_free_block(inode->i_sb,tmp);
}
brelse(dind_bh);
return retry;
diff --git a/fs/msdos/inode.c b/fs/msdos/inode.c
index 5b0ff42..16e4d1e 100644
--- a/fs/msdos/inode.c
+++ b/fs/msdos/inode.c
@@ -11,6 +11,7 @@
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/stat.h>
+#include <linux/locks.h>
#include <asm/segment.h>
@@ -18,6 +19,8 @@ void msdos_put_inode(struct inode *inode)
{
struct inode *depend;
+ if (inode->i_nlink)
+ return;
inode->i_size = 0;
msdos_truncate(inode);
depend = MSDOS_I(inode)->i_depend;
@@ -40,7 +43,7 @@ void msdos_put_super(struct super_block *sb)
cache_inval_dev(sb->s_dev);
lock_super(sb);
sb->s_dev = 0;
- free_super(sb);
+ unlock_super(sb);
return;
}
@@ -55,32 +58,6 @@ static struct super_operations msdos_sops = {
};
-static unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
-{
- unsigned long result = 0,value;
-
- if (!base) {
- base = 10;
- if (*cp == '0') {
- base = 8;
- cp++;
- if ((*cp == 'x') && isxdigit(cp[1])) {
- cp++;
- base = 16;
- }
- }
- }
- while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
- ? toupper(*cp) : *cp)-'A'+10) < base) {
- result = result*base + value;
- cp++;
- }
- if (endp)
- *endp = (char *)cp;
- return result;
-}
-
-
static int parse_options(char *options,char *check,char *conversion,uid_t *uid, gid_t *gid, int *umask)
{
char *this,*value;
@@ -155,7 +132,7 @@ struct super_block *msdos_read_super(struct super_block *s,void *data)
cache_init();
lock_super(s);
bh = bread(s->s_dev, 0, BLOCK_SIZE);
- free_super(s);
+ unlock_super(s);
if (bh == NULL) {
s->s_dev = 0;
printk("MSDOS bread failed\n");
@@ -202,7 +179,7 @@ printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,se=%d,ts=%d]\n",
MSDOS_SB(s)->free_clusters = -1; /* don't know yet */
MSDOS_SB(s)->fat_wait = NULL;
MSDOS_SB(s)->fat_lock = 0;
- if (!(s->s_mounted = iget(s->s_dev,MSDOS_ROOT_INO))) {
+ if (!(s->s_mounted = iget(s,MSDOS_ROOT_INO))) {
s->s_dev = 0;
printk("get root inode failed\n");
return NULL;
diff --git a/fs/msdos/misc.c b/fs/msdos/misc.c
index 8b4acc7..40d2243 100644
--- a/fs/msdos/misc.c
+++ b/fs/msdos/misc.c
@@ -282,7 +282,7 @@ int msdos_scan(struct inode *dir,char *name,struct buffer_head **res_bh,
}
else if (!de->name[0] || ((unsigned char *) (de->name))[0] ==
DELETED_FLAG) {
- if (!(inode = iget(dir->i_dev,*ino))) break;
+ if (!(inode = iget(dir->i_sb,*ino))) break;
if (!MSDOS_I(inode)->i_busy) {
iput(inode);
break;
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index 37b4aa3..80d5194 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -131,7 +131,7 @@ int msdos_lookup(struct inode *dir,const char *name,int len,
ino = msdos_parent_ino(dir,0);
iput(dir);
if (ino < 0) return ino;
- if (!(*result = iget(dir->i_dev,ino))) return -EACCES;
+ if (!(*result = iget(dir->i_sb,ino))) return -EACCES;
return 0;
}
if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) {
@@ -140,7 +140,7 @@ int msdos_lookup(struct inode *dir,const char *name,int len,
}
if (bh) brelse(bh);
/* printk("lookup: ino=%d\r\n",ino); */
- if (!(*result = iget(dir->i_dev,ino))) {
+ if (!(*result = iget(dir->i_sb,ino))) {
iput(dir);
return -EACCES;
}
@@ -152,7 +152,7 @@ int msdos_lookup(struct inode *dir,const char *name,int len,
while (MSDOS_I(*result)->i_old) {
next = MSDOS_I(*result)->i_old;
iput(*result);
- if (!(*result = iget(next->i_dev,next->i_ino)))
+ if (!(*result = iget(next->i_sb,next->i_ino)))
panic("msdos_lookup: Can't happen");
}
iput(dir);
@@ -180,7 +180,7 @@ static int msdos_create_entry(struct inode *dir,char *name,int is_dir,
date_unix2dos(CURRENT_TIME,&de->time,&de->date);
de->size = 0;
bh->b_dirt = 1;
- if (*result = iget(dir->i_dev,ino)) msdos_read_inode(*result);
+ if (*result = iget(dir->i_sb,ino)) msdos_read_inode(*result);
brelse(bh);
if (!*result) return -EIO;
(*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
@@ -308,7 +308,7 @@ int msdos_rmdir(struct inode *dir,const char *name,int len)
get_fs_byte(name+1) == '.'))) goto rmdir_done;
if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done;
res = -ENOENT;
- if (!(inode = iget(dir->i_dev,ino))) goto rmdir_done;
+ if (!(inode = iget(dir->i_sb,ino))) goto rmdir_done;
res = -ENOTDIR;
if (!S_ISDIR(inode->i_mode)) goto rmdir_done;
res = -EBUSY;
@@ -351,7 +351,7 @@ int msdos_unlink(struct inode *dir,const char *name,int len)
inode = NULL;
if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0)
goto unlink_done;
- if (!(inode = iget(dir->i_dev,ino))) {
+ if (!(inode = iget(dir->i_sb,ino))) {
res = -ENOENT;
goto unlink_done;
}
@@ -389,7 +389,7 @@ static int rename_same_dir(struct inode *old_dir,char *old_name,
return -ENOENT;
}
if (exists) {
- if (!(new_inode = iget(new_dir->i_dev,new_ino))) {
+ if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
brelse(new_bh);
return -EIO;
}
@@ -409,7 +409,7 @@ static int rename_same_dir(struct inode *old_dir,char *old_name,
memcpy(old_de->name,new_name,MSDOS_NAME);
old_bh->b_dirt = 1;
if (MSDOS_SB(old_dir->i_sb)->conversion == 'a') /* update binary info */
- if (old_inode = iget(old_dir->i_dev,old_ino)) {
+ if (old_inode = iget(old_dir->i_sb,old_ino)) {
msdos_read_inode(old_inode);
iput(old_inode);
}
@@ -429,20 +429,20 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,
if (old_dir->i_dev != new_dir->i_dev) return -EINVAL;
if (old_ino == new_dir->i_ino) return -EINVAL;
- if (!(walk = iget(new_dir->i_dev,new_dir->i_ino))) return -EIO;
+ if (!(walk = iget(new_dir->i_sb,new_dir->i_ino))) return -EIO;
while (walk->i_ino != MSDOS_ROOT_INO) {
ino = msdos_parent_ino(walk,1);
iput(walk);
if (ino < 0) return ino;
if (ino == old_ino) return -EINVAL;
- if (!(walk = iget(new_dir->i_dev,ino))) return -EIO;
+ if (!(walk = iget(new_dir->i_sb,ino))) return -EIO;
}
iput(walk);
if ((error = msdos_scan(new_dir,NULL,&free_bh,&free_de,&free_ino)) < 0)
return error;
exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino)
>= 0;
- if (!(old_inode = iget(old_dir->i_dev,old_ino))) {
+ if (!(old_inode = iget(old_dir->i_sb,old_ino))) {
brelse(free_bh);
if (exists) brelse(new_bh);
return -EIO;
@@ -455,7 +455,7 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,
}
new_inode = NULL; /* to make GCC happy */
if (exists) {
- if (!(new_inode = iget(new_dir->i_dev,new_ino))) {
+ if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
iput(old_inode);
brelse(new_bh);
return -EIO;
@@ -474,7 +474,7 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,
}
memcpy(free_de,old_de,sizeof(struct msdos_dir_entry));
memcpy(free_de->name,new_name,MSDOS_NAME);
- if (!(free_inode = iget(new_dir->i_dev,free_ino))) {
+ if (!(free_inode = iget(new_dir->i_sb,free_ino))) {
free_de->name[0] = DELETED_FLAG;
/* Don't mark free_bh as dirty. Both states are supposed to be equivalent. */
brelse(free_bh);
@@ -502,7 +502,7 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,
if (S_ISDIR(old_inode->i_mode)) {
if ((error = msdos_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
&dotdot_de,&dotdot_ino)) < 0) goto rename_done;
- if (!(dotdot_inode = iget(old_inode->i_dev,dotdot_ino))) {
+ if (!(dotdot_inode = iget(old_inode->i_sb,dotdot_ino))) {
brelse(dotdot_bh);
error = -EIO;
goto rename_done;
diff --git a/fs/namei.c b/fs/namei.c
index 648c3f2..17c2185 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -71,6 +71,10 @@ int lookup(struct inode * dir,const char * name, int len,
}
if (!dir)
return -ENOENT;
+ if (!dir->i_op || !dir->i_op->lookup) {
+ iput(dir);
+ return -ENOTDIR;
+ }
if (!permission(dir,MAY_EXEC)) {
iput(dir);
return -EACCES;
@@ -79,10 +83,6 @@ int lookup(struct inode * dir,const char * name, int len,
*result = dir;
return 0;
}
- if (!dir->i_op || !dir->i_op->lookup) {
- iput(dir);
- return -ENOENT;
- }
return dir->i_op->lookup(dir,name,len,result);
}
@@ -293,7 +293,7 @@ int open_namei(const char * pathname, int flag, int mode,
return 0;
}
-int do_mknod(const char * filename, int mode, int dev)
+int do_mknod(const char * filename, int mode, dev_t dev)
{
const char * basename;
int namelen, error;
@@ -321,7 +321,7 @@ int do_mknod(const char * filename, int mode, int dev)
return dir->i_op->mknod(dir,basename,namelen,mode,dev);
}
-int sys_mknod(const char * filename, int mode, int dev)
+int sys_mknod(const char * filename, int mode, dev_t dev)
{
if (S_ISFIFO(mode) || suser())
return do_mknod(filename,mode,dev);
@@ -373,7 +373,7 @@ int sys_rmdir(const char * name)
iput(dir);
return -EROFS;
}
- if (!permission(dir,MAY_WRITE)) {
+ if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
iput(dir);
return -EACCES;
}
@@ -401,7 +401,7 @@ int sys_unlink(const char * name)
iput(dir);
return -EROFS;
}
- if (!permission(dir,MAY_WRITE)) {
+ if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
iput(dir);
return -EACCES;
}
diff --git a/fs/open.c b/fs/open.c
index 86f105d..1193e17 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -419,6 +419,28 @@ int sys_close(unsigned int fd)
}
/*
+ * This routine is used by vhangup. It send's sigkill to everything
+ * waiting on a particular wait_queue. It assumes root privledges.
+ * We don't want to destroy the wait queue here, because the caller
+ * should call wake_up immediately after calling kill_wait.
+ */
+static void kill_wait(struct wait_queue **q, int sig)
+{
+ struct wait_queue *next;
+ struct wait_queue *tmp;
+ struct task_struct *p;
+
+ if (!q || !(next = *q))
+ return;
+ do {
+ tmp = next;
+ next = tmp->next;
+ if (p = tmp->task)
+ send_sig (sig, p , 1);
+ } while (next && next != *q);
+}
+
+/*
* This routine looks through all the process's and closes any
* references to the current processes tty. To avoid problems with
* process sleeping on an inode which has already been iput, anyprocess
@@ -430,10 +452,11 @@ int sys_close(unsigned int fd)
*/
int sys_vhangup(void)
{
- int i,j;
+ int j;
+ struct task_struct ** process;
struct file *filep;
+ struct inode *inode;
struct tty_struct *tty;
- extern void kill_wait (struct wait_queue **q, int signal);
extern int kill_pg (int pgrp, int sig, int priv);
if (!suser())
@@ -444,33 +467,34 @@ int sys_vhangup(void)
if (current->tty < 0)
return 0;
- for (i = 0; i < NR_TASKS; i++) {
- if (task[i] == NULL)
- continue;
+ for (process = task + 0; process < task + NR_TASKS; process++) {
for (j = 0; j < NR_OPEN; j++) {
- filep = task[i]->filp[j];
- if (!filep)
+ if (!*process)
+ break;
+ if (!(filep = (*process)->filp[j]))
continue;
- if (!S_ISCHR(filep->f_inode->i_mode))
+ if (!(inode = filep->f_inode))
continue;
- if ((MAJOR(filep->f_inode->i_rdev) == 5 ||
- MAJOR(filep->f_inode->i_rdev) == 4 ) &&
+ if (!S_ISCHR(inode->i_mode))
+ continue;
+ if ((MAJOR(inode->i_rdev) == 5 ||
+ MAJOR(inode->i_rdev) == 4 ) &&
(MAJOR(filep->f_rdev) == 4 &&
MINOR(filep->f_rdev) == MINOR (current->tty))) {
/* so now we have found something to close. We
need to kill every process waiting on the
inode. */
- task[i]->filp[j] = NULL;
- kill_wait (&filep->f_inode->i_wait, SIGKILL);
+ (*process)->filp[j] = NULL;
+ kill_wait (&inode->i_wait, SIGKILL);
/* now make sure they are awake before we close the
file. */
- wake_up (&filep->f_inode->i_wait);
+ wake_up (&inode->i_wait);
/* finally close the file. */
- current->close_on_exec &= ~(1<<j);
+ (*process)->close_on_exec &= ~(1<<j);
close_fp (filep);
}
}
@@ -478,15 +502,17 @@ int sys_vhangup(void)
But we can't touch current->tty until after the
loop is complete. */
- if (task[i]->tty == current->tty && task[i] != current) {
- task[i]->tty = -1;
+ if (*process && (*process)->tty == current->tty && *process != current) {
+ (*process)->tty = -1;
}
}
/* need to do tty->session = 0 */
tty = TTY_TABLE(MINOR(current->tty));
- tty->session = 0;
- tty->pgrp = -1;
- current->tty = -1;
+ if (tty) {
+ tty->session = 0;
+ tty->pgrp = -1;
+ current->tty = -1;
+ }
return 0;
}
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 83a66b8..6c5dd2e 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -120,7 +120,7 @@ static int proc_lookupbase(struct inode * dir,const char * name, int len,
iput(dir);
return -ENOENT;
}
- if (!(*result = iget(dir->i_dev,ino))) {
+ if (!(*result = iget(dir->i_sb,ino))) {
iput(dir);
return -ENOENT;
}
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index 9ddf1d7..5aa841e 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -53,7 +53,8 @@ static int proc_lookupfd(struct inode * dir,const char * name, int len,
{
unsigned int ino, pid, fd, c;
struct task_struct * p;
- int i, dev;
+ struct super_block * sb;
+ int i;
*result = NULL;
ino = dir->i_ino;
@@ -62,6 +63,7 @@ static int proc_lookupfd(struct inode * dir,const char * name, int len,
ino -= 7;
if (!dir)
return -ENOENT;
+ sb = dir->i_sb;
if (!pid || ino > 1 || !S_ISDIR(dir->i_mode)) {
iput(dir);
return -ENOENT;
@@ -72,14 +74,13 @@ static int proc_lookupfd(struct inode * dir,const char * name, int len,
*result = dir;
return 0;
}
- if (!(*result = iget(dir->i_dev,(pid << 16)+2))) {
+ if (!(*result = iget(sb,(pid << 16)+2))) {
iput(dir);
return -ENOENT;
}
iput(dir);
return 0;
}
- dev = dir->i_dev;
iput(dir);
fd = 0;
while (len-- > 0) {
@@ -110,7 +111,7 @@ static int proc_lookupfd(struct inode * dir,const char * name, int len,
return -ENOENT;
ino = (pid << 16) + 0x200 + fd;
}
- if (!(*result = iget(dev,ino)))
+ if (!(*result = iget(sb,ino)))
return -ENOENT;
return 0;
}
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index c79d8dd..e4303b4 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -10,12 +10,15 @@
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
+#include <linux/locks.h>
#include <asm/system.h>
#include <asm/segment.h>
void proc_put_inode(struct inode *inode)
{
+ if (inode->i_nlink)
+ return;
inode->i_size = 0;
}
@@ -23,7 +26,7 @@ void proc_put_super(struct super_block *sb)
{
lock_super(sb);
sb->s_dev = 0;
- free_super(sb);
+ unlock_super(sb);
}
static struct super_operations proc_sops = {
@@ -37,16 +40,13 @@ static struct super_operations proc_sops = {
struct super_block *proc_read_super(struct super_block *s,void *data)
{
- int dev=s->s_dev;
-
lock_super(s);
s->s_blocksize = 1024;
s->s_magic = PROC_SUPER_MAGIC;
- s->s_dev = dev;
s->s_op = &proc_sops;
- free_super(s);
- if (!(s->s_mounted = iget(dev,PROC_ROOT_INO))) {
- s->s_dev=0;
+ unlock_super(s);
+ if (!(s->s_mounted = iget(s,PROC_ROOT_INO))) {
+ s->s_dev = 0;
printk("get root inode failed\n");
return NULL;
}
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 848c97b..78b5360 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -89,7 +89,7 @@ static int proc_lookuproot(struct inode * dir,const char * name, int len,
return -ENOENT;
}
ino = (pid << 16) + 2;
- if (!(*result = iget(dir->i_dev,ino))) {
+ if (!(*result = iget(dir->i_sb,ino))) {
iput(dir);
return -ENOENT;
}
diff --git a/fs/super.c b/fs/super.c
index 7c7cd16..1062eed 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -16,11 +16,11 @@
#include <linux/kernel.h>
#include <linux/stat.h>
#include <linux/errno.h>
+#include <linux/locks.h>
#include <asm/system.h>
#include <asm/segment.h>
-int sync_dev(int dev);
void wait_for_keypress(void);
void fcntl_init_locks(void);
@@ -32,7 +32,7 @@ __res; })
struct super_block super_block[NR_SUPER];
/* this is initialized in init/main.c */
-int ROOT_DEV = 0;
+dev_t ROOT_DEV = 0;
/* Move into include file later */
@@ -56,30 +56,37 @@ struct file_system_type *get_fs_type(char *name)
return(NULL);
}
-void lock_super(struct super_block * sb)
+void __wait_on_super(struct super_block * sb)
{
- cli();
- while (sb->s_lock)
- sleep_on(&(sb->s_wait));
- sb->s_lock = 1;
- sti();
+ add_wait_queue(&sb->s_wait,&current->wait);
+repeat:
+ current->state = TASK_UNINTERRUPTIBLE;
+ if (sb->s_lock) {
+ schedule();
+ goto repeat;
+ }
+ remove_wait_queue(&sb->s_wait,&current->wait);
+ current->state = TASK_RUNNING;
}
-void free_super(struct super_block * sb)
+void sync_supers(dev_t dev)
{
- sb->s_lock = 0;
- wake_up(&(sb->s_wait));
-}
+ struct super_block * sb;
-void wait_on_super(struct super_block * sb)
-{
- cli();
- while (sb->s_lock)
- sleep_on(&(sb->s_wait));
- sti();
+ for (sb = super_block + 0 ; sb < super_block + NR_SUPER ; sb++) {
+ if (!sb->s_dev)
+ continue;
+ wait_on_super(sb);
+ if (!sb->s_dev || !sb->s_dirt)
+ continue;
+ if (dev && (dev != sb->s_dev))
+ continue;
+ if (sb->s_op && sb->s_op->write_super)
+ sb->s_op->write_super(sb);
+ }
}
-struct super_block * get_super(int dev)
+static struct super_block * get_super(dev_t dev)
{
struct super_block * s;
@@ -97,7 +104,7 @@ struct super_block * get_super(int dev)
return NULL;
}
-void put_super(int dev)
+void put_super(dev_t dev)
{
struct super_block * sb;
@@ -115,7 +122,7 @@ void put_super(int dev)
sb->s_op->put_super(sb);
}
-static struct super_block * read_super(int dev,char *name,int flags,void *data)
+static struct super_block * read_super(dev_t dev,char *name,int flags,void *data)
{
struct super_block * s;
struct file_system_type *type;
@@ -148,10 +155,9 @@ static struct super_block * read_super(int dev,char *name,int flags,void *data)
return s;
}
-static int do_umount(int dev)
+static int do_umount(dev_t dev)
{
struct super_block * sb;
- struct inode * inode;
if (dev==ROOT_DEV)
return -EBUSY;
@@ -159,12 +165,8 @@ static int do_umount(int dev)
return -ENOENT;
if (!sb->s_covered->i_mount)
printk("Mounted inode has i_mount=0\n");
- for (inode = inode_table+0 ; inode < inode_table+NR_INODE ; inode++)
- if (inode->i_dev==dev && inode->i_count)
- if (inode == sb->s_mounted && inode->i_count == 1)
- continue;
- else
- return -EBUSY;
+ if (!fs_may_umount(dev, sb->s_mounted))
+ return -EBUSY;
sb->s_covered->i_mount=0;
iput(sb->s_covered);
sb->s_covered = NULL;
@@ -172,7 +174,7 @@ static int do_umount(int dev)
sb->s_mounted = NULL;
if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
sb->s_op->write_super (sb);
- put_super(dev);
+ put_super(dev);
return 0;
}
@@ -191,13 +193,21 @@ int sys_umount(char * dev_name)
iput(inode);
return -ENOTBLK;
}
+ if (IS_NODEV(inode)) {
+ iput(inode);
+ return -EACCES;
+ }
+ if (MAJOR(dev) >= MAX_BLKDEV) {
+ iput(inode);
+ return -ENODEV;
+ }
retval = do_umount(dev);
- if (!retval && MAJOR(dev) < MAX_BLKDEV &&
- blkdev_fops[MAJOR(dev)]->release)
+ if (!retval && blkdev_fops[MAJOR(dev)] && blkdev_fops[MAJOR(dev)]->release)
blkdev_fops[MAJOR(dev)]->release(inode,NULL);
iput(inode);
- if (retval) return retval;
- sync_dev(dev);
+ if (retval)
+ return retval;
+ sync_dev(dev);
return 0;
}
@@ -210,9 +220,9 @@ int sys_umount(char * dev_name)
* We also have to flush all inode-data for this device, as the new mount
* might need new info.
*/
-static int do_mount(int dev, const char * dir, char * type, int flags, void * data)
+static int do_mount(dev_t dev, const char * dir, char * type, int flags, void * data)
{
- struct inode * inode, * dir_i;
+ struct inode * dir_i;
struct super_block * sb;
int error;
@@ -227,14 +237,9 @@ static int do_mount(int dev, const char * dir, char * type, int flags, void * da
iput(dir_i);
return -EPERM;
}
- for (inode = inode_table+0 ; inode < inode_table+NR_INODE ; inode++) {
- if (inode->i_dev != dev)
- continue;
- if (inode->i_count || inode->i_dirt || inode->i_lock) {
- iput(dir_i);
- return -EBUSY;
- }
- inode->i_dev = 0;
+ if (!fs_may_mount(dev)) {
+ iput(dir_i);
+ return -EBUSY;
}
sb = read_super(dev,type,flags,data);
if (!sb || sb->s_covered) {
@@ -263,6 +268,7 @@ int sys_mount(char * dev_name, char * dir_name, char * type,
unsigned long new_flags, void *data)
{
struct inode * inode;
+ struct file_operations * fops;
int dev;
int retval;
char tmp[100],*t;
@@ -272,19 +278,27 @@ int sys_mount(char * dev_name, char * dir_name, char * type,
if (!suser())
return -EPERM;
- retval = namei(dev_name,&inode);
- if (retval)
+ if (retval = namei(dev_name,&inode))
return retval;
dev = inode->i_rdev;
- if (!S_ISBLK(inode->i_mode))
- retval = -EPERM;
- else if (IS_NODEV(inode))
- retval = -EACCES;
- if (!retval && blkdev_fops[MAJOR(dev)]->open)
- retval = blkdev_fops[MAJOR(dev)]->open(inode,NULL);
- if (retval) {
+ if (!S_ISBLK(inode->i_mode)) {
iput(inode);
- return retval;
+ return -ENOTBLK;
+ }
+ if (IS_NODEV(inode)) {
+ iput(inode);
+ return -EACCES;
+ }
+ if (MAJOR(dev) >= MAX_BLKDEV) {
+ iput(inode);
+ return -ENODEV;
+ }
+ fops = blkdev_fops[MAJOR(dev)];
+ if (fops && fops->open) {
+ if (retval = fops->open(inode,NULL)) {
+ iput(inode);
+ return retval;
+ }
}
if ((new_flags & 0xffff0000) == 0xC0ED0000) {
flags = new_flags & 0xffff;
@@ -306,8 +320,8 @@ int sys_mount(char * dev_name, char * dir_name, char * type,
t = "minix";
retval = do_mount(dev,dir_name,t,flags,(void *) page);
free_page(page);
- if (retval && blkdev_fops[MAJOR(dev)]->release)
- blkdev_fops[MAJOR(dev)]->release(inode,NULL);
+ if (retval && fops && fops->release)
+ fops->release(inode,NULL);
iput(inode);
return retval;
}
diff --git a/include/asm/dma.h b/include/asm/dma.h
new file mode 100644
index 0000000..9ba767f
--- /dev/null
+++ b/include/asm/dma.h
@@ -0,0 +1,192 @@
+/* $Header: /sys/linux-0.97/include/asm/RCS/dma.h,v 1.4 1992/09/21 03:15:46 root Exp root $
+ * linux/include/asm/dma.h: Defines for using and allocating dma channels.
+ * Written by Hennus Bergman, 1992.
+ */
+
+#ifndef _ASM_DMA_H
+#define _ASM_DMA_H
+
+#include <asm/io.h> /* need byte IO */
+#include <linux/kernel.h> /* need panic() [FIXME] */
+
+
+#ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
+#define outb outb_p
+#endif
+
+/* FIXME: better fix this code for dma channels>3!!!!!!! */
+
+/*
+ * The routines below should in most cases (with optimizing on) result
+ * in equal or better code than similar code using macros.
+ *
+ * NOTE about DMA transfers: The DMA controller cannot handle transfers
+ * that cross a 64k boundary. When the address reaches 0xNffff, it will wrap
+ * around to 0xN0000, rather than increment to 0x(N+1)0000 !
+ * Make sure you align your buffers properly! Runtime check recommended.
+ *
+ * NOTE2: DMA1..3 can only use the lower 1MB of physical memory. DMA4..7
+ * can access the lower 16MB. There are people with >16MB, so beware!
+ */
+
+
+#define MAX_DMA_CHANNELS 8
+
+/* SOMEBODY should check the following:
+ * Channels 0..3 are on the first DMA controller, channels 4..7 are
+ * on the second. Channel 0 is for refresh, 4 is for cascading.
+ * The first DMA controller uses bytes, the second words.
+ *
+ * Where are the page regs for the second DMA controller?????
+ */
+
+
+/* 8237 DMA controllers */
+#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */
+#define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */
+
+/* DMA controller registers */
+#define DMA1_CMD_REG 0x08 /* DMA command register */
+#define DMA1_STAT_REG 0x08 /* DMA status register */
+#define DMA1_MASK_REG 0x0A /* mask individual channels */
+#define DMA1_MODE_REG 0x0B /* set modes for individual channels */
+#define DMA1_CLEAR_FF_REG 0x0C /* Write 0 for LSB, 1 for MSB */
+#define DMA1_RESET_REG 0x0D /* Write here to reset DMA controller */
+/* don't have much info on the second DMA controller... */
+#define DMA2_MASK_REG 0xD4
+#define DMA2_MODE_REG 0xD6
+/* #define DMA2_CLEAR_FF_REG 0xD8 -- pure guessing.... */
+
+/************* #error This needs more work!!!!!!!*************/
+
+#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */
+#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */
+#define DMA_MODE_CASCADE 0xC0 /* cascade mode (for DMA2 controller only) */
+
+
+/* enable/disable a specific DMA channel */
+static __inline__ void enable_dma(unsigned int dmanr)
+{
+ if (dmanr<=3)
+ outb(dmanr, DMA1_MASK_REG);
+ else
+ outb(dmanr & 3, DMA2_MASK_REG);
+}
+
+static __inline__ void disable_dma(unsigned int dmanr)
+{
+ if (dmanr<=3)
+ outb(dmanr | 4, DMA1_MASK_REG);
+ else
+ outb((dmanr & 3) | 4, DMA2_MASK_REG);
+}
+
+/* Clear the 'DMA Pointer Flip Flop'.
+ * Write 0 for LSB/MSB, 1 for MSB/LSB access.
+ * Use this once to initialize the FF to a know state.
+ * After that, keep track of it. :-) In order to do that,
+ * dma_set_addr() and dma_set_count() should only be used wile
+ * interrupts are disbled.
+ */
+static __inline__ void clear_dma_ff(unsigned int dmanr)
+{
+ if (dmanr<=3)
+ outb(0, DMA1_CLEAR_FF_REG);
+ else
+#ifdef DMA2_CLEAR_FF_REG
+ outb(0, DMA2_CLEAR_FF_REG);
+#else
+ panic("dma.h: Don't have CLEAR_FF for high dma channels!\n");
+#endif
+}
+
+/* set mode (above) for a specific DMA channel */
+static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
+{
+ if (dmanr<=3)
+ outb(mode | dmanr, DMA1_MODE_REG);
+ else
+ outb(DMA_MODE_CASCADE | mode | (dmanr&3), DMA2_MODE_REG);
+}
+
+/* Set only the page register bits of the transfer address.
+ * This is used for successive transfers when we know the contents of
+ * the lower 16 bits of the DMA current address register, but a 64k boundary
+ * may have been crossed.
+ */
+static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
+{
+ switch(dmanr) {
+ case 0:
+ outb(pagenr, 0x80);
+ break;
+ case 1:
+ outb(pagenr, 0x83);
+ break;
+ case 2:
+ outb(pagenr, 0x81);
+ break;
+ case 3:
+ outb(pagenr, 0x82);
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ panic("dma.h: don't know how to set DMA page regs for channels>3");
+ break;
+ }
+}
+
+
+/* Set transfer address & page bits for specific DMA channel.
+ * Assumes dma flipflop is clear.
+ */
+static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
+{
+ unsigned int io_base = (dmanr<=3)? IO_DMA1_BASE : IO_DMA2_BASE;
+
+ set_dma_page(dmanr, a>>16);
+ outb(a & 0xff, ((dmanr&3)<<1) + io_base);
+ outb((a>>8) & 0xff, ((dmanr&3)<<1) + io_base);
+}
+
+
+/* Set transfer size (max 64k) for a specific DMA channel.
+ * You must ensure the parameters are valid.
+ * NOTE: from a manual: "the number of transfers is one more
+ * than the initial word count"! This is taken into account.
+ * Assumes dma flip-flop is clear.
+ */
+static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
+{
+ unsigned int dc = count - 1;
+ unsigned int io_base = (dmanr<=3)? IO_DMA1_BASE : IO_DMA2_BASE;
+
+ outb(dc & 0xff, ((dmanr&3)<<1) + 1 + io_base);
+ outb((dc>>8) & 0xff, ((dmanr&3)<<1) + 1 + io_base);
+}
+
+
+/* Get DMA residue count. After a DMA transfer, this
+ * should return zero. Reading this while a DMA transfer is
+ * still in progress will return unpredictable results.
+ * If called before the channel has been used, it may return 1.
+ * Otherwise, it returns the number of bytes left to transfer,
+ * minus 1, modulo 64k.
+ * Assumes DMA flip-flop is clear.
+ */
+static __inline__ short int get_dma_residue(unsigned int dmanr)
+{
+ unsigned int io_base = (dmanr<=3)? IO_DMA1_BASE : IO_DMA2_BASE;
+
+ return 1 + inb( ((dmanr&3)<<1) + 1 + io_base ) +
+ ( inb( ((dmanr&3)<<1) + 1 + io_base ) << 8 );
+}
+
+/* These are in kernel/dma.c: */
+extern int request_dma(unsigned int dmanr); /* reserve a DMA channel */
+extern void free_dma(unsigned int dmanr); /* release it again */
+
+
+#endif /* _ASM_DMA_H */
diff --git a/include/asm/segment.h b/include/asm/segment.h
index b354a8a..49fda90 100644
--- a/include/asm/segment.h
+++ b/include/asm/segment.h
@@ -37,7 +37,7 @@ extern inline void put_fs_long(unsigned long val,unsigned long * addr)
__asm__ ("movl %0,%%fs:%1"::"r" (val),"m" (*addr));
}
-extern inline void memcpy_tofs(void * to, void * from, unsigned long n)
+extern inline void memcpy_tofs(void * to, const void * from, unsigned long n)
{
__asm__("cld\n\t"
"push %%es\n\t"
@@ -56,7 +56,7 @@ __asm__("cld\n\t"
:"cx","di","si");
}
-extern inline void memcpy_fromfs(void * to, void * from, unsigned long n)
+extern inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
{
__asm__("cld\n\t"
"testb $1,%%cl\n\t"
diff --git a/include/linux/config.h b/include/linux/config.h
index abfbf7e..4fe72bc 100644
--- a/include/linux/config.h
+++ b/include/linux/config.h
@@ -24,6 +24,11 @@
#define DEF_SETUPSEG 0x9020
#define DEF_SYSSIZE 0x7000
+/* internal svga startup constants */
+#define NORMAL_VGA 0xffff /* 80x25 mode */
+#define EXTENDED_VGA 0xfffe /* 80x50 mode */
+#define ASK_VGA 0xfffd /* ask for it at bootup */
+
/*
* The root-device is no longer hard-coded. You can change the default
* root-device by changing the line ROOT_DEV = XXX in boot/bootsect.s
diff --git a/include/linux/ext_fs.h b/include/linux/ext_fs.h
index 7e6e3aa..9e16cba 100644
--- a/include/linux/ext_fs.h
+++ b/include/linux/ext_fs.h
@@ -74,11 +74,11 @@ extern int ext_link(struct inode * oldinode, struct inode * dir, const char * na
extern int ext_mknod(struct inode * dir, const char * name, int len, int mode, int rdev);
extern int ext_rename(struct inode * old_dir, const char * old_name, int old_len,
struct inode * new_dir, const char * new_name, int new_len);
-extern struct inode * ext_new_inode(int dev);
+extern struct inode * ext_new_inode(struct super_block * sb);
extern void ext_free_inode(struct inode * inode);
extern unsigned long ext_count_free_inodes(struct super_block *sb);
-extern int ext_new_block(int dev);
-extern void ext_free_block(int dev, int block);
+extern int ext_new_block(struct super_block * sb);
+extern void ext_free_block(struct super_block * sb, int block);
extern unsigned long ext_count_free_blocks(struct super_block *sb);
extern int ext_bmap(struct inode *,int);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 0aeed9b..87b76d7 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -39,6 +39,7 @@
#define WRITEA 3 /* "write-ahead" - silly, but somewhat useful */
extern void buffer_init(void);
+extern void inode_init(void);
#define MAJOR(a) (((unsigned)(a))>>8)
#define MINOR(a) ((a)&0xff)
@@ -90,7 +91,7 @@ struct buffer_head {
char * b_data; /* pointer to data block (1024 bytes) */
unsigned long b_size; /* block size */
unsigned long b_blocknr; /* block number */
- unsigned short b_dev; /* device (0 = free) */
+ dev_t b_dev; /* device (0 = free) */
unsigned short b_count; /* users using this block */
unsigned char b_uptodate;
unsigned char b_dirt; /* 0-clean,1-dirty */
@@ -145,14 +146,14 @@ struct inode {
};
struct file {
- unsigned short f_mode;
+ mode_t f_mode;
+ dev_t f_rdev; /* needed for /dev/tty */
+ off_t f_pos;
unsigned short f_flags;
unsigned short f_count;
unsigned short f_reada;
- unsigned short f_rdev; /* needed for /dev/tty */
struct inode * f_inode;
struct file_operations * f_op;
- off_t f_pos;
};
struct file_lock {
@@ -170,7 +171,7 @@ struct file_lock {
#include <linux/msdos_fs_sb.h>
struct super_block {
- unsigned short s_dev;
+ dev_t s_dev;
unsigned long s_blocksize;
unsigned char s_lock;
unsigned char s_rd_only;
@@ -237,7 +238,9 @@ extern struct file_operations * blkdev_fops[MAX_BLKDEV];
extern struct file_system_type *get_fs_type(char *name);
-extern struct inode inode_table[NR_INODE];
+extern int fs_may_mount(dev_t dev);
+extern int fs_may_umount(dev_t dev, struct inode * mount_root);
+
extern struct file file_table[NR_FILE];
extern struct super_block super_block[NR_SUPER];
@@ -247,44 +250,41 @@ extern int shrink_buffers(unsigned int priority);
extern int nr_buffers;
extern int nr_buffer_heads;
-extern void check_disk_change(int dev);
-extern void invalidate_inodes(int dev);
-extern void invalidate_buffers(int dev);
+extern void check_disk_change(dev_t dev);
+extern void invalidate_inodes(dev_t dev);
+extern void invalidate_buffers(dev_t dev);
extern int floppy_change(struct buffer_head * first_block);
extern int ticks_to_floppy_on(unsigned int dev);
extern void floppy_on(unsigned int dev);
extern void floppy_off(unsigned int dev);
-extern void sync_inodes(void);
-extern void wait_on(struct inode * inode);
+extern void sync_inodes(dev_t dev);
+extern void sync_dev(dev_t dev);
+extern void sync_supers(dev_t dev);
extern int bmap(struct inode * inode,int block);
extern int namei(const char * pathname, struct inode ** res_inode);
extern int lnamei(const char * pathname, struct inode ** res_inode);
extern int permission(struct inode * inode,int mask);
extern int open_namei(const char * pathname, int flag, int mode,
struct inode ** res_inode, struct inode * base);
-extern int do_mknod(const char * filename, int mode, int dev);
+extern int do_mknod(const char * filename, int mode, dev_t dev);
extern void iput(struct inode * inode);
-extern struct inode * iget(int dev,int nr);
+extern struct inode * iget(struct super_block * sb,int nr);
extern struct inode * get_empty_inode(void);
extern struct inode * get_pipe_inode(void);
extern struct file * get_empty_filp(void);
-extern struct buffer_head * get_hash_table(int dev, int block, int size);
-extern struct buffer_head * getblk(int dev, int block, int size);
+extern struct buffer_head * get_hash_table(dev_t dev, int block, int size);
+extern struct buffer_head * getblk(dev_t dev, int block, int size);
extern void ll_rw_block(int rw, struct buffer_head * bh);
extern void ll_rw_page(int rw, int dev, int nr, char * buffer);
extern void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buffer);
extern void brelse(struct buffer_head * buf);
-extern struct buffer_head * bread(int dev, int block, int size);
-extern void bread_page(unsigned long addr,int dev,int b[4]);
-extern struct buffer_head * breada(int dev,int block,...);
-extern int sync_dev(int dev);
-extern struct super_block * get_super(int dev);
-extern void put_super(int dev);
-extern int ROOT_DEV;
+extern struct buffer_head * bread(dev_t dev, int block, int size);
+extern void bread_page(unsigned long addr,dev_t dev,int b[4]);
+extern struct buffer_head * breada(dev_t dev,int block,...);
+extern void put_super(dev_t dev);
+extern dev_t ROOT_DEV;
extern void mount_root(void);
-extern void lock_super(struct super_block * sb);
-extern void free_super(struct super_block * sb);
extern int char_read(struct inode *, struct file *, char *, int);
extern int block_read(struct inode *, struct file *, char *, int);
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index cf77d54..a4ac54f 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -8,6 +8,7 @@
void verify_area(void * addr,int count);
volatile void panic(const char * str);
volatile void do_exit(long error_code);
+unsigned long simple_strtoul(const char *,char **,unsigned int);
int printk(const char * fmt, ...);
void * malloc(unsigned int size);
void free_s(void * obj, int size);
diff --git a/include/linux/locks.h b/include/linux/locks.h
new file mode 100644
index 0000000..ac9b290
--- /dev/null
+++ b/include/linux/locks.h
@@ -0,0 +1,56 @@
+#ifndef _LINUX_LOCKS_H
+#define _LINUX_LOCKS_H
+
+/*
+ * Buffer cache locking - note that interrupts may only unlock, not
+ * lock buffers.
+ */
+extern void __wait_on_buffer(struct buffer_head *);
+
+extern inline void wait_on_buffer(struct buffer_head * bh)
+{
+ if (bh->b_lock)
+ __wait_on_buffer(bh);
+}
+
+extern inline void lock_buffer(struct buffer_head * bh)
+{
+ if (bh->b_lock)
+ __wait_on_buffer(bh);
+ bh->b_lock = 1;
+}
+
+extern inline void unlock_buffer(struct buffer_head * bh)
+{
+ bh->b_lock = 0;
+ wake_up(&bh->b_wait);
+}
+
+/*
+ * super-block locking. Again, interrupts may only unlock
+ * a super-block (although even this isn't done right now.
+ * nfs may need it).
+ */
+extern void __wait_on_super(struct super_block *);
+
+extern inline void wait_on_super(struct super_block * sb)
+{
+ if (sb->s_lock)
+ __wait_on_super(sb);
+}
+
+extern inline void lock_super(struct super_block * sb)
+{
+ if (sb->s_lock)
+ __wait_on_super(sb);
+ sb->s_lock = 1;
+}
+
+extern inline void unlock_super(struct super_block * sb)
+{
+ sb->s_lock = 0;
+ wake_up(&sb->s_wait);
+}
+
+#endif /* _LINUX_LOCKS_H */
+
diff --git a/include/linux/lp.h b/include/linux/lp.h
index 2fef688..d0d1607 100644
--- a/include/linux/lp.h
+++ b/include/linux/lp.h
@@ -1,10 +1,6 @@
#ifndef _LINUX_LP_H
#define _LINUX_LP_H
-/*
-$Header: /usr/src/linux/include/linux/lp.h,v 1.2 1992/01/21 23:59:24 james_r_wiegand Exp james_r_wiegand $
-*/
-
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -14,15 +10,19 @@ $Header: /usr/src/linux/include/linux/lp.h,v 1.2 1992/01/21 23:59:24 james_r_wie
/*
* usr/include/linux/lp.h c.1991-1992 James Wiegand
+ * many modifications copyright (C) 1992 Michael K. Johnson
*/
/*
* caveat: my machine only has 1 printer @ lpt2 so lpt1 & lpt3 are
* implemented but UNTESTED
+ *
+ * My machine (Michael K. Johnson) has only lpt1... dupla caveat...
*/
/*
* Per POSIX guidelines, this module reserves the LP and lp prefixes
+ * These are the lp_table[minor].flags flags...
*/
#define LP_EXIST 0x0001
#define LP_SELEC 0x0002
@@ -31,11 +31,27 @@ $Header: /usr/src/linux/include/linux/lp.h,v 1.2 1992/01/21 23:59:24 james_r_wie
#define LP_NOPA 0x0010
#define LP_ERR 0x0020
-#define LP_TIMEOUT 200000
-
-#define LP_B(minor) lp_table[(minor)].base
-#define LP_F(minor) lp_table[(minor)].flags
-#define LP_S(minor) inb(LP_B((minor)) + 1)
+/* timeout for each character (This is a good case 50 Mhz computer
+ at a poor case 10 KBS xfer rate to the printer, as best as I can
+ tell.) This is in instruction cycles, kinda -- it is the count
+ in a busy loop. THIS IS THE VALUE TO CHANGE if you have extremely
+ slow printing, or if the machine seems to slow down a lot when you
+ print. If you have slow printing, increase this number and recompile,
+ and if your system gets bogged down, decrease this number.*/
+#define LP_TIME_CHAR 5000
+
+/* timeout for printk'ing a timeout, in jiffies (100ths of a second).
+ If your printer isn't printing at least one character every five seconds,
+ you have worse problems than a slow printer driver and lp_timeout printed
+ every five seconds while trying to print. */
+#define LP_TIMEOUT 5000
+
+#define LP_B(minor) lp_table[(minor)].base /* IO address */
+#define LP_F(minor) lp_table[(minor)].flags /* flags for busy, etc. */
+#define LP_S(minor) inb(LP_B((minor)) + 1) /* status port */
+#define LP_C(minor) (lp_table[(minor)].base + 2) /* control port */
+#define LP_COUNT(minor) lp_table[(minor)].count /* last count */
+#define LP_TIME(minor) lp_table[(minor)].time /* last time */
/*
since we are dealing with a horribly slow device
@@ -44,39 +60,57 @@ I don't see the need for a queue
struct lp_struct {
int base;
int flags;
+ int count;
+ int time;
};
-/*
- * the BIOS manuals say there can be up to 4 lpt devices
+/* This is the starting value for the heuristic algorithm. If you
+ * want to tune this and have a fast printer (i.e. HPIIIP), decrease
+ * this number, and if you have a slow printer, increase this number.
+ * This is not stricly necessary, as the algorithm should be able to
+ * adapt to your printer relatively quickly.
+ * this is in hundredths of a second, the default 50 being .5 seconds.
+ */
+
+#define LP_INIT_TIME 50
+
+/* This is our first guess at the size of the buffer on the printer,
+ * in characters. I am assuming a 4K buffer because most newer printers
+ * have larger ones, which will be adapted to. At this time, it really
+ * doesn't matter, as this value isn't used.
+ */
+
+#define LP_INIT_COUNT 4096
+
+/* the BIOS manuals say there can be up to 4 lpt devices
* but I have not seen a board where the 4th address is listed
* if you have different hardware change the table below
* please let me know if you have different equipment
* if you have more than 3 printers, remember to increase LP_NO
*/
struct lp_struct lp_table[] = {
- { 0x3bc, 0, },
- { 0x378, 0, },
- { 0x278, 0, }
+ { 0x3bc, 0, LP_INIT_COUNT, LP_INIT_TIME, },
+ { 0x378, 0, LP_INIT_COUNT, LP_INIT_TIME, },
+ { 0x278, 0, LP_INIT_COUNT, LP_INIT_TIME, }
};
-
#define LP_NO 3
/*
* bit defines for 8255 status port
* base + 1
+ * accessed with LP_S(minor), which gets the byte...
*/
#define LP_PBUSY 0x80 /* active low */
#define LP_PACK 0x40 /* active low */
#define LP_POUTPA 0x20
#define LP_PSELECD 0x10
-#define LP_PERRORP 0x08 /*å active low*/
-#define LP_PIRQ 0x04 /* active low */
+#define LP_PERRORP 0x08 /* active low*/
/*
* defines for 8255 control port
* base + 2
+ * accessed with LP_C(minor)
*/
-#define LP_PIRQEN 0x10
#define LP_PSELECP 0x08
#define LP_PINITP 0x04 /* active low */
#define LP_PAUTOLF 0x02
@@ -90,7 +124,8 @@ struct lp_struct lp_table[] = {
#define LP_DUMMY 0x00
/*
- * this is the port delay time. your mileage may vary
+ * This is the port delay time. Your mileage may vary.
+ * It is used only in the lp_init() routine.
*/
#define LP_DELAY 150000
diff --git a/include/linux/minix_fs.h b/include/linux/minix_fs.h
index a4ce2e4..c709962 100644
--- a/include/linux/minix_fs.h
+++ b/include/linux/minix_fs.h
@@ -57,11 +57,11 @@ extern int minix_link(struct inode * oldinode, struct inode * dir, const char *
extern int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev);
extern int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
struct inode * new_dir, const char * new_name, int new_len);
-extern struct inode * minix_new_inode(int dev);
+extern struct inode * minix_new_inode(struct super_block * sb);
extern void minix_free_inode(struct inode * inode);
extern unsigned long minix_count_free_inodes(struct super_block *sb);
-extern int minix_new_block(int dev);
-extern void minix_free_block(int dev, int block);
+extern int minix_new_block(struct super_block * sb);
+extern void minix_free_block(struct super_block * sb, int block);
extern unsigned long minix_count_free_blocks(struct super_block *sb);
extern int minix_bmap(struct inode *,int);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index a0954f1..5058896 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -336,18 +336,31 @@ __asm__("movw %%dx,%0\n\t" \
#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , base )
#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , (limit-1)>>12 )
+/*
+ * The wait-queues are circular lists, and you have to be *very* sure
+ * to keep them correct. Use only these two functions to add/remove
+ * entries in the queues.
+ */
extern inline void add_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
{
unsigned long flags;
- struct wait_queue * tmp;
+#ifdef DEBUG
+ if (wait->next) {
+ unsigned long pc;
+ __asm__ __volatile__("call 1f\n"
+ "1:\tpopl %0":"=r" (pc));
+ printk("add_wait_queue (%08x): wait->next = %08x\n",pc,wait->next);
+ }
+#endif
__asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
- wait->next = *p;
- tmp = wait;
- while (tmp->next)
- if ((tmp = tmp->next)->next == *p)
- break;
- *p = tmp->next = wait;
+ if (!*p) {
+ wait->next = wait;
+ *p = wait;
+ } else {
+ wait->next = (*p)->next;
+ (*p)->next = wait;
+ }
__asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
}
@@ -357,14 +370,14 @@ extern inline void remove_wait_queue(struct wait_queue ** p, struct wait_queue *
struct wait_queue * tmp;
__asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
- if (*p == wait)
- if ((*p = wait->next) == wait)
- *p = NULL;
- tmp = wait;
- while (tmp && tmp->next != wait)
- tmp = tmp->next;
- if (tmp)
+ if ((*p == wait) && ((*p = wait->next) == wait)) {
+ *p = NULL;
+ } else {
+ tmp = wait;
+ while (tmp->next != wait)
+ tmp = tmp->next;
tmp->next = wait->next;
+ }
wait->next = NULL;
__asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
}
@@ -377,6 +390,7 @@ extern inline void select_wait(struct wait_queue ** wait_address, select_table *
return;
entry->wait_address = wait_address;
entry->wait.task = current;
+ entry->wait.next = NULL;
add_wait_queue(wait_address,&entry->wait);
p->nr++;
}
diff --git a/include/linux/string.h b/include/linux/string.h
index cdff971..369fb41 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -1,6 +1,8 @@
#ifndef _LINUX_STRING_H_
#define _LINUX_STRING_H_
+#include <linux/types.h> /* for size_t */
+
#ifndef NULL
#define NULL ((void *) 0)
#endif
@@ -326,14 +328,22 @@ __asm__("testl %1,%1\n\t"
return __res;
}
-extern inline void * memcpy(void * dest,const void * src, size_t n)
+extern inline void * memcpy(void * to, const void * from, size_t n)
{
__asm__("cld\n\t"
- "rep\n\t"
- "movsb"
- ::"c" (n),"S" (src),"D" (dest)
- :"cx","si","di");
-return dest;
+ "movl %%edx, %%ecx\n\t"
+ "shrl $2,%%ecx\n\t"
+ "rep ; movsl\n\t"
+ "testb $1,%%dl\n\t"
+ "je 1f\n\t"
+ "movsb\n"
+ "1:\ttestb $2,%%dl\n\t"
+ "je 2f\n\t"
+ "movsw\n"
+ "2:\n"
+ ::"d" (n),"D" ((long) to),"S" ((long) from)
+ : "cx","di","si");
+return (to);
}
extern inline void * memmove(void * dest,const void * src, size_t n)
diff --git a/init/main.c b/init/main.c
index 9736e8d..f321081 100644
--- a/init/main.c
+++ b/init/main.c
@@ -17,6 +17,7 @@
#include <linux/tty.h>
#include <linux/head.h>
#include <linux/unistd.h>
+#include <linux/string.h>
extern unsigned long * prof_buffer;
extern unsigned long prof_len;
@@ -64,22 +65,13 @@ extern void floppy_init(void);
extern void sock_init(void);
extern long rd_init(long mem_start, int length);
extern long kernel_mktime(struct mktime * time);
+extern unsigned long simple_strtoul(const char *cp,char **endp,unsigned int
+ base);
#ifdef CONFIG_SCSI
-extern void scsi_dev_init(void);
+extern unsigned long scsi_dev_init(unsigned long, unsigned long);
#endif
-static int sprintf(char * str, const char *fmt, ...)
-{
- va_list args;
- int i;
-
- va_start(args, fmt);
- i = vsprintf(str, fmt, args);
- va_end(args);
- return i;
-}
-
/*
* This is set up by the setup-routine at boot-time
*/
@@ -90,6 +82,16 @@ static int sprintf(char * str, const char *fmt, ...)
#define AUX_DEVICE_INFO (*(unsigned char *)0x901FF)
/*
+ * Boot command-line arguments
+ */
+#define MAX_INIT_ARGS 8
+#define MAX_INIT_ENVS 8
+#define CL_MAGIC_ADDR (*(unsigned short *) 0x90020)
+#define CL_MAGIC 0xa33f
+#define CL_BASE_ADDR ((char *) 0x90000)
+#define CL_OFFSET (*(unsigned short *) 0x90022)
+
+/*
* Yeah, yeah, it's ugly, but I cannot find how to do this correctly
* and this seems to work. I anybody has more info on the real-time
* clock I'd be interested. Most of this was trial and error, and some
@@ -130,22 +132,71 @@ static unsigned long memory_start = 0; /* After mem_init, stores the */
static unsigned long memory_end = 0;
static unsigned long low_memory_start = 0;
-static char term[32];
-
-static char * argv_init[] = { "/bin/init", NULL };
-static char * envp_init[] = { "HOME=/", NULL, NULL };
+static char * argv_init[MAX_INIT_ARGS+2] = { "/bin/init", NULL, };
+static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=console", NULL, };
static char * argv_rc[] = { "/bin/sh", NULL };
-static char * envp_rc[] = { "HOME=/", NULL ,NULL };
+static char * envp_rc[] = { "HOME=/", "TERM=console", NULL };
static char * argv[] = { "-/bin/sh",NULL };
-static char * envp[] = { "HOME=/usr/root", NULL, NULL };
+static char * envp[] = { "HOME=/usr/root", "TERM=console", NULL };
struct drive_info { char dummy[32]; } drive_info;
struct screen_info screen_info;
unsigned char aux_device_present;
+static char command_line[80] = { 0, };
+
+/*
+ * This is a simple kernel command line parsing function: it parses
+ * the command line, and fills in the arguments/environment to init
+ * as appropriate. Any cmd-line option is taken to be an environment
+ * variable if it contains the character '='.
+ *
+ *
+ * This routine also checks for options meant for the kernel - currently
+ * only the "root=XXXX" option is recognized. These options are not given
+ * to init - they are for internal kernel use only.
+ */
+static void parse_options(char *line)
+{
+ char *next;
+ int args, envs;
+
+ if (!*line)
+ return;
+ args = 0;
+ envs = 1; /* TERM is set to 'console' by default */
+ next = line;
+ while (line = next) {
+ if (next = strchr(line,' '))
+ *next++ = 0;
+ /*
+ * check for kernel options first..
+ */
+ if (!strncmp(line,"root=",5)) {
+ ROOT_DEV = simple_strtoul(line+5,NULL,16);
+ continue;
+ }
+ /*
+ * Then check if it's an environment variable or
+ * an option.
+ */
+ if (strchr(line,'=')) {
+ if (envs >= MAX_INIT_ENVS)
+ break;
+ envp_init[++envs] = line;
+ } else {
+ if (args >= MAX_INIT_ARGS)
+ break;
+ argv_init[++args] = line;
+ }
+ }
+ argv_init[args+1] = NULL;
+ envp_init[envs+1] = NULL;
+}
+
void start_kernel(void)
{
/*
@@ -156,10 +207,6 @@ void start_kernel(void)
drive_info = DRIVE_INFO;
screen_info = SCREEN_INFO;
aux_device_present = AUX_DEVICE_INFO;
- sprintf(term, "TERM=con%dx%d", ORIG_VIDEO_COLS, ORIG_VIDEO_LINES);
- envp[1] = term;
- envp_rc[1] = term;
- envp_init[1] = term;
memory_end = (1<<20) + (EXT_MEM_K<<10);
memory_end &= 0xfffff000;
#ifdef MAX_16M
@@ -171,9 +218,12 @@ void start_kernel(void)
low_memory_start += 0xfff;
low_memory_start &= 0xfffff000;
memory_start = paging_init(memory_start,memory_end);
+ if (CL_MAGIC_ADDR == CL_MAGIC)
+ strcpy(command_line,CL_BASE_ADDR+CL_OFFSET);
trap_init();
init_IRQ();
sched_init();
+ parse_options(command_line);
#ifdef PROFILE_SHIFT
prof_buffer = (unsigned long *) memory_start;
prof_len = (unsigned long) &end;
@@ -182,16 +232,16 @@ void start_kernel(void)
#endif
memory_start = chr_dev_init(memory_start,memory_end);
memory_start = blk_dev_init(memory_start,memory_end);
+#ifdef CONFIG_SCSI
+ memory_start = scsi_dev_init(memory_start,memory_end);
+#endif
mem_init(low_memory_start,memory_start,memory_end);
buffer_init();
+ inode_init();
time_init();
floppy_init();
sock_init();
sti();
-#ifdef CONFIG_SCSI
- scsi_dev_init();
-#endif
- sti();
move_to_user_mode();
if (!fork()) /* we count on this going ok */
init();
diff --git a/kernel/FPU-emu/Makefile b/kernel/FPU-emu/Makefile
index 5277b89..d288ef7 100644
--- a/kernel/FPU-emu/Makefile
+++ b/kernel/FPU-emu/Makefile
@@ -46,30 +46,6 @@ dep:
proto:
cproto -e -DMAKING_PROTO *.c >fpu_proto.h
-tar:
- echo "List of source files for wm-FPU-emu" > MANIFEST
- echo "---- -- ------ ----- --- ----------" >> MANIFEST
- ls -l Makefile *.c *.S *.h >> MANIFEST
- ( cd ../../..; \
- pwd; \
- tar cvf wm-FPU-emu.t \
- linux/kernel/wm-FPU-emu/*.c \
- linux/kernel/wm-FPU-emu/*.S \
- linux/kernel/wm-FPU-emu/*.h \
- linux/kernel/wm-FPU-emu/Makefile \
- linux/kernel/wm-FPU-emu/MANIFEST \
- linux/kernel/wm-FPU-emu/README \
- linux/kernel/wm-FPU-emu/Checklist \
- linux/kernel/wm-FPU-emu/Limitations \
- linux/kernel/wm-FPU-emu/Internals \
- linux/kernel/wm-FPU-emu/Performance \
- linux/kernel/wm-FPU-emu/COPYING \
- linux/include/linux/sched.h \
- linux/include/linux/user.h \
- ; \
- compress wm-FPU-emu.t \
- )
-
dummy:
### Dependencies:
diff --git a/kernel/FPU-emu/errors.c b/kernel/FPU-emu/errors.c
index b66aa7d..078e860 100644
--- a/kernel/FPU-emu/errors.c
+++ b/kernel/FPU-emu/errors.c
@@ -267,27 +267,6 @@ void exception(int n)
}
-/********
-int EmptyError(void)
-{
- EXCEPTION(EX_StackUnder);
- return 0;
-}
- **********/
-
-
-/****
-int FullError(void)
-{
- EXCEPTION(EX_StackOver);
- reg_move(&CONST_QNaN, st0_ptr);
- return 0;
-}
- ****/
-
-
-
-
/* Real operation attempted on two operands, one a NaN */
void real_2op_NaN(REG *a, REG *b, REG *dest)
{
diff --git a/kernel/FPU-emu/reg_ld_str.c b/kernel/FPU-emu/reg_ld_str.c
index 79826cd..4809386 100644
--- a/kernel/FPU-emu/reg_ld_str.c
+++ b/kernel/FPU-emu/reg_ld_str.c
@@ -372,7 +372,7 @@ int reg_store_extended(void)
REG tmp;
EXCEPTION(EX_Denormal); /* De-normal */
reg_move(st0_ptr, &tmp);
- tmp.exp += EXTENDED_Emin + 64; /* largest exp to be 62 */
+ tmp.exp += -EXTENDED_Emin + 64; /* largest exp to be 63 */
round_to_int(&tmp);
e = 0;
put_fs_long(tmp.sigl, (unsigned long *) d);
@@ -516,7 +516,7 @@ int reg_store_double(void)
REG tmp;
EXCEPTION(EX_Denormal);
reg_move(st0_ptr, &tmp);
- tmp.exp += DOUBLE_Emin + 52; /* largest exp to be 51 */
+ tmp.exp += -DOUBLE_Emin + 52; /* largest exp to be 51 */
round_to_int(&tmp);
l[0] = tmp.sigl;
l[1] = tmp.sigh;
@@ -645,7 +645,7 @@ int reg_store_single(void)
REG tmp;
EXCEPTION(EX_Denormal);
reg_move(st0_ptr, &tmp);
- tmp.exp += SINGLE_Emin + 53; /* largest exp to be 52 */
+ tmp.exp += -SINGLE_Emin + 23; /* largest exp to be 22 */
round_to_int(&tmp);
templ = tmp.sigl;
}
@@ -1142,7 +1142,7 @@ void fsave(void)
{
/* Make a de-normal */
reg_move(rp, &tmp);
- tmp.exp += EXTENDED_Emin + 64; /* largest exp to be 62 */
+ tmp.exp += -EXTENDED_Emin + 64; /* largest exp to be 63 */
round_to_int(&tmp);
e = 0;
put_fs_long(tmp.sigl, (unsigned long *) (d+i*10+2));
diff --git a/kernel/FPU-emu/reg_mul.c b/kernel/FPU-emu/reg_mul.c
index 321d9ea..3d33979 100644
--- a/kernel/FPU-emu/reg_mul.c
+++ b/kernel/FPU-emu/reg_mul.c
@@ -27,12 +27,11 @@ void reg_mul(REG *a, REG *b, REG *dest)
reg_u_mul(a, b, dest);
dest->exp += - EXP_BIAS + 1;
dest->sign = (a->sign ^ b->sign);
+ dest->tag = TW_Valid;
if ( dest->exp <= EXP_UNDER )
{ arith_underflow(st0_ptr); }
else if ( dest->exp >= EXP_OVER )
{ arith_overflow(st0_ptr); }
- else
- dest->tag = TW_Valid;
return;
}
else if ((a->tag <= TW_Zero) && (b->tag <= TW_Zero))
diff --git a/kernel/FPU-emu/reg_u_add.S b/kernel/FPU-emu/reg_u_add.S
index c8d58fa..07e4f63 100644
--- a/kernel/FPU-emu/reg_u_add.S
+++ b/kernel/FPU-emu/reg_u_add.S
@@ -133,20 +133,21 @@ L_round_the_result:
cmpl $0x80000000,%edx
jc L_no_round_up
-/* Check the rounding algorithm *********/
jne L_do_round_up
+ /* Now test for round-to-even */
testb $1,%ebx
jz L_no_round_up
L_do_round_up:
addl $1,%ebx
adcl $0,%eax
- jnc L_no_round_up
+ jnc L_no_round_up /* Rounding done, no overflow */
/* Overflow, adjust the result */
rcrl $1,%eax
rcrl $1,%ebx
+ incl EXP(%edi)
L_no_round_up:
/* store the result */
diff --git a/kernel/FPU-emu/reg_u_sub.S b/kernel/FPU-emu/reg_u_sub.S
index 24af560..f3615a3 100644
--- a/kernel/FPU-emu/reg_u_sub.S
+++ b/kernel/FPU-emu/reg_u_sub.S
@@ -208,11 +208,14 @@ L_round:
L_round_up:
addl $1,%ebx
adcl $0,%eax
-
-#ifdef PARANOID
- /* We can show that an overflow here is not possible */
- jc L_bugged_4
-#endif PARANOID
+ jnc L_store
+
+ /* We just rounded up to (1) 00 00 */
+ /* This *is* possible, if the subtraction is of the
+ form (1. + x) - (x + y) where x is small and y is
+ very small. */
+ incl EXP(%edi)
+ movl $0x80000000,%eax
L_store:
/*------------------------------+
diff --git a/kernel/FPU-emu/version.h b/kernel/FPU-emu/version.h
index 7b8db07..cd492ed 100644
--- a/kernel/FPU-emu/version.h
+++ b/kernel/FPU-emu/version.h
@@ -8,5 +8,5 @@
| |
+---------------------------------------------------------------------------*/
-#define FPU_VERSION "wm-FPU-emu version ALPHA 0.5"
+#define FPU_VERSION "wm-FPU-emu version ALPHA 0.61"
diff --git a/kernel/Makefile b/kernel/Makefile
index 9333a4b..0661a0b 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -18,7 +18,7 @@
SUBDIRS = chr_drv blk_drv FPU-emu
-OBJS = sched.o sys_call.o traps.o irq.o fork.o \
+OBJS = sched.o sys_call.o traps.o irq.o dma.o fork.o \
panic.o printk.o vsprintf.o sys.o exit.o \
signal.o mktime.o ptrace.o ioport.o itimer.o
diff --git a/kernel/blk_drv/blk.h b/kernel/blk_drv/blk.h
index 62f1227..a4641c3 100644
--- a/kernel/blk_drv/blk.h
+++ b/kernel/blk_drv/blk.h
@@ -28,7 +28,7 @@ struct request {
unsigned long nr_sectors;
unsigned long current_nr_sectors;
char * buffer;
- struct wait_queue * waiting;
+ struct task_struct * waiting;
struct buffer_head * bh;
struct buffer_head * bhtail;
struct request * next;
@@ -191,6 +191,7 @@ static void end_request(int uptodate)
{
struct request * req;
struct buffer_head * bh;
+ struct task_struct * p;
req = CURRENT;
req->errors = 0;
@@ -220,7 +221,12 @@ static void end_request(int uptodate)
}
DEVICE_OFF(req->dev);
CURRENT = req->next;
- wake_up(&req->waiting);
+ if (p = req->waiting) {
+ req->waiting = NULL;
+ p->state = TASK_RUNNING;
+ if (p->counter > current->counter)
+ need_resched = 1;
+ }
req->dev = -1;
wake_up(&wait_for_request);
}
diff --git a/kernel/blk_drv/floppy.c b/kernel/blk_drv/floppy.c
index c82c896..512500f 100644
--- a/kernel/blk_drv/floppy.c
+++ b/kernel/blk_drv/floppy.c
@@ -42,6 +42,9 @@
* 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed
* FDC data overrun bug, added some preliminary stuff for vertical
* recording support.
+ *
+ * 1992/9/17: Added DMA allocation & DMA functions. -- hhb.
+ *
* TODO: Errors are still not counted properly.
*/
@@ -57,6 +60,7 @@
#define REALLY_SLOW_IO
#define FLOPPY_IRQ 6
+#define FLOPPY_DMA 2
#include <linux/sched.h>
#include <linux/fs.h>
@@ -65,10 +69,8 @@
#include <linux/fdreg.h>
#include <linux/fd.h>
#include <linux/errno.h>
-#ifdef HHB_SYSMACROS
-#include <linux/system.h>
-#endif
+#include <asm/dma.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>
@@ -78,6 +80,8 @@
static unsigned int changed_floppies = 0, fake_change = 0;
+static int initial_reset_flag = 0;
+static int need_configure = 1; /* for 82077 */
static int recalibrate = 0;
static int reset = 0;
static int recover = 0; /* recalibrate immediately after resetting */
@@ -197,6 +201,7 @@ static int keep_data[4] = { 0,0,0,0 };
/*
* Announce successful media type detection and media information loss after
* disk changes.
+ * Also used to enable/disable printing of overrun warnings.
*/
static ftd_msg[4] = { 0,0,0,0 };
@@ -227,7 +232,7 @@ static struct format_descr format_req;
(CURRENT->errors))
/*
- * Treshold for reporting FDC errors to the console.
+ * Threshold for reporting FDC errors to the console.
* Setting this to zero may flood your screen when using
* ultra cheap floppies ;-)
*/
@@ -289,7 +294,8 @@ void floppy_deselect(unsigned int nr)
void request_done(int uptodate)
{
timer_active &= ~(1 << FLOPPY_TIMER);
- if (format_status != FORMAT_BUSY) end_request(uptodate);
+ if (format_status != FORMAT_BUSY)
+ end_request(uptodate);
else {
format_status = uptodate ? FORMAT_OKAY : FORMAT_ERROR;
wake_up(&format_done);
@@ -373,37 +379,12 @@ static void setup_DMA(void)
copy_buffer(CURRENT->buffer,tmp_floppy_area);
}
cli();
-#ifndef HHB_SYSMACROS
-/* mask DMA 2 */
- outb_p(4|2,10);
-/* output command byte. I don't know why, but everyone (minix, */
-/* sanches & canton) output this twice, first to 12 then to 11 */
- outb_p(dma_code,12);
- outb_p(dma_code,11);
-/* 8 low bits of addr */
- outb_p(addr,4);
- addr >>= 8;
-/* bits 8-15 of addr */
- outb_p(addr,4);
- addr >>= 8;
-/* bits 16-19 of addr */
- outb_p(addr,0x81);
-/* low 8 bits of count-1 */
- count--;
- outb_p(count,5);
- count >>= 8;
-/* high 8 bits of count-1 */
- outb_p(count,5);
-/* activate DMA 2 */
- outb_p(0|2,10);
-#else /* just to show off my macros -- hhb */
- DISABLE_DMA(DMA2);
- CLEAR_DMA_FF(DMA2);
- SET_DMA_MODE(DMA2, (command == FD_READ)? DMA_MODE_READ : DMA_MODE_WRITE);
- SET_DMA_ADDR(DMA2, addr);
- SET_DMA_COUNT(DMA2, count);
- ENABLE_DMA(DMA2);
-#endif
+ disable_dma(FLOPPY_DMA);
+ clear_dma_ff(FLOPPY_DMA);
+ set_dma_mode(FLOPPY_DMA, (command == FD_READ)? DMA_MODE_READ : DMA_MODE_WRITE);
+ set_dma_addr(FLOPPY_DMA, addr);
+ set_dma_count(FLOPPY_DMA, count);
+ enable_dma(FLOPPY_DMA);
sti();
}
@@ -453,18 +434,57 @@ static int result(void)
static void bad_flp_intr(void)
{
+ int errors;
+
current_track = NO_TRACK;
- CURRENT_ERRORS++;
- if (CURRENT_ERRORS > MAX_ERRORS) {
+ if (format_status == FORMAT_BUSY)
+ errors = ++format_errors;
+ else if (!CURRENT) {
+ printk(DEVICE_NAME ": no current request\n");
+ reset = recalibrate = 1;
+ return;
+ } else
+ errors = ++CURRENT->errors;
+ if (errors > MAX_ERRORS) {
floppy_deselect(current_drive);
request_done(0);
}
- if (CURRENT_ERRORS > MAX_ERRORS/2)
+ if (errors > MAX_ERRORS/2)
reset = 1;
else
recalibrate = 1;
}
+
+/* Set perpendicular mode as required, based on data rate, if supported.
+ * 82077 Untested! 1Mbps data rate only possible with 82077-1.
+ * TODO: increase MAX_BUFFER_SECTORS, add floppy_type entries.
+ */
+static void inline perpendicular_mode(unsigned char rate)
+{
+ if (fdc_version == FDC_TYPE_82077) {
+ output_byte(FD_PERPENDICULAR);
+ if (rate & 0x40) {
+ unsigned char r = rate & 0x03;
+ if (r == 0)
+ output_byte(2); /* perpendicular, 500 kbps */
+ else if (r == 3)
+ output_byte(3); /* perpendicular, 1Mbps */
+ else {
+ printk(DEVICE_NAME ": Invalid data rate for perpendicular mode!\n");
+ reset = 1;
+ }
+ } else
+ output_byte(0); /* conventional mode */
+ } else {
+ if (rate & 0x40) {
+ printk(DEVICE_NAME ": perpendicular mode not supported by this FDC.\n");
+ reset = 1;
+ }
+ }
+} /* perpendicular_mode */
+
+
/*
* This has only been tested for the case fdc_version == FDC_TYPE_STD.
* In case you have a 82077 and want to test it, you'll have to compile
@@ -473,14 +493,26 @@ static void bad_flp_intr(void)
*/
static void configure_fdc_mode(void)
{
- if (fdc_version == FDC_TYPE_82077) {
+ if (need_configure && (fdc_version == FDC_TYPE_82077)) {
/* Enhanced version with FIFO & vertical recording. */
output_byte(FD_CONFIGURE);
output_byte(0);
- output_byte(0x1A); /* FIFO on, polling off, 10 byte treshold */
+ output_byte(0x1A); /* FIFO on, polling off, 10 byte threshold */
output_byte(0); /* precompensation from track 0 upwards */
+ need_configure = 0;
printk(DEVICE_NAME ": FIFO enabled\n");
}
+ if (cur_spec1 != floppy->spec1) {
+ cur_spec1 = floppy->spec1;
+ output_byte(FD_SPECIFY);
+ output_byte(cur_spec1); /* hut etc */
+ output_byte(6); /* Head load time =6ms, DMA */
+ }
+ if (cur_rate != floppy->rate) {
+ /* use bit 6 of floppy->rate to indicate perpendicular mode */
+ perpendicular_mode(floppy->rate);
+ outb_p((cur_rate = (floppy->rate)) & ~0x40, FD_DCR);
+ }
} /* configure_fdc_mode */
@@ -517,7 +549,8 @@ static void rw_interrupt(void)
request_done(0);
bad = 0;
} else if (ST1 & ST1_OR) {
- printk(DEVICE_NAME ": Over/Underrun - retrying\n");
+ if (ftd_msg[ST0 & ST0_DS])
+ printk(DEVICE_NAME ": Over/Underrun - retrying\n");
/* could continue from where we stopped, but ... */
bad = 0;
} else if (CURRENT_ERRORS > min_report_error_cnt[ST0 & ST0_DS]) {
@@ -646,33 +679,6 @@ static void seek_interrupt(void)
setup_rw_floppy();
}
-/* Set perpendicular mode as required, based on data rate, if supported.
- * 80277: 1Mbps data rate only possible with 82077-1.
- * Untested!! TODO: increase MAX_BUFFER_SECTORS, add floppy_type entries.
- */
-static void inline perpendicular_mode(unsigned char rate)
-{
- if (fdc_version == FDC_TYPE_82077) {
- output_byte(FD_PERPENDICULAR);
- if (rate & 0x40) {
- unsigned char r = rate & 0x03;
- if (r == 0)
- output_byte(2); /* perpendicular, 500 kbps */
- else if (r == 3)
- output_byte(3); /* perpendicular, 1Mbps */
- else {
- printk(DEVICE_NAME ": Invalid data rate for perpendicular mode!\n");
- reset = 1;
- }
- } else
- output_byte(0); /* conventional mode */
- } else {
- if (rate & 0x40) {
- printk(DEVICE_NAME ": perpendicular mode not supported by FDC.\n");
- reset = 1;
- }
- }
-} /* perpendicular_mode */
/*
* This routine is called when everything should be correctly set up
@@ -683,17 +689,9 @@ static void transfer(void)
{
read_track = (command == FD_READ) && (CURRENT_ERRORS < 4) &&
(floppy->sect <= MAX_BUFFER_SECTORS);
- if (cur_spec1 != floppy->spec1) {
- cur_spec1 = floppy->spec1;
- output_byte(FD_SPECIFY);
- output_byte(cur_spec1); /* hut etc */
- output_byte(6); /* Head load time =6ms, DMA */
- }
- if (cur_rate != floppy->rate) {
- /* use bit 6 of floppy->rate to indicate perpendicular mode */
- perpendicular_mode(floppy->rate);
- outb_p(cur_rate = ((floppy->rate)) & ~0x40, FD_DCR);
- }
+
+ configure_fdc_mode();
+
if (reset) {
redo_fd_request();
return;
@@ -702,6 +700,7 @@ static void transfer(void)
setup_rw_floppy();
return;
}
+
do_floppy = seek_interrupt;
output_byte(FD_SEEK);
if (read_track)
@@ -726,8 +725,10 @@ static void recal_interrupt(void)
if (result()!=2 || (ST0 & 0xE0) == 0x60)
reset = 1;
/* Recalibrate until track 0 is reached. Might help on some errors. */
- if ((ST0 & 0x10) == 0x10) recalibrate_floppy();
- else redo_fd_request();
+ if ((ST0 & 0x10) == 0x10)
+ recalibrate_floppy(); /* FIXME: should limit nr of recalibrates */
+ else
+ redo_fd_request();
}
static void unexpected_floppy_interrupt(void)
@@ -766,8 +767,15 @@ static void reset_interrupt(void)
output_byte(FD_SPECIFY);
output_byte(cur_spec1); /* hut etc */
output_byte(6); /* Head load time =6ms, DMA */
- configure_fdc_mode(); /* reprogram if smart fdc */
- if (!recover) redo_fd_request();
+ configure_fdc_mode(); /* reprogram fdc */
+ if (initial_reset_flag) {
+ initial_reset_flag = 0;
+ recalibrate = 1;
+ reset = 0;
+ return;
+ }
+ if (!recover)
+ redo_fd_request();
else {
recalibrate_floppy();
recover = 0;
@@ -787,12 +795,14 @@ static void reset_floppy(void)
cur_spec1 = -1;
cur_rate = -1;
recalibrate = 1;
- printk("Reset-floppy called\n");
+ need_configure = 1;
+ if (!initial_reset_flag)
+ printk("Reset-floppy called\n");
cli();
- outb_p(current_DOR & ~0x04,FD_DOR);
+ outb_p(current_DOR & ~0x04, FD_DOR);
for (i=0 ; i<1000 ; i++)
__asm__("nop");
- outb(current_DOR,FD_DOR);
+ outb(current_DOR, FD_DOR);
sti();
}
@@ -808,7 +818,8 @@ static void floppy_shutdown(void)
static void shake_done(void)
{
current_track = NO_TRACK;
- if (inb(FD_DIR) & 0x80) request_done(0);
+ if (inb(FD_DIR) & 0x80)
+ request_done(0);
redo_fd_request();
}
@@ -846,8 +857,7 @@ static void floppy_on_interrupt(void)
keep_data[current_drive]--;
}
else {
- if (ftd_msg[current_drive] && current_type[
- current_drive] != NULL)
+ if (ftd_msg[current_drive] && current_type[current_drive] != NULL)
printk("Disk type is undefined after disk "
"change in fd%d\n",current_drive);
current_type[current_drive] = NULL;
@@ -919,7 +929,7 @@ repeat:
if (format_status != FORMAT_BUSY) {
if (!CURRENT) {
if (!fdc_busy)
- printk("FDC access conflict");
+ printk("FDC access conflict!");
fdc_busy = 0;
wake_up(&fdc_wait);
CLEAR_INTR;
@@ -1209,13 +1219,13 @@ static struct file_operations floppy_fops = {
* my FDC does, except when booting in SVGA screen mode.
* When it does generate an interrupt, it doesn't return any status bytes.
* It appears to have something to do with the version command...
+ *
+ * This should never be called, because of the reset after the version check.
*/
static void ignore_interrupt(void)
{
- if (result() != 0) {
- printk(DEVICE_NAME ": weird interrupt ignored\n");
- reset = 1;
- }
+ printk(DEVICE_NAME ": weird interrupt ignored (%d)\n", result());
+ reset = 1;
CLEAR_INTR; /* ignore only once */
}
@@ -1251,8 +1261,9 @@ void floppy_init(void)
timer_active &= ~(1 << FLOPPY_TIMER);
config_types();
if (irqaction(FLOPPY_IRQ,&floppy_sigaction))
- printk("Unable to grab IRQ%d for the floppy driver\n",FLOPPY_IRQ);
-
+ printk("Unable to grab IRQ%d for the floppy driver\n", FLOPPY_IRQ);
+ if (request_dma(FLOPPY_DMA))
+ printk("Unable to grab DMA%d for the floppy driver\n", FLOPPY_DMA);
/* Try to determine the floppy controller type */
DEVICE_INTR = ignore_interrupt; /* don't ask ... */
output_byte(FD_VERSION); /* get FDC version code */
@@ -1266,5 +1277,14 @@ void floppy_init(void)
#ifndef FDC_FIFO_UNTESTED
fdc_version = FDC_TYPE_STD; /* force std fdc type; can't test other. */
#endif
- configure_fdc_mode();
+
+ /* Not all FDCs seem to be able to handle the version command
+ * properly, so force a reset for the standard FDC clones,
+ * to avoid interrupt garbage.
+ */
+
+ if (fdc_version == FDC_TYPE_STD) {
+ initial_reset_flag = 1;
+ reset_floppy();
+ }
}
diff --git a/kernel/blk_drv/ll_rw_blk.c b/kernel/blk_drv/ll_rw_blk.c
index 5e03420..c6aef54 100644
--- a/kernel/blk_drv/ll_rw_blk.c
+++ b/kernel/blk_drv/ll_rw_blk.c
@@ -12,6 +12,7 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/config.h>
+#include <linux/locks.h>
#include <asm/system.h>
@@ -56,23 +57,6 @@ struct blk_dev_struct blk_dev[NR_BLK_DEV] = {
*/
int * blk_size[NR_BLK_DEV] = { NULL, NULL, };
-static inline void lock_buffer(struct buffer_head * bh)
-{
- cli();
- while (bh->b_lock)
- sleep_on(&bh->b_wait);
- bh->b_lock=1;
- sti();
-}
-
-static inline void unlock_buffer(struct buffer_head * bh)
-{
- if (!bh->b_lock)
- printk("ll_rw_block.c: buffer not locked\n\r");
- bh->b_lock = 0;
- wake_up(&bh->b_wait);
-}
-
/* RO fail safe mechanism */
static long ro_bits[NR_BLK_DEV][8];
@@ -251,7 +235,7 @@ repeat:
req->nr_sectors = 8;
req->current_nr_sectors = 8;
req->buffer = buffer;
- req->waiting = &current->wait;
+ req->waiting = current;
req->bh = NULL;
req->next = NULL;
current->state = TASK_UNINTERRUPTIBLE;
@@ -284,24 +268,6 @@ void ll_rw_block(int rw, struct buffer_head * bh)
make_request(major,rw,bh);
}
-long blk_dev_init(long mem_start, long mem_end)
-{
- int i;
-
- for (i=0 ; i<NR_REQUEST ; i++) {
- request[i].dev = -1;
- request[i].next = NULL;
- }
- memset(ro_bits,0,sizeof(ro_bits));
-#ifdef CONFIG_BLK_DEV_HD
- mem_start = hd_init(mem_start,mem_end);
-#endif
-#ifdef RAMDISK
- mem_start += rd_init(mem_start, RAMDISK*1024);
-#endif
- return mem_start;
-}
-
void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf)
{
int i;
@@ -341,7 +307,7 @@ repeat:
req->nr_sectors = 2;
req->current_nr_sectors = 2;
req->buffer = buf;
- req->waiting = &current->wait;
+ req->waiting = current;
req->bh = NULL;
req->next = NULL;
current->state = TASK_UNINTERRUPTIBLE;
@@ -349,3 +315,21 @@ repeat:
schedule();
}
}
+
+long blk_dev_init(long mem_start, long mem_end)
+{
+ int i;
+
+ for (i=0 ; i<NR_REQUEST ; i++) {
+ request[i].dev = -1;
+ request[i].next = NULL;
+ }
+ memset(ro_bits,0,sizeof(ro_bits));
+#ifdef CONFIG_BLK_DEV_HD
+ mem_start = hd_init(mem_start,mem_end);
+#endif
+#ifdef RAMDISK
+ mem_start += rd_init(mem_start, RAMDISK*1024);
+#endif
+ return mem_start;
+}
diff --git a/kernel/blk_drv/ramdisk.c b/kernel/blk_drv/ramdisk.c
index 8690a91..d70ee08 100644
--- a/kernel/blk_drv/ramdisk.c
+++ b/kernel/blk_drv/ramdisk.c
@@ -14,7 +14,6 @@
#include <linux/string.h>
#include <asm/system.h>
#include <asm/segment.h>
-#include <asm/memory.h>
#define MAJOR_NR 1
#include "blk.h"
diff --git a/kernel/blk_drv/scsi/7000fasst.h b/kernel/blk_drv/scsi/7000fasst.h
index 7411950..daa6f1f 100644
--- a/kernel/blk_drv/scsi/7000fasst.h
+++ b/kernel/blk_drv/scsi/7000fasst.h
@@ -133,5 +133,5 @@ int wd7000fasst_reset(void);
wd7000fasst_queuecommand, \
wd7000fasst_abort, \
wd7000fasst_reset, \
- 1, 7, 0}
+ 1, 7, 0, 1}
#endif
diff --git a/kernel/blk_drv/scsi/aha1542.c b/kernel/blk_drv/scsi/aha1542.c
index 06d0bcb..b49e1d3 100644
--- a/kernel/blk_drv/scsi/aha1542.c
+++ b/kernel/blk_drv/scsi/aha1542.c
@@ -433,11 +433,6 @@ int aha1542_detect(int hostnum)
return 0;
}
-#ifndef MAX_16M
- printk("Adaptec 1542 disabled for kernels without memory limiting to 16MB.\n");
- return 0;
-#endif
-
/* Set the Bus on/off-times as not to ruin floppy performens */
{
static unchar oncmd[] = {CMD_BUSON_TIME, 5};
diff --git a/kernel/blk_drv/scsi/aha1542.h b/kernel/blk_drv/scsi/aha1542.h
index 5d3640f..aa57544 100644
--- a/kernel/blk_drv/scsi/aha1542.h
+++ b/kernel/blk_drv/scsi/aha1542.h
@@ -135,5 +135,5 @@ int aha1542_reset(void);
aha1542_queuecommand, \
aha1542_abort, \
aha1542_reset, \
- 1, 7, 0}
+ 1, 7, 0, 1}
#endif
diff --git a/kernel/blk_drv/scsi/fdomain.h b/kernel/blk_drv/scsi/fdomain.h
index 78f2b09..40e4609 100644
--- a/kernel/blk_drv/scsi/fdomain.h
+++ b/kernel/blk_drv/scsi/fdomain.h
@@ -40,6 +40,6 @@ int fdomain_16x0_queue( unsigned char target, const void *cmnd,
NULL, \
fdomain_16x0_abort, \
fdomain_16x0_reset, \
- 0, 6, 0 }
+ 0, 6, 0 ,0}
#endif
#endif
diff --git a/kernel/blk_drv/scsi/hosts.h b/kernel/blk_drv/scsi/hosts.h
index f5504d6..686aae3 100644
--- a/kernel/blk_drv/scsi/hosts.h
+++ b/kernel/blk_drv/scsi/hosts.h
@@ -143,6 +143,11 @@ typedef struct
*/
unsigned present:1;
+ /*
+ true if this host adapter uses unchecked DMA onto an ISA bus.
+ */
+ unsigned unchecked_isa_dma:1;
+
} Scsi_Host;
/*
diff --git a/kernel/blk_drv/scsi/scsi.c b/kernel/blk_drv/scsi/scsi.c
index 164813d..fd7457e 100644
--- a/kernel/blk_drv/scsi/scsi.c
+++ b/kernel/blk_drv/scsi/scsi.c
@@ -1105,7 +1105,7 @@ static void update_timeout(void)
*/
static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
-void scsi_dev_init (void)
+unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end)
{
int i;
#ifdef FOO_ON_YOU
@@ -1129,16 +1129,17 @@ void scsi_dev_init (void)
scan_scsis(); /* scan for scsi devices */
#ifdef CONFIG_BLK_DEV_SD
- sd_init(); /* init scsi disks */
+ memory_start = sd_init(memory_start, memory_end); /* init scsi disks */
#endif
#ifdef CONFIG_BLK_DEV_ST
- st_init(); /* init scsi tapes */
+ memory_start = st_init(memory_start, memory_end); /* init scsi tapes */
#endif
#ifdef CONFIG_BLK_DEV_SR
- sr_init();
+ memory_start = sr_init(memory_start, memory_end);
#endif
+ return memory_start;
}
#endif
diff --git a/kernel/blk_drv/scsi/scsi.h b/kernel/blk_drv/scsi/scsi.h
index 7bf6027..14b9dde 100644
--- a/kernel/blk_drv/scsi/scsi.h
+++ b/kernel/blk_drv/scsi/scsi.h
@@ -253,7 +253,7 @@ extern int scsi_abort (int host, int code);
Initializes all SCSI devices. This scans all scsi busses.
*/
-extern void scsi_dev_init (void);
+extern unsigned long scsi_dev_init (unsigned long, unsigned long);
/*
You guesed it. This sends a command to the selected SCSI host
diff --git a/kernel/blk_drv/scsi/scsi_ioctl.c b/kernel/blk_drv/scsi/scsi_ioctl.c
index 411fa64..73c3ea9 100644
--- a/kernel/blk_drv/scsi/scsi_ioctl.c
+++ b/kernel/blk_drv/scsi/scsi_ioctl.c
@@ -70,15 +70,16 @@ static void scsi_ioctl_done (int host, int result)
the_result[host] = result;
}
+/* This function will operate certain scsi functions which require no
+ data transfer */
static int ioctl_internal_command(Scsi_Device *dev, char ** command)
{
- char * buf;
char * cmd;
int temp, host;
+ char sense_buffer[256];
host = dev->host_no;
cmd = command[0];
- buf = command[1];
do {
cli();
@@ -93,16 +94,16 @@ static int ioctl_internal_command(Scsi_Device *dev, char ** command)
}
} while (1);
- scsi_do_cmd(host, dev->id, cmd, buf, 255,
+ scsi_do_cmd(host, dev->id, cmd, NULL, 0,
scsi_ioctl_done, MAX_TIMEOUT,
- buf, MAX_RETRIES);
+ sense_buffer, MAX_RETRIES);
while (the_result[host] == -1)
/* nothing */;
temp = the_result[host];
if(driver_byte(the_result[host]) != 0)
- switch(buf[2] & 0xf) {
+ switch(sense_buffer[2] & 0xf) {
case ILLEGAL_REQUEST:
printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
break;
@@ -125,9 +126,9 @@ static int ioctl_internal_command(Scsi_Device *dev, char ** command)
dev->lun,
the_result);
printk("\tSense class %x, sense error %x, extended sense %x\n",
- sense_class(buf[0]),
- sense_error(buf[0]),
- buf[2] & 0xf);
+ sense_class(sense_buffer[0]),
+ sense_error(sense_buffer[0]),
+ sense_buffer[2] & 0xf);
};
@@ -226,7 +227,6 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
command[0] = scsi_cmd;
- command[1] = (char *) arg;
return ioctl_internal_command((Scsi_Device *) dev, command);
break;
case SCSI_IOCTL_DOORUNLOCK:
@@ -236,7 +236,6 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
command[0] = scsi_cmd;
- command[1] = (char *) arg;
return ioctl_internal_command((Scsi_Device *) dev, command);
case SCSI_IOCTL_TEST_UNIT_READY:
scsi_cmd[0] = TEST_UNIT_READY;
@@ -244,7 +243,6 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
scsi_cmd[4] = 0;
command[0] = scsi_cmd;
- command[1] = (char *) arg;
return ioctl_internal_command((Scsi_Device *) dev, command);
break;
default :
diff --git a/kernel/blk_drv/scsi/sd.c b/kernel/blk_drv/scsi/sd.c
index 53fa133..3d05bd5 100644
--- a/kernel/blk_drv/scsi/sd.c
+++ b/kernel/blk_drv/scsi/sd.c
@@ -17,6 +17,7 @@
#include <asm/system.h>
#include "scsi.h"
+#include "hosts.h"
#include "sd.h"
#include "scsi_ioctl.h"
@@ -37,8 +38,19 @@ static const char RCSid[] = "$Header:";
#define SD_TIMEOUT 200
+#define ISA_DMA_THRESHOLD (0x00ffffff)
struct hd_struct sd[MAX_SD << 4];
+/* For a > 16 Mb system, we may need an intermediate buffer for data */
+
+struct block_buffer
+ {
+ unsigned long int use;
+ unsigned char buffer[4096];
+ };
+
+static struct block_buffer * bb = NULL;
+
int NR_SD=0;
Scsi_Disk rscsi_disks[MAX_SD];
static int sd_sizes[MAX_SD << 4] = {0, };
@@ -61,14 +73,16 @@ static int sd_open(struct inode * inode, struct file * filp)
int target;
target = DEVICE_NR(MINOR(inode->i_rdev));
+ if(target >= NR_SD || !rscsi_disks[target].device)
+ return -EACCES; /* No such device */
+
/* Make sure that only one process can do a check_change_disk at one time.
This is also used to lock out further access when the partition table is being re-read. */
while (rscsi_disks[target].device->busy);
if(rscsi_disks[target].device->removable) {
- if (filp->f_mode)
- check_disk_change(inode->i_rdev);
+ check_disk_change(inode->i_rdev);
if(!rscsi_disks[target].device->access_count)
sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
@@ -150,6 +164,17 @@ static void rw_intr (int host, int result)
*/
if (!result) {
+ if (bb && bb[DEVICE_NR(CURRENT->dev)].use && CURRENT->cmd == READ)
+ {
+ memcpy((char *)CURRENT->buffer,
+ bb[DEVICE_NR(CURRENT->dev)].buffer,
+ this_count << 9);
+#ifdef DEBUG
+ printk("R");
+#endif
+ };
+ if(bb) bb[DEVICE_NR(CURRENT->dev)].use = 0;
+
CURRENT->nr_sectors -= this_count;
if (slow_scsi_io == host) {
total_count -= this_count;
@@ -199,7 +224,7 @@ static void rw_intr (int host, int result)
else
end_request(1);
do_sd_request();
- }
+ }
/*
* Of course, the error handling code is a little Fubar down in scsi.c.
@@ -214,12 +239,25 @@ static void rw_intr (int host, int result)
*/
else if (driver_byte(result) & DRIVER_SENSE) {
+ if (bb) bb[DEVICE_NR(CURRENT->dev)].use = 0;
if (sugestion(result) == SUGGEST_REMAP) {
#ifdef REMAP
/*
Not yet implemented. A read will fail after being remapped,
a write will call the strategy routine again.
*/
+ if rscsi_disks[DEVICE_NR(CURRENT->dev)].remap
+ {
+ result = 0;
+ }
+ else
+
+#endif
+ }
+
+/* A unit attention comes up if there is a media change on a removable
+ disk drive */
+
else if ((sense_buffer[0] & 0x7f) == 0x70) {
if ((sense_buffer[2] & 0xf) == UNIT_ATTENTION) {
/* detected disc change. set a bit and quietly refuse */
@@ -230,16 +268,8 @@ static void rw_intr (int host, int result)
do_sd_request();
return;
}
- }
-
- if rscsi_disks[DEVICE_NR(CURRENT->dev)].remap
- {
- result = 0;
- }
- else
+ }
-#endif
- }
/*
If we had an ILLEGAL REQUEST returned, then we may have performed
an unsupported command. The only thing this should be would be a ten
@@ -247,7 +277,6 @@ static void rw_intr (int host, int result)
system where READ CAPACITY failed, we mave have read past the end of the
disk.
*/
-
else if (sense_buffer[7] == ILLEGAL_REQUEST) {
if (rscsi_disks[DEVICE_NR(CURRENT->dev)].ten) {
rscsi_disks[DEVICE_NR(CURRENT->dev)].ten = 0;
@@ -258,6 +287,7 @@ static void rw_intr (int host, int result)
}
}
if (result) {
+ if (bb) bb[DEVICE_NR(CURRENT->dev)].use = 0;
printk("SCSI disk error : host %d id %d lun %d return code = %x\n",
rscsi_disks[DEVICE_NR(CURRENT->dev)].device->host_no,
rscsi_disks[DEVICE_NR(CURRENT->dev)].device->id,
@@ -284,6 +314,7 @@ static void do_sd_request (void)
{
int dev, block;
unsigned char cmd[10];
+ char * buff;
repeat:
INIT_REQUEST;
@@ -357,6 +388,24 @@ repeat:
cmd[1] = (LUN << 5) & 0xe0;
+ buff = CURRENT->buffer;
+
+/* Curses, curses. If this is a DMA transfer, we could be screwed. */
+ if (((int) buff) + (this_count << 9) > ISA_DMA_THRESHOLD &&
+ (scsi_hosts[HOST].unchecked_isa_dma)) {
+ if (bb[DEVICE_NR(CURRENT->dev)].use) panic ("block buffer already in use");
+ bb[DEVICE_NR(CURRENT->dev)].use = 1;
+ if(this_count > 8) this_count = 8;
+ if (CURRENT->cmd == WRITE) {
+ memcpy(bb[DEVICE_NR(CURRENT->dev)].buffer,
+ (char *)CURRENT->buffer, this_count << 9);
+#ifdef DEBUG
+ printk("W");
+#endif
+ };
+ buff = bb[DEVICE_NR(CURRENT->dev)].buffer;
+ };
+
if (((this_count > 0xff) || (block > 0x1fffff)) && rscsi_disks[dev].ten)
{
if (this_count > 0xffff)
@@ -383,7 +432,7 @@ repeat:
cmd[5] = 0;
}
- scsi_do_cmd (HOST, ID, (void *) cmd, CURRENT->buffer, this_count << 9,
+ scsi_do_cmd (HOST, ID, (void *) cmd, buff, this_count << 9,
rw_intr, SD_TIMEOUT, sense_buffer, MAX_RETRIES);
}
@@ -527,7 +576,7 @@ static int sd_init_onedisk(int i)
their size, and reads partition table entries for them.
*/
-void sd_init(void)
+unsigned long sd_init(unsigned long memory_start, unsigned long memory_end)
{
int i;
@@ -539,6 +588,13 @@ void sd_init(void)
sd_gendisk.next = gendisk_head;
gendisk_head = &sd_gendisk;
boot_init_done++;
+/* Allocate DMA block buffer */
+ if(memory_end > ISA_DMA_THRESHOLD) {
+ bb = (struct block_buffer *) memory_start;
+ memory_start += NR_SD * sizeof(struct block_buffer);
+ for (i=0; i < NR_SD; ++i) bb[i].use = 0;
+ };
+ return memory_start;
}
#define DEVICE_BUSY rscsi_disks[target].device->busy
@@ -567,6 +623,7 @@ int revalidate_scsidisk(int dev, int maxusage){
sti();
if (DEVICE_BUSY || USAGE > maxusage) {
cli();
+ printk("Device busy for revalidation (usage=%d)\n", USAGE);
return -EBUSY;
};
DEVICE_BUSY = 1;
diff --git a/kernel/blk_drv/scsi/sd.h b/kernel/blk_drv/scsi/sd.h
index aacb01f..e36d364 100644
--- a/kernel/blk_drv/scsi/sd.h
+++ b/kernel/blk_drv/scsi/sd.h
@@ -42,7 +42,7 @@ typedef struct {
extern Scsi_Disk rscsi_disks[MAX_SD];
-void sd_init(void);
+unsigned long sd_init(unsigned long, unsigned long);
#define HOST (rscsi_disks[DEVICE_NR(CURRENT->dev)].device->host_no)
#define ID (rscsi_disks[DEVICE_NR(CURRENT->dev)].device->id)
diff --git a/kernel/blk_drv/scsi/seagate.h b/kernel/blk_drv/scsi/seagate.h
index 0eb3b30..744f8d5 100644
--- a/kernel/blk_drv/scsi/seagate.h
+++ b/kernel/blk_drv/scsi/seagate.h
@@ -29,7 +29,7 @@ int seagate_st0x_reset(void);
#define SEAGATE_ST0X {"Seagate ST-01/ST-02", seagate_st0x_detect, \
seagate_st0x_info, seagate_st0x_command, \
seagate_st0x_queue_command, seagate_st0x_abort, \
- seagate_st0x_reset, 1, 7, 0}
+ seagate_st0x_reset, 1, 7, 0, 0}
#endif
diff --git a/kernel/blk_drv/scsi/sr.c b/kernel/blk_drv/scsi/sr.c
index c84cf21..97a16bc 100644
--- a/kernel/blk_drv/scsi/sr.c
+++ b/kernel/blk_drv/scsi/sr.c
@@ -17,6 +17,7 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
+#include <linux/errno.h>
#include "scsi.h"
#include "sr.h"
@@ -42,7 +43,7 @@ struct block_buffer
unsigned char buffer[2048];
};
-static struct block_buffer bb[MAX_SR];
+static struct block_buffer * bb;
static int sr_open(struct inode *, struct file *);
@@ -220,8 +221,10 @@ static void rw_intr (int host, int result)
static int sr_open(struct inode * inode, struct file * filp)
{
- if (filp->f_mode)
- check_disk_change(inode->i_rdev);
+ if(MINOR(inode->i_rdev) >= NR_SR ||
+ !scsi_CDs[MINOR(inode->i_rdev)].device) return -EACCES; /* No such device */
+
+ check_disk_change(inode->i_rdev);
if(!scsi_CDs[MINOR(inode->i_rdev)].device->access_count++)
sr_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
@@ -370,10 +373,13 @@ void do_sr_request (void)
rw_intr, SR_TIMEOUT, sense_buffer, MAX_RETRIES);
}
-void sr_init(void)
+unsigned long sr_init(unsigned long memory_start, unsigned long memory_end)
{
int i;
+ bb = (struct block_buffer *) memory_start;
+ memory_start += NR_SR * sizeof(struct block_buffer);
+
for (i = 0; i < NR_SR; ++i)
{
scsi_CDs[i].capacity = 0x1fffff;
@@ -389,6 +395,7 @@ void sr_init(void)
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
blk_size[MAJOR_NR] = sr_sizes;
blkdev_fops[MAJOR_NR] = &sr_fops;
+ return memory_start;
}
#endif
diff --git a/kernel/blk_drv/scsi/sr.h b/kernel/blk_drv/scsi/sr.h
index 6cf0ece..865d8d0 100644
--- a/kernel/blk_drv/scsi/sr.h
+++ b/kernel/blk_drv/scsi/sr.h
@@ -32,7 +32,7 @@ typedef struct
extern Scsi_CD scsi_CDs[MAX_SR];
-void sr_init(void);
+unsigned long sr_init(unsigned long, unsigned long);
#define SR_HOST (scsi_CDs[DEVICE_NR(CURRENT->dev)].device->host_no)
#define SR_ID (scsi_CDs[DEVICE_NR(CURRENT->dev)].device->id)
diff --git a/kernel/blk_drv/scsi/st.c b/kernel/blk_drv/scsi/st.c
index 1f81217..01feaac 100644
--- a/kernel/blk_drv/scsi/st.c
+++ b/kernel/blk_drv/scsi/st.c
@@ -24,9 +24,11 @@ void do_st_request(void)
panic("There is no st driver.\n\r");
}
-void st_init(void)
+unsigned long st_init(unsigned long memory_start, unsigned long memory_end)
{
blk_dev[MAJOR_NR].request_fn = do_st_request;
blk_size[MAJOR_NR] = st_sizes;
+ return memory_start;
}
#endif
+
diff --git a/kernel/blk_drv/scsi/st.h b/kernel/blk_drv/scsi/st.h
index 9ae0795..ca957df 100644
--- a/kernel/blk_drv/scsi/st.h
+++ b/kernel/blk_drv/scsi/st.h
@@ -22,5 +22,5 @@ typedef struct
extern int NR_ST;
extern Scsi_Tape scsi_tapes[MAX_ST];
-void st_init(void);
+unsigned long st_init(unsigned long, unsigned long);
#endif
diff --git a/kernel/blk_drv/scsi/ultrastor.h b/kernel/blk_drv/scsi/ultrastor.h
index b881419..cf8c1ac 100644
--- a/kernel/blk_drv/scsi/ultrastor.h
+++ b/kernel/blk_drv/scsi/ultrastor.h
@@ -43,7 +43,7 @@ int ultrastor_14f_reset(void);
#define ULTRASTOR_14F \
{ "UltraStor 14F", ultrastor_14f_detect, ultrastor_14f_info, \
ultrastor_14f_command, 0, ultrastor_14f_abort, ultrastor_14f_reset, \
- 0, 0, 0 }
+ 0, 0, 0, 1 }
#endif
#define UD_ABORT 0x0001
diff --git a/kernel/chr_drv/keyboard.c b/kernel/chr_drv/keyboard.c
index 6d0217a..ac24701 100644
--- a/kernel/chr_drv/keyboard.c
+++ b/kernel/chr_drv/keyboard.c
@@ -123,15 +123,17 @@ void keyboard_interrupt(int int_pt_regs)
rep = scancode;
repke0 = ke0;
}
- } else if (ke0 == repke0 && (scancode & 0x7f) == rep)
+ } else if (ke0 == repke0 && (scancode & 0x7f) == rep) {
if (scancode & 0x80)
rep = 0xff;
- else if (!(krepeat && tty && (L_ECHO(tty) ||
- (EMPTY(&tty->secondary) &&
- EMPTY(&tty->read_q))))) {
+ else if (!(krepeat && tty &&
+ (L_ECHO(tty) ||
+ (EMPTY(&tty->secondary) &&
+ EMPTY(&tty->read_q))))) {
ke0 = 0;
return;
}
+ }
key_table[scancode](scancode);
do_keyboard_interrupt();
ke0 = 0;
@@ -1351,12 +1353,11 @@ long no_idt[2] = {0, 0};
void hard_reset_now(void)
{
int i;
- unsigned long * pg_dir;
+ extern unsigned long pg0[1024];
sti();
/* rebooting needs to touch the page at absolute addr 0 */
- pg_dir = (unsigned long *) current->tss.cr3;
- pg_dir[768] = 7; /* 0xC0000000 */
+ pg0[0] = 7;
for (;;) {
for (i=0; i<100; i++) {
kb_wait();
diff --git a/kernel/chr_drv/lp.c b/kernel/chr_drv/lp.c
index e0e2f25..bfa02c7 100644
--- a/kernel/chr_drv/lp.c
+++ b/kernel/chr_drv/lp.c
@@ -1,25 +1,19 @@
/*
- $Header: /usr/src/linux/kernel/chr_drv/lp.c,v 1.9 1992/01/06 16:11:19
- james_r_wiegand Exp james_r_wiegand $
-*/
-
-/*
- * Edited by Linus - cleaner interface etc. Still not using interrupts, so
- * it eats more resources than necessary, but it was easy to code this way...
+ * Copyright (C) 1992 by Jim Weigand, Linus Torvalds, and Michael K. Johnson
*/
-#include <linux/sched.h>
#include <linux/lp.h>
+/* sched.h is included from lp.h */
static int lp_reset(int minor)
{
int testvalue;
/* reset value */
- outb(0, LP_B(minor)+2);
+ outb(0, LP_C(minor));
for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
;
- outb(LP_PSELECP | LP_PINITP, LP_B(minor)+2);
+ outb(LP_PSELECP | LP_PINITP, LP_C(minor));
return LP_S(minor);
}
@@ -31,18 +25,20 @@ static int lp_char(char lpchar, int minor)
outb(lpchar, LP_B(minor));
do {
retval = LP_S(minor);
- schedule();
count ++;
- } while(!(retval & LP_PBUSY) && count < LP_TIMEOUT);
- if (count == LP_TIMEOUT) {
- printk("lp%d timeout\n\r", minor);
+ if (need_resched)
+ schedule();
+ } while(!(retval & LP_PBUSY) && count < LP_TIME_CHAR);
+
+ if (count == LP_TIME_CHAR) {
return 0;
+ /* we timed out, and the character was /not/ printed */
}
- /* control port pr_table[0]+2 take strobe high */
- outb(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_B( minor ) + 2 ));
- /* take strobe low */
- outb(( LP_PSELECP | LP_PINITP ), ( LP_B( minor ) + 2 ));
- /* get something meaningful for return value */
+ /* control port takes strobe high */
+ outb(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor )));
+ /* take strobe low */
+ outb(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));
+ /* get something meaningful for return value */
return LP_S(minor);
}
@@ -50,31 +46,69 @@ static int lp_write(struct inode * inode, struct file * file, char * buf, int co
{
int retval;
unsigned int minor = MINOR(inode->i_rdev);
+ unsigned int each_cnt = 0, old_cnt = 0;
char c, *temp = buf;
temp = buf;
while (count > 0) {
- c = get_fs_byte(temp++);
+ c = get_fs_byte(temp);
retval = lp_char(c, minor);
- count--;
- if (retval & LP_POUTPA) {
- LP_F(minor) |= LP_NOPA;
- return temp-buf?temp-buf:-ENOSPC;
- } else
- LP_F(minor) &= ~LP_NOPA;
-
- if (!(retval & LP_PSELECD)) {
- LP_F(minor) &= ~LP_SELEC;
- return temp-buf?temp-buf:-EFAULT;
- } else
- LP_F(minor) &= ~LP_SELEC;
-
- /* not offline or out of paper. on fire? */
- if (!(retval & LP_PERRORP)) {
- LP_F(minor) |= LP_ERR;
- return temp-buf?temp-buf:-EIO;
- } else
- LP_F(minor) &= ~LP_SELEC;
+ /* only update counting vars if character was printed */
+ if (retval) {
+ count--;
+ temp++;
+ }
+
+ if (!retval) { /* if printer timed out */
+ each_cnt = count - old_cnt;
+ old_cnt = count;
+
+ /* here we do calculations based on old count
+ and change the time that we will sleep.
+ For now this will be hard coded... */
+
+ /* check for signals before going to sleep */
+ if (current->signal & ~current->blocked) {
+ return temp-buf?temp-buf:-ERESTARTSYS;
+ }
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + LP_TIME(minor);
+ schedule();
+ LP_COUNT(minor) = each_cnt;
+
+ /* the following is ugly, but should alert me if
+ something dreadful is going on. It will disappear
+ in the final versions of the driver. */
+ if (!(LP_S(minor) & LP_BUSY)) {
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + LP_TIMEOUT;
+ schedule();
+ if (!(LP_S(minor) & LP_BUSY))
+ printk("lp%d timeout\n\r", minor);
+ }
+ } else {
+ if (retval & LP_POUTPA) {
+ LP_F(minor) |= LP_NOPA;
+ printk("lp%d out of paper\n\r", minor);
+ return temp-buf?temp-buf:-ENOSPC;
+ } else
+ LP_F(minor) &= ~LP_NOPA;
+
+ if (!(retval & LP_PSELECD)) {
+ LP_F(minor) |= LP_SELEC;
+ printk("lp%d off-line\n\r", minor);
+ return temp-buf?temp-buf:-EFAULT;
+ } else
+ LP_F(minor) &= ~LP_SELEC;
+
+ /* not offline or out of paper. on fire? */
+ if (!(retval & LP_PERRORP)) {
+ LP_F(minor) |= LP_ERR;
+ printk("lp%d on fire\n\r", minor);
+ return temp-buf?temp-buf:-EIO;
+ } else
+ LP_F(minor) &= ~LP_SELEC;
+ }
}
return temp-buf;
}
@@ -111,13 +145,13 @@ static void lp_release(struct inode * inode, struct file * file)
}
static struct file_operations lp_fops = {
- lp_lseek,
- lp_read,
+ lp_lseek, /* why not null? */
+ lp_read, /* why not null? */
lp_write,
NULL, /* lp_readdir */
NULL, /* lp_select */
NULL, /* lp_ioctl */
- NULL, /* lp_mmap */
+ NULL, /* mmap */
lp_open,
lp_release
};
diff --git a/kernel/chr_drv/mem.c b/kernel/chr_drv/mem.c
index 301d067..ca486b5 100644
--- a/kernel/chr_drv/mem.c
+++ b/kernel/chr_drv/mem.c
@@ -11,6 +11,10 @@
#include <linux/tty.h>
#include <linux/mouse.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/string.h>
+
#include <asm/segment.h>
#include <asm/io.h>
@@ -24,6 +28,51 @@ static int write_ram(struct inode * inode, struct file * file,char * buf, int co
return -EIO;
}
+static int read_core(struct inode * inode, struct file * file,char * buf, int count)
+{
+ unsigned long p = file->f_pos;
+ int read;
+ int count1;
+ char * pnt;
+ struct user dump;
+
+ memset(&dump, 0, sizeof(struct user));
+ dump.magic = CMAGIC;
+ dump.u_dsize = high_memory >> 12;
+
+ if (count < 0)
+ return -EINVAL;
+ if (p >= high_memory)
+ return 0;
+ if (count > high_memory - p)
+ count = high_memory - p;
+ read = 0;
+
+ if (p < sizeof(struct user) && count > 0) {
+ count1 = count;
+ if (p + count1 > sizeof(struct user))
+ count1 = sizeof(struct user)-p;
+ pnt = (char *) &dump + p;
+ memcpy_tofs(buf,(void *) pnt, count1);
+ buf += count1;
+ p += count1;
+ count -= count1;
+ read += count1;
+ }
+
+ while (p < (4096 + 4096) && count > 0) {
+ put_fs_byte(0,buf);
+ buf++;
+ p++;
+ count--;
+ read++;
+ }
+ memcpy_tofs(buf,(void *) (p - 4096),count);
+ read += count;
+ file->f_pos += read;
+ return read;
+}
+
static int read_mem(struct inode * inode, struct file * file,char * buf, int count)
{
unsigned long p = file->f_pos;
@@ -228,6 +277,18 @@ static struct file_operations zero_fops = {
NULL /* no special release code */
};
+static struct file_operations core_fops = {
+ memory_lseek,
+ read_core,
+ NULL,
+ NULL, /* zero_readdir */
+ NULL, /* zero_select */
+ NULL, /* zero_ioctl */
+ NULL, /* zero_mmap */
+ NULL, /* no special open code */
+ NULL /* no special release code */
+};
+
static int memory_open(struct inode * inode, struct file * filp)
{
switch (MINOR(inode->i_rdev)) {
@@ -249,6 +310,9 @@ static int memory_open(struct inode * inode, struct file * filp)
case 5:
filp->f_op = &zero_fops;
break;
+ case 6:
+ filp->f_op = &core_fops;
+ break;
default:
return -ENODEV;
}
diff --git a/kernel/chr_drv/serial.c b/kernel/chr_drv/serial.c
index e867647..62cf0b6 100644
--- a/kernel/chr_drv/serial.c
+++ b/kernel/chr_drv/serial.c
@@ -235,7 +235,11 @@ static void UART_ISR_proc(async_ISR ISR, int line)
info->timer = jiffies + info->timeout;
if (info->timer < timer_table[RS_TIMER].expires)
timer_table[RS_TIMER].expires = info->timer;
+#ifdef i386
rs_write_active |= 1 << line;
+#else
+ set_bit(line, &rs_write_active);
+#endif
timer_active |= 1 << RS_TIMER;
}
no_xmit:
@@ -328,6 +332,11 @@ static void rs_timer(void)
if ((mask > rs_event) &&
(mask > rs_write_active))
break;
+ if (!info->tty) { /* check that we haven't closed it.. */
+ rs_event &= ~mask;
+ rs_write_active &= ~mask;
+ continue;
+ }
if (mask & rs_event) {
if (!clear_bit(RS_EVENT_READ_PROCESS, &info->event)) {
TTY_READ_FLUSH(info->tty);
@@ -357,7 +366,11 @@ static void rs_timer(void)
}
if (mask & rs_write_active) {
if (info->timer <= jiffies) {
+#ifdef i386
rs_write_active &= ~mask;
+#else
+ clear_bit(info->line, &rs_write_active);
+#endif
rs_write(info->tty);
}
if ((mask & rs_write_active) &&
@@ -405,8 +418,10 @@ static void rs_throttle(struct tty_struct * tty, int status)
struct async_struct *info;
unsigned char mcr;
+#ifdef notdef
printk("throttle tty%d: %d (%d, %d)....\n", DEV_TO_SL(tty->line),
status, LEFT(&tty->read_q), LEFT(&tty->secondary));
+#endif
switch (status) {
case TTY_THROTTLE_RQ_FULL:
info = rs_table + DEV_TO_SL(tty->line);
@@ -460,6 +475,14 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
if (!info->port)
return;
shutdown(info);
+#ifdef i386
+ rs_write_active &= ~(1 << line);
+ rs_event &= ~(1 << line);
+#else
+ clear_bit(line, &rs_write_active);
+ clear_bit(line, &rs_event);
+#endif
+ info->event = 0;
info->tty = 0;
ISR = info->ISR;
irq = ISR->irq;
@@ -556,7 +579,7 @@ void change_speed(unsigned int line)
struct async_struct * info;
unsigned short port;
int quot = 0;
- unsigned cflag,cval;
+ unsigned cflag,cval,mcr;
int i;
if (line >= NR_PORTS)
@@ -589,8 +612,11 @@ void change_speed(unsigned int line)
quot = 0;
info->timeout = 0;
}
- if (!quot) {
- shutdown(info);
+ mcr = inb(UART_MCR + port);
+ if (quot)
+ outb(mcr | UART_MCR_DTR, UART_MCR + port);
+ else {
+ outb(mcr & ~UART_MCR_DTR, UART_MCR + port);
return;
}
/* byte size and parity */
@@ -844,6 +870,7 @@ int rs_open(struct tty_struct *tty, struct file * filp)
IRQ_ISR[irq] = ISR;
}
startup(info);
+ change_speed(info->line);
return 0;
}
@@ -950,8 +977,6 @@ static void init(struct async_struct * info)
}
} else
info->type = PORT_8250;
- startup(info);
- change_speed(info->line);
shutdown(info);
}
diff --git a/kernel/chr_drv/tty_io.c b/kernel/chr_drv/tty_io.c
index 4117fe7..2b25ca4 100644
--- a/kernel/chr_drv/tty_io.c
+++ b/kernel/chr_drv/tty_io.c
@@ -50,7 +50,7 @@ struct termios *tty_termios[256]; /* We need to keep the termios state */
*/
int fg_console = 0;
struct tty_struct * redirect = NULL;
-struct wait_queue * keypress_wait;
+struct wait_queue * keypress_wait = NULL;
int initialize_tty_struct(struct tty_struct *tty, int line);
@@ -545,41 +545,54 @@ static int tty_open(struct inode * inode, struct file * filp)
if (dev < 0)
return -ENODEV;
filp->f_rdev = 0x0400 | dev;
- tty = TTY_TABLE(dev);
- if (!tty) {
- tty = TTY_TABLE(dev) = (struct tty_struct *)
- get_free_page(GFP_KERNEL);
- if (!tty)
- return -ENOMEM;
- retval = initialize_tty_struct(tty, TTY_TABLE_IDX(dev));
- if (retval) {
- free_page((unsigned long)tty);
- return retval;
- }
- if (IS_A_PTY(dev) && !tty_table[PTY_OTHER(dev)]) {
- o_tty = (struct tty_struct *) get_free_page(GFP_USER);
- /*
- * Check for race condition, since get_free_page may sleep.
- */
- if (tty_table[PTY_OTHER(dev)]) {
- free_page((unsigned long) o_tty);
- goto other_done;
- }
- tty_table[PTY_OTHER(dev)] = o_tty;
- if (!o_tty) {
- free_page((unsigned long)tty);
- return -ENOMEM;
- }
- retval = initialize_tty_struct(o_tty, PTY_OTHER(dev));
+/*
+ * There be race-conditions here... Lots of them. Careful now.
+ */
+ tty = o_tty = NULL;
+ if (!TTY_TABLE(dev)) {
+ tty = (struct tty_struct *) get_free_page(GFP_KERNEL);
+ if (tty) {
+ retval = initialize_tty_struct(tty, TTY_TABLE_IDX(dev));
if (retval) {
- free_page((unsigned long) tty);
- free_page((unsigned long) o_tty);
+ free_page((unsigned long)tty);
return retval;
}
- tty->link = o_tty;
- o_tty->link = tty;
}
- other_done:
+ }
+ if (IS_A_PTY(dev)) {
+ if (!tty_table[PTY_OTHER(dev)]) {
+ o_tty = (struct tty_struct *) get_free_page(GFP_KERNEL);
+ if (o_tty) {
+ retval = initialize_tty_struct(o_tty, PTY_OTHER(dev));
+ if (retval) {
+ free_page((unsigned long) tty);
+ free_page((unsigned long) o_tty);
+ return retval;
+ }
+ }
+ }
+ if (!o_tty && !tty_table[PTY_OTHER(dev)]) {
+ free_page((unsigned long) tty);
+ return -ENOMEM;
+ }
+ }
+ if (TTY_TABLE(dev)) {
+ free_page((unsigned long) tty);
+ tty = TTY_TABLE(dev);
+ } else if (tty)
+ TTY_TABLE(dev) = tty;
+ else {
+ free_page((unsigned long) o_tty);
+ return -ENOMEM;
+ }
+ if (IS_A_PTY(dev)) {
+ if (tty_table[PTY_OTHER(dev)]) {
+ free_page((unsigned long) o_tty);
+ o_tty = tty_table[PTY_OTHER(dev)];
+ } else
+ tty_table[PTY_OTHER(dev)] = o_tty;
+ tty->link = o_tty;
+ o_tty->link = tty;
}
if (IS_A_PTY_MASTER(dev)) {
if (tty->count)
@@ -791,11 +804,11 @@ int initialize_tty_struct(struct tty_struct *tty, int line)
tp->c_oflag = OPOST | ONLCR;
tp->c_cflag = B38400 | CS8 | CREAD;
tp->c_lflag = ISIG | ICANON | ECHO | ECHOCTL | ECHOKE;
- } else if IS_A_SERIAL(line) {
+ } else if (IS_A_SERIAL(line)) {
tp->c_cflag = B2400 | CS8 | CREAD | HUPCL;
- } else if IS_A_PTY_MASTER(line) {
+ } else if (IS_A_PTY_MASTER(line)) {
tp->c_cflag = B9600 | CS8 | CREAD;
- } else if IS_A_PTY_SLAVE(line) {
+ } else if (IS_A_PTY_SLAVE(line)) {
tp->c_cflag = B9600 | CS8 | CREAD;
tp->c_lflag = ISIG | ICANON;
}
@@ -820,7 +833,6 @@ long tty_init(long kmem_start)
chrdev_fops[4] = &tty_fops;
chrdev_fops[5] = &tty_fops;
- keypress_wait = 0;
for (i=0 ; i<256 ; i++) {
tty_table[i] = 0;
tty_termios[i] = 0;
diff --git a/kernel/chr_drv/tty_ioctl.c b/kernel/chr_drv/tty_ioctl.c
index 4b2996e..2ecf89f 100644
--- a/kernel/chr_drv/tty_ioctl.c
+++ b/kernel/chr_drv/tty_ioctl.c
@@ -392,6 +392,7 @@ int tty_ioctl(struct inode * inode, struct file * file,
redirect = tty;
return 0;
case FIONBIO:
+ arg = get_fs_long((unsigned long *) arg);
if (arg)
file->f_flags |= O_NONBLOCK;
else
diff --git a/kernel/dma.c b/kernel/dma.c
new file mode 100644
index 0000000..e168383
--- /dev/null
+++ b/kernel/dma.c
@@ -0,0 +1,87 @@
+/* $Header: /sys/linux-0.97/kernel/RCS/dma.c,v 1.4 1992/09/18 02:54:14 root Exp $
+ * linux/kernel/dma.c: A DMA channel allocator. Inspired by linux/kernel/irq.c.
+ * Written by Hennus Bergman, 1992.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <asm/dma.h>
+
+
+/* A note on resource allocation:
+ *
+ * All drivers needing DMA channels, should allocate and release them
+ * through the public routines `request_dma()' and `free_dma()'.
+ *
+ * In order to avoid problems, all processes should allocate resources in
+ * the same sequence and release them in the reverse order.
+ *
+ * So, when allocating DMAs and IRQs, first allocate the IRQ, then the DMA.
+ * When releasing them, first release the DMA, then release the IRQ.
+ * If you don't, you may cause allocation requests to fail unnecessarily.
+ * This doesn't really matter now, but it will once we get real semaphores
+ * in the kernel.
+ */
+
+
+
+/* Channel n is busy iff dma_chan_busy[n] != 0.
+ * DMA0 is reserved for DRAM refresh, I think.
+ * DMA4 is reserved for cascading (?).
+ */
+static volatile unsigned int dma_chan_busy[MAX_DMA_CHANNELS] = {
+ 1, 0, 0, 0, 1, 0, 0, 0
+};
+
+
+
+/* Atomically swap memory location [32 bits] with `newval'.
+ * This avoid the cli()/sti() junk and related problems.
+ * [And it's faster too :-)]
+ * Maybe this should be in include/asm/mutex.h and be used for
+ * implementing kernel-semaphores as well.
+ */
+static unsigned int __inline__ mutex_atomic_swap(volatile unsigned int * p, unsigned int newval)
+{
+ unsigned int semval = newval;
+
+ /* If one of the operands for the XCHG instructions is a memory ref,
+ * it makes the swap an uninterruptible RMW cycle.
+ *
+ * One operand must be in memory, the other in a register, otherwise
+ * the swap may not be atomic.
+ */
+
+ asm __volatile__ ("xchgl %2, %0\n"
+ : /* outputs: semval */ "=r" (semval)
+ : /* inputs: newval, p */ "0" (semval), "m" (*p)
+ ); /* p is a var, containing an address */
+ return semval;
+} /* mutex_atomic_swap */
+
+
+
+int request_dma(unsigned int dmanr)
+{
+ if (dmanr >= MAX_DMA_CHANNELS)
+ return -EINVAL;
+
+ if (mutex_atomic_swap(&dma_chan_busy[dmanr], 1) != 0)
+ return -EBUSY;
+ else
+ /* old flag was 0, now contains 1 to indicate busy */
+ return 0;
+} /* request_dma */
+
+
+void free_dma(unsigned int dmanr)
+{
+ if (dmanr >= MAX_DMA_CHANNELS) {
+ printk("Trying to free DMA%d\n", dmanr);
+ return;
+ }
+
+ if (mutex_atomic_swap(&dma_chan_busy[dmanr], 0) == 0)
+ printk("Trying to free free DMA%d\n", dmanr);
+} /* free_dma */
+
diff --git a/kernel/exit.c b/kernel/exit.c
index 6b7e65e..d7a0891 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -205,30 +205,6 @@ int kill_pg(int pgrp, int sig, int priv)
return(found ? 0 : retval);
}
-/* This routine is used by vhangup. It send's sigkill to everything
- waiting on a particular wait_queue. It assumes root privledges.
- We don't want to destroy the wait queue here, because the caller
- should call wake_up immediately after calling kill_wait. */
-
-void
-kill_wait (struct wait_queue **q, int sig)
-{
- struct wait_queue *next;
- struct wait_queue *tmp;
- struct task_struct *p;
-
- if (!q || !(next = *q))
- return;
- do {
- tmp = next;
- next = tmp->next;
- if (p = tmp->task)
- {
- send_sig (sig, p , 1);
- }
- } while (next && next != *q);
-}
-
int kill_proc(int pid, int sig, int priv)
{
struct task_struct **p;
diff --git a/kernel/sched.c b/kernel/sched.c
index 5d68ca6..dc7677d 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -198,20 +198,19 @@ void wake_one_task(struct task_struct * p)
/*
* wake_up doesn't wake up stopped processes - they have to be awakened
* with signals or similar.
+ *
+ * Note that this doesn't need cli-sti pairs: interrupts may not change
+ * the wait-queue structures directly, but only call wake_up() to wake
+ * a process. The process itself must remove the queue once it has woken.
*/
void wake_up(struct wait_queue **q)
{
- struct wait_queue *tmp, *next;
+ struct wait_queue *tmp;
struct task_struct * p;
- unsigned long flags;
- if (!q || !(next = *q))
+ if (!q || !(tmp = *q))
return;
- save_flags(flags);
- cli();
do {
- tmp = next;
- next = tmp->next;
if (p = tmp->task) {
if (p->state == TASK_ZOMBIE)
printk("wake_up: TASK_ZOMBIE\n");
@@ -221,9 +220,17 @@ void wake_up(struct wait_queue **q)
need_resched = 1;
}
}
- tmp->next = NULL;
- } while (next && next != *q);
- restore_flags(flags);
+#ifdef DEBUG
+ if (!tmp->next) {
+ printk("wait_queue is bad\n");
+ printk(" q = %08x\n",q);
+ printk(" *q = %08x\n",*q);
+ printk(" tmp = %08x\n",tmp);
+ break;
+ }
+#endif
+ tmp = tmp->next;
+ } while (tmp != *q);
}
static inline void __sleep_on(struct wait_queue **p, int state)
@@ -234,12 +241,9 @@ static inline void __sleep_on(struct wait_queue **p, int state)
return;
if (current == task[0])
panic("task[0] trying to sleep");
- if (current->wait.next)
- printk("__sleep_on: wait->next exists\n");
- save_flags(flags);
- cli();
current->state = state;
add_wait_queue(p,&current->wait);
+ save_flags(flags);
sti();
schedule();
remove_wait_queue(p,&current->wait);
diff --git a/kernel/signal.c b/kernel/signal.c
index c5f0dfe..8343267 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -66,26 +66,6 @@ int sys_sigsuspend(int restart, unsigned long old_mask, unsigned long set)
return -ERESTARTNOINTR; /* handle the signal, and come back */
}
-static inline void save_old(char * from,char * to)
-{
- int i;
-
- verify_area(to, sizeof(struct sigaction));
- for (i=0 ; i< sizeof(struct sigaction) ; i++) {
- put_fs_byte(*from,to);
- from++;
- to++;
- }
-}
-
-static inline void get_new(char * from,char * to)
-{
- int i;
-
- for (i=0 ; i< sizeof(struct sigaction) ; i++)
- *(to++) = get_fs_byte(from++);
-}
-
int sys_signal(int signum, long handler, long restorer)
{
struct sigaction tmp;
@@ -104,19 +84,24 @@ int sys_signal(int signum, long handler, long restorer)
int sys_sigaction(int signum, const struct sigaction * action,
struct sigaction * oldaction)
{
- struct sigaction tmp;
+ struct sigaction new, *p;
if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
return -EINVAL;
- tmp = current->sigaction[signum-1];
- get_new((char *) action,
- (char *) (signum-1+current->sigaction));
- if (oldaction)
- save_old((char *) &tmp,(char *) oldaction);
- if (current->sigaction[signum-1].sa_flags & SA_NOMASK)
- current->sigaction[signum-1].sa_mask = 0;
- else
- current->sigaction[signum-1].sa_mask |= (1<<(signum-1));
+ p = signum - 1 + current->sigaction;
+ if (action) {
+ memcpy_fromfs(&new, action, sizeof(struct sigaction));
+ if (new.sa_flags & SA_NOMASK)
+ new.sa_mask = 0;
+ else
+ new.sa_mask |= (1<<(signum-1));
+ }
+ if (oldaction) {
+ verify_area(oldaction, sizeof(struct sigaction));
+ memcpy_tofs(oldaction, p, sizeof(struct sigaction));
+ }
+ if (action)
+ *p = new;
return 0;
}
diff --git a/kernel/sys.c b/kernel/sys.c
index f5cd736..eafed47 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -564,7 +564,7 @@ int sys_sethostname(char *name, int len)
return 0;
}
-int sys_getrlimit(int resource, struct rlimit *rlim)
+int sys_getrlimit(unsigned int resource, struct rlimit *rlim)
{
if (resource >= RLIM_NLIMITS)
return -EINVAL;
@@ -576,7 +576,7 @@ int sys_getrlimit(int resource, struct rlimit *rlim)
return 0;
}
-int sys_setrlimit(int resource, struct rlimit *rlim)
+int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
{
struct rlimit new, *old;
diff --git a/kernel/vsprintf.c b/kernel/vsprintf.c
index 3613e38..03b33c1 100644
--- a/kernel/vsprintf.c
+++ b/kernel/vsprintf.c
@@ -12,6 +12,32 @@
#include <stdarg.h>
#include <linux/types.h>
#include <linux/string.h>
+#include <linux/ctype.h>
+
+unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
+{
+ unsigned long result = 0,value;
+
+ if (!base) {
+ base = 10;
+ if (*cp == '0') {
+ base = 8;
+ cp++;
+ if ((*cp == 'x') && isxdigit(cp[1])) {
+ cp++;
+ base = 16;
+ }
+ }
+ }
+ while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
+ ? toupper(*cp) : *cp)-'A'+10) < base) {
+ result = result*base + value;
+ cp++;
+ }
+ if (endp)
+ *endp = (char *)cp;
+ return result;
+}
/* we use this so that we can do without the ctype library */
#define is_digit(c) ((c) >= '0' && (c) <= '9')
diff --git a/lib/malloc.c b/lib/malloc.c
index e9c5cac..fe0a74c 100644
--- a/lib/malloc.c
+++ b/lib/malloc.c
@@ -55,6 +55,8 @@
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/string.h>
+
#include <asm/system.h>
struct bucket_desc { /* 16 bytes */
@@ -142,6 +144,7 @@ void *malloc(unsigned int len)
printk("malloc called with impossibly large argument (%d)\n", len);
return NULL;
}
+ len = bdir->size;
/*
* Now we search for a bucket descriptor which has free space
*/
@@ -165,7 +168,7 @@ void *malloc(unsigned int len)
bdesc = free_bucket_desc;
free_bucket_desc = bdesc->next;
bdesc->refcnt = 0;
- bdesc->bucket_size = bdir->size;
+ bdesc->bucket_size = len;
bdesc->page = bdesc->freeptr =
(void *) cp = get_free_page(GFP_ATOMIC);
if (!cp) {
@@ -173,9 +176,9 @@ void *malloc(unsigned int len)
return NULL;
}
/* Set up the chain of free objects */
- for (i=PAGE_SIZE/bdir->size; i > 1; i--) {
- *((char **) cp) = cp + bdir->size;
- cp += bdir->size;
+ for (i=PAGE_SIZE/len; i > 1; i--) {
+ *((char **) cp) = cp + len;
+ cp += len;
}
*((char **) cp) = 0;
bdesc->next = bdir->chain; /* OK, link it in! */
@@ -185,6 +188,7 @@ void *malloc(unsigned int len)
bdesc->freeptr = *((void **) retval);
bdesc->refcnt++;
sti(); /* OK, we're safe again */
+ memset(retval, 0, len);
return retval;
}
diff --git a/mm/memory.c b/mm/memory.c
index 3c56e16..6512d7f 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -739,6 +739,10 @@ void do_no_page(unsigned long error_code, unsigned long address,
nr[i] = bmap(inode,block);
bread_page(page,inode->i_dev,nr);
}
+ if (share_page(tsk,inode,address)) {
+ free_page(page);
+ return;
+ }
i = address + PAGE_SIZE - tsk->end_data;
if (i > PAGE_SIZE-1)
i = 0;
diff --git a/net/tcp/arp.c b/net/tcp/arp.c
index ad3a7dc..1b2578f 100644
--- a/net/tcp/arp.c
+++ b/net/tcp/arp.c
@@ -286,10 +286,10 @@ create_arp (unsigned long paddr, unsigned char *addr, int hlen)
apt->hlen =hlen;
memcpy (apt->hard, addr, hlen);
apt->last_used=timer_seq;
- sti();
- apt->next = arp_table[hash];
- arp_table[hash]=apt;
cli();
+ apt->next = arp_table[hash];
+ arp_table[hash] = apt;
+ sti();
return (apt);
}
@@ -439,7 +439,6 @@ arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
return (1);
}
-
void
arp_add (unsigned long addr, unsigned char *haddr, struct device *dev)
{
@@ -461,7 +460,6 @@ arp_add_broad (unsigned long addr, struct device *dev)
arp_add (addr, dev->broadcast , dev);
}
-
void
arp_queue(struct sk_buff *skb)
{
@@ -473,13 +471,11 @@ arp_queue(struct sk_buff *skb)
skb->prev = skb;
}
else
- {
- skb->next = arp_q;
- skb->prev = arp_q->prev;
- skb->next->prev = skb;
- skb->prev->next = skb;
- }
- sti();
-
+ {
+ skb->next = arp_q;
+ skb->prev = arp_q->prev;
+ skb->next->prev = skb;
+ skb->prev->next = skb;
+ }
+ sti();
}
-
diff --git a/net/tcp/dev.c b/net/tcp/dev.c
index 3fd6305..4c96076 100644
--- a/net/tcp/dev.c
+++ b/net/tcp/dev.c
@@ -29,7 +29,6 @@
#include <linux/mm.h>
#include <linux/socket.h>
#include <netinet/in.h>
-#include <asm/memory.h>
#include "dev.h"
#include "eth.h"
#include "timer.h"
diff --git a/net/tcp/eth.c b/net/tcp/eth.c
index 3e6fccd..cfa9220 100644
--- a/net/tcp/eth.c
+++ b/net/tcp/eth.c
@@ -29,7 +29,6 @@
#include <linux/mm.h>
#include <linux/socket.h>
#include <netinet/in.h>
-#include <asm/memory.h>
#include "dev.h"
#include "eth.h"
#include "timer.h"
diff --git a/net/tcp/loopback.c b/net/tcp/loopback.c
index d9f8b4a..163a2d8 100644
--- a/net/tcp/loopback.c
+++ b/net/tcp/loopback.c
@@ -26,10 +26,10 @@
#include <linux/tty.h>
#include <linux/types.h>
#include <linux/ptrace.h>
+#include <linux/string.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/io.h>
-#include <asm/memory.h>
#include <errno.h>
#include <linux/fcntl.h>
#include <netinet/in.h>
diff --git a/net/tcp/sock.c b/net/tcp/sock.c
index 0f4b8ca..ad570f7 100644
--- a/net/tcp/sock.c
+++ b/net/tcp/sock.c
@@ -26,8 +26,8 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/timer.h>
+#include <linux/string.h>
#include <linux/sock_ioctl.h>
-#include <asm/memory.h>
#include "../kern_sock.h"
#include "timer.h"
#include "ip.h"
@@ -124,6 +124,10 @@ struct proto_ops inet_proto_ops =
void
print_sk (volatile struct sock *sk)
{
+ if (!sk) {
+ PRINTK (" print_sk(NULL)\n");
+ return;
+ }
PRINTK (" wmem_alloc = %d\n", sk->wmem_alloc);
PRINTK (" rmem_alloc = %d\n", sk->rmem_alloc);
PRINTK (" send_head = %X\n", sk->send_head);
@@ -149,6 +153,10 @@ print_sk (volatile struct sock *sk)
void
print_skb(struct sk_buff *skb)
{
+ if (!skb) {
+ PRINTK (" print_skb(NULL)\n");
+ return;
+ }
PRINTK (" prev = %X, next = %X\n", skb->prev, skb->next);
PRINTK (" sk = %X link3 = %X\n", skb->sk, skb->link3);
PRINTK (" mem_addr = %X, mem_len = %d\n", skb->mem_addr, skb->mem_len);
@@ -332,27 +340,41 @@ remove_sock(volatile struct sock *sk1)
volatile struct sock *sk2;
PRINTK ("remove_sock(sk1=%X)\n",sk1);
+ if (!sk1)
+ {
+ printk ("sock.c: remove_sock: sk1 == NULL\n");
+ return;
+ }
+
+ if (!sk1->prot)
+ {
+ printk ("sock.c: remove_sock: sk1->prot == NULL\n");
+ return;
+ }
+
/* we can't have this changing out from under us. */
cli();
- sk2=sk1->prot->sock_array[sk1->num & (SOCK_ARRAY_SIZE -1)];
+ sk2 = sk1->prot->sock_array[sk1->num & (SOCK_ARRAY_SIZE -1)];
if (sk2 == sk1)
{
sk1->prot->sock_array[sk1->num & (SOCK_ARRAY_SIZE -1)] = sk1->next;
sti();
return;
}
- while (sk2->next != sk1)
+
+ while (sk2 && sk2->next != sk1)
+ sk2 = sk2->next;
+
+ if (sk2)
{
- if (sk2 == NULL)
- {
- sti();
- PRINTK ("remove_sock: sock not found.\n");
- return;
- }
- sk2=sk2->next;
+ sk2->next = sk1->next;
+ sti();
+ return;
}
- sk2->next = sk1->next;
sti();
+
+ if (sk1->num != 0)
+ PRINTK ("remove_sock: sock not found.\n");
}
void
@@ -1718,6 +1740,18 @@ volatile struct sock *get_sock (struct proto *prot, unsigned short num,
void release_sock (volatile struct sock *sk)
{
+ if (!sk)
+ {
+ printk ("sock.c: release_sock sk == NULL\n");
+ return;
+ }
+
+ if (!sk->prot)
+ {
+ printk ("sock.c: release_sock sk->prot == NULL\n");
+ return;
+ }
+
if (sk->blog) return;
/* see if we have any packets built up. */
diff --git a/net/tcp/tcp.c b/net/tcp/tcp.c
index 65c2331..ef31011 100644
--- a/net/tcp/tcp.c
+++ b/net/tcp/tcp.c
@@ -23,7 +23,7 @@
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/mm.h>
-#include <asm/memory.h>
+#include <linux/string.h>
#include <linux/socket.h>
#include <netinet/in.h>
#include <linux/fcntl.h>
@@ -2101,7 +2101,31 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
struct tcp_header *th;
volatile struct sock *sk;
+ if (!skb)
+ {
+ printk ("tcp.c: tcp_rcv skb = NULL\n");
+ return (0);
+ }
+#if 0 /* it's ok for protocol to be NULL */
+ if (!protocol)
+ {
+ printk ("tcp.c: tcp_rcv protocol = NULL\n");
+ return (0);
+ }
+
+ if (!opt) /* it's ok for opt to be NULL */
+ {
+ printk ("tcp.c: tcp_rcv opt = NULL\n");
+ }
+#endif
+ if (!dev)
+ {
+ printk ("tcp.c: tcp_rcv dev = NULL\n");
+ return (0);
+ }
+
th = skb->h.th;
+
/* find the socket. */
sk=get_sock(&tcp_prot, net16(th->dest), saddr, th->source, daddr);
PRINTK("<<\n");
@@ -2168,6 +2192,20 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
}
sk->inuse = 1;
sti();
+ }
+ else
+ {
+ if (!sk)
+ {
+ printk ("tcp.c: tcp_rcv bug sk=NULL redo = 1\n");
+ return (0);
+ }
+ }
+
+ if (!sk->prot)
+ {
+ printk ("tcp.c: tcp_rcv sk->prot = NULL \n");
+ return (0);
}
/* charge the memory to the socket. */
@@ -2214,6 +2252,7 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
release_sock(sk);
return (0);
}
+
if (th->rst)
{
sk->err = ECONNRESET;
@@ -2226,8 +2265,7 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
release_sock(sk);
return (0);
}
-
- if (opt->security != 0 || opt->compartment != 0 || th->syn)
+ if (opt && (opt->security != 0 || opt->compartment != 0 || th->syn))
{
sk->err = ECONNRESET;
sk->state = TCP_CLOSE;
diff --git a/net/tcp/udp.c b/net/tcp/udp.c
index 0dcecba..99fc5d7 100644
--- a/net/tcp/udp.c
+++ b/net/tcp/udp.c
@@ -567,13 +567,15 @@ udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
sk = get_sock (prot, net16(uh->dest), saddr, uh->source, daddr);
/* if we don't know about the socket, forget about it. */
- if (sk == NULL &&
- (daddr & 0xff000000 != 0) && (daddr & 0xff000000 != 0xff000000))
+ if (sk == NULL)
{
- icmp_reply (skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, dev);
- skb->sk = NULL;
- free_skb (skb, 0);
- return (0);
+ if ((daddr & 0xff000000 != 0) && (daddr & 0xff000000 != 0xff000000))
+ {
+ icmp_reply (skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, dev);
+ }
+ skb->sk = NULL;
+ free_skb (skb, 0);
+ return (0);
}
diff --git a/net/tcp/we.c b/net/tcp/we.c
index 58b8208..6e1617d 100644
--- a/net/tcp/we.c
+++ b/net/tcp/we.c
@@ -51,10 +51,10 @@
#include <linux/tty.h>
#include <linux/types.h>
#include <linux/ptrace.h>
+#include <linux/string.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/io.h>
-#include <asm/memory.h>
#include <errno.h>
#include <linux/fcntl.h>
#include <netinet/in.h>