diff options
author | Linus Torvalds <torvalds@klaava.Helsinki.FI> | 1992-10-27 19:49:52 +0000 |
---|---|---|
committer | Nicolas Pitre <nico@cam.org> | 2007-08-19 14:19:09 -0400 |
commit | 73795752dade564a88db44bdcfd7c5a946322de1 (patch) | |
tree | 7503515d32b5104c3c20fb6710ff69e167980e07 | |
parent | 4c212a02429139af48301686ce7cd24ce1a0b47f (diff) | |
download | archive-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
87 files changed, 1679 insertions, 950 deletions
@@ -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,¤t->wait); +repeat: + current->state = TASK_UNINTERRUPTIBLE; + if (bh->b_lock) { + schedule(); + goto repeat; + } + remove_wait_queue(&bh->b_wait,¤t->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; @@ -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,¤t->wait); +repeat: + current->state = TASK_UNINTERRUPTIBLE; + if (inode->i_lock) { + schedule(); + goto repeat; + } + remove_wait_queue(&inode->i_wait,¤t->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; @@ -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; } @@ -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; } @@ -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,¤t->wait); +repeat: + current->state = TASK_UNINTERRUPTIBLE; + if (sb->s_lock) { + schedule(); + goto repeat; + } + remove_wait_queue(&sb->s_wait,¤t->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 = ¤t->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 = ¤t->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,¤t->wait); + save_flags(flags); sti(); schedule(); remove_wait_queue(p,¤t->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> |