aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@cc.helsinki.fi>1993-04-09 14:45:07 +0000
committerNicolas Pitre <nico@cam.org>2007-08-19 14:19:14 -0400
commitd2c3ec4b1398e55d918df0d1fa718c9940d373f6 (patch)
treed10540f9ee2a6143e28f9706933b284b7d859ce6
parent3ccb23223d9cbee8e7946aa23f44a84ceff88d3c (diff)
downloadarchive-d2c3ec4b1398e55d918df0d1fa718c9940d373f6.tar.gz
ANNOUNCE: linux 0.99 patchlevel 8 availablev0.99-pl8
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
-rw-r--r--Configure8
-rw-r--r--Makefile2
-rw-r--r--boot/bootsect.S7
-rw-r--r--config.in22
-rw-r--r--fs/exec.c4
-rw-r--r--fs/ext/inode.c18
-rw-r--r--fs/ext/namei.c10
-rw-r--r--fs/ext2/balloc.c339
-rw-r--r--fs/ext2/dir.c34
-rw-r--r--fs/ext2/ialloc.c193
-rw-r--r--fs/ext2/inode.c188
-rw-r--r--fs/ext2/namei.c63
-rw-r--r--fs/ext2/truncate.c5
-rw-r--r--fs/fifo.c15
-rw-r--r--fs/filesystems.c6
-rw-r--r--fs/isofs/inode.c17
-rw-r--r--fs/minix/inode.c18
-rw-r--r--fs/minix/namei.c118
-rw-r--r--fs/msdos/inode.c52
-rw-r--r--fs/msdos/namei.c70
-rw-r--r--fs/namei.c39
-rw-r--r--fs/nfs/dir.c9
-rw-r--r--fs/nfs/inode.c14
-rw-r--r--fs/proc/inode.c8
-rw-r--r--fs/super.c17
-rw-r--r--fs/xiafs/inode.c18
-rw-r--r--fs/xiafs/namei.c16
-rw-r--r--include/linux/errno.h1
-rw-r--r--include/linux/ext2_fs.h25
-rw-r--r--include/linux/ext2_fs_i.h5
-rw-r--r--include/linux/ext2_fs_sb.h3
-rw-r--r--include/linux/ext_fs.h2
-rw-r--r--include/linux/fs.h4
-rw-r--r--include/linux/iso_fs.h2
-rw-r--r--include/linux/minix_fs.h2
-rw-r--r--include/linux/msdos_fs.h3
-rw-r--r--include/linux/msdos_fs_sb.h1
-rw-r--r--include/linux/nfs_fs.h3
-rw-r--r--include/linux/proc_fs.h2
-rw-r--r--include/linux/signal.h10
-rw-r--r--include/linux/sys.h3
-rw-r--r--include/linux/timer.h4
-rw-r--r--include/linux/unistd.h1
-rw-r--r--include/linux/xia_fs.h2
-rw-r--r--init/main.c45
-rw-r--r--kernel/FPU-emu/Makefile1
-rw-r--r--kernel/FPU-emu/README23
-rw-r--r--kernel/FPU-emu/Reg_constant.c111
-rw-r--r--kernel/FPU-emu/Reg_constant.h31
-rw-r--r--kernel/FPU-emu/control_w.h21
-rw-r--r--kernel/FPU-emu/errors.c3
-rw-r--r--kernel/FPU-emu/fpu_arith.c24
-rw-r--r--kernel/FPU-emu/fpu_aux.c3
-rw-r--r--kernel/FPU-emu/fpu_emu.h3
-rw-r--r--kernel/FPU-emu/fpu_entry.c19
-rw-r--r--kernel/FPU-emu/fpu_etc.c3
-rw-r--r--kernel/FPU-emu/fpu_proto.h40
-rw-r--r--kernel/FPU-emu/fpu_trig.c96
-rw-r--r--kernel/FPU-emu/get_address.c3
-rw-r--r--kernel/FPU-emu/load_store.c3
-rw-r--r--kernel/FPU-emu/precision.c134
-rw-r--r--kernel/FPU-emu/reg_add_sub.c3
-rw-r--r--kernel/FPU-emu/reg_compare.c12
-rw-r--r--kernel/FPU-emu/reg_ld_str.c76
-rw-r--r--kernel/FPU-emu/version.h5
-rw-r--r--kernel/blk_drv/scsi/aha1542.c11
-rw-r--r--kernel/blk_drv/scsi/aha1740.c315
-rw-r--r--kernel/blk_drv/scsi/aha1740.h17
-rw-r--r--kernel/blk_drv/scsi/hosts.c7
-rw-r--r--kernel/blk_drv/scsi/scsi.c19
-rw-r--r--kernel/blk_drv/scsi/scsi.h45
-rw-r--r--kernel/blk_drv/scsi/scsi_ioctl.c18
-rw-r--r--kernel/blk_drv/scsi/scsi_ioctl.h1
-rw-r--r--kernel/blk_drv/scsi/sd.c49
-rw-r--r--kernel/blk_drv/scsi/seagate.c4
-rw-r--r--kernel/blk_drv/scsi/sr.c100
-rw-r--r--kernel/blk_drv/scsi/st.c2
-rw-r--r--kernel/blk_drv/scsi/ultrastor.c6
-rw-r--r--kernel/blk_drv/scsi/wd7000.c6
-rw-r--r--kernel/chr_drv/keyboard.c4
-rw-r--r--kernel/chr_drv/tty_io.c2
-rw-r--r--kernel/chr_drv/tty_ioctl.c5
-rw-r--r--kernel/exit.c2
-rw-r--r--kernel/irq.c5
-rw-r--r--kernel/sched.c37
-rw-r--r--kernel/signal.c204
-rw-r--r--kernel/sys_call.S4
87 files changed, 1810 insertions, 1095 deletions
diff --git a/Configure b/Configure
index 94ac535..62e4675 100644
--- a/Configure
+++ b/Configure
@@ -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,"
diff --git a/Makefile b/Makefile
index cbcb8f7..e7fbf00 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/boot/bootsect.S b/boot/bootsect.S
index 7655cff..610acac 100644
--- a/boot/bootsect.S
+++ b/boot/bootsect.S
@@ -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:
diff --git a/config.in b/config.in
index 5c6ffb3..df3891e 100644
--- a/config.in
+++ b/config.in
@@ -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
diff --git a/fs/exec.c b/fs/exec.c
index 44ec13b..0aa24a3 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -550,7 +550,7 @@ restart_interp:
p = copy_strings(1, &i_name, page, p, 2);
argc++;
if (!p) {
- retval = -ENOMEM;
+ retval = -E2BIG;
goto exec_error1;
}
/*
@@ -578,7 +578,7 @@ restart_interp:
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;
}
}
diff --git a/fs/ext/inode.c b/fs/ext/inode.c
index 33942a1..ff8efc1 100644
--- a/fs/ext/inode.c
+++ b/fs/ext/inode.c
@@ -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)
diff --git a/fs/ext/namei.c b/fs/ext/namei.c
index 62045f1..49e22d3 100644
--- a/fs/ext/namei.c
+++ b/fs/ext/namei.c
@@ -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;
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 6ea0c62..a080f44 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr)
*
+ * Enhanced block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
*/
/* balloc.c contains the blocks allocation and deallocation routines */
@@ -27,6 +28,8 @@
#include <linux/string.h>
#include <linux/locks.h>
+#include <asm/bitops.h>
+
#define clear_block(addr,size) \
__asm__("cld\n\t" \
"rep\n\t" \
@@ -35,44 +38,66 @@
:"a" (0), "c" (size/4), "D" ((long) (addr)) \
:"cx", "di")
-#define set_bit(nr,addr) ( \
-{ \
- char res; \
- __asm__ __volatile__("btsl %1,%2\n\tsetb %0" \
- :"=q" (res) \
- :"r" (nr),"m" (*(addr))); \
- 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;
+}
-#define clear_bit(nr,addr) ( \
-{ \
- char res; \
- __asm__ __volatile__("btrl %1,%2\n\tsetnb %0" \
- :"=q" (res) \
- :"r" (nr),"m" (*(addr))); \
- res; \
-} \
-)
+static inline int find_next_zero_bit(unsigned *addr, int size, int offset)
+{
+ unsigned *p = ((unsigned *) addr) + (offset >> 5);
+ int set = 0, bit = offset & 31, res;
+
+ if (bit) {
+ /* Look for zero in first byte */
+ __asm__("
+ bsfl %1,%0
+ jne 1f
+ movl $32, %0
+1: " : "=r" (set) : "r" (~(*p >> bit)));
+ if (set < (32-bit))
+ return set + offset;
+ set = 32-bit;
+ p++;
+ }
+ /* No zero yet, search remaining full bytes for a zero */
+ res = find_first_zero_bit(p, size-32*(p-addr));
+ return (offset + set + res);
+}
-#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 char * find_first_zero_byte(char *addr,int size)
+{
+ char *res;
+ if (!size)
+ return 0;
+ __asm__("
+ cld
+ mov $0,%%eax
+ repnz; scasb
+ jnz 1f
+ dec %%edi
+1: " : "=D" (res) : "0" (addr), "c" (size) : "ax");
+ return res;
+}
static void read_block_bitmap (struct super_block * sb,
unsigned int block_group,
@@ -90,11 +115,14 @@ static void read_block_bitmap (struct super_block * sb,
block_group, group_desc, desc);
panic ("read_block_bitmap: Group descriptor not loaded");
}
- gdp = (struct ext2_group_desc *) sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
+ gdp = (struct ext2_group_desc *)
+ sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
bh = bread (sb->s_dev, gdp[desc].bg_block_bitmap, sb->s_blocksize);
if (!bh) {
- printk ("block_group = %d,group_desc = %d,desc = %d,block_bitmap = %d\n",
- block_group, group_desc, desc, gdp[desc].bg_block_bitmap);
+ printk ("block_group = %d,group_desc = %d,"
+ "desc = %d,block_bitmap = %d\n",
+ block_group, group_desc, desc,
+ gdp[desc].bg_block_bitmap);
panic ("read_block_bitmap: Cannot read block bitmap");
}
sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group;
@@ -112,8 +140,8 @@ static void read_block_bitmap (struct super_block * sb,
* 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups,
* this function reads the bitmap without maintaining a LRU cache.
*/
-static int load_block_bitmap (struct super_block * sb,
- unsigned int block_group)
+static int load__block_bitmap (struct super_block * sb,
+ unsigned int block_group)
{
int i, j;
unsigned long block_bitmap_number;
@@ -124,14 +152,13 @@ static int load_block_bitmap (struct super_block * sb,
block_group, sb->u.ext2_sb.s_groups_count);
panic ("load_block_bitmap: block_group >= groups_count");
}
- if (sb->u.ext2_sb.s_loaded_block_bitmaps > 0 &&
- sb->u.ext2_sb.s_block_bitmap_number[0] == block_group)
- return 0;
if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) {
if (sb->u.ext2_sb.s_block_bitmap[block_group]) {
- if (sb->u.ext2_sb.s_block_bitmap_number[block_group] != block_group)
- panic ("load_block_bitmap: block_group != block_bitmap_number");
+ if (sb->u.ext2_sb.s_block_bitmap_number[block_group]
+ != block_group)
+ panic ("load_block_bitmap: "
+ "block_group != block_bitmap_number");
else
return block_group;
} else {
@@ -156,11 +183,13 @@ static int load_block_bitmap (struct super_block * sb,
sb->u.ext2_sb.s_block_bitmap_number[0] = block_bitmap_number;
sb->u.ext2_sb.s_block_bitmap[0] = block_bitmap;
} else {
- if (sb->u.ext2_sb.s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED)
+ if (sb->u.ext2_sb.s_loaded_block_bitmaps <
+ EXT2_MAX_GROUP_LOADED)
sb->u.ext2_sb.s_loaded_block_bitmaps++;
else
- brelse (sb->u.ext2_sb.s_block_bitmap[EXT2_MAX_GROUP_LOADED - 1]);
- for (j = sb->u.ext2_sb.s_loaded_block_bitmaps - 1; j > 0; j--) {
+ brelse (sb->u.ext2_sb.s_block_bitmap
+ [EXT2_MAX_GROUP_LOADED - 1]);
+ for (j = sb->u.ext2_sb.s_loaded_block_bitmaps-1; j>0; j--) {
sb->u.ext2_sb.s_block_bitmap_number[j] =
sb->u.ext2_sb.s_block_bitmap_number[j - 1];
sb->u.ext2_sb.s_block_bitmap[j] =
@@ -171,6 +200,21 @@ static int load_block_bitmap (struct super_block * sb,
return 0;
}
+static inline int load_block_bitmap (struct super_block * sb,
+ unsigned int block_group)
+{
+ if (sb->u.ext2_sb.s_loaded_block_bitmaps > 0 &&
+ sb->u.ext2_sb.s_block_bitmap_number[0] == block_group)
+ return 0;
+
+ if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED &&
+ sb->u.ext2_sb.s_block_bitmap_number[block_group] == block_group &&
+ sb->u.ext2_sb.s_block_bitmap[block_group])
+ return block_group;
+
+ return load__block_bitmap (sb, block_group);
+}
+
void ext2_free_block (struct super_block * sb, unsigned long block)
{
struct buffer_head * bh;
@@ -236,20 +280,27 @@ void ext2_free_block (struct super_block * sb, unsigned long block)
}
/*
- * ext2_new_block does not use a very clever allocation algorithm yet
- *
- * Currently, the group descriptors are scanned until a free block is found
+ * ext2_new_block uses a goal block to assist allocation. If the goal is
+ * free, or there is a free block within 32 blocks of the goal, that block
+ * is allocated. Otherwise a forward search is made for a free block; within
+ * each block group the search first looks for an entire free byte in the block
+ * bitmap, and then for any free bit if that fails.
*/
-int ext2_new_block (struct super_block * sb, unsigned long block_group)
+int ext2_new_block (struct super_block * sb, unsigned long goal)
{
struct buffer_head * bh;
- int i, j;
+ char *p, *r;
+ int i, j, k;
+ unsigned long lmap;
unsigned long group_desc;
unsigned long desc;
int bitmap_nr;
struct ext2_group_desc * gdp;
struct ext2_super_block * es;
+#ifdef EXT2FS_DEBUG
+ static int goal_hits = 0, goal_attempts = 0;
+#endif
if (!sb) {
printk ("ext2_new_block: nonexistant device");
return 0;
@@ -260,49 +311,158 @@ int ext2_new_block (struct super_block * sb, unsigned long block_group)
unlock_super (sb);
return 0;
}
+
+#ifdef EXT2FS_DEBUG
+ printk ("ext2_new_block: goal=%d.\n", goal);
+#endif
repeat:
- group_desc = 0;
- desc = 0;
- gdp = NULL;
- for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
+ /* First, test whether the goal block is free. */
+ i = ((goal - sb->u.ext2_sb.s_first_data_block) /
+ EXT2_BLOCKS_PER_GROUP(sb));
+ group_desc = i / EXT2_DESC_PER_BLOCK(sb);
+ desc = i % EXT2_DESC_PER_BLOCK(sb);
+ gdp = (struct ext2_group_desc *)
+ sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
+ if (!gdp) {
+ panic ("ext2_new_block: Descriptor not loaded");
+ }
+ if (gdp[desc].bg_free_blocks_count > 0) {
+ j = ((goal - sb->u.ext2_sb.s_first_data_block) %
+ EXT2_BLOCKS_PER_GROUP(sb));
+#ifdef EXT2FS_DEBUG
+ if (j)
+ goal_attempts++;
+#endif
+ bitmap_nr = load_block_bitmap (sb, i);
+ bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
+ if (!bh) {
+ printk ("Cannot load bitmap_nr %d.\n",
+ bitmap_nr);
+ unlock_super (sb);
+ return 0;
+ }
+#ifdef EXT2FS_DEBUG
+ printk ("goal is at %d[%d,%d]:%d.\n",
+ i, group_desc, desc, j);
+#endif
+ if (!test_bit(j, bh->b_data)) {
+#ifdef EXT2FS_DEBUG
+ goal_hits++;
+ printk ("ext2_new_block: goal bit allocated.\n");
+#endif
+ goto got_block;
+ }
+ if (j) {
+ /* The goal was occupied; search forward for a free
+ block within the next 32 blocks */
+ lmap = (((((unsigned long *) bh->b_data)[j >> 5])
+ >> ((j&31)+1)) |
+ ((((unsigned long *) bh->b_data)[(j>>5)+1])
+ <<(31-(j&31))));
+ if (lmap != 0xffffffffl) {
+ __asm__ ("bsfl %1,%0" :
+ "=r" (k) :
+ "r" (~lmap)); k++;
+ if ((j + k) < EXT2_BLOCKS_PER_GROUP(sb)) {
+ j += k;
+ goto got_block;
+ }
+ }
+ }
+
+#ifdef EXT2FS_DEBUG
+ printk ("Bit not found near goal\n");
+#endif
+ /* There has been no free block found in the near vicinity
+ of the goal: do a search forward through the block groups,
+ searching in each group first for an entire free byte in
+ the bitmap and then for any free bit.
+
+ Search first in the remainder of the current group; then,
+ cyclicly search throught the rest of the groups. */
+ p = ((char *) bh->b_data) + (j>>3);
+ r = find_first_zero_byte (p,
+ (EXT2_BLOCKS_PER_GROUP(sb)-j+7)>>3);
+ k = (r - ((char *) bh->b_data)) << 3;
+ if (k < EXT2_BLOCKS_PER_GROUP(sb)) {
+ j = k;
+ goto got_block;
+ }
+ k = find_next_zero_bit ((unsigned long *) bh->b_data,
+ EXT2_BLOCKS_PER_GROUP(sb),
+ j);
+ if (k < EXT2_BLOCKS_PER_GROUP(sb)) {
+ j = k;
+ goto got_block;
+ }
+ }
+
+#ifdef EXT2FS_DEBUG
+ printk ("Bit not found in block group %d.\n", i);
+#endif
+ /* Now search the rest of the groups. We assume that group_desc, desc,
+ i and gdp correctly point to the last group visited. */
+ for (k = 0; k < sb->u.ext2_sb.s_groups_count; k++) {
+ i++;
+ if (i >= sb->u.ext2_sb.s_groups_count) {
+ i = 0;
+ group_desc = 0;
+ desc = 0;
+ gdp = (struct ext2_group_desc *)
+ sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
+ }
+ else {
+ desc++;
+ if (desc >= EXT2_DESC_PER_BLOCK(sb)) {
+ group_desc++;
+ desc = 0;
+ gdp = (struct ext2_group_desc *)
+ sb->u.ext2_sb.s_group_desc[group_desc]
+ ->b_data;
+ }
+ }
if (!gdp) {
- if (!sb->u.ext2_sb.s_group_desc[group_desc])
- panic ("ext2_new_block: Descriptor not loaded");
- gdp = (struct ext2_group_desc *) sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
+ panic ("ext2_new_block: Descriptor not loaded");
}
if (gdp[desc].bg_free_blocks_count > 0)
break;
- desc ++;
- if (desc == EXT2_DESC_PER_BLOCK(sb)) {
- group_desc ++;
- desc = 0;
- gdp = NULL;
- }
}
- if (i >= sb->u.ext2_sb.s_groups_count) {
+ if (k >= sb->u.ext2_sb.s_groups_count) {
unlock_super (sb);
return 0;
}
-#ifdef EXT2FS_DEBUG
- printk ("ext2_new_block: using block group %d(%d,%d,%d)\n",
- i, group_desc, desc, gdp[desc].bg_free_blocks_count);
-#endif
bitmap_nr = load_block_bitmap (sb, i);
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
if (!bh) {
printk ("block_group = %d\n", i);
panic ("ext2_new_block: Unable to load group bitmap");
}
- if ((j = find_first_zero (bh->b_data, EXT2_BLOCKS_PER_GROUP(sb))) <
- EXT2_BLOCKS_PER_GROUP(sb)) {
- if (set_bit (j, bh->b_data)) {
- printk ("ext2_new_block: bit already set\n");
- goto repeat;
- }
- bh->b_dirt = 1;
- } else
+ r = find_first_zero_byte (bh->b_data,
+ EXT2_BLOCKS_PER_GROUP(sb) >> 3);
+ j = (r-bh->b_data) << 3;
+ if (j >= EXT2_BLOCKS_PER_GROUP(sb))
+ j = find_first_zero_bit ((unsigned long *) bh->b_data,
+ EXT2_BLOCKS_PER_GROUP(sb));
+ if (j >= EXT2_BLOCKS_PER_GROUP(sb)) {
+ printk ("ext2_new_block: "
+ "Unable to locate free bit in block group %d.\n",i);
+ unlock_super (sb);
+ return 0;
+ }
+
+got_block:
+#ifdef EXT2FS_DEBUG
+ printk ("ext2_new_block: using block group %d(%d,%d,%d)\n",
+ i, group_desc, desc, gdp[desc].bg_free_blocks_count);
+#endif
+
+ if (set_bit (j, bh->b_data)) {
+ printk ("ext2_new_block: bit already set\n");
goto repeat;
+ }
+ bh->b_dirt = 1;
+
#ifdef EXT2FS_DEBUG
printk ("ext2_new_block: found bit %d\n", j);
#endif
@@ -311,6 +471,7 @@ repeat:
if (j >= sb->u.ext2_sb.s_blocks_count) {
printk ("block_group = %d,block=%d\n", i, j);
printk ("ext2_new_block: block >= blocks count");
+ unlock_super (sb);
return 0;
}
if (!(bh = getblk (sb->s_dev, j, sb->s_blocksize))) {
@@ -323,7 +484,8 @@ repeat:
bh->b_dirt = 1;
brelse (bh);
#ifdef EXT2FS_DEBUG
- printk("ext2_new_block: allocating block %d\n", j);
+ printk("ext2_new_block: allocating block %d. "
+ "Goal hits %d of %d.\n", j, goal_hits, goal_attempts);
#endif
gdp[desc].bg_free_blocks_count --;
sb->u.ext2_sb.s_group_desc[group_desc]->b_dirt = 1;
@@ -344,7 +506,7 @@ unsigned long ext2_count_free_blocks (struct super_block *sb)
int bitmap_nr;
struct ext2_group_desc * gdp;
int i;
-
+
lock_super (sb);
es = (struct ext2_super_block *) sb->u.ext2_sb.s_sbh->b_data;
desc_count = 0;
@@ -355,16 +517,19 @@ unsigned long ext2_count_free_blocks (struct super_block *sb)
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
if (!gdp) {
if (!sb->u.ext2_sb.s_group_desc[group_desc]) {
- printk ("ext2_count_free_block: Descriptor not loaded\n");
+ printk ("ext2_count_free_block: "
+ "Descriptor not loaded\n");
break;
}
- gdp = (struct ext2_group_desc *) sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
+ gdp = (struct ext2_group_desc *)
+ sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
}
desc_count += gdp[desc].bg_free_blocks_count;
bitmap_nr = load_block_bitmap (sb, i);
if (sb->u.ext2_sb.s_block_bitmap[bitmap_nr])
- x = ext2_count_free (sb->u.ext2_sb.s_block_bitmap[bitmap_nr],
- sb->s_blocksize);
+ x = ext2_count_free
+ (sb->u.ext2_sb.s_block_bitmap[bitmap_nr],
+ sb->s_blocksize);
else {
x = 0;
printk ("Cannot load bitmap for group %d\n", i);
@@ -380,7 +545,7 @@ unsigned long ext2_count_free_blocks (struct super_block *sb)
}
}
printk("ext2_count_free_blocks: stored = %d, computed = %d, %d\n",
- es->s_free_blocks_count, desc_count, bitmap_count);
+ es->s_free_blocks_count, desc_count, bitmap_count);
unlock_super (sb);
return bitmap_count;
#else
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 0c7f9c1..937d1b2 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -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;
}
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index 017e5ee..e0df46f 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -1,8 +1,11 @@
+
/*
* 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 @@ repeat:
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 @@ repeat:
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 @@ repeat:
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
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 7086c1d..0451fb1 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -8,6 +8,8 @@
* linux/fs/minix/inode.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * Goal-directed block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
*/
#include <linux/sched.h>
@@ -38,7 +40,7 @@ void ext2_put_super (struct super_block * sb)
lock_super (sb);
es = (struct ext2_super_block *) sb->u.ext2_sb.s_sbh->b_data;
- es->s_valid = 1;
+ es->s_valid = sb->u.ext2_sb.s_was_mounted_valid;
sb->u.ext2_sb.s_sbh->b_dirt = 1;
#ifndef DONT_USE_DCACHE
ext2_dcache_invalidate (sb->s_dev);
@@ -105,7 +107,8 @@ static int convert_pre_02b_fs (struct super_block * sb,
return 1;
}
-struct super_block * ext2_read_super (struct super_block * s, void * data)
+struct super_block * ext2_read_super (struct super_block * s, void * data,
+ int silent)
{
struct buffer_head * bh;
struct ext2_super_block * es;
@@ -122,6 +125,7 @@ struct super_block * ext2_read_super (struct super_block * s, void * data)
return NULL;
}
es = (struct ext2_super_block *) bh->b_data;
+ s->s_magic = es->s_magic;
s->s_blocksize = EXT2_MIN_BLOCK_SIZE << es->s_log_block_size;
s->u.ext2_sb.s_inodes_count = es->s_inodes_count;
s->u.ext2_sb.s_blocks_count = es->s_blocks_count;
@@ -131,8 +135,11 @@ struct super_block * ext2_read_super (struct super_block * s, void * data)
s->u.ext2_sb.s_log_frag_size = es->s_log_frag_size;
s->u.ext2_sb.s_frag_size = EXT2_MIN_FRAG_SIZE <<
es->s_log_frag_size;
- s->u.ext2_sb.s_frags_per_block = s->s_blocksize /
+ if (s->u.ext2_sb.s_frag_size)
+ s->u.ext2_sb.s_frags_per_block = s->s_blocksize /
s->u.ext2_sb.s_frag_size;
+ else
+ s->s_magic = 0;
s->u.ext2_sb.s_blocks_per_group = es->s_blocks_per_group;
s->u.ext2_sb.s_frags_per_group = es->s_frags_per_group;
s->u.ext2_sb.s_inodes_per_group = es->s_inodes_per_group;
@@ -140,8 +147,8 @@ struct super_block * ext2_read_super (struct super_block * s, void * data)
sizeof (struct ext2_inode);
s->u.ext2_sb.s_desc_per_block = s->s_blocksize /
sizeof (struct ext2_group_desc);
- s->s_magic = es->s_magic;
s->u.ext2_sb.s_sbh = bh;
+ s->u.ext2_sb.s_was_mounted_valid = es->s_valid;
s->u.ext2_sb.s_rename_lock = 0;
s->u.ext2_sb.s_rename_wait = NULL;
if (s->s_magic == EXT2_OLD_SUPER_MAGIC) {
@@ -177,7 +184,9 @@ struct super_block * ext2_read_super (struct super_block * s, void * data)
s->s_dev = 0;
unlock_super (s);
brelse (bh);
- printk ("EXT2-fs: magic match failed\n");
+ if (!silent)
+ printk("VFS: Can't find an ext2fs filesystem on dev 0x%04x.\n",
+ dev);
return NULL;
}
if (s->s_blocksize != s->u.ext2_sb.s_frag_size) {
@@ -188,7 +197,8 @@ struct super_block * ext2_read_super (struct super_block * s, void * data)
return NULL;
}
if (!es->s_valid)
- printk ("EXT2-fs warning: mounting non valid file system\n");
+ printk ("EXT2-fs warning: mounting unchecked file system, "
+ "running e2fsck is recommended\n");
s->u.ext2_sb.s_groups_count = (s->u.ext2_sb.s_blocks_count -
s->u.ext2_sb.s_first_data_block +
(EXT2_BLOCK_SIZE(s) * 8) - 1) /
@@ -322,7 +332,11 @@ void ext2_statfs (struct super_block * sb, struct statfs * buf)
&buf->f_blocks);
tmp = ext2_count_free_blocks (sb);
put_fs_long (tmp, &buf->f_bfree);
- put_fs_long (tmp - sb->u.ext2_sb.s_r_blocks_count, &buf->f_bavail);
+ if (tmp >= sb->u.ext2_sb.s_r_blocks_count)
+ put_fs_long (tmp - sb->u.ext2_sb.s_r_blocks_count,
+ &buf->f_bavail);
+ else
+ put_fs_long (0, &buf->f_bavail);
put_fs_long (sb->u.ext2_sb.s_inodes_count, &buf->f_files);
put_fs_long (ext2_count_free_inodes(sb), &buf->f_ffree);
put_fs_long (EXT2_NAME_LEN, &buf->f_namelen);
@@ -398,9 +412,9 @@ int ext2_bmap (struct inode * inode, int block)
}
static struct buffer_head * inode_getblk (struct inode * inode, int nr,
- int create)
+ int create, int new_block)
{
- int tmp;
+ int tmp, goal = 0;
unsigned long * p;
struct buffer_head * result;
int blocks = inode->i_sb->s_blocksize / 512;
@@ -415,9 +429,32 @@ repeat:
brelse (result);
goto repeat;
}
- if (!create)
+ if (!create || new_block >=
+ (current->rlim[RLIMIT_FSIZE].rlim_cur >>
+ EXT2_BLOCK_SIZE_BITS(inode->i_sb)))
return NULL;
- tmp = ext2_new_block (inode->i_sb, inode->u.ext2_i.i_block_group);
+ if (inode->u.ext2_i.i_next_alloc_block == new_block)
+ goal = inode->u.ext2_i.i_next_alloc_goal;
+#ifdef EXT2FS_DEBUG
+ printk ("ext2 inode_getblk: hint = %d,", goal);
+#endif
+ if (!goal) {
+ for (tmp = nr-1; tmp>=0; tmp--) {
+ if (inode->u.ext2_i.i_data[tmp]) {
+ goal = inode->u.ext2_i.i_data[tmp];
+ break;
+ }
+ }
+ if (!goal)
+ goal = (inode->u.ext2_i.i_block_group *
+ EXT2_BLOCKS_PER_GROUP(inode->i_sb))
+ + inode->i_sb->u.ext2_sb.s_first_data_block;
+ }
+
+#ifdef EXT2FS_DEBUG
+ printk (" goal = %d.\n", goal);
+#endif
+ tmp = ext2_new_block (inode->i_sb, goal);
if (!tmp)
return NULL;
result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
@@ -427,6 +464,8 @@ repeat:
goto repeat;
}
*p = tmp;
+ inode->u.ext2_i.i_next_alloc_block = new_block;
+ inode->u.ext2_i.i_next_alloc_goal = tmp;
inode->i_ctime = CURRENT_TIME;
inode->i_blocks += blocks;
inode->i_dirt = 1;
@@ -435,9 +474,9 @@ repeat:
static struct buffer_head * block_getblk (struct inode * inode,
struct buffer_head * bh, int nr,
- int create, int blocksize)
+ int create, int blocksize, int new_block)
{
- int tmp;
+ int tmp, goal;
unsigned long * p;
struct buffer_head * result;
int blocks = inode->i_sb->s_blocksize / 512;
@@ -464,11 +503,25 @@ repeat:
brelse (result);
goto repeat;
}
- if (!create) {
+ if (!create || new_block >=
+ (current->rlim[RLIMIT_FSIZE].rlim_cur >>
+ EXT2_BLOCK_SIZE_BITS(inode->i_sb))) {
brelse (bh);
return NULL;
}
- tmp = ext2_new_block (inode->i_sb, inode->u.ext2_i.i_block_group);
+ if (inode->u.ext2_i.i_next_alloc_block == new_block)
+ goal = inode->u.ext2_i.i_next_alloc_goal;
+ if (!goal) {
+ for (tmp = nr-1; tmp>=0; tmp--) {
+ if (bh->b_data[tmp]) {
+ goal = bh->b_data[tmp];
+ break;
+ }
+ }
+ if (!goal)
+ goal = bh->b_blocknr+1;
+ }
+ tmp = ext2_new_block (inode->i_sb, goal);
if (!tmp) {
#ifdef EXT2FS_DEBUG
printk ("inode_getblk: ext2_new_block returned 0\n");
@@ -484,8 +537,11 @@ repeat:
}
*p = tmp;
bh->b_dirt = 1;
+ inode->i_ctime = CURRENT_TIME;
inode->i_blocks += blocks;
inode->i_dirt = 1;
+ inode->u.ext2_i.i_next_alloc_block = new_block;
+ inode->u.ext2_i.i_next_alloc_goal = tmp;
brelse (bh);
return result;
}
@@ -494,6 +550,7 @@ struct buffer_head * ext2_getblk (struct inode * inode, int block,
int create)
{
struct buffer_head * bh;
+ int b;
unsigned long addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
if (block < 0) {
@@ -506,30 +563,44 @@ struct buffer_head * ext2_getblk (struct inode * inode, int block,
printk ("ext2_getblk: block > big\n");
return NULL;
}
+ /* If this is a sequential block allocation, set the next_alloc_block
+ to this block now so that all the indblock and data block allocations
+ use the same goal zone */
+#ifdef EXT2FS_DEBUG
+ printk ("ext2_getblk: block %d, next %d, goal %d.\n", block,
+ inode->u.ext2_i.i_next_alloc_block,
+ inode->u.ext2_i.i_next_alloc_goal);
+#endif
+ if (block == inode->u.ext2_i.i_next_alloc_block + 1) {
+ inode->u.ext2_i.i_next_alloc_block++;
+ inode->u.ext2_i.i_next_alloc_goal++;
+ }
+
+ b = block;
if (block < EXT2_NDIR_BLOCKS)
- return inode_getblk (inode, block, create);
+ return inode_getblk (inode, block, create, b);
block -= EXT2_NDIR_BLOCKS;
if (block < addr_per_block) {
- bh = inode_getblk (inode, EXT2_IND_BLOCK, create);
+ bh = inode_getblk (inode, EXT2_IND_BLOCK, create, b);
return block_getblk (inode, bh, block, create,
- inode->i_sb->s_blocksize);
+ inode->i_sb->s_blocksize, b);
}
block -= addr_per_block;
if (block < addr_per_block * addr_per_block) {
- bh = inode_getblk (inode, EXT2_DIND_BLOCK, create);
+ bh = inode_getblk (inode, EXT2_DIND_BLOCK, create,b );
bh = block_getblk (inode, bh, block / addr_per_block, create,
- inode->i_sb->s_blocksize);
+ inode->i_sb->s_blocksize, b);
return block_getblk (inode, bh, block & (addr_per_block - 1),
- create, inode->i_sb->s_blocksize);
+ create, inode->i_sb->s_blocksize, b);
}
block -= addr_per_block * addr_per_block;
- bh = inode_getblk (inode, EXT2_IND_BLOCK, create);
+ bh = inode_getblk (inode, EXT2_TIND_BLOCK, create, b);
bh = block_getblk (inode, bh, block / (addr_per_block * addr_per_block),
- create, inode->i_sb->s_blocksize);
+ create, inode->i_sb->s_blocksize, b);
bh = block_getblk (inode, bh, (block / addr_per_block) & (addr_per_block - 1),
- create, inode->i_sb->s_blocksize);
+ create, inode->i_sb->s_blocksize, b);
return block_getblk (inode, bh, block & (addr_per_block - 1), create,
- inode->i_sb->s_blocksize);
+ inode->i_sb->s_blocksize, b);
}
struct buffer_head * ext2_bread (struct inode * inode, int block, int create)
@@ -587,21 +658,26 @@ void ext2_read_inode (struct inode * inode)
inode->i_atime = raw_inode->i_atime;
inode->i_ctime = raw_inode->i_ctime;
inode->i_mtime = raw_inode->i_mtime;
- inode->u.ext2_i.i_dtime = raw_inode->i_dtime;
+ if (!S_ISFIFO(inode->i_mode))
+ inode->u.ext2_i.i_dtime = raw_inode->i_dtime;
inode->i_blksize = inode->i_sb->s_blocksize;
inode->i_blocks = raw_inode->i_blocks;
- inode->u.ext2_i.i_flags = raw_inode->i_flags;
- inode->u.ext2_i.i_faddr = raw_inode->i_faddr;
- inode->u.ext2_i.i_frag = raw_inode->i_frag;
- inode->u.ext2_i.i_fsize = raw_inode->i_fsize;
- inode->u.ext2_i.i_file_acl = raw_inode->i_file_acl;
- inode->u.ext2_i.i_dir_acl = raw_inode->i_dir_acl;
- inode->u.ext2_i.i_version = raw_inode->i_version;
- inode->u.ext2_i.i_block_group = block_group;
- if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
- inode->i_rdev = raw_inode->i_block[0];
- else for (block = 0; block < EXT2_N_BLOCKS; block++)
- inode->u.ext2_i.i_data[block] = raw_inode->i_block[block];
+ if (!S_ISFIFO(inode->i_mode)) {
+ inode->u.ext2_i.i_flags = raw_inode->i_flags;
+ inode->u.ext2_i.i_faddr = raw_inode->i_faddr;
+ inode->u.ext2_i.i_frag = raw_inode->i_frag;
+ inode->u.ext2_i.i_fsize = raw_inode->i_fsize;
+ inode->u.ext2_i.i_file_acl = raw_inode->i_file_acl;
+ inode->u.ext2_i.i_dir_acl = raw_inode->i_dir_acl;
+ inode->u.ext2_i.i_version = raw_inode->i_version;
+ inode->u.ext2_i.i_block_group = block_group;
+ inode->u.ext2_i.i_next_alloc_block = 0;
+ inode->u.ext2_i.i_next_alloc_goal = 0;
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+ inode->i_rdev = raw_inode->i_block[0];
+ else for (block = 0; block < EXT2_N_BLOCKS; block++)
+ inode->u.ext2_i.i_data[block] = raw_inode->i_block[block];
+ }
brelse (bh);
inode->i_op = NULL;
if (S_ISREG(inode->i_mode))
@@ -614,14 +690,8 @@ void ext2_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 ext2_write_inode (struct inode * inode)
@@ -664,19 +734,21 @@ void ext2_write_inode (struct inode * inode)
raw_inode->i_atime = inode->i_atime;
raw_inode->i_ctime = inode->i_ctime;
raw_inode->i_mtime = inode->i_mtime;
- raw_inode->i_dtime = inode->u.ext2_i.i_dtime;
raw_inode->i_blocks = inode->i_blocks;
- raw_inode->i_flags = inode->u.ext2_i.i_flags;
- raw_inode->i_faddr = inode->u.ext2_i.i_faddr;
- raw_inode->i_frag = inode->u.ext2_i.i_frag;
- raw_inode->i_fsize = inode->u.ext2_i.i_fsize;
- raw_inode->i_file_acl = inode->u.ext2_i.i_file_acl;
- raw_inode->i_dir_acl = inode->u.ext2_i.i_dir_acl;
- raw_inode->i_version = inode->u.ext2_i.i_version;
- if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
- raw_inode->i_block[0] = inode->i_rdev;
- else for (block = 0; block < EXT2_N_BLOCKS; block++)
- raw_inode->i_block[block] = inode->u.ext2_i.i_data[block];
+ if (!S_ISFIFO(inode->i_mode)) {
+ raw_inode->i_dtime = inode->u.ext2_i.i_dtime;
+ raw_inode->i_flags = inode->u.ext2_i.i_flags;
+ raw_inode->i_faddr = inode->u.ext2_i.i_faddr;
+ raw_inode->i_frag = inode->u.ext2_i.i_frag;
+ raw_inode->i_fsize = inode->u.ext2_i.i_fsize;
+ raw_inode->i_file_acl = inode->u.ext2_i.i_file_acl;
+ raw_inode->i_dir_acl = inode->u.ext2_i.i_dir_acl;
+ raw_inode->i_version = inode->u.ext2_i.i_version;
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+ raw_inode->i_block[0] = inode->i_rdev;
+ else for (block = 0; block < EXT2_N_BLOCKS; block++)
+ raw_inode->i_block[block] = inode->u.ext2_i.i_data[block];
+ }
bh->b_dirt = 1;
inode->i_dirt = 0;
brelse (bh);
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 2088888..c133e6a 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -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 @@ start_up:
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;
diff --git a/fs/ext2/truncate.c b/fs/ext2/truncate.c
index bc613bc..0028845 100644
--- a/fs/ext2/truncate.c
+++ b/fs/ext2/truncate.c
@@ -47,7 +47,7 @@ repeat:
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 @@ repeat:
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;
diff --git a/fs/fifo.c b/fs/fifo.c
index 868558b..78ceb4b 100644
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -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;
+}
diff --git a/fs/filesystems.c b/fs/filesystems.c
index 81f9de3..7c9f71c 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -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
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index ff86ea2..4a087f9 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -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
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index a019314..1f17383 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -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)
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index e7e9702..c5e8285 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -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 @@ start_up:
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 @@ start_up:
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;
diff --git a/fs/msdos/inode.c b/fs/msdos/inode.c
index c19df60..1d690a7 100644
--- a/fs/msdos/inode.c
+++ b/fs/msdos/inode.c
@@ -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;
}
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index 66b9ec7..082c558 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -293,11 +293,36 @@ mkdir_error:
}
+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);
diff --git a/fs/namei.c b/fs/namei.c
index d615e4b..3a3e62a 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -20,12 +20,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
* kernel data space before using them..
@@ -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);
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 81f3fd8..c5526f9 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -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;
}
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 7fa86d0..cf72f40 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -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);
}
/*
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index e788d41..22ef31b 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -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;
diff --git a/fs/super.c b/fs/super.c
index 4820491..886889e 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -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;
}
}
diff --git a/fs/xiafs/inode.c b/fs/xiafs/inode.c
index 4d6ac37..d93e971 100644
--- a/fs/xiafs/inode.c
+++ b/fs/xiafs/inode.c
@@ -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)
diff --git a/fs/xiafs/namei.c b/fs/xiafs/namei.c
index faaf466..9a5dfd4 100644
--- a/fs/xiafs/namei.c
+++ b/fs/xiafs/namei.c
@@ -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;
diff --git a/include/linux/errno.h b/include/linux/errno.h
index 1a40c1a..792213f 100644
--- a/include/linux/errno.h
+++ b/include/linux/errno.h
@@ -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
diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
index 145e62a..f77a678 100644
--- a/include/linux/ext2_fs.h
+++ b/include/linux/ext2_fs.h
@@ -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;
diff --git a/include/linux/ext2_fs_i.h b/include/linux/ext2_fs_i.h
index 09d1371..ce26502 100644
--- a/include/linux/ext2_fs_i.h
+++ b/include/linux/ext2_fs_i.h
@@ -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];
};
diff --git a/include/linux/ext2_fs_sb.h b/include/linux/ext2_fs_sb.h
index 69d2bc1..81c5249 100644
--- a/include/linux/ext2_fs_sb.h
+++ b/include/linux/ext2_fs_sb.h
@@ -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;
};
diff --git a/include/linux/ext_fs.h b/include/linux/ext_fs.h
index a8b455d..4f5c6ad 100644
--- a/include/linux/ext_fs.h
+++ b/include/linux/ext_fs.h
@@ -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 *);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index c1259b0..d149e6a 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -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);
diff --git a/include/linux/iso_fs.h b/include/linux/iso_fs.h
index a144561..20daac3 100644
--- a/include/linux/iso_fs.h
+++ b/include/linux/iso_fs.h
@@ -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 *);
diff --git a/include/linux/minix_fs.h b/include/linux/minix_fs.h
index 90d2252..a48badb 100644
--- a/include/linux/minix_fs.h
+++ b/include/linux/minix_fs.h
@@ -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 *);
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
index cb87458..d32841c 100644
--- a/include/linux/msdos_fs.h
+++ b/include/linux/msdos_fs.h
@@ -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);
diff --git a/include/linux/msdos_fs_sb.h b/include/linux/msdos_fs_sb.h
index 025d250..8e5f304 100644
--- a/include/linux/msdos_fs_sb.h
+++ b/include/linux/msdos_fs_sb.h
@@ -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 */
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index ba8dff7..23f8c67 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -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);
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 8ff2eba..cf40473 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -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 *);
diff --git a/include/linux/signal.h b/include/linux/signal.h
index 2886cd5..0f3a16a 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -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
diff --git a/include/linux/sys.h b/include/linux/sys.h
index d6c15ea..da5b1a9 100644
--- a/include/linux/sys.h
+++ b/include/linux/sys.h
@@ -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);
diff --git a/include/linux/timer.h b/include/linux/timer.h
index 868b2a3..eb6d6cc 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -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;
diff --git a/include/linux/unistd.h b/include/linux/unistd.h
index c422f64..d7581dd 100644
--- a/include/linux/unistd.h
+++ b/include/linux/unistd.h
@@ -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;
diff --git a/include/linux/xia_fs.h b/include/linux/xia_fs.h
index 9d9b5f3..2d4abff 100644
--- a/include/linux/xia_fs.h
+++ b/include/linux/xia_fs.h
@@ -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 *);
diff --git a/init/main.c b/init/main.c
index 09d7d44..272cae2 100644
--- a/init/main.c
+++ b/init/main.c
@@ -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();
diff --git a/kernel/FPU-emu/Makefile b/kernel/FPU-emu/Makefile
index 2a1e34c..96ac5e1 100644
--- a/kernel/FPU-emu/Makefile
+++ b/kernel/FPU-emu/Makefile
@@ -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\
diff --git a/kernel/FPU-emu/README b/kernel/FPU-emu/README
index 062bb3b..1de54ff 100644
--- a/kernel/FPU-emu/README
+++ b/kernel/FPU-emu/README
@@ -1,7 +1,8 @@
+---------------------------------------------------------------------------+
| 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?
diff --git a/kernel/FPU-emu/Reg_constant.c b/kernel/FPU-emu/Reg_constant.c
deleted file mode 100644
index aadf589..0000000
--- a/kernel/FPU-emu/Reg_constant.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*---------------------------------------------------------------------------+
- | 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])();
-}
diff --git a/kernel/FPU-emu/Reg_constant.h b/kernel/FPU-emu/Reg_constant.h
deleted file mode 100644
index b6ee963..0000000
--- a/kernel/FPU-emu/Reg_constant.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*---------------------------------------------------------------------------+
- | 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_
-
diff --git a/kernel/FPU-emu/control_w.h b/kernel/FPU-emu/control_w.h
index 237a70b..fedcfd4 100644
--- a/kernel/FPU-emu/control_w.h
+++ b/kernel/FPU-emu/control_w.h
@@ -1,7 +1,8 @@
/*---------------------------------------------------------------------------+
| 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_
diff --git a/kernel/FPU-emu/errors.c b/kernel/FPU-emu/errors.c
index 07d5d12..1a003b8 100644
--- a/kernel/FPU-emu/errors.c
+++ b/kernel/FPU-emu/errors.c
@@ -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 |
| |
| |
diff --git a/kernel/FPU-emu/fpu_arith.c b/kernel/FPU-emu/fpu_arith.c
index fb86989..b27a747 100644
--- a/kernel/FPU-emu/fpu_arith.c
+++ b/kernel/FPU-emu/fpu_arith.c
@@ -1,9 +1,10 @@
/*---------------------------------------------------------------------------+
| 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();
}
diff --git a/kernel/FPU-emu/fpu_aux.c b/kernel/FPU-emu/fpu_aux.c
index 8d6043f..107a37c 100644
--- a/kernel/FPU-emu/fpu_aux.c
+++ b/kernel/FPU-emu/fpu_aux.c
@@ -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 |
| |
| |
diff --git a/kernel/FPU-emu/fpu_emu.h b/kernel/FPU-emu/fpu_emu.h
index 43354e4..770437b 100644
--- a/kernel/FPU-emu/fpu_emu.h
+++ b/kernel/FPU-emu/fpu_emu.h
@@ -1,7 +1,8 @@
/*---------------------------------------------------------------------------+
| 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 |
| |
+---------------------------------------------------------------------------*/
diff --git a/kernel/FPU-emu/fpu_entry.c b/kernel/FPU-emu/fpu_entry.c
index b425849..870a515 100644
--- a/kernel/FPU-emu/fpu_entry.c
+++ b/kernel/FPU-emu/fpu_entry.c
@@ -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 @@ do_another:
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 @@ do_another:
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 @@ test_for_fp:
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 */
diff --git a/kernel/FPU-emu/fpu_etc.c b/kernel/FPU-emu/fpu_etc.c
index f209694..b7dc7e8 100644
--- a/kernel/FPU-emu/fpu_etc.c
+++ b/kernel/FPU-emu/fpu_etc.c
@@ -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 |
| |
| |
diff --git a/kernel/FPU-emu/fpu_proto.h b/kernel/FPU-emu/fpu_proto.h
index dddee75..525b119 100644
--- a/kernel/FPU-emu/fpu_proto.h
+++ b/kernel/FPU-emu/fpu_proto.h
@@ -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);
diff --git a/kernel/FPU-emu/fpu_trig.c b/kernel/FPU-emu/fpu_trig.c
index fa74c1b..10d57df 100644
--- a/kernel/FPU-emu/fpu_trig.c
+++ b/kernel/FPU-emu/fpu_trig.c
@@ -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;
}
diff --git a/kernel/FPU-emu/get_address.c b/kernel/FPU-emu/get_address.c
index 5f0ee62..b3d77b6 100644
--- a/kernel/FPU-emu/get_address.c
+++ b/kernel/FPU-emu/get_address.c
@@ -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 |
| |
| |
diff --git a/kernel/FPU-emu/load_store.c b/kernel/FPU-emu/load_store.c
index 4a6357d..a038d17 100644
--- a/kernel/FPU-emu/load_store.c
+++ b/kernel/FPU-emu/load_store.c
@@ -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 |
| |
| |
diff --git a/kernel/FPU-emu/precision.c b/kernel/FPU-emu/precision.c
new file mode 100644
index 0000000..7e30782
--- /dev/null
+++ b/kernel/FPU-emu/precision.c
@@ -0,0 +1,134 @@
+/*---------------------------------------------------------------------------+
+ | 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;
+
+}
diff --git a/kernel/FPU-emu/reg_add_sub.c b/kernel/FPU-emu/reg_add_sub.c
index e1e2283..07e8e01 100644
--- a/kernel/FPU-emu/reg_add_sub.c
+++ b/kernel/FPU-emu/reg_add_sub.c
@@ -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 |
| |
| |
diff --git a/kernel/FPU-emu/reg_compare.c b/kernel/FPU-emu/reg_compare.c
index 5a5172a..7d4c6ac 100644
--- a/kernel/FPU-emu/reg_compare.c
+++ b/kernel/FPU-emu/reg_compare.c
@@ -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 )
diff --git a/kernel/FPU-emu/reg_ld_str.c b/kernel/FPU-emu/reg_ld_str.c
index 1972d3d..23b7968 100644
--- a/kernel/FPU-emu/reg_ld_str.c
+++ b/kernel/FPU-emu/reg_ld_str.c
@@ -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 @@ put_indefinite:
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 )
{
diff --git a/kernel/FPU-emu/version.h b/kernel/FPU-emu/version.h
index 26c52df..75edb8c 100644
--- a/kernel/FPU-emu/version.h
+++ b/kernel/FPU-emu/version.h
@@ -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"
diff --git a/kernel/blk_drv/scsi/aha1542.c b/kernel/blk_drv/scsi/aha1542.c
index 2a1a448..c9aba1a 100644
--- a/kernel/blk_drv/scsi/aha1542.c
+++ b/kernel/blk_drv/scsi/aha1542.c
@@ -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;
}
diff --git a/kernel/blk_drv/scsi/aha1740.c b/kernel/blk_drv/scsi/aha1740.c
index ddc2eac..6c1e184 100644
--- a/kernel/blk_drv/scsi/aha1740.c
+++ b/kernel/blk_drv/scsi/aha1740.c
@@ -1,15 +1,20 @@
-/* $Id: aha1740.c,v 1.1 1992/07/24 06:27:38 root Exp root $
+/* $Id$
+ * 1993/03/31
* linux/kernel/aha1740.c
*
* Based loosely on aha1542.c which is
- * Copyright (C) 1992 Tommy Thorn
- * and
+ * Copyright (C) 1992 Tommy Thorn and
* Modified by Eric Youngdale
*
* This file is aha1740.c, written and
- * Copyright (C) 1992 Brad McLean
+ * Copyright (C) 1992,1993 Brad McLean
*
- * aha1740_makecode needs more work
+ * Modifications to makecode and queuecommand
+ * for proper handling of multiple devices courteously
+ * provided by Michael Weller, March, 1993
+ *
+ * aha1740_makecode may still need even more work
+ * if it doesn't work for your devices, take a look.
*/
#include <linux/kernel.h>
@@ -27,12 +32,17 @@
#include "hosts.h"
#include "aha1740.h"
-/* #define DEBUG */
+
+/* IF YOU ARE HAVING PROBLEMS WITH THIS DRIVER, AND WANT TO WATCH
+ IT WORK, THEN:
+#define DEBUG
+*/
#ifdef DEBUG
#define DEB(x) x
#else
#define DEB(x)
#endif
+
/*
static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/aha1740.c,v 1.1 1992/07/24 06:27:38 root Exp root $";
*/
@@ -46,7 +56,8 @@ static int aha1740_last_ecb_used = 0; /* optimization */
int aha1740_makecode(unchar *sense, unchar *status)
{
- struct statusword {
+ struct statusword
+ {
ushort don:1, /* Command Done - No Error */
du:1, /* Data underrun */
:1, qf:1, /* Queue full */
@@ -58,8 +69,9 @@ int aha1740_makecode(unchar *sense, unchar *status)
sns:1, /* Sense information Stored */
:1, ini:1, /* Initialization Required */
me:1, /* Major error or exception */
- :1, eca:1, :1; /* Extended Contingent alliance */
- } status_word;
+ :1, eca:1, /* Extended Contingent alliance */
+ :1;
+ } status_word;
int retval = DID_OK;
status_word = * (struct statusword *) status;
@@ -67,20 +79,57 @@ int aha1740_makecode(unchar *sense, unchar *status)
printk("makecode from %x,%x,%x,%x %x,%x,%x,%x",status[0],status[1],status[2],status[3],
sense[0],sense[1],sense[2],sense[3]);
#endif
- if ( status_word.don )
- return 0;
-/*
- if ( status_word.du && status[2] != 0x11 )
- return 0;
-*/
- if ( status[2] == 0x11 )
- retval = DID_TIME_OUT;
- else
- retval = DID_ERROR;
- return status[3] | retval << 16; /* OKAY, SO I'M LAZY! I'll fix it later... */
+ if (!status_word.don) /* Anything abnormal was detected */
+ {
+ if ( (status[1]&0x18) || status_word.sc ) /*Additional info available*/
+ {
+ /* Use the supplied info for futher diagnostics */
+ switch ( status[2] )
+ {
+ case 0x12:
+ if ( status_word.dor )
+ retval=DID_ERROR; /* It's an Overrun */
+ /* If not overrun, assume underrun and ignore it! */
+ case 0x00: /* No info, assume no error, should not occur */
+ break;
+ case 0x11:
+ case 0x21:
+ retval=DID_TIME_OUT;
+ break;
+ case 0x0a:
+ retval=DID_BAD_TARGET;
+ break;
+ case 0x04:
+ case 0x05:
+ retval=DID_ABORT; /* Either by this driver or the AHA1740
+ itself */
+ break;
+ default:
+ retval=DID_ERROR; /* No further diagnostics possible */
+ }
+ }
+ else
+ { /* Michael suggests, and Brad concurs: */
+ if ( status_word.qf )
+ {
+ retval = DID_TIME_OUT; /* forces a redo */
+ /* I think this specific one should not happen -Brad */
+ printk("aha1740.c: WARNING: AHA1740 queue overflow!\n");
+ }
+ else if ( status[0]&0x60 )
+ {
+ retval = DID_ERROR; /* Didn't found a better error */
+ }
+ /* In any other case return DID_OK so for example
+ CONDITION_CHECKS make it through to the appropriate
+ device driver */
+ }
+ }
+ /* Under all circumstances supply the target status -Michael */
+ return status[3] | retval << 16;
}
-int aha1740_test_port()
+int aha1740_test_port(void)
{
char name[4],tmp;
@@ -94,10 +143,9 @@ int aha1740_test_port()
if ( strcmp ( name, HID_MFG ) || inb(HID2) != HID_PRD )
return 0; /* Not an Adaptec 174x */
-/* if ( inb(HID3) < HID_REV ) */
- if ( inb(HID3) != HID_REV )
+/* if ( inb(HID3) != HID_REV )
printk("aha1740: Warning; board revision of %d; expected %d\n",
- inb(HID3),HID_REV);
+ inb(HID3),HID_REV); */
if ( inb(EBCNTRL) != EBCNTRL_VALUE )
{
@@ -108,14 +156,14 @@ int aha1740_test_port()
if ( inb(PORTADR) & PORTADDR_ENH )
return 1; /* Okay, we're all set */
+
printk("aha1740: Board detected, but not in enhanced mode, so disabled it.\n");
return 0;
}
-/* What's this little function for? */
const char *aha1740_info(void)
{
- static char buffer[] = ""; /* looks nicer without anything here */
+ static char buffer[] = "Adaptec 174x (EISA)";
return buffer;
}
@@ -130,7 +178,8 @@ void aha1740_intr_handle(int foo)
number_serviced = 0;
- while(inb(G2STAT) & G2STAT_INTPEND){
+ while(inb(G2STAT) & G2STAT_INTPEND)
+ {
DEB(printk("aha1740_intr top of loop.\n"));
adapstat = inb(G2INTST);
outb(G2CNTRL_IRST,G2CNTRL); /* interrupt reset */
@@ -138,7 +187,6 @@ void aha1740_intr_handle(int foo)
switch ( adapstat & G2INTST_MASK )
{
case G2INTST_CCBRETRY:
- printk("aha1740 complete with retry!\n");
case G2INTST_CCBERROR:
case G2INTST_CCBGOOD:
ecbptr = (void *) ( ((ulong) inb(MBOXIN0)) +
@@ -196,46 +244,36 @@ int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
int ecbno;
DEB(int i);
- DEB(if (target > 0 || SCpnt->lun > 0) {
- SCpnt->result = DID_TIME_OUT << 16;
- done(SCpnt); return 0;});
- if(*cmd == REQUEST_SENSE){
-#ifndef DEBUG
- if (bufflen != 16) {
- printk("Wrong buffer length supplied for request sense (%d)\n",bufflen);
- panic("aha1740.c");
- };
-#endif
- SCpnt->result = 0;
- done(SCpnt);
- return 0;
- };
+ if(*cmd == REQUEST_SENSE)
+ {
+ if (bufflen != 16)
+ {
+ printk("Wrong buffer length supplied for request sense (%d)\n",bufflen);
+ panic("aha1740.c");
+ }
+ SCpnt->result = 0;
+ done(SCpnt);
+ return 0;
+ }
#ifdef DEBUG
if (*cmd == READ_10 || *cmd == WRITE_10)
- i = xscsi2int(cmd+2);
+ i = xscsi2int(cmd+2);
else if (*cmd == READ_6 || *cmd == WRITE_6)
- i = scsi2int(cmd+2);
- else
- i = -1;
- if (done)
- printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
+ i = scsi2int(cmd+2);
else
- printk("aha1740_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
+ i = -1;
+ printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
printk("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");
-#ifdef 0
- if (*cmd == WRITE_10 || *cmd == WRITE_6)
- return 0; /* we are still testing, so *don't* write */
-#endif
#endif
-/* locate an available ecb */
+ /* locate an available ecb */
cli();
- ecbno = aha1740_last_ecb_used + 1;
+ ecbno = aha1740_last_ecb_used + 1; /* An optimization */
if (ecbno >= AHA1740_ECBS) ecbno = 0;
do{
@@ -248,7 +286,7 @@ int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
if( ecb[ecbno].cmdw )
panic("Unable to find empty ecb for aha1740.\n");
- ecb[ecbno].cmdw = AHA1740CMD_INIT; /* SCSI Initiator Command to reserve*/
+ ecb[ecbno].cmdw = AHA1740CMD_INIT; /* SCSI Initiator Command doubles as reserved flag */
aha1740_last_ecb_used = ecbno;
sti();
@@ -257,7 +295,7 @@ int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
printk("Sending command (%d %x)...",ecbno, done);
#endif
- ecb[ecbno].cdblen = (*cmd<=0x1f)?6:10; /* SCSI Command Descriptor Block Length */
+ ecb[ecbno].cdblen = COMMAND_SIZE(*cmd); /* SCSI Command Descriptor Block Length */
direction = 0;
if (*cmd == READ_10 || *cmd == READ_6)
@@ -267,66 +305,90 @@ int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
memcpy(ecb[ecbno].cdb, cmd, ecb[ecbno].cdblen);
- if (SCpnt->use_sg) {
- struct scatterlist * sgpnt;
- struct aha1740_chain * cptr;
+ if (SCpnt->use_sg)
+ {
+ struct scatterlist * sgpnt;
+ struct aha1740_chain * cptr;
+ int i;
#ifdef DEBUG
- unsigned char * ptr;
+ unsigned char * ptr;
#endif
- int i;
- ecb[ecbno].sg = 1; /* SCSI Initiator Command w/scatter-gather*/
- SCpnt->host_scribble = scsi_malloc(512);
- sgpnt = (struct scatterlist *) SCpnt->request_buffer;
- cptr = (struct aha1740_chain *) SCpnt->host_scribble;
- if (cptr == NULL) panic("aha1740.c: unable to allocate DMA memory\n");
- for(i=0; i<SCpnt->use_sg; i++) {
- cptr[i].dataptr = (long) sgpnt[i].address;
- cptr[i].datalen = sgpnt[i].length;
- };
- ecb[ecbno].datalen = SCpnt->use_sg * sizeof(struct aha1740_chain);
- ecb[ecbno].dataptr = (long) cptr;
+ ecb[ecbno].sg = 1; /* SCSI Initiator Command w/scatter-gather*/
+ SCpnt->host_scribble = scsi_malloc(512);
+ sgpnt = (struct scatterlist *) SCpnt->request_buffer;
+ cptr = (struct aha1740_chain *) SCpnt->host_scribble;
+ if (cptr == NULL) panic("aha1740.c: unable to allocate DMA memory\n");
+ for(i=0; i<SCpnt->use_sg; i++)
+ {
+ cptr[i].dataptr = (long) sgpnt[i].address;
+ cptr[i].datalen = sgpnt[i].length;
+ }
+ ecb[ecbno].datalen = SCpnt->use_sg * sizeof(struct aha1740_chain);
+ ecb[ecbno].dataptr = (long) cptr;
#ifdef DEBUG
- printk("cptr %x: ",cptr);
- ptr = (unsigned char *) cptr;
- for(i=0;i<24;i++) printk("%02x ", ptr[i]);
+ printk("cptr %x: ",cptr);
+ ptr = (unsigned char *) cptr;
+ for(i=0;i<24;i++) printk("%02x ", ptr[i]);
#endif
- } else {
- SCpnt->host_scribble = NULL;
- ecb[ecbno].datalen = bufflen;
- ecb[ecbno].dataptr = (long) buff;
- };
+ }
+ else
+ {
+ SCpnt->host_scribble = NULL;
+ ecb[ecbno].datalen = bufflen;
+ ecb[ecbno].dataptr = (long) buff;
+ }
ecb[ecbno].lun = SCpnt->lun;
ecb[ecbno].ses = 1; /* Suppress underrun errors */
-/* ecb[ecbno].dat=1; */ /* Yes, check the data direction */
ecb[ecbno].dir= direction;
ecb[ecbno].ars=1; /* Yes, get the sense on an error */
- ecb[ecbno].senselen = 12; /* Why 12? Eric? MAXSENSE? */
+ ecb[ecbno].senselen = 12;
ecb[ecbno].senseptr = (long) ecb[ecbno].sense;
ecb[ecbno].statusptr = (long) ecb[ecbno].status;
ecb[ecbno].done = done;
ecb[ecbno].SCpnt = SCpnt;
#ifdef DEBUG
- { int i;
- printk("aha1740_command: sending.. ");
- for (i = 0; i < sizeof(ecb[ecbno])-10; i++)
- printk("%02x ", ((unchar *)&ecb[ecbno])[i]);
- };
+ {
+ int i;
+ printk("aha1740_command: sending.. ");
+ for (i = 0; i < sizeof(ecb[ecbno])-10; i++)
+ printk("%02x ", ((unchar *)&ecb[ecbno])[i]);
+ }
printk("\n");
#endif
- if (done) { ulong adrs;
-
- if ( ! (inb(G2STAT) & G2STAT_MBXOUT) ) /* Spec claim's it's so fast */
- printk("aha1740_mbxout wait!\n"); /* that this is okay? It seems */
- while ( ! (inb(G2STAT) & G2STAT_MBXOUT) ); /* to work, so I'll leave it */
- adrs = (ulong) &(ecb[ecbno]);
- outb((char) (adrs&0xff), MBOXOUT0);
- outb((char) ((adrs>>8)&0xff), MBOXOUT1);
- outb((char) ((adrs>>16)&0xff), MBOXOUT2);
+ if (done)
+ { /* You may question the code below, which contains potentially
+ non-terminating while loops with interrupts disabled. So did
+ I when I wrote it, but the Adaptec Spec says the card is so fast,
+ that this problem virtually never occurs so I've kept it. We
+ do printk a warning first, so that you'll know if it happens.
+ In practive the only time we've seen this message is when some-
+ thing else is in the driver was broken, like _makecode(), or
+ when a scsi device hung the scsi bus. Even under these conditions,
+ The loop actually only cycled < 3 times (we instrumented it). */
+ ulong adrs;
+
+ DEB(printk("aha1740[%d] critical section\n",ecbno));
+ cli();
+ if ( ! (inb(G2STAT) & G2STAT_MBXOUT) )
+ {
+ printk("aha1740[%d]_mbxout wait!\n",ecbno);
+ cli(); /* printk may have done a sti()! */
+ }
+ while ( ! (inb(G2STAT) & G2STAT_MBXOUT) ); /* Oh Well. */
+ adrs = (ulong) &(ecb[ecbno]); /* Spit the command */
+ outb((char) (adrs&0xff), MBOXOUT0); /* out, note this set */
+ outb((char) ((adrs>>8)&0xff), MBOXOUT1); /* of outb's must be */
+ outb((char) ((adrs>>16)&0xff), MBOXOUT2); /* atomic */
outb((char) ((adrs>>24)&0xff), MBOXOUT3);
- if ( inb(G2STAT) & G2STAT_BUSY ) /* Again, allegedly fast */
- printk("aha1740_attn wait!\n");
- while ( inb(G2STAT) & G2STAT_BUSY );
+ if ( inb(G2STAT) & G2STAT_BUSY )
+ {
+ printk("aha1740[%d]_attn wait!\n",ecbno);
+ cli();
+ }
+ while ( inb(G2STAT) & G2STAT_BUSY ); /* And Again! */
outb(ATTN_START | (target & 7), ATTN); /* Start it up */
+ sti();
+ DEB(printk("aha1740[%d] request queued.\n",ecbno));
}
else
printk("aha1740_queuecommand: done can't be NULL\n");
@@ -336,6 +398,7 @@ int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
static volatile int internal_done_flag = 0;
static volatile int internal_done_errcode = 0;
+
static void internal_done(Scsi_Cmnd * SCpnt)
{
internal_done_errcode = SCpnt->result;
@@ -351,22 +414,14 @@ int aha1740_command(Scsi_Cmnd * SCpnt)
return internal_done_errcode;
}
-/* Query the board for it's port addresses, etc. Actually, the irq_level is
- all we care about for this board, since it's EISA */
+/* Query the board for it's irq_level. Nothing else matters
+ in enhanced mode on an EISA bus. */
-static int aha1740_getconfig()
+void aha1740_getconfig(void)
{
- int iop, bios, scsi, dma;
- static int iotab[] = { 0, 0, 0x130, 0x134, 0x230, 0x234, 0x330, 0x334 };
static int intab[] = { 9,10,11,12,0,14,15,0 };
- static int dmatab[] = { 0,5,6,7 };
- iop = iotab [ inb(PORTADR)&0x7 ];
- bios = inb(BIOSADR);
irq_level = intab [ inb(INTDEF)&0x7 ];
- scsi = inb(SCSIDEF);
- dma = dmatab[ (inb(BUSDEF)>>2) & 0x3 ];
- return 0;
}
int aha1740_detect(int hostnum)
@@ -377,18 +432,16 @@ int aha1740_detect(int hostnum)
for ( slot=MINEISA; slot <= MAXEISA; slot++ )
{
base = SLOTBASE(slot);
- if ( aha1740_test_port(base)) break;
+ if ( aha1740_test_port()) break;
}
if ( slot > MAXEISA )
return 0;
- if (aha1740_getconfig() == -1)
- return 0;
+ aha1740_getconfig();
if ( (inb(G2STAT) & (G2STAT_MBXOUT | G2STAT_BUSY) ) != G2STAT_MBXOUT )
- {
+ { /* If the card isn't ready, hard reset it */
outb(G2CNTRL_HRST,G2CNTRL);
- /* 10 Msec Delay Here */
outb(0,G2CNTRL);
}
@@ -397,16 +450,25 @@ int aha1740_detect(int hostnum)
DEB(printk("aha1740_detect: enable interrupt channel %d\n", irq_level));
- if (request_irq(irq_level,aha1740_intr_handle)) {
- printk("Unable to allocate IRQ for adaptec controller.\n");
- return 0;
- };
+ if (request_irq(irq_level,aha1740_intr_handle))
+ {
+ printk("Unable to allocate IRQ for adaptec controller.\n");
+ return 0;
+ }
return 1;
}
+/* Note: They following two functions do not apply very well to the Adaptec,
+which basically manages it's own affairs quite well without our interference,
+so I haven't put anything into them. I can faintly imagine someone with a
+*very* badly behaved SCSI target (perhaps an old tape?) wanting the abort(),
+but it hasn't happened yet, and doing aborts brings the Adaptec to it's
+knees. I cannot (at this moment in time) think of any reason to reset the
+card once it's running. So there. */
+
int aha1740_abort(Scsi_Cmnd * SCpnt, int i)
{
- DEB(printk("aha1740_abort\n"));
+ DEB(printk("aha1740_abort called\n"));
return 0;
}
@@ -416,13 +478,16 @@ int aha1740_reset(void)
return 0;
}
-int aha1740_biosparam(int size, int dev, int* info){
+int aha1740_biosparam(int size, int dev, int* info)
+{
DEB(printk("aha1740_biosparam\n"));
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;
}
-
+/* Okay, you made it all the way through. As of this writing, 3/31/93, I'm
+brad@saturn.gaylord.com or brad@bradpc.gaylord.com. I'll try to help as time
+permits if you have any trouble with this driver. Happy Linuxing! */
diff --git a/kernel/blk_drv/scsi/aha1740.h b/kernel/blk_drv/scsi/aha1740.h
index 178fdf0..ec25861 100644
--- a/kernel/blk_drv/scsi/aha1740.h
+++ b/kernel/blk_drv/scsi/aha1740.h
@@ -1,16 +1,21 @@
#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, \
diff --git a/kernel/blk_drv/scsi/hosts.c b/kernel/blk_drv/scsi/hosts.c
index 02da3fc..50c9c3f 100644
--- a/kernel/blk_drv/scsi/hosts.c
+++ b/kernel/blk_drv/scsi/hosts.c
@@ -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
diff --git a/kernel/blk_drv/scsi/scsi.c b/kernel/blk_drv/scsi/scsi.c
index 13187ac..78a1c10 100644
--- a/kernel/blk_drv/scsi/scsi.c
+++ b/kernel/blk_drv/scsi/scsi.c
@@ -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++;
};
};
diff --git a/kernel/blk_drv/scsi/scsi.h b/kernel/blk_drv/scsi/scsi.h
index e86b141..7bc7663 100644
--- a/kernel/blk_drv/scsi/scsi.h
+++ b/kernel/blk_drv/scsi/scsi.h
@@ -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
-
diff --git a/kernel/blk_drv/scsi/scsi_ioctl.c b/kernel/blk_drv/scsi/scsi_ioctl.c
index b3724ef..45142d1 100644
--- a/kernel/blk_drv/scsi/scsi_ioctl.c
+++ b/kernel/blk_drv/scsi/scsi_ioctl.c
@@ -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;
diff --git a/kernel/blk_drv/scsi/scsi_ioctl.h b/kernel/blk_drv/scsi/scsi_ioctl.h
index 531f27a..c25ed86 100644
--- a/kernel/blk_drv/scsi/scsi_ioctl.h
+++ b/kernel/blk_drv/scsi/scsi_ioctl.h
@@ -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
diff --git a/kernel/blk_drv/scsi/sd.c b/kernel/blk_drv/scsi/sd.c
index 47d3767..889a5f9 100644
--- a/kernel/blk_drv/scsi/sd.c
+++ b/kernel/blk_drv/scsi/sd.c
@@ -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 @@ repeat:
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 @@ repeat:
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;
diff --git a/kernel/blk_drv/scsi/seagate.c b/kernel/blk_drv/scsi/seagate.c
index f9598e9..400d06c 100644
--- a/kernel/blk_drv/scsi/seagate.c
+++ b/kernel/blk_drv/scsi/seagate.c
@@ -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,
diff --git a/kernel/blk_drv/scsi/sr.c b/kernel/blk_drv/scsi/sr.c
index 24140d9..22df4b7 100644
--- a/kernel/blk_drv/scsi/sr.c
+++ b/kernel/blk_drv/scsi/sr.c
@@ -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;
diff --git a/kernel/blk_drv/scsi/st.c b/kernel/blk_drv/scsi/st.c
index 29e37a1..bfe0539 100644
--- a/kernel/blk_drv/scsi/st.c
+++ b/kernel/blk_drv/scsi/st.c
@@ -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);
}
diff --git a/kernel/blk_drv/scsi/ultrastor.c b/kernel/blk_drv/scsi/ultrastor.c
index c41968a..6bc1a00 100644
--- a/kernel/blk_drv/scsi/ultrastor.c
+++ b/kernel/blk_drv/scsi/ultrastor.c
@@ -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;
}
diff --git a/kernel/blk_drv/scsi/wd7000.c b/kernel/blk_drv/scsi/wd7000.c
index db402ad..234ae7f 100644
--- a/kernel/blk_drv/scsi/wd7000.c
+++ b/kernel/blk_drv/scsi/wd7000.c
@@ -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;
}
diff --git a/kernel/chr_drv/keyboard.c b/kernel/chr_drv/keyboard.c
index 30d4e83..033831a 100644
--- a/kernel/chr_drv/keyboard.c
+++ b/kernel/chr_drv/keyboard.c
@@ -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;
diff --git a/kernel/chr_drv/tty_io.c b/kernel/chr_drv/tty_io.c
index aed9428..2017cda 100644
--- a/kernel/chr_drv/tty_io.c
+++ b/kernel/chr_drv/tty_io.c
@@ -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;
diff --git a/kernel/chr_drv/tty_ioctl.c b/kernel/chr_drv/tty_ioctl.c
index 0ff7f97..d9cd91e 100644
--- a/kernel/chr_drv/tty_ioctl.c
+++ b/kernel/chr_drv/tty_ioctl.c
@@ -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;
diff --git a/kernel/exit.c b/kernel/exit.c
index 4a1e02a..5255386 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -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;
diff --git a/kernel/irq.c b/kernel/irq.c
index 2e5d29f..9d503ae 100644
--- a/kernel/irq.c
+++ b/kernel/irq.c
@@ -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.
*/
diff --git a/kernel/sched.c b/kernel/sched.c
index 992a3fb..6fba0a8 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -74,6 +74,8 @@ void math_state_restore(void)
{
if (last_task_used_math == current)
return;
+ timer_table[COPRO_TIMER].expires = jiffies+50;
+ timer_active |= 1<<COPRO_TIMER;
if (last_task_used_math) {
__asm__("fnsave %0"::"m" (last_task_used_math->tss.i387));
}
@@ -85,6 +87,7 @@ void math_state_restore(void)
__asm__("fninit"::);
current->used_math=1;
}
+ timer_active &= ~(1<<COPRO_TIMER);
}
/*
@@ -138,39 +141,11 @@ void schedule(void)
switch_to(next);
}
-/*
- * This is a little tricky because POSIX pause (3.4.2.1) should only
- * return for a caught signal or a signal that terminates the process.
- * We just block ignored signals or "harmless" default signals.
- * For suspending signals, we must return so that they are handled
- * and then pause again. -- jrs
- */
-
int sys_pause(void)
{
- unsigned long old_blocked;
- unsigned long mask;
- int sig;
- struct sigaction * sa = current->sigaction;
-
- old_blocked = current->blocked;
- /* block everything we can that shouldn't interrupt pause */
- for (mask = 1, sig = 1; mask; sa++, mask += mask, sig++)
- if (sa->sa_handler == SIG_IGN || (sa->sa_handler == SIG_DFL
- && (sig == SIGCONT || sig == SIGCHLD || sig == SIGWINCH)))
- current->blocked |= mask;
- do {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- } while (!(current->signal & ~current->blocked));
- /* if a suspending signal interrupted us we must restart */
- if (!(current->signal & ~current->blocked &
- ~(_S(SIGSTOP) | _S(SIGTSTP) | _S(SIGTTIN) | _S(SIGTTOU)))) {
- current->blocked = old_blocked;
- return -ERESTARTSYS;
- }
- current->blocked = old_blocked;
- return -EINTR;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ return -ERESTARTNOHAND;
}
/*
diff --git a/kernel/signal.c b/kernel/signal.c
index f90b7a2..cea610c 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -10,6 +10,7 @@
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/ptrace.h>
+#include <linux/unistd.h>
#include <asm/segment.h>
@@ -18,6 +19,7 @@
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
extern int core_dump(long signr,struct pt_regs * regs);
+int do_signal(unsigned long oldmask, struct pt_regs * regs);
int sys_sgetmask(void)
{
@@ -42,47 +44,23 @@ int sys_sigpending(sigset_t *set)
return error;
}
-/* atomically swap in the new signal mask, and wait for a signal.
- *
- * we need to play some games with syscall restarting. We get help
- * from the syscall library interface. Note that we need to coordinate
- * the calling convention with the libc routine.
- *
- * "set" is just the sigmask as described in 1003.1-1988, 3.3.7.
- * It is assumed that sigset_t can be passed as a 32 bit quantity.
- *
- * "restart" holds a restart indication. If it's 1, then we
- * install the old mask, and return normally. If it's zero, we store
- * the current mask in old_mask and block until a signal comes in.
- * If it's 2, then it's a signal we must handle but not return from.
- *
- * We are careful to prevent a rouge restart from user space from fooling
- * us into blocking SIGKILL or SIGSTOP.
+/*
+ * atomically swap in the new signal mask, and wait for a signal.
*/
-int sys_sigsuspend(volatile int restart, volatile unsigned long old_mask, unsigned long set)
+int sys_sigsuspend(volatile int restart, volatile unsigned long oldmask, unsigned long set)
{
- extern int sys_pause(void);
+ unsigned long mask;
+ struct pt_regs * regs = (struct pt_regs *) &restart;
- switch (restart) {
- case 0:
- /* we're not restarting. do the work */
- restart = 1;
- old_mask = current->blocked;
- current->blocked = set & _BLOCKABLE;
- break;
- case 1:
- /* we're restarting to restore and exit */
- current->blocked = old_mask & _BLOCKABLE;
- return -EINTR;
- case 2:
- /* we're restarting but staying paused */
- restart = 1;
- break;
+ mask = current->blocked;
+ current->blocked = set & _BLOCKABLE;
+ regs->eax = -EINTR;
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ if (do_signal(mask,regs))
+ return -EINTR;
}
- /* pause returns after a signal arrives */
- if (sys_pause() == -ERESTARTSYS)
- restart = 2;
- return -ERESTARTNOINTR; /* handle the signal, and come back */
}
/*
@@ -119,7 +97,7 @@ static void check_pending(int signum)
}
}
-int sys_signal(int signum, long handler, long restorer)
+int sys_signal(int signum, long handler)
{
struct sigaction tmp;
@@ -128,7 +106,7 @@ int sys_signal(int signum, long handler, long restorer)
tmp.sa_handler = (void (*)(int)) handler;
tmp.sa_mask = 0;
tmp.sa_flags = SA_ONESHOT | SA_NOMASK | SA_INTERRUPT;
- tmp.sa_restorer = (void (*)(void)) restorer;
+ tmp.sa_restorer = NULL;
handler = (long) current->sigaction[signum-1].sa_handler;
current->sigaction[signum-1] = tmp;
check_pending(signum);
@@ -165,26 +143,75 @@ int sys_sigaction(int signum, const struct sigaction * action,
extern int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
+void sys_sigreturn(int signr, unsigned long oldmask, unsigned long unused)
+{
+ current->blocked = oldmask & _BLOCKABLE;
+}
+
+/*
+ * This routine sets up the return stack for the first signal found
+ * (== last delivered). It makes room for the registers we need to save,
+ * but the actual saving is left until the very last moment when we
+ * know whether we can restart system calls etc.
+ */
+static unsigned long * setup_first(struct pt_regs * regs,
+ int signr, unsigned long sa_handler, unsigned long oldmask)
+{
+ unsigned long * tmp_esp;
+
+ regs->esp -= 18*4;
+ tmp_esp = (unsigned long *) regs->esp;
+ verify_area(VERIFY_WRITE,tmp_esp,18*4);
+/* set up the "normal" stack seen by the signal handler */
+ put_fs_long(regs->esp+15*4,tmp_esp); /* points to the stack.. */
+ put_fs_long(signr,tmp_esp+1); /* parameter to handler and sigreturn */
+ put_fs_long(0,tmp_esp+2); /* third parameter to sigreturn */
+ put_fs_long(oldmask,tmp_esp+3); /* second .. */
+ put_fs_long(__NR_sigreturn,tmp_esp+4); /* sigreturn number.. */
+/* save this frame so that we later can fill in the saved registers */
+ return tmp_esp+5;
+}
+
+/*
+ * This sets up the stack for any stacked signals other than the
+ * first one: no need to restore registers etc, as that is done
+ * by the very last signal handler return code..
+ */
+static void setup_other(unsigned long eip, struct pt_regs * regs, int signr,
+ unsigned long sa_handler, unsigned long oldmask)
+{
+ unsigned long * tmp_esp;
+
+ regs->esp -= 9*4;
+ tmp_esp = (unsigned long *) regs->esp;
+ verify_area(VERIFY_WRITE,tmp_esp,9*4);
+/* set up the "normal" stack seen by the signal handler */
+ put_fs_long(regs->esp+6*4,tmp_esp); /* points to the stack.. */
+ put_fs_long(signr,tmp_esp+1); /* parameter to handler and sigreturn */
+ put_fs_long(0,tmp_esp+2); /* third parameter to sigreturn */
+ put_fs_long(oldmask,tmp_esp+3); /* second .. */
+ put_fs_long(__NR_sigreturn,tmp_esp+4); /* sigreturn number.. */
+ put_fs_long(eip,tmp_esp+5); /* return address */
+/* set up the return code... */
+ put_fs_long(0x58595a5b,tmp_esp+6); /* pop bx,dx,cx,ax */
+ put_fs_long(0x909080cd,tmp_esp+7); /* int $0x80 + nop + nop */
+ put_fs_long(0x000cc290,tmp_esp+8); /* nop + "ret 12" */
+}
+
/*
* Note that 'init' is a special process: it doesn't get signals it doesn't
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
*/
-void do_signal(struct pt_regs * regs)
+int do_signal(unsigned long oldmask, struct pt_regs * regs)
{
+ unsigned long *frame = NULL;
+ unsigned long eip = 0;
unsigned long signr;
unsigned long sa_handler;
- long old_eip = regs->eip;
struct sigaction * sa;
- int longs;
- unsigned long * tmp_esp;
- if (regs->orig_eax >= 0 && regs->eax == -ERESTARTNOINTR) {
- regs->eax = regs->orig_eax;
- regs->eip = old_eip -= 2;
- }
- signr = current->signal & ~current->blocked;
- do {
+ while ((signr = current->signal & ~current->blocked)) {
__asm__("bsf %2,%1\n\t"
"btrl %1,%0"
:"=m" (current->signal),"=r" (signr)
@@ -203,15 +230,10 @@ void do_signal(struct pt_regs * regs)
if (current->pid == 1)
continue;
switch (signr) {
- case SIGCONT:
- case SIGCHLD:
- case SIGWINCH:
+ case SIGCONT: case SIGCHLD: case SIGWINCH:
continue;
- case SIGSTOP:
- case SIGTSTP:
- case SIGTTIN:
- case SIGTTOU:
+ case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
current->state = TASK_STOPPED;
current->exit_code = signr;
if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags &
@@ -220,12 +242,8 @@ void do_signal(struct pt_regs * regs)
schedule();
continue;
- case SIGQUIT:
- case SIGILL:
- case SIGTRAP:
- case SIGIOT:
- case SIGFPE:
- case SIGSEGV:
+ case SIGQUIT: case SIGILL: case SIGTRAP:
+ case SIGIOT: case SIGFPE: case SIGSEGV:
if (core_dump(signr,regs))
signr |= 0x80;
/* fall through */
@@ -235,39 +253,49 @@ void do_signal(struct pt_regs * regs)
}
}
/*
- * OK, we're invoking a handler
+ * OK, we're invoking a handler
*/
- if (regs->orig_eax >= 0 && regs->eax == -ERESTARTSYS) {
- if (sa->sa_flags & SA_INTERRUPT)
+ if (regs->orig_eax >= 0) {
+ if (regs->eax == -ERESTARTNOHAND ||
+ (regs->eax == -ERESTARTSYS && (sa->sa_flags & SA_INTERRUPT)))
regs->eax = -EINTR;
- else {
- regs->eax = regs->orig_eax;
- regs->eip = old_eip -= 2;
- }
}
if (sa->sa_flags & SA_ONESHOT)
sa->sa_handler = NULL;
- regs->eip = sa_handler;
- longs = (sa->sa_flags & SA_NOMASK)?(7*4):(8*4);
- regs->esp -= longs;
- tmp_esp = (unsigned long *) regs->esp;
- verify_area(VERIFY_WRITE,tmp_esp,longs);
- put_fs_long((long) sa->sa_restorer,tmp_esp++);
- put_fs_long(signr,tmp_esp++);
- if (!(sa->sa_flags & SA_NOMASK))
- put_fs_long(current->blocked,tmp_esp++);
- put_fs_long(regs->eax,tmp_esp++);
- put_fs_long(regs->ecx,tmp_esp++);
- put_fs_long(regs->edx,tmp_esp++);
- put_fs_long(regs->eflags,tmp_esp++);
- put_fs_long(old_eip,tmp_esp++);
- current->blocked |= sa->sa_mask;
/* force a supervisor-mode page-in of the signal handler to reduce races */
__asm__("testb $0,%%fs:%0"::"m" (*(char *) sa_handler));
- return;
- } while ((signr = current->signal & ~current->blocked));
- if (regs->orig_eax >= 0 && regs->eax == -ERESTARTSYS) {
+ if (!frame) {
+ frame = setup_first(regs,signr,sa_handler,oldmask);
+ } else
+ setup_other(eip,regs,signr,sa_handler,oldmask);
+ eip = sa_handler;
+ current->blocked |= sa->sa_mask;
+ oldmask |= sa->sa_mask;
+ }
+ if (regs->orig_eax >= 0 &&
+ (regs->eax == -ERESTARTNOHAND ||
+ regs->eax == -ERESTARTSYS ||
+ regs->eax == -ERESTARTNOINTR)) {
regs->eax = regs->orig_eax;
- regs->eip = old_eip -= 2;
+ regs->eip -= 2;
}
+ if (!frame) /* no handlers installed - return 0 */
+ return 0;
+/* save registers if one or more handlers are called.. */
+ put_fs_long(regs->edi,frame); /* suitable order for "popad" */
+ put_fs_long(regs->esi,frame+1);
+ put_fs_long(regs->ebp,frame+2); /* using 'frame++' instead of the 'frame+x' */
+ put_fs_long(regs->esp,frame+3); /* form used now results in atrocious code */
+ put_fs_long(regs->ebx,frame+4); /* due to gcc not being very good at optimizing */
+ put_fs_long(regs->edx,frame+5); /* things with inline-assembly/functions.. */
+ put_fs_long(regs->ecx,frame+6);
+ put_fs_long(regs->eax,frame+7);
+ put_fs_long(regs->eflags,frame+8); /* flags */
+ put_fs_long(regs->eip,frame+9); /* original return address */
+/* set up the return code... */
+ put_fs_long(0x58595a5b,frame+10); /* pop bx,dx,cx,ax */
+ put_fs_long(0x906180cd,frame+11); /* int $0x80 + popad + nop */
+ put_fs_long(0x000cc29d,frame+12); /* popfl + "ret 12" */
+ regs->eip = eip; /* "return" to the first handler */
+ return 1;
}
diff --git a/kernel/sys_call.S b/kernel/sys_call.S
index 9b10c82..d16ec17 100644
--- a/kernel/sys_call.S
+++ b/kernel/sys_call.S
@@ -184,16 +184,20 @@ signal_return:
pushl %ebx
testl $VM_MASK,EFLAGS(%ebx)
jne v86_signal_return
+ pushl blocked(%eax)
call _do_signal
popl %ebx
+ popl %ebx
RESTORE_ALL
.align 4
v86_signal_return:
call _save_v86_state
movl %eax,%esp
pushl %eax
+ pushl blocked(%eax)
call _do_signal
popl %ebx
+ popl %ebx
RESTORE_ALL
.align 4