Commit ddc733f4 authored by Linus Torvalds's avatar Linus Torvalds

[PATCH] Linux-0.97 (August 1, 1992)

Move <xxx.h> to <linux/xxxx.h>

Variable-sized buffer blocks and dynamic buffer cache allocation. The VM
knows how to shrink it automatically!

Add support for "fast" interrupt handlers for serial lines.

Update copyrights to say 1992 too.

Remove broken VESA video card handling.

Separate out partition handling code ("genhd").

Make init unkillable.

Norwegian keyboard map.

Future Domain SCSI controller driver by Rik Faith.

Changes in 0.97:

 - The VESA-support was removed.  I'd be happy to put it back once it
   works on all hardware.  Instead of the VESA-code, I finally put in
   the automatic SVGA setup patches.  See the top-level Makefile.

 - The IRQ code has solidified, and should work on all machines.  Not
   all of the SCSI drivers use it yet, so I expect patches for that..

 - Serial interrupts are handled slightly differently, and performance
   should be up.  I've sent out a few alpha-releases, and testing seems
   to indicate that's actually true this time.  Reactions have ranged
   from "nice" to "wonderful" :-)

 - The buffer-cache and memory management code has been edited quite a
   bit.  ps/free etc programs that reads kernel memory directly no
   longer work, and even a recompilation won't be enough.  They actually
   need editing before they work.

   The buffer-cache now grows and shrinks dynamically depending on how
   much free memory there is.  Shift+PrintScreen will give some memory
   statistics.  (Ctrl+PrSc gives task-info, ALT+PrSc gives current
   register values).

   The mm code changes removed some race-conditions in the VM code, and
   I also tried to make the Out-of-swapspace error less severe (better
   thrashing-detection etc).

 - The super-block code has been cleaned up.  Especially the extended fs
   needs to be edited a bit to take advantage of the new setup, and I
   expect Remy Card will have a patch out eventually.

 - include-files have been moved around some more: there are still some
   names that clash with the standard headers, but not many.

 - Unswappable processes implemented: by default only 'init' is
   unswappable.  This is a bit safer in low-memory conditions, as at
   least init won't die due to low memory.  I also made killing init
   impossible: if init doesn't recognize a signal, it simply won't get
   it.  Some other changes ("while (1) fork();" won't kill the machine
   for non-root users etc)

 - The new SCSI drivers are in.  These make the kernel noticeably
   bigger, but you can leave them out if you don't want them.

 - The floppy- and hd-drivers print out more debugging-info in case of
   errors: this might be irritating if you have hardware that works, but
   often gives soft-errors.  On the other hand, some old debugging-info
   was removed - notably for user-level protection errors etc.

 - Various minor fixes.  I haven't made cdiffs (and I haven't gotten any
   requests for them, so I probably never will), but they would be
   pretty big.

Things that I didn't have time for:

 - I wanted to rewrite the tty drivers to be more "streams-like" (ie not
   an actual streams-implementation, but some of the ideas from
   streams).  I never got around to it: there was simply too much else
   to do.

 - I got a lot of patches, and some went in, others didn't.  If you
   think your patch was important, please re-send it relative to the new
   version.

I'd like comments on the new system: performance / clarity of code etc.
0.97 should correct all known bugs (at least the ones I know about), but
I guess that's just wishful thinking.

Note that the dynamic buffer-code also handles differently-sized
buffers, but that the rest of the system (block device drivers,
filesystem code etc) cannot yet take advantage of this - there is still
some coding needed.

		Linus
