Commit a2858ced authored by Linus Torvalds's avatar Linus Torvalds

[PATCH] Linux-0.99.8 (April 8, 1993)

Mount root filesystem read-only (conditional for now).

SCSI updates.

Stephen Tweedie shows up in ext2, with an enhanced block allocator.

Signal handling update with generated code on the stack and a
"sigreturn" system call.  This was needed to maintain compatibility in
the face of a changed stack layout.  sigsuspend() also works correctly now.

[original announcement below]

Yet another kernel release is now available on nic.funet.fi in the usual
place (pub/OS/Linux/PEOPLE/Linus for those of you that have already
forgotten), and will probably show up on the other ftp-sites within a
day or two.  There are two new files:

 linux-0.99.8.tar.z - the full gzipped and tarred source-tree of the
   linux kernel.

 linux-0.99.patch8.z - unified diffs against the last official release
   (0.99pl7).

There is no SLIP or new networking routines in this kernel despite the
rumors that have been flying around - the main changes to 0.99.7 are
(some of them were in 0.99pl7A as well):

- the signal handling code has been extensively reworked, and should be
  POSIX as well as clean.
- dosfs is upgraded to version 12 (Werner Almesberger)
- xiafs is upgraded to the latest version (Qi Xia)
- ext2fs is upgraded to the latest version (Remy Card/Stephen Tweedie)
- FPU-emulation patches for v86 mode and precision rounding (Bill
  Metzenthen)
- SCSI patches by various people (Eric Youngdale & co)
- XT harddisk support (Pat Mackinlay)
- new trial code to try to handle 387 lockups on some systems more
  gracefully.
- keyboard, lp and serial driver fixes
- various minor changes (mounting root read-only, bootup messages
  cleaned up etc)

As always, comments/bugs etc are encouraged,

            Linus
