Commit fdb2f0a5 authored by Linus Torvalds's avatar Linus Torvalds

[PATCH] Linux-0.97.3 (September 5, 1992)

Hey, we switched to the GPL several months ago, but only now do we
include the license text itself.  Apparently everybody expected
everybody else to just know what the GPL was..

Add a README on compiling the kernel (by Lasu)

Add PS/2 mouse driver, make generic "mouse" infrastructure.

Add /proc filesystem, clean up minixfs block mapping.

sys_wait4() and swapoff().

VM gets a "secondary page free" list for things like interrupts
that want a page _now_ and can't wait for the regular free list
to fill up.

[Original announcement below]

Patch3 is almost 100kB even compressed, as there were quite big changes
in the mm and minix fs.  No major new features: there are two new system
calls: swapoff(const char * swapfile) and wait4(), and linux accepts
several swap-files, but the rest of the thing is mostly bug-fixes or
simply rewrites.

Major changes:
 - new swap-page handling: linux no longer uses just one bit to keep
   track of used swap-space, but a counter for each swap-page.  This
   allows processes to share swap-pages after a fork(), and should
   result in /major/ performance increases on machines with less memory.
   I've seen better performance even with 8MB - I wouldn't be surprised
   if 4MB machines would re-compile the kernel noticeably faster under
   pl3.  I'd be interested to hear numbers.
 - The low 1MB memory that isn't used directly by the kernel is now
   swappable memory, instead of being hardcoded for buffer cache.  The
   patches for this were originally by tytso, and I expanded on it a bit
   more.  This might also help better performance on 2-4MB machines.
   Note that this does /not/ mean that you can use 1M machines for
   linux: linux still needs some extended memory.
 - the dosfs has been upgraded to dosfs.8 - patches by almesber.
 - I edited the minix fs pretty heavily to remove a couple of race-
   conditions.  The same races still exist in the extended fs, as I
   didn't have time to edit that yet.  The minix-fs took precedence as I
   know that better, and extfs isn't "official" yet anyway.

other changes:

 - the mouse-driver now handles both Logitech (minor = 0) and PS/2
   (minor = 1) busmice.
 - there is a proc-fs for access to user memory/files etc.
 - better support for the tcp/ip patches (but see below...)
 - corrected symlink and /dev/[k]mem behaviour
 - Lars Wirzenius' README (with minimal comments by me) and the GNU
   COPYING notice are now part of the normal kernel setup, and can be
   found in the tar-archive.
 - the floppy ioctl() to get the FD parameters no longer requires root
   priviledges.  Thus, the msdos emulator runs even for a normal user.

Some comments on patchlevel 3:

        mm:

The swap-page handling resulted in a reduction of swap-file (or
partition) size to a maximum of 16MB per file.  It's nothing inherent to
the code, but it eased some algorithms, so I didn't bother coding around
it.  After all, 16MB is enough for most people, and if you want more,
you can have up to 128 swapfiles of 16MB each.  If I get enough
hate-mail about it, I might just try to find the energy to correct it.
Maybe.

Bigger swapfiles will still work, but linux will take advantage of only
the low 16MB.  Also, there is no nifty logic to try to optimize the
usage of the swap-files: pages are simply allocated from one swap-file
until it fills up, and then the next swap-file is used.

The memory management changes break ps/free once more, but not very
much.  Also, I changed the load-average counting, so 'w' also needs
slight editing.  On the other hand, I made '/dev/kmem' mmap()able, and
'ps' and 'free' should be edited to take advantage of that: it should
result in much faster operation, as well as possibly using less real
memory.

        fs:

The fs changes should remove at least two races - the races don't happen
very often, but they were theoretically possible, and might be the
reason for some fs corruption problems that have been reported.  The
changes are related to the use of bmap() - the bmap interface doesn't
really lend itself to some things that it was used for.  Re-writing
internal fs-functions not to use bmap not only should have removed any
races, but also actually resulted in cleaner code.

The proc-fs code isn't too beautiful, and I'll probably leave it out
from 0.98 unless I can make it loadable.  We'll see.  If anybody wants
to use it, you can do something like

  # mount -t proc /dev/ram /proc

Instead of /dev/ram you can use any block device - it's not used, and is
only a dummy as the proc-fs doesn't actually use any external device.
(but note that the device is still marked as mounted, so you cannot
mount it for anything else).

        kernel/mm/lib:

The TCP/IP patches are also essentially in 0.97.pl3 - not the full
TCP/IP directory, only the patches to the main kernel.  NOTE!! I don't
like the 'grab_malloc_pages()' function, so I left that out, and added a
GFP_ATOMIC priority to get_free_page() that should be used instead.  I
hope this will be used (Ross?), as it's a lot cleaner.

Also, I hope the tcp/ip people will clean up malloc() so that it doesn't
panic instead of returning NULL etc.  Ugly, ugly.  This is related to
the get_free_page(GFP_ATOMIC) changes, and I'd like to have patches as
soon as possible - tcp/ip won't be part of the standard kernel until
that can be cleaned up.

                Linus
parent eb79918f
This diff is collapsed.
......@@ -84,7 +84,7 @@ CPP =$(CC) -E
AR =ar
ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o net/net.o
FILESYSTEMS =fs/minix/minix.o fs/ext/ext.o fs/msdos/msdos.o
FILESYSTEMS =fs/minix/minix.o fs/ext/ext.o fs/msdos/msdos.o fs/proc/proc.o
DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a \
kernel/blk_drv/scsi/scsi.a
MATH =kernel/math/math.a
......@@ -102,14 +102,21 @@ KERNELHDRS =/usr/src/linux/include
all: Version Image
lilo: Image
if [ -f /vmlinux ]; then mv /vmlinux /vmlinux.old; fi
dd if=Image of=/vmlinux
/etc/lilo/lilo -b /dev/hda /vmlinux
linuxsubdirs: dummy
@for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE)) || exit; done
Version:
@./makever.sh
@echo \#define UTS_RELEASE \"0.97.pl2-`cat .version`\" > include/linux/config_rel.h
@echo \#define UTS_VERSION \"`date +%D`\" > include/linux/config_ver.h
touch include/linux/config.h
@echo \#define UTS_RELEASE \"0.97.pl3-`cat .version`\" > tools/version.h
@echo \#define UTS_VERSION \"`date +%D`\" >> tools/version.h
@echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> tools/version.h
@echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h
@echo \#define LINUX_COMPILE_HOST \"`hostname`\" >> tools/version.h
Image: boot/bootsect boot/setup tools/system tools/build
cp tools/system system.tmp
......@@ -127,11 +134,13 @@ tools/build: tools/build.c
boot/head.o: boot/head.s
tools/version.o: tools/version.c tools/version.h
init/main.o: init/main.c
$(CC) $(CFLAGS) $(PROFILING) -c -o $*.o $<
tools/system: boot/head.o init/main.o linuxsubdirs
$(LD) $(LDFLAGS) -M boot/head.o init/main.o \
tools/system: boot/head.o init/main.o tools/version.o linuxsubdirs
$(LD) $(LDFLAGS) -M boot/head.o init/main.o tools/version.o \
$(ARCHIVES) \
$(FILESYSTEMS) \
$(DRIVERS) \
......@@ -156,10 +165,16 @@ boot/bootsect: boot/bootsect.s
fs: dummy
$(MAKE) linuxsubdirs SUBDIRS=fs
mm: dummy
$(MAKE) linuxsubdirs SUBDIRS=mm
kernel: dummy
$(MAKE) linuxsubdirs SUBDIRS=kernel
clean:
rm -f Image System.map tmp_make core boot/bootsect boot/setup \
boot/bootsect.s boot/setup.s init/main.s
rm -f init/*.o tools/system tools/build boot/*.o
rm -f init/*.o tools/system tools/build boot/*.o tools/*.o
for i in $(SUBDIRS); do (cd $$i && $(MAKE) clean); done
backup: clean
......
VERY QUICK AND DIRTY README
by Lars Wirzenius
This is the README for the Linux kernel sources. It tells a few small
things about kernel configuration and other things that can perhaps be
useful if you want to compile the kernel from scratch. It leaves out a
lot as well, probably because the person who wrote it doesn't understand
very much about operating systems. Linus did his best to help, but all
problems this causes are my fault.
In order to compile this version of the kernel you need GCC 2.2.2 or
newer. Some makefile targets require special commands which may not be
available on all machines (see below). Normal utilities like ls etc are
not explicitly listed, they are assumed to be available on all systems.
Kernel sources are usually kept in /usr/src/linux. If you have them
elsewhere, you will have to change path names in a few places.
Filenames that aren't absolute are supposed to be relative to the
toplevel kernel source directory.
* Basic configuration
1. Edit Makefile: Check the definitions of macros ROOTDEV, KEYBOARD,
MATH_EMULATION, RAMDISK and SVGA_MODE before you run make. They are
explained in the Makefile. MATH_EMULATION does not hurt much even if
you have an FPU (387 or a 486 with a built in FPU), since Linux uses
the FPU if it finds one, even with MATH_EMULATION defined. The kernel
will be slightly bigger. It is probably not worth it to recompile the
kernel just to get rid of the emulation.
[ Linus' note1: if you have a correctly installed gcc-2.2.2d, you can
also remove the "-nostdinc -I$(KERNELHDRS)" thing from the main
Makefile CC definition. But it doesn't hurt to have it, as long as
KERNELHDRS is correctly defined ]
2. Create a symlink:
ln -s /usr/src/linux/include/linux /usr/include/linux
This is required so that tools/build.c will compile and link (it
requires the standard versions of headers instead of the kernel specific
headers, as it is a normal application, not kernel code).
[ Linus' note2: This is automatically done by the gcc-2.2.2d
installation script, so if you have the new compiler, you should
already have this link ]
* Things you may want to get rid of
3. To remove SCSI drivers, do this:
- remove kernel/blk_drv/scsi/scsi.a from DRIVERS in the Makefile
- remove the commands for the subdirs dependency in
kernel/blk_drv/Makefile
- add "#undef CONFIG_SCSI" to the end of include/linux/config.h
The SCSI drivers take a bit of memory, and also slow the bootup a bit,
so you may want to get rid of them if you don't have an SCSI drive.
4. The kernel contains code for the extended filesystem (extfs),
MS-DOS filesystem (dosfs) and proc-fs (proc), all of which are in
testing phases and are not recommended for real use yet. If you don't
want to include these in the kernel, do the following:
- remove references to these in the FILESYSTEMS macro in the
root Makefile
- remove directory names from the SUBDIRS macro in fs/Makefile
- remove the corresponding lines in the initialization of
file_systems in fs/super.c.
5. To configure more ptys do this:
- change NR_PTYS in include/linux/tty.h to the number you want
- create the new files in /dev
- recompile the kernel
* Running make
[ Linus' note3: if you have problems with make not working correctly,
get a new copy of GNU make. pmake may or may not work due to the
macro inheritation assumptions etc ]
Unless you know what you're doing, don't ever run the makefiles in
subdirectories by hand. There is a bit of interaction between the
various makefiles, e.g. in the form of inherited macros and the like.
The following targets all apply for the makefile at the root of the
kernel source tree.
"make" or "make all" compiles everything.
"make Image" is like "make all", but it doesn't bump the number in
.version, which tells how many times this version has been compiled
(helps you differentiate between different configurations etc).
"make disk" is like "make Image", but it additionally writes out a copy
of the boot image to a floppy in your first floppy drive (/dev/fd0;
change the filename if you want a different floppy). You need to have
a formatted, overwritable floppy in that drive when it is time to do the
copy. This requires dd.
"make dep" updates all dependencies. This requires sed. It modifies
the makefiles directly (the end of them, starting at the ###Dependencies
-line at the end).
"make clean" will remove all object files and other files created by the
compilation. This requires basename.
You may wish to redirect compiler error messages to a file so that you
can review them later and to ease problem fixing. You can do this with
Bash with:
make something 2>&1 | tee make.out
The tee part is so that you can check what is going on while the
compilation runs. If you have GNU emacs and use M-x compile you don't
need this, of course.
Lars Wirzeniu
......@@ -120,6 +120,40 @@ no_disk1:
stosb
is_disk1:
! check for PS/2 pointing device
mov ax,#INITSEG
mov ds,ax
mov [0x1ff],#0 ! default is no pointing device
int 0x11 ! int 0x11: equipment determination
test al,#0x04 ! check if pointing device installed
jz no_psmouse
mov ax,#0xc201 ! reset pointing device
int 0x15
jc no_psmouse
mov bh,#0x03 ! 3 bytes/packet
mov ax,#0xc205 ! initialize pointing device
int 0x15
jc no_psmouse
mov ax,#0xc203 ! set resolution
mov bh,#0x03 ! 8 counts/mm
int 0x15
jc no_psmouse
mov ax,#0xc206 ! set scaling
mov bh,0x02 ! 2:1 scaling
int 0x15
jc no_psmouse
mov ax,#0xc202 ! set sample rate
mov bh,#0x05 ! 100 reports per second
int 0x15
jc no_psmouse
mov bh,#0x01
mov ax,#0xc200 ! enable pointing device
int 0x15
jc no_psmouse
mov [0x1ff],#0xaa ! device present
no_psmouse:
! now we want to move to protected mode ...
cli ! no interrupts allowed !
......
......@@ -7,7 +7,7 @@
#
# Note 2! The CFLAGS definitions are now in the main makefile...
SUBDIRS =minix ext msdos
SUBDIRS =minix ext msdos proc
.c.s:
$(CC) $(CFLAGS) -S $<
......
......@@ -497,10 +497,15 @@ void grow_buffers(int size)
}
tmp = bh;
while (1) {
tmp->b_next_free = free_list;
tmp->b_prev_free = free_list->b_prev_free;
free_list->b_prev_free->b_next_free = tmp;
free_list->b_prev_free = tmp;
if (free_list) {
tmp->b_next_free = free_list;
tmp->b_prev_free = free_list->b_prev_free;
free_list->b_prev_free->b_next_free = tmp;
free_list->b_prev_free = tmp;
} else {
tmp->b_prev_free = tmp;
tmp->b_next_free = tmp;
}
free_list = tmp;
++nr_buffers;
if (tmp->b_this_page)
......@@ -558,23 +563,26 @@ 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".
* buffers: 3 means "don't bother too much", while a value
* of 0 means "we'd better get some free pages now".
*/
int shrink_buffers(unsigned int priority)
{
struct buffer_head *bh;
int i;
if (priority > 2) {
priority = 3;
if (priority < 2)
sync_buffers(0);
}
bh = free_list;
i = nr_buffers >> (3-priority);
i = nr_buffers >> priority;
for ( ; i-- > 0 ; bh = bh->b_next_free) {
if (bh->b_lock || bh->b_count || !bh->b_this_page)
if (bh->b_count || !bh->b_this_page)
continue;
if (bh->b_lock)
if (priority)
continue;
else
wait_on_buffer(bh);
if (bh->b_dirt) {
ll_rw_block(WRITEA,bh);
continue;
......@@ -586,47 +594,21 @@ int shrink_buffers(unsigned int priority)
}
/*
* This initializes the low 1M that isn't used by the kernel to buffer
* cache. It should really be used for paging memory, but it takes a lot
* of special-casing, which I don't want to do.
*
* The biggest problem with this approach is that all low-mem buffers
* have a fixed size of 1024 chars: not good if/when the other sizes
* are implemented.
* This initializes the initial buffer free list. nr_buffers is set
* to one less the actual number of buffers, as a sop to backwards
* compatibility --- the old code did this (I think unintentionally,
* but I'm not sure), and programs in the ps package expect it.
* - TYT 8/30/92
*/
void buffer_init(void)
{
struct buffer_head * bh;
extern int end;
unsigned long mem;
int i;
for (i = 0 ; i < NR_HASH ; i++)
hash_table[i] = NULL;
mem = (unsigned long) & end;
mem += BLOCK_SIZE-1;
mem &= ~(BLOCK_SIZE-1);
free_list = get_unused_buffer_head();
free_list = 0;
grow_buffers(BLOCK_SIZE);
if (!free_list)
panic("unable to get a single buffer-head");
free_list->b_prev_free = free_list;
free_list->b_next_free = free_list;
free_list->b_data = (char *) mem;
free_list->b_size = BLOCK_SIZE;
mem += BLOCK_SIZE;
while (mem + 1024 < 0xA0000) {
bh = get_unused_buffer_head();
if (!bh)
break;
bh->b_data = (char *) mem;
bh->b_size = BLOCK_SIZE;
mem += BLOCK_SIZE;
bh->b_next_free = free_list;
bh->b_prev_free = free_list->b_prev_free;
free_list->b_prev_free->b_next_free = bh;
free_list->b_prev_free = bh;
free_list = bh;
++nr_buffers;
}
panic("Unable to initialize buffer free list!");
return;
}
......@@ -80,8 +80,10 @@ int core_dump(long signr, struct pt_regs * regs)
if(current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE/1024) return 0;
__asm__("mov %%fs,%0":"=r" (fs));
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
if (open_namei("core",O_CREAT | O_WRONLY | O_TRUNC,0600,&inode,NULL))
if (open_namei("core",O_CREAT | O_WRONLY | O_TRUNC,0600,&inode,NULL)) {
inode = NULL;
goto end_coredump;
}
if (!S_ISREG(inode->i_mode))
goto end_coredump;
if (!inode->i_op || !inode->i_op->default_file_ops)
......@@ -415,7 +417,7 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
retval = -EACCES;
goto exec_error2;
}
if (IS_NOEXEC(inode)) { /* FS mustn't be mounted noexec */
if (IS_NOEXEC(inode)) { /* FS mustn't be mounted noexec */
retval = -EPERM;
goto exec_error2;
}
......
......@@ -470,14 +470,14 @@ static int empty_dir(struct inode * inode)
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);
return 0;
return 1;
}
de = (struct ext_dir_entry *) bh->b_data;
de1 = (struct ext_dir_entry *) ((char *) de + de->rec_len);
if (de->inode != inode->i_ino || !de1->inode ||
strcmp(".",de->name) || strcmp("..",de1->name)) {
printk("warning - bad directory on dev %04x\n",inode->i_dev);
return 0;
return 1;
}
offset = de->rec_len + de1->rec_len;
de = (struct ext_dir_entry *) ((char *) de1 + de1->rec_len);
......
......@@ -11,20 +11,37 @@
#include <linux/string.h>
#include <linux/stat.h>
static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
{
int block;
switch (cmd) {
case FIBMAP:
if (filp->f_inode->i_op == NULL) return -EBADF;
if (filp->f_inode->i_op->bmap == NULL) return -EINVAL;
block = get_fs_long((long *) arg);
block = filp->f_inode->i_op->bmap(filp->f_inode,block);
put_fs_long(block,(long *) arg);
return 0;
case FIGETBSZ:
if (filp->f_inode->i_sb == NULL) return -EBADF;
put_fs_long(filp->f_inode->i_sb->s_blocksize,
(long *) arg);
return 0;
default:
return -EINVAL;
}
}
int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct file * filp;
int block;
if (fd >= NR_OPEN || !(filp = current->filp[fd]))
return -EBADF;
if (S_ISREG(filp->f_inode->i_mode) && cmd == BMAP_IOCTL &&
filp->f_inode->i_op->bmap) {
block = get_fs_long((long *) arg);
block = filp->f_inode->i_op->bmap(filp->f_inode,block);
put_fs_long(block,(long *) arg);
return 0;
}
if (filp->f_inode && S_ISREG(filp->f_inode->i_mode))
return file_ioctl(filp,cmd,arg);
if (filp->f_op && filp->f_op->ioctl)
return filp->f_op->ioctl(filp->f_inode, filp, cmd,arg);
return -EINVAL;
......
......@@ -56,6 +56,6 @@ struct inode_operations minix_blkdev_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
minix_bmap, /* bmap */
minix_truncate /* truncate */
NULL, /* bmap */
NULL /* truncate */
};
......@@ -56,7 +56,7 @@ struct inode_operations minix_chrdev_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
minix_bmap, /* bmap */
minix_truncate /* truncate */
NULL, /* bmap */
NULL /* truncate */
};
......@@ -42,14 +42,14 @@ struct inode_operations minix_dir_inode_operations = {
minix_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
minix_bmap, /* bmap */
NULL, /* bmap */
minix_truncate /* truncate */
};
static int minix_readdir(struct inode * inode, struct file * filp,
struct dirent * dirent, int count)
{
unsigned int block,offset,i;
unsigned int offset,i;
char c;
struct buffer_head * bh;
struct minix_dir_entry * de;
......@@ -60,8 +60,8 @@ static int minix_readdir(struct inode * inode, struct file * filp,
return -EBADF;
while (filp->f_pos < inode->i_size) {
offset = filp->f_pos & 1023;
block = minix_bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS);
if (!block || !(bh = bread(inode->i_dev,block,BLOCK_SIZE))) {
bh = minix_bread(inode,(filp->f_pos)>>BLOCK_SIZE_BITS,0);
if (!bh) {
filp->f_pos += 1024-offset;
continue;
}
......
......@@ -24,6 +24,14 @@
#include <linux/fs.h>
#include <linux/minix_fs.h>
static inline void wait_on_buffer(struct buffer_head * bh)
{
cli();
while (bh->b_lock)
sleep_on(&bh->b_wait);
sti();
}
int minix_file_read(struct inode *, struct file *, char *, int);
static int minix_file_write(struct inode *, struct file *, char *, int);
......@@ -59,14 +67,6 @@ struct inode_operations minix_file_inode_operations = {
minix_truncate /* truncate */
};
static inline void wait_on_buffer(struct buffer_head * bh)
{
cli();
while (bh->b_lock)
sleep_on(&bh->b_wait);
sti();
}
/*
* minix_file_read() is also needed by the directory read-routine,
* so it's not static. NOTE! reading directories directly is a bad idea,
......@@ -75,7 +75,7 @@ static inline void wait_on_buffer(struct buffer_head * bh)
*/
int minix_file_read(struct inode * inode, struct file * filp, char * buf, int count)
{
int read,left,chars,nr;
int read,left,chars;
int block, blocks, offset;
struct buffer_head ** bhb, ** bhe;
struct buffer_head * buflist[NBUF];
......@@ -104,12 +104,9 @@ int minix_file_read(struct inode * inode, struct file * filp, char * buf, int co
do {
if (blocks) {
--blocks;
if (nr = minix_bmap(inode,block++)) {
*bhb = getblk(inode->i_dev,nr,BLOCK_SIZE);
if (!(*bhb)->b_uptodate)
ll_rw_block(READ,*bhb);
} else
*bhb = NULL;
*bhb = minix_getblk(inode,block++,0);
if (*bhb && !(*bhb)->b_uptodate)
ll_rw_block(READ,*bhb);
if (++bhb == &buflist[NBUF])
bhb = buflist;
......@@ -160,7 +157,7 @@ int minix_file_read(struct inode * inode, struct file * filp, char * buf, int co
static int minix_file_write(struct inode * inode, struct file * filp, char * buf, int count)
{
off_t pos;
int written,block,c;
int written,c;
struct buffer_head * bh;
char * p;
......@@ -182,7 +179,8 @@ static int minix_file_write(struct inode * inode, struct file * filp, char * buf
pos = filp->f_pos;
written = 0;
while (written<count) {
if (!(block = minix_create_block(inode,pos/BLOCK_SIZE))) {
bh = minix_getblk(inode,pos/BLOCK_SIZE,1);
if (!bh) {
if (!written)
written = -ENOSPC;
break;
......@@ -190,14 +188,15 @@ static int minix_file_write(struct inode * inode, struct file * filp, char * buf
c = BLOCK_SIZE - (pos % BLOCK_SIZE);
if (c > count-written)
c = count-written;
if (c == BLOCK_SIZE)
bh = getblk(inode->i_dev, block, BLOCK_SIZE);
else
bh = bread(inode->i_dev,block, BLOCK_SIZE);
if (!bh) {
if (!written)
written = -EIO;
break;
if (c != BLOCK_SIZE && !bh->b_uptodate) {
ll_rw_block(READ,bh);
wait_on_buffer(bh);
if (!bh->b_uptodate) {
brelse(bh);
if (!written)
written = -EIO;
break;
}
}
p = (pos % BLOCK_SIZE) + bh->b_data;
pos += c;
......
......@@ -16,6 +16,14 @@
int sync_dev(int dev);
static inline void wait_on_buffer(struct buffer_head * bh)
{
cli();
while (bh->b_lock)
sleep_on(&bh->b_wait);
sti();
}
void minix_put_inode(struct inode *inode)
{
inode->i_size = 0;
......@@ -130,86 +138,168 @@ void minix_statfs (struct super_block *sb, struct statfs *buf)
/* Don't know what value to put in buf->f_fsid */
}
static int _minix_bmap(struct inode * inode,int block,int create)
#define inode_bmap(inode,nr) ((inode)->i_data[(nr)])
static int block_bmap(struct buffer_head * bh, int nr)
{
int tmp;
if (!bh)
return 0;
tmp = ((unsigned short *) bh->b_data)[nr];
brelse(bh);
return tmp;
}
int minix_bmap(struct inode * inode,int block)
{
struct buffer_head * bh;
int i;
if (block<0) {
printk("_minix_bmap: block<0");
printk("minix_bmap: block<0");
return 0;
}
if (block >= 7+512+512*512) {
printk("_minix_bmap: block>big");
printk("minix_bmap: block>big");
return 0;
}
if (block<7) {
if (create && !inode->i_data[block])
if (inode->i_data[block]=minix_new_block(inode->i_dev)) {
inode->i_ctime=CURRENT_TIME;
inode->i_dirt=1;
}
return inode->i_data[block];
}
if (block < 7)
return inode_bmap(inode,block);
block -= 7;
if (block<512) {
if (create && !inode->i_data[7])
if (inode->i_data[7]=minix_new_block(inode->i_dev)) {
inode->i_dirt=1;
inode->i_ctime=CURRENT_TIME;
}
if (!inode->i_data[7])
return 0;
if (!(bh = bread(inode->i_dev,inode->i_data[7],BLOCK_SIZE)))
if (block < 512) {
i = inode_bmap(inode,7);
if (!i)
return 0;
i = ((unsigned short *) (bh->b_data))[block];
if (create && !i)
if (i=minix_new_block(inode->i_dev)) {
((unsigned short *) (bh->b_data))[block]=i;
bh->b_dirt=1;
}
brelse(bh);
return i;
return block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block);
}
block -= 512;
if (create && !inode->i_data[8])
if (inode->i_data[8]=minix_new_block(inode->i_dev)) {
inode->i_dirt=1;
inode->i_ctime=CURRENT_TIME;
}
if (!inode->i_data[8])
return 0;
if (!(bh=bread(inode->i_dev,inode->i_data[8], BLOCK_SIZE)))
return 0;
i = ((unsigned short *)bh->b_data)[block>>9];
if (create && !i)
if (i=minix_new_block(inode->i_dev)) {
((unsigned short *) (bh->b_data))[block>>9]=i;
bh->b_dirt=1;
}
brelse(bh);
i = inode_bmap(inode,8);
if (!i)
return 0;
if (!(bh=bread(inode->i_dev,i,BLOCK_SIZE)))
i = block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block>>9);
if (!i)
return 0;
i = ((unsigned short *)bh->b_data)[block&511];
if (create && !i)
if (i=minix_new_block(inode->i_dev)) {
((unsigned short *) (bh->b_data))[block&511]=i;
bh->b_dirt=1;
return block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block & 511);
}
static struct buffer_head * inode_getblk(struct inode * inode, int nr, int create)
{
int tmp;
struct buffer_head * result;
repeat:
tmp = inode->i_data[nr];
if (tmp) {
result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
if (tmp == inode->i_data[nr])
return result;
brelse(result);
goto repeat;
}
if (!create)
return NULL;
tmp = minix_new_block(inode->i_dev);
if (!tmp)
return NULL;
result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
if (inode->i_data[nr]) {
minix_free_block(inode->i_dev,tmp);
brelse(result);
goto repeat;
}
inode->i_data[nr] = tmp;
inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
return result;
}
static struct buffer_head * block_getblk(struct buffer_head * bh, int nr, int create)
{
int tmp;
unsigned short *p;
struct buffer_head * result;
if (!bh)
return NULL;
if (!bh->b_uptodate) {
ll_rw_block(READ,bh);
wait_on_buffer(bh);
if (!bh->b_uptodate) {
brelse(bh);
return NULL;
}
}
p = nr + (unsigned short *) bh->b_data;
repeat:
tmp = *p;
if (tmp) {
result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
if (tmp == *p) {
brelse(bh);
return result;
}
brelse(result);
goto repeat;
}
if (!create) {
brelse(bh);
return NULL;
}
tmp = minix_new_block(bh->b_dev);
if (!tmp) {
brelse(bh);
return NULL;
}
result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
if (*p) {
minix_free_block(bh->b_dev,tmp);
brelse(result);
goto repeat;
}
*p = tmp;
bh->b_dirt = 1;
brelse(bh);
return i;
return result;
}
int minix_bmap(struct inode * inode,int block)
struct buffer_head * minix_getblk(struct inode * inode, int block, int create)
{
return _minix_bmap(inode,block,0);
struct buffer_head * bh;
if (block<0) {
printk("minix_getblk: block<0");
return NULL;
}
if (block >= 7+512+512*512) {
printk("minix_getblk: block>big");
return NULL;
}
if (block < 7)
return inode_getblk(inode,block,create);
block -= 7;
if (block < 512) {
bh = inode_getblk(inode,7,create);
return block_getblk(bh,block,create);
}
block -= 512;
bh = inode_getblk(inode,8,create);
bh = block_getblk(bh,block>>9,create);
return block_getblk(bh,block & 511,create);
}
int minix_create_block(struct inode * inode, int block)
struct buffer_head * minix_bread(struct inode * inode, int block, int create)
{
return _minix_bmap(inode,block,1);
struct buffer_head * bh;
bh = minix_getblk(inode,block,create);
if (!bh || bh->b_uptodate)
return bh;
ll_rw_block(READ,bh);
wait_on_buffer(bh);
if (bh->b_uptodate)
return bh;
brelse(bh);
return NULL;
}
void minix_read_inode(struct inode * inode)
......
......@@ -60,8 +60,7 @@ static int minix_match(int len,const char * name,struct minix_dir_entry * de)
static struct buffer_head * minix_find_entry(struct inode * dir,
const char * name, int namelen, struct minix_dir_entry ** res_dir)
{
int entries;
int block,i;
int entries, i;
struct buffer_head * bh;
struct minix_dir_entry * de;
......@@ -76,18 +75,16 @@ static struct buffer_head * minix_find_entry(struct inode * dir,
namelen = MINIX_NAME_LEN;
#endif
entries = dir->i_size / (sizeof (struct minix_dir_entry));
if (!(block = dir->i_data[0]))
return NULL;
if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE)))
bh = minix_bread(dir,0,0);
if (!bh)
return NULL;
i = 0;
de = (struct minix_dir_entry *) bh->b_data;
while (i < entries) {
if ((char *)de >= BLOCK_SIZE+bh->b_data) {
brelse(bh);
bh = NULL;
if (!(block = minix_bmap(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK)) ||
!(bh = bread(dir->i_dev, block, BLOCK_SIZE))) {
bh = minix_bread(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK,0);
if (!bh) {
i += MINIX_DIR_ENTRIES_PER_BLOCK;
continue;
}
......@@ -145,7 +142,7 @@ int minix_lookup(struct inode * dir,const char * name, int len,
static struct buffer_head * minix_add_entry(struct inode * dir,
const char * name, int namelen, struct minix_dir_entry ** res_dir)
{
int block,i;
int i;
struct buffer_head * bh;
struct minix_dir_entry * de;
......@@ -161,23 +158,17 @@ static struct buffer_head * minix_add_entry(struct inode * dir,
#endif
if (!namelen)
return NULL;
if (!(block = dir->i_data[0]))
return NULL;
if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE)))
bh = minix_bread(dir,0,0);
if (!bh)
return NULL;
i = 0;
de = (struct minix_dir_entry *) bh->b_data;
while (1) {
if ((char *)de >= BLOCK_SIZE+bh->b_data) {
brelse(bh);
bh = NULL;
block = minix_create_block(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK);
if (!block)
bh = minix_bread(dir,i/MINIX_DIR_ENTRIES_PER_BLOCK,1);
if (!bh)
return NULL;
if (!(bh = bread(dir->i_dev, block, BLOCK_SIZE))) {
i += MINIX_DIR_ENTRIES_PER_BLOCK;
continue;
}
de = (struct minix_dir_entry *) bh->b_data;
}
if (i*sizeof(struct minix_dir_entry) >= dir->i_size) {
......@@ -314,21 +305,14 @@ int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
inode->i_op = &minix_dir_inode_operations;
inode->i_size = 2 * sizeof (struct minix_dir_entry);
inode->i_mtime = inode->i_atime = CURRENT_TIME;
if (!(inode->i_data[0] = minix_new_block(inode->i_dev))) {
dir_block = minix_bread(inode,0,1);
if (!dir_block) {
iput(dir);
inode->i_nlink--;
inode->i_dirt = 1;
iput(inode);
return -ENOSPC;
}
inode->i_dirt = 1;
if (!(dir_block = bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) {
iput(dir);
inode->i_nlink--;
inode->i_dirt = 1;
iput(inode);
return -EIO;
}
de = (struct minix_dir_entry *) dir_block->b_data;
de->inode=inode->i_ino;
strcpy(de->name,".");
......@@ -362,35 +346,31 @@ int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
*/
static int empty_dir(struct inode * inode)
{
int nr,block;
int len;
int nr, len;
struct buffer_head * bh;
struct minix_dir_entry * de;
len = inode->i_size / sizeof (struct minix_dir_entry);
if (len<2 || !inode->i_data[0] ||
!(bh=bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) {
if (len<2 || !(bh = minix_bread(inode,0,0))) {
printk("warning - bad directory on dev %04x\n",inode->i_dev);
return 0;
return 1;
}
de = (struct minix_dir_entry *) bh->b_data;
if (de[0].inode != inode->i_ino || !de[1].inode ||
strcmp(".",de[0].name) || strcmp("..",de[1].name)) {
printk("warning - bad directory on dev %04x\n",inode->i_dev);
return 0;
return 1;
}
nr = 2;
de += 2;
while (nr<len) {
if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
brelse(bh);
block = minix_bmap(inode,nr/MINIX_DIR_ENTRIES_PER_BLOCK);
if (!block) {
bh = minix_bread(inode,nr/MINIX_DIR_ENTRIES_PER_BLOCK,0);
if (!bh) {
nr += MINIX_DIR_ENTRIES_PER_BLOCK;
continue;
}
if (!(bh=bread(inode->i_dev, block, BLOCK_SIZE)))
return 0;
de = (struct minix_dir_entry *) bh->b_data;
}
if (de->inode) {
......@@ -508,21 +488,14 @@ int minix_symlink(struct inode * dir, const char * name, int len, const char * s
}
inode->i_mode = S_IFLNK | 0777;
inode->i_op = &minix_symlink_inode_operations;
if (!(inode->i_data[0] = minix_new_block(inode->i_dev))) {
name_block = minix_bread(inode,0,1);
if (!name_block) {
iput(dir);
inode->i_nlink--;
inode->i_dirt = 1;
iput(inode);
return -ENOSPC;
}
inode->i_dirt = 1;
if (!(name_block = bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) {
iput(dir);
inode->i_nlink--;
inode->i_dirt = 1;
iput(inode);
return -EIO;
}
i = 0;
while (i < 1023 && (c=get_fs_byte(symname++)))
name_block->b_data[i++] = c;
......@@ -692,9 +665,8 @@ static int do_minix_rename(struct inode * old_dir, const char * old_name, int ol
if (subdir(new_dir, old_inode))
goto end_rename;
retval = -EIO;
if (!old_inode->i_data[0])
goto end_rename;
if (!(dir_bh = bread(old_inode->i_dev, old_inode->i_data[0], BLOCK_SIZE)))
dir_bh = minix_bread(old_inode,0,0);
if (!dir_bh)
goto end_rename;
if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
goto end_rename;
......
......@@ -44,13 +44,13 @@ static int minix_follow_link(struct inode * dir, struct inode * inode,
unsigned short fs;
struct buffer_head * bh;
*res_inode = NULL;
if (!dir) {
dir = current->root;
dir->i_count++;
}
if (!inode) {
iput(dir);
*res_inode = NULL;
return -ENOENT;
}
if (!S_ISLNK(inode->i_mode)) {
......@@ -58,15 +58,18 @@ static int minix_follow_link(struct inode * dir, struct inode * inode,
*res_inode = inode;
return 0;
}
__asm__("mov %%fs,%0":"=r" (fs));
if ((current->link_count > 5) || !inode->i_data[0] ||
!(bh = bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE))) {
iput(dir);
if (current->link_count > 5) {
iput(inode);
*res_inode = NULL;
iput(dir);
return -ELOOP;
}
if (!(bh = minix_bread(inode, 0, 0))) {
iput(inode);
iput(dir);
return -EIO;
}
iput(inode);
__asm__("mov %%fs,%0":"=r" (fs));
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
current->link_count++;
error = open_namei(bh->b_data,flag,mode,res_inode,dir);
......@@ -88,10 +91,7 @@ static int minix_readlink(struct inode * inode, char * buffer, int buflen)
}
if (buflen > 1023)
buflen = 1023;
if (inode->i_data[0])
bh = bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE);
else
bh = NULL;
bh = minix_bread(inode, 0, 0);
iput(inode);
if (!bh)
return 0;
......
......@@ -57,7 +57,7 @@ static int msdos_dummy_read(struct inode *inode,struct file *filp,char *buf,
static long last_warning = 0;
if (CURRENT_TIME-last_warning >= 10) {
printk("COMPATIBILITY WARNING: reading a directory\r\n");
printk("COMPATIBILITY WARNING: reading a directory\n");
last_warning = CURRENT_TIME;
}
return 0;
......
......@@ -9,6 +9,7 @@
#include <linux/errno.h>
#include <linux/stat.h>
static struct fat_cache *fat_cache,cache[FAT_CACHE];
/* Returns the this'th FAT entry, -1 if it is an end-of-file entry. If
......@@ -28,7 +29,7 @@ int fat_access(struct super_block *sb,int this,int new_value)
}
if (!(bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(first >>
SECTOR_BITS),&data))) {
printk("bread in fat_access failed\r\n");
printk("bread in fat_access failed\n");
return 0;
}
if ((first >> SECTOR_BITS) == (last >> SECTOR_BITS)) {
......@@ -39,11 +40,12 @@ int fat_access(struct super_block *sb,int this,int new_value)
if (!(bh2 = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(last
>> SECTOR_BITS),&data2))) {
brelse(bh);
printk("bread in fat_access failed\r\n");
printk("bread in fat_access failed\n");
return 0;
}
}
if (MSDOS_SB(sb)->fat_bits == 16) {
p_first = p_last = NULL; /* GCC needs that stuff */
next = ((unsigned short *) data)[(first & (SECTOR_SIZE-1))
>> 1];
if (next >= 0xfff8) next = -1;
......@@ -119,7 +121,8 @@ void cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu)
struct fat_cache *walk;
#ifdef DEBUG
printk("cache lookup: %d\r\n",*f_clu);
printk("cache lookup: <%d,%d> %d (%d,%d) -> ",inode->i_dev,inode->i_ino,cluster,
*f_clu,*d_clu);
#endif
for (walk = fat_cache; walk; walk = walk->next)
if (inode->i_dev == walk->device && walk->ino == inode->i_ino &&
......@@ -127,10 +130,13 @@ printk("cache lookup: %d\r\n",*f_clu);
*f_clu) {
*d_clu = walk->disk_cluster;
#ifdef DEBUG
printk("cache hit: %d (%d)\r\n",walk->file_cluster,*d_clu);
printk("cache hit: %d (%d)\n",walk->file_cluster,*d_clu);
#endif
if ((*f_clu = walk->file_cluster) == cluster) return;
}
#ifdef DEBUG
printk("cache miss\n");
#endif
}
......@@ -140,11 +146,12 @@ static void list_cache(void)
struct fat_cache *walk;
for (walk = fat_cache; walk; walk = walk->next) {
if (walk->device) printk("(%d,%d) ",walk->file_cluster,
walk->disk_cluster);
if (walk->device)
printk("<%d,%d>(%d,%d) ",walk->device,walk->ino,
walk->file_cluster,walk->disk_cluster);
else printk("-- ");
}
printk("\r\n");
printk("\n");
}
#endif
......@@ -154,7 +161,7 @@ void cache_add(struct inode *inode,int f_clu,int d_clu)
struct fat_cache *walk,*last;
#ifdef DEBUG
printk("cache add: %d (%d)\r\n",f_clu,d_clu);
printk("cache add: <%d,%d> %d (%d)\n",inode->i_dev,inode->i_ino,f_clu,d_clu);
#endif
last = NULL;
for (walk = fat_cache; walk->next; walk = (last = walk)->next)
......@@ -211,7 +218,7 @@ int get_cluster(struct inode *inode,int cluster)
{
int this,count;
if (!(this = inode->i_data[D_START])) return 0;
if (!(this = MSDOS_I(inode)->i_start)) return 0;
if (!cluster) return this;
count = 0;
for (cache_lookup(inode,cluster,&count,&this); count < cluster;
......@@ -219,7 +226,10 @@ int get_cluster(struct inode *inode,int cluster)
if ((this = fat_access(inode->i_sb,this,-1)) == -1) return 0;
if (!this) return 0;
}
cache_add(inode,cluster,this);
if (!(MSDOS_I(inode)->i_busy || inode->i_nlink))
cache_add(inode,cluster,this);
/* don't add clusters of moved files, because we can't invalidate them
when this inode is returned. */
return this;
}
......@@ -231,7 +241,7 @@ int msdos_smap(struct inode *inode,int sector)
sb = MSDOS_SB(inode->i_sb);
if (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) &&
!inode->i_data[D_START])) {
!MSDOS_I(inode)->i_start)) {
if (sector >= sb->dir_entries >> MSDOS_DPS_BITS) return 0;
return sector+sb->dir_start;
}
......@@ -249,14 +259,13 @@ int fat_free(struct inode *inode,int skip)
{
int this,last;
if (!(this = inode->i_data[D_START])) return 0;
if (!(this = MSDOS_I(inode)->i_start)) return 0;
last = 0;
while (skip--) {
last = this;
if ((this = fat_access(inode->i_sb,this,-1)) == -1)
return 0;
if ((this = fat_access(inode->i_sb,this,-1)) == -1) return 0;
if (!this) {
printk("fat_free: skipped EOF\r\n");
printk("fat_free: skipped EOF\n");
return -EIO;
}
}
......@@ -264,12 +273,18 @@ int fat_free(struct inode *inode,int skip)
fat_access(inode->i_sb,last,MSDOS_SB(inode->i_sb)->fat_bits ==
12 ? 0xff8 : 0xfff8);
else {
inode->i_data[D_START] = 0;
MSDOS_I(inode)->i_start = 0;
inode->i_dirt = 1;
}
while (this != -1)
lock_fat(inode->i_sb);
while (this != -1) {
if (!(this = fat_access(inode->i_sb,this,0)))
panic("fat_free: deleting beyond EOF");
if (MSDOS_SB(inode->i_sb)->free_clusters != -1)
MSDOS_SB(inode->i_sb)->free_clusters++;
inode->i_blocks--;
}
unlock_fat(inode->i_sb);
cache_inval_inode(inode);
return 0;
}
......@@ -82,9 +82,9 @@ static int msdos_file_read(struct inode *inode,struct file *filp,char *buf,
struct buffer_head *bh;
void *data;
/* printk("msdos_file_read\r\n"); */
/* printk("msdos_file_read\n"); */
if (!inode) {
printk("msdos_file_read: inode = NULL\r\n");
printk("msdos_file_read: inode = NULL\n");
return -EINVAL;
}
if (!S_ISREG(inode->i_mode)) {
......@@ -99,7 +99,7 @@ static int msdos_file_read(struct inode *inode,struct file *filp,char *buf,
offset = filp->f_pos & (SECTOR_SIZE-1);
if (!(bh = msdos_sread(inode->i_dev,sector,&data))) break;
filp->f_pos += (size = MIN(SECTOR_SIZE-offset,left));
if (inode->i_data[D_BINARY]) {
if (MSDOS_I(inode)->i_binary) {
memcpy_tofs(buf,data+offset,size);
buf += size;
}
......@@ -149,14 +149,17 @@ static int msdos_file_write(struct inode *inode,struct file *filp,char *buf,
for (start = buf; count || carry; count -= size) {
while (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS)))
if ((error = msdos_add_cluster(inode)) < 0) break;
if (error) break;
if (error) {
msdos_truncate(inode);
break;
}
offset = filp->f_pos & (SECTOR_SIZE-1);
size = MIN(SECTOR_SIZE-offset,MAX(carry,count));
if (!(bh = msdos_sread(inode->i_dev,sector,&data))) {
error = -EIO;
break;
}
if (inode->i_data[D_BINARY]) {
if (MSDOS_I(inode)->i_binary) {
memcpy_fromfs(data+(filp->f_pos & (SECTOR_SIZE-1)),
buf,written = size);
buf += size;
......@@ -191,7 +194,7 @@ static int msdos_file_write(struct inode *inode,struct file *filp,char *buf,
brelse(bh);
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_data[D_ATTRS] |= ATTR_ARCH;
MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
inode->i_dirt = 1;
return start == buf ? error : buf-start;
}
......@@ -203,6 +206,6 @@ void msdos_truncate(struct inode *inode)
cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
(void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
inode->i_data[D_ATTRS] |= ATTR_ARCH;
MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
inode->i_dirt = 1;
}
......@@ -19,16 +19,16 @@ void msdos_put_inode(struct inode *inode)
inode->i_size = 0;
msdos_truncate(inode);
depend = (struct inode *) inode->i_data[D_DEPEND];
depend = MSDOS_I(inode)->i_depend;
memset(inode,0,sizeof(struct inode));
if (depend) {
if ((struct inode *) depend->i_data[D_OLD] != inode) {
if (MSDOS_I(depend)->i_old != inode) {
printk("Invalid link (0x%X): expected 0x%X, got "
"0x%X\r\n",(int) depend,(int) inode,
depend->i_data[D_OLD]);
"0x%X\n",(int) depend,(int) inode,(int)
MSDOS_I(depend)->i_old);
panic("That's fatal");
}
depend->i_data[D_OLD] = 0;
MSDOS_I(depend)->i_old = NULL;
iput(depend);
}
}
......@@ -104,7 +104,7 @@ struct super_block *msdos_read_super(struct super_block *s,void *data)
free_super(s);
if (bh == NULL) {
s->s_dev = 0;
printk("MSDOS bread failed\r\n");
printk("MSDOS bread failed\n");
return NULL;
}
b = (struct msdos_boot_sector *) bh->b_data;
......@@ -123,9 +123,9 @@ struct super_block *msdos_read_super(struct super_block *s,void *data)
0;
MSDOS_SB(s)->fat_bits = MSDOS_SB(s)->clusters > MSDOS_FAT12 ? 16 : 12;
brelse(bh);
printk("[MS-DOS FS Rel. alpha.6, FAT %d, check=%c, conv=%c]\r\n",
printk("[MS-DOS FS Rel. alpha.8, FAT %d, check=%c, conv=%c]\n",
MSDOS_SB(s)->fat_bits,check,conversion);
printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,se=%d,ts=%d]\r\n",
printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,se=%d,ts=%d]\n",
b->media,MSDOS_SB(s)->cluster_size,MSDOS_SB(s)->fats,MSDOS_SB(s)->fat_start,
MSDOS_SB(s)->fat_length,MSDOS_SB(s)->dir_start,MSDOS_SB(s)->dir_entries,
MSDOS_SB(s)->data_start,*(unsigned short *) &b->sectors,b->total_sect);
......@@ -133,10 +133,10 @@ printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,se=%d,ts=%d]\r\n",
|| !b->cluster_size || MSDOS_SB(s)->clusters+2 > MSDOS_SB(s)->
fat_length*SECTOR_SIZE*8/MSDOS_SB(s)->fat_bits) {
s->s_dev = 0;
printk("Unsupported FS parameters\r\n");
printk("Unsupported FS parameters\n");
return NULL;
}
if (!MSDOS_CAN_BMAP(MSDOS_SB(s))) printk("No bmap support\r\n");
if (!MSDOS_CAN_BMAP(MSDOS_SB(s))) printk("No bmap support\n");
s->s_magic = MSDOS_SUPER_MAGIC;
MSDOS_SB(s)->name_check = check;
MSDOS_SB(s)->conversion = conversion;
......@@ -145,6 +145,9 @@ printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,se=%d,ts=%d]\r\n",
MSDOS_SB(s)->fs_uid = current->uid;
MSDOS_SB(s)->fs_gid = current->gid;
MSDOS_SB(s)->fs_umask = current->umask;
MSDOS_SB(s)->free_clusters = -1; /* don't know yet */
MSDOS_SB(s)->fat_wait = NULL;
MSDOS_SB(s)->fat_lock = 0;
if (!(s->s_mounted = iget(s->s_dev,MSDOS_ROOT_INO))) {
s->s_dev = 0;
printk("get root inode failed\n");
......@@ -156,16 +159,21 @@ printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,se=%d,ts=%d]\r\n",
void msdos_statfs(struct super_block *sb,struct statfs *buf)
{
int cluster_size,free,this;
int free,this;
cluster_size = MSDOS_SB(sb)->cluster_size;
put_fs_long(sb->s_magic,&buf->f_type);
put_fs_long(SECTOR_SIZE,&buf->f_bsize);
put_fs_long(MSDOS_SB(sb)->clusters*cluster_size,&buf->f_blocks);
free = 0;
for (this = 2; this < MSDOS_SB(sb)->clusters+2; this++)
if (!fat_access(sb,this,-1)) free++;
free *= cluster_size;
put_fs_long(MSDOS_SB(sb)->cluster_size*SECTOR_SIZE,&buf->f_bsize);
put_fs_long(MSDOS_SB(sb)->clusters,&buf->f_blocks);
lock_fat(sb);
if (MSDOS_SB(sb)->free_clusters != -1)
free = MSDOS_SB(sb)->free_clusters;
else {
free = 0;
for (this = 2; this < MSDOS_SB(sb)->clusters+2; this++)
if (!fat_access(sb,this,-1)) free++;
MSDOS_SB(sb)->free_clusters = free;
}
unlock_fat(sb);
put_fs_long(free,&buf->f_bfree);
put_fs_long(free,&buf->f_bavail);
put_fs_long(0,&buf->f_files);
......@@ -197,21 +205,26 @@ void msdos_read_inode(struct inode *inode)
struct msdos_dir_entry *raw_entry;
int this;
/* printk("read inode %d\r\n",inode->i_ino); */
inode->i_data[D_BUSY] = inode->i_data[D_DEPEND] =
inode->i_data[D_OLD] = 0;
inode->i_data[D_BINARY] = 1;
/* printk("read inode %d\n",inode->i_ino); */
MSDOS_I(inode)->i_busy = 0;
MSDOS_I(inode)->i_depend = MSDOS_I(inode)->i_old = NULL;
MSDOS_I(inode)->i_binary = 1;
inode->i_uid = MSDOS_SB(inode->i_sb)->fs_uid;
inode->i_gid = MSDOS_SB(inode->i_sb)->fs_gid;
if (inode->i_ino == MSDOS_ROOT_INO) {
inode->i_mode = (0777 & ~MSDOS_SB(inode->i_sb)->fs_umask) |
S_IFDIR;
inode->i_op = &msdos_dir_inode_operations;
inode->i_nlink = 1;
inode->i_nlink = msdos_subdirs(inode)+2;
/* subdirs (neither . nor ..) plus . and "self" */
inode->i_size = MSDOS_SB(inode->i_sb)->dir_entries*
sizeof(struct msdos_dir_entry);
inode->i_data[D_START] = 0;
inode->i_data[D_ATTRS] = 0;
inode->i_blksize = MSDOS_SB(inode->i_sb)->cluster_size*
SECTOR_SIZE;
inode->i_blocks = (inode->i_size+inode->i_blksize-1)/
inode->i_blksize;
MSDOS_I(inode)->i_start = 0;
MSDOS_I(inode)->i_attrs = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = 0;
return;
}
......@@ -219,16 +232,29 @@ void msdos_read_inode(struct inode *inode)
panic("unable to read i-node block");
raw_entry = &((struct msdos_dir_entry *) (bh->b_data))
[inode->i_ino & (MSDOS_DPB-1)];
if (raw_entry->attr & ATTR_DIR) {
if ((raw_entry->attr & ATTR_DIR) && *raw_entry->name && *(unsigned char *)
raw_entry->name != DELETED_FLAG) {
inode->i_mode = MSDOS_MKMODE(raw_entry->attr,0777 &
~MSDOS_SB(inode->i_sb)->fs_umask) | S_IFDIR;
inode->i_op = &msdos_dir_inode_operations;
inode->i_nlink = 3;
MSDOS_I(inode)->i_start = raw_entry->start;
inode->i_nlink = msdos_subdirs(inode);
/* includes .., compensating for "self" */
#ifdef DEBUG
if (!inode->i_nlink) {
printk("directory %d: i_nlink == 0\n",inode->i_ino);
inode->i_nlink = 1;
}
#endif
inode->i_size = 0;
for (this = raw_entry->start; this && this != -1; this =
fat_access(inode->i_sb,this,-1))
inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->i_sb)->
cluster_size;
if (this = raw_entry->start)
while (this != -1) {
inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->
i_sb)->cluster_size;
if (!(this = fat_access(inode->i_sb,this,-1)))
printk("Directory %d: bad FAT\n",
inode->i_ino);
}
}
else {
inode->i_mode = MSDOS_MKMODE(raw_entry->attr,0666 &
......@@ -236,13 +262,17 @@ void msdos_read_inode(struct inode *inode)
inode->i_op = MSDOS_CAN_BMAP(MSDOS_SB(inode->i_sb)) ?
&msdos_file_inode_operations :
&msdos_file_inode_operations_no_bmap;
MSDOS_I(inode)->i_start = raw_entry->start;
inode->i_nlink = 1;
inode->i_size = raw_entry->size;
}
inode->i_data[D_BINARY] = is_binary(MSDOS_SB(inode->i_sb)->conversion,
MSDOS_I(inode)->i_binary = is_binary(MSDOS_SB(inode->i_sb)->conversion,
raw_entry->ext);
inode->i_data[D_START] = raw_entry->start;
inode->i_data[D_ATTRS] = raw_entry->attr & ATTR_UNUSED;
MSDOS_I(inode)->i_attrs = raw_entry->attr & ATTR_UNUSED;
/* this is as close to the truth as we can get ... */
inode->i_blksize = MSDOS_SB(inode->i_sb)->cluster_size*SECTOR_SIZE;
inode->i_blocks = (inode->i_size+inode->i_blksize-1)/
inode->i_blksize;
inode->i_mtime = inode->i_atime = inode->i_ctime =
date_dos2unix(raw_entry->time,raw_entry->date);
brelse(bh);
......@@ -268,8 +298,9 @@ void msdos_write_inode(struct inode *inode)
raw_entry->attr = ATTR_NONE;
raw_entry->size = inode->i_size;
}
raw_entry->attr |= MSDOS_MKATTR(inode->i_mode) | inode->i_data[D_ATTRS];
raw_entry->start = inode->i_data[D_START];
raw_entry->attr |= MSDOS_MKATTR(inode->i_mode) |
MSDOS_I(inode)->i_attrs;
raw_entry->start = MSDOS_I(inode)->i_start;
date_unix2dos(inode->i_mtime,&raw_entry->time,&raw_entry->date);
bh->b_dirt = 1;
brelse(bh);
......
This diff is collapsed.
......@@ -22,6 +22,12 @@ static char *reserved_names[] = {
NULL };
/* Characters that are undesirable in an MS-DOS file name */
static char bad_chars[] = "*?<>|\" ";
static char bad_if_strict[] = "+=,;";
/* Formats an MS-DOS file name. Rejects invalid names. */
static int msdos_format_name(char conv,const char *name,int len,char *res)
......@@ -42,9 +48,10 @@ static int msdos_format_name(char conv,const char *name,int len,char *res)
for (walk = res; len && walk-res < 8; walk++) {
c = get_fs_byte(name++);
len--;
if (c == ' ' && conv != 'r') return -EINVAL;
if (c >= 'A' && c <= 'Z') {
if (conv != 'r') return -EINVAL;
if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
if (c >= 'A' && c <= 'Z') {
if (conv == 's') return -EINVAL;
c += 32;
}
if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
......@@ -65,11 +72,13 @@ static int msdos_format_name(char conv,const char *name,int len,char *res)
while (len > 0 && walk-res < MSDOS_NAME) {
c = get_fs_byte(name++);
len--;
if (c == ' ' && conv != 'r') return -EINVAL;
if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
if (conv == 's' && strchr(bad_if_strict,c))
return -EINVAL;
if (c < ' ' || c == ':' || c == '\\' || c == '.')
return -EINVAL;
if (c >= 'A' && c <= 'Z') {
if (conv != 'r') return -EINVAL;
if (conv == 's') return -EINVAL;
c += 32;
}
space = c == ' ';
......@@ -135,13 +144,13 @@ int msdos_lookup(struct inode *dir,const char *name,int len,
iput(dir);
return -EACCES;
}
if ((*result)->i_data[D_BUSY]) { /* mkdir in progress */
if (MSDOS_I(*result)->i_busy) { /* mkdir in progress */
iput(*result);
iput(dir);
return -ENOENT;
}
while ((*result)->i_data[D_OLD]) {
next = (struct inode *) ((*result)->i_data[D_OLD]);
while (MSDOS_I(*result)->i_old) {
next = MSDOS_I(*result)->i_old;
iput(*result);
if (!(*result = iget(next->i_dev,next->i_ino)))
panic("msdos_lookup: Can't happen");
......@@ -209,6 +218,26 @@ int msdos_create(struct inode *dir,const char *name,int len,int mode,
}
#ifdef DEBUG
static void dump_fat(struct super_block *sb,int start)
{
printk("[");
while (start) {
printk("%d ",start);
start = fat_access(sb,start,-1);
if (!start) {
printk("ERROR");
break;
}
if (start == -1) break;
}
printk("]\n");
}
#endif
int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
{
struct buffer_head *bh;
......@@ -234,21 +263,25 @@ int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
iput(dir);
return res;
}
inode->i_data[D_BUSY] = 1; /* prevent lookups */
dir->i_nlink++;
inode->i_nlink = 2; /* no need to mark them dirty */
MSDOS_I(inode)->i_busy = 1; /* prevent lookups */
if ((res = msdos_add_cluster(inode)) < 0) goto mkdir_error;
if ((res = msdos_create_entry(inode,MSDOS_DOT,1,&dot)) < 0)
goto mkdir_error;
dot->i_size = inode->i_size;
dot->i_data[D_START] = inode->i_data[D_START];
dot->i_size = inode->i_size; /* doesn't grow in the 2nd create_entry */
MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start;
dot->i_nlink = inode->i_nlink;
dot->i_dirt = 1;
iput(dot);
if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,1,&dot)) < 0)
goto mkdir_error;
unlock_creation();
dot->i_size = dir->i_size;
dot->i_data[D_START] = dir->i_data[D_START];
MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
dot->i_nlink = dir->i_nlink;
dot->i_dirt = 1;
inode->i_data[D_BUSY] = 0;
MSDOS_I(inode)->i_busy = 0;
iput(dot);
iput(inode);
iput(dir);
......@@ -271,7 +304,8 @@ int msdos_rmdir(struct inode *dir,const char *name,int len)
bh = NULL;
inode = NULL;
res = -EINVAL;
if (len == 1 && get_fs_byte(name) == '.') goto rmdir_done;
if (get_fs_byte(name) == '.' && (len == 1 || (len == 2 &&
get_fs_byte(name+1) == '.'))) goto rmdir_done;
if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done;
res = -ENOENT;
if (!(inode = iget(dir->i_dev,ino))) goto rmdir_done;
......@@ -280,7 +314,7 @@ int msdos_rmdir(struct inode *dir,const char *name,int len)
res = -EBUSY;
if (dir->i_dev != inode->i_dev || dir == inode) goto rmdir_done;
if (inode->i_count > 1) goto rmdir_done;
if (inode->i_data[D_START]) { /* may be zero in mkdir */
if (MSDOS_I(inode)->i_start) { /* may be zero in mkdir */
res = -ENOTEMPTY;
pos = 0;
dbh = NULL;
......@@ -293,6 +327,7 @@ int msdos_rmdir(struct inode *dir,const char *name,int len)
}
inode->i_nlink = 0;
dir->i_mtime = CURRENT_TIME;
dir->i_nlink--;
inode->i_dirt = dir->i_dirt = 1;
de->name[0] = DELETED_FLAG;
bh->b_dirt = 1;
......@@ -325,7 +360,7 @@ int msdos_unlink(struct inode *dir,const char *name,int len)
goto unlink_done;
}
inode->i_nlink = 0;
inode->i_data[D_BUSY] = 1;
MSDOS_I(inode)->i_busy = 1;
inode->i_dirt = 1;
de->name[0] = DELETED_FLAG;
bh->b_dirt = 1;
......@@ -364,7 +399,7 @@ static int rename_same_dir(struct inode *old_dir,char *old_name,
return -EPERM;
}
new_inode->i_nlink = 0;
new_inode->i_data[D_BUSY] = 1;
MSDOS_I(new_inode)->i_busy = 1;
new_inode->i_dirt = 1;
new_de->name[0] = DELETED_FLAG;
new_bh->b_dirt = 1;
......@@ -432,7 +467,7 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,
return -EPERM;
}
new_inode->i_nlink = 0;
new_inode->i_data[D_BUSY] = 1;
MSDOS_I(new_inode)->i_busy = 1;
new_inode->i_dirt = 1;
new_de->name[0] = DELETED_FLAG;
new_bh->b_dirt = 1;
......@@ -450,15 +485,16 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,
return -EIO;
}
msdos_read_inode(free_inode);
old_inode->i_data[D_BUSY] = 1;
MSDOS_I(old_inode)->i_busy = 1;
cache_inval_inode(old_inode);
old_inode->i_dirt = 1;
old_de->name[0] = DELETED_FLAG;
old_bh->b_dirt = 1;
free_bh->b_dirt = 1;
if (!exists) iput(free_inode);
else {
new_inode->i_data[D_DEPEND] = (int) free_inode;
free_inode->i_data[D_OLD] = (int) new_inode;
MSDOS_I(new_inode)->i_depend = free_inode;
MSDOS_I(free_inode)->i_old = new_inode;
/* free_inode is put when putting new_inode */
iput(new_inode);
brelse(new_bh);
......@@ -471,12 +507,15 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,
error = -EIO;
goto rename_done;
}
dotdot_de->start = dotdot_inode->i_data[D_START] =
new_dir->i_data[D_START];
dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
MSDOS_I(new_dir)->i_start;
dotdot_inode->i_dirt = 1;
dotdot_bh->b_dirt = 1;
iput(dotdot_inode);
brelse(dotdot_bh);
old_dir->i_nlink--;
new_dir->i_nlink++;
/* no need to mark them dirty */
}
error = 0;
rename_done:
......
......@@ -19,7 +19,7 @@
#include <linux/fcntl.h>
#include <linux/stat.h>
#define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE])
#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
/*
* comment out this line if you want names > MINIX_NAME_LEN chars to be
......@@ -200,6 +200,14 @@ int namei(const char * pathname, struct inode ** res_inode)
* open_namei()
*
* namei for open - this is in fact almost the whole open-routine.
*
* Note that the low bits of "flag" aren't the same asin the open
* system call - they are 00 - no permissions needed
* 01 - read permission needed
* 10 - write permission needed
* 11 - read/write permissions needed
* which is a lot more logical, and also allows the "no perm" needed
* for symlinks (where the permissions are checked later).
*/
int open_namei(const char * pathname, int flag, int mode,
struct inode ** res_inode, struct inode * base)
......@@ -209,15 +217,13 @@ int open_namei(const char * pathname, int flag, int mode,
struct inode * dir, *inode;
struct task_struct ** p;
if ((flag & O_TRUNC) && !(flag & O_ACCMODE))
flag |= O_WRONLY;
mode &= 07777 & ~current->umask;
mode |= I_REGULAR;
error = dir_namei(pathname,&namelen,&basename,base,&dir);
if (error)
return error;
if (!namelen) { /* special case: '/usr/' etc */
if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) {
if (!(flag & 2)) {
*res_inode=dir;
return 0;
}
......@@ -252,23 +258,26 @@ int open_namei(const char * pathname, int flag, int mode,
}
if (error = follow_link(dir,inode,flag,mode,&inode))
return error;
if (S_ISDIR(inode->i_mode) && (flag & 2)) {
iput(inode);
return -EPERM;
}
if (!permission(inode,ACC_MODE(flag))) {
iput(inode);
return -EACCES;
}
if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
if (IS_NODEV(inode)) {
iput(inode);
return -EACCES;
}
} else {
if (IS_RDONLY(inode) && (flag & (O_TRUNC | O_ACCMODE))) {
if (IS_RDONLY(inode) && (flag & 2)) {
iput(inode);
return -EROFS;
}
}
if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
!permission(inode,ACC_MODE(flag))) {
iput(inode);
return -EPERM;
}
if ((inode->i_count > 1) && (flag & O_ACCMODE))
if ((inode->i_count > 1) && (flag & 2))
for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
if (!*p)
continue;
......@@ -282,15 +291,6 @@ int open_namei(const char * pathname, int flag, int mode,
return -ETXTBSY;
}
}
if (flag & O_TRUNC)
if (inode->i_op && inode->i_op->truncate) {
inode->i_size = 0;
inode->i_op->truncate(inode);
}
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
}
*res_inode = inode;
return 0;
}
......
......@@ -311,6 +311,20 @@ int sys_chown(const char * filename, uid_t user, gid_t group)
return -EPERM;
}
/*
* Note that while the flag value (low two bits) for sys_open means:
* 00 - read-only
* 01 - write-only
* 10 - read-write
* 11 - special
* it is changed into
* 00 - no permissions needed
* 01 - read-permission
* 10 - write-permission
* 11 - read-write
* for the internal routines (ie open_namei()/follow_link() etc). 00 is
* used by symlinks.
*/
int sys_open(const char * filename,int flag,int mode)
{
struct inode * inode;
......@@ -327,13 +341,26 @@ int sys_open(const char * filename,int flag,int mode)
if (!f)
return -ENFILE;
current->filp[fd] = f;
if ((i = open_namei(filename,flag,mode,&inode,NULL))<0) {
f->f_flags = flag;
if (f->f_mode = (flag+1) & O_ACCMODE)
flag++;
if (flag & (O_TRUNC | O_CREAT))
flag |= 2;
i = open_namei(filename,flag,mode,&inode,NULL);
if (i) {
current->filp[fd]=NULL;
f->f_count--;
return i;
}
f->f_mode = "\001\002\003\000"[flag & O_ACCMODE];
f->f_flags = flag;
if (flag & O_TRUNC)
if (inode->i_op && inode->i_op->truncate) {
inode->i_size = 0;
inode->i_op->truncate(inode);
}
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
}
f->f_inode = inode;
f->f_pos = 0;
f->f_reada = 0;
......
#
# Makefile for the linux proc-filesystem routines.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
# Note 2! The CFLAGS definitions are now in the main makefile...
.c.s:
$(CC) $(CFLAGS) -S $<
.c.o:
$(CC) $(CFLAGS) -c $<
.s.o:
$(AS) -o $*.o $<
OBJS= inode.o root.o base.o mem.o link.o fd.o
proc.o: $(OBJS)
$(LD) -r -o proc.o $(OBJS)
clean:
rm -f core *.o *.a tmp_make
for i in *.c;do rm -f `basename $$i .c`.s;done
dep:
sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
for i in *.c;do $(CPP) -M $$i;done >> tmp_make
cp tmp_make Makefile
### Dependencies:
base.o : base.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/linux/errno.h \
/usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
/usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
/usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_i.h \
/usr/src/linux/include/linux/ext_fs_i.h /usr/src/linux/include/linux/msdos_fs_i.h \
/usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
/usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
/usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
/usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
/usr/src/linux/include/linux/vm86.h /usr/src/linux/include/linux/proc_fs.h /usr/src/linux/include/linux/stat.h
fd.o : fd.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/linux/errno.h \
/usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
/usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
/usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_i.h \
/usr/src/linux/include/linux/ext_fs_i.h /usr/src/linux/include/linux/msdos_fs_i.h \
/usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
/usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
/usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
/usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
/usr/src/linux/include/linux/vm86.h /usr/src/linux/include/linux/proc_fs.h /usr/src/linux/include/linux/stat.h
inode.o : inode.c /usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h \
/usr/src/linux/include/linux/fs.h /usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h \
/usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h \
/usr/src/linux/include/linux/minix_fs_i.h /usr/src/linux/include/linux/ext_fs_i.h \
/usr/src/linux/include/linux/msdos_fs_i.h /usr/src/linux/include/linux/minix_fs_sb.h \
/usr/src/linux/include/linux/ext_fs_sb.h /usr/src/linux/include/linux/msdos_fs_sb.h \
/usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
/usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
/usr/src/linux/include/linux/vm86.h /usr/src/linux/include/linux/proc_fs.h /usr/src/linux/include/linux/string.h \
/usr/src/linux/include/linux/stat.h /usr/src/linux/include/asm/system.h /usr/src/linux/include/asm/segment.h
link.o : link.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/linux/errno.h \
/usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
/usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
/usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_i.h \
/usr/src/linux/include/linux/ext_fs_i.h /usr/src/linux/include/linux/msdos_fs_i.h \
/usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
/usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
/usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
/usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
/usr/src/linux/include/linux/vm86.h /usr/src/linux/include/linux/minix_fs.h \
/usr/src/linux/include/linux/stat.h
mem.o : mem.c /usr/src/linux/include/linux/types.h /usr/src/linux/include/linux/errno.h \
/usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
/usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/dirent.h \
/usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_i.h \
/usr/src/linux/include/linux/ext_fs_i.h /usr/src/linux/include/linux/msdos_fs_i.h \
/usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
/usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
/usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
/usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
/usr/src/linux/include/linux/vm86.h /usr/src/linux/include/asm/segment.h /usr/src/linux/include/asm/io.h
root.o : root.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/linux/errno.h \
/usr/src/linux/include/linux/sched.h /usr/src/linux/include/linux/head.h /usr/src/linux/include/linux/fs.h \
/usr/src/linux/include/linux/limits.h /usr/src/linux/include/linux/wait.h /usr/src/linux/include/linux/types.h \
/usr/src/linux/include/linux/dirent.h /usr/src/linux/include/linux/vfs.h /usr/src/linux/include/linux/minix_fs_i.h \
/usr/src/linux/include/linux/ext_fs_i.h /usr/src/linux/include/linux/msdos_fs_i.h \
/usr/src/linux/include/linux/minix_fs_sb.h /usr/src/linux/include/linux/ext_fs_sb.h \
/usr/src/linux/include/linux/msdos_fs_sb.h /usr/src/linux/include/linux/mm.h \
/usr/src/linux/include/linux/kernel.h /usr/src/linux/include/linux/signal.h \
/usr/src/linux/include/linux/time.h /usr/src/linux/include/linux/param.h /usr/src/linux/include/linux/resource.h \
/usr/src/linux/include/linux/vm86.h /usr/src/linux/include/linux/proc_fs.h /usr/src/linux/include/linux/stat.h
/*
* linux/fs/proc/base.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* proc base directory handling functions
*/
#include <asm/segment.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
static int proc_readbase(struct inode *, struct file *, struct dirent *, int);
static int proc_lookupbase(struct inode *,const char *,int,struct inode **);
static struct file_operations proc_base_operations = {
NULL, /* lseek - default */
NULL, /* read - bad */
NULL, /* write - bad */
proc_readbase, /* readdir */
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* no special open code */
NULL /* no special release code */
};
/*
* proc directories can do almost nothing..
*/
struct inode_operations proc_base_inode_operations = {
&proc_base_operations, /* default base directory file-ops */
NULL, /* create */
proc_lookupbase, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL /* truncate */
};
struct proc_dir_entry {
unsigned short low_ino;
unsigned short namelen;
char * name;
};
static struct proc_dir_entry base_dir[] = {
{ 1,2,".." },
{ 2,1,"." },
{ 3,3,"mem" },
{ 4,3,"cwd" },
{ 5,4,"root" },
{ 6,3,"exe" },
{ 7,2,"fd" },
{ 8,3,"lib" }
};
#define NR_BASE_DIRENTRY ((sizeof (base_dir))/(sizeof (base_dir[0])))
static int proc_match(int len,const char * name,struct proc_dir_entry * de)
{
register int same __asm__("ax");
if (!de || !de->low_ino)
return 0;
/* "" means "." ---> so paths like "/usr/lib//libc.a" work */
if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
return 1;
if (de->namelen != len)
return 0;
__asm__("cld\n\t"
"fs ; repe ; cmpsb\n\t"
"setz %%al"
:"=a" (same)
:"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
:"cx","di","si");
return same;
}
static int proc_lookupbase(struct inode * dir,const char * name, int len,
struct inode ** result)
{
unsigned int pid;
int i, ino;
*result = NULL;
if (!dir)
return -ENOENT;
if (!S_ISDIR(dir->i_mode)) {
iput(dir);
return -ENOENT;
}
ino = dir->i_ino;
pid = ino >> 16;
i = NR_BASE_DIRENTRY;
while (i-- > 0 && !proc_match(len,name,base_dir+i))
/* nothing */;
if (i < 0) {
iput(dir);
return -ENOENT;
}
if (base_dir[i].low_ino == 1)
ino = 1;
else
ino = (pid << 16) + base_dir[i].low_ino;
for (i = 0 ; i < NR_TASKS ; i++)
if (task[i] && task[i]->pid == pid)
break;
if (!pid || i >= NR_TASKS) {
iput(dir);
return -ENOENT;
}
if (!(*result = iget(dir->i_dev,ino))) {
iput(dir);
return -ENOENT;
}
iput(dir);
return 0;
}
static int proc_readbase(struct inode * inode, struct file * filp,
struct dirent * dirent, int count)
{
struct proc_dir_entry * de;
unsigned int pid, ino;
int i,j;
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
ino = inode->i_ino;
pid = ino >> 16;
for (i = 0 ; i < NR_TASKS ; i++)
if (task[i] && task[i]->pid == pid)
break;
if (!pid || i >= NR_TASKS)
return 0;
if (((unsigned) filp->f_pos) < NR_BASE_DIRENTRY) {
de = base_dir + filp->f_pos;
filp->f_pos++;
i = de->namelen;
ino = de->low_ino;
if (ino != 1)
ino |= (pid << 16);
put_fs_long(ino, &dirent->d_ino);
put_fs_word(i,&dirent->d_reclen);
put_fs_byte(0,i+dirent->d_name);
j = i;
while (i--)
put_fs_byte(de->name[i], i+dirent->d_name);
return j;
}
return 0;
}
/*
* linux/fs/proc/fd.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* proc fd directory handling functions
*/
#include <asm/segment.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
static int proc_readfd(struct inode *, struct file *, struct dirent *, int);
static int proc_lookupfd(struct inode *,const char *,int,struct inode **);
static struct file_operations proc_fd_operations = {
NULL, /* lseek - default */
NULL, /* read - bad */
NULL, /* write - bad */
proc_readfd, /* readdir */
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* no special open code */
NULL /* no special release code */
};
/*
* proc directories can do almost nothing..
*/
struct inode_operations proc_fd_inode_operations = {
&proc_fd_operations, /* default base directory file-ops */
NULL, /* create */
proc_lookupfd, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL /* truncate */
};
static int proc_lookupfd(struct inode * dir,const char * name, int len,
struct inode ** result)
{
unsigned int ino, pid, fd, c;
struct task_struct * p;
int i, dev;
*result = NULL;
ino = dir->i_ino;
pid = ino >> 16;
ino &= 0x0000ffff;
ino -= 7;
if (!dir)
return -ENOENT;
if (!pid || ino > 1 || !S_ISDIR(dir->i_mode)) {
iput(dir);
return -ENOENT;
}
if (!len || (get_fs_byte(name) == '.' && (len == 1 ||
(get_fs_byte(name+1) == '.' && len == 2)))) {
if (len < 2) {
*result = dir;
return 0;
}
if (!(*result = iget(dir->i_dev,(pid << 16)+2))) {
iput(dir);
return -ENOENT;
}
iput(dir);
return 0;
}
dev = dir->i_dev;
iput(dir);
fd = 0;
while (len-- > 0) {
c = get_fs_byte(name) - '0';
name++;
if (c > 9) {
fd = 0xfffff;
break;
}
fd *= 10;
fd += c;
if (fd & 0xffff0000) {
fd = 0xfffff;
break;
}
}
for (i = 0 ; i < NR_TASKS ; i++)
if ((p = task[i]) && p->pid == pid)
break;
if (!pid || i >= NR_TASKS)
return -ENOENT;
if (!ino) {
if (fd >= NR_OPEN || !p->filp[fd] || !p->filp[fd]->f_inode)
return -ENOENT;
ino = (pid << 16) + 0x100 + fd;
} else {
if (fd >= p->numlibraries)
return -ENOENT;
ino = (pid << 16) + 0x200 + fd;
}
if (!(*result = iget(dev,ino)))
return -ENOENT;
return 0;
}
static int proc_readfd(struct inode * inode, struct file * filp,
struct dirent * dirent, int count)
{
struct task_struct * p;
unsigned int fd, pid, ino;
int i,j;
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
ino = inode->i_ino;
pid = ino >> 16;
ino &= 0x0000ffff;
ino -= 7;
if (ino > 1)
return 0;
while (1) {
fd = filp->f_pos;
filp->f_pos++;
if (fd < 2) {
i = j = fd+1;
if (!fd)
fd = inode->i_ino;
else
fd = (inode->i_ino & 0xffff0000) | 2;
put_fs_long(fd, &dirent->d_ino);
put_fs_word(i, &dirent->d_reclen);
put_fs_byte(0, i+dirent->d_name);
while (i--)
put_fs_byte('.', i+dirent->d_name);
return j;
}
fd -= 2;
for (i = 1 ; i < NR_TASKS ; i++)
if ((p = task[i]) && p->pid == pid)
break;
if (i >= NR_TASKS)
return 0;
if (!ino) {
if (fd >= NR_OPEN)
break;
if (!p->filp[fd] || !p->filp[fd]->f_inode)
continue;
} else
if (fd >= p->numlibraries)
break;
j = 10;
i = 1;
while (fd >= j) {
j *= 10;
i++;
}
j = i;
if (!ino)
ino = (pid << 16) + 0x100 + fd;
else
ino = (pid << 16) + 0x200 + fd;
put_fs_long(ino, &dirent->d_ino);
put_fs_word(i, &dirent->d_reclen);
put_fs_byte(0, i+dirent->d_name);
while (i--) {
put_fs_byte('0'+(fd % 10), i+dirent->d_name);
fd /= 10;
}
return j;
}
return 0;
}
/*
* linux/fs/proc/inode.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <asm/system.h>
#include <asm/segment.h>
void proc_put_inode(struct inode *inode)
{
inode->i_size = 0;
}
void proc_put_super(struct super_block *sb)
{
lock_super(sb);
sb->s_dev = 0;
free_super(sb);
}
static struct super_operations proc_sops = {
proc_read_inode,
proc_write_inode,
proc_put_inode,
proc_put_super,
NULL,
proc_statfs
};
struct super_block *proc_read_super(struct super_block *s,void *data)
{
int dev=s->s_dev;
lock_super(s);
s->s_blocksize = 1024;
s->s_magic = PROC_SUPER_MAGIC;
s->s_dev = dev;
s->s_op = &proc_sops;
free_super(s);
if (!(s->s_mounted = iget(dev,PROC_ROOT_INO))) {
s->s_dev=0;
printk("get root inode failed\n");
return NULL;
}
return s;
}
void proc_statfs(struct super_block *sb, struct statfs *buf)
{
put_fs_long(PROC_SUPER_MAGIC, &buf->f_type);
put_fs_long(1024, &buf->f_bsize);
put_fs_long(0, &buf->f_blocks);
put_fs_long(0, &buf->f_bfree);
put_fs_long(0, &buf->f_bavail);
put_fs_long(0, &buf->f_files);
put_fs_long(0, &buf->f_ffree);
/* Don't know what value to put in buf->f_fsid */
}
int proc_bmap(struct inode * inode,int block)
{
return 0;
}
int proc_create_block(struct inode * inode, int block)
{
return 0;
}
void proc_read_inode(struct inode * inode)
{
unsigned long ino, pid;
struct task_struct * p;
int i;
inode->i_op = NULL;
inode->i_mode = 0;
inode->i_uid = 0;
inode->i_gid = 0;
inode->i_nlink = 1;
inode->i_size = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_blocks = inode->i_blksize = 0;
ino = inode->i_ino;
pid = ino >> 16;
p = task[0];
for (i = 0; i < NR_TASKS ; i++)
if ((p = task[i]) && (p->pid == pid))
break;
if (!p || i >= NR_TASKS)
return;
if (ino == PROC_ROOT_INO) {
inode->i_mode = S_IFDIR | 0555;
inode->i_op = &proc_root_inode_operations;
return;
}
if (!pid)
return;
ino &= 0x0000ffff;
inode->i_uid = p->euid;
inode->i_gid = p->egid;
switch (ino) {
case 2:
inode->i_nlink = 2;
for (i = 1 ; i < NR_TASKS ; i++)
if (task[i])
inode->i_nlink++;
inode->i_mode = S_IFDIR | 0500;
inode->i_op = &proc_base_inode_operations;
return;
case 3:
inode->i_op = &proc_mem_inode_operations;
inode->i_mode = S_IFCHR | 0600;
inode->i_rdev = 0x0101;
return;
case 4:
case 5:
case 6:
inode->i_op = &proc_link_inode_operations;
inode->i_size = 3;
inode->i_mode = S_IFLNK | 0700;
return;
case 7:
case 8:
inode->i_mode = S_IFDIR | 0500;
inode->i_op = &proc_fd_inode_operations;
inode->i_nlink = 2;
return;
}
switch (ino >> 8) {
case 1:
ino &= 0xff;
if (ino >= NR_OPEN || !p->filp[ino])
return;
inode->i_op = &proc_link_inode_operations;
inode->i_size = 3;
inode->i_mode = S_IFLNK | 0700;
return;
case 2:
ino &= 0xff;
if (ino >= p->numlibraries)
return;
inode->i_op = &proc_link_inode_operations;
inode->i_size = 3;
inode->i_mode = S_IFLNK | 0700;
return;
}
return;
}
void proc_write_inode(struct inode * inode)
{
inode->i_dirt=0;
}
/*
* linux/fs/proc/link.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* /proc link-file handling code
*/
#include <asm/segment.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/minix_fs.h>
#include <linux/stat.h>
static int proc_readlink(struct inode *, char *, int);
static int proc_follow_link(struct inode *, struct inode *, int, int, struct inode **);
/*
* links can't do much...
*/
struct inode_operations proc_link_inode_operations = {
NULL, /* no file-operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
proc_readlink, /* readlink */
proc_follow_link, /* follow_link */
NULL, /* bmap */
NULL /* truncate */
};
static int proc_follow_link(struct inode * dir, struct inode * inode,
int flag, int mode, struct inode ** res_inode)
{
unsigned int pid, ino;
struct task_struct * p;
int i;
*res_inode = NULL;
if (dir)
iput(dir);
if (!inode)
return -ENOENT;
ino = inode->i_ino;
pid = ino >> 16;
ino &= 0x0000ffff;
iput(inode);
for (i = 0 ; i < NR_TASKS ; i++)
if ((p = task[i]) && p->pid == pid)
break;
if (i >= NR_TASKS)
return -ENOENT;
inode = NULL;
switch (ino) {
case 4:
inode = p->pwd;
break;
case 5:
inode = p->root;
break;
case 6:
inode = p->executable;
break;
default:
switch (ino >> 8) {
case 1:
ino &= 0xff;
if (ino < NR_OPEN && p->filp[ino])
inode = p->filp[ino]->f_inode;
break;
case 2:
ino &= 0xff;
if (ino < p->numlibraries)
inode = p->libraries[ino].library;
}
}
if (!inode)
return -ENOENT;
*res_inode = inode;
inode->i_count++;
return 0;
}
static int proc_readlink(struct inode * inode, char * buffer, int buflen)
{
int i;
iput(inode);
if (buflen > 3)
buflen = 3;
i = 0;
while (i++ < buflen)
put_fs_byte('-',buffer++);
return i;
}
/*
* linux/fs/proc/mem.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
#include <asm/io.h>
static int mem_read(struct inode * inode, struct file * file,char * buf, int count)
{
unsigned long addr, pid, cr3;
char *tmp;
unsigned long pde, pte, page;
int i;
if (count < 0)
return -EINVAL;
pid = inode->i_ino;
pid >>= 16;
cr3 = 0;
for (i = 1 ; i < NR_TASKS ; i++)
if (task[i] && task[i]->pid == pid) {
cr3 = task[i]->tss.cr3;
break;
}
if (!cr3)
return -EACCES;
addr = file->f_pos;
tmp = buf;
while (count > 0) {
if (current->signal & ~current->blocked)
break;
pde = cr3 + (addr >> 20 & 0xffc);
pte = *(unsigned long *) pde;
if (!(pte & PAGE_PRESENT))
break;
pte &= 0xfffff000;
pte += (addr >> 10) & 0xffc;
page = *(unsigned long *) pte;
if (!(page & 1))
break;
page &= 0xfffff000;
page += addr & 0xfff;
i = 4096-(addr & 0xfff);
if (i > count)
i = count;
memcpy_tofs(tmp,(void *) page,i);
addr += i;
tmp += i;
count -= i;
}
file->f_pos = addr;
return tmp-buf;
}
static int mem_write(struct inode * inode, struct file * file,char * buf, int count)
{
unsigned long addr, pid, cr3;
char *tmp;
unsigned long pde, pte, page;
int i;
if (count < 0)
return -EINVAL;
addr = file->f_pos;
pid = inode->i_ino;
pid >>= 16;
cr3 = 0;
for (i = 1 ; i < NR_TASKS ; i++)
if (task[i] && task[i]->pid == pid) {
cr3 = task[i]->tss.cr3;
break;
}
if (!cr3)
return -EACCES;
tmp = buf;
while (count > 0) {
if (current->signal & ~current->blocked)
break;
pde = cr3 + (addr >> 20 & 0xffc);
pte = *(unsigned long *) pde;
if (!(pte & PAGE_PRESENT))
break;
pte &= 0xfffff000;
pte += (addr >> 10) & 0xffc;
page = *(unsigned long *) pte;
if (!(page & PAGE_PRESENT))
break;
if (!(page & 2)) {
do_wp_page(0,addr,current,0);
continue;
}
page &= 0xfffff000;
page += addr & 0xfff;
i = 4096-(addr & 0xfff);
if (i > count)
i = count;
memcpy_fromfs((void *) page,tmp,i);
addr += i;
tmp += i;
count -= i;
}
file->f_pos = addr;
if (tmp != buf)
return tmp-buf;
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
return 0;
}
static int mem_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
{
switch (orig) {
case 0:
file->f_pos = offset;
return file->f_pos;
case 1:
file->f_pos += offset;
return file->f_pos;
default:
return -EINVAL;
}
if (file->f_pos < 0)
return 0;
return file->f_pos;
}
static struct file_operations proc_mem_operations = {
mem_lseek,
mem_read,
mem_write,
NULL, /* mem_readdir */
NULL, /* mem_select */
NULL, /* mem_ioctl */
NULL, /* no special open code */
NULL /* no special release code */
};
struct inode_operations proc_mem_inode_operations = {
&proc_mem_operations, /* default base directory file-ops */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL /* truncate */
};
/*
* linux/fs/proc/root.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* proc root directory handling functions
*/
#include <asm/segment.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
static int proc_readroot(struct inode *, struct file *, struct dirent *, int);
static int proc_lookuproot(struct inode *,const char *,int,struct inode **);
static struct file_operations proc_root_operations = {
NULL, /* lseek - default */
NULL, /* read - bad */
NULL, /* write - bad */
proc_readroot, /* readdir */
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* no special open code */
NULL /* no special release code */
};
/*
* proc directories can do almost nothing..
*/
struct inode_operations proc_root_inode_operations = {
&proc_root_operations, /* default base directory file-ops */
NULL, /* create */
proc_lookuproot, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL /* truncate */
};
static int proc_lookuproot(struct inode * dir,const char * name, int len,
struct inode ** result)
{
unsigned int pid, c;
int i, ino;
*result = NULL;
if (!dir)
return -ENOENT;
if (!S_ISDIR(dir->i_mode)) {
iput(dir);
return -ENOENT;
}
pid = 0;
if (!len || (get_fs_byte(name) == '.' && (len == 1 ||
(get_fs_byte(name+1) == '.' && len == 2)))) {
*result = dir;
return 0;
}
while (len-- > 0) {
c = get_fs_byte(name) - '0';
name++;
if (c > 9) {
pid = 0;
break;
}
pid *= 10;
pid += c;
if (pid & 0xffff0000) {
pid = 0;
break;
}
}
for (i = 0 ; i < NR_TASKS ; i++)
if (task[i] && task[i]->pid == pid)
break;
if (!pid || i >= NR_TASKS) {
iput(dir);
return -ENOENT;
}
ino = (pid << 16) + 2;
if (!(*result = iget(dir->i_dev,ino))) {
iput(dir);
return -ENOENT;
}
iput(dir);
return 0;
}
static int proc_readroot(struct inode * inode, struct file * filp,
struct dirent * dirent, int count)
{
struct task_struct * p;
unsigned int pid;
int i,j;
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
while ((pid = filp->f_pos) < NR_TASKS+2) {
filp->f_pos++;
if (pid < 2) {
i = j = pid+1;
put_fs_long(1, &dirent->d_ino);
put_fs_word(i, &dirent->d_reclen);
put_fs_byte(0, i+dirent->d_name);
while (i--)
put_fs_byte('.', i+dirent->d_name);
return j;
}
p = task[pid-2];
if (!p || !(pid = p->pid))
continue;
if (pid & 0xffff0000)
continue;
j = 10;
i = 1;
while (pid >= j) {
j *= 10;
i++;
}
j = i;
put_fs_long((pid << 16)+2, &dirent->d_ino);
put_fs_word(i, &dirent->d_reclen);
put_fs_byte(0, i+dirent->d_name);
while (i--) {
put_fs_byte('0'+(pid % 10), i+dirent->d_name);
pid /= 10;
}
return j;
}
return 0;
}
......@@ -10,6 +10,7 @@
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/proc_fs.h>
#include <linux/ext_fs.h>
#include <linux/msdos_fs.h>
#include <linux/kernel.h>
......@@ -39,6 +40,7 @@ static struct file_system_type file_systems[] = {
{minix_read_super,"minix"},
{ext_read_super,"ext"},
{msdos_read_super,"msdos"},
{proc_read_super,"proc"},
{NULL,NULL}
};
......
......@@ -110,7 +110,7 @@ void BAD_IRQ_NAME(nr); \
__asm__( \
"\n.align 2\n" \
"_IRQ" #nr "_interrupt:\n\t" \
"pushl $-1\n\t" \
"pushl $-"#nr"-2\n\t" \
SAVE_ALL \
ACK_##chip(mask) \
"sti\n\t" \
......
......@@ -5,6 +5,7 @@
* user data space). This is NOT a bug, as any user program that changes
* es deserves to die if it isn't careful.
*/
#if 0
#define memcpy(dest,src,n) ({ \
void * _res = dest; \
__asm__ __volatile__ ("cld;rep;movsb" \
......@@ -12,3 +13,27 @@ __asm__ __volatile__ ("cld;rep;movsb" \
:"di","si","cx"); \
_res; \
})
#else
/* this is basically memcpy_tofs. It should be faster.
I've reorder it. This should be a little faster. -RAB */
#define memcpy(dest, src, n) f_memcpy(dest, src, n)
extern inline void * f_memcpy(void * to, void * from, unsigned long n)
{
__asm__("cld\n\t"
"movl %%edx, %%ecx\n\t"
"shrl $2,%%ecx\n\t"
"rep ; movsl\n\t"
"testb $1,%%dl\n\t"
"je 1f\n\t"
"movsb\n"
"1:\ttestb $2,%%dl\n\t"
"je 2f\n\t"
"movsw\n"
"2:\n"
::"d" (n),"D" ((long) to),"S" ((long) from)
: "cx","di","si");
return (to);
}
#endif
#ifndef _LINUX_BUSMOUSE_H
#define _LINUX_BUSMOUSE_H
/*
* linux/include/linux/mouse.h: header file for Logitech Bus Mouse driver
* by James Banks
*
* based on information gleamed from various mouse drivers on the net
*
* Heavily modified by David giller (rafetmad@oxy.edu)
*
* Minor modifications for Linux 0.96c-pl1 by Nathan Laredo
* gt7080a@prism.gatech.edu (13JUL92)
*
*/
#define MOUSE_IRQ 5
#define MSE_DATA_PORT 0x23c
#define MSE_SIGNATURE_PORT 0x23d
#define MSE_CONTROL_PORT 0x23e
#define MSE_INTERRUPT_PORT 0x23e
#define MSE_CONFIG_PORT 0x23f
#define MSE_ENABLE_INTERRUPTS 0x00
#define MSE_DISABLE_INTERRUPTS 0x10
#define MSE_READ_X_LOW 0x80
#define MSE_READ_X_HIGH 0xa0
#define MSE_READ_Y_LOW 0xc0
#define MSE_READ_Y_HIGH 0xe0
/* Magic number used to check if the mouse exists */
#define MSE_CONFIG_BYTE 0x91
#define MSE_DEFAULT_MODE 0x90
#define MSE_SIGNATURE_BYTE 0xa5
/* useful macros */
#define MSE_INT_OFF() outb(MSE_DISABLE_INTERRUPTS, MSE_CONTROL_PORT)
#define MSE_INT_ON() outb(MSE_ENABLE_INTERRUPTS, MSE_CONTROL_PORT)
struct mouse_status
{
char buttons;
char latch_buttons;
int dx;
int dy;
int present;
int ready;
int active;
struct inode *inode;
};
/* Function Prototypes */
extern long mouse_init(long);
#endif
......@@ -12,15 +12,11 @@
#ifndef UTS_NODENAME
#define UTS_NODENAME "(none)" /* set by sethostname() */
#endif
#include <linux/config_rel.h>
#ifndef UTS_RELEASE
#define UTS_RELEASE "0.95c-0"
#endif
#include <linux/config_ver.h>
#ifndef UTS_VERSION
#define UTS_VERSION "mm/dd/yy"
#endif
#define UTS_MACHINE "i386" /* hardware type */
/*
* The definitions for UTS_RELEASE and UTS_VERSION are now defined
* in linux/version.h, and should only be used by linux/version.c
*/
/* Don't touch these, unless you really know what your doing. */
#define DEF_INITSEG 0x9000
......
......@@ -89,7 +89,9 @@ extern void buffer_init(void);
#define BLKROSET 4701 /* set device read-only (0 = read-write) */
#define BLKROGET 4702 /* get read-only status (0 = read_write) */
#define BMAP_IOCTL 1
#define BMAP_IOCTL 1 /* obsolete - kept for compatibility */
#define FIBMAP 1 /* bmap access */
#define FIGETBSZ 2 /* get the block size used for bmap */
typedef char buffer_block[BLOCK_SIZE];
......
......@@ -66,9 +66,11 @@ extern int minix_new_block(int dev);
extern int minix_free_block(int dev, int block);
extern unsigned long minix_count_free_blocks(struct super_block *sb);
extern int minix_create_block(struct inode *, int);
extern int minix_bmap(struct inode *,int);
extern struct buffer_head * minix_getblk(struct inode *, int, int);
extern struct buffer_head * minix_bread(struct inode *, int, int);
extern void minix_truncate(struct inode *);
extern void minix_put_super(struct super_block *);
extern struct super_block *minix_read_super(struct super_block *,void *);
......
......@@ -2,6 +2,7 @@
#define _LINUX_MM_H
#define PAGE_SIZE 4096
#define PAGE_SHIFT 12
#include <linux/fs.h>
#include <linux/kernel.h>
......@@ -42,10 +43,14 @@ extern unsigned long inline __bad_pagetable(void)
}
#define BAD_PAGETABLE __bad_pagetable()
extern unsigned int swap_device;
extern struct inode * swap_file;
extern volatile short free_page_ptr; /* used by malloc and tcp/ip. */
extern int nr_free_pages;
extern unsigned long free_page_list;
extern int nr_secondary_pages;
extern unsigned long secondary_page_list;
#define MAX_SECONDARY_PAGES 10
extern void rw_swap_page(int rw, unsigned int nr, char * buf);
......@@ -73,27 +78,29 @@ extern void do_wp_page(unsigned long error_code, unsigned long address,
extern void do_no_page(unsigned long error_code, unsigned long address,
struct task_struct *tsk, unsigned long user_esp);
extern unsigned long mem_init(unsigned long start_mem, unsigned long end_mem);
extern void mem_init(unsigned long low_start_mem,
unsigned long start_mem, unsigned long end_mem);
extern void show_mem(void);
extern void do_page_fault(unsigned long *esp, unsigned long error_code);
extern void oom(struct task_struct * task);
extern void malloc_grab_pages(void);
/* swap.c */
extern void swap_free(unsigned int page_nr);
extern void swap_duplicate(unsigned int page_nr);
extern void swap_in(unsigned long *table_ptr);
#define invalidate() \
__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3":::"ax")
extern unsigned long low_memory;
extern unsigned long high_memory;
extern unsigned long paging_pages;
#define MAP_NR(addr) (((addr)-low_memory)>>12)
#define MAP_NR(addr) ((addr) >> PAGE_SHIFT)
#define MAP_PAGE_RESERVED (1<<15)
#define USED 100
extern unsigned char * mem_map;
extern unsigned short * mem_map;
#define PAGE_DIRTY 0x40
#define PAGE_ACCESSED 0x20
......@@ -102,7 +109,8 @@ extern unsigned char * mem_map;
#define PAGE_PRESENT 0x01
#define GFP_BUFFER 0x00
#define GFP_USER 0x01
#define GFP_KERNEL 0x02
#define GFP_ATOMIC 0x01
#define GFP_USER 0x02
#define GFP_KERNEL 0x03
#endif
#ifndef _LINUX_MOUSE_H
#if !defined _LINUX_MOUSE_H
#define _LINUX_MOUSE_H
/*
* linux/include/linux/mouse.h: header file for Logitech Bus Mouse driver
* by James Banks
*
* based on information gleamed from various mouse drivers on the net
*
* Heavily modified by David giller (rafetmad@oxy.edu)
*
* Minor modifications for Linux 0.96c-pl1 by Nathan Laredo
* gt7080a@prism.gatech.edu (13JUL92)
*
*/
#define BUSMOUSE_MINOR 0
#define PSMOUSE_MINOR 1
#define MOUSE_IRQ 5
#define MSE_DATA_PORT 0x23c
#define MSE_SIGNATURE_PORT 0x23d
#define MSE_CONTROL_PORT 0x23e
#define MSE_INTERRUPT_PORT 0x23e
#define MSE_CONFIG_PORT 0x23f
#define MSE_ENABLE_INTERRUPTS 0x00
#define MSE_DISABLE_INTERRUPTS 0x10
#define MSE_READ_X_LOW 0x80
#define MSE_READ_X_HIGH 0xa0
#define MSE_READ_Y_LOW 0xc0
#define MSE_READ_Y_HIGH 0xe0
/* Magic number used to check if the mouse exists */
#define MSE_CONFIG_BYTE 0x91
#define MSE_DEFAULT_MODE 0x90
#define MSE_SIGNATURE_BYTE 0xa5
/* useful macros */
#define MSE_INT_OFF() outb(MSE_DISABLE_INTERRUPTS, MSE_CONTROL_PORT)
#define MSE_INT_ON() outb(MSE_ENABLE_INTERRUPTS, MSE_CONTROL_PORT)
struct mouse_status
{
char buttons;
char latch_buttons;
int dx;
int dy;
int present;
int ready;
int active;
struct inode *inode;
};
/* Function Prototypes */
extern long mouse_init(long);
long mouse_init(long);
#endif
......@@ -33,17 +33,8 @@
#define DELETED_FLAG 0xe5 /* marks file as deleted when in name[0] */
#define D_START 0 /* i_data[0]: first cluster or 0 */
#define D_ATTRS 1 /* i_data[1]: unused attribute bits */
#define D_BUSY 2 /* i_data[2]: file is either deleted but still open, or
inconsistent (mkdir) */
#define D_DEPEND 3 /* i_data[3]: pointer to inode that depends on the current
inode */
#define D_OLD 4 /* i_data[4]: pointer to the old inode this inode depends
on */
#define D_BINARY 5 /* i_data[5]: file contains non-text data */
#define MSDOS_SB(s) (&((s)->u.msdos_sb))
#define MSDOS_I(i) (&((i)->u.msdos_i))
#define MSDOS_NAME 11 /* maximum name length */
#define MSDOS_DOT ". " /* ".", padded to MSDOS_NAME chars */
......@@ -112,6 +103,8 @@ static inline struct buffer_head *msdos_sread(int dev,int sector,void **start)
extern int is_binary(char conversion,char *extension);
extern void lock_creation(void);
extern void unlock_creation(void);
extern void lock_fat(struct super_block *sb);
extern void unlock_fat(struct super_block *sb);
extern int msdos_add_cluster(struct inode *inode);
extern int date_dos2unix(unsigned short time,unsigned short date);
extern void date_unix2dos(int unix_date,unsigned short *time,
......@@ -121,6 +114,7 @@ extern int msdos_get_entry(struct inode *dir,int *pos,struct buffer_head **bh,
extern int msdos_scan(struct inode *dir,char *name,struct buffer_head **res_bh,
struct msdos_dir_entry **res_de,int *ino);
extern int msdos_parent_ino(struct inode *dir,int locked);
extern int msdos_subdirs(struct inode *dir);
/* fat.c */
......
......@@ -5,6 +5,15 @@
* msdos file system inode data in memory
*/
struct msdos_inode_info {
int i_start; /* first cluster or 0 */
int i_attrs; /* unused attribute bits */
int i_busy; /* file is either deleted but still open, or
inconsistent (mkdir) */
struct inode *i_depend; /* pointer to inode that depends on the
current inode */
struct inode *i_old; /* pointer to the old inode this inode
depends on */
int i_binary; /* file contains non-text data */
};
#endif
#ifndef _MSDOS_FS_SB
#define _MSDOS_FS_SB
struct msdos_sb_info { /* space in struct super_block is 28 bytes */
struct msdos_sb_info {
unsigned short cluster_size; /* sectors/cluster */
unsigned char fats,fat_bits; /* number of FATs, FAT bits (12 or 16) */
unsigned short fat_start,fat_length; /* FAT start & length (sec.) */
......@@ -13,6 +13,9 @@ struct msdos_sb_info { /* space in struct super_block is 28 bytes */
unsigned short fs_umask;
unsigned char name_check; /* r = relaxed, n = normal, s = strict */
unsigned char conversion; /* b = binary, t = text, a = auto */
struct wait_queue *fat_wait;
int fat_lock;
int free_clusters; /* -1 if undefined */
};
#endif
#ifndef _LINUX_PROC_FS_H
#define _LINUX_PROC_FS_H
/*
* The proc filesystem constants/structures
*/
#define PROC_ROOT_INO 1
#define PROC_SUPER_MAGIC 0x9fa0
extern struct super_block *proc_read_super(struct super_block *,void *);
extern void proc_put_inode(struct inode *);
extern void proc_put_super(struct super_block *);
extern void proc_statfs(struct super_block *, struct statfs *);
extern void proc_read_inode(struct inode *);
extern void proc_write_inode(struct inode *);
extern struct inode_operations proc_root_inode_operations;
extern struct inode_operations proc_base_inode_operations;
extern struct inode_operations proc_mem_inode_operations;
extern struct inode_operations proc_link_inode_operations;
extern struct inode_operations proc_fd_inode_operations;
#endif
......@@ -14,6 +14,7 @@
*/
#define RUSAGE_SELF 0
#define RUSAGE_CHILDREN -1
#define RUSAGE_BOTH -2 /* sys_wait4() uses this */
struct rusage {
struct timeval ru_utime; /* user time used */
......
......@@ -19,6 +19,28 @@
*/
#define IO_BITMAP_SIZE 32
/*
* These are the constant used to fake the fixed-point load-average
* counting. Some notes:
* - 11 bit fractions expand to 22 bits by the multiplies: this gives
* a load-average precision of 10 bits integer + 11 bits fractional
* - if you want to count load-averages more often, you need more
* precision, or rounding will get you. With 2-second counting freq,
* the EXP_n values would be 1981, 2034 and 2043 if still using only
* 11 bit fractions.
*/
#define FSHIFT 11 /* nr of bits of precision */
#define FIXED_1 (1<<FSHIFT) /* 1.0 as fixed-point */
#define LOAD_FREQ (5*HZ) /* 5 sec intervals */
#define EXP_1 1884 /* 1/exp(5sec/1min) as fixed-point */
#define EXP_5 2014 /* 1/exp(5sec/5min) */
#define EXP_15 2037 /* 1/exp(5sec/15min) */
#define CALC_LOAD(load,exp,n) \
load *= exp; \
load += n*(FIXED_1-exp); \
load >>= FSHIFT;
#define CT_TO_SECS(x) ((x) / HZ)
#define CT_TO_USECS(x) (((x) % HZ) * 1000000/HZ)
......
/* ip.h */
/* Contains the structures for communicating with the ip level of the
sockets. Currently just for configuration. */
#ifndef _LINUX_SOCK_IOCTL_H
#define _LINUX_SOCK_IOCTL_H
#define MAX_IP_NAME 20
/* some ioctl. Their values are not special. */
#define IP_SET_DEV 0x2401
#define IP_ADD_ROUTE 0x2402
#define IP_HANDOFF 0x2403
struct ip_config
{
char name[MAX_IP_NAME];
unsigned long paddr;
unsigned long router;
unsigned long net;
unsigned long up:1;
};
#endif
......@@ -14,6 +14,10 @@ struct sockaddr {
#define SOCK_RAW 3 /* raw socket */
#define SOCK_RDM 4 /* reliably-delivered message */
#define SOCK_SEQPACKET 5 /* sequential packet socket */
#define SOCK_PACKET 10 /* linux specific way of getting
packets at the dev level. For
writing rarp and other similiar
things on the user level. */
/*
* supported address families
......@@ -42,6 +46,8 @@ struct sockaddr {
#define SO_SNDBUF 7
#define SO_RCVBUF 8
#define SO_KEEPALIVE 9
#define SO_OOBINLINE 10
#define SO_NO_CHECK 11
/* setsockoptions level */
#define SOL_SOCKET 1
......
......@@ -116,6 +116,8 @@ extern int sys_iopl();
extern int sys_vhangup();
extern int sys_idle();
extern int sys_vm86();
extern int sys_wait4();
extern int sys_swapoff();
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,
......@@ -138,7 +140,7 @@ 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_idle, sys_vm86 };
sys_idle, sys_vm86, sys_wait4, sys_swapoff };
/* So we don't have to do any more manual updating.... */
int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
......@@ -120,6 +120,8 @@
#define __NR_vhangup 111
#define __NR_idle 112
#define __NR_vm86 113
#define __NR_wait4 114
#define __NR_swapoff 115
extern int errno;
......
......@@ -21,4 +21,6 @@ struct new_utsname {
char machine[65];
};
extern struct new_utsname system_utsname;
#endif
......@@ -21,6 +21,7 @@
extern unsigned long * prof_buffer;
extern unsigned long prof_len;
extern int end;
extern char *linux_banner;
/*
* we need this inline - forking from kernel space will result
......@@ -63,6 +64,7 @@ extern void floppy_init(void);
extern void sock_init(void);
extern long rd_init(long mem_start, int length);
extern long kernel_mktime(struct tm * tm);
extern void malloc_grab_pages(void);
#ifdef CONFIG_SCSI
extern void scsi_dev_init(void);
......@@ -86,6 +88,7 @@ static int sprintf(char * str, const char *fmt, ...)
#define DRIVE_INFO (*(struct drive_info *)0x90080)
#define SCREEN_INFO (*(struct screen_info *)0x90000)
#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC)
#define AUX_DEVICE_INFO (*(unsigned char *)0x901FF)
/*
* Yeah, yeah, it's ugly, but I cannot find how to do this correctly
......@@ -123,8 +126,10 @@ static void time_init(void)
startup_time = kernel_mktime(&time);
}
static unsigned long memory_start = 0;
static unsigned long memory_start = 0; /* After mem_init, stores the */
/* amount of free user memory */
static unsigned long memory_end = 0;
static unsigned long low_memory_start = 0;
static char term[32];
......@@ -140,6 +145,8 @@ static char * envp[] = { "HOME=/usr/root", NULL, NULL };
struct drive_info { char dummy[32]; } drive_info;
struct screen_info screen_info;
unsigned char aux_device_present;
void start_kernel(void)
{
/*
......@@ -149,6 +156,7 @@ void start_kernel(void)
ROOT_DEV = ORIG_ROOT_DEV;
drive_info = DRIVE_INFO;
screen_info = SCREEN_INFO;
aux_device_present = AUX_DEVICE_INFO;
sprintf(term, "TERM=con%dx%d", ORIG_VIDEO_COLS, ORIG_VIDEO_LINES);
envp[1] = term;
envp_rc[1] = term;
......@@ -158,6 +166,9 @@ void start_kernel(void)
if (memory_end > 16*1024*1024)
memory_end = 16*1024*1024;
memory_start = 1024*1024;
low_memory_start = (unsigned long) &end;
low_memory_start += 0xfff;
low_memory_start &= 0xfffff000;
trap_init();
init_IRQ();
sched_init();
......@@ -169,11 +180,11 @@ void start_kernel(void)
#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);
mem_init(low_memory_start,memory_start,memory_end);
buffer_init();
time_init();
printk("Linux version " UTS_RELEASE " " __DATE__ " " __TIME__ "\n");
floppy_init();
malloc_grab_pages();
sock_init();
sti();
#ifdef CONFIG_SCSI
......@@ -215,10 +226,8 @@ void init(void)
(void) open("/dev/tty1",O_RDWR,0);
(void) dup(0);
(void) dup(0);
printf("%d buffers = %d bytes buffer space\n\r",nr_buffers,
nr_buffers*BLOCK_SIZE);
printf("Free mem: %d bytes\n\r",memory_end-memory_start);
printf(linux_banner);
execve("/etc/init",argv_init,envp_init);
execve("/bin/init",argv_init,envp_init);
/* if this fails, fall through to original stuff */
......
......@@ -191,7 +191,7 @@ static int keep_data[4] = { 0,0,0,0 };
* Announce successful media type detection and media information loss after
* disk changes.
*/
static ftd_msg[4] = { 1,1,1,1 };
static ftd_msg[4] = { 0,0,0,0 };
/* Prevent "aliased" accesses. */
......@@ -1008,12 +1008,15 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
switch (cmd) {
RO_IOCTLS(inode->i_rdev,param);
}
if (!suser()) return -EPERM;
drive = MINOR(inode->i_rdev);
switch (cmd) {
case FDFMTBEG:
if (!suser())
return -EPERM;
return 0;
case FDFMTEND:
if (!suser())
return -EPERM;
cli();
fake_change |= 1 << (drive & 3);
sti();
......@@ -1030,6 +1033,8 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
(char *) param+cnt);
return 0;
case FDFMTTRK:
if (!suser())
return -EPERM;
cli();
while (format_status != FORMAT_NONE)
sleep_on(&format_done);
......@@ -1056,7 +1061,10 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
wake_up(&format_done);
return okay ? 0 : -EIO;
}
if (drive < 0 || drive > 3) return -EINVAL;
if (!suser())
return -EPERM;
if (drive < 0 || drive > 3)
return -EINVAL;
switch (cmd) {
case FDCLRPRM:
current_type[drive] = NULL;
......
......@@ -17,7 +17,7 @@
$(CC) $(CFLAGS) -c $<
OBJS = tty_io.o console.o keyboard.o serial.o \
tty_ioctl.o pty.o lp.o vt.o mem.o mouse.o
tty_ioctl.o pty.o lp.o vt.o mem.o mouse.o busmouse.o psaux.o
chr_drv.a: $(OBJS)
$(AR) rcs chr_drv.a $(OBJS)
......
/*
* Logitech Bus Mouse Driver for Linux
* by James Banks
*
* Heavily modified by David Giller
* changed from queue- to counter- driven
* hacked out a (probably incorrect) mouse_select
*
* Modified again by Nathan Laredo to interface with
* 0.96c-pl1 IRQ handling changes (13JUL92)
* didn't bother touching select code.
*
* Modified the select() code blindly to conform to the VFS
* requirements. 92.07.14 - Linus. Somebody should test it out.
*
* Modified by Johan Myreen to make room for other mice (9AUG92)
* removed assignment chr_fops[10] = &mouse_fops; see mouse.c
* renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public.
* renamed this file mouse.c => busmouse.c
*
* version 0.1
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/busmouse.h>
#include <linux/tty.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <asm/io.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/irq.h>
static struct mouse_status mouse;
static void mouse_interrupt(int unused)
{
char dx, dy, buttons;
MSE_INT_OFF();
outb(MSE_READ_X_LOW, MSE_CONTROL_PORT);
dx = (inb(MSE_DATA_PORT) & 0xf);
outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT);
dx |= (inb(MSE_DATA_PORT) & 0xf) << 4;
outb(MSE_READ_Y_LOW, MSE_CONTROL_PORT );
dy = (inb(MSE_DATA_PORT) & 0xf);
outb(MSE_READ_Y_HIGH, MSE_CONTROL_PORT);
buttons = inb(MSE_DATA_PORT);
dy |= (buttons & 0xf) << 4;
buttons = ((buttons >> 5) & 0x07);
mouse.buttons = buttons;
mouse.latch_buttons |= buttons;
mouse.dx += dx;
mouse.dy += dy;
mouse.ready = 1;
if (mouse.inode && mouse.inode->i_wait)
wake_up(&mouse.inode->i_wait);
MSE_INT_ON();
}
static void release_mouse(struct inode * inode, struct file * file)
{
MSE_INT_OFF();
mouse.active = 0;
mouse.ready = 0;
mouse.inode = NULL;
free_irq(MOUSE_IRQ);
}
static int open_mouse(struct inode * inode, struct file * file)
{
if (mouse.active)
return -EBUSY;
if (!mouse.present)
return -EINVAL;
mouse.active = 1;
mouse.ready = 0;
mouse.inode = inode;
mouse.dx = 0;
mouse.dy = 0;
mouse.buttons = mouse.latch_buttons = 0x80;
if (request_irq(MOUSE_IRQ, mouse_interrupt)) {
/* 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;
}
static int write_mouse(struct inode * inode, struct file * file, char * buffer, int count)
{
return -EINVAL;
}
static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count)
{
int i;
if (count < 3) return -EINVAL;
if (!mouse.ready) return -EAGAIN;
MSE_INT_OFF();
put_fs_byte(mouse.latch_buttons | 0x80, buffer);
if (mouse.dx < -127) mouse.dx = -127;
if (mouse.dx > 127) mouse.dx = 127;
put_fs_byte((char)mouse.dx, buffer + 1);
if (mouse.dy < -127) mouse.dy = -127;
if (mouse.dy > 127) mouse.dy = 127;
put_fs_byte((char) -mouse.dy, buffer + 2);
for (i = 3; i < count; i++)
put_fs_byte(0x00, buffer + i);
mouse.dx = 0;
mouse.dy = 0;
mouse.latch_buttons = mouse.buttons;
mouse.ready = 0;
MSE_INT_ON();
return i;
}
static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
{
if (sel_type != SEL_IN)
return 0;
if (mouse.ready)
return 1;
select_wait(&inode->i_wait,wait);
return 0;
}
struct file_operations bus_mouse_fops = {
NULL, /* mouse_seek */
read_mouse,
write_mouse,
NULL, /* mouse_readdir */
mouse_select, /* mouse_select */
NULL, /* mouse_ioctl */
open_mouse,
release_mouse,
};
long bus_mouse_init(long kmem_start)
{
int i;
outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT);
outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT);
for (i = 0; i < 100000; i++); /* busy loop */
if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) {
printk("No bus mouse detected.\n");
mouse.present = 0;
return kmem_start;
}
outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT);
MSE_INT_OFF();
mouse.present = 1;
mouse.active = 0;
mouse.ready = 0;
mouse.buttons = mouse.latch_buttons = 0x80;
mouse.dx = 0;
mouse.dy = 0;
printk("Bus mouse detected and installed.\n");
return kmem_start;
}
......@@ -25,88 +25,6 @@ static int write_ram(struct inode * inode, struct file * file,char * buf, int co
}
static int read_mem(struct inode * inode, struct file * file,char * buf, int count)
{
unsigned long addr;
char *tmp;
unsigned long pde, pte, page;
int i;
if (count < 0)
return -EINVAL;
addr = file->f_pos;
tmp = buf;
while (count > 0) {
if (current->signal & ~current->blocked)
break;
pde = current->tss.cr3 + (addr >> 20 & 0xffc);
pte = *(unsigned long *) pde;
if (!(pte & PAGE_PRESENT))
break;
pte &= 0xfffff000;
pte += (addr >> 10) & 0xffc;
page = *(unsigned long *) pte;
if (!(page & 1))
break;
page &= 0xfffff000;
page += addr & 0xfff;
i = 4096-(addr & 0xfff);
if (i > count)
i = count;
memcpy_tofs(tmp,(void *) page,i);
addr += i;
tmp += i;
count -= i;
}
file->f_pos = addr;
return tmp-buf;
}
static int write_mem(struct inode * inode, struct file * file,char * buf, int count)
{
unsigned long addr;
char *tmp;
unsigned long pde, pte, page;
int i;
if (count < 0)
return -EINVAL;
addr = file->f_pos;
tmp = buf;
while (count > 0) {
if (current->signal & ~current->blocked)
break;
pde = current->tss.cr3 + (addr >> 20 & 0xffc);
pte = *(unsigned long *) pde;
if (!(pte & PAGE_PRESENT))
break;
pte &= 0xfffff000;
pte += (addr >> 10) & 0xffc;
page = *(unsigned long *) pte;
if (!(page & PAGE_PRESENT))
break;
if (!(page & 2)) {
do_wp_page(0,addr,current,0);
continue;
}
page &= 0xfffff000;
page += addr & 0xfff;
i = 4096-(addr & 0xfff);
if (i > count)
i = count;
memcpy_fromfs((void *) page,tmp,i);
addr += i;
tmp += i;
count -= i;
}
file->f_pos = addr;
if (tmp != buf)
return tmp-buf;
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
return 0;
}
static int read_kmem(struct inode * inode, struct file * file,char * buf, int count)
{
unsigned long p = file->f_pos;
......@@ -121,7 +39,7 @@ static int read_kmem(struct inode * inode, struct file * file,char * buf, int co
return count;
}
static int write_kmem(struct inode * inode, struct file * file,char * buf, int count)
static int write_mem(struct inode * inode, struct file * file,char * buf, int count)
{
unsigned long p = file->f_pos;
......@@ -200,6 +118,9 @@ static int mem_lseek(struct inode * inode, struct file * file, off_t offset, int
return file->f_pos;
}
#define read_kmem read_mem
#define write_kmem write_mem
static int mem_read(struct inode * inode, struct file * file, char * buf, int count)
{
switch (MINOR(inode->i_rdev)) {
......
/*
* Logitech Bus Mouse Driver for Linux
* by James Banks
*
* Heavily modified by David Giller
* changed from queue- to counter- driven
* hacked out a (probably incorrect) mouse_select
* linux/kernel/chr_drv/mouse.c
*
* Modified again by Nathan Laredo to interface with
* 0.96c-pl1 IRQ handling changes (13JUL92)
* didn't bother touching select code.
* Generic mouse open routine by Johan Myreen
*
* Modified the select() code blindly to conform to the VFS
* requirements. 92.07.14 - Linus. Somebody should test it out.
*
* version 0.1
* Based on code from Linus
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mouse.h>
#include <linux/tty.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mouse.h>
#include <asm/io.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/irq.h>
extern struct file_operations bus_mouse_fops;
extern struct file_operations psaux_fops;
extern long bus_mouse_init(long);
extern long psaux_init(long);
static struct mouse_status mouse;
static void mouse_interrupt(int unused)
{
char dx, dy, buttons;
MSE_INT_OFF();
outb(MSE_READ_X_LOW, MSE_CONTROL_PORT);
dx = (inb(MSE_DATA_PORT) & 0xf);
outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT);
dx |= (inb(MSE_DATA_PORT) & 0xf) << 4;
outb(MSE_READ_Y_LOW, MSE_CONTROL_PORT );
dy = (inb(MSE_DATA_PORT) & 0xf);
outb(MSE_READ_Y_HIGH, MSE_CONTROL_PORT);
buttons = inb(MSE_DATA_PORT);
dy |= (buttons & 0xf) << 4;
buttons = ((buttons >> 5) & 0x07);
mouse.buttons = buttons;
mouse.latch_buttons |= buttons;
mouse.dx += dx;
mouse.dy += dy;
mouse.ready = 1;
if (mouse.inode && mouse.inode->i_wait)
wake_up(&mouse.inode->i_wait);
MSE_INT_ON();
}
static void release_mouse(struct inode * inode, struct file * file)
{
MSE_INT_OFF();
mouse.active = 0;
mouse.ready = 0;
mouse.inode = NULL;
free_irq(MOUSE_IRQ);
}
static int open_mouse(struct inode * inode, struct file * file)
{
if (mouse.active)
return -EBUSY;
if (!mouse.present)
return -EINVAL;
mouse.active = 1;
mouse.ready = 0;
mouse.inode = inode;
mouse.dx = 0;
mouse.dy = 0;
mouse.buttons = mouse.latch_buttons = 0x80;
if (request_irq(MOUSE_IRQ, mouse_interrupt)) {
/* 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;
}
static int write_mouse(struct inode * inode, struct file * file, char * buffer, int count)
{
return -EINVAL;
}
static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count)
static int mouse_open(struct inode * inode, struct file * file)
{
int i;
if (count < 3) return -EINVAL;
if (!mouse.ready) return -EAGAIN;
MSE_INT_OFF();
put_fs_byte(mouse.latch_buttons | 0x80, buffer);
if (mouse.dx < -127) mouse.dx = -127;
if (mouse.dx > 127) mouse.dx = 127;
put_fs_byte((char)mouse.dx, buffer + 1);
if (mouse.dy < -127) mouse.dy = -127;
if (mouse.dy > 127) mouse.dy = 127;
put_fs_byte((char) -mouse.dy, buffer + 2);
for (i = 3; i < count; i++)
put_fs_byte(0x00, buffer + i);
mouse.dx = 0;
mouse.dy = 0;
mouse.latch_buttons = mouse.buttons;
mouse.ready = 0;
MSE_INT_ON();
return i;
}
static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
{
if (sel_type != SEL_IN)
return 0;
if (mouse.ready)
return 1;
select_wait(&inode->i_wait,wait);
return 0;
if (MINOR(inode->i_rdev) == BUSMOUSE_MINOR)
file->f_op = &bus_mouse_fops;
else if (MINOR(inode->i_rdev) == PSMOUSE_MINOR)
file->f_op = &psaux_fops;
else
return -ENODEV;
return file->f_op->open(inode,file);
}
static struct file_operations mouse_fops = {
NULL, /* mouse_seek */
read_mouse,
write_mouse,
NULL, /* mouse_readdir */
mouse_select, /* mouse_select */
NULL, /* mouse_ioctl */
open_mouse,
release_mouse,
NULL, /* seek */
NULL, /* read */
NULL, /* write */
NULL, /* readdir */
NULL, /* select */
NULL, /* ioctl */
mouse_open,
NULL /* release */
};
long mouse_init(long kmem_start)
{
int i;
outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT);
outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT);
for (i = 0; i < 100000; i++); /* busy loop */
if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) {
printk("No bus mouse detected.\n");
mouse.present = 0;
return kmem_start;
}
{
kmem_start = bus_mouse_init(kmem_start);
kmem_start = psaux_init(kmem_start);
chrdev_fops[10] = &mouse_fops;
outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT);
MSE_INT_OFF();
mouse.present = 1;
mouse.active = 0;
mouse.ready = 0;
mouse.buttons = mouse.latch_buttons = 0x80;
mouse.dx = 0;
mouse.dy = 0;
printk("Bus mouse detected and installed.\n");
return kmem_start;
}
/*
* linux/kernel/chr_drv/psaux.c
*
* Driver for PS/2 type mouse by Johan Myreen.
*
* Supports pointing devices attached to a PS/2 type
* Keyboard and Auxiliary Device Controller.
*
*/
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
#include <asm/io.h>
#include <asm/segment.h>
#include <asm/system.h>
#define AUX_INPUT_PORT 0x60 /* Aux device output buffer */
#define AUX_OUTPUT_PORT 0x60 /* Aux device input buffer */
#define AUX_COMMAND 0x64 /* Aux device command buffer */
#define AUX_STATUS 0x64 /* Aux device status reg */
#define MAX_RETRIES 3
#define AUX_IRQ 12
#define AUX_BUF_SIZE 2048
extern unsigned char aux_device_present;
struct aux_queue {
unsigned long head;
unsigned long tail;
struct wait_queue *proc_list;
unsigned char buf[AUX_BUF_SIZE];
};
static struct aux_queue *queue;
static int aux_ready = 0;
static int aux_busy = 0;
static int aux_present = 0;
static int poll_status(void);
static unsigned int get_from_queue()
{
unsigned int result;
unsigned long flags;
__asm__ __volatile__ ("pushfl ; popl %0; cli":"=r" (flags));
result = queue->buf[queue->tail];
queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
__asm__ __volatile__ ("pushl %0 ; popfl"::"r" (flags));
return result;
}
static inline int queue_empty()
{
return queue->head == queue->tail;
}
/*
* Interrupt from the auxiliary device: a character
* is waiting in the keyboard/aux controller.
*/
static void aux_interrupt(int cpl)
{
int head = queue->head;
int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
queue->buf[head] = inb(AUX_INPUT_PORT);
if (head != maxhead) {
head++;
head &= AUX_BUF_SIZE-1;
}
queue->head = head;
aux_ready = 1;
wake_up(&queue->proc_list);
}
static void release_aux(struct inode * inode, struct file * file)
{
poll_status();
outb_p(0xa7,AUX_COMMAND); /* Disable Aux device */
poll_status();
outb_p(0x60,AUX_COMMAND);
poll_status();
outb_p(0x65,AUX_OUTPUT_PORT);
free_irq(AUX_IRQ);
aux_busy = 0;
}
/*
* Install interrupt handler.
* Enable auxiliary device.
*/
static int open_aux(struct inode * inode, struct file * file)
{
if (aux_busy)
return -EBUSY;
if (!aux_present)
return -EINVAL;
if (!poll_status())
return -EBUSY;
aux_busy = 1;
queue->head = queue->tail = 0; /* Flush input queue */
if (request_irq(AUX_IRQ, aux_interrupt))
return -EBUSY;
outb_p(0x60,AUX_COMMAND); /* Write command */
poll_status();
outb_p(0x47,AUX_OUTPUT_PORT); /* Enable AUX and keyb interrupts */
poll_status();
outb_p(0xa8,AUX_COMMAND); /* Enable AUX */
return 0;
}
/*
* Write to the aux device.
*/
static int write_aux(struct inode * inode, struct file * file, char * buffer, int count)
{
int i = count;
while (i--) {
if (!poll_status())
return -EIO;
outb_p(0xd4,AUX_COMMAND);
if (!poll_status())
return -EIO;
outb_p(get_fs_byte(buffer++),AUX_OUTPUT_PORT);
}
inode->i_mtime = CURRENT_TIME;
return count;
}
/*
* Put bytes from input queue to buffer.
*/
static int read_aux(struct inode * inode, struct file * file, char * buffer, int count)
{
int i = count;
unsigned char c;
if (queue_empty()) {
if (file->f_flags & O_NONBLOCK)
return -EWOULDBLOCK;
cli();
interruptible_sleep_on(&queue->proc_list);
sti();
}
while (i > 0 && !queue_empty()) {
c = get_from_queue();
put_fs_byte(c, buffer++);
i--;
}
aux_ready = !queue_empty();
if (count-i) {
inode->i_atime = CURRENT_TIME;
return count-i;
}
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
return 0;
}
static int aux_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
{
if (sel_type != SEL_IN)
return 0;
if (aux_ready)
return 1;
select_wait(&queue->proc_list, wait);
return 0;
}
struct file_operations psaux_fops = {
NULL, /* seek */
read_aux,
write_aux,
NULL, /* readdir */
aux_select,
NULL, /* ioctl */
open_aux,
release_aux,
};
long psaux_init(long kmem_start)
{
if (aux_device_present != 0xaa) {
printk("No PS/2 type pointing device detected.\n");
return kmem_start;
}
printk("PS/2 type pointing device detected and installed.\n");
queue = (struct aux_queue *) kmem_start;
kmem_start += sizeof (struct aux_queue);
queue->head = queue->tail = 0;
queue->proc_list = 0;
aux_present = 1;
return kmem_start;
}
static int poll_status(void)
{
int retries=0;
while ((inb(AUX_STATUS)&0x03) && retries++ < MAX_RETRIES) {
if (inb_p(AUX_STATUS)&0x01)
inb_p(AUX_INPUT_PORT);
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + 5;
schedule();
}
return !(retries==MAX_RETRIES);
}
......@@ -735,7 +735,7 @@ long tty_init(long kmem_start)
0, 0, 0, 0, 0,
0,
0,
{25,80,0,0},
{24,80,0,0},
rs_write,
NULL, /* other-tty */
rs_queues+0+i*3,rs_queues+1+i*3,rs_queues+2+i*3
......@@ -754,7 +754,7 @@ long tty_init(long kmem_start)
0, 0, 0, 0, 0,
0,
0,
{25,80,0,0},
{24,80,0,0},
mpty_write,
spty_table+i,
mpty_queues+0+i*3,mpty_queues+1+i*3,mpty_queues+2+i*3
......@@ -771,7 +771,7 @@ long tty_init(long kmem_start)
0, 0, 0, 0, 0,
0,
0,
{25,80,0,0},
{24,80,0,0},
spty_write,
mpty_table+i,
spty_queues+0+i*3,spty_queues+1+i*3,spty_queues+2+i*3
......
......@@ -11,12 +11,14 @@
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/resource.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <asm/segment.h>
int sys_close(int fd);
void getrusage(struct task_struct *, int, struct rusage *);
int send_sig(long sig,struct task_struct * p,int priv)
{
......@@ -435,7 +437,7 @@ int sys_exit(int error_code)
do_exit((error_code&0xff)<<8);
}
int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
int sys_wait4(pid_t pid,unsigned long * stat_addr, int options, struct rusage * ru)
{
int flag;
struct task_struct *p;
......@@ -467,12 +469,16 @@ int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
put_fs_long((p->exit_code << 8) | 0x7f,
stat_addr);
p->exit_code = 0;
if (ru != NULL)
getrusage(p, RUSAGE_BOTH, ru);
return p->pid;
case TASK_ZOMBIE:
current->cutime += p->utime + p->cutime;
current->cstime += p->stime + p->cstime;
current->cmin_flt += p->min_flt + p->cmin_flt;
current->cmaj_flt += p->maj_flt + p->cmaj_flt;
if (ru != NULL)
getrusage(p, RUSAGE_BOTH, ru);
flag = p->pid;
if (stat_addr)
put_fs_long(p->exit_code, stat_addr);
......@@ -507,3 +513,12 @@ int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
}
return -ECHILD;
}
/*
* sys_waitpid() remains for compatibility. waitpid() should be
* implemented by calling sys_wait4() from libc.a.
*/
int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
{
return sys_wait4(pid, stat_addr, options, NULL);
}
......@@ -115,7 +115,7 @@ static struct sigaction irq_sigaction[16] = {
/*
* do_IRQ handles IRQ's that have been installed without the
* SA_INTERRUPT flag: it uses the full signal-handling return
* and runs with other interrupts disabled. All relatively slow
* and runs with other interrupts enabled. All relatively slow
* IRQ's should use this format: notably the keyboard/timer
* routines.
*/
......@@ -136,7 +136,7 @@ int do_fast_IRQ(int irq)
{
struct sigaction * sa = irq + irq_sigaction;
sa->sa_handler(0);
sa->sa_handler(irq);
return 0; /* re-enable the irq when returning */
}
......
......@@ -356,36 +356,44 @@ void add_timer(long jiffies, void (*fn)(void))
sti();
}
#define FSHIFT 11
#define FSCALE (1<<FSHIFT)
unsigned long timer_active = 0;
struct timer_struct timer_table[32];
/*
* Constants for averages over 1, 5, and 15 minutes
* when sampling at 5 second intervals.
* Hmm.. Changed this, as the GNU make sources (load.c) seems to
* imply that avenrun[] is the standard name for this kind of thing.
* Nothing else seems to be standardized: the fractional size etc
* all seem to differ on different machines.
*/
static unsigned long cexp[3] = {
1884, /* 0.9200444146293232 * FSCALE, exp(-1/12) */
2014, /* 0.9834714538216174 * FSCALE, exp(-1/60) */
2037, /* 0.9944598480048967 * FSCALE, exp(-1/180) */
};
unsigned long averunnable[3] = { 0, }; /* fixed point numbers */
unsigned long avenrun[3] = { 0,0,0 };
void update_avg(void)
/*
* Nr of active tasks - counted in fixed-point numbers
*/
static unsigned long count_active_tasks(void)
{
int i, n=0;
struct task_struct **p;
unsigned long nr = 0;
for(p = &LAST_TASK; p > &FIRST_TASK; --p)
if (*p && ((*p)->state == TASK_RUNNING ||
(*p)->state == TASK_UNINTERRUPTIBLE))
++n;
for (i = 0; i < 3; ++i)
averunnable[i] = (cexp[i] * averunnable[i] +
n * FSCALE * (FSCALE - cexp[i])) >> FSHIFT;
if (*p && (*p)->state == TASK_RUNNING)
nr += FIXED_1;
return nr;
}
unsigned long timer_active = 0;
struct timer_struct timer_table[32];
static inline void calc_load(void)
{
unsigned long active_tasks; /* fixed-point */
static int count = LOAD_FREQ;
if (count-- > 0)
return;
count = LOAD_FREQ;
active_tasks = count_active_tasks();
CALC_LOAD(avenrun[0], EXP_1, active_tasks);
CALC_LOAD(avenrun[1], EXP_5, active_tasks);
CALC_LOAD(avenrun[2], EXP_15, active_tasks);
}
/*
* The int argument is really a (struct pt_regs *), in case the
......@@ -398,9 +406,9 @@ static void do_timer(struct pt_regs * regs)
unsigned long mask;
struct timer_struct *tp = timer_table+0;
struct task_struct ** task_p;
static int avg_cnt = 0;
jiffies++;
calc_load();
if ((VM_MASK & regs->eflags) || (3 & regs->cs)) {
current->utime++;
/* Update ITIMER_VIRT for current task if not in a system call */
......@@ -419,10 +427,6 @@ static void do_timer(struct pt_regs * regs)
}
#endif
}
if (--avg_cnt < 0) {
avg_cnt = 500;
update_avg();
}
if (current == task[0] || (--current->counter)<=0) {
current->counter=0;
need_resched = 1;
......
......@@ -136,7 +136,7 @@ int do_signal(long signr,struct pt_regs * regs)
unsigned long * tmp_esp;
sa_handler = (unsigned long) sa->sa_handler;
if ((regs->orig_eax != -1) &&
if ((regs->orig_eax >= 0) &&
((regs->eax == -ERESTARTSYS) || (regs->eax == -ERESTARTNOINTR))) {
if ((sa_handler > 1) && (regs->eax == -ERESTARTSYS) &&
(sa->sa_flags & SA_INTERRUPT))
......@@ -180,9 +180,10 @@ int do_signal(long signr,struct pt_regs * regs)
case SIGFPE:
case SIGSEGV:
if (core_dump(signr,regs))
do_exit(signr|0x80);
signr |= 0x80;
/* fall through */
default:
current->signal |= 1<<((signr & 0x7f)-1);
do_exit(signr);
}
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -50,12 +50,12 @@ mmap_chr(unsigned long addr, size_t len, int prot, int flags,
minor = MINOR(inode->i_rdev);
/*
* for character devices, only /dev/mem may be mapped. when the
* for character devices, only /dev/[k]mem may be mapped. when the
* swapping code is modified to allow arbitrary sources of pages,
* then we can open it up to regular files.
*/
if (major != 1 || minor != 1)
if (major != 1 || (minor != 1 && minor != 2))
return (caddr_t)-ENODEV;
/*
......
This diff is collapsed.
......@@ -23,7 +23,7 @@ SOCK_FLAGS =# -DINET_SOCKETS
OBJS = socket.o unix.o
net.o: $(OBJS) subdirs
$(LD) -r -o net.o $(OBJS) #tcp/tcpip.o
$(LD) -r -o net.o $(OBJS)# tcp/tcpip.o
subdirs: dummy
......
......@@ -566,7 +566,7 @@ sock_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen)
if (!(newsock = sock_alloc(0))) {
printk("sys_accept: no more sockets\n");
return -EINVAL;
return -EAGAIN;
}
newsock->type = sock->type;
newsock->ops = sock->ops;
......@@ -583,7 +583,7 @@ sock_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen)
if ( i < 0)
{
sock_release (newsock);
sys_close (fd);
return (i);
}
......
/*
* linux/version.c
*
* Copyright (C) 1992 Theodore Ts'o
*
* May be freely distributed as part of Linux.
*/
#include <linux/config.h>
#include <linux/utsname.h>
#include "./version.h"
struct new_utsname system_utsname = {
UTS_SYSNAME, UTS_NODENAME, UTS_RELEASE, UTS_VERSION, UTS_MACHINE
};
char *linux_banner =
"Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
LINUX_COMPILE_HOST ") " UTS_VERSION " " LINUX_COMPILE_TIME " \n";
#define UTS_RELEASE "0.97.pl3-34"
#define UTS_VERSION "09/05/92"
#define LINUX_COMPILE_TIME "17:58:09"
#define LINUX_COMPILE_BY "root"
#define LINUX_COMPILE_HOST "home"
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