parent d1e6fdb2
#
# comment this line if you don't want the emulation-code
# ROOT_DEV specifies the default root-device when making the image.
# This can be either FLOPPY, /dev/xxxx or empty, in which case the
# default of FLOPPY is used by 'build'.
#
MATH_EMULATION = -DKERNEL_MATH_EMULATION
ROOT_DEV = /dev/hdb1
#
# uncomment the correct keyboard:
#
KEYBOARD = -DKBD_FINNISH
# KEYBOARD = -DKBD_US
# KEYBOARD = -DKBD_GR
# KEYBOARD = -DKBD_FR
# KEYBOARD = -DKBD_UK
# KEYBOARD = -DKBD_DK
#
# uncomment this line if you are using gcc-1.40
#
#GCC_OPT = -fcombine-regs -fstrength-reduce
# The value of KBDFLAGS should be or'ed together from the following
# bits, depending on which features you want enabled.
# 0x80 - Off: the Alt key will set bit 7 if pressed together with
# another key.
# On: the Alt key will NOT set the high bit; an escape
# character is prepended instead.
# The least significant bits control if the following keys are "dead".
# The key is dead by default if the bit is on.
# 0x01 - backquote (`)
# 0x02 - accent acute
# 0x04 - circumflex (^)
# 0x08 - tilde (~)
# 0x10 - dieresis (umlaut)
KEYBOARD = -DKBD_FINNISH -DKBDFLAGS=0
# KEYBOARD = -DKBD_FINNISH_LATIN1 -DKBDFLAGS=0x9F
# KEYBOARD = -DKBD_US -DKBDFLAGS=0
# KEYBOARD = -DKBD_GR -DKBDFLAGS=0
# KEYBOARD = -DKBD_GR_LATIN1 -DKBDFLAGS=0x9F
# KEYBOARD = -DKBD_FR -DKBDFLAGS=0
# KEYBOARD = -DKBD_FR_LATIN1 -DKBDFLAGS=0x9F
# KEYBOARD = -DKBD_UK -DKBDFLAGS=0
# KEYBOARD = -DKBD_DK -DKBDFLAGS=0
# KEYBOARD = -DKBD_DK_LATIN1 -DKBDFLAGS=0x9F
# KEYBOARD = -DKBD_DVORAK -DKBDFLAGS=0
# KEYBOARD = -DKBD_SG -DKBDFLAGS=0
# KEYBOARD = -DKBD_SG_LATIN1 -DKBDFLAGS=0x9F
# KEYBOARD = -DKDB_NO
#
# standard CFLAGS
# comment this line if you don't want the emulation-code
#
CFLAGS =-Wall -O6 -fomit-frame-pointer $(GCC_OPT)
MATH_EMULATION = -DKERNEL_MATH_EMULATION
#
# ROOT_DEV specifies the default root-device when making the image.
# This can be either FLOPPY, /dev/xxxx or empty, in which case the
# default of FLOPPY is used by 'build'.
# standard CFLAGS
#
ROOT_DEV = /dev/hdb1
CFLAGS =-Wall -O6 -fomit-frame-pointer
#
# if you want the ram-disk device, define this to be the
......@@ -44,34 +60,47 @@ ROOT_DEV = /dev/hdb1
AS86 =as86 -0 -a
LD86 =ld86 -0
#
# If you want to preset the SVGA mode, uncomment the next line and
# set SVGA_MODE to whatever number you want.
# Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode.
# The number is the same as you would ordinarily press at bootup.
#
#SVGA_MODE= -DSVGA_MODE=1
AS =as
LD =ld
#LDFLAGS =-s -x -M
LDFLAGS = -M
CC =gcc $(RAMDISK)
MAKE =make CFLAGS="$(CFLAGS)"
CPP =cpp -nostdinc -Iinclude
ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o
FILESYSTEMS =fs/minix/minix.o
DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a
HOSTCC =gcc -static
CC =gcc -nostdinc -I$(KERNELHDRS)
MAKE =make
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
DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a \
kernel/blk_drv/scsi/scsi.a
MATH =kernel/math/math.a
LIBS =lib/lib.a
SUBDIRS =kernel mm fs net lib
KERNELHDRS =/usr/src/linux/include
.c.s:
$(CC) $(CFLAGS) \
-nostdinc -Iinclude -S -o $*.s $<
$(CC) $(CFLAGS) -S $<
.s.o:
$(AS) -c -o $*.o $<
.c.o:
$(CC) $(CFLAGS) \
-nostdinc -Iinclude -c -o $*.o $<
$(CC) $(CFLAGS) -c -o $*.o $<
all: Version Image
linuxsubdirs: dummy
@for i in $(SUBDIRS); do (cd $$i; echo $$i; $(MAKE)) || exit; done
Version:
@./makever.sh
@echo \#define UTS_RELEASE \"0.95c-`cat .version`\" > include/linux/config_rel.h
@echo \#define UTS_RELEASE \"0.97-`cat .version`\" > include/linux/config_rel.h
@echo \#define UTS_VERSION \"`date +%D`\" > include/linux/config_ver.h
touch include/linux/config.h
......@@ -83,54 +112,29 @@ Image: boot/bootsect boot/setup tools/system tools/build
sync
disk: Image
dd bs=8192 if=Image of=/dev/PS0
dd bs=8192 if=Image of=/dev/fd0
tools/build: tools/build.c
$(CC) -static $(CFLAGS) \
$(HOSTCC) $(CFLAGS) \
-o tools/build tools/build.c
boot/head.o: boot/head.s
tools/system: boot/head.o init/main.o \
$(ARCHIVES) $(FILESYSTEMS) $(DRIVERS) $(MATH) $(LIBS)
$(LD) $(LDFLAGS) boot/head.o init/main.o \
$(ARCHIVES) \
$(FILESYSTEMS) \
$(DRIVERS) \
$(MATH) \
$(LIBS) \
-o tools/system > System.map
kernel/math/math.a: dummy
(cd kernel/math; $(MAKE) MATH_EMULATION="$(MATH_EMULATION)")
kernel/blk_drv/blk_drv.a: dummy
(cd kernel/blk_drv; $(MAKE))
kernel/chr_drv/chr_drv.a: dummy
(cd kernel/chr_drv; $(MAKE) KEYBOARD="$(KEYBOARD)")
kernel/kernel.o: dummy
(cd kernel; $(MAKE))
mm/mm.o: dummy
(cd mm; $(MAKE))
fs/fs.o: dummy
(cd fs; $(MAKE))
fs/minix/minix.o: dummy
(cd fs/minix; $(MAKE))
lib/lib.a: dummy
(cd lib; $(MAKE))
tools/system: boot/head.o init/main.o linuxsubdirs
$(LD) $(LDFLAGS) -M boot/head.o init/main.o \
$(ARCHIVES) \
$(FILESYSTEMS) \
$(DRIVERS) \
$(MATH) \
$(LIBS) \
-o tools/system > System.map
boot/setup: boot/setup.s
$(AS86) -o boot/setup.o boot/setup.s
$(LD86) -s -o boot/setup boot/setup.o
boot/setup.s: boot/setup.S include/linux/config.h
$(CPP) -traditional boot/setup.S -o boot/setup.s
$(CPP) -traditional $(SVGA_MODE) boot/setup.S -o boot/setup.s
boot/bootsect.s: boot/bootsect.S include/linux/config.h
$(CPP) -traditional boot/bootsect.S -o boot/bootsect.s
......@@ -139,35 +143,36 @@ boot/bootsect: boot/bootsect.s
$(AS86) -o boot/bootsect.o boot/bootsect.s
$(LD86) -s -o boot/bootsect boot/bootsect.o
fs: dummy
$(MAKE) linuxsubdirs SUBDIRS=fs
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
(cd mm;make clean)
(cd fs;make clean)
(cd kernel;make clean)
(cd lib;make clean)
for i in $(SUBDIRS); do (cd $$i; $(MAKE) clean); done
backup: clean
(cd .. ; tar cf - linux | compress - > backup.Z)
cd .. ; tar cf - linux | compress - > backup.Z
sync
dep:
depend dep:
sed '/\#\#\# Dependencies/q' < Makefile > tmp_make
(for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done) >> tmp_make
for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done >> tmp_make
cp tmp_make Makefile
(cd fs; make dep)
(cd kernel; make dep)
(cd mm; make dep)
(cd lib; make dep)
for i in $(SUBDIRS); do (cd $$i; $(MAKE) dep) || exit; done
dummy:
### Dependencies:
init/main.o : init/main.c include/unistd.h include/sys/stat.h include/sys/types.h \
include/sys/time.h include/time.h include/sys/times.h include/sys/utsname.h \
include/sys/param.h include/sys/resource.h include/utime.h include/linux/sched.h \
include/linux/head.h include/linux/fs.h include/sys/dirent.h include/limits.h \
include/linux/mm.h include/linux/kernel.h include/signal.h include/linux/tty.h \
include/termios.h include/linux/string.h include/asm/system.h include/asm/io.h \
include/stddef.h include/stdarg.h include/fcntl.h
init/main.o : init/main.c /usr/src/linux/include/stdarg.h /usr/src/linux/include/time.h \
/usr/src/linux/include/asm/system.h /usr/src/linux/include/asm/io.h /usr/src/linux/include/linux/types.h \
/usr/src/linux/include/linux/fcntl.h /usr/src/linux/include/linux/config.h /usr/src/linux/include/linux/config_rel.h \
/usr/src/linux/include/linux/config_ver.h /usr/src/linux/include/linux/config.dist.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_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/tty.h /usr/src/linux/include/linux/termios.h /usr/src/linux/include/linux/unistd.h
......@@ -6,7 +6,7 @@
#include <linux/config.h>
SYSSIZE = DEF_SYSSIZE
!
! bootsect.s (C) 1991 Linus Torvalds
! bootsect.s Copyright (C) 1991, 1992 Linus Torvalds
! modified by Drew Eckhardt
! modified by Bruce Evans (bde)
!
......@@ -224,8 +224,7 @@ got_sectors:
mov ax,#0x021c ! /dev/PS0 - 1.44Mb
cmp bx,#18
je root_defined
undef_root:
jmp undef_root
mov ax,#0x0200 ! /dev/fd0 - autodetect
root_defined:
seg cs
mov root_dev,ax
......
/*
* linux/boot/head.s
*
* (C) 1991 Linus Torvalds
* Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
......@@ -13,6 +13,9 @@
*/
.text
.globl _idt,_gdt,_pg_dir,_tmp_floppy_area,_floppy_track_buffer
/*
* pg_dir is the main page directory, address 0x00000000
*/
_pg_dir:
startup_32:
cld
......@@ -147,6 +150,23 @@ pg2:
pg3:
.org 0x5000
/*
* empty_bad_page is a bogus page that will be used when out of memory,
* so that a process isn't accidentally killed due to a page fault when
* it is running in kernel mode..
*/
.globl _empty_bad_page
_empty_bad_page:
.org 0x6000
/*
* empty_bad_page_table is similar to the above, but is used when the
* system needs a bogus page-table
*/
.globl _empty_bad_page_table
_empty_bad_page_table:
.org 0x7000
/*
* tmp_floppy_area is used by the floppy-driver when DMA cannot
* reach to a buffer-block. It needs to be aligned, so that it isn't
......
!
! setup.s (C) 1991 Linus Torvalds
! setup.s Copyright (C) 1991, 1992 Linus Torvalds
!
! setup.s is responsible for getting the system data from the BIOS,
! and putting them into the appropriate places in system memory.
......@@ -14,6 +14,7 @@
! NOTE! These had better be the same as in bootsect.s!
#include <linux/config.h>
#define NORMAL_VGA 0xffff
INITSEG = DEF_INITSEG ! we move boot here - out of the way
SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536).
......@@ -189,9 +190,10 @@ end_move:
out #0xA1,al
.word 0x00eb,0x00eb
mov al,#0xFF ! mask off all interrupts for now
out #0x21,al
.word 0x00eb,0x00eb
out #0xA1,al
.word 0x00eb,0x00eb
mov al,#0xFB ! mask all irq's but irq2 which
out #0x21,al ! is cascaded
! well, that certainly wasn't fun :-(. Hopefully it works, and we don't
! need no steenking BIOS anyway (except for the initial loading :-).
......@@ -245,6 +247,7 @@ chsvga: cld
mov es,ax
lea si,msg1
call prtstr
#ifndef SVGA_MODE
flush: in al,#0x60 ! Flush the keyboard buffer
cmp al,#0x82
jb nokey
......@@ -256,9 +259,12 @@ nokey: call getkey
ja nokey
cmp al,#0x9c
je svga
#endif
#if !defined(SVGA_MODE) || SVGA_MODE == NORMAL_VGA
mov ax,#0x5019
pop ds
ret
#endif
svga: cld
lea si,idati ! Check ATI 'clues'
mov di,#0x31
......@@ -497,6 +503,9 @@ tbl: pop bx
call prtstr
pop si
add cl,#0x80
#if defined(SVGA_MODE) && SVGA_MODE != NORMAL_VGA
mov al,#SVGA_MODE ! Preset SVGA mode
#else
nonum: call getkey
cmp al,#0x82
jb nonum
......@@ -508,6 +517,7 @@ nonum: call getkey
zero: sub al,#0x0a
nozero: sub al,#0x80
dec al
#endif
xor ah,ah
add di,ax
inc di
......
This diff is collapsed.
/*
* linux/fs/block_dev.c
*
* (C) 1991 Linus Torvalds
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <errno.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
......@@ -36,7 +35,7 @@ int block_write(struct inode * inode, struct file * filp, char * buf, int count)
if (chars > count)
chars=count;
if (chars == BLOCK_SIZE)
bh = getblk(dev,block);
bh = getblk(dev, block, BLOCK_SIZE);
else
bh = breada(dev,block,block+1,block+2,-1);
block++;
......
This diff is collapsed.
/*
* linux/fs/exec.c
*
* (C) 1991 Linus Torvalds
* Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
......@@ -17,16 +17,19 @@
* was less than 2 hours work to get demand-loading completely implemented.
*/
#include <signal.h>
#include <errno.h>
#include <linux/string.h>
#include <sys/stat.h>
#include <a.out.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/a.out.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/user.h>
#include <asm/segment.h>
extern int sys_exit(int exit_code);
......@@ -39,6 +42,121 @@ extern int sys_close(int fd);
*/
#define MAX_ARG_PAGES 32
/*
* These are the only things you should do on a core-file: use only these
* macros to write out all the necessary info.
*/
#define DUMP_WRITE(addr,nr) \
while (file.f_op->write(inode,&file,(char *)(addr),(nr)) != (nr)) goto close_coredump
#define DUMP_SEEK(offset) \
if (file.f_op->lseek) { \
if (file.f_op->lseek(inode,&file,(offset),0) != (offset)) \
goto close_coredump; \
} else file.f_pos = (offset)
/*
* Routine writes a core dump image in the current directory.
* Currently only a stub-function.
*
* Note that setuid/setgid files won't make a core-dump if the uid/gid
* changed due to the set[u|g]id. It's enforced by the "current->dumpable"
* field, which also makes sure the core-dumps won't be recursive if the
* dumping of the process results in another error..
*/
int core_dump(long signr, struct pt_regs * regs)
{
struct inode * inode = NULL;
struct file file;
unsigned short fs;
int has_dumped = 0;
register int dump_start, dump_size;
struct user dump;
if (!current->dumpable)
return 0;
current->dumpable = 0;
/* See if we have enough room to write the upage. */
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))
goto end_coredump;
if (!S_ISREG(inode->i_mode))
goto end_coredump;
if (!inode->i_op || !inode->i_op->default_file_ops)
goto end_coredump;
file.f_mode = 3;
file.f_flags = 0;
file.f_count = 1;
file.f_inode = inode;
file.f_pos = 0;
file.f_reada = 0;
file.f_op = inode->i_op->default_file_ops;
if (file.f_op->open)
if (file.f_op->open(inode,&file))
goto end_coredump;
if (!file.f_op->write)
goto close_coredump;
has_dumped = 1;
/* write and seek example: from kernel space */
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
dump.magic = CMAGIC;
dump.u_tsize = current->end_code / PAGE_SIZE;
dump.u_dsize = (current->brk - current->end_code) / PAGE_SIZE;
dump.u_ssize =((current->start_stack +(PAGE_SIZE-1)) / PAGE_SIZE) -
(regs->esp/ PAGE_SIZE);
/* If the size of the dump file exceeds the rlimit, then see what would happen
if we wrote the stack, but not the data area. */
if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE/1024 >
current->rlim[RLIMIT_CORE].rlim_cur)
dump.u_dsize = 0;
/* Make sure we have enough room to write the stack and data areas. */
if ((dump.u_ssize+1) * PAGE_SIZE / 1024 >
current->rlim[RLIMIT_CORE].rlim_cur)
dump.u_ssize = 0;
dump.u_comm = 0;
dump.u_ar0 = (struct pt_regs *)(((int)(&dump.regs)) -((int)(&dump)));
dump.signal = signr;
dump.regs = *regs;
dump.start_code = 0;
dump.start_stack = regs->esp & ~(PAGE_SIZE - 1);
/* Flag indicating the math stuff is valid. */
if (dump.u_fpvalid = current->used_math) {
if (last_task_used_math == current)
__asm__("clts ; fnsave %0"::"m" (dump.i387));
else
memcpy(&dump.i387,&current->tss.i387,sizeof(dump.i387));
};
DUMP_WRITE(&dump,sizeof(dump));
DUMP_SEEK(sizeof(dump));
/* Dump the task struct. Not be used by gdb, but could be useful */
DUMP_WRITE(current,sizeof(*current));
/* Now dump all of the user data. Include malloced stuff as well */
DUMP_SEEK(PAGE_SIZE);
/* now we start writing out the user space info */
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x17));
/* Dump the data area */
if (dump.u_dsize != 0) {
dump_start = current->end_code;
dump_size = current->brk - current->end_code;
DUMP_WRITE(dump_start,dump_size);
};
/* Now prepare to dump the stack area */
if (dump.u_ssize != 0) {
dump_start = regs->esp & ~(PAGE_SIZE - 1);
dump_size = dump.u_ssize * PAGE_SIZE;
DUMP_WRITE(dump_start,dump_size);
};
close_coredump:
if (file.f_op->release)
file.f_op->release(inode,&file);
end_coredump:
__asm__("mov %0,%%fs"::"r" (fs));
iput(inode);
return has_dumped;
}
/*
* Note that a shared library must be both readable and executable due to
* security reasons.
......@@ -62,14 +180,18 @@ int sys_uselib(const char * library)
inode = NULL;
if (!inode)
return -ENOENT;
if (!S_ISREG(inode->i_mode) || !permission(inode,MAY_READ|MAY_EXEC)) {
if (!inode->i_sb || !S_ISREG(inode->i_mode) || !permission(inode,MAY_READ)) {
iput(inode);
return -EACCES;
}
if (!(bh = bread(inode->i_dev,inode->i_data[0]))) {
if (!(bh = bread(inode->i_dev,bmap(inode,0),inode->i_sb->s_blocksize))) {
iput(inode);
return -EACCES;
}
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
}
ex = *(struct exec *) bh->b_data;
brelse(bh);
if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
......@@ -158,7 +280,7 @@ static int count(char ** argv)
static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
unsigned long p, int from_kmem)
{
char *tmp, *pag;
char *tmp, *pag = NULL;
int len, offset = 0;
unsigned long old_fs, new_fs;
......@@ -191,7 +313,7 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
set_fs(old_fs);
if (!(pag = (char *) page[p/PAGE_SIZE]) &&
!(pag = (char *) page[p/PAGE_SIZE] =
(unsigned long *) get_free_page()))
(unsigned long *) get_free_page(GFP_USER)))
return 0;
if (from_kmem==2)
set_fs(new_fs);
......@@ -229,6 +351,36 @@ static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
return data_limit;
}
static void read_omagic(struct inode *inode, int bytes)
{
struct buffer_head *bh;
int n, blkno, blk = 0;
char *dest = (char *) 0;
unsigned int block_size;
block_size = 1024;
if (inode->i_sb)
block_size = inode->i_sb->s_blocksize;
while (bytes > 0) {
if (!(blkno = bmap(inode, blk)))
sys_exit(-1);
if (!(bh = bread(inode->i_dev, blkno, block_size)))
sys_exit(-1);
n = (blk ? block_size : block_size - sizeof(struct exec));
if (bytes < n)
n = bytes;
memcpy_tofs(dest, (blk ? bh->b_data :
bh->b_data + sizeof(struct exec)), n);
brelse(bh);
++blk;
dest += n;
bytes -= n;
}
iput(inode);
current->executable = NULL;
}
/*
* 'do_execve()' executes a new program.
*
......@@ -263,7 +415,21 @@ 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 */
retval = -EPERM;
goto exec_error2;
}
if (!inode->i_sb) {
retval = -EACCES;
goto exec_error2;
}
i = inode->i_mode;
if (IS_NOSUID(inode) && (((i & S_ISUID) && inode->i_uid != current->
euid) || ((i & S_ISGID) && inode->i_gid != current->egid)) &&
!suser()) {
retval = -EPERM;
goto exec_error2;
}
/* make sure we don't let suid, sgid files be ptraced. */
if (current->flags & PF_PTRACED) {
e_uid = current->euid;
......@@ -281,10 +447,14 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
retval = -EACCES;
goto exec_error2;
}
if (!(bh = bread(inode->i_dev,inode->i_data[0]))) {
if (!(bh = bread(inode->i_dev,bmap(inode,0),inode->i_sb->s_blocksize))) {
retval = -EACCES;
goto exec_error2;
}
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
}
ex = *((struct exec *) bh->b_data); /* read exec-header */
if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) {
/*
......@@ -359,13 +529,14 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
goto restart_interp;
}
brelse(bh);
if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize ||
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC) ||
ex.a_trsize || ex.a_drsize ||
ex.a_text+ex.a_data+ex.a_bss>0x3000000 ||
inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
retval = -ENOEXEC;
goto exec_error2;
}
if (N_TXTOFF(ex) != BLOCK_SIZE) {
if (N_TXTOFF(ex) != BLOCK_SIZE && N_MAGIC(ex) != OMAGIC) {
printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename);
retval = -ENOEXEC;
goto exec_error2;
......@@ -379,6 +550,7 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
}
}
/* OK, This is the point of no return */
current->dumpable = 1;
for (i=0; (ch = get_fs_byte(filename++)) != '\0';)
if (ch == '/')
i = 0;
......@@ -394,6 +566,9 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
iput(current->libraries[i].library);
current->libraries[i].library = NULL;
}
if (e_uid != current->euid || e_gid != current->egid ||
!permission(inode,MAY_READ))
current->dumpable = 0;
current->numlibraries = 0;
current->executable = inode;
current->signal = 0;
......@@ -422,10 +597,12 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
current->rss = (LIBRARY_OFFSET - p + PAGE_SIZE-1) / PAGE_SIZE;
current->suid = current->euid = e_uid;
current->sgid = current->egid = e_gid;
if (N_MAGIC(ex) == OMAGIC)
read_omagic(inode, ex.a_text+ex.a_data);
eip[0] = ex.a_entry; /* eip, magic happens :-) */
eip[3] = p; /* stack pointer */
if (current->flags & PF_PTRACED)
send_sig(SIGTRAP, current, 0);
send_sig(SIGTRAP, current, 0);
return 0;
exec_error2:
iput(inode);
......
#
# Makefile for the linux ext-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= bitmap.o freelists.o truncate.o namei.o inode.o \
file.o dir.o symlink.o blkdev.o chrdev.o fifo.o
ext.o: $(OBJS)
$(LD) -r -o ext.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:
bitmap.o : bitmap.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_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/ext_fs.h /usr/src/linux/include/linux/string.h
blkdev.o : blkdev.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_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/ext_fs.h /usr/src/linux/include/linux/tty.h /usr/src/linux/include/linux/termios.h \
/usr/src/linux/include/asm/system.h /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/fcntl.h \
/usr/src/linux/include/linux/errno.h
chrdev.o : chrdev.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_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/ext_fs.h /usr/src/linux/include/linux/tty.h /usr/src/linux/include/linux/termios.h \
/usr/src/linux/include/asm/system.h /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/fcntl.h \
/usr/src/linux/include/linux/errno.h
dir.o : dir.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/linux/errno.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_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/ext_fs.h \
/usr/src/linux/include/linux/stat.h
fifo.o : fifo.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_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/ext_fs.h
file.o : file.c /usr/src/linux/include/asm/segment.h /usr/src/linux/include/asm/system.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_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/ext_fs.h /usr/src/linux/include/linux/errno.h /usr/src/linux/include/linux/fcntl.h \
/usr/src/linux/include/linux/stat.h
freelists.o : freelists.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_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/ext_fs.h /usr/src/linux/include/linux/string.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_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/ext_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
namei.o : namei.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_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/ext_fs.h /usr/src/linux/include/linux/string.h \
/usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/fcntl.h /usr/src/linux/include/linux/errno.h \
/usr/src/linux/include/asm/segment.h /usr/src/linux/include/const.h
symlink.o : symlink.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_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/ext_fs.h /usr/src/linux/include/linux/stat.h
truncate.o : truncate.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_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/ext_fs.h /usr/src/linux/include/linux/tty.h /usr/src/linux/include/linux/termios.h \
/usr/src/linux/include/asm/system.h /usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/fcntl.h \
/usr/src/linux/include/linux/errno.h
/*
* linux/fs/ext/bitmap.c
*
* Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
*
* from
*
* linux/fs/minix/bitmap.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
/* bitmap.c contains the code that handles the inode and block bitmaps */
#include <linux/sched.h>
#include <linux/ext_fs.h>
#include <linux/kernel.h>
#include <linux/string.h>
#ifdef EXTFS_BITMAP
#define clear_block(addr) \
__asm__("cld\n\t" \
"rep\n\t" \
"stosl" \
::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di")
#define set_bit(nr,addr) ({\
char res; \
__asm__ __volatile__("btsl %1,%2\n\tsetb %0": \
"=q" (res):"r" (nr),"m" (*(addr))); \
res;})
#define clear_bit(nr,addr) ({\
char res; \
__asm__ __volatile__("btrl %1,%2\n\tsetnb %0": \
"=q" (res):"r" (nr),"m" (*(addr))); \
res;})
#define find_first_zero(addr) ({ \
int __res; \
__asm__("cld\n" \
"1:\tlodsl\n\t" \
"notl %%eax\n\t" \
"bsfl %%eax,%%edx\n\t" \
"jne 2f\n\t" \
"addl $32,%%ecx\n\t" \
"cmpl $8192,%%ecx\n\t" \
"jl 1b\n\t" \
"xorl %%edx,%%edx\n" \
"2:\taddl %%edx,%%ecx" \
:"=c" (__res):"0" (0),"S" (addr):"ax","dx","si"); \
__res;})
static int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
static unsigned long count_used(struct buffer_head *map[], unsigned numblocks,
unsigned numbits)
{
unsigned i, j, end, sum = 0;
struct buffer_head *bh;
for (i=0; (i<numblocks) && numbits; i++) {
if (!(bh=map[i]))
return(0);
if (numbits >= (8*BLOCK_SIZE)) {
end = BLOCK_SIZE;
numbits -= 8*BLOCK_SIZE;
} else {
int tmp;
end = numbits >> 3;
numbits &= 0x7;
tmp = bh->b_data[end] & ((1<<numbits)-1);
sum += nibblemap[tmp&0xf] + nibblemap[(tmp>>4)&0xf];
numbits = 0;
}
for (j=0; j<end; j++)
sum += nibblemap[bh->b_data[j] & 0xf]
+ nibblemap[(bh->b_data[j]>>4)&0xf];
}
return(sum);
}
int ext_free_block(int dev, int block)
{
struct super_block * sb;
struct buffer_head * bh;
unsigned int bit,zone;
if (!(sb = get_super(dev)))
panic("trying to free block on nonexistent device");
if (block < sb->s_firstdatazone || block >= sb->s_nzones)
panic("trying to free block not in datazone");
bh = get_hash_table(dev,block);
if (bh) {
if (bh->b_count > 1) {
brelse(bh);
return 0;
}
bh->b_dirt=0;
bh->b_uptodate=0;
if (bh->b_count)
brelse(bh);
}
zone = block - sb->s_firstdatazone + 1;
bit = zone & 8191;
zone >>= 13;
bh = sb->s_zmap[zone];
if (clear_bit(bit,bh->b_data))
printk("free_block (%04x:%d): bit already cleared\n",dev,block);
bh->b_dirt = 1;
return 1;
}
int ext_new_block(int dev)
{
struct buffer_head * bh;
struct super_block * sb;
int i,j;
if (!(sb = get_super(dev)))
panic("trying to get new block from nonexistant device");
j = 8192;
for (i=0 ; i<8 ; i++)
if (bh=sb->s_zmap[i])
if ((j=find_first_zero(bh->b_data))<8192)
break;
if (i>=8 || !bh || j>=8192)
return 0;
if (set_bit(j,bh->b_data))
panic("new_block: bit already set");
bh->b_dirt = 1;
j += i*8192 + sb->s_firstdatazone-1;
if (j >= sb->s_nzones)
return 0;
if (!(bh=getblk(dev,j)))
panic("new_block: cannot get block");
if (bh->b_count != 1)
panic("new block: count is != 1");
clear_block(bh->b_data);
bh->b_uptodate = 1;
bh->b_dirt = 1;
brelse(bh);
#ifdef EXTFS_DEBUG
printk("ext_new_block: allocating block %d\n", j);
#endif
return j;
}
unsigned long ext_count_free_blocks(struct super_block *sb)
{
return (sb->s_nzones - count_used(sb->s_zmap,sb->s_zmap_blocks,sb->s_nzones))
<< sb->s_log_zone_size;
}
void ext_free_inode(struct inode * inode)
{
struct buffer_head * bh;
if (!inode)
return;
if (!inode->i_dev) {
memset(inode,0,sizeof(*inode));
return;
}
if (inode->i_count>1) {
printk("free_inode: inode has count=%d\n",inode->i_count);
return;
}
if (inode->i_nlink) {
printk("free_inode: inode has nlink=%d\n",inode->i_nlink);
return;
}
if (!inode->i_sb) {
printk("free_inode: inode on nonexistent device\n");
return;
}
if (inode->i_ino < 1 || inode->i_ino > inode->i_sb->s_ninodes) {
printk("free_inode: inode 0 or nonexistent inode\n");
return;
}
if (!(bh=inode->i_sb->s_imap[inode->i_ino>>13])) {
printk("free_inode: nonexistent imap in superblock\n");
return;
}
if (clear_bit(inode->i_ino&8191,bh->b_data))
printk("free_inode: bit already cleared.\n\r");
bh->b_dirt = 1;
memset(inode,0,sizeof(*inode));
}
struct inode * ext_new_inode(int dev)
{
struct inode * inode;
struct buffer_head * bh;
int i,j;
if (!(inode=get_empty_inode()))
return NULL;
if (!(inode->i_sb = get_super(dev))) {
printk("new_inode: unknown device\n");
iput(inode);
return NULL;
}
inode->i_flags = inode->i_sb->s_flags;
j = 8192;
for (i=0 ; i<8 ; i++)
if (bh=inode->i_sb->s_imap[i])
if ((j=find_first_zero(bh->b_data))<8192)
break;
if (!bh || j >= 8192 || j+i*8192 > inode->i_sb->s_ninodes) {
iput(inode);
return NULL;
}
if (set_bit(j,bh->b_data)) { /* shouldn't happen */
printk("new_inode: bit already set");
iput(inode);
return NULL;
}
bh->b_dirt = 1;
inode->i_count = 1;
inode->i_nlink = 1;
inode->i_dev = dev;
inode->i_uid = current->euid;
inode->i_gid = current->egid;
inode->i_dirt = 1;
inode->i_ino = j + i*8192;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_op = NULL;
#ifdef EXTFS_DEBUG
printk("ext_new_inode : allocating inode %d\n", inode->i_ino);
#endif
return inode;
}
unsigned long ext_count_free_inodes(struct super_block *sb)
{
return sb->s_ninodes - count_used(sb->s_imap,sb->s_imap_blocks,sb->s_ninodes);
}
#endif
/*
* linux/fs/ext/blkdev.c
*
* Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
*
* from
*
* linux/fs/minix/blkdev.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/sched.h>
#include <linux/ext_fs.h>
#include <linux/tty.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
/*
* Called every time an ext block special file is opened
*/
static int blkdev_open(struct inode * inode, struct file * filp)
{
int i;
i = MAJOR(inode->i_rdev);
if (i < MAX_BLKDEV) {
filp->f_op = blkdev_fops[i];
if (filp->f_op && filp->f_op->open)
return filp->f_op->open(inode,filp);
}
return 0;
}
/*
* Dummy default file-operations: the only thing this does
* is contain the open that then fills in the correct operations
* depending on the special file...
*/
static struct file_operations def_blk_fops = {
NULL, /* lseek */
NULL, /* read */
NULL, /* write */
NULL, /* readdir */
NULL, /* select */
NULL, /* ioctl */
blkdev_open, /* open */
NULL, /* release */
};
struct inode_operations ext_blkdev_inode_operations = {
&def_blk_fops, /* default file operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
ext_bmap, /* bmap */
ext_truncate /* truncate */
};
/*
* linux/fs/ext/chrdev.c
*
* Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
*
* from
*
* linux/fs/minix/chrdev.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/sched.h>
#include <linux/ext_fs.h>
#include <linux/tty.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
/*
* Called every time an ext character special file is opened
*/
static int chrdev_open(struct inode * inode, struct file * filp)
{
int i;
i = MAJOR(inode->i_rdev);
if (i < MAX_CHRDEV) {
filp->f_op = chrdev_fops[i];
if (filp->f_op && filp->f_op->open)
return filp->f_op->open(inode,filp);
}
return 0;
}
/*
* Dummy default file-operations: the only thing this does
* is contain the open that then fills in the correct operations
* depending on the special file...
*/
static struct file_operations def_chr_fops = {
NULL, /* lseek */
NULL, /* read */
NULL, /* write */
NULL, /* readdir */
NULL, /* select */
NULL, /* ioctl */
chrdev_open, /* open */
NULL, /* release */
};
struct inode_operations ext_chrdev_inode_operations = {
&def_chr_fops, /* default file operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
ext_bmap, /* bmap */
ext_truncate /* truncate */
};
/*
* linux/fs/ext/dir.c
*
* Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
*
* from
*
* linux/fs/minix/dir.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* ext directory handling functions
*/
#include <asm/segment.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext_fs.h>
#include <linux/stat.h>
static int ext_readdir(struct inode *, struct file *, struct dirent *, int);
static struct file_operations ext_dir_operations = {
NULL, /* lseek - default */
NULL, /* read */
NULL, /* write - bad */
ext_readdir, /* readdir */
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* no special open code */
NULL /* no special release code */
};
/*
* directories can handle most operations...
*/
struct inode_operations ext_dir_inode_operations = {
&ext_dir_operations, /* default directory file-ops */
ext_create, /* create */
ext_lookup, /* lookup */
ext_link, /* link */
ext_unlink, /* unlink */
ext_symlink, /* symlink */
ext_mkdir, /* mkdir */
ext_rmdir, /* rmdir */
ext_mknod, /* mknod */
ext_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
ext_bmap, /* bmap */
ext_truncate /* truncate */
};
static int ext_readdir(struct inode * inode, struct file * filp,
struct dirent * dirent, int count)
{
unsigned int block,offset,i;
char c;
struct buffer_head * bh;
struct ext_dir_entry * de;
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
/* if (filp->f_pos & (sizeof (struct ext_dir_entry) - 1))
return -EBADF; */
while (filp->f_pos < inode->i_size) {
offset = filp->f_pos & 1023;
block = ext_bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS);
if (!block || !(bh = bread(inode->i_dev, block, BLOCK_SIZE))) {
filp->f_pos += 1024-offset;
continue;
}
de = (struct ext_dir_entry *) (offset + bh->b_data);
while (offset < 1024 && filp->f_pos < inode->i_size) {
offset += de->rec_len;
filp->f_pos += de->rec_len;
if (de->inode) {
for (i = 0; i < de->name_len; i++)
if (c = de->name[i])
put_fs_byte(c,i+dirent->d_name);
else
break;
if (i) {
put_fs_long(de->inode,&dirent->d_ino);
put_fs_byte(0,i+dirent->d_name);
put_fs_word(i,&dirent->d_reclen);
brelse(bh);
return i;
}
}
/* de++; */
de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
}
brelse(bh);
}
return 0;
}
/*
* linux/fs/fifo.c
*
* written by Paul H. Hargrove.
*/
#include <linux/sched.h>
#include <linux/ext_fs.h>
extern struct file_operations def_fifo_fops;
struct inode_operations ext_fifo_inode_operations = {
&def_fifo_fops, /* default file operations */
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/ext/file.c
*
* Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
*
* from
*
* linux/fs/minix/file.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* ext regular file handling primitives
*/
#include <asm/segment.h>
#include <asm/system.h>
#include <linux/sched.h>
#include <linux/ext_fs.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
#define NBUF 16
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
#include <linux/fs.h>
#include <linux/ext_fs.h>
static int ext_file_read(struct inode *, struct file *, char *, int);
static int ext_file_write(struct inode *, struct file *, char *, int);
/*
* We have mostly NULL's here: the current defaults are ok for
* the ext filesystem.
*/
static struct file_operations ext_file_operations = {
NULL, /* lseek - default */
ext_file_read, /* read */
ext_file_write, /* write */
NULL, /* readdir - bad */
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* no special open is needed */
NULL /* release */
};
struct inode_operations ext_file_inode_operations = {
&ext_file_operations, /* default file operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
ext_bmap, /* bmap */
ext_truncate /* truncate */
};
static inline void wait_on_buffer(struct buffer_head * bh)
{
cli();
while (bh->b_lock)
sleep_on(&bh->b_wait);
sti();
}
static int ext_file_read(struct inode * inode, struct file * filp, char * buf, int count)
{
int read,left,chars,nr;
int block, blocks, offset;
struct buffer_head ** bhb, ** bhe;
struct buffer_head * buflist[NBUF];
if (!inode) {
printk("ext_file_read: inode = NULL\n");
return -EINVAL;
}
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {
printk("ext_file_read: mode = %07o\n",inode->i_mode);
return -EINVAL;
}
if (filp->f_pos > inode->i_size)
left = 0;
else
left = inode->i_size - filp->f_pos;
if (left > count)
left = count;
if (left <= 0)
return 0;
read = 0;
block = filp->f_pos >> BLOCK_SIZE_BITS;
offset = filp->f_pos & (BLOCK_SIZE-1);
blocks = (left + offset + BLOCK_SIZE - 1) / BLOCK_SIZE;
bhb = bhe = buflist;
do {
if (blocks) {
--blocks;
if (nr = ext_bmap(inode,block++)) {
*bhb = getblk(inode->i_dev, nr, BLOCK_SIZE);
if (!(*bhb)->b_uptodate)
ll_rw_block(READ,*bhb);
} else
*bhb = NULL;
if (++bhb == &buflist[NBUF])
bhb = buflist;
if (bhb != bhe)
continue;
}
if (*bhe) {
wait_on_buffer(*bhe);
if (!(*bhe)->b_uptodate) {
do {
brelse(*bhe);
if (++bhe == &buflist[NBUF])
bhe = buflist;
} while (bhe != bhb);
break;
}
}
if (left < BLOCK_SIZE - offset)
chars = left;
else
chars = BLOCK_SIZE - offset;
filp->f_pos += chars;
left -= chars;
read += chars;
if (*bhe) {
memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
brelse(*bhe);
buf += chars;
} else {
while (chars-->0)
put_fs_byte(0,buf++);
}
offset = 0;
if (++bhe == &buflist[NBUF])
bhe = buflist;
} while (left > 0);
if (!read)
return -EIO;
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
}
return read;
}
static int ext_file_write(struct inode * inode, struct file * filp, char * buf, int count)
{
off_t pos;
int written,block,c;
struct buffer_head * bh;
char * p;
if (!inode) {
printk("ext_file_write: inode = NULL\n");
return -EINVAL;
}
if (!S_ISREG(inode->i_mode)) {
printk("ext_file_write: mode = %07o\n",inode->i_mode);
return -EINVAL;
}
/*
* ok, append may not work when many processes are writing at the same time
* but so what. That way leads to madness anyway.
*/
if (filp->f_flags & O_APPEND)
pos = inode->i_size;
else
pos = filp->f_pos;
written = 0;
while (written<count) {
if (!(block = ext_create_block(inode,pos/BLOCK_SIZE))) {
if (!written)
written = -ENOSPC;
break;
}
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;
}
p = (pos % BLOCK_SIZE) + bh->b_data;
pos += c;
if (pos > inode->i_size) {
inode->i_size = pos;
inode->i_dirt = 1;
}
written += c;
memcpy_fromfs(p,buf,c);
buf += c;
bh->b_uptodate = 1;
bh->b_dirt = 1;
brelse(bh);
}
inode->i_mtime = CURRENT_TIME;
inode->i_ctime = CURRENT_TIME;
filp->f_pos = pos;
inode->i_dirt = 1;
return written;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* linux/fs/ext/symlink.c
*
* Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
*
* from
*
* linux/fs/minix/symlink.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* ext symlink handling code
*/
#include <asm/segment.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/ext_fs.h>
#include <linux/stat.h>
static int ext_readlink(struct inode *, char *, int);
static struct inode * ext_follow_link(struct inode *, struct inode *);
/*
* symlinks can't do much...
*/
struct inode_operations ext_symlink_inode_operations = {
NULL, /* no file-operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
ext_readlink, /* readlink */
ext_follow_link, /* follow_link */
NULL, /* bmap */
NULL /* truncate */
};
static struct inode * ext_follow_link(struct inode * dir, struct inode * inode)
{
unsigned short fs;
struct buffer_head * bh;
if (!dir) {
dir = current->root;
dir->i_count++;
}
if (!inode) {
iput(dir);
return NULL;
}
if (!S_ISLNK(inode->i_mode)) {
iput(dir);
return inode;
}
__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);
iput(inode);
return NULL;
}
iput(inode);
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
current->link_count++;
inode = _namei(bh->b_data,dir,1);
current->link_count--;
__asm__("mov %0,%%fs"::"r" (fs));
brelse(bh);
return inode;
}
static int ext_readlink(struct inode * inode, char * buffer, int buflen)
{
struct buffer_head * bh;
int i;
char c;
if (!S_ISLNK(inode->i_mode)) {
iput(inode);
return -EINVAL;
}
if (buflen > 1023)
buflen = 1023;
if (inode->i_data[0])
bh = bread(inode->i_dev, inode->i_data[0], BLOCK_SIZE);
else
bh = NULL;
iput(inode);
if (!bh)
return 0;
i = 0;
while (i<buflen && (c = bh->b_data[i])) {
i++;
put_fs_byte(c,buffer++);
}
brelse(bh);
return i;
}
/*
* linux/fs/ext/truncate.c
*
* Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
*
* from
*
* linux/fs/minix/truncate.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/sched.h>
#include <linux/ext_fs.h>
#include <linux/tty.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
/*
* Truncate has the most races in the whole filesystem: coding it is
* a pain in the a**. Especially as I don't do any locking...
*
* The code may look a bit weird, but that's just because I've tried to
* handle things like file-size changes in a somewhat graceful manner.
* Anyway, truncating a file at the same time somebody else writes to it
* is likely to result in pretty weird behaviour...
*
* The new code handles normal truncates (size = 0) as well as the more
* general case (size = XXX). I hope.
*/
static int trunc_direct(struct inode * inode)
{
int i;
int result = 0;
#define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
repeat:
for (i = DIRECT_BLOCK ; i < 9 ; i++) {
if (i < DIRECT_BLOCK)
goto repeat;
if (!inode->i_data[i])
continue;
result = 1;
if (ext_free_block(inode->i_dev,inode->i_data[i]))
inode->i_data[i] = 0;
}
return result;
}
static int trunc_indirect(struct inode * inode, int offset, unsigned long * p)
{
int i;
struct buffer_head * bh = NULL;
unsigned long * ind;
int result = 0;
#define INDIRECT_BLOCK (DIRECT_BLOCK-offset)
if (*p)
bh = bread(inode->i_dev, *p, BLOCK_SIZE);
if (!bh)
return 0;
repeat:
for (i = INDIRECT_BLOCK ; i < 256 ; i++) {
if (i < 0)
i = 0;
if (i < INDIRECT_BLOCK)
goto repeat;
ind = i+(unsigned long *) bh->b_data;
if (!*ind)
continue;
result = 1;
if (ext_free_block(inode->i_dev,*ind))
*ind = 0;
}
ind = (unsigned long *) bh->b_data;
for (i = 0; i < 256; i++)
if (*(ind++))
break;
brelse(bh);
if (i >= 256) {
result = 1;
if (ext_free_block(inode->i_dev,*p))
*p = 0;
}
return result;
}
static int trunc_dindirect(struct inode * inode, int offset, unsigned long * p)
{
int i;
struct buffer_head * bh = NULL;
unsigned long * dind;
int result = 0;
#define DINDIRECT_BLOCK ((DIRECT_BLOCK-offset)>>8)
if (*p)
bh = bread(inode->i_dev, *p, BLOCK_SIZE);
if (!bh)
return 0;
repeat:
for (i = DINDIRECT_BLOCK ; i < 256 ; i ++) {
if (i < 0)
i = 0;
if (i < DINDIRECT_BLOCK)
goto repeat;
dind = i+(unsigned long *) bh->b_data;
if (!*dind)
continue;
result |= trunc_indirect(inode,offset+(i<<8),dind);
}
dind = (unsigned long *) bh->b_data;
for (i = 0; i < 256; i++)
if (*(dind++))
break;
brelse(bh);
if (i >= 256) {
result = 1;
if (ext_free_block(inode->i_dev,*p))
*p = 0;
}
return result;
}
static int trunc_tindirect(struct inode * inode)
{
int i;
struct buffer_head * bh = NULL;
unsigned long * tind;
int result = 0;
#define TINDIRECT_BLOCK ((DIRECT_BLOCK-(256*256+256+9))>>16)
if (inode->i_data[11])
bh = bread(inode->i_dev, inode->i_data[11], BLOCK_SIZE);
if (!bh)
return 0;
repeat:
for (i = TINDIRECT_BLOCK ; i < 256 ; i ++) {
if (i < 0)
i = 0;
if (i < TINDIRECT_BLOCK)
goto repeat;
tind = i+(unsigned long *) bh->b_data;
if (!*tind)
continue;
result |= trunc_dindirect(inode,9+256+256*256+(i<<16),tind);
}
tind = (unsigned long *) bh->b_data;
for (i = 0; i < 256; i++)
if (*(tind++))
break;
brelse(bh);
if (i >= 256) {
result = 1;
if (ext_free_block(inode->i_dev,inode->i_data[11]))
inode->i_data[11] = 0;
}
return result;
}
void ext_truncate(struct inode * inode)
{
int flag;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
return;
/* if (inode->i_data[7] & 0xffff0000)
printk("BAD! ext inode has 16 high bits set\n"); */
while (1) {
flag = trunc_direct(inode);
flag |= trunc_indirect(inode,9,(unsigned long *)&inode->i_data[9]);
flag |= trunc_dindirect(inode,9+256,(unsigned long *)&inode->i_data[10]);
flag |= trunc_tindirect(inode);
if (!flag)
break;
current->counter = 0;
schedule();
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
}
/*
* Called when a inode is released. Note that this is different
* from ext_open: open gets called at every open, but release
* gets called only when /all/ the files are closed.
*/
void ext_release(struct inode * inode, struct file * filp)
{
printk("ext_release not implemented\n");
}
/*
* linux/fs/fcntl.c
*
* (C) 1991 Linus Torvalds
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/string.h>
#include <errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/string.h>
extern int sys_close(int fd);
......@@ -35,6 +35,8 @@ static int dupfd(unsigned int fd, unsigned int arg)
int sys_dup2(unsigned int oldfd, unsigned int newfd)
{
if (oldfd >= NR_OPEN || !current->filp[oldfd])
return -EBADF;
if (newfd == oldfd)
return newfd;
sys_close(newfd);
......
/*
* linux/fs/fifo.c
*
* written by Paul H. Hargrove
*/
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
extern struct file_operations read_pipe_fops;
extern struct file_operations write_pipe_fops;
extern struct file_operations rdwr_pipe_fops;
static int fifo_open(struct inode * inode,struct file * filp)
{
int retval = 0;
unsigned long page;
switch( filp->f_mode ) {
case 1:
/*
* O_RDONLY
* POSIX.1 says that O_NONBLOCK means return with the FIFO
* opened, even when there is no process writing the FIFO.
*/
filp->f_op = &read_pipe_fops;
PIPE_READERS(*inode)++;
if (!(filp->f_flags & O_NONBLOCK))
while (!PIPE_WRITERS(*inode)) {
if (PIPE_HEAD(*inode) != PIPE_TAIL(*inode))
break;
if (current->signal & ~current->blocked) {
retval = -ERESTARTSYS;
break;
}
interruptible_sleep_on(&PIPE_READ_WAIT(*inode));
}
if (retval)
PIPE_READERS(*inode)--;
break;
case 2:
/*
* O_WRONLY
* POSIX.1 says that O_NONBLOCK means return -1 with
* errno=ENXIO when there is no process reading the FIFO.
*/
if ((filp->f_flags & O_NONBLOCK) && !PIPE_READERS(*inode)) {
retval = -ENXIO;
break;
}
filp->f_op = &write_pipe_fops;
PIPE_WRITERS(*inode)++;
while (!PIPE_READERS(*inode)) {
if (current->signal & ~current->blocked) {
retval = -ERESTARTSYS;
break;
}
interruptible_sleep_on(&PIPE_WRITE_WAIT(*inode));
}
if (retval)
PIPE_WRITERS(*inode)--;
break;
case 3:
/*
* O_RDWR
* POSIX.1 leaves this case "undefined" when O_NONBLOCK is set.
* This implementation will NEVER block on a O_RDWR open, since
* the process can at least talk to itself.
*/
filp->f_op = &rdwr_pipe_fops;
PIPE_WRITERS(*inode) += 1;
PIPE_READERS(*inode) += 1;
break;
default:
retval = -EINVAL;
}
if (PIPE_WRITERS(*inode))
wake_up(&PIPE_READ_WAIT(*inode));
if (PIPE_READERS(*inode))
wake_up(&PIPE_WRITE_WAIT(*inode));
if (retval || inode->i_size)
return retval;
page = get_free_page(GFP_KERNEL);
if (inode->i_size) {
free_page(page);
return 0;
}
if (!page)
return -ENOMEM;
inode->i_size = page;
return 0;
}
/*
* Dummy default file-operations: the only thing this does
* is contain the open that then fills in the correct operations
* depending on the access mode of the file...
*/
struct file_operations def_fifo_fops = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
fifo_open, /* will set read or write pipe_fops */
NULL
};
/*
* linux/fs/file_table.c
*
* (C) 1991 Linus Torvalds
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/fs.h>
#include <linux/string.h>
struct file file_table[NR_FILE];
struct file * get_empty_filp(void)
{
int i;
struct file * f = file_table+0;
for (i = 0; i++ < NR_FILE; f++)
if (!f->f_count) {
memset(f,0,sizeof(*f));
f->f_count = 1;
return f;
}
return NULL;
}
/*
* linux/fs/inode.c
*
* (C) 1991 Linus Torvalds
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/string.h>
#include <sys/stat.h>
#include <linux/stat.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <asm/system.h>
struct inode inode_table[NR_INODE]={{0,},};
......@@ -39,13 +39,13 @@ static inline void unlock_inode(struct inode * inode)
static void write_inode(struct inode * inode)
{
lock_inode(inode);
if (!inode->i_dirt || !inode->i_dev) {
unlock_inode(inode);
if (!inode->i_dirt)
return;
}
if (inode->i_op && inode->i_op->write_inode)
inode->i_op->write_inode(inode);
inode->i_dirt = 0;
lock_inode(inode);
if (inode->i_dev && inode->i_sb &&
inode->i_sb->s_op && inode->i_sb->s_op->write_inode)
inode->i_sb->s_op->write_inode(inode);
unlock_inode(inode);
}
......@@ -100,7 +100,7 @@ void sync_inodes(void)
inode = 0+inode_table;
for(i=0 ; i<NR_INODE ; i++,inode++) {
wait_on_inode(inode);
if (inode->i_dirt && !inode->i_pipe)
if (inode->i_dirt)
write_inode(inode);
}
}
......@@ -110,36 +110,34 @@ void iput(struct inode * inode)
if (!inode)
return;
wait_on_inode(inode);
if (!inode->i_count)
panic("iput: trying to free free inode");
if (!inode->i_count) {
printk("iput: trying to free free inode\n");
printk("device %04x, inode %d, mode=%07o\n",inode->i_rdev,
inode->i_ino,inode->i_mode);
return;
}
if (inode->i_pipe) {
wake_up(&inode->i_wait);
wake_up(&inode->i_wait2);
if (--inode->i_count)
return;
free_page(inode->i_size);
inode->i_count=0;
inode->i_dirt=0;
inode->i_pipe=0;
return;
}
if (!inode->i_dev) {
repeat:
if (inode->i_count>1) {
inode->i_count--;
return;
}
if (S_ISBLK(inode->i_mode)) {
sync_dev(inode->i_rdev);
wait_on_inode(inode);
if (inode->i_pipe) {
free_page(inode->i_size);
inode->i_size = 0;
}
repeat:
if (inode->i_count>1) {
if (!inode->i_dev) {
inode->i_count--;
return;
}
if (!inode->i_nlink) {
if (inode->i_op && inode->i_op->put_inode)
inode->i_op->put_inode(inode);
return;
if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->put_inode) {
inode->i_sb->s_op->put_inode(inode);
return;
}
}
if (inode->i_dirt) {
write_inode(inode); /* we can sleep - so do again */
......@@ -190,12 +188,13 @@ struct inode * get_pipe_inode(void)
if (!(inode = get_empty_inode()))
return NULL;
if (!(inode->i_size=get_free_page())) {
if (!(inode->i_size = get_free_page(GFP_USER))) {
inode->i_count = 0;
return NULL;
}
inode->i_count = 2; /* sum of readers/writers */
PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
inode->i_pipe = 1;
return inode;
}
......@@ -253,6 +252,7 @@ struct inode * iget(int dev,int nr)
}
inode->i_dev = dev;
inode->i_ino = nr;
inode->i_flags = inode->i_sb->s_flags;
read_inode(inode);
return inode;
}
/*
* linux/fs/ioctl.c
*
* (C) 1991 Linus Torvalds
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/string.h>
#include <errno.h>
#include <sys/stat.h>
#include <asm/segment.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/stat.h>
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_op && filp->f_op->ioctl)
return filp->f_op->ioctl(filp->f_inode, filp, cmd,arg);
return -EINVAL;
......
This diff is collapsed.
/*
* linux/fs/bitmap.c
* linux/fs/minix/bitmap.c
*
* (C) 1991 Linus Torvalds
* Copyright (C) 1991, 1992 Linus Torvalds
*/
/* bitmap.c contains the code that handles the inode and block bitmaps */
#include <linux/string.h>
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/kernel.h>
#include <linux/string.h>
#define clear_block(addr) \
__asm__("cld\n\t" \
......@@ -44,6 +44,35 @@ __asm__("cld\n" \
:"=c" (__res):"0" (0),"S" (addr):"ax","dx","si"); \
__res;})
static int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
static unsigned long count_used(struct buffer_head *map[], unsigned numblocks,
unsigned numbits)
{
unsigned i, j, end, sum = 0;
struct buffer_head *bh;
for (i=0; (i<numblocks) && numbits; i++) {
if (!(bh=map[i]))
return(0);
if (numbits >= (8*BLOCK_SIZE)) {
end = BLOCK_SIZE;
numbits -= 8*BLOCK_SIZE;
} else {
int tmp;
end = numbits >> 3;
numbits &= 0x7;
tmp = bh->b_data[end] & ((1<<numbits)-1);
sum += nibblemap[tmp&0xf] + nibblemap[(tmp>>4)&0xf];
numbits = 0;
}
for (j=0; j<end; j++)
sum += nibblemap[bh->b_data[j] & 0xf]
+ nibblemap[(bh->b_data[j]>>4)&0xf];
}
return(sum);
}
int minix_free_block(int dev, int block)
{
struct super_block * sb;
......@@ -52,9 +81,9 @@ int minix_free_block(int dev, int block)
if (!(sb = get_super(dev)))
panic("trying to free block on nonexistent device");
if (block < sb->s_firstdatazone || block >= sb->s_nzones)
if (block < sb->u.minix_sb.s_firstdatazone || block >= sb->u.minix_sb.s_nzones)
panic("trying to free block not in datazone");
bh = get_hash_table(dev,block);
bh = get_hash_table(dev,block,BLOCK_SIZE);
if (bh) {
if (bh->b_count > 1) {
brelse(bh);
......@@ -65,10 +94,10 @@ int minix_free_block(int dev, int block)
if (bh->b_count)
brelse(bh);
}
zone = block - sb->s_firstdatazone + 1;
zone = block - sb->u.minix_sb.s_firstdatazone + 1;
bit = zone & 8191;
zone >>= 13;
bh = sb->s_zmap[zone];
bh = sb->u.minix_sb.s_zmap[zone];
if (clear_bit(bit,bh->b_data))
printk("free_block (%04x:%d): bit already cleared\n",dev,block);
bh->b_dirt = 1;
......@@ -85,18 +114,18 @@ int minix_new_block(int dev)
panic("trying to get new block from nonexistant device");
j = 8192;
for (i=0 ; i<8 ; i++)
if (bh=sb->s_zmap[i])
if (bh=sb->u.minix_sb.s_zmap[i])
if ((j=find_first_zero(bh->b_data))<8192)
break;
if (i>=8 || !bh || j>=8192)
return 0;
if (set_bit(j,bh->b_data))
if (set_bit(j,bh->b_data))
panic("new_block: bit already set");
bh->b_dirt = 1;
j += i*8192 + sb->s_firstdatazone-1;
if (j >= sb->s_nzones)
j += i*8192 + sb->u.minix_sb.s_firstdatazone-1;
if (j >= sb->u.minix_sb.s_nzones)
return 0;
if (!(bh=getblk(dev,j)))
if (!(bh=getblk(dev,j,BLOCK_SIZE)))
panic("new_block: cannot get block");
if (bh->b_count != 1)
panic("new block: count is != 1");
......@@ -107,6 +136,12 @@ int minix_new_block(int dev)
return j;
}
unsigned long minix_count_free_blocks(struct super_block *sb)
{
return (sb->u.minix_sb.s_nzones - count_used(sb->u.minix_sb.s_zmap,sb->u.minix_sb.s_zmap_blocks,sb->u.minix_sb.s_nzones))
<< sb->u.minix_sb.s_log_zone_size;
}
void minix_free_inode(struct inode * inode)
{
struct buffer_head * bh;
......@@ -129,11 +164,11 @@ void minix_free_inode(struct inode * inode)
printk("free_inode: inode on nonexistent device\n");
return;
}
if (inode->i_ino < 1 || inode->i_ino > inode->i_sb->s_ninodes) {
if (inode->i_ino < 1 || inode->i_ino > inode->i_sb->u.minix_sb.s_ninodes) {
printk("free_inode: inode 0 or nonexistent inode\n");
return;
}
if (!(bh=inode->i_sb->s_imap[inode->i_ino>>13])) {
if (!(bh=inode->i_sb->u.minix_sb.s_imap[inode->i_ino>>13])) {
printk("free_inode: nonexistent imap in superblock\n");
return;
}
......@@ -156,12 +191,13 @@ struct inode * minix_new_inode(int dev)
iput(inode);
return NULL;
}
inode->i_flags = inode->i_sb->s_flags;
j = 8192;
for (i=0 ; i<8 ; i++)
if (bh=inode->i_sb->s_imap[i])
if (bh=inode->i_sb->u.minix_sb.s_imap[i])
if ((j=find_first_zero(bh->b_data))<8192)
break;
if (!bh || j >= 8192 || j+i*8192 > inode->i_sb->s_ninodes) {
if (!bh || j >= 8192 || j+i*8192 > inode->i_sb->u.minix_sb.s_ninodes) {
iput(inode);
return NULL;
}
......@@ -179,6 +215,11 @@ struct inode * minix_new_inode(int dev)
inode->i_dirt = 1;
inode->i_ino = j + i*8192;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_op = &minix_inode_operations;
inode->i_op = NULL;
return inode;
}
unsigned long minix_count_free_inodes(struct super_block *sb)
{
return sb->u.minix_sb.s_ninodes - count_used(sb->u.minix_sb.s_imap,sb->u.minix_sb.s_imap_blocks,sb->u.minix_sb.s_ninodes);
}
/*
* linux/fs/minix/blkdev.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/tty.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
/*
* Called every time a minix block special file is opened
*/
static int blkdev_open(struct inode * inode, struct file * filp)
{
int i;
i = MAJOR(inode->i_rdev);
if (i < MAX_BLKDEV) {
filp->f_op = blkdev_fops[i];
if (filp->f_op && filp->f_op->open)
return filp->f_op->open(inode,filp);
}
return 0;
}
/*
* Dummy default file-operations: the only thing this does
* is contain the open that then fills in the correct operations
* depending on the special file...
*/
static struct file_operations def_blk_fops = {
NULL, /* lseek */
NULL, /* read */
NULL, /* write */
NULL, /* readdir */
NULL, /* select */
NULL, /* ioctl */
blkdev_open, /* open */
NULL, /* release */
};
struct inode_operations minix_blkdev_inode_operations = {
&def_blk_fops, /* default file operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
minix_bmap, /* bmap */
minix_truncate /* truncate */
};
/*
* linux/fs/minix/chrdev.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/tty.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
/*
* Called every time a minix character special file is opened
*/
static int chrdev_open(struct inode * inode, struct file * filp)
{
int i;
i = MAJOR(inode->i_rdev);
if (i < MAX_CHRDEV) {
filp->f_op = chrdev_fops[i];
if (filp->f_op && filp->f_op->open)
return filp->f_op->open(inode,filp);
}
return 0;
}
/*
* Dummy default file-operations: the only thing this does
* is contain the open that then fills in the correct operations
* depending on the special file...
*/
static struct file_operations def_chr_fops = {
NULL, /* lseek */
NULL, /* read */
NULL, /* write */
NULL, /* readdir */
NULL, /* select */
NULL, /* ioctl */
chrdev_open, /* open */
NULL, /* release */
};
struct inode_operations minix_chrdev_inode_operations = {
&def_chr_fops, /* default file operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
minix_bmap, /* bmap */
minix_truncate /* truncate */
};
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -94,6 +94,6 @@ extern inline unsigned long get_ds()
extern inline void set_fs(unsigned long val)
{
__asm__("mov %0,%%fs"::"r" ((unsigned short) val));
__asm__ __volatile__("mov %0,%%fs"::"r" ((unsigned short) val));
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment