Commit ce823b44 authored by Linus Torvalds's avatar Linus Torvalds

[PATCH] Linux-0.97.1 (August 6, 1992)

Make the page allocator use a free page list instead of a silly
linear search.

Add sys_vhangup() and stubs for send/rcv/sendto/recvfrom/shutdown.
We're making ready for real networking..

Remove nonworking extfs bitmap allocators. We'll have them in ext2.

[Original announcement below]

Patch 1 is essentially a performance-release, but it also contains some
other patches: Ross Biro's tcp-ip stubs are there (but not the tcpip
subdirectory: alpha-testers should know where to find that), as are the
ext-fs superblock cleanups. The first header-file patch by hlu is also
in there.

The resulting patch is pretty big - it's also not as cleaned up as I'd
like it to be.  The swapping/buffer-block handling heuristics are
better, but could still do with some tuning.  Also, the idle task in
this version doesn't do very much: it will be expanded to do some more
page-table calculations.

I will be unable to hack on linux for a couple of weeks (I'll still
answer mails, read the newsgroup and fix bugs, but no heavy-duty
hacking) due to some "circumstances beyond my control".  That probably
means that this patch is the last one for a while (three weeks) unless
some bad bugs show up.

                Linus
parent ddc733f4
......@@ -6,6 +6,13 @@
ROOT_DEV = /dev/hdb1
#
# uncomment this if you want kernel profiling: the profile_shift is the
# granularity of the profiling (5 = 32-byte granularity)
#
#PROFILING = -DPROFILE_SHIFT=2
#
# uncomment the correct keyboard:
#
......@@ -71,7 +78,7 @@ LD86 =ld86 -0
AS =as
LD =ld
HOSTCC =gcc -static
CC =gcc -nostdinc -I$(KERNELHDRS)
CC =gcc -nostdinc -I$(KERNELHDRS) $(PROFILING)
MAKE =make
CPP =$(CC) -E
AR =ar
......
......@@ -557,16 +557,24 @@ static int try_to_free(struct buffer_head * bh)
/*
* Try to free up some pages by shrinking the buffer-cache
*
* Priority tells the routine how hard to try to shrink the
* buffers: 0 means "don't bother too much", while a value
* of 3 means "we'd better get some free pages now".
*/
int shrink_buffers(void)
int shrink_buffers(unsigned int priority)
{
struct buffer_head *bh;
int i;
if (priority > 2) {
priority = 3;
sync_buffers(0);
}
bh = free_list;
for (i = nr_buffers*2 ; i-- > 0 ; bh = bh->b_next_free) {
wait_on_buffer(bh);
if (bh->b_count || !bh->b_this_page)
i = nr_buffers >> (3-priority);
for ( ; i-- > 0 ; bh = bh->b_next_free) {
if (bh->b_lock || bh->b_count || !bh->b_this_page)
continue;
if (bh->b_dirt) {
ll_rw_block(WRITEA,bh);
......
......@@ -14,7 +14,7 @@
.s.o:
$(AS) -o $*.o $<
OBJS= bitmap.o freelists.o truncate.o namei.o inode.o \
OBJS= freelists.o truncate.o namei.o inode.o \
file.o dir.o symlink.o blkdev.o chrdev.o fifo.o
ext.o: $(OBJS)
......
......@@ -62,8 +62,6 @@ static int ext_readdir(struct inode * inode, struct file * filp,
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
/* if (filp->f_pos & (sizeof (struct ext_dir_entry) - 1))
return -EBADF; */
while (filp->f_pos < inode->i_size) {
offset = filp->f_pos & 1023;
block = ext_bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS);
......@@ -89,8 +87,8 @@ static int ext_readdir(struct inode * inode, struct file * filp,
return i;
}
}
/* de++; */
de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
de = (struct ext_dir_entry *) ((char *) de
+ de->rec_len);
}
brelse(bh);
}
......
This diff is collapsed.
......@@ -31,24 +31,13 @@ void ext_put_inode(struct inode *inode)
void ext_put_super(struct super_block *sb)
{
#ifdef EXTFS_BITMAP
int i;
#endif
lock_super(sb);
sb->s_dev = 0;
#ifdef EXTFS_BITMAP
for(i = 0 ; i < EXT_I_MAP_SLOTS ; i++)
brelse(sb->u.ext_sb.s_imap[i]);
for(i = 0 ; i < EXT_Z_MAP_SLOTS ; i++)
brelse(sb->u.ext_sb.s_zmap[i]);
#endif
#ifdef EXTFS_FREELIST
if (sb->u.ext_sb.s_imap[1])
brelse (sb->u.ext_sb.s_imap[1]);
if (sb->u.ext_sb.s_zmap[1])
brelse (sb->u.ext_sb.s_zmap[1]);
#endif
if (sb->u.ext_sb.s_firstfreeinodeblock)
brelse (sb->u.ext_sb.s_firstfreeinodeblock);
if (sb->u.ext_sb.s_firstfreeblock)
brelse (sb->u.ext_sb.s_firstfreeblock);
free_super(sb);
return;
}
......@@ -67,9 +56,6 @@ struct super_block *ext_read_super(struct super_block *s,void *data)
struct buffer_head *bh;
struct ext_super_block *es;
int dev = s->s_dev,block;
#ifdef EXTFS_BITMAP
int i;
#endif
lock_super(s);
if (!(bh = bread(dev, 1, BLOCK_SIZE))) {
......@@ -78,26 +64,18 @@ struct super_block *ext_read_super(struct super_block *s,void *data)
printk("bread failed\n");
return NULL;
}
/* *((struct ext_super_block *) s) =
*((struct ext_super_block *) bh->b_data); */
es = (struct ext_super_block *) bh->b_data;
s->s_blocksize = 1024;
s->u.ext_sb.s_ninodes = es->s_ninodes;
s->u.ext_sb.s_nzones = es->s_nzones;
#ifdef EXTFS_BITMAP
s->u.ext_sb.s_imap_blocks = es->s_imap_blocks;
s->u.ext_sb.s_zmap_blocks = es->s_zmap_blocks;
#endif
s->u.ext_sb.s_firstdatazone = es->s_firstdatazone;
s->u.ext_sb.s_log_zone_size = es->s_log_zone_size;
s->u.ext_sb.s_max_size = es->s_max_size;
s->s_magic = es->s_magic;
#ifdef EXTFS_FREELIST
s->u.ext_sb.s_zmap[0] = (struct buffer_head *) es->s_firstfreeblock;
s->u.ext_sb.s_zmap[2] = (struct buffer_head *) es->s_freeblockscount;
s->u.ext_sb.s_imap[0] = (struct buffer_head *) es->s_firstfreeinode;
s->u.ext_sb.s_imap[2] = (struct buffer_head *) es->s_freeinodescount;
#endif
s->u.ext_sb.s_firstfreeblocknumber = es->s_firstfreeblock;
s->u.ext_sb.s_freeblockscount = es->s_freeblockscount;
s->u.ext_sb.s_firstfreeinodenumber = es->s_firstfreeinode;
s->u.ext_sb.s_freeinodescount = es->s_freeinodescount;
brelse(bh);
if (s->s_magic != EXT_SUPER_MAGIC) {
s->s_dev = 0;
......@@ -105,59 +83,28 @@ struct super_block *ext_read_super(struct super_block *s,void *data)
printk("magic match failed\n");
return NULL;
}
#ifdef EXTFS_BITMAP
for (i=0;i < EXT_I_MAP_SLOTS;i++)
s->u.ext_sb.s_imap[i] = NULL;
for (i=0;i < EXT_Z_MAP_SLOTS;i++)
s->u.ext_sb.s_zmap[i] = NULL;
block=2;
for (i=0 ; i < s->u.ext_sb.s_imap_blocks ; i++)
if (s->u.ext_sb.s_imap[i]=bread(dev, block, BLOCK_SIZE))
block++;
else
break;
for (i=0 ; i < s->u.ext_sb.s_zmap_blocks ; i++)
if (s->u.ext_sb.s_zmap[i]=bread(dev, block, BLOCK_SIZE))
block++;
else
break;
if (block != 2+s->u.ext_sb.s_imap_blocks+s->u.ext_sb.s_zmap_blocks) {
for(i=0;i<EXT_I_MAP_SLOTS;i++)
brelse(s->u.ext_sb.s_imap[i]);
for(i=0;i<EXT_Z_MAP_SLOTS;i++)
brelse(s->u.ext_sb.s_zmap[i]);
s->s_dev=0;
free_super(s);
printk("block failed\n");
return NULL;
}
s->u.ext_sb.s_imap[0]->b_data[0] |= 1;
s->u.ext_sb.s_zmap[0]->b_data[0] |= 1;
#endif
#ifdef EXTFS_FREELIST
if (!s->u.ext_sb.s_zmap[0])
s->u.ext_sb.s_zmap[1] = NULL;
if (!s->u.ext_sb.s_firstfreeblocknumber)
s->u.ext_sb.s_firstfreeblock = NULL;
else
if (!(s->u.ext_sb.s_zmap[1] = bread(dev, (unsigned long) s->u.ext_sb.s_zmap[0], BLOCK_SIZE))) {
if (!(s->u.ext_sb.s_firstfreeblock = bread(dev,
s->u.ext_sb.s_firstfreeblocknumber, BLOCK_SIZE))) {
printk ("ext_read_super: unable to read first free block\n");
s->s_dev = 0;
free_super(s);
return NULL;
}
if (!s->u.ext_sb.s_imap[0])
s->u.ext_sb.s_imap[1] = NULL;
if (!s->u.ext_sb.s_firstfreeinodenumber)
s->u.ext_sb.s_firstfreeinodeblock = NULL;
else {
block = 2 + (((unsigned long) s->u.ext_sb.s_imap[0]) - 1) / EXT_INODES_PER_BLOCK;
if (!(s->u.ext_sb.s_imap[1] = bread(dev, block, BLOCK_SIZE))) {
block = 2 + (s->u.ext_sb.s_firstfreeinodenumber - 1) / EXT_INODES_PER_BLOCK;
if (!(s->u.ext_sb.s_firstfreeinodeblock = bread(dev, block, BLOCK_SIZE))) {
printk ("ext_read_super: unable to read first free inode block\n");
brelse(s->u.ext_sb.s_zmap[1]);
brelse(s->u.ext_sb.s_firstfreeblock);
s->s_dev = 0;
free_super (s);
return NULL;
}
}
#endif
free_super(s);
/* set up enough so that it can read an inode */
s->s_dev = dev;
......@@ -172,26 +119,21 @@ struct super_block *ext_read_super(struct super_block *s,void *data)
void ext_write_super (struct super_block *sb)
{
#ifdef EXTFS_FREELIST
struct buffer_head * bh;
struct ext_super_block * es;
#ifdef EXTFS_DEBUG
printk ("ext_write_super called\n");
#endif
if (!(bh = bread(sb->s_dev, 1, BLOCK_SIZE))) {
printk ("ext_write_super: bread failed\n");
return;
}
es = (struct ext_super_block *) bh->b_data;
es->s_firstfreeblock = (unsigned long) sb->u.ext_sb.s_zmap[0];
es->s_freeblockscount = (unsigned long) sb->u.ext_sb.s_zmap[2];
es->s_firstfreeinode = (unsigned long) sb->u.ext_sb.s_imap[0];
es->s_freeinodescount = (unsigned long) sb->u.ext_sb.s_imap[2];
es->s_firstfreeblock = sb->u.ext_sb.s_firstfreeblocknumber;
es->s_freeblockscount = sb->u.ext_sb.s_freeblockscount;
es->s_firstfreeinode = sb->u.ext_sb.s_firstfreeinodenumber;
es->s_freeinodescount = sb->u.ext_sb.s_freeinodescount;
bh->b_dirt = 1;
brelse (bh);
sb->s_dirt = 0;
#endif
}
void ext_statfs (struct super_block *sb, struct statfs *buf)
......@@ -200,7 +142,8 @@ void ext_statfs (struct super_block *sb, struct statfs *buf)
put_fs_long(EXT_SUPER_MAGIC, &buf->f_type);
put_fs_long(1024, &buf->f_bsize);
put_fs_long(sb->u.ext_sb.s_nzones << sb->u.ext_sb.s_log_zone_size, &buf->f_blocks);
put_fs_long(sb->u.ext_sb.s_nzones << sb->u.ext_sb.s_log_zone_size,
&buf->f_blocks);
tmp = ext_count_free_blocks(sb);
put_fs_long(tmp, &buf->f_bfree);
put_fs_long(tmp, &buf->f_bavail);
......@@ -341,13 +284,7 @@ void ext_read_inode(struct inode * inode)
struct ext_inode * raw_inode;
int block;
#ifdef EXTFS_BITMAP
block = 2 + inode->i_sb->u.ext_sb.s_imap_blocks + inode->i_sb->u.ext_sb.s_zmap_blocks +
(inode->i_ino-1)/EXT_INODES_PER_BLOCK;
#endif
#ifdef EXTFS_FREELIST
block = 2 + (inode->i_ino-1)/EXT_INODES_PER_BLOCK;
#endif
if (!(bh=bread(inode->i_dev, block, BLOCK_SIZE)))
panic("unable to read i-node block");
raw_inode = ((struct ext_inode *) bh->b_data) +
......@@ -389,13 +326,7 @@ void ext_write_inode(struct inode * inode)
struct ext_inode * raw_inode;
int block;
#ifdef EXTFS_BITMAP
block = 2 + inode->i_sb->u.ext_sb.s_imap_blocks + inode->i_sb->u.ext_sb.s_zmap_blocks +
(inode->i_ino-1)/EXT_INODES_PER_BLOCK;
#endif
#ifdef EXTFS_FREELIST
block = 2 + (inode->i_ino-1)/EXT_INODES_PER_BLOCK;
#endif
if (!(bh=bread(inode->i_dev, block, BLOCK_SIZE)))
panic("unable to read i-node block");
raw_inode = ((struct ext_inode *)bh->b_data) +
......
......@@ -64,8 +64,6 @@ static int ext_match(int len,const char * name,struct ext_dir_entry * de)
/* "" means "." ---> so paths like "/usr/lib//libc.a" work */
if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
return 1;
/* if (len < EXT_NAME_LEN && de->name[len])
return 0; */
if (len < EXT_NAME_LEN && len != de->name_len)
return 0;
__asm__("cld\n\t"
......@@ -92,8 +90,7 @@ static struct buffer_head * ext_find_entry(struct inode * dir,
const char * name, int namelen, struct ext_dir_entry ** res_dir,
struct ext_dir_entry ** prev_dir, struct ext_dir_entry ** next_dir)
{
/* int entries; */
int block /* ,i */;
int block;
long offset;
struct buffer_head * bh;
struct ext_dir_entry * de;
......@@ -108,7 +105,6 @@ static struct buffer_head * ext_find_entry(struct inode * dir,
if (namelen > EXT_NAME_LEN)
namelen = EXT_NAME_LEN;
#endif
/* entries = dir->i_size / (sizeof (struct ext_dir_entry)); */
if (!(block = dir->i_data[0]))
return NULL;
if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE)))
......@@ -117,7 +113,6 @@ static struct buffer_head * ext_find_entry(struct inode * dir,
*prev_dir = NULL;
if (next_dir)
*next_dir = NULL;
/* i = 0; */
offset = 0;
de = (struct ext_dir_entry *) bh->b_data;
while (offset < dir->i_size) {
......@@ -126,8 +121,6 @@ static struct buffer_head * ext_find_entry(struct inode * dir,
bh = NULL;
if (!(block = ext_bmap(dir,offset>>BLOCK_SIZE_BITS)) ||
!(bh = bread(dir->i_dev, block, BLOCK_SIZE))) {
/* i += EXT_DIR_ENTRIES_PER_BLOCK; */
/* offset += BLOCK_SIZE; */
continue;
}
de = (struct ext_dir_entry *) bh->b_data;
......@@ -148,7 +141,6 @@ static struct buffer_head * ext_find_entry(struct inode * dir,
if (prev_dir)
*prev_dir = de;
de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
/* i++; */
}
brelse(bh);
return NULL;
......@@ -218,7 +210,6 @@ static struct buffer_head * ext_add_entry(struct inode * dir,
if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE)))
return NULL;
rec_len = ((8 + namelen + EXT_DIR_PAD - 1) / EXT_DIR_PAD) * EXT_DIR_PAD;
/* i = 0; */
offset = 0;
de = (struct ext_dir_entry *) bh->b_data;
while (1) {
......@@ -232,7 +223,6 @@ printk ("ext_add_entry: skipping to next block\n");
if (!block)
return NULL;
if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE))) {
/* i += EXT_DIR_ENTRIES_PER_BLOCK; */
offset += BLOCK_SIZE;
continue;
}
......@@ -271,7 +261,6 @@ printk ("ext_add_entry : creating next block\n");
/* Allocate the entry */
de->inode=0;
de->rec_len = rec_len;
/* dir->i_size = (i+1)*sizeof(struct ext_dir_entry); */
dir->i_size += de->rec_len;
dir->i_dirt = 1;
dir->i_ctime = CURRENT_TIME;
......@@ -292,7 +281,7 @@ printk ("ext_add_entry : creating next block\n");
dir->i_mtime = CURRENT_TIME;
de->name_len = namelen;
for (i=0; i < namelen ; i++)
de->name[i]=/*(i<namelen)?*/get_fs_byte(name+i)/*:0*/;
de->name[i]=get_fs_byte(name+i);
bh->b_dirt = 1;
*res_dir = de;
return bh;
......@@ -441,7 +430,6 @@ int ext_mkdir(struct inode * dir, const char * name, int len, int mode)
de->rec_len=16;
de->name_len=1;
strcpy(de->name,".");
/* de++; */
de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
de->inode = dir->i_ino;
de->rec_len=16;
......@@ -474,13 +462,11 @@ int ext_mkdir(struct inode * dir, const char * name, int len, int mode)
*/
static int empty_dir(struct inode * inode)
{
int /* nr, */ block;
/* int len; */
int block;
unsigned long offset;
struct buffer_head * bh;
struct ext_dir_entry * de, * de1;
/* len = inode->i_size / sizeof (struct ext_dir_entry); */
if (inode->i_size < 2 * 12 || !inode->i_data[0] ||
!(bh=bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) {
printk("warning - bad directory on dev %04x\n",inode->i_dev);
......@@ -493,7 +479,6 @@ static int empty_dir(struct inode * inode)
printk("warning - bad directory on dev %04x\n",inode->i_dev);
return 0;
}
/* nr = 2; */
offset = de->rec_len + de1->rec_len;
de = (struct ext_dir_entry *) ((char *) de1 + de1->rec_len);
while (offset < inode->i_size ) {
......@@ -749,12 +734,10 @@ static int subdir(struct inode * new, struct inode * old)
#define PARENT_INO(buffer) \
((struct ext_dir_entry *) ((char *) buffer + \
((struct ext_dir_entry *) buffer)->rec_len))->inode
/* (((struct ext_dir_entry *) (buffer))[1].inode) */
#define PARENT_NAME(buffer) \
((struct ext_dir_entry *) ((char *) buffer + \
((struct ext_dir_entry *) buffer)->rec_len))->name
/* (((struct ext_dir_entry *) (buffer))[1].name) */
/*
* rename uses retrying to avoid race-conditions: at least they should be minimal.
......
......@@ -166,8 +166,6 @@ void ext_truncate(struct inode * inode)
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
return;
/* if (inode->i_data[7] & 0xffff0000)
printk("BAD! ext inode has 16 high bits set\n"); */
while (1) {
flag = trunc_direct(inode);
flag |= trunc_indirect(inode,9,(unsigned long *)&inode->i_data[9]);
......
......@@ -51,7 +51,8 @@ int sys_dup(unsigned int fildes)
int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct file * filp;
extern int sock_fcntl (struct file *, unsigned int cmd,
unsigned long arg);
if (fd >= NR_OPEN || !(filp = current->filp[fd]))
return -EBADF;
switch (cmd) {
......@@ -74,6 +75,11 @@ int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
case F_GETLK: case F_SETLK: case F_SETLKW:
return -ENOSYS;
default:
/* sockets need a few special fcntls. */
if (S_ISSOCK (filp->f_inode->i_mode))
{
return (sock_fcntl (filp, cmd, arg));
}
return -EINVAL;
}
}
......@@ -79,10 +79,15 @@ int minix_free_block(int dev, int block)
struct buffer_head * bh;
unsigned int bit,zone;
if (!(sb = get_super(dev)))
panic("trying to free block on nonexistent device");
if (block < sb->u.minix_sb.s_firstdatazone || block >= sb->u.minix_sb.s_nzones)
panic("trying to free block not in datazone");
if (!(sb = get_super(dev))) {
printk("trying to free block on nonexistent device\n");
return 1;
}
if (block < sb->u.minix_sb.s_firstdatazone ||
block >= sb->u.minix_sb.s_nzones) {
printk("trying to free block not in datazone\n");
return 1;
}
bh = get_hash_table(dev,block,BLOCK_SIZE);
if (bh) {
if (bh->b_count > 1) {
......@@ -110,8 +115,11 @@ int minix_new_block(int dev)
struct super_block * sb;
int i,j;
if (!(sb = get_super(dev)))
panic("trying to get new block from nonexistant device");
if (!(sb = get_super(dev))) {
printk("trying to get new block from nonexistant device\n");
return 0;
}
repeat:
j = 8192;
for (i=0 ; i<8 ; i++)
if (bh=sb->u.minix_sb.s_zmap[i])
......@@ -119,16 +127,22 @@ int minix_new_block(int dev)
break;
if (i>=8 || !bh || j>=8192)
return 0;
if (set_bit(j,bh->b_data))
panic("new_block: bit already set");
if (set_bit(j,bh->b_data)) {
printk("new_block: bit already set");
goto repeat;
}
bh->b_dirt = 1;
j += i*8192 + sb->u.minix_sb.s_firstdatazone-1;
if (j >= sb->u.minix_sb.s_nzones)
return 0;
if (!(bh=getblk(dev,j,BLOCK_SIZE)))
panic("new_block: cannot get block");
if (bh->b_count != 1)
panic("new block: count is != 1");
if (!(bh=getblk(dev,j,BLOCK_SIZE))) {
printk("new_block: cannot get block");
return 0;
}
if (bh->b_count != 1) {
printk("new block: count is != 1");
return 0;
}
clear_block(bh->b_data);
bh->b_uptodate = 1;
bh->b_dirt = 1;
......
......@@ -14,7 +14,7 @@
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/tty.h>
#include <asm/segment.h>
struct file_operations * chrdev_fops[MAX_CHRDEV] = {
......@@ -338,35 +338,132 @@ int sys_creat(const char * pathname, int mode)
return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
}
int sys_close(unsigned int fd)
{
struct file * filp;
struct inode * inode;
static int
close_fp (struct file *filp)
{
struct inode *inode;
if (fd >= NR_OPEN)
return -EINVAL;
current->close_on_exec &= ~(1<<fd);
if (!(filp = current->filp[fd]))
return -EINVAL;
current->filp[fd] = NULL;
if (filp->f_count == 0) {
printk("Close: file count is 0\n");
return 0;
}
if (filp->f_count > 1) {
filp->f_count--;
return 0;
}
inode = filp->f_inode;
if (filp->f_op && filp->f_op->release)
filp->f_op->release(inode,filp);
filp->f_count--;
filp->f_inode = NULL;
iput(inode);
return 0;
}
int sys_vhangup(void)
int sys_close(unsigned int fd)
{
struct file * filp;
if (fd >= NR_OPEN)
return -EINVAL;
current->close_on_exec &= ~(1<<fd);
if (!(filp = current->filp[fd]))
return -EINVAL;
current->filp[fd] = NULL;
return (close_fp (filp));
}
/* This routine looks through all the process's and closes any
references to the current processes tty. To avoid problems with
process sleeping on an inode which has already been iput, anyprocess
which is sleeping on the tty is sent a sigkill (It's probably a rogue
process.) Also no process should ever have /dev/console as it's
controlling tty, or have it open for reading. So we don't have to
worry about messing with all the daemons abilities to write messages
to the console. (Besides they should be using syslog.) */
int
sys_vhangup(void)
{
return -ENOSYS;
int i;
int j;
struct file *filep;
struct tty_struct *tty;
extern void kill_wait (struct wait_queue **q, int signal);
extern int kill_pg (int pgrp, int sig, int priv);
if (!suser()) return (-EPERM);
/* send the SIGHUP signal. */
kill_pg (current->pgrp, SIGHUP, 0);
/* See if there is a controlling tty. */
if (current->tty < 0) return (0);
for (i = 0; i < NR_TASKS; i++)
{
if (task[i] == NULL) continue;
for (j = 0; j < NR_OPEN; j++)
{
filep = task[i]->filp[j];
if (filep == NULL) continue;
/* now we need to check to see if this file points to the
device we are trying to close. */
if (!S_ISCHR (filep->f_inode->i_mode)) continue;
/* This will catch both /dev/tty and the explicit terminal
device. However, we must make sure that f_rdev is
defined and correct. */
if ((MAJOR(filep->f_inode->i_rdev) == 5 ||
MAJOR(filep->f_inode->i_rdev) == 4 ) &&
(MAJOR(filep->f_rdev) == 4 &&
MINOR(filep->f_rdev) == MINOR (current->tty)))
{
task[i]->filp[j] = NULL;
/* so now we have found something to close. We
need to kill every process waiting on the
inode. */
kill_wait (&filep->f_inode->i_wait, SIGKILL);
/* now make sure they are awake before we close the
file. */
wake_up (&filep->f_inode->i_wait);
/* finally close the file. */
current->close_on_exec &= ~(1<<j);
close_fp (filep);
}
}
/* can't let them keep a reference to it around.
But we can't touch current->tty until after the
loop is complete. */
if (task[i]->tty == current->tty && task[i] != current)
{
task[i]->tty = -1;
}
}
/* need to do tty->session = 0 */
tty = TTY_TABLE(MINOR(current->tty));
tty->session = 0;
tty->pgrp = -1;
current->tty = -1;
return (0);
}
#ifndef _CONFIG_DIST_H
#define _CONFIG_DIST_H
#ifndef _LINUX_CONFIG_DIST_H
#define _LINUX_CONFIG_DIST_H
#ifdef CONFIG_DISTRIBUTION
#undef CONFG_SCSI
......
#ifndef _CONFIG_H
#define _CONFIG_H
#ifndef _LINUX_CONFIG_H
#define _LINUX_CONFIG_H
#define CONFIG_DISTRIBUTION
......
#ifndef _CONFIG_SITE_H
#define _CONFIG_SITE_H
#ifndef _LINUX_CONFIG_SITE_H
#define _LINUX_CONFIG_SITE_H
/*
This configuration file contains site specific things, things
......
#ifndef _CTYPE_H
#define _CTYPE_H
#ifndef _LINUX_CTYPE_H
#define _LINUX_CTYPE_H
#define _U 0x01 /* upper */
#define _L 0x02 /* lower */
......
#ifndef _EXT_FS_H
#define _EXT_FS_H
#ifndef _LINUX_EXT_FS_H
#define _LINUX_EXT_FS_H
/*
* The ext filesystem constants/structures
*/
/*
* Free blocks/inodes management style
*
* One of these two constants must be defined
*
*/
/* #define EXTFS_BITMAP */ /* use a bitmap */
#define EXTFS_FREELIST /* use a linked list */
#define EXT_NAME_LEN 255
#define EXT_ROOT_INO 1
#define EXT_I_MAP_SLOTS 8
#define EXT_Z_MAP_SLOTS 8
#define EXT_SUPER_MAGIC 0x137D
#define EXT_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct ext_inode)))
/* #define EXT_DIR_ENTRIES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct ext_dir_entry))) */
struct ext_inode {
unsigned short i_mode;
......@@ -49,16 +37,10 @@ struct ext_free_block {
struct ext_super_block {
unsigned long s_ninodes;
unsigned long s_nzones;
#ifdef EXTFS_BITMAP
unsigned long s_imap_blocks;
unsigned long s_zmap_blocks;
#endif
#ifdef EXTFS_FREELIST
unsigned long s_firstfreeblock;
unsigned long s_freeblockscount;
unsigned long s_firstfreeinode;
unsigned long s_freeinodescount;
#endif
unsigned long s_firstdatazone;
unsigned long s_log_zone_size;
unsigned long s_max_size;
......
......@@ -2,18 +2,20 @@
#define _EXT_FS_SB
/*
* extended-fs super-block data in memory (same as minix: has to change)
* extended-fs super-block data in memory
*/
struct ext_sb_info {
unsigned long s_ninodes;
unsigned long s_nzones;
unsigned long s_imap_blocks;
unsigned long s_zmap_blocks;
unsigned long s_firstdatazone;
unsigned long s_log_zone_size;
unsigned long s_max_size;
struct buffer_head * s_imap[8];
struct buffer_head * s_zmap[8];
unsigned long s_firstfreeblocknumber;
unsigned long s_freeblockscount;
struct buffer_head * s_firstfreeblock;
unsigned long s_firstfreeinodenumber;
unsigned long s_freeinodescount;
struct buffer_head * s_firstfreeinodeblock;
};
#endif
#ifndef _FCNTL_H
#define _FCNTL_H
#ifndef _LINUX_FCNTL_H
#define _LINUX_FCNTL_H
/* open/fcntl - O_SYNC isn't implemented yet */
#define O_ACCMODE 0003
......@@ -28,6 +28,9 @@
#define F_SETLK 6
#define F_SETLKW 7
#define F_SETOWN 8 /* for sockets. */
#define F_GETOWN 9 /* for sockets. */
/* for F_[GET|SET]FL */
#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
......
......@@ -225,7 +225,7 @@ extern struct file file_table[NR_FILE];
extern struct super_block super_block[NR_SUPER];
extern void grow_buffers(int size);
extern int shrink_buffers(void);
extern int shrink_buffers(unsigned int priority);
extern int nr_buffers;
extern int nr_buffer_heads;
......
#ifndef _GENHD_H
#define _GENHD_H
#ifndef _LINUX_GENHD_H
#define _LINUX_GENHD_H
/*
* genhd.h Copyright (C) 1992 Drew Eckhardt
......
......@@ -7,14 +7,14 @@
#define NR_INODE 128
#define NR_FILE 128
#define NR_SUPER 8
#define NR_HASH 307
#define NR_HASH 997
#define BLOCK_SIZE 1024
#define BLOCK_SIZE_BITS 10
#define MAX_CHRDEV 16
#define MAX_BLKDEV 16
#define NGROUPS_MAX 32 /* supplemental group IDs are available */
#define ARG_MAX 40960 /* # bytes of args + environ for exec() */
#define ARG_MAX 131072 /* # bytes of args + environ for exec() */
#define CHILD_MAX 999 /* no limit :-) */
#define OPEN_MAX 32 /* # open files a process may have */
#define LINK_MAX 127 /* # links a file may have */
......
#ifndef _MINIX_FS_H
#define _MINIX_FS_H
#ifndef _LINUX_MINIX_FS_H
#define _LINUX_MINIX_FS_H
/*
* The minix filesystem constants/structures
......
#ifndef _MM_H
#define _MM_H
#ifndef _LINUX_MM_H
#define _LINUX_MM_H
#define PAGE_SIZE 4096
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/signal.h>
/*
* BAD_PAGE is the page that is used for page faults when linux
......
#ifndef _MSDOS_FS_H
#define _MSDOS_FS_H
#ifndef _LINUX_MSDOS_FS_H
#define _LINUX_MSDOS_FS_H
/*
* The MS-DOS filesystem constants/structures
......
#ifndef _SYS_PARAM_H
#define _SYS_PARAM_H
#ifndef _LINUX_PARAM_H
#define _LINUX_PARAM_H
#ifndef HZ
#define HZ 100
#define EXEC_PAGESIZE 4096
#endif
#define EXEC_PAGESIZE 4096
#define NGROUPS 32 /* Max number of groups per user */
#ifndef NGROUPS
#define NGROUPS 32
#endif
#ifndef NOGROUP
#define NOGROUP -1
#endif
#define MAXHOSTNAMELEN 8
#define MAXHOSTNAMELEN 64 /* max length of hostname */
#endif
......@@ -221,6 +221,7 @@ extern struct task_struct *current;
extern unsigned long volatile jiffies;
extern unsigned long startup_time;
extern int jiffies_offset;
extern int need_resched;
#define CURRENT_TIME (startup_time+(jiffies+jiffies_offset)/HZ)
......
......@@ -35,12 +35,13 @@ typedef unsigned int sigset_t; /* 32 bits */
* so they are commented out.
*/
/*
#define SIGIO 23
#define SIGPOLL SIGIO
#define SIGURG SIGIO
#define SIGXCPU 24
#define SIGXFSZ 25
*/
#define SIGVTALRM 26
#define SIGPROF 27
......@@ -60,12 +61,15 @@ typedef unsigned int sigset_t; /* 32 bits */
#define SIG_UNBLOCK 1 /* for unblocking signals */
#define SIG_SETMASK 2 /* for setting the signal mask */
#define SIG_DFL ((void (*)(int))0) /* default signal handling */
#define SIG_IGN ((void (*)(int))1) /* ignore signal */
#define SIG_ERR ((void (*)(int))-1) /* error return from signal */
/* Type of a signal handler. */
typedef void (*__sighandler_t)(int);
#define SIG_DFL ((__sighandler_t)0) /* default signal handling */
#define SIG_IGN ((__sighandler_t)1) /* ignore signal */
#define SIG_ERR ((__sighandler_t)-1) /* error return from signal */
struct sigaction {
void (*sa_handler)(int);
__sighandler_t sa_handler;
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
......
......@@ -2,7 +2,7 @@
#define _LINUX_SOCKET_H
struct sockaddr {
u_short sa_family; /* address family, AF_xxx */
unsigned short sa_family; /* address family, AF_xxx */
char sa_data[14]; /* 14 bytes of protocol address */
};
......@@ -11,8 +11,9 @@ struct sockaddr {
*/
#define SOCK_STREAM 1 /* stream (connection) socket */
#define SOCK_DGRAM 2 /* datagram (connectionless) socket */
#define SOCK_SEQPACKET 3 /* sequential packet socket */
#define SOCK_RAW 4 /* raw socket */
#define SOCK_RAW 3 /* raw socket */
#define SOCK_RDM 4 /* reliably-delivered message */
#define SOCK_SEQPACKET 5 /* sequential packet socket */
/*
* supported address families
......@@ -27,4 +28,22 @@ struct sockaddr {
#define PF_UNIX AF_UNIX
#define PF_INET AF_INET
#endif
/* flags we can use with send/ and recv. */
#define MSG_OOB 1
#define MSG_PEEK 2
/* for setsockoptions */
#define SO_DEBUG 1
#define SO_REUSEADDR 2
#define SO_TYPE 3
#define SO_ERROR 4
#define SO_DONTROUTE 5
#define SO_BROADCAST 6
#define SO_SNDBUF 7
#define SO_RCVBUF 8
#define SO_KEEPALIVE 9
/* setsockoptions level */
#define SOL_SOCKET 1
#endif /* _LINUX_SOCKET_H */
#ifndef _LINUX_STAT_H
#define _LINUX_STAT_H
#ifndef __NOT_KERNEL
struct old_stat {
unsigned short st_dev;
unsigned short st_ino;
......@@ -38,6 +40,8 @@ struct new_stat {
unsigned long __unused5;
};
#endif
#define S_IFMT 00170000
#define S_IFSOCK 0140000
#define S_IFLNK 0120000
......
......@@ -114,6 +114,7 @@ extern int sys_newfstat();
extern int sys_newuname();
extern int sys_iopl();
extern int sys_vhangup();
extern int sys_idle();
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,
......@@ -135,7 +136,8 @@ sys_swapon, sys_reboot, sys_readdir, sys_mmap, sys_munmap,
sys_truncate, 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_newlstat, sys_newfstat, sys_newuname, sys_iopl, sys_vhangup,
sys_idle };
/* So we don't have to do any more manual updating.... */
int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
......@@ -22,6 +22,8 @@
* FLOPPY_TIMER floppy disk timer (not used right now)
*
* SCSI_TIMER scsi.c timeout timer
*
* NET_TIMER tcp/ip timeout timer
*/
#define BLANK_TIMER 0
......@@ -40,6 +42,7 @@
#define HD_TIMER 16
#define FLOPPY_TIMER 17
#define SCSI_TIMER 18
#define NET_TIMER 19
struct timer_struct {
unsigned long expires;
......
......@@ -2,10 +2,10 @@
#define _LINUX_TIMES_H
struct tms {
time_t tms_utime;
time_t tms_stime;
time_t tms_cutime;
time_t tms_cstime;
clock_t tms_utime;
clock_t tms_stime;
clock_t tms_cutime;
clock_t tms_cstime;
};
#endif
......@@ -146,7 +146,9 @@ struct tty_struct {
struct termios termios;
int pgrp;
int session;
int stopped;
unsigned char stopped:1, status_changed:1, packet:1;
unsigned char ctrl_status;
short unused; /* make everything a multiple of 4. */
int flags;
int count;
struct winsize winsize;
......
......@@ -23,7 +23,7 @@ typedef long clock_t;
#ifndef _PTRDIFF_T
#define _PTRDIFF_T
typedef long ptrdiff_t;
typedef int ptrdiff_t;
#endif
#ifndef NULL
......@@ -65,9 +65,6 @@ typedef unsigned long tcflag_t;
typedef unsigned long fd_set;
typedef struct { int quot,rem; } div_t;
typedef struct { long quot,rem; } ldiv_t;
struct ustat {
daddr_t f_tfree;
ino_t f_tinode;
......
......@@ -2,8 +2,8 @@
#define _LINUX_UN_H
struct sockaddr_un {
u_short sun_family; /* AF_UNIX */
unsigned short sun_family; /* AF_UNIX */
char sun_path[108]; /* pathname */
};
#endif /* _UN_H */
#endif /* _LINUX_UN_H */
......@@ -117,6 +117,8 @@
#define __NR_fstat 108
#define __NR_uname 109
#define __NR_iopl 110
#define __NR_vhangup 111
#define __NR_idle 112
extern int errno;
......
......@@ -18,6 +18,10 @@
#include <linux/head.h>
#include <linux/unistd.h>
extern unsigned long * prof_buffer;
extern unsigned long prof_len;
extern int end;
/*
* we need this inline - forking from kernel space will result
* in NO COPY ON WRITE (!!!), until an execve is executed. This
......@@ -30,6 +34,7 @@
* won't be any messing with the stack from main(), but we define
* some others too.
*/
static inline _syscall0(int,idle)
static inline _syscall0(int,fork)
static inline _syscall0(int,pause)
static inline _syscall1(int,setup,void *,BIOS)
......@@ -54,7 +59,6 @@ extern void init(void);
extern void init_IRQ(void);
extern long blk_dev_init(long,long);
extern long chr_dev_init(long,long);
extern void hd_init(void);
extern void floppy_init(void);
extern void sock_init(void);
extern long rd_init(long mem_start, int length);
......@@ -157,23 +161,28 @@ void start_kernel(void)
trap_init();
init_IRQ();
sched_init();
#ifdef PROFILE_SHIFT
prof_buffer = (unsigned long *) memory_start;
prof_len = (unsigned long) &end;
prof_len >>= PROFILE_SHIFT;
memory_start += prof_len * sizeof(unsigned long);
#endif
memory_start = chr_dev_init(memory_start,memory_end);
memory_start = blk_dev_init(memory_start,memory_end);
memory_start = mem_init(memory_start,memory_end);
buffer_init();
time_init();
printk("Linux version " UTS_RELEASE " " __DATE__ " " __TIME__ "\n");
hd_init();
floppy_init();
sock_init();
sti();
#ifdef CONFIG_SCSI
scsi_dev_init();
#endif
sti();
move_to_user_mode();
if (!fork()) { /* we count on this going ok */
if (!fork()) /* we count on this going ok */
init();
}
/*
* task[0] is meant to be used as an "idle" task: it may not sleep, but
* it might do some general things like count free pages or it could be
......@@ -181,10 +190,10 @@ void start_kernel(void)
* anything that can be useful, but shouldn't take time from the real
* processes.
*
* Right now task[0] just does a infinite loop in user mode.
* Right now task[0] just does a infinite idle loop.
*/
for(;;)
/* nothing */ ;
idle();
}
static int printf(const char *fmt, ...)
......
......@@ -593,7 +593,7 @@ static struct sigaction hd_sigaction = {
NULL
};
void hd_init(void)
unsigned long hd_init(unsigned long mem_start)
{
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
blkdev_fops[MAJOR_NR] = &hd_fops;
......@@ -602,6 +602,7 @@ void hd_init(void)
if (irqaction(HD_IRQ,&hd_sigaction))
printk("Unable to get IRQ%d for the harddisk driver\n",HD_IRQ);
timer_table[HD_TIMER].fn = hd_times_out;
return mem_start;
}
#endif
......@@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/config.h>
#include <asm/system.h>
......@@ -299,6 +300,9 @@ long blk_dev_init(long mem_start, long mem_end)
request[i].next = NULL;
}
memset(ro_bits,0,sizeof(ro_bits));
#ifdef CONFIG_BLK_DEV_HD
mem_start = hd_init(mem_start,mem_end);
#endif
#ifdef RAMDISK
mem_start += rd_init(mem_start, RAMDISK*1024);
#endif
......
......@@ -7,11 +7,11 @@
#include <linux/config.h>
#ifdef RAMDISK
#include <linux/string.h>
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/memory.h>
......
......@@ -929,13 +929,13 @@ void con_write(struct tty_struct * tty)
* Control characters can be used in the _middle_
* of an escape sequence.
*/
if (c < 32 || c == 127) switch(c) {
switch (c) {
case 7:
sysbeep();
break;
continue;
case 8:
bs(currcons);
break;
continue;
case 9:
pos -= (x << 1);
while (x < video_num_columns - 1) {
......@@ -944,80 +944,84 @@ void con_write(struct tty_struct * tty)
break;
}
pos += (x << 1);
break;
continue;
case 10: case 11: case 12:
lf(currcons);
if (!lfnlmode)
break;
continue;
case 13:
cr(currcons);
break;
continue;
case 14:
charset = 1;
translate = G1_charset;
break;
continue;
case 15:
charset = 0;
translate = G0_charset;
break;
continue;
case 24: case 26:
state = ESnormal;
break;
continue;
case 27:
state = ESesc;
break;
continue;
case 127:
del(currcons);
break;
} else switch(state) {
continue;
case 128+27:
state = ESsquare;
continue;
}
switch(state) {
case ESesc:
state = ESnormal;
switch (c) {
case '[':
state = ESsquare;
break;
continue;
case 'E':
cr(currcons);
lf(currcons);
break;
continue;
case 'M':
ri(currcons);
break;
continue;
case 'D':
lf(currcons);
break;
continue;
case 'H':
tab_stop[x >> 5] |= (1 << (x & 31));
break;
continue;
case 'Z':
respond_ID(currcons,tty);
break;
continue;
case '7':
save_cur(currcons);
break;
continue;
case '8':
restore_cur(currcons);
break;
continue;
case '(':
state = ESsetG0;
break;
continue;
case ')':
state = ESsetG1;
break;
continue;
case '#':
state = EShash;
break;
continue;
case 'c':
reset_terminal(currcons,1);
break;
continue;
case '>': /* Numeric keypad */
SET(kbdapplic,kapplic,0);
break;
continue;
case '=': /* Appl. keypad */
SET(kbdapplic,kapplic,1);
break;
continue;
}
break;
continue;
case ESsquare:
for(npar = 0 ; npar < NPAR ; npar++)
par[npar] = 0;
......@@ -1025,97 +1029,97 @@ void con_write(struct tty_struct * tty)
state = ESgetpars;
if (c == '[') { /* Function key */
state=ESfunckey;
break;
continue;
}
if (ques=(c=='?'))
break;
continue;
case ESgetpars:
if (c==';' && npar<NPAR-1) {
npar++;
break;
continue;
} else if (c>='0' && c<='9') {
par[npar] *= 10;
par[npar] += c-'0';
break;
continue;
} else state=ESgotpars;
case ESgotpars:
state = ESnormal;
switch(c) {
case 'h':
set_mode(currcons,1);
break;
continue;
case 'l':
set_mode(currcons,0);
break;
continue;
case 'n':
if (!ques)
if (par[0] == 5)
status_report(currcons,tty);
else if (par[0] == 6)
cursor_report(currcons,tty);
break;
continue;
}
if (ques) {
ques = 0;
break;
continue;
}
switch(c) {
case 'G': case '`':
if (par[0]) par[0]--;
gotoxy(currcons,par[0],y);
break;
continue;
case 'A':
if (!par[0]) par[0]++;
gotoxy(currcons,x,y-par[0]);
break;
continue;
case 'B': case 'e':
if (!par[0]) par[0]++;
gotoxy(currcons,x,y+par[0]);
break;
continue;
case 'C': case 'a':
if (!par[0]) par[0]++;
gotoxy(currcons,x+par[0],y);
break;
continue;
case 'D':
if (!par[0]) par[0]++;
gotoxy(currcons,x-par[0],y);
break;
continue;
case 'E':
if (!par[0]) par[0]++;
gotoxy(currcons,0,y+par[0]);
break;
continue;
case 'F':
if (!par[0]) par[0]++;
gotoxy(currcons,0,y-par[0]);
break;
continue;
case 'd':
if (par[0]) par[0]--;
gotoxy(currcons,x,par[0]);
break;
continue;
case 'H': case 'f':
if (par[0]) par[0]--;
if (par[1]) par[1]--;
gotoxy(currcons,par[1],par[0]);
break;
continue;
case 'J':
csi_J(currcons,par[0]);
break;
continue;
case 'K':
csi_K(currcons,par[0]);
break;
continue;
case 'L':
csi_L(currcons,par[0]);
break;
continue;
case 'M':
csi_M(currcons,par[0]);
break;
continue;
case 'P':
csi_P(currcons,par[0]);
break;
continue;
case 'c':
if (!par[0])
respond_ID(currcons,tty);
break;
continue;
case 'g':
if (!par[0])
tab_stop[x >> 5] &= ~(1 << (x & 31));
......@@ -1126,10 +1130,10 @@ void con_write(struct tty_struct * tty)
tab_stop[3] =
tab_stop[4] = 0;
}
break;
continue;
case 'm':
csi_m(currcons);
break;
continue;
case 'r':
if (!par[0])
par[0]++;
......@@ -1142,24 +1146,24 @@ void con_write(struct tty_struct * tty)
bottom=par[1];
gotoxy(currcons,0,0);
}
break;
continue;
case 's':
save_cur(currcons);
break;
continue;
case 'u':
restore_cur(currcons);
break;
continue;
case '@':
csi_at(currcons,par[0]);
break;
continue;
case ']': /* setterm functions */
setterm_command(currcons);
break;
continue;
}
break;
continue;
case ESfunckey:
state = ESnormal;
break;
continue;
case EShash:
state = ESnormal;
if (c == '8') {
......@@ -1170,7 +1174,7 @@ void con_write(struct tty_struct * tty)
video_erase_char =
(video_erase_char & 0xff00) | ' ';
}
break;
continue;
case ESsetG0:
if (c == '0')
G0_charset = GRAF_TRANS;
......@@ -1181,7 +1185,7 @@ void con_write(struct tty_struct * tty)
if (charset == 0)
translate = G0_charset;
state = ESnormal;
break;
continue;
case ESsetG1:
if (c == '0')
G1_charset = GRAF_TRANS;
......@@ -1192,7 +1196,7 @@ void con_write(struct tty_struct * tty)
if (charset == 1)
translate = G1_charset;
state = ESnormal;
break;
continue;
default:
state = ESnormal;
}
......
......@@ -83,14 +83,12 @@ static int open_mouse(struct inode * inode, struct file * file)
mouse.dx = 0;
mouse.dy = 0;
mouse.buttons = mouse.latch_buttons = 0x80;
MSE_INT_ON();
if (request_irq(MOUSE_IRQ, mouse_interrupt)) {
MSE_INT_OFF();
mouse.active = 0;
mouse.ready = 0;
mouse.inode = NULL;
return -EBUSY;
}
/* once we get to here mouse is unused, IRQ is busy */
mouse.active = 0; /* it's not active, fix it */
return -EBUSY; /* IRQ is busy, so we're BUSY */
} /* if we can't get the IRQ and mouse not active */
MSE_INT_ON();
return 0;
}
......
......@@ -201,11 +201,15 @@ void copy_to_cooked(struct tty_struct * tty)
if (I_IXON(tty)) {
if ((STOP_CHAR(tty) != __DISABLED_CHAR) &&
(c==STOP_CHAR(tty))) {
tty->status_changed = 1;
tty->ctrl_status |= TIOCPKT_STOP;
tty->stopped=1;
continue;
}
if ((START_CHAR(tty) != __DISABLED_CHAR) &&
(c==START_CHAR(tty))) {
tty->status_changed = 1;
tty->ctrl_status |= TIOCPKT_START;
tty->stopped=0;
continue;
}
......@@ -338,10 +342,32 @@ static int read_chan(unsigned int channel, struct file * file, char * buf, int n
}
if (file->f_flags & O_NONBLOCK)
time = current->timeout = 0;
else if (L_CANON(tty))
else if (L_CANON(tty)) {
wait_for_canon_input(tty);
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
}
if (minimum>nr)
minimum = nr;
/* deal with packet mode: First test for status change */
if (tty->packet && tty->link && tty->link->status_changed)
{
put_fs_byte (tty->link->ctrl_status, b);
tty->link->status_changed = 0;
return (1);
}
/* now bump the buffer up one. */
if (tty->packet)
{
put_fs_byte (0,b++);
nr --;
/* this really shouldn't happen, but we need to
put it here. */
if (nr == 0) return (1);
}
while (nr>0) {
TTY_READ_FLUSH(tty);
if (tty->link)
......@@ -379,8 +405,20 @@ static int read_chan(unsigned int channel, struct file * file, char * buf, int n
if (tty->link && tty->link->write)
TTY_WRITE_FLUSH(tty->link);
current->timeout = 0;
if (b-buf)
return b-buf;
/* packet mode sticks in an extra 0. If that's all we've got,
we should count it a zero bytes. */
if (tty->packet)
{
if ((b-buf) > 1)
return b-buf;
}
else
{
if (b-buf)
return b-buf;
}
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
if (file->f_flags & O_NONBLOCK)
......@@ -523,9 +561,20 @@ static int tty_open(struct inode * inode, struct file * filp)
return -EAGAIN;
if (tty->link)
tty->link->count++;
/* perhaps user applications that don't take care of
this deserve what the get, but I think my system
has hung do to this, esp. in X. -RAB */
tty->termios.c_lflag &= ~ECHO;
}
tty->count++;
retval = 0;
/* clean up the packet stuff. */
tty->status_changed = 0;
tty->ctrl_status = 0;
tty->packet = 0;
if (!(filp->f_flags & O_NOCTTY) &&
current->leader &&
current->tty<0 &&
......@@ -598,6 +647,12 @@ static int tty_select(struct inode * inode, struct file * filp, int sel_type, se
return 1;
if (tty->link && !tty->link->count)
return 1;
/* see if the status byte can be read. */
if (tty->packet && tty->link &&
tty->link->status_changed)
return 1;
select_wait(&tty->secondary->proc_list, wait);
return 0;
case SEL_OUT:
......@@ -639,7 +694,7 @@ long tty_init(long kmem_start)
for (i=0 ; i<256 ; i++) {
tty_table[i] = (struct tty_struct) {
{0, 0, 0, 0, 0, INIT_C_CC},
-1, 0, 0, 0, 0, {0,0,0,0},
-1, 0, 0, 0, 0, 0, 0, 0, 0, {0,0,0,0},
NULL, NULL, NULL, NULL, NULL
};
}
......@@ -655,6 +710,10 @@ long tty_init(long kmem_start)
-1, /* initial pgrp */
0, /* initial session */
0, /* initial stopped */
0, /* initial status_changed */
0, /* initial packet */
0, /* initial ctrl_status */
0, /* initial unused */
0, /* initial flags */
0, /* initial count */
{video_num_lines,video_num_columns,0,0},
......@@ -673,7 +732,7 @@ long tty_init(long kmem_start)
INIT_C_CC},
-1,
0,
0,
0, 0, 0, 0, 0,
0,
0,
{25,80,0,0},
......@@ -692,7 +751,7 @@ long tty_init(long kmem_start)
INIT_C_CC},
-1,
0,
0,
0, 0, 0, 0, 0,
0,
0,
{25,80,0,0},
......@@ -709,7 +768,7 @@ long tty_init(long kmem_start)
INIT_C_CC},
-1,
0,
0,
0, 0, 0, 0, 0,
0,
0,
{25,80,0,0},
......
......@@ -33,6 +33,8 @@ static void flush(struct tty_queue * queue)
void flush_input(struct tty_struct * tty)
{
tty->status_changed = 1;
tty->ctrl_status |= TIOCPKT_FLUSHREAD;
if (tty->read_q) {
flush(tty->read_q);
wake_up(&tty->read_q->proc_list);
......@@ -49,6 +51,8 @@ void flush_input(struct tty_struct * tty)
void flush_output(struct tty_struct * tty)
{
tty->status_changed = 1;
tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
if (tty->write_q) {
flush(tty->write_q);
wake_up(&tty->write_q->proc_list);
......@@ -138,6 +142,12 @@ static int set_termios(struct tty_struct * tty, struct termios * termios,
((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios);
if (IS_A_SERIAL(channel) && tty->termios.c_cflag != old_cflag)
change_speed(channel-64);
/* puting mpty's into echo mode is very bad, and I think under
some situations can cause the kernel to do nothing but
copy characters back and forth. -RAB */
if (IS_A_PTY_MASTER(channel)) tty->termios.c_lflag &= ~ECHO;
return 0;
}
......@@ -179,6 +189,22 @@ static int set_termio(struct tty_struct * tty, struct termio * termio,
}
for (i=0 ; i< (sizeof (*termio)) ; i++)
((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio);
/* take care of the packet stuff. */
if ((tmp_termio.c_iflag & IXON) &&
~(tty->termios.c_iflag & IXON))
{
tty->status_changed = 1;
tty->ctrl_status |= TIOCPKT_DOSTOP;
}
if (~(tmp_termio.c_iflag & IXON) &&
(tty->termios.c_iflag & IXON))
{
tty->status_changed = 1;
tty->ctrl_status |= TIOCPKT_NOSTOP;
}
*(unsigned short *)&tty->termios.c_iflag = tmp_termio.c_iflag;
*(unsigned short *)&tty->termios.c_oflag = tmp_termio.c_oflag;
*(unsigned short *)&tty->termios.c_cflag = tmp_termio.c_cflag;
......@@ -408,6 +434,21 @@ int tty_ioctl(struct inode * inode, struct file * file,
tty->session = 0;
}
return 0;
case TIOCPKT:
{
int on;
if (!IS_A_PTY_MASTER(dev))
return (-EINVAL);
verify_area ((unsigned long *)arg, sizeof (int));
on=get_fs_long ((unsigned long *)arg);
if (on )
tty->packet = 1;
else
tty->packet = 0;
return (0);
}
default:
return vt_ioctl(tty, dev, cmd, arg);
}
......
......@@ -203,6 +203,30 @@ int kill_pg(int pgrp, int sig, int priv)
return(found ? 0 : retval);
}
/* This routine is used by vhangup. It send's sigkill to everything
waiting on a particular wait_queue. It assumes root privledges.
We don't want to destroy the wait queue here, because the caller
should call wake_up immediately after calling kill_wait. */
void
kill_wait (struct wait_queue **q, int sig)
{
struct wait_queue *next;
struct wait_queue *tmp;
struct task_struct *p;
if (!q || !(next = *q))
return;
do {
tmp = next;
next = tmp->next;
if (p = tmp->task)
{
send_sig (sig, p , 1);
}
} while (next && next != *q);
}
int kill_proc(int pid, int sig, int priv)
{
struct task_struct **p;
......
......@@ -29,6 +29,9 @@
int need_resched = 0;
unsigned long * prof_buffer = NULL;
unsigned long prof_len = 0;
#define _S(nr) (1<<((nr)-1))
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
......@@ -157,12 +160,14 @@ void schedule(void)
if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
c = (*p)->counter, next = i;
}
if (c) break;
if (c)
break;
for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
if (*p)
(*p)->counter = ((*p)->counter >> 1) +
(*p)->priority;
}
sti();
switch_to(next);
}
......@@ -396,21 +401,29 @@ static void do_timer(int regs)
static int avg_cnt = 0;
jiffies++;
if (3 & ((struct pt_regs *) regs)->cs)
if (3 & ((struct pt_regs *) regs)->cs) {
current->utime++;
else {
current->stime++;
/* Update ITIMER_VIRT for current task if not in a system call */
if (current->it_virt_value && !(--current->it_virt_value)) {
current->it_virt_value = current->it_virt_incr;
send_sig(SIGVTALRM,current,1);
}
} else {
current->stime++;
#ifdef PROFILE_SHIFT
if (prof_buffer && current != task[0]) {
unsigned long eip = ((struct pt_regs *) regs)->eip;
eip >>= PROFILE_SHIFT;
if (eip < prof_len)
prof_buffer[eip]++;
}
#endif
}
if (--avg_cnt < 0) {
avg_cnt = 500;
update_avg();
}
if ((--current->counter)<=0) {
if (current == task[0] || (--current->counter)<=0) {
current->counter=0;
need_resched = 1;
}
......
......@@ -12,6 +12,9 @@
* NOTE: This code handles signal-recognition, which happens every time
* after a timer-interrupt and after each system call.
*
* I changed all the .align's to 4 (16 byte alignment), as that's faster
* on a 486.
*
* Stack layout in 'ret_from_system_call':
* ptrace needs to have all regs on the stack.
* if the order here is changed, it needs to be
......@@ -75,10 +78,6 @@ sa_restorer = 12
ENOSYS = 38
/*
* Ok, I get parallel printer interrupts while using the floppy for some
* strange reason. Urgel. Now I just ignore them.
*/
.globl _system_call,_sys_execve
.globl _device_not_available, _coprocessor_error
.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op
......@@ -107,11 +106,11 @@ ENOSYS = 38
movl $0x17,%edx; \
mov %dx,%fs
.align 2
.align 4
reschedule:
pushl $ret_from_sys_call
jmp _schedule
.align 2
.align 4
_system_call:
pushl %eax # save orig_eax
SAVE_ALL
......@@ -120,6 +119,7 @@ _system_call:
jae ret_from_sys_call
call _sys_call_table(,%eax,4)
movl %eax,EAX(%esp) # save the return value
.align 4,0x90
ret_from_sys_call:
cmpw $0x0f,CS(%esp) # was old code segment supervisor ?
jne 2f
......@@ -128,14 +128,12 @@ ret_from_sys_call:
1: cmpl $0,_need_resched
jne reschedule
movl _current,%eax
cmpl _task,%eax # task[0] cannot have signals
je 2f
cmpl $0,state(%eax) # state
jne reschedule
cmpl $0,counter(%eax) # counter
je reschedule
movl $1,_need_resched
cmpl _task,%eax # task[0] cannot have signals
je 2f
movl $0,_need_resched
movl signal(%eax),%ebx
movl blocked(%eax),%ecx
notl %ecx
......@@ -167,7 +165,7 @@ ret_from_sys_call:
addl $4,%esp # skip the orig_eax
iret
.align 2
.align 4
_sys_execve:
lea (EIP+4)(%esp),%eax # don't forget about the return address.
pushl %eax
......@@ -175,9 +173,11 @@ _sys_execve:
addl $4,%esp
ret
.align 4
_divide_error:
pushl $0 # no error code
pushl $_do_divide_error
.align 4,0x90
error_code:
push %fs
push %es
......@@ -207,13 +207,13 @@ error_code:
addl $8,%esp
jmp ret_from_sys_call
.align 2
.align 4
_coprocessor_error:
pushl $0
pushl $_do_coprocessor_error
jmp error_code
.align 2
.align 4
_device_not_available:
pushl $-1 # mark this as an int
SAVE_ALL
......@@ -227,70 +227,85 @@ _device_not_available:
addl $4,%esp
ret
.align 4
_debug:
pushl $0
pushl $_do_debug
jmp error_code
.align 4
_nmi:
pushl $0
pushl $_do_nmi
jmp error_code
.align 4
_int3:
pushl $0
pushl $_do_int3
jmp error_code
.align 4
_overflow:
pushl $0
pushl $_do_overflow
jmp error_code
.align 4
_bounds:
pushl $0
pushl $_do_bounds
jmp error_code
.align 4
_invalid_op:
pushl $0
pushl $_do_invalid_op
jmp error_code
.align 4
_coprocessor_segment_overrun:
pushl $0
pushl $_do_coprocessor_segment_overrun
jmp error_code
.align 4
_reserved:
pushl $0
pushl $_do_reserved
jmp error_code
.align 4
_double_fault:
pushl $_do_double_fault
jmp error_code
.align 4
_invalid_TSS:
pushl $_do_invalid_TSS
jmp error_code
.align 4
_segment_not_present:
pushl $_do_segment_not_present
jmp error_code
.align 4
_stack_segment:
pushl $_do_stack_segment
jmp error_code
.align 4
_general_protection:
pushl $_do_general_protection
jmp error_code
.align 4
_alignment_check:
pushl $_do_alignment_check
jmp error_code
.align 4
_page_fault:
pushl $_do_page_fault
jmp error_code
......@@ -41,7 +41,7 @@ current->start_code + current->end_code)
unsigned long low_memory = 0;
unsigned long high_memory = 0;
unsigned long paging_pages = 0;
unsigned long free_page_list = 0;
#define copy_page(from,to) \
__asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si")
......@@ -71,14 +71,16 @@ void free_page(unsigned long addr)
if (addr < low_memory)
return;
if (addr < high_memory) {
i = addr - low_memory;
i >>= 12;
if (mem_map[i] == 1)
++nr_free_pages;
if (mem_map[i]--)
i = addr - low_memory;
i >>= 12;
if (addr < high_memory && mem_map[i]) {
if (--mem_map[i])
return;
mem_map[i] = 0;
addr &= 0xfffff000;
*(unsigned long *) addr = free_page_list;
free_page_list = addr;
++nr_free_pages;
return;
}
printk("trying to free free page (%08x): memory probably corrupted\n",addr);
}
......@@ -170,7 +172,7 @@ int copy_page_tables(unsigned long from,unsigned long to,long size)
from_page_table = (unsigned long *) (0xfffff000 & *from_dir);
if (!(to_page_table = (unsigned long *) get_free_page(GFP_KERNEL)))
return -1; /* Out of memory, see freeing */
*to_dir = ((unsigned long) to_page_table) | 7;
*to_dir = ((unsigned long) to_page_table) | PAGE_ACCESSED | 7;
nr = (from==0)?0xA0:1024;
for ( ; nr-- > 0 ; from_page_table++,to_page_table++) {
repeat:
......@@ -187,7 +189,7 @@ int copy_page_tables(unsigned long from,unsigned long to,long size)
goto repeat;
}
*to_page_table = this_page;
*from_page_table = new_page | (PAGE_DIRTY | 7);
*from_page_table = new_page | (PAGE_DIRTY | PAGE_ACCESSED | 7);
continue;
}
this_page &= ~2;
......@@ -294,7 +296,7 @@ int remap_page_range(unsigned long from, unsigned long to, unsigned long size,
invalidate();
return -1;
}
*dir++ = ((unsigned long) page_table) | 7;
*dir++ = ((unsigned long) page_table) | PAGE_ACCESSED | 7;
}
else
page_table = (unsigned long *)(0xfffff000 & *dir++);
......@@ -384,7 +386,7 @@ static unsigned long put_page(unsigned long page,unsigned long address)
oom(current);
tmp = BAD_PAGETABLE;
}
*page_table = tmp | 7;
*page_table = tmp | PAGE_ACCESSED | 7;
return 0;
}
page_table += (address>>12) & 0x3ff;
......@@ -393,7 +395,7 @@ static unsigned long put_page(unsigned long page,unsigned long address)
*page_table = 0;
invalidate();
}
*page_table = page | 7;
*page_table = page | PAGE_ACCESSED | 7;
/* no need for invalidate */
return page;
}
......@@ -429,7 +431,7 @@ unsigned long put_dirty_page(unsigned long page, unsigned long address)
*page_table = 0;
invalidate();
}
*page_table = page | (PAGE_DIRTY | 7);
*page_table = page | (PAGE_DIRTY | PAGE_ACCESSED | 7);
/* no need for invalidate */
return page;
}
......@@ -472,7 +474,7 @@ static void un_wp_page(unsigned long * table_entry, struct task_struct * task)
new_page = BAD_PAGE;
send_sig(SIGSEGV,task,1);
}
*table_entry = new_page | dirty | 7;
*table_entry = new_page | dirty | PAGE_ACCESSED | 7;
free_page(old_page);
invalidate();
}
......@@ -580,7 +582,7 @@ static int try_to_share(unsigned long address, struct task_struct * p)
to = get_free_page(GFP_KERNEL);
if (!to)
return 0;
*(unsigned long *) to_page = to | 7;
*(unsigned long *) to_page = to | PAGE_ACCESSED | 7;
}
to &= 0xfffff000;
to_page = to + ((address>>10) & 0xffc);
......@@ -650,7 +652,7 @@ static unsigned long get_empty_pgtable(unsigned long * p)
*p = 0;
}
if (page) {
*p = page | 7;
*p = page | PAGE_ACCESSED | 7;
return *p;
}
if (page = get_free_page(GFP_KERNEL))
......@@ -764,7 +766,8 @@ void show_mem(void)
printk("Free pages: %6d\n",nr_free_pages);
printk("Buffer heads: %6d\n",nr_buffer_heads);
printk("Buffer blocks: %6d\n",nr_buffers);
for (i = 0 ; i < paging_pages ; i++) {
i = (high_memory - low_memory) >> 12;
while (i-- > 0) {
total++;
if (!mem_map[i])
free++;
......@@ -830,18 +833,26 @@ void do_page_fault(unsigned long *esp, unsigned long error_code)
unsigned long mem_init(unsigned long start_mem, unsigned long end_mem)
{
unsigned long tmp;
end_mem &= 0xfffff000;
high_memory = end_mem;
mem_map = (char *) start_mem;
paging_pages = (end_mem - start_mem) >> 12;
start_mem += paging_pages;
tmp = (end_mem - start_mem) >> 12;
start_mem += tmp;
start_mem += 0xfff;
start_mem &= 0xfffff000;
low_memory = start_mem;
paging_pages = (high_memory - low_memory) >> 12;
tmp = (high_memory - low_memory) >> 12;
swap_device = 0;
swap_file = NULL;
memset(mem_map,0,paging_pages);
nr_free_pages = paging_pages;
memset(mem_map,0,tmp);
nr_free_pages = tmp;
free_page_list = low_memory;
*(unsigned long *) free_page_list = 0;
while ((tmp = free_page_list + 4096) < high_memory) {
*(unsigned long *) tmp = free_page_list;
free_page_list = tmp;
}
return start_mem;
}
......@@ -20,6 +20,8 @@
static int lowest_bit = 0;
static int highest_bit = 0;
extern unsigned long free_page_list;
/*
* The following are used to make sure we don't thrash too much...
*/
......@@ -150,6 +152,9 @@ int try_to_swap_out(unsigned long * table_ptr)
page = *table_ptr;
if (!(PAGE_PRESENT & page))
return 0;
*table_ptr &= ~PAGE_ACCESSED;
if (PAGE_ACCESSED & page)
return 0;
if (page < low_memory || page >= high_memory)
return 0;
for (i = 0; i < NR_LAST_FREE_PAGES; i++)
......@@ -182,6 +187,40 @@ int try_to_swap_out(unsigned long * table_ptr)
#define LAST_VM_PAGE (1024*1024)
#define VM_PAGES (LAST_VM_PAGE - FIRST_VM_PAGE)
static unsigned int dir_entry = 1024;
static unsigned int page_entry = 0;
/*
* sys_idle() does nothing much: it just searches for likely candidates for
* swapping out or forgetting about. This speeds up the search when we
* actually have to swap.
*/
int sys_idle(void)
{
struct task_struct * p;
unsigned long page;
need_resched = 1;
if (dir_entry >= 1024)
dir_entry = FIRST_VM_PAGE>>10;
p = task[dir_entry >> 4];
page = pg_dir[dir_entry];
if (!(page & 1) || !p || !p->swappable) {
dir_entry++;
return 0;
}
page &= 0xfffff000;
if (page_entry >= 1024) {
page_entry = 0;
dir_entry++;
return 0;
}
page = *(page_entry + (unsigned long *) page);
if ((page < low_memory) || !(page & PAGE_PRESENT) || (page & PAGE_ACCESSED))
page_entry++;
return 0;
}
/*
* Go through the page tables, searching for a user page that
* we can swap out.
......@@ -190,11 +229,9 @@ int try_to_swap_out(unsigned long * table_ptr)
* is un-swappable), allowing high-priority processes which cannot be
* swapped out (things like user-level device drivers (Not implemented)).
*/
int swap_out(void)
int swap_out(unsigned int priority)
{
static int dir_entry = 1024;
static int page_entry = -1;
int counter = VM_PAGES;
int counter = VM_PAGES / 2;
int pg_table;
struct task_struct * p;
......@@ -203,7 +240,7 @@ int swap_out(void)
goto no_swap;
if (dir_entry >= 1024)
dir_entry = FIRST_VM_PAGE>>10;
if (!(p = task[dir_entry >> 4])) {
if (!(p = task[dir_entry >> 4]) || !p->swappable) {
counter -= 1024;
dir_entry++;
goto check_dir;
......@@ -222,24 +259,41 @@ int swap_out(void)
check_table:
if (counter < 0)
goto no_swap;
counter--;
page_entry++;
if (page_entry >= 1024) {
page_entry = -1;
page_entry = 0;
dir_entry++;
goto check_dir;
}
if (p->swappable && try_to_swap_out(page_entry + (unsigned long *) pg_table)) {
if (try_to_swap_out(page_entry + (unsigned long *) pg_table)) {
p->rss--;
dir_entry++;
return 1;
}
page_entry++;
counter--;
goto check_table;
no_swap:
printk("Out of swap-memory\n\r");
return 0;
}
static int try_to_free_page(void)
{
if (shrink_buffers(0))
return 1;
if (swap_out(0))
return 1;
if (shrink_buffers(1))
return 1;
if (swap_out(1))
return 1;
if (shrink_buffers(2))
return 1;
if (swap_out(2))
return 1;
if (shrink_buffers(3))
return 1;
return swap_out(3);
}
/*
* Get physical address of first (actually last :-) free page, and mark it
* used. If no free pages left, return 0.
......@@ -250,29 +304,24 @@ unsigned long get_free_page(int priority)
static unsigned long index = 0;
repeat:
__asm__("std ; repne ; scasb\n\t"
"jne 1f\n\t"
"movb $1,1(%%edi)\n\t"
"sall $12,%%ecx\n\t"
"addl %2,%%ecx\n\t"
"movl %%ecx,%%edx\n\t"
"movl $1024,%%ecx\n\t"
"leal 4092(%%edx),%%edi\n\t"
"rep ; stosl\n\t"
"movl %%edx,%%eax\n"
"1:\tcld"
:"=a" (result)
:"0" (0),"b" (low_memory),"c" (paging_pages),
"D" (mem_map+paging_pages-1)
:"di","cx","dx");
if (result >= high_memory)
goto repeat;
if ((result && result < low_memory) || (result & 0xfff)) {
printk("weird result: %08x\n",result);
result = 0;
}
result = free_page_list;
if (result) {
--nr_free_pages;
if ((result & 0xfff) || result < low_memory || result >= high_memory) {
free_page_list = 0;
printk("Result = %08x - memory map destroyed\n");
panic("mm error");
}
free_page_list = *(unsigned long *) result;
nr_free_pages--;
if (mem_map[MAP_NR(result)]) {
printk("Free page %08x has mem_map = %d\n",
result,mem_map[MAP_NR(result)]);
goto repeat;
}
mem_map[MAP_NR(result)] = 1;
__asm__ __volatile__("cld ; rep ; stosl"
::"a" (0),"c" (1024),"D" (result)
:"di","cx");
if (index >= NR_LAST_FREE_PAGES)
index = 0;
last_free_pages[index] = result;
......@@ -286,11 +335,7 @@ unsigned long get_free_page(int priority)
}
if (priority <= GFP_BUFFER)
return 0;
if (shrink_buffers()) {
schedule();
goto repeat;
}
if (swap_out()) {
if (try_to_free_page()) {
schedule();
goto repeat;
}
......
......@@ -7,17 +7,27 @@
#
# Note 2! The CFLAGS definition is now in the main makefile...
# only these two lines should need to be changed to remove inet sockets.
# (and the tcp/tcpip.o in net.o)
SUBDIRS =# tcp
SOCK_FLAGS =# -DINET_SOCKETS
.c.o:
$(CC) $(CFLAGS) -c $<
$(CC) $(CFLAGS) $(SOCK_FLAGS) -c $<
.s.o:
$(AS) -o $*.o $<
.c.s:
$(CC) $(CFLAGS) -S $<
OBJS = socket.o unix.o
OBJS = socket.o unix.o
net.o: $(OBJS) subdirs
$(LD) -r -o net.o $(OBJS) #tcp/tcpip.o
net.o: $(OBJS)
$(LD) -r -o net.o $(OBJS)
subdirs: dummy
for i in $(SUBDIRS); do (cd $$i; echo $$i; $(MAKE)) || exit; done
clean:
rm -f core *.o *.a tmp_make
......@@ -27,6 +37,9 @@ dep:
sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
for i in *.c;do $(CPP) -M $$i;done >> tmp_make
cp tmp_make Makefile
@for i in $(SUBDIRS); do (cd $$i; echo $$i; $(MAKE) dep || exit; done
dummy:
### Dependencies:
socket.o : socket.c /usr/src/linux/include/linux/signal.h /usr/src/linux/include/linux/errno.h \
......
#ifndef _KERN_SOCK_H
#define _KERN_SOCK_H
#undef SOCK_DEBUG
#define NSOCKETS 128 /* should be dynamic, later... */
typedef enum {
......@@ -29,7 +29,7 @@ struct socket {
socket_state state;
long flags;
struct proto_ops *ops; /* protocols do most everything */
char *data; /* protocol data */
void *data; /* protocol data */
struct socket *conn; /* server socket connected to */
struct socket *iconn; /* incomplete client connections */
struct socket *next;
......@@ -45,15 +45,31 @@ struct proto_ops {
int (*bind)(struct socket *sock, struct sockaddr *umyaddr,
int sockaddr_len);
int (*connect)(struct socket *sock, struct sockaddr *uservaddr,
int sockaddr_len);
int sockaddr_len, int flags);
int (*socketpair)(struct socket *sock1, struct socket *sock2);
int (*accept)(struct socket *sock, struct socket *newsock);
int (*accept)(struct socket *sock, struct socket *newsock, int flags);
int (*getname)(struct socket *sock, struct sockaddr *uaddr,
int *usockaddr_len, int peer);
int (*read)(struct socket *sock, char *ubuf, int size, int nonblock);
int (*write)(struct socket *sock, char *ubuf, int size, int nonblock);
int (*select)(struct socket *sock, int sel_type, select_table * wait);
int (*ioctl)(struct socket *sock, unsigned int cmd, unsigned long arg);
int (*listen)(struct socket *sock, int len);
int (*send)(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags);
int (*recv)(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags);
int (*sendto)(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags, struct sockaddr *, int addr_len);
int (*recvfrom)(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags, struct sockaddr *, int *addr_len);
int (*shutdown)(struct socket *sock, int flags);
int (*setsockopt)(struct socket *sock, int level, int optname,
char *optval, int optlen);
int (*getsockopt)(struct socket *sock, int level, int optname,
char *optval, int *optlen);
int (*fcntl) (struct socket *sock, unsigned int cmd,
unsigned long arg);
};
extern int sock_awaitconn(struct socket *mysock, struct socket *servsock);
......
This diff is collapsed.
......@@ -9,5 +9,12 @@
#define SYS_GETSOCKNAME 6
#define SYS_GETPEERNAME 7
#define SYS_SOCKETPAIR 8
#define SYS_SEND 9
#define SYS_RECV 10
#define SYS_SENDTO 11
#define SYS_RECVFROM 12
#define SYS_SHUTDOWN 13
#define SYS_SETSOCKOPT 14
#define SYS_GETSOCKOPT 15
#endif _SOCKETCALL_
......@@ -46,9 +46,10 @@ static int unix_proto_release(struct socket *sock, struct socket *peer);
static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
int sockaddr_len);
static int unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
int sockaddr_len);
int sockaddr_len, int flags);
static int unix_proto_socketpair(struct socket *sock1, struct socket *sock2);
static int unix_proto_accept(struct socket *sock, struct socket *newsock);
static int unix_proto_accept(struct socket *sock, struct socket *newsock,
int flags);
static int unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,
int *usockaddr_len, int peer);
static int unix_proto_read(struct socket *sock, char *ubuf, int size,
......@@ -58,6 +59,24 @@ static int unix_proto_write(struct socket *sock, char *ubuf, int size,
static int unix_proto_select(struct socket *sock, int sel_type, select_table * wait);
static int unix_proto_ioctl(struct socket *sock, unsigned int cmd,
unsigned long arg);
static int unix_proto_listen(struct socket *sock, int backlog);
static int unix_proto_send (struct socket *sock, void *buff, int len,
int nonblock, unsigned flags);
static int unix_proto_recv (struct socket *sock, void *buff, int len,
int nonblock, unsigned flags);
static int unix_proto_sendto (struct socket *sock, void *buff, int len,
int nonblock, unsigned flags,
struct sockaddr *addr, int addr_len);
static int unix_proto_recvfrom (struct socket *sock, void *buff, int len,
int nonblock, unsigned flags,
struct sockaddr *addr, int *addr_len);
static int unix_proto_shutdown (struct socket *sock, int how);
static int unix_proto_setsockopt (struct socket *sock, int level, int optname,
char *optval, int optlen);
static int unix_proto_getsockopt (struct socket *sock, int level, int optname,
char *optval, int *optlen);
struct proto_ops unix_proto_ops = {
unix_proto_init,
......@@ -72,7 +91,16 @@ struct proto_ops unix_proto_ops = {
unix_proto_read,
unix_proto_write,
unix_proto_select,
unix_proto_ioctl
unix_proto_ioctl,
unix_proto_listen,
unix_proto_send,
unix_proto_recv,
unix_proto_sendto,
unix_proto_recvfrom,
unix_proto_shutdown,
unix_proto_setsockopt,
unix_proto_getsockopt,
NULL /* unix_proto_fcntl. */
};
#ifdef SOCK_DEBUG
......@@ -94,6 +122,68 @@ sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len)
}
}
#endif
/* don't have to do anything. */
static int
unix_proto_listen (struct socket *sock, int backlog)
{
return (0);
}
static int
unix_proto_setsockopt(struct socket *sock, int level, int optname,
char *optval, int optlen)
{
return (-EOPNOTSUPP);
}
static int
unix_proto_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen)
{
return (-EOPNOTSUPP);
}
static int
unix_proto_sendto(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags, struct sockaddr *addr, int addr_len)
{
return (-EOPNOTSUPP);
}
static int
unix_proto_recvfrom(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags, struct sockaddr *addr, int *addr_len)
{
return (-EOPNOTSUPP);
}
static int
unix_proto_shutdown (struct socket *sock, int how)
{
return (-EOPNOTSUPP);
}
static int
unix_proto_send(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags)
{
/* this error needs to be checked. */
if (flags != 0)
return (-EINVAL);
return (unix_proto_write (sock, buff, len, nonblock));
}
static int
unix_proto_recv(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags)
{
/* this error needs to be checked. */
if (flags != 0)
return (-EINVAL);
return (unix_proto_read (sock, buff, len, nonblock));
}
static struct unix_proto_data *
unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len)
......@@ -282,7 +372,7 @@ unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
*/
static int
unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
int sockaddr_len)
int sockaddr_len, int flags)
{
int i;
struct unix_proto_data *serv_upd;
......@@ -337,11 +427,39 @@ unix_proto_socketpair(struct socket *sock1, struct socket *sock2)
* on accept, we ref the peer's data for safe writes
*/
static int
unix_proto_accept(struct socket *sock, struct socket *newsock)
unix_proto_accept(struct socket *sock, struct socket *newsock, int flags)
{
struct socket *clientsock;
PRINTK("unix_proto_accept: socket 0x%x accepted via socket 0x%x\n",
sock, newsock);
unix_data_ref(UN_DATA(newsock->conn));
/*
* if there aren't any sockets awaiting connection, then wait for
* one, unless nonblocking
*/
while (!(clientsock = sock->iconn)) {
if (flags & O_NONBLOCK)
return -EAGAIN;
interruptible_sleep_on(sock->wait);
if (current->signal & ~current->blocked) {
PRINTK("sys_accept: sleep was interrupted\n");
return -ERESTARTSYS;
}
}
/*
* great. finish the connection relative to server and client,
* wake up the client and return the new fd to the server
*/
sock->iconn = clientsock->next;
clientsock->next = NULL;
newsock->conn = clientsock;
clientsock->conn = newsock;
clientsock->state = SS_CONNECTED;
newsock->state = SS_CONNECTED;
wake_up(clientsock->wait);
unix_data_ref (UN_DATA(newsock->conn));
UN_DATA(newsock)->peerupd = UN_DATA(newsock->conn);
return 0;
}
......@@ -525,6 +643,23 @@ unix_proto_select(struct socket *sock, int sel_type, select_table * wait)
{
struct unix_proto_data *upd, *peerupd;
/*
* handle server sockets specially
*/
if (sock->flags & SO_ACCEPTCON) {
if (sel_type == SEL_IN) {
PRINTK("sock_select: %sconnections pending\n",
sock->iconn ? "" : "no ");
if (sock->iconn)
return 1;
select_wait(sock->wait, wait);
return sock->iconn ? 1 : 0;
}
PRINTK("sock_select: nothing else for server socket\n");
select_wait(sock->wait, wait);
return 0;
}
if (sel_type == SEL_IN) {
upd = UN_DATA(sock);
PRINTK("unix_proto_select: there is%s data available\n",
......@@ -565,7 +700,10 @@ unix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
peerupd = (sock->state == SS_CONNECTED) ? UN_DATA(sock->conn) : NULL;
switch (cmd) {
case TIOCINQ:
if (sock->flags & SO_ACCEPTCON)
return -EINVAL;
verify_area((void *)arg, sizeof(unsigned long));
if (UN_BUF_AVAIL(upd) || peerupd)
put_fs_long(UN_BUF_AVAIL(upd), (unsigned long *)arg);
......@@ -574,6 +712,8 @@ unix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
break;
case TIOCOUTQ:
if (sock->flags & SO_ACCEPTCON)
return -EINVAL;
verify_area((void *)arg, sizeof(unsigned long));
if (peerupd)
put_fs_long(UN_BUF_SPACE(peerupd),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment