Commit c6af1a5c authored by Linus Torvalds's avatar Linus Torvalds

[PATCH] Linux-0.98.3 (October 27, 1992)

More networking updates.. Ross Biro is still struggling with net-1.

Michael Johnson (now RH kernel release manager) works on line printer
driver.

Locking function cleanups (for inodes, superblocks, buffer heads).  We
also now pass in the superblock pointer instead of the device number to
the filesystem routines.  That cleans up use and locking of
"get_super()" a lot.

[Original announcement below]

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
parent c96bf123
......@@ -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
......
......@@ -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 :-) */
......
!
! 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:
......
......@@ -7,9 +7,7 @@
/*
* 'buffer.c' implements the buffer-cache functions. Race-conditions have
* been avoided by NEVER letting a interrupt change a buffer (except for the
* data, of course), but instead letting the caller do it. NOTE! As interrupts
* can wake up a caller, some cli-sti sequences are needed to check for
* sleep-on-calls. These should be extremely quick, though (I hope).
* data, of course), but instead letting the caller do it.
*/
/*
......@@ -24,6 +22,7 @@
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/locks.h>
#include <asm/system.h>
#include <asm/io.h>
......@@ -46,15 +45,29 @@ static struct wait_queue * buffer_wait = NULL;
int nr_buffers = 0;
int nr_buffer_heads = 0;
static inline void wait_on_buffer(struct buffer_head * bh)
/*
* Rewrote the wait-routines to use the "new" wait-queue functionality,
* and getting rid of the cli-sti pairs. The wait-queue routines still
* need cli-sti, but now it's just a couple of 386 instructions or so.
*
* Note that the real wait_on_buffer() is an inline function that checks
* if 'b_wait' is set before calling this, so that the queues aren't set
* up unnecessarily.
*/
void __wait_on_buffer(struct buffer_head * bh)
{
cli();
while (bh->b_lock)
sleep_on(&bh->b_wait);
sti();
add_wait_queue(&bh->b_wait,&current->wait);
repeat:
current->state = TASK_UNINTERRUPTIBLE;
if (bh->b_lock) {
schedule();
goto repeat;
}
remove_wait_queue(&bh->b_wait,&current->wait);
current->state = TASK_RUNNING;
}
static void sync_buffers(int dev)
static void sync_buffers(dev_t dev)
{
int i;
struct buffer_head * bh;
......@@ -69,35 +82,21 @@ static void sync_buffers(int dev)
}
}
int sys_sync(void)
void sync_dev(dev_t dev)
{
int i;
for (i=0 ; i<NR_SUPER ; i++)
if (super_block[i].s_dev
&& super_block[i].s_op
&& super_block[i].s_op->write_super
&& super_block[i].s_dirt)
super_block[i].s_op->write_super(&super_block[i]);
sync_inodes(); /* write out inodes into buffers */
sync_buffers(0);
return 0;
sync_buffers(dev);
sync_supers(dev);
sync_inodes(dev);
sync_buffers(dev);
}
int sync_dev(int dev)
int sys_sync(void)
{
struct super_block * sb;
if (sb = get_super (dev))
if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
sb->s_op->write_super (sb);
sync_buffers(dev);
sync_inodes();
sync_buffers(dev);
sync_dev(0);
return 0;
}
void invalidate_buffers(int dev)
void invalidate_buffers(dev_t dev)
{
int i;
struct buffer_head * bh;
......@@ -126,7 +125,7 @@ void invalidate_buffers(int dev)
* and that mount/open needn't know that floppies/whatever are
* special.
*/
void check_disk_change(int dev)
void check_disk_change(dev_t dev)
{
int i;
struct buffer_head * bh;
......@@ -251,7 +250,7 @@ static inline void insert_into_queues(struct buffer_head * bh)
bh->b_next->b_prev = bh;
}
static struct buffer_head * find_buffer(int dev, int block, int size)
static struct buffer_head * find_buffer(dev_t dev, int block, int size)
{
struct buffer_head * tmp;
......@@ -273,7 +272,7 @@ static struct buffer_head * find_buffer(int dev, int block, int size)
* will force it bad). This shouldn't really happen currently, but
* the code is ready.
*/
struct buffer_head * get_hash_table(int dev, int block, int size)
struct buffer_head * get_hash_table(dev_t dev, int block, int size)
{
struct buffer_head * bh;
......@@ -301,7 +300,7 @@ struct buffer_head * get_hash_table(int dev, int block, int size)
* when the filesystem starts to get full of dirty blocks (I hope).
*/
#define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock)
struct buffer_head * getblk(int dev, int block, int size)
struct buffer_head * getblk(dev_t dev, int block, int size)
{
struct buffer_head * bh, * tmp;
int buffers;
......@@ -377,7 +376,7 @@ void brelse(struct buffer_head * buf)
* bread() reads a specified block and returns the buffer that contains
* it. It returns NULL if the block was unreadable.
*/
struct buffer_head * bread(int dev, int block, int size)
struct buffer_head * bread(dev_t dev, int block, int size)
{
struct buffer_head * bh;
......@@ -408,7 +407,7 @@ __asm__("cld\n\t" \
* all at the same time, not waiting for one to be read, and then another
* etc.
*/
void bread_page(unsigned long address,int dev,int b[4])
void bread_page(unsigned long address, dev_t dev, int b[4])
{
struct buffer_head * bh[4];
int i;
......@@ -434,7 +433,7 @@ void bread_page(unsigned long address,int dev,int b[4])
* blocks for reading as well. End the argument list with a negative
* number.
*/
struct buffer_head * breada(int dev,int first, ...)
struct buffer_head * breada(dev_t dev,int first, ...)
{
va_list args;
struct buffer_head * bh, *tmp;
......
......@@ -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);
......
......@@ -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;
......
......@@ -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 @@ static struct buffer_head * inode_getblk(struct inode * inode, int nr, int creat
}
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 @@ static struct buffer_head * inode_getblk(struct inode * inode, int nr, int creat
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 @@ static struct buffer_head * block_getblk(struct buffer_head * bh, int nr, int cr
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)
......
......@@ -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 @@ static int do_ext_rename(struct inode * old_dir, const char * old_name, int old_
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 @@ static int do_ext_rename(struct inode * old_dir, const char * old_name, int old_
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;
......
......@@ -56,7 +56,7 @@ static int trunc_direct(struct inode * inode)
*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 @@ static int trunc_indirect(struct inode * inode, int offset, unsigned long * p)
*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 @@ static int trunc_indirect(struct inode * inode, int offset, unsigned long * p)
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 @@ static int trunc_dindirect(struct inode * inode, int offset, unsigned long * p)
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 @@ static int trunc_tindirect(struct inode * inode)
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,&current->wait);
repeat:
current->state = TASK_UNINTERRUPTIBLE;
if (inode->i_lock) {
schedule();
goto repeat;
}
remove_wait_queue(&inode->i_wait,&current->wait);
current->state = TASK_RUNNING;
}
static inline void wait_on_inode(struct inode * inode)
{
cli();
while (inode->i_lock)
sleep_on(&inode->i_wait);
sti();
if (inode->i_lock)
__wait_on_inode(inode);
}
static inline void lock_inode(struct inode * inode)
{
cli();
while (inode->i_lock)
sleep_on(&inode->i_wait);
inode->i_lock=1;
sti();
wait_on_inode(inode);
inode->i_lock = 1;
}
static inline void unlock_inode(struct inode * inode)
{
inode->i_lock=0;
inode->i_lock = 0;
wake_up(&inode->i_wait);
}
......@@ -41,8 +87,8 @@ static void write_inode(struct inode * inode)
{
if (!inode->i_dirt)
return;
inode->i_dirt = 0;
lock_inode(inode);
inode->i_dirt = 0;
if (inode->i_dev && inode->i_sb &&
inode->i_sb->s_op && inode->i_sb->s_op->write_inode)
inode->i_sb->s_op->write_inode(inode);
......@@ -74,7 +120,7 @@ int bmap(struct inode * inode, int block)
return 0;
}
void invalidate_inodes(int dev)
void invalidate_inodes(dev_t dev)
{
int i;
struct inode * inode;
......@@ -92,7 +138,7 @@ void invalidate_inodes(int dev)
}
}
void sync_inodes(void)
void sync_inodes(dev_t dev)
{
int i;
struct inode * inode;
......@@ -134,11 +180,10 @@ void iput(struct inode * inode)
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;
}
......@@ -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 @@ int minix_new_block(int dev)
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;
......
......@@ -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);
......
......@@ -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 @@ static struct buffer_head * inode_getblk(struct inode * inode, int nr, int creat
}
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 @@ static struct buffer_head * inode_getblk(struct inode * inode, int nr, int creat
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 @@ static struct buffer_head * block_getblk(struct buffer_head * bh, int nr, int cr
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)
......
......@@ -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 @@ static int do_minix_rename(struct inode * old_dir, const char * old_name, int ol
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 @@ static int do_minix_rename(struct inode * old_dir, const char * old_name, int ol
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;
......
......@@ -50,7 +50,7 @@ static int trunc_direct(struct inode * inode)
*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 @@ static int trunc_indirect(struct inode * inode, int offset, unsigned short * p)
*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 @@ static int trunc_indirect(struct inode * inode, int offset, unsigned short * p)
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 @@ static int trunc_dindirect(struct inode * inode)
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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
}
......
......@@ -418,6 +418,28 @@ int sys_close(unsigned int fd)
return (close_fp (filp));
}
/*
* 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
......@@ -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;
}
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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,&current->wait);
repeat:
current->state = TASK_UNINTERRUPTIBLE;
if (sb->s_lock) {
schedule();
goto repeat;
}
remove_wait_queue(&sb->s_wait,&current->wait);
current->state = TASK_RUNNING;
}
void free_super(struct super_block * sb)
void sync_supers(dev_t dev)
{
sb->s_lock = 0;
wake_up(&(sb->s_wait));
}
struct super_block * sb;
void wait_on_super(struct super_block * sb)
{
cli();
while (sb->s_lock)
sleep_on(&(sb->s_wait));
sti();
for (sb = super_block + 0 ; sb < super_block + NR_SUPER ; sb++) {
if (!sb->s_dev)
continue;
wait_on_super(sb);
if (!sb->s_dev || !sb->s_dirt)
continue;
if (dev && (dev != sb->s_dev))
continue;
if (sb->s_op && sb->s_op->write_super)
sb->s_op->write_super(sb);
}
}
struct super_block * get_super(int dev)
static struct super_block * get_super(dev_t dev)
{
struct super_block * s;
......@@ -97,7 +104,7 @@ struct super_block * get_super(int dev)
return NULL;
}
void put_super(int dev)
void put_super(dev_t dev)
{
struct super_block * sb;
......@@ -115,7 +122,7 @@ void put_super(int dev)
sb->s_op->put_super(sb);
}
static struct super_block * read_super(int dev,char *name,int flags,void *data)
static struct super_block * read_super(dev_t dev,char *name,int flags,void *data)
{
struct super_block * s;
struct file_system_type *type;
......@@ -148,10 +155,9 @@ static struct super_block * read_super(int dev,char *name,int flags,void *data)
return s;
}
static int do_umount(int dev)
static int do_umount(dev_t dev)
{
struct super_block * sb;
struct inode * inode;
if (dev==ROOT_DEV)
return -EBUSY;
......@@ -159,12 +165,8 @@ static int do_umount(int dev)
return -ENOENT;
if (!sb->s_covered->i_mount)
printk("Mounted inode has i_mount=0\n");
for (inode = inode_table+0 ; inode < inode_table+NR_INODE ; inode++)
if (inode->i_dev==dev && inode->i_count)
if (inode == sb->s_mounted && inode->i_count == 1)
continue;
else
return -EBUSY;
if (!fs_may_umount(dev, sb->s_mounted))
return -EBUSY;
sb->s_covered->i_mount=0;
iput(sb->s_covered);
sb->s_covered = NULL;
......@@ -172,7 +174,7 @@ static int do_umount(int dev)
sb->s_mounted = NULL;
if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
sb->s_op->write_super (sb);
put_super(dev);
put_super(dev);
return 0;
}
......@@ -191,13 +193,21 @@ int sys_umount(char * dev_name)
iput(inode);
return -ENOTBLK;
}
if (IS_NODEV(inode)) {
iput(inode);
return -EACCES;
}
if (MAJOR(dev) >= MAX_BLKDEV) {
iput(inode);
return -ENODEV;
}
retval = do_umount(dev);
if (!retval && MAJOR(dev) < MAX_BLKDEV &&
blkdev_fops[MAJOR(dev)]->release)
if (!retval && blkdev_fops[MAJOR(dev)] && blkdev_fops[MAJOR(dev)]->release)
blkdev_fops[MAJOR(dev)]->release(inode,NULL);
iput(inode);
if (retval) return retval;
sync_dev(dev);
if (retval)
return retval;
sync_dev(dev);
return 0;
}
......@@ -210,9 +220,9 @@ int sys_umount(char * dev_name)
* We also have to flush all inode-data for this device, as the new mount
* might need new info.
*/
static int do_mount(int dev, const char * dir, char * type, int flags, void * data)
static int do_mount(dev_t dev, const char * dir, char * type, int flags, void * data)
{
struct inode * inode, * dir_i;
struct inode * dir_i;
struct super_block * sb;
int error;
......@@ -227,14 +237,9 @@ static int do_mount(int dev, const char * dir, char * type, int flags, void * da
iput(dir_i);
return -EPERM;
}
for (inode = inode_table+0 ; inode < inode_table+NR_INODE ; inode++) {
if (inode->i_dev != dev)
continue;
if (inode->i_count || inode->i_dirt || inode->i_lock) {
iput(dir_i);
return -EBUSY;
}
inode->i_dev = 0;
if (!fs_may_mount(dev)) {
iput(dir_i);
return -EBUSY;
}
sb = read_super(dev,type,flags,data);
if (!sb || sb->s_covered) {
......@@ -263,6 +268,7 @@ int sys_mount(char * dev_name, char * dir_name, char * type,
unsigned long new_flags, void *data)
{
struct inode * inode;
struct file_operations * fops;
int dev;
int retval;
char tmp[100],*t;
......@@ -272,19 +278,27 @@ int sys_mount(char * dev_name, char * dir_name, char * type,
if (!suser())
return -EPERM;
retval = namei(dev_name,&inode);
if (retval)
if (retval = namei(dev_name,&inode))
return retval;
dev = inode->i_rdev;
if (!S_ISBLK(inode->i_mode))
retval = -EPERM;
else if (IS_NODEV(inode))
retval = -EACCES;
if (!retval && blkdev_fops[MAJOR(dev)]->open)
retval = blkdev_fops[MAJOR(dev)]->open(inode,NULL);
if (retval) {
if (!S_ISBLK(inode->i_mode)) {
iput(inode);
return retval;
return -ENOTBLK;
}
if (IS_NODEV(inode)) {
iput(inode);
return -EACCES;
}
if (MAJOR(dev) >= MAX_BLKDEV) {
iput(inode);
return -ENODEV;
}
fops = blkdev_fops[MAJOR(dev)];
if (fops && fops->open) {
if (retval = fops->open(inode,NULL)) {
iput(inode);
return retval;
}
}
if ((new_flags & 0xffff0000) == 0xC0ED0000) {
flags = new_flags & 0xffff;
......@@ -306,8 +320,8 @@ int sys_mount(char * dev_name, char * dir_name, char * type,
t = "minix";
retval = do_mount(dev,dir_name,t,flags,(void *) page);
free_page(page);
if (retval && blkdev_fops[MAJOR(dev)]->release)
blkdev_fops[MAJOR(dev)]->release(inode,NULL);
if (retval && fops && fops->release)
fops->release(inode,NULL);
iput(inode);
return retval;
}
......
/* $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 */
......@@ -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"
......
......@@ -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
......
......@@ -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);
......
......@@ -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);
......
......@@ -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);
......
#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 */
#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 @@
/*
* 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 @@
#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
......
......@@ -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);
......
......@@ -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++;
}
......
#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)
......
......@@ -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
*/
......@@ -89,6 +81,16 @@ static int sprintf(char * str, const char *fmt, ...)
#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC)
#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
......@@ -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();
......
......@@ -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:
......
......@@ -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)
{
......
......@@ -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));
......
......@@ -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))
......
......@@ -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 */
......
......@@ -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:
/*------------------------------+
......
......@@ -8,5 +8,5 @@
| |
+---------------------------------------------------------------------------*/
#define FPU_VERSION "wm-FPU-emu version ALPHA 0.5"
#define FPU_VERSION "wm-FPU-emu version ALPHA 0.61"
......@@ -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
......
......@@ -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);
}
......
This diff is collapsed.
......@@ -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 @@ void ll_rw_page(int rw, int dev, int page, char * buffer)
req->nr_sectors = 8;
req->current_nr_sectors = 8;
req->buffer = buffer;
req->waiting = &current->wait;
req->waiting = current;
req->bh = NULL;
req->next = NULL;
current->state = TASK_UNINTERRUPTIBLE;
......@@ -284,24 +268,6 @@ void ll_rw_block(int rw, struct buffer_head * bh)
make_request(major,rw,bh);
}
long blk_dev_init(long mem_start, long mem_end)
{
int i;
for (i=0 ; i<NR_REQUEST ; i++) {
request[i].dev = -1;
request[i].next = NULL;
}
memset(ro_bits,0,sizeof(ro_bits));
#ifdef CONFIG_BLK_DEV_HD
mem_start = hd_init(mem_start,mem_end);
#endif
#ifdef RAMDISK
mem_start += rd_init(mem_start, RAMDISK*1024);
#endif
return mem_start;
}
void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf)
{
int i;
......@@ -341,7 +307,7 @@ void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf)
req->nr_sectors = 2;
req->current_nr_sectors = 2;
req->buffer = buf;
req->waiting = &current->wait;
req->waiting = current;
req->bh = NULL;
req->next = NULL;
current->state = TASK_UNINTERRUPTIBLE;
......@@ -349,3 +315,21 @@ void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf)
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;
}
......@@ -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"
......
......@@ -133,5 +133,5 @@ int wd7000fasst_reset(void);
wd7000fasst_queuecommand, \
wd7000fasst_abort, \
wd7000fasst_reset, \
1, 7, 0}
1, 7, 0, 1}
#endif
......@@ -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};
......
......@@ -135,5 +135,5 @@ int aha1542_reset(void);
aha1542_queuecommand, \
aha1542_abort, \
aha1542_reset, \
1, 7, 0}
1, 7, 0, 1}
#endif
......@@ -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
......@@ -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;
/*
......
......@@ -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
......
......@@ -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
......
......@@ -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 :
......
......@@ -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 @@ static void do_sd_request (void)
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 @@ static void do_sd_request (void)
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;
......
......@@ -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)
......
......@@ -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
......
......@@ -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
......
......@@ -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)
......
......@@ -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
......@@ -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
......@@ -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
......
......@@ -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();
......
/*
$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
};
......
......@@ -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;
}
......
......@@ -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);
}
......
......@@ -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;
......
......@@ -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
......
/* $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 */
......@@ -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;
......
......@@ -198,20 +198,19 @@ void wake_one_task(struct task_struct * p)
/*
* wake_up doesn't wake up stopped processes - they have to be awakened
* with signals or similar.
*
* Note that this doesn't need cli-sti pairs: interrupts may not change
* the wait-queue structures directly, but only call wake_up() to wake
* a process. The process itself must remove the queue once it has woken.
*/
void wake_up(struct wait_queue **q)
{
struct wait_queue *tmp, *next;
struct wait_queue *tmp;
struct task_struct * p;
unsigned long flags;
if (!q || !(next = *q))
if (!q || !(tmp = *q))
return;
save_flags(flags);
cli();
do {
tmp = next;
next = tmp->next;
if (p = tmp->task) {
if (p->state == TASK_ZOMBIE)
printk("wake_up: TASK_ZOMBIE\n");
......@@ -221,9 +220,17 @@ void wake_up(struct wait_queue **q)
need_resched = 1;
}
}
tmp->next = NULL;
} while (next && next != *q);
restore_flags(flags);
#ifdef DEBUG
if (!tmp->next) {
printk("wait_queue is bad\n");
printk(" q = %08x\n",q);
printk(" *q = %08x\n",*q);
printk(" tmp = %08x\n",tmp);
break;
}
#endif
tmp = tmp->next;
} while (tmp != *q);
}
static inline void __sleep_on(struct wait_queue **p, int state)
......@@ -234,12 +241,9 @@ static inline void __sleep_on(struct wait_queue **p, int state)
return;
if (current == task[0])
panic("task[0] trying to sleep");
if (current->wait.next)
printk("__sleep_on: wait->next exists\n");
save_flags(flags);
cli();
current->state = state;
add_wait_queue(p,&current->wait);
save_flags(flags);
sti();
schedule();
remove_wait_queue(p,&current->wait);
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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')
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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();
}
......@@ -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"
......
......@@ -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"
......
......@@ -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>
......
......@@ -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. */
......
This diff is collapsed.
......@@ -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);
}
......
......@@ -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>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment