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:
#
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
/*
* 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);
.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)
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);
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);
}
free blocks and the number of the next block in the list.
When an ext fs is mounted, the number of the first free block is stored
- in s->u.ext_sb.s_zmap[0] and the block header is stored in s->u.ext_sb.s_zmap[1]. u.ext_sb.s_zmap[2]
- contains the count of free blocks.
-
- Currently, it is a hack to allow this kind of management with the super_block
- structure.
- Perhaps, in the future, we may have to change the super_block structure to
- include dedicated fields.
+ in s->u.ext_sb.s_firstfreeblocknumber and the block header is stored in
+ s->u.ext_sb.s_firstfreeblock. u.ext_sb.s_freeblockscount contains the count
+ of free blocks.
The free inodes are also managed by a linked list in a similar way. The
super block contains the number of the first free inode. This inode contains
14 numbers of other free inodes and the number of the next inode in the list.
- The number of the first free inode is stored in s->u.ext_sb.s_imap[0] and the header
- of the block containing the inode is stored in s->u.ext_sb.s_imap[1]. u.ext_sb.s_imap[2] contains
- the count of free inodes.
+ The number of the first free inode is stored in
+ s->u.ext_sb.s_firstfreeinodenumber and the header of the block containing
+ the inode is stored in s->u.ext_sb.s_firstfreeinodeblock.
+ u.ext_sb.s_freeinodescount contains the count of free inodes.
*/
#include <linux/kernel.h>
#include <linux/string.h>
-#ifdef EXTFS_FREELIST
-
#define clear_block(addr) \
__asm__("cld\n\t" \
"rep\n\t" \
if (!(sb = get_super(dev)))
panic("trying to free block on nonexistent device");
lock_super (sb);
- if (block < sb->u.ext_sb.s_firstdatazone || block >= sb->u.ext_sb.s_nzones)
+ if (block < sb->u.ext_sb.s_firstdatazone
+ || block >= sb->u.ext_sb.s_nzones)
panic("trying to free block not in datazone");
bh = get_hash_table(dev, block, sb->s_blocksize);
if (bh) {
if (bh->b_count)
brelse(bh);
}
- if (sb->u.ext_sb.s_zmap[1])
- efb = (struct ext_free_block *) sb->u.ext_sb.s_zmap[1]->b_data;
- if (!sb->u.ext_sb.s_zmap[1] || efb->count == 254) {
+ if (sb->u.ext_sb.s_firstfreeblock)
+ efb = (struct ext_free_block *) sb->u.ext_sb.s_firstfreeblock->b_data;
+ if (!sb->u.ext_sb.s_firstfreeblock || efb->count == 254) {
#ifdef EXTFS_DEBUG
printk("ext_free_block: block full, skipping to %d\n", block);
#endif
- if (sb->u.ext_sb.s_zmap[1])
- brelse (sb->u.ext_sb.s_zmap[1]);
- if (!(sb->u.ext_sb.s_zmap[1] = bread (dev, block, sb->s_blocksize)))
+ if (sb->u.ext_sb.s_firstfreeblock)
+ brelse (sb->u.ext_sb.s_firstfreeblock);
+ if (!(sb->u.ext_sb.s_firstfreeblock = bread (dev,
+ block, sb->s_blocksize)))
panic ("ext_free_block: unable to read block to free\n");
- efb = (struct ext_free_block *) sb->u.ext_sb.s_zmap[1]->b_data;
- efb->next = (unsigned long) sb->u.ext_sb.s_zmap[0];
+ efb = (struct ext_free_block *) sb->u.ext_sb.s_firstfreeblock->b_data;
+ efb->next = sb->u.ext_sb.s_firstfreeblocknumber;
efb->count = 0;
- sb->u.ext_sb.s_zmap[0] = (struct buffer_head *) block;
+ sb->u.ext_sb.s_firstfreeblocknumber = block;
} else {
efb->free[efb->count++] = block;
}
- sb->u.ext_sb.s_zmap[2] = (struct buffer_head *) (((unsigned long) sb->u.ext_sb.s_zmap[2]) + 1);
+ sb->u.ext_sb.s_freeblockscount ++;
sb->s_dirt = 1;
- sb->u.ext_sb.s_zmap[1]->b_dirt = 1;
+ sb->u.ext_sb.s_firstfreeblock->b_dirt = 1;
free_super (sb);
return 1;
}
struct buffer_head * bh;
struct super_block * sb;
struct ext_free_block * efb;
- int /* i, */ j;
+ int j;
if (!(sb = get_super(dev)))
panic("trying to get new block from nonexistant device");
- if (!sb->u.ext_sb.s_zmap[1])
+ if (!sb->u.ext_sb.s_firstfreeblock)
return 0;
lock_super (sb);
- efb = (struct ext_free_block *) sb->u.ext_sb.s_zmap[1]->b_data;
+ efb = (struct ext_free_block *) sb->u.ext_sb.s_firstfreeblock->b_data;
if (efb->count) {
j = efb->free[--efb->count];
- sb->u.ext_sb.s_zmap[1]->b_dirt = 1;
+ sb->u.ext_sb.s_firstfreeblock->b_dirt = 1;
} else {
#ifdef EXTFS_DEBUG
printk("ext_new_block: block empty, skipping to %d\n", efb->next);
#endif
- j = (unsigned long) sb->u.ext_sb.s_zmap[0];
- sb->u.ext_sb.s_zmap[0] = (struct buffer_head *) efb->next;
- brelse (sb->u.ext_sb.s_zmap[1]);
- if (!sb->u.ext_sb.s_zmap[0]) {
- sb->u.ext_sb.s_zmap[1] = NULL;
+ j = sb->u.ext_sb.s_firstfreeblocknumber;
+ sb->u.ext_sb.s_firstfreeblocknumber = efb->next;
+ brelse (sb->u.ext_sb.s_firstfreeblock);
+ if (!sb->u.ext_sb.s_firstfreeblocknumber) {
+ sb->u.ext_sb.s_firstfreeblock = NULL;
} else {
- if (!(sb->u.ext_sb.s_zmap[1] = bread (dev, (unsigned long) sb->u.ext_sb.s_zmap[0], sb->s_blocksize)))
+ if (!(sb->u.ext_sb.s_firstfreeblock = bread (dev,
+ sb->u.ext_sb.s_firstfreeblocknumber,
+ sb->s_blocksize)))
panic ("ext_new_block: unable to read next free block\n");
}
}
printk ("ext_new_block: blk = %d\n", j);
panic ("allocating block not in data zone\n");
}
- sb->u.ext_sb.s_zmap[2] = (struct buffer_head *) (((unsigned long) sb->u.ext_sb.s_zmap[2]) - 1);
+ sb->u.ext_sb.s_freeblockscount --;
sb->s_dirt = 1;
if (!(bh=getblk(dev, j, sb->s_blocksize)))
unsigned long count, block;
lock_super (sb);
- if (!sb->u.ext_sb.s_zmap[1])
+ if (!sb->u.ext_sb.s_firstfreeblock)
count = 0;
else {
- efb = (struct ext_free_block *) sb->u.ext_sb.s_zmap[1]->b_data;
+ efb = (struct ext_free_block *) sb->u.ext_sb.s_firstfreeblock->b_data;
count = efb->count + 1;
block = efb->next;
while (block) {
}
}
printk("ext_count_free_blocks: stored = %d, computed = %d\n",
- (unsigned long) sb->u.ext_sb.s_zmap[2], count);
+ sb->u.ext_sb.s_freeblockscount, count);
free_super (sb);
return count;
#else
- return (unsigned long) sb->u.ext_sb.s_zmap[2];
+ return sb->u.ext_sb.s_freeblockscount;
#endif
}
free_super (inode->i_sb);
return;
}
- if (inode->i_sb->u.ext_sb.s_imap[1])
- efi = ((struct ext_free_inode *) inode->i_sb->u.ext_sb.s_imap[1]->b_data) +
- (((unsigned long) inode->i_sb->u.ext_sb.s_imap[0])-1)%EXT_INODES_PER_BLOCK;
- if (!inode->i_sb->u.ext_sb.s_imap[1] || efi->count == 14) {
+ if (inode->i_sb->u.ext_sb.s_firstfreeinodeblock)
+ efi = ((struct ext_free_inode *) inode->i_sb->u.ext_sb.s_firstfreeinodeblock->b_data) +
+ (inode->i_sb->u.ext_sb.s_firstfreeinodenumber-1)%EXT_INODES_PER_BLOCK;
+ if (!inode->i_sb->u.ext_sb.s_firstfreeinodeblock || efi->count == 14) {
#ifdef EXTFS_DEBUG
printk("ext_free_inode: inode full, skipping to %d\n", inode->i_ino);
#endif
- if (inode->i_sb->u.ext_sb.s_imap[1])
- brelse (inode->i_sb->u.ext_sb.s_imap[1]);
+ if (inode->i_sb->u.ext_sb.s_firstfreeinodeblock)
+ brelse (inode->i_sb->u.ext_sb.s_firstfreeinodeblock);
block = 2 + (inode->i_ino - 1) / EXT_INODES_PER_BLOCK;
if (!(bh = bread(inode->i_dev, block, inode->i_sb->s_blocksize)))
panic("ext_free_inode: unable to read inode block\n");
efi = ((struct ext_free_inode *) bh->b_data) +
(inode->i_ino - 1) % EXT_INODES_PER_BLOCK;
- efi->next = (unsigned long) inode->i_sb->u.ext_sb.s_imap[0];
+ efi->next = inode->i_sb->u.ext_sb.s_firstfreeinodenumber;
efi->count = 0;
- inode->i_sb->u.ext_sb.s_imap[0] = (struct buffer_head *) inode->i_ino;
- inode->i_sb->u.ext_sb.s_imap[1] = bh;
+ inode->i_sb->u.ext_sb.s_firstfreeinodenumber = inode->i_ino;
+ inode->i_sb->u.ext_sb.s_firstfreeinodeblock = bh;
} else {
efi->free[efi->count++] = inode->i_ino;
}
- inode->i_sb->u.ext_sb.s_imap[2] = (struct buffer_head *) (((unsigned long) inode->i_sb->u.ext_sb.s_imap[2]) + 1);
+ inode->i_sb->u.ext_sb.s_freeinodescount ++;
inode->i_sb->s_dirt = 1;
- inode->i_sb->u.ext_sb.s_imap[1]->b_dirt = 1;
+ inode->i_sb->u.ext_sb.s_firstfreeinodeblock->b_dirt = 1;
free_super (inode->i_sb);
memset(inode,0,sizeof(*inode));
}
struct inode * inode;
struct ext_free_inode * efi;
unsigned long block;
- int /* i, */ j;
+ int j;
if (!(inode=get_empty_inode()))
return NULL;
return NULL;
}
inode->i_flags = inode->i_sb->s_flags;
- if (!inode->i_sb->u.ext_sb.s_imap[1])
+ if (!inode->i_sb->u.ext_sb.s_firstfreeinodeblock)
return 0;
lock_super (inode->i_sb);
- efi = ((struct ext_free_inode *) inode->i_sb->u.ext_sb.s_imap[1]->b_data) +
- (((unsigned long) inode->i_sb->u.ext_sb.s_imap[0])-1)%EXT_INODES_PER_BLOCK;
+ efi = ((struct ext_free_inode *) inode->i_sb->u.ext_sb.s_firstfreeinodeblock->b_data) +
+ (inode->i_sb->u.ext_sb.s_firstfreeinodenumber-1)%EXT_INODES_PER_BLOCK;
if (efi->count) {
j = efi->free[--efi->count];
- inode->i_sb->u.ext_sb.s_imap[1]->b_dirt = 1;
+ inode->i_sb->u.ext_sb.s_firstfreeinodeblock->b_dirt = 1;
} else {
#ifdef EXTFS_DEBUG
printk("ext_free_inode: inode empty, skipping to %d\n", efi->next);
#endif
- j = (unsigned long) inode->i_sb->u.ext_sb.s_imap[0];
+ j = inode->i_sb->u.ext_sb.s_firstfreeinodenumber;
if (efi->next > inode->i_sb->u.ext_sb.s_ninodes) {
printk ("efi->next = %d\n", efi->next);
panic ("ext_new_inode: bad inode number in free list\n");
}
- inode->i_sb->u.ext_sb.s_imap[0] = (struct buffer_head *) efi->next;
+ inode->i_sb->u.ext_sb.s_firstfreeinodenumber = efi->next;
block = 2 + (((unsigned long) efi->next) - 1) / EXT_INODES_PER_BLOCK;
- brelse (inode->i_sb->u.ext_sb.s_imap[1]);
- if (!inode->i_sb->u.ext_sb.s_imap[0]) {
- inode->i_sb->u.ext_sb.s_imap[1] = NULL;
+ brelse (inode->i_sb->u.ext_sb.s_firstfreeinodeblock);
+ if (!inode->i_sb->u.ext_sb.s_firstfreeinodenumber) {
+ inode->i_sb->u.ext_sb.s_firstfreeinodeblock = NULL;
} else {
- if (!(inode->i_sb->u.ext_sb.s_imap[1] = bread (dev, block, inode->i_sb->s_blocksize)))
+ if (!(inode->i_sb->u.ext_sb.s_firstfreeinodeblock = bread (dev, block, inode->i_sb->s_blocksize)))
panic ("ext_new_inode: unable to read next free inode block\n");
}
}
- inode->i_sb->u.ext_sb.s_imap[2] = (struct buffer_head *) (((unsigned long) inode->i_sb->u.ext_sb.s_imap[2]) - 1);
+ inode->i_sb->u.ext_sb.s_freeinodescount --;
inode->i_sb->s_dirt = 1;
inode->i_count = 1;
inode->i_nlink = 1;
unsigned long count, block, ino;
lock_super (sb);
- if (!sb->u.ext_sb.s_imap[1])
+ if (!sb->u.ext_sb.s_firstfreeinodeblock)
count = 0;
else {
- efi = ((struct ext_free_inode *) sb->u.ext_sb.s_imap[1]->b_data) +
- ((((unsigned long) sb->u.ext_sb.s_imap[0])-1)%EXT_INODES_PER_BLOCK);
+ efi = ((struct ext_free_inode *) sb->u.ext_sb.s_firstfreeinodeblock->b_data) +
+ ((sb->u.ext_sb.s_firstfreeinodenumber-1)%EXT_INODES_PER_BLOCK);
count = efi->count + 1;
ino = efi->next;
while (ino) {
if (ino < 1 || ino > sb->u.ext_sb.s_ninodes) {
- printk ("u.ext_sb.s_imap[0] = %d, ino = %d\n",
- (int) sb->u.ext_sb.s_imap[0],ino);
+ printk ("u.ext_sb.s_firstfreeinodenumber = %d, ino = %d\n",
+ (int) sb->u.ext_sb.s_firstfreeinodenumber,ino);
panic ("ext_count_fre_inodes: bad inode number in free list\n");
}
block = 2 + ((ino - 1) / EXT_INODES_PER_BLOCK);
}
}
printk("ext_count_free_inodes: stored = %d, computed = %d\n",
- (unsigned long) sb->u.ext_sb.s_imap[2], count);
+ sb->u.ext_sb.s_freeinodescount, count);
free_super (sb);
return count;
#else
- return (unsigned long) sb->u.ext_sb.s_imap[2];
+ return sb->u.ext_sb.s_freeinodescount;
#endif
}
-
-#endif
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;
}
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))) {
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;
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;
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)
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);
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) +
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) +
/* "" 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"
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;
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)))
*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) {
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;
if (prev_dir)
*prev_dir = de;
de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
-/* i++; */
}
brelse(bh);
return NULL;
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) {
if (!block)
return NULL;
if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE))) {
-/* i += EXT_DIR_ENTRIES_PER_BLOCK; */
offset += BLOCK_SIZE;
continue;
}
/* 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;
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;
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;
*/
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);
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 ) {
#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.
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]);
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) {
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;
}
}
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) {
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])
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;
#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] = {
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;
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;
#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
#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 */
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
#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
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)
* 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
#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);
#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 */
};
*/
#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
#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;
unsigned long __unused5;
};
+#endif
+
#define S_IFMT 00170000
#define S_IFSOCK 0140000
#define S_IFLNK 0120000
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,
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);
* 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
#define HD_TIMER 16
#define FLOPPY_TIMER 17
#define SCSI_TIMER 18
+#define NET_TIMER 19
struct timer_struct {
unsigned long expires;
#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
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;
#ifndef _PTRDIFF_T
#define _PTRDIFF_T
-typedef long ptrdiff_t;
+typedef int ptrdiff_t;
#endif
#ifndef NULL
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;
#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 */
#define __NR_fstat 108
#define __NR_uname 109
#define __NR_iopl 110
+#define __NR_vhangup 111
+#define __NR_idle 112
extern int errno;
#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
* 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)
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);
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
* 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, ...)
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;
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
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
+#include <linux/config.h>
#include <asm/system.h>
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
#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>
* 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) {
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;
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));
tab_stop[3] =
tab_stop[4] = 0;
}
- break;
+ continue;
case 'm':
csi_m(currcons);
- break;
+ continue;
case 'r':
if (!par[0])
par[0]++;
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') {
video_erase_char =
(video_erase_char & 0xff00) | ' ';
}
- break;
+ continue;
case ESsetG0:
if (c == '0')
G0_charset = GRAF_TRANS;
if (charset == 0)
translate = G0_charset;
state = ESnormal;
- break;
+ continue;
case ESsetG1:
if (c == '0')
G1_charset = GRAF_TRANS;
if (charset == 1)
translate = G1_charset;
state = ESnormal;
- break;
+ continue;
default:
state = ESnormal;
}
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;
}
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;
}
}
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)
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)
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 &&
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:
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
};
}
-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},
INIT_C_CC},
-1,
0,
- 0,
+ 0, 0, 0, 0, 0,
0,
0,
{25,80,0,0},
INIT_C_CC},
-1,
0,
- 0,
+ 0, 0, 0, 0, 0,
0,
0,
{25,80,0,0},
INIT_C_CC},
-1,
0,
- 0,
+ 0, 0, 0, 0, 0,
0,
0,
{25,80,0,0},
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);
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);
((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;
}
}
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;
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);
}
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;
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)))
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);
}
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;
}
* 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
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
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
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
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
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
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
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
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
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")
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);
}
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:
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;
invalidate();
return -1;
}
- *dir++ = ((unsigned long) page_table) | 7;
+ *dir++ = ((unsigned long) page_table) | PAGE_ACCESSED | 7;
}
else
page_table = (unsigned long *)(0xfffff000 & *dir++);
oom(current);
tmp = BAD_PAGETABLE;
}
- *page_table = tmp | 7;
+ *page_table = tmp | PAGE_ACCESSED | 7;
return 0;
}
page_table += (address>>12) & 0x3ff;
*page_table = 0;
invalidate();
}
- *page_table = page | 7;
+ *page_table = page | PAGE_ACCESSED | 7;
/* no need for invalidate */
return page;
}
*page_table = 0;
invalidate();
}
- *page_table = page | (PAGE_DIRTY | 7);
+ *page_table = page | (PAGE_DIRTY | PAGE_ACCESSED | 7);
/* no need for invalidate */
return page;
}
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();
}
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);
*p = 0;
}
if (page) {
- *p = page | 7;
+ *p = page | PAGE_ACCESSED | 7;
return *p;
}
if (page = get_free_page(GFP_KERNEL))
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++;
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;
}
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...
*/
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++)
#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.
* 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;
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;
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.
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;
}
if (priority <= GFP_BUFFER)
return 0;
- if (shrink_buffers()) {
- schedule();
- goto repeat;
- }
- if (swap_out()) {
+ if (try_to_free_page()) {
schedule();
goto repeat;
}
#
# 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
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 {
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;
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);
+/* modified by Ross Biro to help support inet sockets. */
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/sched.h>
extern int sys_close(int fd);
extern struct proto_ops unix_proto_ops;
+#ifdef INET_SOCKETS
+extern struct proto_ops inet_proto_ops;
+#endif
static struct {
short family;
char *name;
struct proto_ops *ops;
} proto_table[] = {
- AF_UNIX, "AF_UNIX", &unix_proto_ops
+ {AF_UNIX, "AF_UNIX", &unix_proto_ops},
+#ifdef INET_SOCKETS
+ {AF_INET, "AF_INET", &inet_proto_ops},
+#endif
};
#define NPROTO (sizeof(proto_table) / sizeof(proto_table[0]))
printk("sock_ioctl: can't find socket for inode!\n");
return -EBADF;
}
- switch (cmd) {
- case TIOCINQ:
- case TIOCOUTQ:
- if (sock->flags & SO_ACCEPTCON)
- return -EINVAL;
- break;
-
- default:
- return -EINVAL;
- }
return sock->ops->ioctl(sock, cmd, arg);
}
printk("sock_select: can't find socket for inode!\n");
return 0;
}
-
- /*
- * 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(&inode->i_wait, wait);
- return sock->iconn ? 1 : 0;
- }
- PRINTK("sock_select: nothing else for server socket\n");
- select_wait(&inode->i_wait, wait);
- return 0;
- }
/*
* we can't return errors to select, so its either yes or no.
*/
PRINTK("sys_listen: socket already accepting connections!\n");
return -EINVAL;
}
+ if (sock->ops && sock->ops->listen)
+ sock->ops->listen (sock, backlog);
sock->flags |= SO_ACCEPTCON;
return 0;
}
sock_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen)
{
struct file *file;
- struct socket *sock, *clientsock, *newsock;
+ struct socket *sock, *newsock;
int i;
PRINTK("sys_accept: fd = %d\n", fd);
return -EINVAL;
}
- /*
- * if there aren't any sockets awaiting connection, then wait for
- * one, unless nonblocking
- */
- while (!(clientsock = sock->iconn)) {
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
- interruptible_sleep_on(sock->wait);
- if (current->signal & ~current->blocked) {
- PRINTK("sys_accept: sleep was interrupted\n");
- return -ERESTARTSYS;
- }
- }
-
if (!(newsock = sock_alloc(0))) {
printk("sys_accept: no more sockets\n");
return -EINVAL;
sock_release(newsock);
return -EINVAL;
}
+ i = newsock->ops->accept(sock, newsock, file->f_flags);
+
+ if ( i < 0)
+ {
+ sock_release (newsock);
+ return (i);
+ }
+
+ PRINTK("sys_accept: connected socket 0x%x via 0x%x\n",
+ sock, newsock);
- /*
- * 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;
- newsock->ops->accept(sock, newsock);
- PRINTK("sys_accept: connected socket 0x%x via 0x%x to 0x%x\n",
- sock, newsock, clientsock);
if (upeer_sockaddr)
newsock->ops->getname(newsock, upeer_sockaddr,
upeer_addrlen, 1);
- wake_up(clientsock->wait);
return fd;
}
sock_connect(int fd, struct sockaddr *uservaddr, int addrlen)
{
struct socket *sock;
+ struct file *file;
int i;
PRINTK("sys_connect: fd = %d\n", fd);
- if (!(sock = sockfd_lookup(fd, NULL)))
+ if (!(sock = sockfd_lookup(fd, &file)))
return -EBADF;
if (sock->state != SS_UNCONNECTED) {
PRINTK("sys_connect: socket not unconnected\n");
return -EINVAL;
}
- if ((i = sock->ops->connect(sock, uservaddr, addrlen)) < 0) {
+ i = sock->ops->connect(sock, uservaddr, addrlen, file->f_flags);
+ if (i < 0) {
PRINTK("sys_connect: connect failed\n");
return i;
}
return sock->ops->getname(sock, usockaddr, usockaddr_len, 1);
}
+
+/* send - shutdown added by bir7@leland.stanford.edu */
+
+static int
+sys_send( int fd, void * buff, int len, unsigned flags)
+{
+ struct socket *sock;
+ struct file *file;
+
+ PRINTK("sys_send (fd = %d, buff = %X, len = %d, flags = %X)\n",
+ fd, buff, len, flags);
+
+ if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
+ return (-EBADF);
+
+ if (!(sock = sockfd_lookup(fd, NULL)))
+ return (-ENOTSOCK);
+
+ return (sock->ops->send (sock, buff, len, (file->f_flags & O_NONBLOCK),
+ flags));
+
+}
+
+static int
+sys_sendto( int fd, void * buff, int len, unsigned flags,
+ struct sockaddr *addr, int addr_len)
+{
+ struct socket *sock;
+ struct file *file;
+
+ PRINTK("sys_sendto (fd = %d, buff = %X, len = %d, flags = %X,"
+ " addr=%X, alen = %d\n", fd, buff, len, flags, addr, addr_len);
+
+ if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
+ return (-EBADF);
+
+ if (!(sock = sockfd_lookup(fd, NULL)))
+ return (-ENOTSOCK);
+
+ return (sock->ops->sendto (sock, buff, len,
+ (file->f_flags & O_NONBLOCK),
+ flags, addr, addr_len));
+
+}
+
+
+static int
+sys_recv( int fd, void * buff, int len, unsigned flags)
+{
+ struct socket *sock;
+ struct file *file;
+
+ PRINTK("sys_recv (fd = %d, buff = %X, len = %d, flags = %X)\n",
+ fd, buff, len, flags);
+
+ if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
+ return (-EBADF);
+
+ if (!(sock = sockfd_lookup(fd, NULL)))
+ return (-ENOTSOCK);
+
+ return (sock->ops->recv (sock, buff, len,(file->f_flags & O_NONBLOCK),
+ flags));
+
+}
+
+static int
+sys_recvfrom( int fd, void * buff, int len, unsigned flags,
+ struct sockaddr *addr, int *addr_len)
+{
+ struct socket *sock;
+ struct file *file;
+
+ PRINTK("sys_recvfrom (fd = %d, buff = %X, len = %d, flags = %X,"
+ " addr=%X, alen=%X\n", fd, buff, len, flags, addr, addr_len);
+
+ if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
+ return (-EBADF);
+
+ if (!(sock = sockfd_lookup(fd, NULL)))
+ return (-ENOTSOCK);
+
+ return (sock->ops->recvfrom (sock, buff, len,
+ (file->f_flags & O_NONBLOCK),
+ flags, addr, addr_len));
+
+}
+
+
+static int
+sys_setsockopt (int fd, int level, int optname, char *optval, int optlen)
+{
+ struct socket *sock;
+ struct file *file;
+
+ PRINTK ("sys_setsockopt(fd=%d, level=%d, optname=%d,\n",fd, level,
+ optname);
+ PRINTK (" optval = %X, optlen = %d)\n", optval, optlen);
+
+ if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
+ return (-EBADF);
+
+ if (!(sock = sockfd_lookup(fd, NULL)))
+ return (-ENOTSOCK);
+
+ return (sock->ops->setsockopt (sock, level, optname, optval, optlen));
+
+}
+
+static int
+sys_getsockopt (int fd, int level, int optname, char *optval, int *optlen)
+{
+ struct socket *sock;
+ struct file *file;
+ PRINTK ("sys_getsockopt(fd=%d, level=%d, optname=%d,\n",fd, level,
+ optname);
+ PRINTK (" optval = %X, optlen = %X)\n", optval, optlen);
+
+ if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL))
+ return (-EBADF);
+
+ if (!(sock = sockfd_lookup(fd, NULL)))
+ return (-ENOTSOCK);
+
+ return (0);
+ return (sock->ops->getsockopt (sock, level, optname, optval, optlen));
+
+}
+
+
+static int
+sys_shutdown( int fd, int how)
+{
+ struct socket *sock;
+ struct file *file;
+
+ PRINTK("sys_shutdown (fd = %d, how = %d)\n",fd, how);
+
+ file = current->filp[fd];
+ if (fd < 0 || fd >= NR_OPEN || file == NULL)
+ return (-EBADF);
+
+ if (!(sock = sockfd_lookup(fd, NULL)))
+ return (-ENOTSOCK);
+
+ return (sock->ops->shutdown (sock, how));
+
+}
+
+int
+sock_fcntl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ struct socket *sock;
+ sock = socki_lookup (filp->f_inode);
+
+ if (sock != NULL && sock->ops != NULL && sock->ops->fcntl != NULL)
+ return (sock->ops->fcntl (sock, cmd, arg));
+
+ return (-EINVAL);
+}
+
+
/*
* system call vectors. since i want to rewrite sockets as streams, we have
* this level of indirection. not a lot of overhead, since more of the work is
get_fs_long(args+2),
(int *)get_fs_long(args+3));
+ case SYS_SEND:
+ verify_area(args, 4 * sizeof (unsigned long));
+ return ( sys_send (get_fs_long(args+0),
+ (void *)get_fs_long(args+1),
+ get_fs_long(args+2),
+ get_fs_long(args+3)));
+
+ case SYS_SENDTO:
+ verify_area(args, 6 * sizeof (unsigned long));
+ return ( sys_sendto (get_fs_long(args+0),
+ (void *)get_fs_long(args+1),
+ get_fs_long(args+2),
+ get_fs_long(args+3),
+ (struct sockaddr *)get_fs_long(args+4),
+ get_fs_long(args+5)));
+
+
+ case SYS_RECV:
+ verify_area(args, 4 * sizeof (unsigned long));
+ return ( sys_recv (get_fs_long(args+0),
+ (void *)get_fs_long(args+1),
+ get_fs_long(args+2),
+ get_fs_long(args+3)));
+
+ case SYS_RECVFROM:
+ verify_area(args, 6 * sizeof (unsigned long));
+ return ( sys_recvfrom (get_fs_long(args+0),
+ (void *)get_fs_long(args+1),
+ get_fs_long(args+2),
+ get_fs_long(args+3),
+ (struct sockaddr *)get_fs_long(args+4),
+ (int *)get_fs_long(args+5)));
+
+ case SYS_SHUTDOWN:
+ verify_area (args, 2* sizeof (unsigned long));
+ return ( sys_shutdown (get_fs_long (args+0),
+ get_fs_long (args+1)));
+
+ case SYS_SETSOCKOPT:
+ verify_area (args, 5*sizeof (unsigned long));
+ return (sys_setsockopt (get_fs_long (args+0),
+ get_fs_long (args+1),
+ get_fs_long (args+2),
+ (char *)get_fs_long (args+3),
+ get_fs_long (args+4)));
+
+
+ case SYS_GETSOCKOPT:
+ verify_area (args, 5*sizeof (unsigned long));
+ return (sys_getsockopt (get_fs_long (args+0),
+ get_fs_long (args+1),
+ get_fs_long (args+2),
+ (char *)get_fs_long (args+3),
+ (int *)get_fs_long (args+4)));
+
default:
return -EINVAL;
}
#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_
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,
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,
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
}
}
#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)
*/
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;
* 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;
}
{
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",
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);
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),