parent 5b726c10
......@@ -4,6 +4,7 @@
# It's a fast hack - feel free to do something better.
CONFIG=.config~
CONFIG_H=include/linux/autoconf.h
> config.new
echo "#" > $CONFIG
echo "# Automatically generated make config: don't edit" >> $CONFIG
echo "#" >> $CONFIG
......@@ -17,6 +18,7 @@ old="y"
while read i
do
echo $i >> config.new
echo >> $CONFIG
echo >> $CONFIG_H
echo
......@@ -29,11 +31,13 @@ do
echo " * "$i >> $CONFIG_H
echo "**" $i
read i || break
echo $i >> config.new
done
echo "#" >> $CONFIG
echo " */" >> $CONFIG_H
echo "**"
read i || break
echo $i >> config.new
while [ "$i" != "." -a "$i" != ":" ]
do
read j ques def || break
......@@ -49,6 +53,7 @@ do
ans=$def
fi
fi
echo $j $ques $ans >> config.new
if [ "$ans" = "y" ]
then
echo $j = $j >> $CONFIG
......@@ -56,6 +61,7 @@ do
next="y";
fi
read i || break
echo $i >> config.new
done
old=$next
next="y"
......@@ -65,6 +71,8 @@ do
fi
done
mv config.new config.in
echo
echo "The linux kernel is now hopefully configured for your setup."
echo "Check the top-level Makefile for additional configuration,"
......
......@@ -139,7 +139,7 @@ tools/./version.h: tools/version.h
tools/version.h: $(CONFIGURE) Makefile
@./makever.sh
@echo \#define UTS_RELEASE \"0.99.pl7A-`cat .version`\" > tools/version.h
@echo \#define UTS_RELEASE \"0.99.pl8-`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
......
......@@ -45,6 +45,9 @@ SWAP_DEV = 0
#ifndef RAMDISK
#define RAMDISK 0
#endif
#ifndef CONFIG_ROOT_RDONLY
#define CONFIG_ROOT_RDONLY 0
#endif
! ld86 requires an entry symbol. This may as well be the usual one.
.globl _main
......@@ -429,7 +432,9 @@ msg1:
.byte 13,10
.ascii "Loading"
.org 500
.org 498
root_flags:
.word CONFIG_ROOT_RDONLY
syssize:
.word SYSSIZE
swap_dev:
......
......@@ -11,7 +11,7 @@ CONFIG_TCPIP y/n y
Kernel profiling support
CONFIG_PROFILE y/n n
Limit memory to low 16MB
CONFIG_MAX_16M y/n y
CONFIG_MAX_16M y/n n
Use -m486 flag for 486-specific optimizations
CONFIG_M486 y/n y
:
......@@ -23,29 +23,31 @@ CONFIG_SCSI y/n n
SCSI support type (disk, tape, CDrom)
.
Scsi disk support
CONFIG_BLK_DEV_SD y/n y
CONFIG_BLK_DEV_SD y/n n
Scsi tape support
CONFIG_BLK_DEV_ST y/n y
CONFIG_BLK_DEV_ST y/n n
Scsi CDROM support
CONFIG_BLK_DEV_SR y/n y
CONFIG_BLK_DEV_SR y/n n
.
SCSI low-level drivers
.
Adaptec AHA1542 support
CONFIG_SCSI_AHA1542 y/n y
CONFIG_SCSI_AHA1542 y/n n
Adaptec AHA1740 support
CONFIG_SCSI_AHA1740 y/n y
CONFIG_SCSI_AHA1740 y/n n
Future Domain SCSI support
CONFIG_SCSI_FUTURE_DOMAIN y/n y
CONFIG_SCSI_FUTURE_DOMAIN y/n n
Seagate ST-02 and Future Domain TMC-8xx SCSI support
CONFIG_SCSI_SEAGATE y/n y
CONFIG_SCSI_SEAGATE y/n n
UltraStor SCSI support
CONFIG_SCSI_ULTRASTOR y/n y
CONFIG_SCSI_ULTRASTOR y/n n
7000FASST SCSI support
CONFIG_SCSI_7000FASST y/n y
CONFIG_SCSI_7000FASST y/n n
.
Filesystems
.
Mount root initially readonly
CONFIG_ROOT_RDONLY y/n n
Standard (minix) fs support
CONFIG_MINIX_FS y/n y
Extended fs support
......
......@@ -550,7 +550,7 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
p = copy_strings(1, &i_name, page, p, 2);
argc++;
if (!p) {
retval = -ENOMEM;
retval = -E2BIG;
goto exec_error1;
}
/*
......@@ -578,7 +578,7 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
p = copy_strings(envc,envp,page,p,0);
p = copy_strings(argc,argv,page,p,0);
if (!p) {
retval = -ENOMEM;
retval = -E2BIG;
goto exec_error2;
}
}
......
......@@ -53,7 +53,8 @@ static struct super_operations ext_sops = {
ext_statfs
};
struct super_block *ext_read_super(struct super_block *s,void *data)
struct super_block *ext_read_super(struct super_block *s,void *data,
int silent)
{
struct buffer_head *bh;
struct ext_super_block *es;
......@@ -82,7 +83,9 @@ struct super_block *ext_read_super(struct super_block *s,void *data)
if (s->s_magic != EXT_SUPER_MAGIC) {
s->s_dev = 0;
unlock_super(s);
printk("EXT-fs: magic match failed\n");
if (!silent)
printk("VFS: Can't find an extfs filesystem on dev 0x%04x.\n",
dev);
return NULL;
}
if (!s->u.ext_sb.s_firstfreeblocknumber)
......@@ -151,6 +154,7 @@ void ext_statfs (struct super_block *sb, struct statfs *buf)
put_fs_long(tmp, &buf->f_bavail);
put_fs_long(sb->u.ext_sb.s_ninodes, &buf->f_files);
put_fs_long(ext_count_free_inodes(sb), &buf->f_ffree);
put_fs_long(EXT_NAME_LEN, &buf->f_namelen);
/* Don't know what value to put in buf->f_fsid */
}
......@@ -375,14 +379,8 @@ void ext_read_inode(struct inode * inode)
inode->i_op = &chrdev_inode_operations;
else if (S_ISBLK(inode->i_mode))
inode->i_op = &blkdev_inode_operations;
else if (S_ISFIFO(inode->i_mode)) {
inode->i_op = &fifo_inode_operations;
inode->i_pipe = 1;
PIPE_BASE(*inode) = NULL;
PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
PIPE_READ_WAIT(*inode) = PIPE_WRITE_WAIT(*inode) = NULL;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
}
else if (S_ISFIFO(inode->i_mode))
init_fifo(inode);
}
void ext_write_inode(struct inode * inode)
......
......@@ -372,14 +372,8 @@ int ext_mknod(struct inode * dir, const char * name, int len, int mode, int rdev
inode->i_op = &chrdev_inode_operations;
else if (S_ISBLK(inode->i_mode))
inode->i_op = &blkdev_inode_operations;
else if (S_ISFIFO(inode->i_mode)) {
inode->i_op = &fifo_inode_operations;
inode->i_pipe = 1;
PIPE_BASE(*inode) = NULL;
PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
PIPE_READ_WAIT(*inode) = PIPE_WRITE_WAIT(*inode) = NULL;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
}
else if (S_ISFIFO(inode->i_mode))
init_fifo(inode);
if (S_ISBLK(mode) || S_ISCHR(mode))
inode->i_rdev = rdev;
inode->i_mtime = inode->i_atime = CURRENT_TIME;
......
This diff is collapsed.
......@@ -65,6 +65,31 @@ struct inode_operations ext2_dir_inode_operations = {
NULL /* permission */
};
int ext2_check_dir_entry (char * function, struct inode * dir,
struct ext2_dir_entry * de, struct buffer_head * bh,
unsigned int offset)
{
char * error_msg = NULL;
if (de->rec_len < EXT2_DIR_REC_LEN(1))
error_msg = "rec_len is smaller than minimal";
else if (de->rec_len % 4 != 0)
error_msg = "rec_len % 4 != 0";
else if (de->rec_len < EXT2_DIR_REC_LEN(de->name_len))
error_msg = "rec_len is too small for name_len";
else if (((char *) de - bh->b_data) + de->rec_len >
dir->i_sb->s_blocksize)
error_msg = "directory entry accross blocks";
if (error_msg != NULL) {
printk ("%s: bad directory entry (dev %04x, dir %d): %s\n",
function, dir->i_dev, dir->i_ino, error_msg);
printk ("offset=%d, inode=%d, rec_len=%d, name_len=%d\n",
offset, de->inode, de->rec_len, de->name_len);
}
return error_msg == NULL ? 1 : 0;
}
static int ext2_readdir (struct inode * inode, struct file * filp,
struct dirent * dirent, int count)
{
......@@ -85,13 +110,8 @@ static int ext2_readdir (struct inode * inode, struct file * filp,
}
de = (struct ext2_dir_entry *) (offset + bh->b_data);
while (offset < sb->s_blocksize && filp->f_pos < inode->i_size) {
if (de->rec_len < EXT2_DIR_REC_LEN(1) ||
de->rec_len % 4 != 0 ||
de->rec_len < EXT2_DIR_REC_LEN(de->name_len)) {
printk ("ext2_readdir: bad directory entry (dev %04x, dir %d)\n",
inode->i_dev, inode->i_ino);
printk ("offset=%d, inode=%d, rec_len=%d, name_len=%d\n",
offset, de->inode, de->rec_len, de->name_len);
if (! ext2_check_dir_entry ("ext2_readdir", inode, de,
bh, offset)) {
brelse (bh);
return 0;
}
......
/*
* linux/fs/ext2/ialloc.c
*
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr)
*
* BSD ufs-inspired inode and directory allocation by
* Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
*/
/* ialloc.c contains the inodes allocation and deallocation routines */
......@@ -27,45 +30,31 @@
#include <linux/string.h>
#include <linux/locks.h>
#define set_bit(nr,addr) ( \
{ \
char res; \
__asm__ __volatile__("btsl %1,%2\n\tsetb %0" \
:"=q" (res) \
:"r" (nr),"m" (*(addr))); \
res; \
} \
)
#define clear_bit(nr,addr) ( \
{ \
char res; \
__asm__ __volatile__("btrl %1,%2\n\tsetnb %0" \
:"=q" (res) \
:"r" (nr),"m" (*(addr))); \
res; \
} \
)
#include <asm/bitops.h>
#define find_first_zero(addr,size) ( \
{ \
int __res; \
__asm__("cld\n" \
"1:\tlodsl\n\t" \
"notl %%eax\n\t" \
"bsfl %%eax,%%edx\n\t" \
"jne 2f\n\t" \
"addl $32,%%ecx\n\t" \
"cmpl %%ebx,%%ecx\n\t" \
"jl 1b\n\t" \
"xorl %%edx,%%edx\n" \
"2:\taddl %%edx,%%ecx" \
:"=c" (__res):"0" (0), "S" (addr), "b" (size) \
:"ax", "bx", "dx", "si"); \
__res; \
} \
)
static inline int find_first_zero_bit(unsigned *addr, unsigned size)
{
int res;
if (!size)
return 0;
__asm__("
cld
movl $-1,%%eax
repe; scasl
je 1f
subl $4,%%edi
movl (%%edi),%%eax
notl %%eax
bsfl %%eax,%%edx
jmp 2f
1: xorl %%edx,%%edx
2: subl %%ebx,%%edi
shll $3,%%edi
addl %%edi,%%edx"
:"=d" (res):"c" ((size+31)>>5), "D" (addr), "b" (addr)
:"ax", "bx", "cx", "di");
return res;
}
static void read_inode_bitmap (struct super_block * sb,
unsigned long block_group,
......@@ -278,13 +267,13 @@ void ext2_free_inode (struct inode * inode)
*/
static void inc_inode_version (struct inode * inode,
struct ext2_group_desc *gdp,
unsigned long desc)
int mode)
{
unsigned long inode_block;
struct buffer_head * bh;
struct ext2_inode * raw_inode;
inode_block = gdp[desc].bg_inode_table + (((inode->i_ino - 1) %
inode_block = gdp->bg_inode_table + (((inode->i_ino - 1) %
EXT2_INODES_PER_GROUP(inode->i_sb)) /
EXT2_INODES_PER_BLOCK(inode->i_sb));
bh = bread (inode->i_sb->s_dev, inode_block, inode->i_sb->s_blocksize);
......@@ -300,26 +289,44 @@ static void inc_inode_version (struct inode * inode,
EXT2_INODES_PER_GROUP(inode->i_sb)) %
EXT2_INODES_PER_BLOCK(inode->i_sb));
raw_inode->i_version++;
inode->u.ext2_i.i_version = raw_inode->i_version;
if (!S_ISFIFO(mode))
inode->u.ext2_i.i_version = raw_inode->i_version;
bh->b_dirt = 1;
brelse (bh);
}
static struct ext2_group_desc *
get_group_desc(struct super_block *sb, int group)
{
struct ext2_group_desc * gdp;
if (group >= sb->u.ext2_sb.s_groups_count || group < 0 )
panic ("ext2: get_group_desc: Invalid group\n");
if (!sb->u.ext2_sb.s_group_desc[group / EXT2_DESC_PER_BLOCK(sb)])
panic ("ext2: get_group_desc: Descriptor not loaded");
gdp = (struct ext2_group_desc *)
sb->u.ext2_sb.s_group_desc[group / EXT2_DESC_PER_BLOCK(sb)]
->b_data;
return gdp + (group % EXT2_DESC_PER_BLOCK(sb));
}
/*
* ext2_new_inode does not use a very clever algorithm yet
* There are two policies for allocating an inode. If the new inode is
* a directory, then a forward search is made for a block group with both
* free space and a low directory-to-inode ratio; if that fails, then of
* the groups with above-average free space, that group with the fewest
* directories already is chosen.
*
* Currently, the group descriptors are scanned until a free block is found
* For other inodes, search forward from the parent directory\'s block
* group to find a free inode.
*/
struct inode * ext2_new_inode (const struct inode * dir, int mode)
{
struct super_block * sb;
struct buffer_head * bh;
int i, j;
int i, j, avefreei;
struct inode * inode;
unsigned long group_desc;
unsigned long desc;
int bitmap_nr;
struct ext2_group_desc * gdp;
struct ext2_group_desc * gdp, * tmp;
struct ext2_super_block * es;
if (!dir || !(inode = get_empty_inode ()))
......@@ -330,25 +337,73 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
lock_super (sb);
es = (struct ext2_super_block *) sb->u.ext2_sb.s_sbh->b_data;
repeat:
group_desc = 0;
desc = 0;
gdp = NULL;
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
gdp = NULL; i=0;
if (S_ISDIR(mode)) {
avefreei = es->s_free_inodes_count /
sb->u.ext2_sb.s_groups_count;
/* I am not yet convinced that this next bit is necessary.
i = dir->u.ext2_i.i_block_group;
for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) {
tmp = get_group_desc(sb, i);
if ((tmp->bg_used_dirs_count << 8) <
tmp->bg_free_inodes_count) {
gdp = tmp;
break;
}
else
i = ++i % sb->u.ext2_sb.s_groups_count;
}
*/
if (!gdp) {
if (!sb->u.ext2_sb.s_group_desc[group_desc])
panic ("ext2_new_inode: Descriptor not loaded");
gdp = (struct ext2_group_desc *) sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) {
tmp = get_group_desc(sb, j);
if (tmp->bg_free_inodes_count >= avefreei) {
if (!gdp ||
(tmp->bg_free_inodes_count >
gdp->bg_free_inodes_count)) {
i = j;
gdp = tmp;
}
}
}
}
if (gdp[desc].bg_free_inodes_count > 0)
break;
desc ++;
if (desc == EXT2_DESC_PER_BLOCK(sb)) {
group_desc ++;
desc = 0;
gdp = NULL;
}
else
{ /* Try to place the inode in it\'s parent directory */
i = dir->u.ext2_i.i_block_group;
tmp = get_group_desc(sb, i);
if (tmp->bg_free_inodes_count)
gdp = tmp;
else
{ /* Use a quadratic hash to find a group with a free inode */
for (j=1; j<sb->u.ext2_sb.s_groups_count; j<<=1) {
i+=j;
if (i>=sb->u.ext2_sb.s_groups_count)
i-=sb->u.ext2_sb.s_groups_count;
tmp = get_group_desc(sb,i);
if (tmp->bg_free_inodes_count) {
gdp = tmp;
break;
}
}
}
if (!gdp) {
/* That failed: try linear search for a free inode */
i = dir->u.ext2_i.i_block_group + 2;
for (j=2; j<sb->u.ext2_sb.s_groups_count; j++) {
if (++i > sb->u.ext2_sb.s_groups_count)
i=0;
tmp = get_group_desc(sb,i);
if (tmp->bg_free_inodes_count) {
gdp = tmp;
break;
}
}
}
}
if (i >= sb->u.ext2_sb.s_groups_count) {
if (!gdp) {
unlock_super (sb);
return NULL;
}
......@@ -358,7 +413,8 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
printk ("block_group = %d\n", i);
panic ("ext2_new_inode: Unable to load group inode bitmap");
}
if ((j = find_first_zero (bh->b_data, EXT2_INODES_PER_GROUP(sb))) <
if ((j = find_first_zero_bit ((unsigned long *) bh->b_data,
EXT2_INODES_PER_GROUP(sb))) <
EXT2_INODES_PER_GROUP(sb)) {
if (set_bit (j, bh->b_data)) {
printk ("ext2_new_inode: bit already set\n");
......@@ -373,10 +429,10 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
printk ("ext2_new_inode: inode > inodes count");
return NULL;
}
gdp[desc].bg_free_inodes_count --;
gdp->bg_free_inodes_count --;
if (S_ISDIR(mode))
gdp[desc].bg_used_dirs_count ++;
sb->u.ext2_sb.s_group_desc[group_desc]->b_dirt = 1;
gdp->bg_used_dirs_count ++;
sb->u.ext2_sb.s_group_desc[i / EXT2_DESC_PER_BLOCK(sb)]->b_dirt = 1;
es->s_free_inodes_count --;
sb->u.ext2_sb.s_sbh->b_dirt = 1;
sb->s_dirt = 1;
......@@ -398,9 +454,10 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
inode->u.ext2_i.i_file_acl = 0;
inode->u.ext2_i.i_dir_acl = 0;
inode->u.ext2_i.i_dtime = 0;
inode->u.ext2_i.i_block_group = i;
if (!S_ISFIFO(mode))
inode->u.ext2_i.i_block_group = i;
inode->i_op = NULL;
inc_inode_version (inode, gdp, desc);
inc_inode_version (inode, gdp, mode);
#ifdef EXT2FS_DEBUG
printk ("ext2_new_inode : allocating inode %d\n", inode->i_ino);
#endif
......
This diff is collapsed.
......@@ -105,13 +105,8 @@ static struct buffer_head * ext2_find_entry (struct inode * dir,
if (prev_dir)
*prev_dir = NULL;
}
if (de->rec_len < EXT2_DIR_REC_LEN(1) ||
de->rec_len % 4 != 0 ||
de->rec_len < EXT2_DIR_REC_LEN(de->name_len)) {
printk ("ext2_find_entry: bad directory entry (dev %04x, dir %d)\n",
dir->i_dev, dir->i_ino);
printk ("offset=%d, inode=%d, rec_len=%d, name_len=%d\n",
offset, de->inode, de->rec_len, de->name_len);
if (! ext2_check_dir_entry ("ext2_find_entry", dir, de, bh,
offset)) {
brelse (bh);
return NULL;
}
......@@ -230,13 +225,8 @@ static struct buffer_head * ext2_add_entry (struct inode * dir,
de = (struct ext2_dir_entry *) bh->b_data;
}
}
if (de->rec_len < EXT2_DIR_REC_LEN(1) ||
de->rec_len % 4 != 0 ||
de->rec_len < EXT2_DIR_REC_LEN(de->name_len)) {
printk ("ext2_add_entry: bad directory entry (dev %04x, dir %d)\n",
dir->i_dev, dir->i_ino);
printk ("offset=%d, inode=%d, rec_len=%d, name_len=%d\n",
offset, de->inode, de->rec_len, de->name_len);
if (! ext2_check_dir_entry ("ext2_add_entry", dir, de, bh,
offset)) {
brelse (bh);
return NULL;
}
......@@ -267,6 +257,19 @@ static struct buffer_head * ext2_add_entry (struct inode * dir,
return NULL;
}
/*
* ext2_delete_entry deletes a directory entry by merging it with the
* previous entry
*/
static void ext2_delete_entry (struct ext2_dir_entry * dir,
struct ext2_dir_entry * prev_dir)
{
if (prev_dir != NULL)
prev_dir->rec_len += dir->rec_len;
else
dir->inode = 0;
}
int ext2_create (struct inode * dir,const char * name, int len, int mode,
struct inode ** result)
{
......@@ -341,14 +344,8 @@ int ext2_mknod (struct inode * dir, const char * name, int len, int mode,
inode->i_op = &chrdev_inode_operations;
else if (S_ISBLK(inode->i_mode))
inode->i_op = &blkdev_inode_operations;
else if (S_ISFIFO(inode->i_mode)) {
inode->i_op = &fifo_inode_operations;
inode->i_pipe = 1;
PIPE_BASE(*inode) = NULL;
PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
PIPE_READ_WAIT(*inode) = PIPE_WRITE_WAIT(*inode) = NULL;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
}
else if (S_ISFIFO(inode->i_mode))
init_fifo(inode);
if (S_ISBLK(mode) || S_ISCHR(mode))
inode->i_rdev = rdev;
inode->i_mtime = inode->i_atime = CURRENT_TIME;
......@@ -477,13 +474,8 @@ static int empty_dir (struct inode * inode)
}
de = (struct ext2_dir_entry *) bh->b_data;
}
if (de->rec_len < EXT2_DIR_REC_LEN(1) ||
de->rec_len % 4 != 0 ||
de->rec_len < EXT2_DIR_REC_LEN(de->name_len)) {
printk ("empty_dir: bad directory entry (dev %04x, dir %d)\n",
inode->i_dev, inode->i_ino);
printk ("offset=%d, inode=%d, rec_len=%d, name_len=%d\n",
offset, de->inode, de->rec_len, de->name_len);
if (! ext2_check_dir_entry ("empty_dir", inode, de, bh,
offset)) {
brelse (bh);
return 1;
}
......@@ -537,10 +529,13 @@ int ext2_rmdir (struct inode * dir, const char * name, int len)
#ifndef DONT_USE_DCACHE
ext2_dcache_remove (dir->i_dev, dir->i_ino, de->name, de->name_len);
#endif
ext2_delete_entry (de, pde);
#if 0
if (pde)
pde->rec_len += de->rec_len;
else
de->inode = 0;
#endif
bh->b_dirt = 1;
inode->i_nlink = 0;
inode->i_dirt = 1;
......@@ -584,10 +579,13 @@ int ext2_unlink (struct inode * dir, const char * name, int len)
#ifndef DONT_USE_DCACHE
ext2_dcache_remove (dir->i_dev, dir->i_ino, de->name, de->name_len);
#endif
ext2_delete_entry (de, pde);
#if 0
if (pde)
pde->rec_len += de->rec_len;
else
de->inode = 0;
#endif
bh->b_dirt = 1;
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_dirt = 1;
......@@ -857,12 +855,19 @@ static int do_ext2_rename (struct inode * old_dir, const char * old_name,
ext2_dcache_add (new_dir->i_dev, new_dir->i_ino, new_de->name,
new_de->name_len, new_de->inode);
#endif
if (old_bh->b_blocknr == new_bh->b_blocknr &&
((char *) new_de) + new_de->rec_len == (char *) old_de)
new_de->rec_len += old_de->rec_len;
else
ext2_delete_entry (old_de, pde);
#if 0
if (((char *) new_de) + new_de->rec_len == (char *) old_de)
new_de->rec_len += old_de->rec_len;
else if (pde)
pde->rec_len += old_de->rec_len;
else
old_de->inode = 0;
#endif
if (new_inode) {
new_inode->i_nlink --;
new_inode->i_dirt = 1;
......
......@@ -47,7 +47,7 @@ static int trunc_direct (struct inode * inode)
tmp = *p;
if (!tmp)
continue;
bh = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
bh = get_hash_table (inode->i_dev, tmp, inode->i_sb->s_blocksize);
if (i < direct_block) {
brelse (bh);
goto repeat;
......@@ -100,7 +100,8 @@ static int trunc_indirect (struct inode * inode, int offset, unsigned long * p)
tmp = *ind;
if (!tmp)
continue;
bh = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
bh = get_hash_table (inode->i_dev, tmp,
inode->i_sb->s_blocksize);
if (i < indirect_block) {
brelse (bh);
goto repeat;
......
......@@ -122,7 +122,7 @@ static int fifo_open(struct inode * inode,struct file * filp)
* is contain the open that then fills in the correct operations
* depending on the access mode of the file...
*/
struct file_operations def_fifo_fops = {
static struct file_operations def_fifo_fops = {
NULL,
NULL,
NULL,
......@@ -135,7 +135,7 @@ struct file_operations def_fifo_fops = {
NULL
};
struct inode_operations fifo_inode_operations = {
static struct inode_operations fifo_inode_operations = {
&def_fifo_fops, /* default file operations */
NULL, /* create */
NULL, /* lookup */
......@@ -152,3 +152,14 @@ struct inode_operations fifo_inode_operations = {
NULL, /* truncate */
NULL /* permission */
};
void init_fifo(struct inode * inode)
{
inode->i_op = &fifo_inode_operations;
inode->i_pipe = 1;
PIPE_BASE(*inode) = NULL;
PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0;
PIPE_READ_WAIT(*inode) = PIPE_WRITE_WAIT(*inode) = NULL;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
}
......@@ -37,15 +37,15 @@ struct file_system_type file_systems[] = {
#ifdef CONFIG_MINIX_FS
{minix_read_super, "minix", 1},
#endif
#ifdef CONFIG_XIA_FS
{xiafs_read_super, "xiafs", 1},
#endif
#ifdef CONFIG_EXT_FS
{ext_read_super, "ext", 1},
#endif
#ifdef CONFIG_EXT2_FS
{ext2_read_super, "ext2", 1},
#endif
#ifdef CONFIG_XIA_FS
{xiafs_read_super, "xiafs", 1},
#endif
#ifdef CONFIG_MSDOS_FS
{msdos_read_super, "msdos", 1},
#endif
......
......@@ -91,7 +91,8 @@ static int parse_options(char *options,char *map,char *conversion, char * rock,
return 1;
}
struct super_block *isofs_read_super(struct super_block *s,void *data)
struct super_block *isofs_read_super(struct super_block *s,void *data,
int silent)
{
struct buffer_head *bh;
int iso_blknum;
......@@ -155,7 +156,8 @@ struct super_block *isofs_read_super(struct super_block *s,void *data)
brelse(bh);
}
if(iso_blknum == 100) {
printk("Unable to identify CD-ROM format.\n");
if (!silent)
printk("Unable to identify CD-ROM format.\n");
s->s_dev = 0;
unlock_super(s);
return NULL;
......@@ -247,6 +249,7 @@ void isofs_statfs (struct super_block *sb, struct statfs *buf)
put_fs_long(0, &buf->f_bavail);
put_fs_long(sb->u.isofs_sb.s_ninodes, &buf->f_files);
put_fs_long(0, &buf->f_ffree);
put_fs_long(NAME_MAX, &buf->f_namelen);
/* Don't know what value to put in buf->f_fsid */
}
......@@ -415,14 +418,8 @@ void isofs_read_inode(struct inode * inode)
inode->i_op = &chrdev_inode_operations;
else if (S_ISBLK(inode->i_mode))
inode->i_op = &blkdev_inode_operations;
else if (S_ISFIFO(inode->i_mode)) {
inode->i_op = &fifo_inode_operations;
inode->i_pipe = 1;
PIPE_BASE(*inode) = NULL;
PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
PIPE_READ_WAIT(*inode) = PIPE_WRITE_WAIT(*inode) = NULL;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
}
else if (S_ISFIFO(inode->i_mode))
init_fifo(inode);
}
/* There are times when we need to know the inode number of a parent of
......
......@@ -48,7 +48,8 @@ static struct super_operations minix_sops = {
minix_statfs
};
struct super_block *minix_read_super(struct super_block *s,void *data)
struct super_block *minix_read_super(struct super_block *s,void *data,
int silent)
{
struct buffer_head *bh;
struct minix_super_block *ms;
......@@ -83,7 +84,9 @@ struct super_block *minix_read_super(struct super_block *s,void *data)
} else {
s->s_dev = 0;
unlock_super(s);
printk("MINIX-fs magic match failed\n");
if (!silent)
printk("VFS: Can't find a minix filesystem on dev 0x%04x.\n",
dev);
return NULL;
}
for (i=0;i < MINIX_I_MAP_SLOTS;i++)
......@@ -138,6 +141,7 @@ void minix_statfs(struct super_block *sb, struct statfs *buf)
put_fs_long(tmp, &buf->f_bavail);
put_fs_long(sb->u.minix_sb.s_ninodes, &buf->f_files);
put_fs_long(minix_count_free_inodes(sb), &buf->f_ffree);
put_fs_long(sb->u.minix_sb.s_namelen, &buf->f_namelen);
/* Don't know what value to put in buf->f_fsid */
}
......@@ -354,14 +358,8 @@ void minix_read_inode(struct inode * inode)
inode->i_op = &chrdev_inode_operations;
else if (S_ISBLK(inode->i_mode))
inode->i_op = &blkdev_inode_operations;
else if (S_ISFIFO(inode->i_mode)) {
inode->i_op = &fifo_inode_operations;
inode->i_pipe = 1;
PIPE_BASE(*inode) = NULL;
PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
PIPE_READ_WAIT(*inode) = PIPE_WRITE_WAIT(*inode) = NULL;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
}
else if (S_ISFIFO(inode->i_mode))
init_fifo(inode);
}
void minix_write_inode(struct inode * inode)
......
......@@ -15,11 +15,25 @@
#include <asm/segment.h>
/*
* comment out this line if you want names > MINIX_NAME_LEN chars to be
* truncated. Else they will be disallowed.
* comment out this line if you want names > info->s_namelen chars to be
* truncated. Else they will be disallowed (ENAMETOOLONG).
*/
/* #define NO_TRUNCATE */
static inline int namecompare(int len, int maxlen,
const char * name, const char * buffer)
{
if (len >= maxlen || !buffer[len]) {
unsigned char same;
__asm__("repe ; cmpsb ; setz %0"
:"=q" (same)
:"S" ((long) name),"D" ((long) buffer),"c" (len)
:"cx","di","si");
return same;
}
return 0;
}
/*
* ok, we cannot use strncmp, as the name is not in our data space.
* Thus we'll have to use minix_match. No big problem. Match also makes
......@@ -32,7 +46,6 @@ static int minix_match(int len, const char * name,
struct minix_sb_info * info)
{
struct minix_dir_entry * de;
register int same __asm__("ax");
de = (struct minix_dir_entry *) (bh->b_data + *offset);
*offset += info->s_dirsize;
......@@ -41,15 +54,7 @@ static int minix_match(int len, const char * name,
/* "" means "." ---> so paths like "/usr/lib//libc.a" work */
if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
return 1;
if (len < info->s_namelen && de->name[len])
return 0;
__asm__("cld\n\t"
"repe ; cmpsb\n\t"
"setz %%al"
:"=a" (same)
:"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
:"cx","di","si");
return same;
return namecompare(len,info->s_namelen,name,de->name);
}
/*
......@@ -134,15 +139,17 @@ int minix_lookup(struct inode * dir,const char * name, int len,
/*
* minix_add_entry()
*
* adds a file entry to the specified directory, using the same
* semantics as minix_find_entry(). It returns NULL if it failed.
* adds a file entry to the specified directory, returning a possible
* error value if it fails.
*
* NOTE!! The inode part of 'de' is left at 0 - which means you
* may not sleep between calling this and putting something into
* the entry, as someone else might have used it while you slept.
*/
static struct buffer_head * minix_add_entry(struct inode * dir,
const char * name, int namelen, struct minix_dir_entry ** res_dir)
static int minix_add_entry(struct inode * dir,
const char * name, int namelen,
struct buffer_head ** res_buf,
struct minix_dir_entry ** res_dir)
{
int i;
unsigned long block, offset;
......@@ -150,26 +157,27 @@ static struct buffer_head * minix_add_entry(struct inode * dir,
struct minix_dir_entry * de;
struct minix_sb_info * info;
*res_buf = NULL;
*res_dir = NULL;
if (!dir || !dir->i_sb)
return NULL;
return -ENOENT;
info = &dir->i_sb->u.minix_sb;
if (namelen > info->s_namelen) {
#ifdef NO_TRUNCATE
return NULL;
return -ENAMETOOLONG;
#else
namelen = info->s_namelen;
#endif
}
if (!namelen)
return NULL;
return -ENOENT;
bh = NULL;
block = offset = 0;
while (1) {
if (!bh) {
bh = minix_bread(dir,block,1);
if (!bh)
return NULL;
return -ENOSPC;
}
de = (struct minix_dir_entry *) (bh->b_data + offset);
offset += info->s_dirsize;
......@@ -179,7 +187,12 @@ static struct buffer_head * minix_add_entry(struct inode * dir,
dir->i_dirt = 1;
dir->i_ctime = CURRENT_TIME;
}
if (!de->inode) {
if (de->inode) {
if (namecompare(namelen, info->s_namelen, name, de->name)) {
brelse(bh);
return -EEXIST;
}
} else {
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
for (i = 0; i < info->s_namelen ; i++)
de->name[i] = (i < namelen) ? name[i] : 0;
......@@ -194,12 +207,14 @@ static struct buffer_head * minix_add_entry(struct inode * dir,
offset = 0;
block++;
}
return bh;
*res_buf = bh;
return 0;
}
int minix_create(struct inode * dir,const char * name, int len, int mode,
struct inode ** result)
{
int error;
struct inode * inode;
struct buffer_head * bh;
struct minix_dir_entry * de;
......@@ -215,13 +230,13 @@ int minix_create(struct inode * dir,const char * name, int len, int mode,
inode->i_op = &minix_file_inode_operations;
inode->i_mode = mode;
inode->i_dirt = 1;
bh = minix_add_entry(dir,name,len,&de);
if (!bh) {
error = minix_add_entry(dir,name,len, &bh ,&de);
if (error) {
inode->i_nlink--;
inode->i_dirt = 1;
iput(inode);
iput(dir);
return -ENOSPC;
return error;
}
de->inode = inode->i_ino;
bh->b_dirt = 1;
......@@ -233,6 +248,7 @@ int minix_create(struct inode * dir,const char * name, int len, int mode,
int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev)
{
int error;
struct inode * inode;
struct buffer_head * bh;
struct minix_dir_entry * de;
......@@ -266,25 +282,19 @@ int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rd
inode->i_op = &chrdev_inode_operations;
else if (S_ISBLK(inode->i_mode))
inode->i_op = &blkdev_inode_operations;
else if (S_ISFIFO(inode->i_mode)) {
inode->i_op = &fifo_inode_operations;
inode->i_pipe = 1;
PIPE_BASE(*inode) = NULL;
PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
PIPE_READ_WAIT(*inode) = PIPE_WRITE_WAIT(*inode) = NULL;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
}
else if (S_ISFIFO(inode->i_mode))
init_fifo(inode);
if (S_ISBLK(mode) || S_ISCHR(mode))
inode->i_rdev = rdev;
inode->i_mtime = inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
bh = minix_add_entry(dir,name,len,&de);
if (!bh) {
error = minix_add_entry(dir, name, len, &bh, &de);
if (error) {
inode->i_nlink--;
inode->i_dirt = 1;
iput(inode);
iput(dir);
return -ENOSPC;
return error;
}
de->inode = inode->i_ino;
bh->b_dirt = 1;
......@@ -296,6 +306,7 @@ int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rd
int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
{
int error;
struct inode * inode;
struct buffer_head * bh, *dir_block;
struct minix_dir_entry * de;
......@@ -345,12 +356,12 @@ int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
if (dir->i_mode & S_ISGID)
inode->i_mode |= S_ISGID;
inode->i_dirt = 1;
bh = minix_add_entry(dir,name,len,&de);
if (!bh) {
error = minix_add_entry(dir, name, len, &bh, &de);
if (error) {
iput(dir);
inode->i_nlink=0;
iput(inode);
return -ENOSPC;
return error;
}
de->inode = inode->i_ino;
bh->b_dirt = 1;
......@@ -559,13 +570,13 @@ int minix_symlink(struct inode * dir, const char * name, int len, const char * s
iput(dir);
return -EEXIST;
}
bh = minix_add_entry(dir,name,len,&de);
if (!bh) {
i = minix_add_entry(dir, name, len, &bh, &de);
if (i) {
inode->i_nlink--;
inode->i_dirt = 1;
iput(inode);
iput(dir);
return -ENOSPC;
return i;
}
de->inode = inode->i_ino;
bh->b_dirt = 1;
......@@ -577,6 +588,7 @@ int minix_symlink(struct inode * dir, const char * name, int len, const char * s
int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
{
int error;
struct minix_dir_entry * de;
struct buffer_head * bh;
......@@ -597,11 +609,11 @@ int minix_link(struct inode * oldinode, struct inode * dir, const char * name, i
iput(oldinode);
return -EEXIST;
}
bh = minix_add_entry(dir,name,len,&de);
if (!bh) {
error = minix_add_entry(dir, name, len, &bh, &de);
if (error) {
iput(dir);
iput(oldinode);
return -ENOSPC;
return error;
}
de->inode = oldinode->i_ino;
bh->b_dirt = 1;
......@@ -717,8 +729,8 @@ static int do_minix_rename(struct inode * old_dir, const char * old_name, int ol
current->euid != new_dir->i_uid && !suser())
goto end_rename;
if (S_ISDIR(old_inode->i_mode)) {
retval = -EACCES;
if (!permission(old_inode, MAY_WRITE))
retval = -ENOTDIR;
if (new_inode && !S_ISDIR(new_inode->i_mode))
goto end_rename;
retval = -EINVAL;
if (subdir(new_dir, old_inode))
......@@ -730,14 +742,14 @@ static int do_minix_rename(struct inode * old_dir, const char * old_name, int ol
if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
goto end_rename;
retval = -EMLINK;
if (new_dir->i_nlink >= MINIX_LINK_MAX)
if (!new_inode && new_dir->i_nlink >= MINIX_LINK_MAX)
goto end_rename;
}
if (!new_bh) {
retval = minix_add_entry(new_dir,new_name,new_len,&new_bh,&new_de);
if (retval)
goto end_rename;
}
if (!new_bh)
new_bh = minix_add_entry(new_dir,new_name,new_len,&new_de);
retval = -ENOSPC;
if (!new_bh)
goto end_rename;
/* sanity checking before doing the rename - avoid races */
if (new_inode && (new_de->inode != new_inode->i_ino))
goto try_again;
......
......@@ -66,7 +66,7 @@ static struct super_operations msdos_sops = {
static int parse_options(char *options,char *check,char *conversion,uid_t *uid,
gid_t *gid,int *umask,int *debug,int *fat)
gid_t *gid,int *umask,int *debug,int *fat,int *quiet)
{
char *this,*value;
......@@ -75,7 +75,7 @@ static int parse_options(char *options,char *check,char *conversion,uid_t *uid,
*uid = current->uid;
*gid = current->gid;
*umask = current->umask;
*debug = *fat = 0;
*debug = *fat = *quiet = 0;
if (!options) return 1;
for (this = strtok(options,","); this; this = strtok(NULL,",")) {
if ((value = strchr(this,'=')) != NULL)
......@@ -128,6 +128,10 @@ static int parse_options(char *options,char *check,char *conversion,uid_t *uid,
if (*value || (*fat != 12 && *fat != 16))
return 0;
}
else if (!strcmp(this,"quiet")) {
if (value) return 0;
*quiet = 1;
}
else return 0;
}
return 1;
......@@ -136,19 +140,20 @@ static int parse_options(char *options,char *check,char *conversion,uid_t *uid,
/* Read the super block of an MS-DOS FS. */
struct super_block *msdos_read_super(struct super_block *s,void *data)
struct super_block *msdos_read_super(struct super_block *s,void *data,
int silent)
{
struct buffer_head *bh;
struct msdos_boot_sector *b;
int data_sectors,logical_sector_size,sector_mult;
int debug,error,fat;
int debug,error,fat,quiet;
char check,conversion;
uid_t uid;
gid_t gid;
int umask;
if (!parse_options((char *) data,&check,&conversion,&uid,&gid,&umask,
&debug,&fat)) {
&debug,&fat,&quiet)) {
s->s_dev = 0;
return NULL;
}
......@@ -198,21 +203,24 @@ struct super_block *msdos_read_super(struct super_block *s,void *data)
data_sectors = (CF_LE_W(*((unsigned short *) &b->sectors)) ?
CF_LE_W(*((unsigned short *) &b->sectors)) :
CF_LE_L(b->total_sect))*sector_mult-MSDOS_SB(s)->data_start;
MSDOS_SB(s)->clusters = b->cluster_size ? data_sectors/b->cluster_size/
sector_mult : 0;
MSDOS_SB(s)->fat_bits = fat ? fat : MSDOS_SB(s)->clusters > MSDOS_FAT12
? 16 : 12;
error = !MSDOS_SB(s)->fats || (MSDOS_SB(s)->dir_entries & (MSDOS_DPS-1))
|| !b->cluster_size || MSDOS_SB(s)->clusters+2 > MSDOS_SB(s)->
fat_length*SECTOR_SIZE*8/MSDOS_SB(s)->fat_bits || !sector_mult ||
(logical_sector_size & (SECTOR_SIZE-1)) || !b->secs_track ||
!b->heads;
error = !b->cluster_size || !sector_mult;
if (!error) {
MSDOS_SB(s)->clusters = b->cluster_size ? data_sectors/
b->cluster_size/sector_mult : 0;
MSDOS_SB(s)->fat_bits = fat ? fat : MSDOS_SB(s)->clusters >
MSDOS_FAT12 ? 16 : 12;
error = !MSDOS_SB(s)->fats || (MSDOS_SB(s)->dir_entries &
(MSDOS_DPS-1)) || MSDOS_SB(s)->clusters+2 > MSDOS_SB(s)->
fat_length*SECTOR_SIZE*8/MSDOS_SB(s)->fat_bits ||
(logical_sector_size & (SECTOR_SIZE-1)) || !b->secs_track ||
!b->heads;
}
brelse(bh);
if (error || debug) {
printk("[MS-DOS FS Rel. alpha.10,FAT %d,check=%c,conv=%c,"
printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c,"
"uid=%d,gid=%d,umask=%03o%s]\n",MSDOS_SB(s)->fat_bits,check,
conversion,uid,gid,umask,MSDOS_CAN_BMAP(MSDOS_SB(s)) ? ",
bmap" : "");
conversion,uid,gid,umask,MSDOS_CAN_BMAP(MSDOS_SB(s)) ?
",bmap" : "");
printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,"
"se=%d,ts=%d,ls=%d]\n",b->media,MSDOS_SB(s)->cluster_size,
MSDOS_SB(s)->fats,MSDOS_SB(s)->fat_start,MSDOS_SB(s)->
......@@ -221,8 +229,10 @@ struct super_block *msdos_read_super(struct super_block *s,void *data)
sectors),b->total_sect,logical_sector_size);
}
if (error) {
if (!silent)
printk("VFS: Can't find a valid MSDOS filesystem on dev 0x%04x.\n",
s->s_dev);
s->s_dev = 0;
printk("Unsupported FS parameters\n");
return NULL;
}
s->s_magic = MSDOS_SUPER_MAGIC;
......@@ -233,6 +243,7 @@ struct super_block *msdos_read_super(struct super_block *s,void *data)
MSDOS_SB(s)->fs_uid = uid;
MSDOS_SB(s)->fs_gid = gid;
MSDOS_SB(s)->fs_umask = umask;
MSDOS_SB(s)->quiet = quiet;
MSDOS_SB(s)->free_clusters = -1; /* don't know yet */
MSDOS_SB(s)->fat_wait = NULL;
MSDOS_SB(s)->fat_lock = 0;
......@@ -267,6 +278,7 @@ void msdos_statfs(struct super_block *sb,struct statfs *buf)
put_fs_long(free,&buf->f_bavail);
put_fs_long(0,&buf->f_files);
put_fs_long(0,&buf->f_ffree);
put_fs_long(12,&buf->f_namelen);
}
......@@ -416,7 +428,7 @@ int msdos_notify_change(int flags,struct inode *inode)
error = -EPERM;
}
if (!(flags & NOTIFY_MODE))
return error;
return MSDOS_SB(inode->i_sb)->quiet ? 0 : error;
if (inode->i_mode & ~MSDOS_VALID_MODE) {
inode->i_mode &= MSDOS_VALID_MODE;
error = -EPERM;
......@@ -427,5 +439,5 @@ int msdos_notify_change(int flags,struct inode *inode)
inode->i_mode = ((inode->i_mode & S_IFMT) | ((((inode->i_mode & S_IRWXU
& ~MSDOS_SB(inode->i_sb)->fs_umask) | S_IRUSR) >> 6)*0111)) &
~MSDOS_SB(inode->i_sb)->fs_umask;
return error;
return MSDOS_SB(inode->i_sb)->quiet ? 0 : error;
}
......@@ -293,11 +293,36 @@ int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
}
static int msdos_empty(struct inode *dir)
{
int pos;
struct buffer_head *bh;
struct msdos_dir_entry *de;
if (dir->i_count > 1)
return -EBUSY;
if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
pos = 0;
bh = NULL;
while (msdos_get_entry(dir,&pos,&bh,&de) > -1)
if (!IS_FREE(de->name) && strncmp(de->name,MSDOS_DOT,
MSDOS_NAME) && strncmp(de->name,MSDOS_DOTDOT,
MSDOS_NAME)) {
brelse(bh);
return -ENOTEMPTY;
}
if (bh)
brelse(bh);
}
return 0;
}
int msdos_rmdir(struct inode *dir,const char *name,int len)
{
int res,ino,pos;
struct buffer_head *bh,*dbh;
struct msdos_dir_entry *de,*dde;
int res,ino;
struct buffer_head *bh;
struct msdos_dir_entry *de;
struct inode *inode;
bh = NULL;
......@@ -312,17 +337,9 @@ int msdos_rmdir(struct inode *dir,const char *name,int len)
if (!S_ISDIR(inode->i_mode)) goto rmdir_done;
res = -EBUSY;
if (dir->i_dev != inode->i_dev || dir == inode) goto rmdir_done;
if (inode->i_count > 1) goto rmdir_done;
if (MSDOS_I(inode)->i_start) { /* may be zero in mkdir */
res = -ENOTEMPTY;
pos = 0;
dbh = NULL;
while (msdos_get_entry(inode,&pos,&dbh,&dde) > -1)
if (!IS_FREE(dde->name) && strncmp(dde->name,MSDOS_DOT,
MSDOS_NAME) && strncmp(dde->name,MSDOS_DOTDOT,
MSDOS_NAME)) goto rmdir_done;
if (dbh) brelse(dbh);
}
res = msdos_empty(inode);
if (res)
goto rmdir_done;
inode->i_nlink = 0;
dir->i_mtime = CURRENT_TIME;
dir->i_nlink--;
......@@ -377,8 +394,7 @@ static int rename_same_dir(struct inode *old_dir,char *old_name,
struct buffer_head *new_bh;
struct msdos_dir_entry *new_de;
struct inode *new_inode,*old_inode;
int new_ino;
int exists;
int new_ino,exists,error;
if (!strncmp(old_name,new_name,MSDOS_NAME)) return 0;
exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0;
......@@ -391,10 +407,17 @@ static int rename_same_dir(struct inode *old_dir,char *old_name,
brelse(new_bh);
return -EIO;
}
if (S_ISDIR(new_inode->i_mode)) {
error = S_ISDIR(new_inode->i_mode) ? (old_de->attr & ATTR_DIR) ?
msdos_empty(new_inode) : -EPERM : (old_de->attr & ATTR_DIR)
? -EPERM : 0;
if (error) {
iput(new_inode);
brelse(new_bh);
return -EPERM;
return error;
}
if (S_ISDIR(new_inode->i_mode)) {
new_dir->i_nlink--;
new_dir->i_dirt = 1;
}
new_inode->i_nlink = 0;
MSDOS_I(new_inode)->i_busy = 1;
......@@ -461,11 +484,14 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,
brelse(new_bh);
return -EIO;
}
if (S_ISDIR(new_inode->i_mode)) {
error = S_ISDIR(new_inode->i_mode) ? (old_de->attr & ATTR_DIR) ?
msdos_empty(new_inode) : -EPERM : (old_de->attr & ATTR_DIR)
? -EPERM : 0;
if (error) {
iput(new_inode);
iput(old_inode);
brelse(new_bh);
return -EPERM;
return error;
}
new_inode->i_nlink = 0;
MSDOS_I(new_inode)->i_busy = 1;
......@@ -485,6 +511,10 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,
}
return -EIO;
}
if (exists && S_ISDIR(new_inode->i_mode)) {
new_dir->i_nlink--;
new_dir->i_dirt = 1;
}
msdos_read_inode(free_inode);
MSDOS_I(old_inode)->i_busy = 1;
cache_inval_inode(old_inode);
......
......@@ -19,12 +19,6 @@
#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
/*
* comment out this line if you want names > MINIX_NAME_LEN chars to be
* truncated. Else they will be disallowed.
*/
/* #define NO_TRUNCATE */
/*
* In order to reduce some races, while at the same time doing additional
* checking and hopefully speeding things up, we copy filenames to the
......@@ -105,8 +99,13 @@ int lookup(struct inode * dir,const char * name, int len,
struct inode ** result)
{
struct super_block * sb;
int perm;
*result = NULL;
if (!dir)
return -ENOENT;
/* check permissions before traversing mount-points */
perm = permission(dir,MAY_EXEC);
if (len==2 && name[0] == '.' && name[1] == '.') {
if (dir == current->root) {
*result = dir;
......@@ -115,17 +114,16 @@ int lookup(struct inode * dir,const char * name, int len,
sb = dir->i_sb;
iput(dir);
dir = sb->s_covered;
if (dir)
dir->i_count++;
if (!dir)
return -ENOENT;
dir->i_count++;
}
}
if (!dir)
return -ENOENT;
if (!dir->i_op || !dir->i_op->lookup) {
iput(dir);
return -ENOTDIR;
}
if (!permission(dir,MAY_EXEC)) {
if (!perm) {
iput(dir);
return -EACCES;
}
......@@ -305,9 +303,11 @@ int open_namei(const char * pathname, int flag, int mode,
*res_inode=dir;
return 0;
}
dir->i_count++; /* lookup eats the dir */
error = lookup(dir,basename,namelen,&inode);
if (error) {
for (i = 0; i < 5; i++) { /* races... */
dir->i_count++; /* lookup eats the dir */
error = lookup(dir,basename,namelen,&inode);
if (!error)
break;
if (!(flag & O_CREAT)) {
iput(dir);
return error;
......@@ -324,7 +324,16 @@ int open_namei(const char * pathname, int flag, int mode,
iput(dir);
return -EROFS;
}
return dir->i_op->create(dir,basename,namelen,mode,res_inode);
dir->i_count++; /* create eats the dir */
error = dir->i_op->create(dir,basename,namelen,mode,res_inode);
if (error != -EEXIST) {
iput(dir);
return error;
}
}
if (error) {
iput(dir);
return error;
}
if ((flag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) {
iput(dir);
......
......@@ -592,13 +592,8 @@ void nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
inode->i_op = &chrdev_inode_operations;
else if (S_ISBLK(inode->i_mode))
inode->i_op = &blkdev_inode_operations;
else if (S_ISFIFO(inode->i_mode)) {
inode->i_op = &fifo_inode_operations;
inode->i_pipe = 1;
PIPE_BASE(*inode) = NULL;
PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
}
else if (S_ISFIFO(inode->i_mode))
init_fifo(inode);
else
inode->i_op = NULL;
}
......
......@@ -21,6 +21,7 @@
extern int close_fp(struct file *filp);
static int nfs_notify_change(int, struct inode *);
static void nfs_put_inode(struct inode *);
static void nfs_put_super(struct super_block *);
static void nfs_statfs(struct super_block *, struct statfs *);
......@@ -28,12 +29,17 @@ static struct super_operations nfs_sops = {
NULL, /* read inode */
nfs_notify_change, /* notify change */
NULL, /* write inode */
NULL, /* put inode */
nfs_put_inode, /* put inode */
nfs_put_super, /* put superblock */
NULL, /* write superblock */
nfs_statfs /* stat filesystem */
};
static void nfs_put_inode(struct inode * inode)
{
clear_inode(inode);
}
void nfs_put_super(struct super_block *sb)
{
close_fp(sb->u.nfs_sb.s_server.file);
......@@ -50,7 +56,8 @@ void nfs_put_super(struct super_block *sb)
* Later we can add other mount parameters like caching values.
*/
struct super_block *nfs_read_super(struct super_block *sb, void *raw_data)
struct super_block *nfs_read_super(struct super_block *sb, void *raw_data,
int silent)
{
struct nfs_mount_data *data = (struct nfs_mount_data *) raw_data;
struct nfs_server *server;
......@@ -134,6 +141,9 @@ void nfs_statfs(struct super_block *sb, struct statfs *buf)
put_fs_long(res.bavail, &buf->f_bavail);
put_fs_long(0, &buf->f_files);
put_fs_long(0, &buf->f_ffree);
/* We should really try to interrogate the remote server to find
it's maximum name length here */
put_fs_long(NAME_MAX, &buf->f_namelen);
}
/*
......
......@@ -40,7 +40,8 @@ static struct super_operations proc_sops = {
proc_statfs
};
struct super_block *proc_read_super(struct super_block *s,void *data)
struct super_block *proc_read_super(struct super_block *s,void *data,
int silent)
{
lock_super(s);
s->s_blocksize = 1024;
......@@ -64,6 +65,7 @@ void proc_statfs(struct super_block *sb, struct statfs *buf)
put_fs_long(0, &buf->f_bavail);
put_fs_long(0, &buf->f_files);
put_fs_long(0, &buf->f_ffree);
put_fs_long(NAME_MAX, &buf->f_namelen);
/* Don't know what value to put in buf->f_fsid */
}
......@@ -101,8 +103,10 @@ void proc_read_inode(struct inode * inode)
if (!pid) {
inode->i_mode = S_IFREG | 0444;
inode->i_op = &proc_array_inode_operations;
if (ino == 5)
if (ino == 5) {
inode->i_mode = S_IFREG | 0400;
inode->i_op = &proc_kmsg_inode_operations;
}
return;
}
ino &= 0x0000ffff;
......
......@@ -17,6 +17,7 @@
#include <asm/system.h>
#include <asm/segment.h>
/*
* The definition of file_systems that used to be here is now in
......@@ -29,6 +30,8 @@ extern struct file_operations * blkdev_fops[];
extern void wait_for_keypress(void);
extern void fcntl_init_locks(void);
extern int root_mountflags;
struct super_block super_block[NR_SUPER];
/* this is initialized in init/main.c */
......@@ -118,7 +121,8 @@ void put_super(dev_t dev)
sb->s_op->put_super(sb);
}
static struct super_block * read_super(dev_t dev,char *name,int flags,void *data)
static struct super_block * read_super(dev_t dev,char *name,int flags,
void *data, int silent)
{
struct super_block * s;
struct file_system_type *type;
......@@ -142,7 +146,7 @@ static struct super_block * read_super(dev_t dev,char *name,int flags,void *data
}
s->s_dev = dev;
s->s_flags = flags;
if (!type->read_super(s,data)) {
if (!type->read_super(s,data, silent)) {
s->s_dev = 0;
return NULL;
}
......@@ -308,7 +312,7 @@ static int do_mount(dev_t dev, const char * dir, char * type, int flags, void *
iput(dir_i);
return -EBUSY;
}
sb = read_super(dev,type,flags,data);
sb = read_super(dev,type,flags,data,0);
if (!sb || sb->s_covered) {
iput(dir_i);
return -EBUSY;
......@@ -452,14 +456,17 @@ void mount_root(void)
for (fs_type = file_systems; fs_type->read_super; fs_type++) {
if (!fs_type->requires_dev)
continue;
sb = read_super(ROOT_DEV,fs_type->name,0,NULL);
sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1);
if (sb) {
inode = sb->s_mounted;
inode->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */
sb->s_covered = inode;
sb->s_flags = 0;
sb->s_flags = root_mountflags;
current->pwd = inode;
current->root = inode;
printk ("VFS: Mounted root (%s filesystem)%s.\n",
fs_type->name,
(sb->s_flags & MS_RDONLY) ? " readonly" : "");
return;
}
}
......
......@@ -55,7 +55,8 @@ static struct super_operations xiafs_sops = {
xiafs_statfs
};
struct super_block *xiafs_read_super(struct super_block *s, void *data)
struct super_block *xiafs_read_super(struct super_block *s, void *data,
int silent)
{
struct buffer_head *bh;
struct xiafs_super_block *sp;
......@@ -75,7 +76,9 @@ struct super_block *xiafs_read_super(struct super_block *s, void *data)
s->s_dev = 0;
unlock_super(s);
brelse(bh);
printk("XIA-FS: super magic mismatch\n");
if (!silent)
printk("VFS: Can't find a xiafs filesystem on dev 0x%04x.\n",
dev);
return NULL;
}
s->s_blocksize = sp->s_zone_size;
......@@ -150,6 +153,7 @@ void xiafs_statfs(struct super_block *sb, struct statfs *buf)
put_fs_long(tmp, &buf->f_bavail);
put_fs_long(sb->u.xiafs_sb.s_ninodes, &buf->f_files);
put_fs_long(xiafs_count_free_inodes(sb), &buf->f_ffree);
put_fs_long(_XIAFS_NAME_LEN, &buf->f_namelen);
/* don't know what should be put in buf->f_fsid */
}
......@@ -394,14 +398,8 @@ void xiafs_read_inode(struct inode * inode)
inode->i_op = &chrdev_inode_operations;
else if (S_ISBLK(inode->i_mode))
inode->i_op = &blkdev_inode_operations;
else if (S_ISFIFO(inode->i_mode)) {
inode->i_op = &fifo_inode_operations;
inode->i_pipe = 1;
PIPE_BASE(*inode) = NULL;
PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
PIPE_READ_WAIT(*inode) = PIPE_WRITE_WAIT(*inode) = NULL;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
}
else if (S_ISFIFO(inode->i_mode))
init_fifo(inode);
}
void xiafs_write_inode(struct inode * inode)
......
......@@ -37,12 +37,12 @@ static int xiafs_match(int len, const char * name, struct xiafs_direct * dep)
/* "" means "." ---> so paths like "/usr/lib//libc.a" work */
if (!len && (dep->d_name[0]=='.') && (dep->d_name[1]=='\0'))
return 1;
if (len < _XIAFS_NAME_LEN && dep->d_name[len])
if (len != dep->d_name_len)
return 0;
for (i=0; i < len; i++)
if (*name++ != dep->d_name[i])
break;
return (i==len) ? 1 : 0;
return 0;
return 1;
}
/*
......@@ -306,14 +306,8 @@ int xiafs_mknod(struct inode *dir, const char *name, int len, int mode, int rdev
inode->i_op = &chrdev_inode_operations;
else if (S_ISBLK(inode->i_mode))
inode->i_op = &blkdev_inode_operations;
else if (S_ISFIFO(inode->i_mode)) {
inode->i_op = &fifo_inode_operations;
inode->i_pipe = 1;
PIPE_BASE(*inode) = NULL;
PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
PIPE_READ_WAIT(*inode) = PIPE_WRITE_WAIT(*inode) = NULL;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
}
else if (S_ISFIFO(inode->i_mode))
init_fifo(inode);
if (S_ISBLK(mode) || S_ISCHR(mode))
inode->i_rdev = rdev;
inode->i_atime = inode->i_ctime = inode->i_atime = CURRENT_TIME;
......
......@@ -126,5 +126,6 @@
/* Should never be seen by user programs */
#define ERESTARTSYS 512
#define ERESTARTNOINTR 513
#define ERESTARTNOHAND 514 /* restart if no handler.. */
#endif
......@@ -23,7 +23,7 @@
/*
* The second extended file system version
*/
#define EXT2FS_VERSION "0.2c, 93/03/06"
#define EXT2FS_VERSION "0.2d, 93/03/30"
/*
* Special inodes numbers
......@@ -138,10 +138,11 @@ struct ext2_inode {
unsigned long i_version; /* File version (for NFS) */
unsigned long i_file_acl; /* File ACL */
unsigned long i_dir_acl; /* Directory ACL */
unsigned short i_faddr; /* Fragment address */
unsigned long i_faddr; /* Fragment address */
unsigned char i_frag; /* Fragment number */
unsigned char i_fsize; /* Fragment size */
unsigned long i_reserved2[3];
unsigned short i_pad1;
unsigned long i_reserved2[2];
};
/*
......@@ -155,7 +156,7 @@ struct ext2_super_block {
unsigned long s_free_inodes_count;/* Free inodes count */
unsigned long s_first_data_block;/* First Data Block */
unsigned long s_log_block_size; /* Block size */
unsigned long s_log_frag_size; /* Fragment size */
long s_log_frag_size; /* Fragment size */
unsigned long s_blocks_per_group;/* # Blocks per group */
unsigned long s_frags_per_group;/* # Fragments per group */
unsigned long s_inodes_per_group;/* # Inodes per group */
......@@ -212,6 +213,11 @@ extern void ext2_dcache_add (unsigned short, unsigned long, const char *,
extern void ext2_dcache_remove (unsigned short, unsigned long, const char *,
int);
/* dir.c */
extern int ext2_check_dir_entry (char *, struct inode *,
struct ext2_dir_entry *, struct buffer_head *,
unsigned int);
/* file.c */
extern int ext2_read (struct inode *, struct file *, char *, int);
extern int ext2_write (struct inode *, struct file *, char *, int);
......@@ -230,7 +236,7 @@ extern struct buffer_head * ext2_bread (struct inode *, int, int);
extern void ext2_truncate (struct inode *);
extern void ext2_put_super (struct super_block *);
extern void ext2_write_super (struct super_block *);
extern struct super_block * ext2_read_super (struct super_block *,void *);
extern struct super_block * ext2_read_super (struct super_block *,void *,int);
extern void ext2_read_inode (struct inode *);
extern void ext2_write_inode (struct inode *);
extern void ext2_put_inode (struct inode *);
......@@ -255,19 +261,10 @@ extern int ext2_rename (struct inode *, const char *, int,
* Inodes and files operations
*/
/* blkdev.c */
extern struct inode_operations ext2_blkdev_inode_operations;
/* chrdev.c */
extern struct inode_operations ext2_chrdev_inode_operations;
/* dir.c */
extern struct inode_operations ext2_dir_inode_operations;
extern struct file_operations ext2_dir_operations;
/* fifo.c */
extern struct inode_operations ext2_fifo_inode_operations;
/* file.c */
extern struct inode_operations ext2_file_inode_operations;
extern struct file_operations ext2_file_operations;
......
......@@ -6,14 +6,17 @@
*/
struct ext2_inode_info {
unsigned long i_flags;
unsigned short i_faddr;
unsigned long i_faddr;
unsigned char i_frag;
unsigned char i_fsize;
unsigned short i_pad1;
unsigned long i_file_acl;
unsigned long i_dir_acl;
unsigned long i_dtime;
unsigned long i_version;
unsigned long i_block_group;
unsigned long i_next_alloc_block;
unsigned long i_next_alloc_goal;
unsigned long i_data[15];
};
......
......@@ -13,7 +13,7 @@ struct ext2_sb_info {
unsigned long s_r_blocks_count; /* Reserved blocks count */
unsigned long s_first_data_block;/* First data block */
unsigned long s_log_block_size; /* Log of block size */
unsigned long s_log_frag_size; /* Log of fragment size */
long s_log_frag_size; /* Log of fragment size */
unsigned long s_frag_size; /* Size of a fragment in bytes */
unsigned long s_frags_per_block;/* Number of fragments per block */
unsigned long s_inodes_per_block;/* Number of inodes per block */
......@@ -31,6 +31,7 @@ struct ext2_sb_info {
unsigned long s_block_bitmap_number[EXT2_MAX_GROUP_LOADED];
struct buffer_head * s_block_bitmap[EXT2_MAX_GROUP_LOADED];
int s_rename_lock;
int s_was_mounted_valid;
struct wait_queue * s_rename_wait;
};
......
......@@ -89,7 +89,7 @@ extern struct buffer_head * ext_bread(struct inode *, int, int);
extern void ext_truncate(struct inode *);
extern void ext_put_super(struct super_block *);
extern void ext_write_super(struct super_block *);
extern struct super_block *ext_read_super(struct super_block *,void *);
extern struct super_block *ext_read_super(struct super_block *,void *,int);
extern void ext_read_inode(struct inode *);
extern void ext_write_inode(struct inode *);
extern void ext_put_inode(struct inode *);
......
......@@ -300,7 +300,7 @@ struct super_operations {
};
struct file_system_type {
struct super_block *(*read_super) (struct super_block *, void *);
struct super_block *(*read_super) (struct super_block *, void *, int);
char *name;
int requires_dev;
};
......@@ -318,7 +318,7 @@ extern int chrdev_open(struct inode * inode, struct file * filp);
extern struct file_operations def_chr_fops;
extern struct inode_operations chrdev_inode_operations;
extern struct inode_operations fifo_inode_operations;
extern void init_fifo(struct inode * inode);
extern struct file_system_type *get_fs_type(char *name);
......
......@@ -163,7 +163,7 @@ extern int isofs_free_block(int dev, int block);
extern int isofs_bmap(struct inode *,int);
extern void isofs_put_super(struct super_block *);
extern struct super_block *isofs_read_super(struct super_block *,void *);
extern struct super_block *isofs_read_super(struct super_block *,void *,int);
extern void isofs_read_inode(struct inode *);
extern void isofs_put_inode(struct inode *);
extern void isofs_statfs(struct super_block *, struct statfs *);
......
......@@ -99,7 +99,7 @@ extern struct buffer_head * minix_bread(struct inode *, int, int);
extern void minix_truncate(struct inode *);
extern void minix_put_super(struct super_block *);
extern struct super_block *minix_read_super(struct super_block *,void *);
extern struct super_block *minix_read_super(struct super_block *,void *,int);
extern void minix_read_inode(struct inode *);
extern void minix_write_inode(struct inode *);
extern void minix_put_inode(struct inode *);
......
......@@ -168,7 +168,8 @@ extern int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
extern void msdos_put_inode(struct inode *inode);
extern void msdos_put_super(struct super_block *sb);
extern struct super_block *msdos_read_super(struct super_block *s,void *data);
extern struct super_block *msdos_read_super(struct super_block *s,
void *data,int);
extern void msdos_statfs(struct super_block *sb,struct statfs *buf);
extern int msdos_bmap(struct inode *inode,int block);
extern void msdos_read_inode(struct inode *inode);
......
......@@ -14,6 +14,7 @@ struct msdos_sb_info {
unsigned long clusters; /* number of clusters */
uid_t fs_uid;
gid_t fs_gid;
int quiet; /* fake successful chmods and chowns */
unsigned short fs_umask;
unsigned char name_check; /* r = relaxed, n = normal, s = strict */
unsigned char conversion; /* b = binary, t = text, a = auto */
......
......@@ -98,7 +98,8 @@ extern int nfs_rpc_call(struct nfs_server *server, int *start, int *end);
/* linux/fs/nfs/inode.c */
extern struct super_block *nfs_read_super(struct super_block *sb, void *data);
extern struct super_block *nfs_read_super(struct super_block *sb,
void *data,int);
extern struct inode *nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle,
struct nfs_fattr *fattr);
extern void nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr);
......
......@@ -15,7 +15,7 @@ struct proc_dir_entry {
char * name;
};
extern struct super_block *proc_read_super(struct super_block *,void *);
extern struct super_block *proc_read_super(struct super_block *,void *,int);
extern void proc_put_inode(struct inode *);
extern void proc_put_super(struct super_block *);
extern void proc_statfs(struct super_block *, struct statfs *);
......
......@@ -52,7 +52,17 @@ typedef unsigned int sigset_t; /* 32 bits */
#define SIGLOST 29
*/
/*
* sa_flags values: SA_STACK is not currently supported, but will allow the
* usage of signal stacks by using the (now obsolete) sa_restorer field in
* the sigaction structure as a stack pointer. This is now possible due to
* the changes in signal handling. LBT 010493.
* SA_RESTART is a no-op, as restarting is the default anyway. Use the
* SA_INTERRUPT flag to get interrupting signals..
*/
#define SA_NOCLDSTOP 1
#define SA_STACK 0x08000000
#define SA_RESTART 0x10000000
#define SA_INTERRUPT 0x20000000
#define SA_NOMASK 0x40000000
#define SA_ONESHOT 0x80000000
......
......@@ -121,6 +121,7 @@ extern int sys_swapoff();
extern int sys_sysinfo();
extern int sys_ipc();
extern int sys_fsync();
extern int sys_sigreturn();
fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,
......@@ -143,7 +144,7 @@ sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority, sys_setpriority,
sys_profil, sys_statfs, sys_fstatfs, sys_ioperm, sys_socketcall,
sys_syslog, sys_setitimer, sys_getitimer, sys_newstat, sys_newlstat,
sys_newfstat, sys_newuname, sys_iopl, sys_vhangup, sys_idle, sys_vm86,
sys_wait4, sys_swapoff, sys_sysinfo, sys_ipc, sys_fsync };
sys_wait4, sys_swapoff, sys_sysinfo, sys_ipc, sys_fsync, sys_sigreturn };
/* So we don't have to do any more manual updating.... */
int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
......@@ -23,7 +23,7 @@
*
* NET_TIMER tcp/ip timeout timer
*
* MISC_TIMER reserved for special uses like the 387 timeouts etc
* COPRO_TIMER 387 timeout for buggy hardware..
*/
#define BLANK_TIMER 0
......@@ -35,7 +35,7 @@
#define SCSI_TIMER 18
#define NET_TIMER 19
#define SOUND_TIMER 20
#define MISC_TIMER 21
#define COPRO_TIMER 21
struct timer_struct {
unsigned long expires;
......
......@@ -125,6 +125,7 @@
#define __NR_sysinfo 116
#define __NR_ipc 117 /* not implemented yet */
#define __NR_fsync 118 /* not implemented yet */
#define __NR_sigreturn 119
extern int errno;
......
......@@ -92,7 +92,7 @@ extern struct buffer_head * xiafs_bread(struct inode *, int, int);
extern void xiafs_truncate(struct inode *);
extern void xiafs_put_super(struct super_block *);
extern struct super_block *xiafs_read_super(struct super_block *,void *);
extern struct super_block *xiafs_read_super(struct super_block *,void *,int);
extern void xiafs_read_inode(struct inode *);
extern void xiafs_write_inode(struct inode *);
extern void xiafs_put_inode(struct inode *);
......
......@@ -19,6 +19,7 @@
#include <linux/unistd.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/fs.h>
extern unsigned long * prof_buffer;
extern unsigned long prof_len;
......@@ -79,6 +80,7 @@ extern unsigned long scsi_dev_init(unsigned long, unsigned long);
#define EXT_MEM_K (*(unsigned short *)0x90002)
#define DRIVE_INFO (*(struct drive_info *)0x90080)
#define SCREEN_INFO (*(struct screen_info *)0x90000)
#define MOUNT_ROOT_RDONLY (*(unsigned short *)0x901F2)
#define RAMDISK_SIZE (*(unsigned short *)0x901F8)
#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC)
#define AUX_DEVICE_INFO (*(unsigned char *)0x901FF)
......@@ -152,6 +154,9 @@ struct screen_info screen_info;
unsigned char aux_device_present;
int ramdisk_size;
int root_mountflags = 0;
static char fpu_error = 0;
static char command_line[80] = { 0, };
......@@ -186,6 +191,14 @@ static void parse_options(char *line)
ROOT_DEV = simple_strtoul(line+5,NULL,16);
continue;
}
if (!strcmp(line,"ro")) {
root_mountflags |= MS_RDONLY;
continue;
}
if (!strcmp(line,"rw")) {
root_mountflags &= ~MS_RDONLY;
continue;
}
/*
* Then check if it's an environment variable or
* an option.
......@@ -206,13 +219,13 @@ static void parse_options(char *line)
static void copro_timeout(void)
{
#ifdef CONFIG_MATH_EMULATION
printk(" Trying to use software floating point\n");
hard_math = 0;
__asm__("movl %%cr0,%%eax ; xorl $6,%%eax ; movl %%eax,%%cr0":::"ax");
#else
printk(" No software floating point - tough cookies\n");
#endif
fpu_error = 1;
timer_table[COPRO_TIMER].expires = jiffies+100;
timer_active |= 1<<COPRO_TIMER;
printk("387 failed: trying to reset\n");
send_sig(SIGFPE, last_task_used_math, 1);
outb_p(0,0xf1);
outb_p(0,0xf0);
}
void start_kernel(void)
......@@ -232,6 +245,8 @@ void start_kernel(void)
if (memory_end > 16*1024*1024)
memory_end = 16*1024*1024;
#endif
if (MOUNT_ROOT_RDONLY)
root_mountflags |= MS_RDONLY;
if ((unsigned long)&end >= (1024*1024)) {
memory_start = (unsigned long) &end;
low_memory_start = 4096;
......@@ -278,18 +293,18 @@ void start_kernel(void)
if (hard_math) {
unsigned short control_word;
timer_table[MISC_TIMER].expires = jiffies+100;
timer_table[MISC_TIMER].fn = copro_timeout;
timer_active |= 1<<MISC_TIMER;
printk("You have a bad 386/387 coupling.");
__asm__("fninit ; fnstcw %0 ; fwait":"=m" (*&control_word));
timer_table[COPRO_TIMER].expires = jiffies+50;
timer_table[COPRO_TIMER].fn = copro_timeout;
timer_active |= 1<<COPRO_TIMER;
printk("You have a bad 386/387 coupling.\r");
__asm__("clts ; fninit ; fnstcw %0 ; fwait":"=m" (*&control_word));
control_word &= 0xffc0;
__asm__("fldcw %0 ; fwait"::"m" (*&control_word));
outb_p(inb_p(0x21) | (1 << 2), 0x21);
__asm__("fldz ; fld1 ; fdiv %st,%st(1) ; fwait");
timer_active &= ~(1<<MISC_TIMER);
if (hard_math)
printk("\rMath coprocessor using %s error reporting.\n",
timer_active &= ~(1<<COPRO_TIMER);
if (!fpu_error)
printk("Math coprocessor using %s error reporting.\n",
ignore_irq13?"exception 16":"irq13");
}
move_to_user_mode();
......
......@@ -24,6 +24,7 @@ OBJS := $(OBJS) div_small.o errors.o\
load_store.o get_address.o\
poly_atan.o poly_l2.o poly_2xm1.o poly_sin.o poly_tan.o\
poly_div.o poly_mul64.o polynomial.o\
precision.o\
reg_add_sub.o reg_compare.o reg_constant.o reg_ld_str.o\
reg_div.o reg_mul.o reg_norm.o \
reg_u_add.o reg_u_div.o reg_u_mul.o reg_u_sub.o\
......
+---------------------------------------------------------------------------+
| wm-FPU-emu an FPU emulator for 80386 and 80486SX microprocessors. |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
| This program is free software; you can redistribute it and/or modify |
......@@ -43,14 +44,7 @@ Please report bugs, etc to me at:
--Bill Metzenthen
Oct 1992
[ note: I have advanced the version number from alpha numbers
to beta numbers. This is not meant to indicate any major
changes but rather the fact that the emulator has been a
standard part of the Linux distribution for some months
and is currently reasonably stable. WM Jan 1993 ]
March 1993
----------------------- Internals of wm-FPU-emu -----------------------
......@@ -89,7 +83,7 @@ is confined to five files:
----------------------- Limitations of wm-FPU-emu -----------------------
There are a number of differences between the current wm-FPU-emu
(version beta 1.0) and the 80486 FPU (apart from bugs). Some of the
(version beta 1.2) and the 80486 FPU (apart from bugs). Some of the
more important differences are listed below:
Internal computations do not use de-normal numbers (but External
......@@ -97,9 +91,12 @@ de-normals ARE recognised and generated). The design of wm-FPU-emu
allows a larger exponent range than the 80486 FPU for internal
computations.
All computations are performed at full 64 bit precision (the PC bits
of the FPU control word are ignored). Under Linux, the FPU normally
runs at 64 bits precision.
All computations are performed at full 64 bit precision with `round to
nearest or even' performed for the basic functions. The results of the
basic arithmetic functions and sqrt are then rounded to lower
precision if required by the PC bits of the FPU control word. Under
the crt0 version for Linux current at March 1993, the FPU PC bits
specify 53 bits precision.
The precision flag (PE of the FPU status word) is not implemented.
Does anyone write code which uses this feature?
......
/*---------------------------------------------------------------------------+
| reg_constant.c |
| |
| All of the constant FPU_REGs |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
| |
+---------------------------------------------------------------------------*/
#include "fpu_system.h"
#include "fpu_emu.h"
#include "status_w.h"
#include "reg_constant.h"
FPU_REG CONST_1 = { SIGN_POS, TW_Valid, EXP_BIAS,
0x00000000, 0x80000000 };
FPU_REG CONST_2 = { SIGN_POS, TW_Valid, EXP_BIAS+1,
0x00000000, 0x80000000 };
FPU_REG CONST_HALF = { SIGN_POS, TW_Valid, EXP_BIAS-1,
0x00000000, 0x80000000 };
FPU_REG CONST_L2T = { SIGN_POS, TW_Valid, EXP_BIAS+1,
0xcd1b8afe, 0xd49a784b };
FPU_REG CONST_L2E = { SIGN_POS, TW_Valid, EXP_BIAS,
0x5c17f0bc, 0xb8aa3b29 };
FPU_REG CONST_PI = { SIGN_POS, TW_Valid, EXP_BIAS+1,
0x2168c235, 0xc90fdaa2 };
FPU_REG CONST_PI2 = { SIGN_POS, TW_Valid, EXP_BIAS,
0x2168c235, 0xc90fdaa2 };
FPU_REG CONST_PI4 = { SIGN_POS, TW_Valid, EXP_BIAS-1,
0x2168c235, 0xc90fdaa2 };
FPU_REG CONST_LG2 = { SIGN_POS, TW_Valid, EXP_BIAS-2,
0xfbcff799, 0x9a209a84 };
FPU_REG CONST_LN2 = { SIGN_POS, TW_Valid, EXP_BIAS-1,
0xd1cf79ac, 0xb17217f7 };
/* Only the sign (and tag) is used in internal zeroes */
FPU_REG CONST_Z = { SIGN_POS, TW_Zero, 0, 0x0, 0x0 };
/* Only the sign and significand (and tag) are used in internal NaNs */
/* The 80486 never generates one of these
FPU_REG CONST_SNAN = { SIGN_POS, TW_NaN, EXP_OVER, 0x00000001, 0x80000000 };
*/
/* This is the real indefinite QNaN */
FPU_REG CONST_QNaN = { SIGN_NEG, TW_NaN, EXP_OVER, 0x00000000, 0xC0000000 };
/* Only the sign (and tag) is used in internal infinities */
FPU_REG CONST_INF = { SIGN_POS, TW_Infinity, EXP_OVER, 0x00000000, 0x80000000 };
static void fld_const(FPU_REG *c)
{
FPU_REG *st_new_ptr;
if ( STACK_OVERFLOW )
{
stack_overflow();
return;
}
push();
reg_move(c, FPU_st0_ptr);
status_word &= ~SW_C1;
}
static void fld1()
{
fld_const(&CONST_1);
}
static void fldl2t()
{
fld_const(&CONST_L2T);
}
static void fldl2e()
{
fld_const(&CONST_L2E);
}
static void fldpi()
{
fld_const(&CONST_PI);
}
static void fldlg2()
{
fld_const(&CONST_LG2);
}
static void fldln2()
{
fld_const(&CONST_LN2);
}
static void fldz()
{
fld_const(&CONST_Z);
}
static FUNC constants_table[] = {
fld1, fldl2t, fldl2e, fldpi, fldlg2, fldln2, fldz, Un_impl
};
void fconst()
{
(constants_table[FPU_rm])();
}
/*---------------------------------------------------------------------------+
| reg_constant.h |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
+---------------------------------------------------------------------------*/
#ifndef _REG_CONSTANT_H_
#define _REG_CONSTANT_H_
#include "fpu_emu.h"
extern FPU_REG CONST_1;
extern FPU_REG CONST_2;
extern FPU_REG CONST_HALF;
extern FPU_REG CONST_L2T;
extern FPU_REG CONST_L2E;
extern FPU_REG CONST_PI;
extern FPU_REG CONST_PI2;
extern FPU_REG CONST_PI4;
extern FPU_REG CONST_LG2;
extern FPU_REG CONST_LN2;
extern FPU_REG CONST_Z;
extern FPU_REG CONST_PINF;
extern FPU_REG CONST_INF;
extern FPU_REG CONST_MINF;
extern FPU_REG CONST_QNaN;
#endif _REG_CONSTANT_H_
/*---------------------------------------------------------------------------+
| control_w.h |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
+---------------------------------------------------------------------------*/
......@@ -30,4 +31,22 @@
#define RC_UP _Const_(0x0800)
#define RC_CHOP _Const_(0x0C00)
/* p 15-5: Precision control bits affect only the following:
ADD, SUB(R), MUL, DIV(R), and SQRT */
#define PRECISION_ADJUST_CONTROL (control_word & 0x300)
#define PR_24_BITS 0x000
#define PR_53_BITS 0x200
/* By doing this as a macro, we allow easy modification */
#define PRECISION_ADJUST(x) \
switch (PRECISION_ADJUST_CONTROL) \
{ \
case PR_24_BITS: \
round_to_24_bits(x); \
break; \
case PR_53_BITS: \
round_to_53_bits(x); \
break; \
}
#endif _CONTROLW_H_
......@@ -3,7 +3,8 @@
| |
| The error handling functions for wm-FPU-emu |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
| |
......
/*---------------------------------------------------------------------------+
| fpu_arith.c |
| |
| Code to implement the FPU register/register arithmetis instructions |
| Code to implement the FPU register/register arithmetic instructions |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
| |
......@@ -11,12 +12,14 @@
#include "fpu_system.h"
#include "fpu_emu.h"
#include "control_w.h"
void fadd__()
{
/* fadd st,st(i) */
reg_add(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr);
PRECISION_ADJUST(FPU_st0_ptr);
}
......@@ -24,6 +27,7 @@ void fmul__()
{
/* fmul st,st(i) */
reg_mul(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr);
PRECISION_ADJUST(FPU_st0_ptr);
}
......@@ -32,6 +36,7 @@ void fsub__()
{
/* fsub st,st(i) */
reg_sub(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr);
PRECISION_ADJUST(FPU_st0_ptr);
}
......@@ -39,6 +44,7 @@ void fsubr_()
{
/* fsubr st,st(i) */
reg_sub(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr);
PRECISION_ADJUST(FPU_st0_ptr);
}
......@@ -46,6 +52,7 @@ void fdiv__()
{
/* fdiv st,st(i) */
reg_div(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr);
PRECISION_ADJUST(FPU_st0_ptr);
}
......@@ -53,6 +60,7 @@ void fdivr_()
{
/* fdivr st,st(i) */
reg_div(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr);
PRECISION_ADJUST(FPU_st0_ptr);
}
......@@ -61,6 +69,7 @@ void fadd_i()
{
/* fadd st(i),st */
reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm));
PRECISION_ADJUST(&st(FPU_rm));
}
......@@ -68,6 +77,7 @@ void fmul_i()
{
/* fmul st(i),st */
reg_mul(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm));
PRECISION_ADJUST(&st(FPU_rm));
}
......@@ -77,6 +87,7 @@ void fsubri()
/* This is the sense of the 80486 manual
reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm)); */
reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm));
PRECISION_ADJUST(&st(FPU_rm));
}
......@@ -86,6 +97,7 @@ void fsub_i()
/* This is the sense of the 80486 manual
reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm)); */
reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm));
PRECISION_ADJUST(&st(FPU_rm));
}
......@@ -93,6 +105,7 @@ void fdivri()
{
/* fdivr st(i),st */
reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm));
PRECISION_ADJUST(&st(FPU_rm));
}
......@@ -100,6 +113,7 @@ void fdiv_i()
{
/* fdiv st(i),st */
reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm));
PRECISION_ADJUST(&st(FPU_rm));
}
......@@ -108,6 +122,7 @@ void faddp_()
{
/* faddp st(i),st */
reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm));
PRECISION_ADJUST(&st(FPU_rm));
pop();
}
......@@ -116,6 +131,7 @@ void fmulp_()
{
/* fmulp st(i),st */
reg_mul(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm));
PRECISION_ADJUST(&st(FPU_rm));
pop();
}
......@@ -127,6 +143,7 @@ void fsubrp()
/* This is the sense of the 80486 manual
reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm)); */
reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm));
PRECISION_ADJUST(&st(FPU_rm));
pop();
}
......@@ -137,6 +154,7 @@ void fsubp_()
/* This is the sense of the 80486 manual
reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm)); */
reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm));
PRECISION_ADJUST(&st(FPU_rm));
pop();
}
......@@ -145,6 +163,7 @@ void fdivrp()
{
/* fdivrp st(i),st */
reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm));
PRECISION_ADJUST(&st(FPU_rm));
pop();
}
......@@ -153,6 +172,7 @@ void fdivp_()
{
/* fdivp st(i),st */
reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm));
PRECISION_ADJUST(&st(FPU_rm));
pop();
}
......@@ -3,7 +3,8 @@
| |
| Code to implement some of the FPU auxiliary instructions. |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
| |
......
/*---------------------------------------------------------------------------+
| fpu_emu.h |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
+---------------------------------------------------------------------------*/
......
......@@ -3,7 +3,8 @@
| |
| The entry function for wm-FPU-emu |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
| See the files "README" and "COPYING" for further copyright and warranty |
......@@ -31,6 +32,7 @@
#include "fpu_system.h"
#include "fpu_emu.h"
#include "exception.h"
#include "control_w.h"
#include <asm/segment.h>
......@@ -157,7 +159,10 @@ void math_emulate(long arg)
/* We cannot handle emulation in v86-mode */
if (FPU_EFLAGS & 0x00020000)
math_abort(FPU_info,SIGILL);
{
FPU_ORIG_EIP = FPU_EIP;
math_abort(FPU_info,SIGILL);
}
/* 0x000f means user code space */
if (FPU_CS != 0x000f)
......@@ -227,10 +232,12 @@ void math_emulate(long arg)
break;
case 2: /* fcom */
compare_st_data();
goto no_precision_adjust;
break;
case 3: /* fcomp */
compare_st_data();
pop();
goto no_precision_adjust;
break;
case 4: /* fsub */
reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr);
......@@ -245,6 +252,9 @@ void math_emulate(long arg)
reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr);
break;
}
PRECISION_ADJUST(FPU_st0_ptr);
no_precision_adjust:
;
}
else
stack_underflow();
......@@ -328,9 +338,14 @@ void math_emulate(long arg)
void __math_abort(struct info * info, unsigned int signal)
{
RE_ENTRANT_CHECK_OFF
FPU_EIP = FPU_ORIG_EIP;
send_sig(signal,current,1);
RE_ENTRANT_CHECK_OFF
__asm__("movl %0,%%esp ; ret"::"g" (((long) info)-4));
#ifdef PARANOID
printk("ERROR: wm-FPU-emu math_abort failed!\n");
#endif PARANOID
}
#else /* no math emulation */
......
......@@ -3,7 +3,8 @@
| |
| Implement a few FPU instructions. |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
| |
......
......@@ -2,11 +2,11 @@
extern void Un_impl(void);
extern void emu_printall(void);
extern void exception(int n);
extern void real_2op_NaN(struct fpu_reg *a, struct fpu_reg *b, struct fpu_reg *dest);
extern void arith_invalid(struct fpu_reg *dest);
extern void divide_by_zero(int sign, struct fpu_reg *dest);
extern void arith_overflow(struct fpu_reg *dest);
extern void arith_underflow(struct fpu_reg *dest);
extern void real_2op_NaN(FPU_REG *a, FPU_REG *b, FPU_REG *dest);
extern void arith_invalid(FPU_REG *dest);
extern void divide_by_zero(int sign, FPU_REG *dest);
extern void arith_overflow(FPU_REG *dest);
extern void arith_underflow(FPU_REG *dest);
extern void stack_overflow(void);
extern void stack_underflow(void);
/* fpu_arith.c */
......@@ -41,10 +41,11 @@ extern void fst_i_(void);
extern void fstp_i(void);
/* fpu_entry.c */
extern void math_emulate(long arg);
extern void __math_abort(struct info *info, unsigned int signal);
/* fpu_etc.c */
extern void fp_etc(void);
/* fpu_trig.c */
extern void convert_l2reg(long *arg, struct fpu_reg *dest);
extern void convert_l2reg(long *arg, FPU_REG *dest);
extern void trig_a(void);
extern void trig_b(void);
/* get_address.c */
......@@ -52,22 +53,25 @@ extern void get_address(unsigned char FPU_modrm);
/* load_store.c */
extern void load_store_instr(char type);
/* poly_2xm1.c */
extern int poly_2xm1(struct fpu_reg *arg, struct fpu_reg *result);
extern int poly_2xm1(FPU_REG *arg, FPU_REG *result);
/* poly_atan.c */
extern void poly_atan(struct fpu_reg *arg);
extern void poly_add_1(struct fpu_reg *src);
extern void poly_atan(FPU_REG *arg);
extern void poly_add_1(FPU_REG *src);
/* poly_l2.c */
extern void poly_l2(struct fpu_reg *arg, struct fpu_reg *result);
extern int poly_l2p1(struct fpu_reg *arg, struct fpu_reg *result);
extern void poly_l2(FPU_REG *arg, FPU_REG *result);
extern int poly_l2p1(FPU_REG *arg, FPU_REG *result);
/* poly_sin.c */
extern void poly_sine(struct fpu_reg *arg, struct fpu_reg *result);
extern void poly_sine(FPU_REG *arg, FPU_REG *result);
/* poly_tan.c */
extern void poly_tan(struct fpu_reg *arg, struct fpu_reg *y_reg);
extern void poly_tan(FPU_REG *arg, FPU_REG *y_reg);
/* precision.c */
extern int round_to_53_bits(FPU_REG *reg);
extern int round_to_24_bits(FPU_REG *reg);
/* reg_add_sub.c */
extern void reg_add(struct fpu_reg *a, struct fpu_reg *b, struct fpu_reg *dest);
extern void reg_sub(struct fpu_reg *a, struct fpu_reg *b, struct fpu_reg *dest);
extern void reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest);
extern void reg_sub(FPU_REG *a, FPU_REG *b, FPU_REG *dest);
/* reg_compare.c */
extern int compare(struct fpu_reg *b);
extern int compare(FPU_REG *b);
extern void compare_st_data(void);
extern void fcom_st(void);
extern void fcompst(void);
......@@ -92,10 +96,10 @@ extern int reg_store_int64(void);
extern int reg_store_int32(void);
extern int reg_store_int16(void);
extern int reg_store_bcd(void);
extern int round_to_int(struct fpu_reg *r);
extern int round_to_int(FPU_REG *r);
extern char *fldenv(void);
extern void frstor(void);
extern char *fstenv(void);
extern void fsave(void);
/* reg_mul.c */
extern void reg_mul(struct fpu_reg *a, struct fpu_reg *b, struct fpu_reg *dest);
extern void reg_mul(FPU_REG *a, FPU_REG *b, FPU_REG *dest);
......@@ -3,7 +3,8 @@
| |
| Implementation of the FPU "transcendental" functions. |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
| |
......@@ -105,9 +106,8 @@ static void f2xm1(void)
{
/* poly_2xm1(x) requires 0 < x < 1. */
if ( poly_2xm1(FPU_st0_ptr, &rv) )
return;
return; /* error */
reg_mul(&rv, FPU_st0_ptr, FPU_st0_ptr);
return;
}
else
{
......@@ -119,9 +119,9 @@ static void f2xm1(void)
reg_mul(&rv, &tmp, &tmp);
reg_sub(&tmp, &CONST_1, FPU_st0_ptr);
FPU_st0_ptr->exp--;
if ( FPU_st0_ptr->exp <= EXP_UNDER )
arith_underflow(FPU_st0_ptr);
}
if ( FPU_st0_ptr->exp <= EXP_UNDER )
arith_underflow(FPU_st0_ptr);
return;
}
case TW_Zero:
......@@ -301,7 +301,9 @@ static void fsqrt_(void)
return;
}
else
single_arg_error();
{ single_arg_error(); return; }
PRECISION_ADJUST(FPU_st0_ptr);
}
......@@ -557,30 +559,27 @@ static void fyl2x(void)
reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr);
pop(); FPU_st0_ptr = &st(0);
if ( FPU_st0_ptr->exp <= EXP_UNDER )
arith_underflow(FPU_st0_ptr);
{ arith_underflow(FPU_st0_ptr); return; }
else if ( FPU_st0_ptr->exp >= EXP_OVER )
arith_overflow(FPU_st0_ptr);
{ arith_overflow(FPU_st0_ptr); return; }
}
else
{
/* negative */
pop(); FPU_st0_ptr = &st(0);
arith_invalid(FPU_st0_ptr);
return;
}
return;
}
if ( (FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
else if ( (FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
{ stack_underflow(); return; }
if ( (FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
else if ( (FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
{
real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
pop();
return;
}
if ( (FPU_st0_tag <= TW_Zero) && (st1_tag <= TW_Zero) )
else if ( (FPU_st0_tag <= TW_Zero) && (st1_tag <= TW_Zero) )
{
/* one of the args is zero, the other valid, or both zero */
if ( FPU_st0_tag == TW_Zero )
......@@ -592,7 +591,7 @@ static void fyl2x(void)
divide_by_zero(st1_ptr->sign ^ SIGN_NEG, FPU_st0_ptr);
return;
}
if ( st1_ptr->sign == SIGN_POS )
else if ( st1_ptr->sign == SIGN_POS )
{
/* Zero is the valid answer */
char sign = FPU_st0_ptr->sign;
......@@ -602,13 +601,15 @@ static void fyl2x(void)
FPU_st0_ptr->sign = sign;
return;
}
pop(); FPU_st0_ptr = &st(0);
arith_invalid(FPU_st0_ptr);
return;
else
{
pop(); FPU_st0_ptr = &st(0);
arith_invalid(FPU_st0_ptr);
return;
}
}
/* One or both arg must be an infinity */
if ( FPU_st0_tag == TW_Infinity )
else if ( FPU_st0_tag == TW_Infinity )
{
if ( (FPU_st0_ptr->sign == SIGN_NEG) || (st1_tag == TW_Zero) )
{ pop(); FPU_st0_ptr = &st(0); arith_invalid(FPU_st0_ptr); return; }
......@@ -621,9 +622,8 @@ static void fyl2x(void)
return;
}
}
/* st(1) must be infinity here */
if ( (FPU_st0_tag == TW_Valid) && (FPU_st0_ptr->sign == SIGN_POS) )
else if ( (FPU_st0_tag == TW_Valid) && (FPU_st0_ptr->sign == SIGN_POS) )
{
if ( FPU_st0_ptr->exp >= EXP_BIAS )
{
......@@ -636,19 +636,21 @@ static void fyl2x(void)
return;
}
pop();
return;
}
else
{
pop(); FPU_st0_ptr = &st(0);
FPU_st0_ptr->sign ^= SIGN_NEG;
return;
}
return;
}
else
{
/* st(0) must be zero or negative */
pop(); FPU_st0_ptr = &st(0);
arith_invalid(FPU_st0_ptr);
return;
}
/* st(0) must be zero or negative */
pop(); FPU_st0_ptr = &st(0);
arith_invalid(FPU_st0_ptr);
return;
}
......@@ -686,21 +688,17 @@ static void fpatan(void)
reg_move(&sum, st1_ptr);
pop(); FPU_st0_ptr = &st(0);
if ( FPU_st0_ptr->exp <= EXP_UNDER )
arith_underflow(FPU_st0_ptr);
return;
{ arith_underflow(FPU_st0_ptr); return; }
}
if ( (FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
else if ( (FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
{ stack_underflow(); return; }
if ( (FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
else if ( (FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
{
real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
pop();
return;
}
if ( (FPU_st0_tag == TW_Infinity) || (st1_tag == TW_Infinity) )
else if ( (FPU_st0_tag == TW_Infinity) || (st1_tag == TW_Infinity) )
{
char sign = st1_ptr->sign;
if ( FPU_st0_tag == TW_Infinity )
......@@ -726,10 +724,8 @@ static void fpatan(void)
}
st1_ptr->sign = sign;
pop();
return;
}
if ( st1_tag == TW_Zero )
else if ( st1_tag == TW_Zero )
{
char sign = st1_ptr->sign;
/* st(0) must be valid or zero */
......@@ -737,21 +733,20 @@ static void fpatan(void)
{ reg_move(&CONST_Z, st1_ptr); }
else
reg_move(&CONST_PI, st1_ptr);
st1_tag = sign;
st1_ptr->sign = sign;
pop();
return;
}
else if ( FPU_st0_tag == TW_Zero )
{
char sign = st1_ptr->sign;
/* st(1) must be TW_Valid here */
reg_move(&CONST_PI2, st1_ptr);
st1_tag = sign;
st1_ptr->sign = sign;
pop();
return;
}
#ifdef PARANOID
EXCEPTION(EX_INTERNAL | 0x220);
else
EXCEPTION(EX_INTERNAL | 0x220);
#endif PARANOID
}
......@@ -782,10 +777,9 @@ static void fyl2xp1(void)
reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr);
pop();
return;
}
else if ( (FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty) )
stack_underflow();
{ stack_underflow(); return; }
else if ( FPU_st0_tag == TW_Zero )
{
if ( st1_tag <= TW_Zero )
......@@ -796,21 +790,23 @@ static void fyl2xp1(void)
else if ( st1_tag == TW_Infinity )
{
arith_invalid(st1_ptr);
return;
}
else if ( st1_tag == TW_NaN )
{
if ( !(st1_ptr->sigh & 0x40000000) )
EXCEPTION(EX_Invalid); /* signaling NaN */
st1_ptr->sigh |= 0x40000000; /* QNaN */
return;
}
#ifdef PARANOID
else
{
EXCEPTION(EX_INTERNAL | 0x116);
return;
}
#endif PARANOID
pop();
return;
}
else if ( FPU_st0_tag == TW_NaN )
{
......@@ -868,9 +864,9 @@ static void fscale(void)
FPU_st0_ptr->exp = scale;
if ( scale <= EXP_UNDER )
arith_underflow(FPU_st0_ptr);
{ arith_underflow(FPU_st0_ptr); return; }
else if ( scale >= EXP_OVER )
arith_overflow(FPU_st0_ptr);
{ arith_overflow(FPU_st0_ptr); return; }
return;
}
......
......@@ -3,7 +3,8 @@
| |
| Get the effective address from an FPU instruction. |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
| |
......
......@@ -4,7 +4,8 @@
| This file contains most of the code to interpret the FPU instructions |
| which load and store from user memory. |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
| |
......
/*---------------------------------------------------------------------------+
| precision.c |
| |
| The functions which adjust the precision of a result. |
| |
| Copyright (C) 1993 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
| |
+---------------------------------------------------------------------------*/
#include <asm/segment.h>
#include "fpu_system.h"
#include "exception.h"
#include "reg_constant.h"
#include "fpu_emu.h"
#include "control_w.h"
/* Round the result to 53 bits */
int round_to_53_bits(FPU_REG *reg)
{
if (reg->tag == TW_Valid)
{
unsigned long increment = 0; /* avoid gcc warnings */
switch (control_word & CW_RC)
{
case RC_RND:
/* Rounding can get a little messy.. */
increment = ((reg->sigl & 0x7ff) > 0x400) | /* nearest */
((reg->sigl & 0xc00) == 0xc00); /* odd -> even */
break;
case RC_DOWN: /* towards -infinity */
increment = (reg->sign == SIGN_POS) ? 0 : reg->sigl & 0x7ff;
break;
case RC_UP: /* towards +infinity */
increment = (reg->sign == SIGN_POS) ? reg->sigl & 0x7ff : 0;
break;
case RC_CHOP:
increment = 0;
break;
}
/* Truncate the mantissa */
reg->sigl &= 0xfffff800;
if ( increment )
{
if ( reg->sigl >= 0xfffff800 )
{
/* the sigl part overflows */
if ( reg->sigh == 0xffffffff )
{
/* The sigh part overflows */
reg->sigh = 0x80000000;
reg->exp++;
if (reg->exp >= EXP_OVER)
{ arith_overflow(reg); return 1; }
}
else
{
reg->sigh ++;
}
reg->sigl = 0x00000000;
}
else
{
/* We only need to increment sigl */
reg->sigl += 0x00000800;
}
}
}
return 0;
}
/* Round the result to 24 bits */
int round_to_24_bits(FPU_REG *reg)
{
if (reg->tag == TW_Valid)
{
unsigned long increment = 0; /* avoid gcc warnings */
unsigned long sigh = reg->sigh;
unsigned long sigl = reg->sigl;
switch (control_word & CW_RC)
{
case RC_RND:
increment = ((sigh & 0xff) > 0x80) /* more than half */
|| (((sigh & 0xff) == 0x80) && sigl) /* more than half */
|| ((sigh & 0x180) == 0x180); /* round to even */
break;
case RC_DOWN: /* towards -infinity */
increment = (reg->sign == SIGN_POS) ? 0 : (sigl | (sigh & 0xff));
break;
case RC_UP: /* towards +infinity */
increment = (reg->sign == SIGN_POS) ? (sigl | (sigh & 0xff)) : 0;
break;
case RC_CHOP:
increment = 0;
break;
}
/* Truncate the mantissa */
reg->sigl = 0;
if (increment)
{
if ( sigh >= 0xffffff00 )
{
/* The sigh part overflows */
reg->sigh = 0x80000000;
reg->exp++;
if (reg->exp >= EXP_OVER)
{ arith_overflow(reg); return 1; }
}
else
{
reg->sigh &= 0xffffff00;
reg->sigh += 0x100;
}
}
}
return 0;
}
......@@ -3,7 +3,8 @@
| |
| Functions to add or subtract two registers and put the result in a third. |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
| |
......
......@@ -3,7 +3,8 @@
| |
| Compare two floating point registers |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
| |
......@@ -91,9 +92,14 @@ int compare(FPU_REG *b)
diff = FPU_st0_ptr->exp - b->exp;
if ( diff == 0 )
{
diff = FPU_st0_ptr->sigh - b->sigh;
diff = FPU_st0_ptr->sigh - b->sigh; /* Works only if ms bits are
identical */
if ( diff == 0 )
diff = FPU_st0_ptr->sigl - b->sigl;
{
diff = FPU_st0_ptr->sigl > b->sigl;
if ( diff == 0 )
diff = -(FPU_st0_ptr->sigl < b->sigl);
}
}
if ( diff > 0 )
......
......@@ -3,7 +3,8 @@
| |
| All of the functions which transfer data between user memory and FPU_REGs.|
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
| |
......@@ -505,45 +506,19 @@ int reg_store_double(void)
if (FPU_st0_tag == TW_Valid)
{
/* Rounding can get a little messy.. */
int exp = FPU_st0_ptr->exp - EXP_BIAS;
int increment = ((FPU_st0_ptr->sigl & 0x7ff) > 0x400) | /* nearest */
((FPU_st0_ptr->sigl & 0xc00) == 0xc00); /* odd -> even */
if ( increment )
{
if ( FPU_st0_ptr->sigl >= 0xfffff800 )
{
/* the sigl part overflows */
if ( FPU_st0_ptr->sigh == 0xffffffff )
{
/* The sigh part overflows */
l[0] = l[1] = 0;
exp++; /* no need to check here for overflow */
}
else
{
/* No overflow of sigh will happen, can safely increment */
l[0] = (FPU_st0_ptr->sigh+1) << 21;
l[1] = (((FPU_st0_ptr->sigh+1) >> 11) & 0xfffff);
}
}
else
{
/* We only need to increment sigl */
l[0] = ((FPU_st0_ptr->sigl+0x800) >> 11) | (FPU_st0_ptr->sigh << 21);
l[1] = ((FPU_st0_ptr->sigh >> 11) & 0xfffff);
}
}
else
{
/* No increment required */
l[0] = (FPU_st0_ptr->sigl >> 11) | (FPU_st0_ptr->sigh << 21);
l[1] = ((FPU_st0_ptr->sigh >> 11) & 0xfffff);
}
int exp;
FPU_REG tmp;
reg_move(FPU_st0_ptr, &tmp);
if (round_to_53_bits(&tmp)) goto overflow;
l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
l[1] = ((tmp.sigh >> 11) & 0xfffff);
exp = tmp.exp - EXP_BIAS;
if ( exp > DOUBLE_Emax )
{
EXCEPTION(EX_Overflow);
overflow:
/* This is a special case: see sec 16.2.5.1 of the 80486 book */
if ( control_word & EX_Overflow )
{
......@@ -645,7 +620,6 @@ int reg_store_double(void)
RE_ENTRANT_CHECK_ON
return 1;
}
......@@ -654,31 +628,21 @@ int reg_store_single(void)
{
float *single = (float *)FPU_data_address;
long templ;
int exp = FPU_st0_ptr->exp - EXP_BIAS;
unsigned long sigh = FPU_st0_ptr->sigh;
if (FPU_st0_tag == TW_Valid)
{
if ( ((sigh & 0xff) > 0x80) /* more than half */
|| ((sigh & 0x180) == 0x180) ) /* round to even */
{
/* Round up */
if ( sigh >= 0xffffff00 )
{
/* sigh would overflow */
exp++;
sigh = 0x80000000;
}
else
{
sigh += 0x100;
}
}
templ = (sigh >> 8) & 0x007fffff;
int exp;
FPU_REG tmp;
reg_move(FPU_st0_ptr, &tmp);
if (round_to_24_bits(&tmp)) goto overflow;
templ = (tmp.sigh >> 8) & 0x007fffff;
exp = tmp.exp - EXP_BIAS;
if ( exp > SINGLE_Emax )
{
EXCEPTION(EX_Overflow);
overflow:
/* This is a special case: see sec 16.2.5.1 of the 80486 book */
if ( control_word & EX_Overflow )
{
......
......@@ -2,11 +2,12 @@
| version.h |
| |
| |
| Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Copyright (C) 1992,1993 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail apm233m@vaxc.cc.monash.edu.au |
| |
| |
+---------------------------------------------------------------------------*/
#define FPU_VERSION "wm-FPU-emu version BETA 1.1"
#define FPU_VERSION "wm-FPU-emu version BETA 1.2"
......@@ -66,6 +66,7 @@ static int aha1542_last_mbo_used = (AHA1542_MAILBOXES - 1);
static long WAITnexttimeout = 3000000;
static int aha1542_host = 0;
static void setup_mailboxes();
extern void aha1542_interrupt();
#define aha1542_intr_reset() outb(IRST, CONTROL)
......@@ -185,6 +186,7 @@ int aha1542_test_port(int bse)
debug = 2;
/* Shouldn't have generated any interrupts during reset */
if (inb(INTRFLAGS)&INTRMASK) goto fail;
setup_mailboxes();
debug = 3;
/* Test the basic ECHO command */
......@@ -229,7 +231,7 @@ int aha1542_test_port(int bse)
/* What's this little function for? */
const char *aha1542_info(void)
{
static char buffer[] = ""; /* looks nicer without anything here */
static char buffer[] = "Adaptec 1542";
return buffer;
}
......@@ -396,7 +398,7 @@ int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
printk("aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
aha1542_stat();
printk("aha1542_queuecommand: dumping scsi cmd:");
for (i = 0; i < (*cmd<=0x1f?6:10); i++) printk("%02x ", cmd[i]);
for (i = 0; i < (COMMAND_SIZE(*cmd)); i++) printk("%02x ", cmd[i]);
printk("\n");
if (*cmd == WRITE_10 || *cmd == WRITE_6)
return 0; /* we are still testing, so *don't* write */
......@@ -430,7 +432,7 @@ int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
memset(&ccb[mbo], 0, sizeof(struct ccb));
ccb[mbo].cdblen = (*cmd<=0x1f)?6:10; /* SCSI Command Descriptor Block Length */
ccb[mbo].cdblen = COMMAND_SIZE(*cmd); /* SCSI Command Descriptor Block Length */
direction = 0;
if (*cmd == READ_10 || *cmd == READ_6)
......@@ -548,7 +550,6 @@ static void setup_mailboxes()
aha1542_intr_reset();
}
/* Query the board to find out if it is a 1542 or a 1740, or whatever. */
static int aha1542_getconfig(int hostnum)
{
static unchar inquiry_cmd[] = {CMD_RETCONF };
......@@ -776,6 +777,6 @@ int aha1542_biosparam(int size, int dev, int* info){
info[0] = 64;
info[1] = 32;
info[2] = size >> 11;
if (info[2] >= 1024) info[2] = 1024;
/* if (info[2] >= 1024) info[2] = 1024; */
return 0;
}
This diff is collapsed.
#ifndef _AHA1740_H
/* $Id: aha1740.h,v 1.1 1992/07/24 06:27:38 root Exp root $
/* $Id$
*
* Header file for the adaptec 1740 driver for Linux
*
* With minor revisions 3/31/93
* Written and (C) 1992,1993 Brad McLean. See aha1740.c
* for more info
*
*/
#include <linux/types.h>
/* Eisa Enhanced mode operation - slot locating and addressing */
#define MINEISA 1 /* I don't have an EISA Spec to know these ranges, so I */
#define MAXEISA 6 /* Just took my machine's specifications. Adjust to fit.*/
#define MAXEISA 8 /* Just took my machine's specifications. Adjust to fit.*/
/* I just saw an ad, and bumped this from 6 to 8 */
#define SLOTBASE(x) ((x << 12)+ 0xc80 )
#define BASE (base)
......@@ -31,7 +36,7 @@
#define HID_MFG "ADP"
#define HID_PRD 0
#define HID_REV 1
#define HID_REV 2
#define EBCNTRL_VALUE 1
#define PORTADDR_ENH 0x80
/* READ */
......@@ -80,7 +85,7 @@ struct aha1740_chain {
ulong datalen; /* Size of this part of chain */
};
/* These belong in scsi.h also */
/* These belong in scsi.h */
#define any2scsi(up, p) \
(up)[0] = (((unsigned long)(p)) >> 16) ; \
(up)[1] = (((unsigned long)(p)) >> 8); \
......@@ -155,11 +160,11 @@ const char *aha1740_info(void);
int aha1740_reset(void);
int aha1740_biosparam(int, int, int*);
#define AHA1740_ECBS 64
#define AHA1740_ECBS 32
#define AHA1740_SCATTER 16
#ifndef NULL
#define NULL 0
#define NULL 0
#endif
#define AHA1740 {"Adaptec 1740", aha1740_detect, \
......
......@@ -67,6 +67,13 @@ static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hos
* during detection.
*/
/* This is a placeholder for controllers that are not configured into
the system - we do this to ensure that the controller numbering is
always consistent, no matter how the kernel is configured. */
#define NO_CONTROLLER {NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
NULL, NULL, 0, 0, 0, 0, 0, 0}
/*
* When figure is run, we don't want to link to any object code. Since
* the macro for each host will contain function pointers, we cannot
......
......@@ -244,6 +244,8 @@ static void scan_scsis (void)
scsi_devices[NR_SCSI_DEVICES].
removable = (0x80 &
scsi_result[1]) >> 7;
scsi_devices[NR_SCSI_DEVICES].lockable =
scsi_devices[NR_SCSI_DEVICES].removable;
scsi_devices[NR_SCSI_DEVICES].
changed = 0;
scsi_devices[NR_SCSI_DEVICES].
......@@ -309,7 +311,10 @@ static void scan_scsis (void)
/* These devices need this "key" to unlock the device
so we can use it */
if(strncmp("INSITE", &scsi_result[8], 6) == 0 &&
strncmp("Floptical F*8I", &scsi_result[16], 16) == 0) {
(strncmp("Floptical F*8I", &scsi_result[16], 16) == 0
||strncmp("I325VM", &scsi_result[16], 6) == 0)) {
printk("Unlocked floptical drive.\n");
scsi_devices[NR_SCSI_DEVICES].lockable = 0;
scsi_cmd[0] = MODE_SENSE;
scsi_cmd[1] = (lun << 5) & 0xe0;
scsi_cmd[2] = 0x2e;
......@@ -464,8 +469,8 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, int index, int wait)
if (reqp) req = *reqp;
if (req && (dev = req->dev) <= 0)
panic("Invalid device in allocate_device");
/* See if this request has already been queued by an interrupt routine */
if (req && (dev = req->dev) <= 0) return NULL;
host = scsi_devices[index].host_no;
......@@ -481,7 +486,10 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, int index, int wait)
};
cli();
/* See if this request has already been queued by an interrupt routine */
if (req && ((req->dev < 0) || (req->dev != dev))) return NULL;
if (req && ((req->dev < 0) || (req->dev != dev))) {
sti();
return NULL;
};
if (!SCpnt || SCpnt->request.dev >= 0) /* Might have changed */
{
sti();
......@@ -1407,7 +1415,8 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
if(scsi_hosts[host].unchecked_isa_dma &&
memory_end > ISA_DMA_THRESHOLD &&
scsi_devices[i].type != TYPE_TAPE) {
dma_sectors += 32 * scsi_hosts[host].cmd_per_lun;
dma_sectors += (BLOCK_SIZE >> 9) * scsi_hosts[host].sg_tablesize *
scsi_hosts[host].cmd_per_lun;
need_isa_buffer++;
};
};
......
......@@ -76,7 +76,28 @@
#define MODE_SELECT_10 0x55
#define MODE_SENSE_10 0x5a
#define COMMAND_SIZE(opcode) ((opcode) ? ((opcode) > 0x20 ? 10 : 6) : 0)
static __inline__ int COMMAND_SIZE (int opcode) {
int group = (opcode >> 5) & 7;
switch (group) {
case 0:
return 6;
case 1:
case 2:
return 10;
case 3:
case 4:
printk("COMMAND_SIZE : reserved command group %d\n", group);
panic ("");
case 5:
return 12;
default:
#ifdef DEBUG
printk("COMMAND_SIZE : vendor specific command group %d - assuming"
" 10 bytes\n", group);
#endif
return 10;
}
}
/*
MESSAGE CODES
......@@ -258,6 +279,7 @@ typedef struct scsi_device {
unsigned random:1;
unsigned changed:1; /* Data invalid due to media change */
unsigned busy:1; /* Used to prevent races */
unsigned lockable:1; /* Able to prevent media removal */
} Scsi_Device;
/*
Use these to separate status msg and our bytes
......@@ -348,7 +370,7 @@ typedef struct scsi_cmnd {
* abort, etc are in process.
*/
unsigned char internal_timeout;
unsigned volatile char internal_timeout;
unsigned flags;
......@@ -459,6 +481,24 @@ static void end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors)
wake_up(&scsi_devices[SCpnt->index].device_wait);
return;
}
/* This is just like INIT_REQUEST, but we need to be aware of the fact
that an interrupt may start another request, so we run this with interrupts
turned off */
#define INIT_SCSI_REQUEST \
if (!CURRENT) {\
CLEAR_INTR; \
sti(); \
return; \
} \
if (MAJOR(CURRENT->dev) != MAJOR_NR) \
panic(DEVICE_NAME ": request list destroyed"); \
if (CURRENT->bh) { \
if (!CURRENT->bh->b_lock) \
panic(DEVICE_NAME ": block not locked"); \
}
#endif
#define SCSI_SLEEP(QUEUE, CONDITION) { \
......@@ -476,4 +516,3 @@ sleep_repeat: \
}; }
#endif
......@@ -29,10 +29,14 @@ static int ioctl_probe(int dev, void *buffer)
{
int temp;
int len;
char * string;
if ((temp = scsi_hosts[dev].present) && buffer) {
len = get_fs_long ((int *) buffer);
memcpy_tofs (buffer, scsi_hosts[dev].info(), len);
string = scsi_hosts[dev].info();
if (len > strlen(string)) len = strlen(string)+1;
verify_area(VERIFY_WRITE, buffer, len);
memcpy_tofs (buffer, string, len);
}
return temp;
}
......@@ -101,7 +105,8 @@ static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
if(driver_byte(SCpnt->result) != 0)
switch(SCpnt->sense_buffer[2] & 0xf) {
case ILLEGAL_REQUEST:
printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0;
else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
break;
case NOT_READY: /* This happens if there is no disc in drive */
if(dev->removable){
......@@ -225,12 +230,17 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
return -ENODEV;
switch (cmd) {
case SCSI_IOCTL_GET_IDLUN:
verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
put_fs_long(dev->id + (dev->lun << 8) +
(dev->host_no << 16), (long *) arg);
return 0;
case SCSI_IOCTL_PROBE_HOST:
return ioctl_probe(dev->host_no, arg);
case SCSI_IOCTL_SEND_COMMAND:
return ioctl_command((Scsi_Device *) dev, arg);
case SCSI_IOCTL_DOORLOCK:
if (!dev->removable) return 0;
if (!dev->removable || !dev->lockable) return 0;
scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
scsi_cmd[1] = dev->lun << 5;
scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
......@@ -238,7 +248,7 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
break;
case SCSI_IOCTL_DOORUNLOCK:
if (!dev->removable) return 0;
if (!dev->removable || !dev->lockable) return 0;
scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
scsi_cmd[1] = dev->lun << 5;
scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
......
......@@ -8,6 +8,7 @@
the cdrom */
#define SCSI_IOCTL_DOORLOCK 0x5380 /* lock the eject mechanism */
#define SCSI_IOCTL_DOORUNLOCK 0x5381 /* unlock the mechanism */
#define SCSI_IOCTL_GET_IDLUN 0x5382
#define SCSI_REMOVAL_PREVENT 1
#define SCSI_REMOVAL_ALLOW 0
......
......@@ -322,9 +322,13 @@ static void do_sd_request (void)
struct request * req = NULL;
int flag = 0;
while (1==1){
if (CURRENT != NULL && CURRENT->dev == -1) return;
cli();
if (CURRENT != NULL && CURRENT->dev == -1) {
sti();
return;
};
INIT_REQUEST;
INIT_SCSI_REQUEST;
/* We have to be careful here. allocate_device will get a free pointer, but
there is no guarantee that it is queueable. In normal usage, we want to
......@@ -341,6 +345,7 @@ static void do_sd_request (void)
SCpnt = allocate_device(&CURRENT,
rscsi_disks[DEVICE_NR(MINOR(CURRENT->dev))].device->index, 0);
else SCpnt = NULL;
sti();
/* This is a performance enhancement. We dig down into the request list and
try and find a queueable request (i.e. device not busy, and host able to
......@@ -562,6 +567,18 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
cmd[1] = (SCpnt->lun << 5) & 0xe0;
if (rscsi_disks[dev].sector_size == 1024){
if(block & 1) panic("sd.c:Bad block number requested");
if(this_count & 1) panic("sd.c:Bad block number requested");
block = block >> 1;
this_count = this_count >> 1;
};
if (rscsi_disks[dev].sector_size == 256){
block = block << 1;
this_count = this_count << 1;
};
if (((this_count > 0xff) || (block > 0x1fffff)) && rscsi_disks[dev].ten)
{
if (this_count > 0xffff)
......@@ -588,7 +605,8 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
cmd[5] = 0;
}
scsi_do_cmd (SCpnt, (void *) cmd, buff, this_count << 9,
scsi_do_cmd (SCpnt, (void *) cmd, buff,
this_count * rscsi_disks[dev].sector_size,
rw_intr, SD_TIMEOUT, MAX_RETRIES);
}
......@@ -660,6 +678,8 @@ static int sd_init_onedisk(int i)
cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
memset ((void *) &cmd[2], 0, 8);
SCpnt->request.dev = 0xffff; /* Mark as really busy again */
SCpnt->sense_buffer[0] = 0;
SCpnt->sense_buffer[2] = 0;
scsi_do_cmd (SCpnt,
(void *) cmd, (void *) buffer,
......@@ -717,8 +737,15 @@ static int sd_init_onedisk(int i)
printk("sd%d : sense not available. \n", i);
printk("sd%d : block size assumed to be 512 bytes, disk size 1GB. \n", i);
rscsi_disks[i].capacity = 0xfffff;
rscsi_disks[i].capacity = 0x1fffff;
rscsi_disks[i].sector_size = 512;
/* Set dirty bit for removable devices if not ready - sometimes drives
will not report this properly. */
if(rscsi_disks[i].device->removable &&
SCpnt->sense_buffer[2] == NOT_READY)
rscsi_disks[i].device->changed = 1;
}
else
{
......@@ -727,10 +754,12 @@ static int sd_init_onedisk(int i)
(buffer[2] << 8) |
buffer[3];
if ((rscsi_disks[i].sector_size = (buffer[4] << 24) |
(buffer[5] << 16) |
(buffer[6] << 8) |
buffer[7]) != 512)
rscsi_disks[i].sector_size = (buffer[4] << 24) |
(buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
if (rscsi_disks[i].sector_size != 512 &&
rscsi_disks[i].sector_size != 1024 &&
rscsi_disks[i].sector_size != 256)
{
printk ("sd%d : unsupported sector size %d.\n",
i, rscsi_disks[i].sector_size);
......@@ -745,6 +774,10 @@ static int sd_init_onedisk(int i)
return i;
};
}
if(rscsi_disks[i].sector_size == 1024)
rscsi_disks[i].capacity <<= 1; /* Change this into 512 byte sectors */
if(rscsi_disks[i].sector_size == 256)
rscsi_disks[i].capacity >>= 1; /* Change this into 512 byte sectors */
}
rscsi_disks[i].ten = 1;
......
......@@ -64,9 +64,9 @@ static volatile int st0x_aborted=0; /*
static unsigned char controller_type; /* set to SEAGATE for ST0x boards or FD for TMC-88x boards */
#define retcode(result) (((result) << 16) | (message << 8) | status)
#define STATUS (*(unsigned char *) st0x_cr_sr)
#define STATUS (*(volatile unsigned char *) st0x_cr_sr)
#define CONTROL STATUS
#define DATA (*(unsigned char *) st0x_dr)
#define DATA (*(volatile unsigned char *) st0x_dr)
#ifndef OVERRIDE
static const char * seagate_bases[] = {(char *) 0xc8000, (char *) 0xca000, (char *) 0xcc000, (char *) 0xce000, (char *) 0xce000,
......
......@@ -28,7 +28,7 @@
#include "sr.h"
#include "scsi_ioctl.h" /* For the door lock/unlock commands */
#define MAX_RETRIES 0
#define MAX_RETRIES 1
#define SR_TIMEOUT 250
int NR_SR=0;
......@@ -279,14 +279,19 @@ static void do_sr_request (void)
int flag = 0;
while (1==1){
if (CURRENT != NULL && CURRENT->dev == -1) return;
cli();
if (CURRENT != NULL && CURRENT->dev == -1) {
sti();
return;
};
INIT_REQUEST;
INIT_SCSI_REQUEST;
if (flag++ == 0)
SCpnt = allocate_device(&CURRENT,
scsi_CDs[DEVICE_NR(MINOR(CURRENT->dev))].device->index, 0);
else SCpnt = NULL;
sti();
/* This is a performance enhancement. We dig down into the request list and
......@@ -542,15 +547,21 @@ are any multiple of 512 bytes long. */
}
};
block = block >> 2; /* These are the sectors that the cdrom uses */
if (scsi_CDs[dev].sector_size == 2048)
block = block >> 2; /* These are the sectors that the cdrom uses */
else
block = block & 0xfffffffc;
realcount = (this_count + 3) / 4;
if (scsi_CDs[dev].sector_size == 512) realcount = realcount << 2;
if (((realcount > 0xff) || (block > 0x1fffff)) && scsi_CDs[dev].ten)
{
if (realcount > 0xffff)
{
realcount = 0xffff;
this_count = realcount * 4;
this_count = realcount * (scsi_CDs[dev].sector_size >> 9);
}
cmd[0] += READ_10 - READ_6 ;
......@@ -567,7 +578,7 @@ are any multiple of 512 bytes long. */
if (realcount > 0xff)
{
realcount = 0xff;
this_count = realcount * 4;
this_count = realcount * (scsi_CDs[dev].sector_size >> 9);
}
cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
......@@ -578,11 +589,12 @@ are any multiple of 512 bytes long. */
}
#ifdef DEBUG
printk("ReadCD: %d %d %d\n",block, realcount, buffer);
printk("ReadCD: %d %d %d %d\n",block, realcount, buffer, this_count);
#endif
SCpnt->this_count = this_count;
scsi_do_cmd (SCpnt, (void *) cmd, buffer, realcount << 11,
scsi_do_cmd (SCpnt, (void *) cmd, buffer,
realcount * scsi_CDs[dev].sector_size,
rw_intr, SR_TIMEOUT, MAX_RETRIES);
}
......@@ -597,9 +609,29 @@ void sr_attach(Scsi_Device * SDp){
if(NR_SR > MAX_SR) panic ("scsi_devices corrupt (sr)");
};
static void sr_init_done (Scsi_Cmnd * SCpnt)
{
struct request * req;
struct task_struct * p;
req = &SCpnt->request;
req->dev = 0xfffe; /* Busy, but indicate request done */
if ((p = req->waiting) != NULL) {
req->waiting = NULL;
p->state = TASK_RUNNING;
if (p->counter > current->counter)
need_resched = 1;
}
}
unsigned long sr_init(unsigned long memory_start, unsigned long memory_end)
{
int i;
unsigned char cmd[10];
unsigned char buffer[513];
int the_result, retries;
Scsi_Cmnd * SCpnt;
if (register_blkdev(MAJOR_NR,"sr",&sr_fops)) {
printk("Unable to get major %d for SCSI-CD\n",MAJOR_NR);
......@@ -613,8 +645,56 @@ unsigned long sr_init(unsigned long memory_start, unsigned long memory_end)
for (i = 0; i < NR_SR; ++i)
{
scsi_CDs[i].capacity = 0x1fffff;
scsi_CDs[i].sector_size = 2048;
SCpnt = allocate_device(NULL, scsi_CDs[i].device->index, 1);
retries = 3;
do {
cmd[0] = READ_CAPACITY;
cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
memset ((void *) &cmd[2], 0, 8);
SCpnt->request.dev = 0xffff; /* Mark as really busy */
scsi_do_cmd (SCpnt,
(void *) cmd, (void *) buffer,
512, sr_init_done, SR_TIMEOUT,
MAX_RETRIES);
if (current == task[0])
while(SCpnt->request.dev != 0xfffe);
else
if (SCpnt->request.dev != 0xfffe){
SCpnt->request.waiting = current;
current->state = TASK_UNINTERRUPTIBLE;
while (SCpnt->request.dev != 0xfffe) schedule();
};
the_result = SCpnt->result;
retries--;
} while(the_result && retries);
SCpnt->request.dev = -1; /* Mark as not busy */
wake_up(&scsi_devices[SCpnt->index].device_wait);
if (the_result) {
scsi_CDs[i].capacity = 0x1fffff;
scsi_CDs[i].sector_size = 2048;
} else {
scsi_CDs[i].capacity = (buffer[0] << 24) |
(buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
scsi_CDs[i].sector_size = (buffer[4] << 24) |
(buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
if(scsi_CDs[i].sector_size != 2048 &&
scsi_CDs[i].sector_size != 512) {
printk ("scd%d : unsupported sector size %d.\n",
i, scsi_CDs[i].sector_size);
scsi_CDs[i].capacity = 0;
};
if(scsi_CDs[i].sector_size == 2048)
scsi_CDs[i].capacity *= 4;
};
printk("Scd sectorsize = %d bytes\n", scsi_CDs[i].sector_size);
scsi_CDs[i].use = 1;
scsi_CDs[i].ten = 1;
scsi_CDs[i].remap = 1;
......
......@@ -1197,7 +1197,7 @@ static int st_ioctl(struct inode * inode,struct file * file,
return result;
}
else
return (-EINVAL);
return scsi_ioctl(scsi_tapes[dev].device, cmd_in, (void *) arg);
}
......
......@@ -403,7 +403,7 @@ int ultrastor_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
memset(&mscp.command_link, 0, sizeof(mscp.command_link)); /*???*/
mscp.scsi_command_link_id = 0; /*???*/
mscp.length_of_sense_byte = 0; /*???*/
mscp.length_of_scsi_cdbs = ((SCpnt->cmnd[0] <= 0x1F) ? 6 : 10);
mscp.length_of_scsi_cdbs = COMMAND_SIZE(*(unsigned char *)SCpnt->cmnd);
memcpy(mscp.scsi_cdbs, SCpnt->cmnd, mscp.length_of_scsi_cdbs);
mscp.adapter_status = 0;
mscp.target_status = 0;
......@@ -496,8 +496,8 @@ int ultrastor_biosparam(int size, int dev, int *info)
info[0] = config.heads;
info[1] = config.sectors;
info[2] = (size + (s - 1)) / s;
if (info[2] > 1024)
info[2] = 1024;
/* if (info[2] > 1024)
info[2] = 1024; */
return 0;
}
......
......@@ -357,7 +357,7 @@ int wd7000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
short cdblen;
cdb = (unchar *) SCpnt->cmnd;
cdblen = (*cdb <= 0x1f ? 6 : 10);
cdblen = COMMAND_SIZE(*cdb);
idlun = ((SCpnt->target << 5) & 0xe0) | (SCpnt->lun & 7);
SCpnt->scsi_done = done;
SCpnt->SCp.phase = 1;
......@@ -580,7 +580,7 @@ int wd7000_abort(Scsi_Cmnd * SCpnt, int i)
printk("wd7000_abort: Scsi_Cmnd = 0x%08x, code = %d ", SCpnt, i);
printk("id %d lun %d cdb", SCpnt->target, SCpnt->lun);
{ int j; unchar *cdbj = (unchar *) SCpnt->cmnd;
for (j=0; j < (*cdbj <= 0x1f?6:10); j++) printk(" %02x", *(cdbj++));
for (j=0; j < COMMAND_SIZE(*cdbj); j++) printk(" %02x", *(cdbj++));
printk(" result %08x\n", SCpnt->result);
}
#endif
......@@ -606,7 +606,7 @@ int wd7000_biosparam(int size, int dev, int* info)
info[0] = 64;
info[1] = 32;
info[2] = (size + 2047) >> 11;
if (info[2] >= 1024) info[2] = 1024;
/* if (info[2] >= 1024) info[2] = 1024; */
return 0;
}
......@@ -40,7 +40,9 @@
extern void do_keyboard_interrupt(void);
extern void ctrl_alt_del(void);
extern void change_console(unsigned int new_console);
extern void fake_keyboard_interrupt(void);
#define fake_keyboard_interrupt() \
__asm__ __volatile__("int $0x21")
unsigned long kbd_flags = 0;
unsigned long kbd_dead_keys = 0;
......
......@@ -243,6 +243,8 @@ void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops)
continue;
if (filp->f_rdev != dev)
continue;
if (filp->f_inode && filp->f_inode->i_rdev == 0x0400)
continue;
if (filp->f_op != &tty_fops)
continue;
filp->f_op = fops;
......
......@@ -387,8 +387,9 @@ int tty_ioctl(struct inode * inode, struct file * file,
case TIOCNXCL:
return -EINVAL; /* not implemented */
case TIOCSCTTY:
if (current->leader && current->tty < 0
&& tty->session == 0) {
if ((current->leader && current->tty < 0 &&
tty->session == 0) ||
(arg == 1 && suser())) {
current->tty = dev;
tty->session = current->session;
tty->pgrp = current->pgrp;
......
......@@ -98,7 +98,7 @@ int bad_task_ptr(struct task_struct *p)
* This routine scans the pid tree and make sure the rep invarient still
* holds. Used for debugging only, since it's very slow....
*
* It looks a lot scarier than it really is.... we're doing nothing more
* It looks a lot scarier than it really is.... we're doing nothing more
* than verifying the doubly-linked list found in p_ysptr and p_osptr,
* and checking it corresponds with the process tree defined by p_cptr and
* p_pptr;
......
......@@ -125,11 +125,6 @@ static void (*bad_interrupt[16])(void) = {
bad_IRQ14_interrupt, bad_IRQ15_interrupt
};
void fake_keyboard_interrupt(void)
{
IRQ1_interrupt();
}
/*
* Initial irq handlers.
*/
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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