Commit d1e6fdb2 authored by Linus Torvalds's avatar Linus Torvalds

[PATCH] Linux-0.96-pre (April 21, 1992)

More VFS layer work: remove more special cases, and take advantage of
the virtual VFS functions (close and select).  Add fchown/fchgrp and
[f]truncate.

Orest Zborowski shows up, and works on porting X11 to X.  This needs a
lot of infrastructure support: ioperm() for user-mode IO port access,
and SVR style virtual terminal ioctl's to make porting easier.  Perhaps
more importantly, the mmap() system call shows up, even if it right now
is limited only to a direct /dev/mem remapping.

[Original changelog below]

- truncate/ftruncate/fchmod/fchown system calls

        note that there aren't any library functions for these, so they
        aren't very useful yet...

        [f]truncate needed a change in the logic of the internal
        truncate VFS call - anybody that has any nonstandard filesystem
        probably needs to look it up.

- io-bitmap syscalls giving root-processes access to selected io ports
  from user space.  There is a "ioperm()" system call that lets the
  process select which ports it wants to enable/disable (all ports
  disabled as default) as well as a (standard sysv?) ioctl interface
  that X uses.

        again, no library stubs, but it allows things like reading and
        setting the cmos clock without using /dev/port, as well as
        control over the VGA registers...

- mmap for /dev/mem

        more things needed for X...

- the signal-handling fixes needed for gdb

        These aren't yet complete: serial lines still send signals under
        interrupts that can result in problems (ie ptrace doesn't
        correctly get them), but that's pretty unlikely (and will be
        fixed in the final 0.96).  Breakpoints should work etc..

- multiple shared libraries

        Up to 6 simultaneous shared libraries/process: the patches were
        originally by pmacdona, but they were heavily changed by me, and
        I think they work in a more natural manner now.  One user-level
        change is that the libraries are now checked for read and
        execute permissions for safety-reasons.

- cleaned up special files.

        read/write/ioctl no longer has special-case code: it is all
        handled with tables to functions.  This will mean that the SCSI
        patches won't patch in quite cleanly into 0.96: you'll need to
        add the code that sets up the functions.

        Again: device drivers and vfs-filesystem hackers need to look
        into the changes, although they are pretty logical (earlier
        versions just didn't implement all the vfs-routines)

        Note that the vfs-code for select is still not used: select is
        hardcoded for the devices it supports right now.

- ptrace() has a new interface

        as gdb for versions < 0.95c don't work on the new version, and
        gdb won't work very well at all on 0.95c[+], there was no reason
        not to break ptrace.  Thus 0.96 has a new calling convention for
        ptrace, and the old ptrace library function no longer works.
        I'm including the new ptrace library function at the end of this
        post.

- mount() takes 4 arguments, and checks that only the super-user can
  mount/umount things.

        Happily this shouldn't break any old binaries.

- some general cleanups
parent 6f8473c7
#
# 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'.
# comment this line if you don't want the emulation-code
#
ROOT_DEV = /dev/hdb1
MATH_EMULATION = -DKERNEL_MATH_EMULATION
#
# uncomment the correct keyboard:
#
# 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 = -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
#
# comment this line if you don't want the emulation-code
# standard CFLAGS
#
MATH_EMULATION = -DKERNEL_MATH_EMULATION
CFLAGS =-Wall -O6 -fomit-frame-pointer $(GCC_OPT)
#
# standard CFLAGS
# 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'.
#
CFLAGS =-Wall -O6 -fomit-frame-pointer
ROOT_DEV = /dev/hdb1
#
# if you want the ram-disk device, define this to be the
......@@ -61,37 +46,32 @@ LD86 =ld86 -0
AS =as
LD =ld
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
#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
MATH =kernel/math/math.a
LIBS =lib/lib.a
SUBDIRS =kernel mm fs net lib
KERNELHDRS =/usr/src/linux/include
.c.s:
$(CC) $(CFLAGS) -S $<
$(CC) $(CFLAGS) \
-nostdinc -Iinclude -S -o $*.s $<
.s.o:
$(AS) -c -o $*.o $<
.c.o:
$(CC) $(CFLAGS) -c -o $*.o $<
$(CC) $(CFLAGS) \
-nostdinc -Iinclude -c -o $*.o $<
all: Version Image
subdirs: dummy
for i in $(SUBDIRS); do (cd $$i; $(MAKE)); done
Version:
@./makever.sh
@echo \#define UTS_RELEASE \"0.96c.pl2-`cat .version`\" > include/linux/config_rel.h
@echo \#define UTS_RELEASE \"0.95c-`cat .version`\" > include/linux/config_rel.h
@echo \#define UTS_VERSION \"`date +%D`\" > include/linux/config_ver.h
touch include/linux/config.h
......@@ -106,19 +86,44 @@ disk: Image
dd bs=8192 if=Image of=/dev/PS0
tools/build: tools/build.c
$(HOSTCC) $(CFLAGS) \
$(CC) -static $(CFLAGS) \
-o tools/build tools/build.c
boot/head.o: boot/head.s
tools/system: boot/head.o init/main.o subdirs
$(LD) $(LDFLAGS) -M boot/head.o init/main.o \
$(ARCHIVES) \
$(FILESYSTEMS) \
$(DRIVERS) \
$(MATH) \
$(LIBS) \
-o tools/system > System.map
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))
boot/setup: boot/setup.s
$(AS86) -o boot/setup.o boot/setup.s
......@@ -138,28 +143,31 @@ 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
for i in $(SUBDIRS); do (cd $$i; $(MAKE) clean); done
(cd mm;make clean)
(cd fs;make clean)
(cd kernel;make clean)
(cd lib;make clean)
backup: clean
cd .. ; tar cf - linux | compress - > backup.Z
(cd .. ; tar cf - linux | compress - > backup.Z)
sync
depend dep:
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
for i in $(SUBDIRS); do (cd $$i; $(MAKE) dep); done
(cd fs; make dep)
(cd kernel; make dep)
(cd mm; make dep)
(cd lib; make dep)
dummy:
### Dependencies:
init/main.o : init/main.c /usr/src/linux/include/stddef.h /usr/src/linux/include/stdarg.h \
/usr/src/linux/include/time.h /usr/src/linux/include/sys/types.h /usr/src/linux/include/asm/system.h \
/usr/src/linux/include/asm/io.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/sys/dirent.h \
/usr/src/linux/include/limits.h /usr/src/linux/include/sys/vfs.h /usr/src/linux/include/linux/mm.h \
/usr/src/linux/include/linux/kernel.h /usr/src/linux/include/signal.h /usr/src/linux/include/sys/param.h \
/usr/src/linux/include/sys/time.h /usr/src/linux/include/sys/resource.h /usr/src/linux/include/linux/tty.h \
/usr/src/linux/include/termios.h /usr/src/linux/include/linux/unistd.h
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
......@@ -224,7 +224,8 @@ got_sectors:
mov ax,#0x021c ! /dev/PS0 - 1.44Mb
cmp bx,#18
je root_defined
mov ax,#0x0200 ! /dev/fd0 - autodetect
undef_root:
jmp undef_root
root_defined:
seg cs
mov root_dev,ax
......
......@@ -189,10 +189,9 @@ end_move:
out #0xA1,al
.word 0x00eb,0x00eb
mov al,#0xFF ! mask off all interrupts for now
out #0xA1,al
out #0x21,al
.word 0x00eb,0x00eb
mov al,#0xFB ! mask all irq's but irq2 which
out #0x21,al ! is cascaded
out #0xA1,al
! well, that certainly wasn't fun :-(. Hopefully it works, and we don't
! need no steenking BIOS anyway (except for the initial loading :-).
......@@ -242,75 +241,10 @@ chsvga: cld
push ds
push cs
pop ds
! First try and execute a VESA BIOS call
mov ax,#0x4f00 ! AX = VESA BIOS func RETURN SVGA Info
push cs
pop es
lea di,vib ! ES:[DI] -> VESA Information Block Ptr
int 0x10
cmp ax,#0x004f ! Check result status
jne novesa ! VESA BIOS not supported or failed
! OK! We got a VESA BIOS, let's figure out what we can do!
! Print out the VESA information from the VIB
lea si,vib ! This should print out VESA
lodsb
call prnt1
lodsb
call prnt1
lodsb
call prnt1
lodsb
call prnt1
call space
mov al,vib+5 ! This is the version of VESA supported
call dprnt
mov al,#0x2e
call prnt1
mov al,vib+4
call dprnt
call space
push ds
lds si,vib+6 ! This prints out the OEM string
call prtstr
call space
pop ds
mov al,vib+10 ! This prints out the Vesa Capabilities
call dprnt
mov al,vib+11
call dprnt
mov al,vib+12
call dprnt
mov al,vib+13
call dprnt
push ds ! Finally, go through the list of modes
lds si,vib+14
model: lodsw ! Get mode number
cmp ax,#0xFFFF
je isvesa
call addmod ! Check to see if this is a TEXT mode
jmp model
isvesa: call docr
pop ds
lea si,dscvesa
lea di,movesa
lea cx,selmod
jmp cx
novesa: mov ax,#0xc000
mov ax,#0xc000
mov es,ax
lea si,msg1
call prtstr ! Press <RETURN> to see SVGA-modes ...
call prtstr
flush: in al,#0x60 ! Flush the keyboard buffer
cmp al,#0x82
jb nokey
......@@ -529,38 +463,23 @@ even7: mov al,#0x0c
mov al,#0x55
xor al,#0xea
cmp al,bh
je isvideo7
lea cx,set8x8
jmp cx
isvideo7:
jne novid7
lea si,dscvideo7
lea di,movideo7
! Upon Entry to SELMOD, SI -> list of Modes, DI -> List of Mode Numbers
selmod: push si
lea si,msg2 ! Numb: Mode: COLSxROWS
lea si,msg2
call prtstr
mov cx,(di) ! This gets Number of Modes in list
xor cx,cx
mov cl,(di)
pop si
push si
push cx
tbl: pop bx
push bx
mov ax,bx
sub ax,cx
call hprntl ! Print out selection number
push ax
call spcing
pop ax
push di
add ax,ax
add ax,#2
add di,ax
mov ax,(di)
call hprntl ! Print out MODE number
mov al,bl
sub al,cl
call dprnt
call spcing
pop di
lodsw
xchg al,ah
call dprnt
......@@ -574,7 +493,7 @@ tbl: pop bx
loop tbl
pop cx
call docr
lea si,msg3 ! Choose Mode Number
lea si,msg3
call prtstr
pop si
add cl,#0x80
......@@ -590,38 +509,18 @@ zero: sub al,#0x0a
nozero: sub al,#0x80
dec al
xor ah,ah
shl ax,#1
push ax
add di,ax
inc di
inc di
mov ax,(di) ! AX = Mode
cmp ah,#0
jne setvesa
int 0x10 ! Set OLD style mode
retmode:
push ax
mov al,(di)
int 0x10
pop ax
shl ax,#1
add si,ax
lodsw ! Get COLSxROWS
lodsw
pop ds
ret
setvesa:
pop bx
cmp ah,#0xFF ! Special, mode FF, set 8x8 font
je set8x8
push bx
mov bx,ax ! Mode to set
mov ax,#0x4f02 ! Set VESA mode
int 0x10
jmp retmode
! If we can't find the adapter in the table, at least set 80x50
set8x8:
novid7:
mov ax,#0x1112
mov bl,#0
int 0x10 ! use 8x8 font set (50 lines on VGA)
......@@ -642,83 +541,17 @@ set8x8:
mov ax,#0x5032 ! return 80x50
ret
! Routine to add mode in ax to VESA selection table
addmod: push cx
push ds
push es
push di
push bx
push dx
push ax
mov cx,ax ! CX = VESA mode number
push cs
pop es
lea di,mib ! ES:[DI] -> Mode Information Block
mov ax,#0x4f01 ! AX = Get VESA Mode Info
int 0x10
cmp ax,#0x004f ! If fails, assume it's not a TEXT mode
jne adfail
push cs
pop ds ! Make DS contain something reasonable
mov ax,mib ! Get Mode Attributes field
and al,#0x12 ! Mask Text and Extended bits
cmp al,#0x02 ! Text and Extended info available?
jne adfail
call space
mov ax,mib+18 ! Horizontal Resolution
mov bl,mib+22 ! X Char Size
div bl
! HACK: For some reason, my Diamond Stealth card returns 160 cols for its
! 132 coloumn modes, so don't return any sizes > 132?
sub al,#132
jbe orgcol
sub al,al
orgcol: add al,#132 ! MIN(cols, 132)
mov dh,al ! Put num cols in DH
mov ax,mib+20 ! Vertical Resolution
mov bl,mib+23 ! Y Char Size
div bl
mov dl,al ! Put num rows in DL
mov bx,movesa ! Get current number of video modes
lea di,movesa
inc (di) ! This is a NEW mode
add bx,bx
add di,bx
add di,#2
pop ax ! Get Mode number back
push ax
mov (di),ax ! Mode number
lea di,dscvesa
add di,bx
mov (di),dx ! Screen resolution
adfail: pop ax
pop dx
pop bx
pop di
pop es
pop ds
pop cx
ret
! Routine that 'tabs' to next col.
spcing: mov al,#0x2e
call prnt1
mov al,#0x20
call prnt1
space3: mov al,#0x20
mov al,#0x20
call prnt1
space2: mov al,#0x20
mov al,#0x20
call prnt1
space: mov al,#0x20
mov al,#0x20
call prnt1
ret
......@@ -731,39 +564,6 @@ prtstr: lodsb
jmp prtstr
fin: ret
! Routine to print out HEX values on screen.
! The value to be printed is in the AX register.
hprntl: xchg ah,al
call hprnt
xchg ah,al
call hprnt
ret
! Routine to print out HEX values on the screen
! The valueto be printed is in the AL register. AH is preserved.
hprnt: push ax
shr al,4
and al,#0xf
call hprnt1
pop ax
push ax
and al,#0xf
call hprnt1
pop ax
ret
! Routine to print out one HEX digit on the screen.
! The value to be printed is in al (0-F)
hprnt1: cmp al,#10
jl hdec
add al,#7 ! Convert 10-15 to A-F
hdec: add al,#0x30 ! Convert to ASCII
call prnt1 ! print it
ret
! Routine to print a decimal value on screen, the value to be
! printed is put in al (i.e 0-255).
......@@ -835,7 +635,7 @@ gdt_48:
msg1: .ascii "Press <RETURN> to see SVGA-modes available or any other key to continue."
db 0x0d, 0x0a, 0x0a, 0x00
msg2: .ascii "Numb: Mode: COLSxROWS:"
msg2: .ascii "Mode: COLSxROWS:"
db 0x0d, 0x0a, 0x0a, 0x00
msg3: .ascii "Choose mode by pressing the corresponding number."
db 0x0d, 0x0a, 0x00
......@@ -847,17 +647,16 @@ idparadise: .ascii "VGA="
! Manufacturer: Numofmodes: Mode:
moati: .word 0x02, 0x23, 0x33
moahead: .word 0x05, 0x22, 0x23, 0x24, 0x2f, 0x34
mocandt: .word 0x02, 0x60, 0x61
mocirrus: .word 0x04, 0x1f, 0x20, 0x22, 0x31
moeverex: .word 0x0a, 0x03, 0x04, 0x07, 0x08, 0x0a, 0x0b, 0x16, 0x18, 0x21, 0x40
mogenoa: .word 0x0a, 0x58, 0x5a, 0x60, 0x61, 0x62, 0x63, 0x64, 0x72, 0x74, 0x78
moparadise: .word 0x02, 0x55, 0x54
motrident: .word 0x07, 0x50, 0x51, 0x52, 0x57, 0x58, 0x59, 0x5a
motseng: .word 0x05, 0x26, 0x2a, 0x23, 0x24, 0x22
movideo7: .word 0x06, 0x40, 0x43, 0x44, 0x41, 0x42, 0x45
movesa: .word 0x02, 0x03, 0xFFFF, 254*0
moati: .byte 0x02, 0x23, 0x33
moahead: .byte 0x05, 0x22, 0x23, 0x24, 0x2f, 0x34
mocandt: .byte 0x02, 0x60, 0x61
mocirrus: .byte 0x04, 0x1f, 0x20, 0x22, 0x31
moeverex: .byte 0x0a, 0x03, 0x04, 0x07, 0x08, 0x0a, 0x0b, 0x16, 0x18, 0x21, 0x40
mogenoa: .byte 0x0a, 0x58, 0x5a, 0x60, 0x61, 0x62, 0x63, 0x64, 0x72, 0x74, 0x78
moparadise: .byte 0x02, 0x55, 0x54
motrident: .byte 0x07, 0x50, 0x51, 0x52, 0x57, 0x58, 0x59, 0x5a
motseng: .byte 0x05, 0x26, 0x2a, 0x23, 0x24, 0x22
movideo7: .byte 0x06, 0x40, 0x43, 0x44, 0x41, 0x42, 0x45
! msb = Cols lsb = Rows:
......@@ -871,11 +670,7 @@ dscparadise: .word 0x8419, 0x842b
dsctrident: .word 0x501e, 0x502b, 0x503c, 0x8419, 0x841e, 0x842b, 0x843c
dsctseng: .word 0x503c, 0x6428, 0x8419, 0x841c, 0x842c
dscvideo7: .word 0x502b, 0x503c, 0x643c, 0x8419, 0x842c, 0x841c
dscvesa: .word 0x5019, 0x5032, 254*0
vib: .word 256*0
mib: .word 256*0
.text
endtext:
.data
......
This diff is collapsed.
......@@ -30,7 +30,7 @@ extern int end;
static struct buffer_head * start_buffer = (struct buffer_head *) &end;
static struct buffer_head * hash_table[NR_HASH];
static struct buffer_head * free_list;
static struct wait_queue * buffer_wait = NULL;
static struct task_struct * buffer_wait = NULL;
int NR_BUFFERS = 0;
static inline void wait_on_buffer(struct buffer_head * bh)
......@@ -47,25 +47,23 @@ static void sync_buffers(int dev)
struct buffer_head * bh;
bh = free_list;
for (i = NR_BUFFERS*2 ; i-- > 0 ; bh = bh->b_next_free) {
if (bh->b_lock)
for (i=0 ; i<NR_BUFFERS ; i++,bh = bh->b_next_free) {
#if 0
if (dev && (bh->b_dev != dev))
continue;
if (!bh->b_dirt)
#endif
wait_on_buffer(bh);
#if 0
if (dev && (bh->b_dev != dev))
continue;
ll_rw_block(WRITE,bh);
#endif
if (bh->b_dirt)
ll_rw_block(WRITE,bh);
}
}
int sys_sync(void)
{
int i;
for (i=0 ; i<NR_SUPER ; i++)
if (super_block[i].s_dev
&& super_block[i].s_op
&& super_block[i].s_op->write_super
&& super_block[i].s_dirt)
super_block[i].s_op->write_super(&super_block[i]);
sync_inodes(); /* write out inodes into buffers */
sync_buffers(0);
return 0;
......@@ -73,11 +71,6 @@ int sys_sync(void)
int sync_dev(int dev)
{
struct super_block * sb;
if (sb = get_super (dev))
if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
sb->s_op->write_super (sb);
sync_buffers(dev);
sync_inodes();
sync_buffers(dev);
......@@ -265,7 +258,9 @@ struct buffer_head * getblk(int dev,int block)
if (bh = get_hash_table(dev,block))
return bh;
buffers = NR_BUFFERS;
for (tmp = free_list ; buffers-- > 0 ; tmp = tmp->b_next_free) {
tmp = free_list;
do {
tmp = tmp->b_next_free;
if (tmp->b_count)
continue;
if (!bh || BADNESS(tmp)<BADNESS(bh)) {
......@@ -273,12 +268,10 @@ struct buffer_head * getblk(int dev,int block)
if (!BADNESS(tmp))
break;
}
#if 0
if (tmp->b_dirt)
ll_rw_block(WRITEA,tmp);
#endif
}
/* and repeat until we find something good */
} while (buffers--);
if (!bh) {
sleep_on(&buffer_wait);
goto repeat;
......@@ -286,9 +279,11 @@ struct buffer_head * getblk(int dev,int block)
wait_on_buffer(bh);
if (bh->b_count)
goto repeat;
if (bh->b_dirt) {
sync_buffers(bh->b_dev);
goto repeat;
while (bh->b_dirt) {
sync_dev(bh->b_dev);
wait_on_buffer(bh);
if (bh->b_count)
goto repeat;
}
/* NOTE!! While we slept waiting for this block, somebody else might */
/* already have added "this" block to the cache. check it */
......@@ -389,7 +384,7 @@ struct buffer_head * breada(int dev,int first, ...)
tmp=getblk(dev,first);
if (tmp) {
if (!tmp->b_uptodate)
ll_rw_block(READA,tmp);
ll_rw_block(READA,bh);
tmp->b_count--;
}
}
......@@ -425,7 +420,6 @@ void buffer_init(long buffer_end)
h->b_next = NULL;
h->b_prev = NULL;
h->b_data = (char *) b;
h->b_reqnext = NULL;
h->b_prev_free = h-1;
h->b_next_free = h+1;
h++;
......
......@@ -19,18 +19,15 @@
#include <signal.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <linux/string.h>
#include <sys/stat.h>
#include <a.out.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/segment.h>
#include <sys/user.h>
extern int sys_exit(int exit_code);
extern int sys_close(int fd);
......@@ -42,121 +39,6 @@ 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.
......@@ -169,8 +51,6 @@ int sys_uselib(const char * library)
struct inode * inode;
struct buffer_head * bh;
struct exec ex;
int i;
struct file * f;
if (get_limit(0x17) != TASK_SIZE)
return -EINVAL;
......@@ -182,20 +62,11 @@ int sys_uselib(const char * library)
inode = NULL;
if (!inode)
return -ENOENT;
if (!S_ISREG(inode->i_mode) || !permission(inode,MAY_READ)) {
if (!S_ISREG(inode->i_mode) || !permission(inode,MAY_READ|MAY_EXEC)) {
iput(inode);
return -EACCES;
}
if (inode->i_count > 1) { /* check for writers */
f=0+file_table;
for (i=0 ; i<NR_FILE ; i++,f++ )
if (f->f_count && (f->f_mode & 2))
if (inode == f->f_inode) {
iput(inode);
return -ETXTBSY;
}
}
if (!(bh = bread(inode->i_dev,bmap(inode,0)))) {
if (!(bh = bread(inode->i_dev,inode->i_data[0]))) {
iput(inode);
return -EACCES;
}
......@@ -287,7 +158,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 = NULL;
char *tmp, *pag;
int len, offset = 0;
unsigned long old_fs, new_fs;
......@@ -358,32 +229,6 @@ 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;
while (bytes > 0) {
if (!(blkno = bmap(inode, blk)))
sys_exit(-1);
if (!(bh = bread(inode->i_dev, blkno)))
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.
*
......@@ -403,7 +248,6 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
int sh_bang = 0;
unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;
int ch;
struct file * f;
if ((0xffff & eip[1]) != 0x000f)
panic("execve called from supervisor mode");
......@@ -411,15 +255,6 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
page[i]=0;
if (!(inode=namei(filename))) /* get executables inode */
return -ENOENT;
if (inode->i_count > 1) { /* check for writers */
f=0+file_table;
for (i=0 ; i<NR_FILE ; i++,f++ )
if (f->f_count && (f->f_mode & 2))
if (inode == f->f_inode) {
retval = -ETXTBSY;
goto exec_error2;
}
}
argc = count(argv);
envc = count(envp);
......@@ -428,17 +263,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 */
retval = -EPERM;
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;
......@@ -456,7 +281,7 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
retval = -EACCES;
goto exec_error2;
}
if (!(bh = bread(inode->i_dev,bmap(inode,0)))) {
if (!(bh = bread(inode->i_dev,inode->i_data[0]))) {
retval = -EACCES;
goto exec_error2;
}
......@@ -534,14 +359,13 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
goto restart_interp;
}
brelse(bh);
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC) ||
ex.a_trsize || ex.a_drsize ||
if (N_MAGIC(ex) != ZMAGIC || 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 && N_MAGIC(ex) != OMAGIC) {
if (N_TXTOFF(ex) != BLOCK_SIZE) {
printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename);
retval = -ENOEXEC;
goto exec_error2;
......@@ -555,7 +379,6 @@ 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;
......@@ -571,9 +394,6 @@ 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;
......@@ -602,12 +422,10 @@ 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/string.h /usr/src/linux/include/sys/types.h \
/usr/src/linux/include/stddef.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/sys/dirent.h /usr/src/linux/include/limits.h \
/usr/src/linux/include/sys/vfs.h /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h \
/usr/src/linux/include/signal.h /usr/src/linux/include/sys/param.h /usr/src/linux/include/sys/time.h \
/usr/src/linux/include/time.h /usr/src/linux/include/sys/resource.h /usr/src/linux/include/linux/ext_fs.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/sys/types.h /usr/src/linux/include/stddef.h \
/usr/src/linux/include/sys/dirent.h /usr/src/linux/include/limits.h /usr/src/linux/include/sys/vfs.h \
/usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/signal.h \
/usr/src/linux/include/sys/param.h /usr/src/linux/include/sys/time.h /usr/src/linux/include/time.h \
/usr/src/linux/include/sys/resource.h /usr/src/linux/include/linux/ext_fs.h \
/usr/src/linux/include/linux/tty.h /usr/src/linux/include/asm/system.h /usr/src/linux/include/termios.h \
/usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/fcntl.h /usr/src/linux/include/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/sys/types.h /usr/src/linux/include/stddef.h \
/usr/src/linux/include/sys/dirent.h /usr/src/linux/include/limits.h /usr/src/linux/include/sys/vfs.h \
/usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/signal.h \
/usr/src/linux/include/sys/param.h /usr/src/linux/include/sys/time.h /usr/src/linux/include/time.h \
/usr/src/linux/include/sys/resource.h /usr/src/linux/include/linux/ext_fs.h \
/usr/src/linux/include/linux/tty.h /usr/src/linux/include/asm/system.h /usr/src/linux/include/termios.h \
/usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/fcntl.h /usr/src/linux/include/errno.h
dir.o : dir.c /usr/src/linux/include/errno.h /usr/src/linux/include/asm/segment.h \
/usr/src/linux/include/linux/fs.h /usr/src/linux/include/sys/types.h /usr/src/linux/include/stddef.h \
/usr/src/linux/include/sys/dirent.h /usr/src/linux/include/limits.h /usr/src/linux/include/sys/vfs.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/sys/types.h /usr/src/linux/include/stddef.h \
/usr/src/linux/include/sys/dirent.h /usr/src/linux/include/limits.h /usr/src/linux/include/sys/vfs.h \
/usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/signal.h \
/usr/src/linux/include/sys/param.h /usr/src/linux/include/sys/time.h /usr/src/linux/include/time.h \
/usr/src/linux/include/sys/resource.h /usr/src/linux/include/linux/ext_fs.h
file.o : file.c /usr/src/linux/include/errno.h /usr/src/linux/include/sys/dirent.h \
/usr/src/linux/include/limits.h /usr/src/linux/include/sys/types.h /usr/src/linux/include/stddef.h \
/usr/src/linux/include/asm/segment.h /usr/src/linux/include/asm/system.h /usr/src/linux/include/linux/fcntl.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/sys/vfs.h /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h \
/usr/src/linux/include/signal.h /usr/src/linux/include/sys/param.h /usr/src/linux/include/sys/time.h \
/usr/src/linux/include/time.h /usr/src/linux/include/sys/resource.h /usr/src/linux/include/linux/ext_fs.h \
/usr/src/linux/include/linux/stat.h
freelists.o : freelists.c /usr/src/linux/include/linux/string.h /usr/src/linux/include/sys/types.h \
/usr/src/linux/include/stddef.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/sys/dirent.h /usr/src/linux/include/limits.h \
/usr/src/linux/include/sys/vfs.h /usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h \
/usr/src/linux/include/signal.h /usr/src/linux/include/sys/param.h /usr/src/linux/include/sys/time.h \
/usr/src/linux/include/time.h /usr/src/linux/include/sys/resource.h /usr/src/linux/include/linux/ext_fs.h
inode.o : inode.c /usr/src/linux/include/linux/string.h /usr/src/linux/include/sys/types.h \
/usr/src/linux/include/stddef.h /usr/src/linux/include/linux/stat.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/sys/dirent.h \
/usr/src/linux/include/limits.h /usr/src/linux/include/sys/vfs.h /usr/src/linux/include/linux/mm.h \
/usr/src/linux/include/linux/kernel.h /usr/src/linux/include/signal.h /usr/src/linux/include/sys/param.h \
/usr/src/linux/include/sys/time.h /usr/src/linux/include/time.h /usr/src/linux/include/sys/resource.h \
/usr/src/linux/include/linux/ext_fs.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/sys/types.h /usr/src/linux/include/stddef.h \
/usr/src/linux/include/sys/dirent.h /usr/src/linux/include/limits.h /usr/src/linux/include/sys/vfs.h \
/usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/signal.h \
/usr/src/linux/include/sys/param.h /usr/src/linux/include/sys/time.h /usr/src/linux/include/time.h \
/usr/src/linux/include/sys/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/asm/segment.h /usr/src/linux/include/errno.h /usr/src/linux/include/const.h
symlink.o : symlink.c /usr/src/linux/include/errno.h /usr/src/linux/include/asm/segment.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/sys/types.h /usr/src/linux/include/stddef.h /usr/src/linux/include/sys/dirent.h \
/usr/src/linux/include/limits.h /usr/src/linux/include/sys/vfs.h /usr/src/linux/include/linux/mm.h \
/usr/src/linux/include/linux/kernel.h /usr/src/linux/include/signal.h /usr/src/linux/include/sys/param.h \
/usr/src/linux/include/sys/time.h /usr/src/linux/include/time.h /usr/src/linux/include/sys/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/sys/types.h /usr/src/linux/include/stddef.h \
/usr/src/linux/include/sys/dirent.h /usr/src/linux/include/limits.h /usr/src/linux/include/sys/vfs.h \
/usr/src/linux/include/linux/mm.h /usr/src/linux/include/linux/kernel.h /usr/src/linux/include/signal.h \
/usr/src/linux/include/sys/param.h /usr/src/linux/include/sys/time.h /usr/src/linux/include/time.h \
/usr/src/linux/include/sys/resource.h /usr/src/linux/include/linux/ext_fs.h \
/usr/src/linux/include/linux/tty.h /usr/src/linux/include/asm/system.h /usr/src/linux/include/termios.h \
/usr/src/linux/include/linux/stat.h /usr/src/linux/include/linux/fcntl.h /usr/src/linux/include/errno.h
/*
* linux/fs/ext/bitmap.c
*
* (C) 1992 Remy Card (card@masi.ibp.fr)
*
* from
*
* linux/fs/minix/bitmap.c
*
* (C) 1991 Linus Torvalds
*/
/* bitmap.c contains the code that handles the inode and block bitmaps */
#include <linux/string.h>
#include <linux/sched.h>
#include <linux/ext_fs.h>
#include <linux/kernel.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
*
* (C) 1992 Remy Card (card@masi.ibp.fr)
*
* from
*
* linux/fs/minix/blkdev.c
*
* (C) 1991 Linus Torvalds
*/
#include <linux/sched.h>
#include <linux/ext_fs.h>
#include <linux/tty.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <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
*
* (C) 1992 Remy Card (card@masi.ibp.fr)
*
* from
*
* linux/fs/minix/chrdev.c
*
* (C) 1991 Linus Torvalds
*/
#include <linux/sched.h>
#include <linux/ext_fs.h>
#include <linux/tty.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <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
*
* (C) 1992 Remy Card (card@masi.ibp.fr)
*
* from
*
* linux/fs/minix/dir.c
*
* (C) 1991 Linus Torvalds
*
* ext directory handling functions
*/
#include <errno.h>
#include <asm/segment.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))) {
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
*
* (C) 1992 Remy Card (card@masi.ibp.fr)
*
* from
*
* linux/fs/minix/file.c
*
* (C) 1991 Linus Torvalds
*
* ext regular file handling primitives
*/
#include <errno.h>
#include <sys/dirent.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <linux/fcntl.h>
#include <linux/sched.h>
#include <linux/ext_fs.h>
#include <linux/kernel.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);
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);
else
bh = bread(inode->i_dev,block);
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;
}
/*
* linux/fs/ext/freelists.c
*
* (C) 1992 Remy Card (card@masi.ibp.fr)
*
*/
/* freelists.c contains the code that handles the inode and block free lists */
/*
The free blocks are managed by a linked list. The super block contains the
number of the first free block. This block contains 254 numbers of other
free blocks and the number of the next block in the list.
When an ext fs is mounted, the number of the first free block is stored
in s->s_zmap[0] and the block header is stored in s->s_zmap[1]. s_zmap[2]
contains the count of free blocks.
Currently, it is a hack to allow this kind of management with the super_block
structure.
Perhaps, in the future, we may have to change the super_block structure to
include dedicated fields.
The free inodes are also managed by a linked list in a similar way. The
super block contains the number of the first free inode. This inode contains
14 numbers of other free inodes and the number of the next inode in the list.
The number of the first free inode is stored in s->s_imap[0] and the header
of the block containing the inode is stored in s->s_imap[1]. s_imap[2] contains
the count of free inodes.
*/
#include <linux/string.h>
#include <linux/sched.h>
#include <linux/ext_fs.h>
#include <linux/kernel.h>
#ifdef EXTFS_FREELIST
#define clear_block(addr) \
__asm__("cld\n\t" \
"rep\n\t" \
"stosl" \
::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di")
int ext_free_block(int dev, int block)
{
struct super_block * sb;
struct buffer_head * bh;
struct ext_free_block * efb;
if (!(sb = get_super(dev)))
panic("trying to free block on nonexistent device");
lock_super (sb);
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);
free_super (sb);
return 0;
}
bh->b_dirt=0;
bh->b_uptodate=0;
if (bh->b_count)
brelse(bh);
}
if (sb->s_zmap[1])
efb = (struct ext_free_block *) sb->s_zmap[1]->b_data;
if (!sb->s_zmap[1] || efb->count == 254) {
#ifdef EXTFS_DEBUG
printk("ext_free_block: block full, skipping to %d\n", block);
#endif
if (sb->s_zmap[1])
brelse (sb->s_zmap[1]);
if (!(sb->s_zmap[1] = bread (dev, block)))
panic ("ext_free_block: unable to read block to free\n");
efb = (struct ext_free_block *) sb->s_zmap[1]->b_data;
efb->next = (unsigned long) sb->s_zmap[0];
efb->count = 0;
sb->s_zmap[0] = (struct buffer_head *) block;
} else {
efb->free[efb->count++] = block;
}
sb->s_zmap[2] = (struct buffer_head *) (((unsigned long) sb->s_zmap[2]) + 1);
sb->s_dirt = 1;
sb->s_zmap[1]->b_dirt = 1;
free_super (sb);
return 1;
}
int ext_new_block(int dev)
{
struct buffer_head * bh;
struct super_block * sb;
struct ext_free_block * efb;
int /* i, */ j;
if (!(sb = get_super(dev)))
panic("trying to get new block from nonexistant device");
if (!sb->s_zmap[1])
return 0;
lock_super (sb);
efb = (struct ext_free_block *) sb->s_zmap[1]->b_data;
if (efb->count) {
j = efb->free[--efb->count];
sb->s_zmap[1]->b_dirt = 1;
} else {
#ifdef EXTFS_DEBUG
printk("ext_new_block: block empty, skipping to %d\n", efb->next);
#endif
j = (unsigned long) sb->s_zmap[0];
sb->s_zmap[0] = (struct buffer_head *) efb->next;
brelse (sb->s_zmap[1]);
if (!sb->s_zmap[0]) {
sb->s_zmap[1] = NULL;
} else {
if (!(sb->s_zmap[1] = bread (dev, (unsigned long) sb->s_zmap[0])))
panic ("ext_new_block: unable to read next free block\n");
}
}
if (j < sb->s_firstdatazone || j > sb->s_nzones) {
printk ("ext_new_block: blk = %d\n", j);
panic ("allocating block not in data zone\n");
}
sb->s_zmap[2] = (struct buffer_head *) (((unsigned long) sb->s_zmap[2]) - 1);
sb->s_dirt = 1;
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
free_super (sb);
return j;
}
unsigned long ext_count_free_blocks(struct super_block *sb)
{
#ifdef EXTFS_DEBUG
struct buffer_head * bh;
struct ext_free_block * efb;
unsigned long count, block;
lock_super (sb);
if (!sb->s_zmap[1])
count = 0;
else {
efb = (struct ext_free_block *) sb->s_zmap[1]->b_data;
count = efb->count + 1;
block = efb->next;
while (block) {
if (!(bh = bread (sb->s_dev, block))) {
printk ("ext_count_free: error while reading free blocks list\n");
block = 0;
} else {
efb = (struct ext_free_block *) bh->b_data;
count += efb->count + 1;
block = efb->next;
brelse (bh);
}
}
}
printk("ext_count_free_blocks: stored = %d, computed = %d\n",
(unsigned long) sb->s_zmap[2], count);
free_super (sb);
return count;
#else
return (unsigned long) sb->s_zmap[2];
#endif
}
void ext_free_inode(struct inode * inode)
{
struct buffer_head * bh;
struct ext_free_inode * efi;
unsigned long block;
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;
}
lock_super (inode->i_sb);
if (inode->i_ino < 1 || inode->i_ino > inode->i_sb->s_ninodes) {
printk("free_inode: inode 0 or nonexistent inode\n");
free_super (inode->i_sb);
return;
}
if (inode->i_sb->s_imap[1])
efi = ((struct ext_free_inode *) inode->i_sb->s_imap[1]->b_data) +
(((unsigned long) inode->i_sb->s_imap[0])-1)%EXT_INODES_PER_BLOCK;
if (!inode->i_sb->s_imap[1] || efi->count == 14) {
#ifdef EXTFS_DEBUG
printk("ext_free_inode: inode full, skipping to %d\n", inode->i_ino);
#endif
if (inode->i_sb->s_imap[1])
brelse (inode->i_sb->s_imap[1]);
block = 2 + (inode->i_ino - 1) / EXT_INODES_PER_BLOCK;
if (!(bh = bread(inode->i_dev, block)))
panic("ext_free_inode: unable to read inode block\n");
efi = ((struct ext_free_inode *) bh->b_data) +
(inode->i_ino - 1) % EXT_INODES_PER_BLOCK;
efi->next = (unsigned long) inode->i_sb->s_imap[0];
efi->count = 0;
inode->i_sb->s_imap[0] = (struct buffer_head *) inode->i_ino;
inode->i_sb->s_imap[1] = bh;
} else {
efi->free[efi->count++] = inode->i_ino;
}
inode->i_sb->s_imap[2] = (struct buffer_head *) (((unsigned long) inode->i_sb->s_imap[2]) + 1);
inode->i_sb->s_dirt = 1;
inode->i_sb->s_imap[1]->b_dirt = 1;
free_super (inode->i_sb);
memset(inode,0,sizeof(*inode));
}
struct inode * ext_new_inode(int dev)
{
struct inode * inode;
struct ext_free_inode * efi;
unsigned long block;
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;
if (!inode->i_sb->s_imap[1])
return 0;
lock_super (inode->i_sb);
efi = ((struct ext_free_inode *) inode->i_sb->s_imap[1]->b_data) +
(((unsigned long) inode->i_sb->s_imap[0])-1)%EXT_INODES_PER_BLOCK;
if (efi->count) {
j = efi->free[--efi->count];
inode->i_sb->s_imap[1]->b_dirt = 1;
} else {
#ifdef EXTFS_DEBUG
printk("ext_free_inode: inode empty, skipping to %d\n", efi->next);
#endif
j = (unsigned long) inode->i_sb->s_imap[0];
if (efi->next < 1 || efi->next > inode->i_sb->s_ninodes) {
printk ("efi->next = %d\n", efi->next);
panic ("ext_new_inode: bad inode number in free list\n");
}
inode->i_sb->s_imap[0] = (struct buffer_head *) efi->next;
block = 2 + (((unsigned long) efi->next) - 1) / EXT_INODES_PER_BLOCK;
brelse (inode->i_sb->s_imap[1]);
if (!inode->i_sb->s_imap[0]) {
inode->i_sb->s_imap[1] = NULL;
} else {
if (!(inode->i_sb->s_imap[1] = bread (dev, block)))
panic ("ext_new_inode: unable to read next free inode block\n");
}
}
inode->i_sb->s_imap[2] = (struct buffer_head *) (((unsigned long) inode->i_sb->s_imap[2]) - 1);
inode->i_sb->s_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;
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
free_super (inode->i_sb);
return inode;
}
unsigned long ext_count_free_inodes(struct super_block *sb)
{
#ifdef EXTFS_DEBUG
struct buffer_head * bh;
struct ext_free_inode * efi;
unsigned long count, block, ino;
lock_super (sb);
if (!sb->s_imap[1])
count = 0;
else {
efi = ((struct ext_free_inode *) sb->s_imap[1]->b_data) +
((((unsigned long) sb->s_imap[0])-1)%EXT_INODES_PER_BLOCK);
count = efi->count + 1;
ino = efi->next;
while (ino) {
if (ino < 1 || ino > sb->s_ninodes) {
printk ("s_imap[0] = %d, ino = %d\n",
(int) sb->s_imap[0],ino);
panic ("ext_count_fre_inodes: bad inode number in free list\n");
}
block = 2 + ((ino - 1) / EXT_INODES_PER_BLOCK);
if (!(bh = bread (sb->s_dev, block))) {
printk ("ext_count_free_inodes: error while reading free inodes list\n");
block = 0;
} else {
efi = ((struct ext_free_inode *) bh->b_data) +
((ino - 1) % EXT_INODES_PER_BLOCK);
count += efi->count + 1;
ino = efi->next;
brelse (bh);
}
}
}
printk("ext_count_free_inodes: stored = %d, computed = %d\n",
(unsigned long) sb->s_imap[2], count);
free_super (sb);
return count;
#else
return (unsigned long) sb->s_imap[2];
#endif
}
#endif
/*
* linux/fs/ext/inode.c
*
* (C) 1992 Remy Card (card@masi.ibp.fr)
*
* from
*
* linux/fs/minix/inode.c
*
* (C) 1991 Linus Torvalds
*/
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/sched.h>
#include <linux/ext_fs.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/system.h>
#include <asm/segment.h>
int sync_dev(int dev);
void ext_put_inode(struct inode *inode)
{
inode->i_size = 0;
ext_truncate(inode);
ext_free_inode(inode);
}
void ext_put_super(struct super_block *sb)
{
#ifdef EXTFS_BITMAP
int i;
#endif
lock_super(sb);
sb->s_dev = 0;
#ifdef EXTFS_BITMAP
for(i = 0 ; i < EXT_I_MAP_SLOTS ; i++)
brelse(sb->s_imap[i]);
for(i = 0 ; i < EXT_Z_MAP_SLOTS ; i++)
brelse(sb->s_zmap[i]);
#endif
#ifdef EXTFS_FREELIST
if (sb->s_imap[1])
brelse (sb->s_imap[1]);
if (sb->s_zmap[1])
brelse (sb->s_zmap[1]);
#endif
free_super(sb);
return;
}
static struct super_operations ext_sops = {
ext_read_inode,
ext_write_inode,
ext_put_inode,
ext_put_super,
ext_write_super,
ext_statfs
};
struct super_block *ext_read_super(struct super_block *s,void *data)
{
struct buffer_head *bh;
struct ext_super_block *es;
int dev=s->s_dev,block;
#ifdef EXTFS_BITMAP
int i;
#endif
lock_super(s);
if (!(bh = bread(dev,1))) {
s->s_dev=0;
free_super(s);
printk("bread failed\n");
return NULL;
}
/* *((struct ext_super_block *) s) =
*((struct ext_super_block *) bh->b_data); */
es = (struct ext_super_block *) bh->b_data;
s->s_ninodes = es->s_ninodes;
s->s_nzones = es->s_nzones;
#ifdef EXTFS_BITMAP
s->s_imap_blocks = es->s_imap_blocks;
s->s_zmap_blocks = es->s_zmap_blocks;
#endif
s->s_firstdatazone = es->s_firstdatazone;
s->s_log_zone_size = es->s_log_zone_size;
s->s_max_size = es->s_max_size;
s->s_magic = es->s_magic;
#ifdef EXTFS_FREELIST
s->s_zmap[0] = (struct buffer_head *) es->s_firstfreeblock;
s->s_zmap[2] = (struct buffer_head *) es->s_freeblockscount;
s->s_imap[0] = (struct buffer_head *) es->s_firstfreeinode;
s->s_imap[2] = (struct buffer_head *) es->s_freeinodescount;
#endif
brelse(bh);
if (s->s_magic != EXT_SUPER_MAGIC) {
s->s_dev = 0;
free_super(s);
printk("magic match failed\n");
return NULL;
}
#ifdef EXTFS_BITMAP
for (i=0;i < EXT_I_MAP_SLOTS;i++)
s->s_imap[i] = NULL;
for (i=0;i < EXT_Z_MAP_SLOTS;i++)
s->s_zmap[i] = NULL;
block=2;
for (i=0 ; i < s->s_imap_blocks ; i++)
if (s->s_imap[i]=bread(dev,block))
block++;
else
break;
for (i=0 ; i < s->s_zmap_blocks ; i++)
if (s->s_zmap[i]=bread(dev,block))
block++;
else
break;
if (block != 2+s->s_imap_blocks+s->s_zmap_blocks) {
for(i=0;i<EXT_I_MAP_SLOTS;i++)
brelse(s->s_imap[i]);
for(i=0;i<EXT_Z_MAP_SLOTS;i++)
brelse(s->s_zmap[i]);
s->s_dev=0;
free_super(s);
printk("block failed\n");
return NULL;
}
s->s_imap[0]->b_data[0] |= 1;
s->s_zmap[0]->b_data[0] |= 1;
#endif
#ifdef EXTFS_FREELIST
if (!s->s_zmap[0])
s->s_zmap[1] = NULL;
else
if (!(s->s_zmap[1] = bread (dev, (unsigned long) s->s_zmap[0]))) {
printk ("ext_read_super: unable to read first free block\n");
s->s_dev = 0;
free_super(s);
return NULL;
}
if (!s->s_imap[0])
s->s_imap[1] = NULL;
else {
block = 2 + (((unsigned long) s->s_imap[0]) - 1) / EXT_INODES_PER_BLOCK;
if (!(s->s_imap[1] = bread (dev, block))) {
printk ("ext_read_super: unable to read first free inode block\n");
brelse(s->s_zmap[1]);
s->s_dev = 0;
free_super (s);
return NULL;
}
}
#endif
free_super(s);
/* set up enough so that it can read an inode */
s->s_dev = dev;
s->s_op = &ext_sops;
if (!(s->s_mounted = iget(dev,EXT_ROOT_INO))) {
s->s_dev=0;
printk("get root inode failed\n");
return NULL;
}
return s;
}
void ext_write_super (struct super_block *sb)
{
#ifdef EXTFS_FREELIST
struct buffer_head * bh;
struct ext_super_block * es;
#ifdef EXTFS_DEBUG
printk ("ext_write_super called\n");
#endif
if (!(bh = bread (sb->s_dev, 1))) {
printk ("ext_write_super: bread failed\n");
return;
}
es = (struct ext_super_block *) bh->b_data;
es->s_firstfreeblock = (unsigned long) sb->s_zmap[0];
es->s_freeblockscount = (unsigned long) sb->s_zmap[2];
es->s_firstfreeinode = (unsigned long) sb->s_imap[0];
es->s_freeinodescount = (unsigned long) sb->s_imap[2];
bh->b_dirt = 1;
brelse (bh);
sb->s_dirt = 0;
#endif
}
void ext_statfs (struct super_block *sb, struct statfs *buf)
{
long tmp;
put_fs_long(EXT_SUPER_MAGIC, &buf->f_type);
put_fs_long(1024, &buf->f_bsize);
put_fs_long(sb->s_nzones << sb->s_log_zone_size, &buf->f_blocks);
tmp = ext_count_free_blocks(sb);
put_fs_long(tmp, &buf->f_bfree);
put_fs_long(tmp, &buf->f_bavail);
put_fs_long(sb->s_ninodes, &buf->f_files);
put_fs_long(ext_count_free_inodes(sb), &buf->f_ffree);
/* Don't know what value to put in buf->f_fsid */
}
static int _ext_bmap(struct inode * inode,int block,int create)
{
struct buffer_head * bh;
int i;
if (block<0) {
printk("_ext_bmap: block<0");
return 0;
}
if (block >= 9+256+256*256+256*256*256) {
printk("_ext_bmap: block>big");
return 0;
}
if (block<9) {
if (create && !inode->i_data[block])
if (inode->i_data[block]=ext_new_block(inode->i_dev)) {
inode->i_ctime=CURRENT_TIME;
inode->i_dirt=1;
}
return inode->i_data[block];
}
block -= 9;
if (block<256) {
if (create && !inode->i_data[9])
if (inode->i_data[9]=ext_new_block(inode->i_dev)) {
inode->i_dirt=1;
inode->i_ctime=CURRENT_TIME;
}
if (!inode->i_data[9])
return 0;
if (!(bh = bread(inode->i_dev,inode->i_data[9])))
return 0;
i = ((unsigned long *) (bh->b_data))[block];
if (create && !i)
if (i=ext_new_block(inode->i_dev)) {
((unsigned long *) (bh->b_data))[block]=i;
bh->b_dirt=1;
}
brelse(bh);
return i;
}
block -= 256;
if (block<256*256) {
if (create && !inode->i_data[10])
if (inode->i_data[10]=ext_new_block(inode->i_dev)) {
inode->i_dirt=1;
inode->i_ctime=CURRENT_TIME;
}
if (!inode->i_data[10])
return 0;
if (!(bh=bread(inode->i_dev,inode->i_data[10])))
return 0;
i = ((unsigned long *)bh->b_data)[block>>8];
if (create && !i)
if (i=ext_new_block(inode->i_dev)) {
((unsigned long *) (bh->b_data))[block>>8]=i;
bh->b_dirt=1;
}
brelse(bh);
if (!i)
return 0;
if (!(bh=bread(inode->i_dev,i)))
return 0;
i = ((unsigned long *)bh->b_data)[block&255];
if (create && !i)
if (i=ext_new_block(inode->i_dev)) {
((unsigned long *) (bh->b_data))[block&255]=i;
bh->b_dirt=1;
}
brelse(bh);
return i;
}
printk("ext_bmap: triple indirection not yet implemented\n");
return 0;
}
int ext_bmap(struct inode * inode,int block)
{
return _ext_bmap(inode,block,0);
}
int ext_create_block(struct inode * inode, int block)
{
return _ext_bmap(inode,block,1);
}
void ext_read_inode(struct inode * inode)
{
struct buffer_head * bh;
struct ext_inode * raw_inode;
int block;
#ifdef EXTFS_BITMAP
block = 2 + inode->i_sb->s_imap_blocks + inode->i_sb->s_zmap_blocks +
(inode->i_ino-1)/EXT_INODES_PER_BLOCK;
#endif
#ifdef EXTFS_FREELIST
block = 2 + (inode->i_ino-1)/EXT_INODES_PER_BLOCK;
#endif
if (!(bh=bread(inode->i_dev,block)))
panic("unable to read i-node block");
raw_inode = ((struct ext_inode *) bh->b_data) +
(inode->i_ino-1)%EXT_INODES_PER_BLOCK;
inode->i_mode = raw_inode->i_mode;
inode->i_uid = raw_inode->i_uid;
inode->i_gid = raw_inode->i_gid;
inode->i_nlink = raw_inode->i_nlinks;
inode->i_size = raw_inode->i_size;
inode->i_mtime = inode->i_atime = inode->i_ctime = raw_inode->i_time;
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
inode->i_rdev = raw_inode->i_zone[0];
else for (block = 0; block < 12; block++)
inode->i_data[block] = raw_inode->i_zone[block];
brelse(bh);
inode->i_op = NULL;
if (S_ISREG(inode->i_mode))
inode->i_op = &ext_file_inode_operations;
else if (S_ISDIR(inode->i_mode))
inode->i_op = &ext_dir_inode_operations;
else if (S_ISLNK(inode->i_mode))
inode->i_op = &ext_symlink_inode_operations;
else if (S_ISCHR(inode->i_mode))
inode->i_op = &ext_chrdev_inode_operations;
else if (S_ISBLK(inode->i_mode))
inode->i_op = &ext_blkdev_inode_operations;
else if (S_ISFIFO(inode->i_mode)) {
inode->i_op = &ext_fifo_inode_operations;
inode->i_size = 0;
inode->i_pipe = 1;
PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
}
}
void ext_write_inode(struct inode * inode)
{
struct buffer_head * bh;
struct ext_inode * raw_inode;
int block;
#ifdef EXTFS_BITMAP
block = 2 + inode->i_sb->s_imap_blocks + inode->i_sb->s_zmap_blocks +
(inode->i_ino-1)/EXT_INODES_PER_BLOCK;
#endif
#ifdef EXTFS_FREELIST
block = 2 + (inode->i_ino-1)/EXT_INODES_PER_BLOCK;
#endif
if (!(bh=bread(inode->i_dev,block)))
panic("unable to read i-node block");
raw_inode = ((struct ext_inode *)bh->b_data) +
(inode->i_ino-1)%EXT_INODES_PER_BLOCK;
raw_inode->i_mode = inode->i_mode;
raw_inode->i_uid = inode->i_uid;
raw_inode->i_gid = inode->i_gid;
raw_inode->i_nlinks = inode->i_nlink;
raw_inode->i_size = inode->i_size;
raw_inode->i_time = inode->i_mtime;
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
raw_inode->i_zone[0] = inode->i_rdev;
else for (block = 0; block < 12; block++)
raw_inode->i_zone[block] = inode->i_data[block];
bh->b_dirt=1;
inode->i_dirt=0;
brelse(bh);
}
This diff is collapsed.
/*
* linux/fs/ext/symlink.c
*
* (C) 1992 Remy Card (card@masi.ibp.fr)
*
* from
*
* linux/fs/minix/symlink.c
*
* (C) 1991 Linus Torvalds
*
* ext symlink handling code
*/
#include <errno.h>
#include <asm/segment.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]))) {
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]);
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
*
* (C) 1992 Remy Card (card@masi.ibp.fr)
*
* from
*
* linux/fs/minix/truncate.c
*
* (C) 1991 Linus Torvalds
*/
#include <linux/sched.h>
#include <linux/ext_fs.h>
#include <linux/tty.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <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);
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 i;
struct buffer_head * bh = NULL;
unsigned long * dind;
int result = 0;
#define DINDIRECT_BLOCK ((DIRECT_BLOCK-(256+9))>>8)
if (inode->i_data[10])
bh = bread(inode->i_dev,inode->i_data[10]);
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,9+256+(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,inode->i_data[10]))
inode->i_data[10] = 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);
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");
}
......@@ -4,15 +4,14 @@
* (C) 1991 Linus Torvalds
*/
#include <errno.h>
#include <asm/segment.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#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>
extern int sys_close(int fd);
......@@ -36,8 +35,6 @@ 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 <errno.h>
#include <linux/fcntl.h>
#include <linux/sched.h>
#include <linux/kernel.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();
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
};
......@@ -5,11 +5,11 @@
*/
#include <linux/string.h>
#include <linux/stat.h>
#include <sys/stat.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.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)
{
if (!inode->i_dirt)
return;
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);
if (!inode->i_dirt || !inode->i_dev) {
unlock_inode(inode);
return;
}
if (inode->i_op && inode->i_op->write_inode)
inode->i_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)
if (inode->i_dirt && !inode->i_pipe)
write_inode(inode);
}
}
......@@ -110,34 +110,36 @@ void iput(struct inode * inode)
if (!inode)
return;
wait_on_inode(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_count)
panic("iput: trying to free free inode");
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;
}
repeat:
if (inode->i_count>1) {
if (!inode->i_dev) {
inode->i_count--;
return;
}
if (inode->i_pipe) {
free_page(inode->i_size);
inode->i_size = 0;
if (S_ISBLK(inode->i_mode)) {
sync_dev(inode->i_rdev);
wait_on_inode(inode);
}
if (!inode->i_dev) {
repeat:
if (inode->i_count>1) {
inode->i_count--;
return;
}
if (!inode->i_nlink) {
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_op && inode->i_op->put_inode)
inode->i_op->put_inode(inode);
return;
}
if (inode->i_dirt) {
write_inode(inode); /* we can sleep - so do again */
......@@ -188,13 +190,12 @@ 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())) {
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;
}
......@@ -252,7 +253,6 @@ 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;
}
......@@ -4,27 +4,18 @@
* (C) 1991 Linus Torvalds
*/
#include <linux/string.h>
#include <errno.h>
#include <sys/stat.h>
#include <asm/segment.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/sched.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/minix/bitmap.c
* linux/fs/bitmap.c
*
* (C) 1991 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>
......@@ -44,35 +44,6 @@ __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;
......@@ -136,12 +107,6 @@ int minix_new_block(int dev)
return j;
}
unsigned long minix_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 minix_free_inode(struct inode * inode)
{
struct buffer_head * bh;
......@@ -191,7 +156,6 @@ 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])
......@@ -215,11 +179,6 @@ 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 = NULL;
inode->i_op = &minix_inode_operations;
return inode;
}
unsigned long minix_count_free_inodes(struct super_block *sb)
{
return sb->s_ninodes - count_used(sb->s_imap,sb->s_imap_blocks,sb->s_ninodes);
}
/*
* linux/fs/minix/blkdev.c
*
* (C) 1991 Linus Torvalds
*/
#include <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
*
* (C) 1991 Linus Torvalds
*/
#include <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 */
};
/*
* linux/fs/minix/dir.c
*
* (C) 1991 Linus Torvalds
*
* minix directory handling functions
*/
#include <errno.h>
#include <asm/segment.h>
#include <linux/fs.h>
#include <linux/minix_fs.h>
#include <linux/stat.h>
static int minix_readdir(struct inode *, struct file *, struct dirent *, int);
static struct file_operations minix_dir_operations = {
NULL, /* lseek - default */
minix_file_read, /* read */
NULL, /* write - bad */
minix_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 minix_dir_inode_operations = {
&minix_dir_operations, /* default directory file-ops */
minix_create, /* create */
minix_lookup, /* lookup */
minix_link, /* link */
minix_unlink, /* unlink */
minix_symlink, /* symlink */
minix_mkdir, /* mkdir */
minix_rmdir, /* rmdir */
minix_mknod, /* mknod */
minix_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
minix_bmap, /* bmap */
minix_truncate /* truncate */
};
static int minix_readdir(struct inode * inode, struct file * filp,
struct dirent * dirent, int count)
{
unsigned int block,offset,i;
char c;
struct buffer_head * bh;
struct minix_dir_entry * de;
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
if (filp->f_pos & (sizeof (struct minix_dir_entry) - 1))
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))) {
filp->f_pos += 1024-offset;
continue;
}
de = (struct minix_dir_entry *) (offset + bh->b_data);
while (offset < 1024 && filp->f_pos < inode->i_size) {
offset += sizeof (struct minix_dir_entry);
filp->f_pos += sizeof (struct minix_dir_entry);
if (de->inode) {
for (i = 0; i < MINIX_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++;
}
brelse(bh);
}
return 0;
}
/*
* linux/fs/fifo.c
*
* written by Paul H. Hargrove
*/
#include <linux/sched.h>
#include <linux/minix_fs.h>
extern struct file_operations def_fifo_fops;
struct inode_operations minix_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/minix/file.c
* linux/fs/file_dev.c
*
* (C) 1991 Linus Torvalds
*
* minix regular file handling primitives
* (C) 1991 Linus Torvalds
*/
#include <errno.h>
#include <fcntl.h>
#include <sys/dirent.h>
#include <sys/stat.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <linux/fcntl.h>
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/kernel.h>
#include <linux/stat.h>
#define NBUF 16
#include <asm/segment.h>
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
#include <linux/fs.h>
#include <linux/minix_fs.h>
int minix_file_read(struct inode *, struct file *, char *, int);
static int minix_file_write(struct inode *, struct file *, char *, int);
/*
* We have mostly NULL's here: the current defaults are ok for
* the minix filesystem.
*/
static struct file_operations minix_file_operations = {
NULL, /* lseek - default */
minix_file_read, /* read */
minix_file_write, /* write */
NULL, /* readdir - bad */
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* no special open is needed */
NULL /* release */
};
struct inode_operations minix_file_inode_operations = {
&minix_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 */
minix_bmap, /* bmap */
minix_truncate /* truncate */
};
static inline void wait_on_buffer(struct buffer_head * bh)
int minix_readdir(struct inode * inode, struct file * filp, struct dirent * dirent, int count)
{
cli();
while (bh->b_lock)
sleep_on(&bh->b_wait);
sti();
unsigned int block,offset,i;
char c;
struct buffer_head * bh;
struct minix_dir_entry * de;
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
if (filp->f_pos & (sizeof (struct minix_dir_entry) - 1))
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))) {
filp->f_pos += 1024-offset;
continue;
}
de = (struct minix_dir_entry *) (offset + bh->b_data);
while (offset < 1024 && filp->f_pos < inode->i_size) {
offset += sizeof (struct minix_dir_entry);
filp->f_pos += sizeof (struct minix_dir_entry);
if (de->inode) {
for (i = 0; i < MINIX_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++;
}
brelse(bh);
}
return 0;
}
/*
* minix_file_read() is also needed by the directory read-routine,
* so it's not static. NOTE! reading directories directly is a bad idea,
* but has to be supported for now for compatability reasons with older
* versions.
*/
int minix_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];
struct buffer_head * bh;
if (!inode) {
printk("minix_file_read: inode = NULL\n");
......@@ -97,70 +79,32 @@ int minix_file_read(struct inode * inode, struct file * filp, char * buf, int co
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 = minix_bmap(inode,block++)) {
*bhb = getblk(inode->i_dev,nr);
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;
while (left > 0) {
if (nr = minix_bmap(inode,(filp->f_pos)>>BLOCK_SIZE_BITS)) {
if (!(bh=bread(inode->i_dev,nr)))
return read?read:-EIO;
} else
bh = NULL;
nr = filp->f_pos & (BLOCK_SIZE-1);
chars = MIN( BLOCK_SIZE-nr , left );
filp->f_pos += chars;
left -= chars;
read += chars;
if (*bhe) {
memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
brelse(*bhe);
if (bh) {
memcpy_tofs(buf,nr+bh->b_data,chars);
buf += chars;
brelse(bh);
} 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;
}
inode->i_atime = CURRENT_TIME;
return read;
}
static int minix_file_write(struct inode * inode, struct file * filp, char * buf, int count)
int minix_file_write(struct inode * inode, struct file * filp, char * buf, int count)
{
off_t pos;
int written,block,c;
......@@ -216,8 +160,10 @@ static int minix_file_write(struct inode * inode, struct file * filp, char * buf
brelse(bh);
}
inode->i_mtime = CURRENT_TIME;
inode->i_ctime = CURRENT_TIME;
filp->f_pos = pos;
if (!(filp->f_flags & O_APPEND)) {
filp->f_pos = pos;
inode->i_ctime = CURRENT_TIME;
}
inode->i_dirt = 1;
return written;
}
This diff is collapsed.
/*
* linux/fs/minix/minix_op.c
*
* structures for the minix super_block/inode/file-operations
*/
#include <linux/fs.h>
#include <linux/minix_fs.h>
void minix_put_inode(struct inode *inode)
{
inode->i_size = 0;
minix_truncate(inode);
minix_free_inode(inode);
}
/*
* These are the low-level inode operations for minix filesystem inodes.
*/
struct inode_operations minix_inode_operations = {
minix_create,
minix_lookup,
minix_link,
minix_unlink,
minix_symlink,
minix_mkdir,
minix_rmdir,
minix_mknod,
minix_rename,
minix_readlink,
minix_open,
minix_release,
minix_follow_link,
minix_bmap,
minix_truncate,
minix_write_inode,
minix_put_inode
};
/*
* We have mostly NULL's here: the current defaults are ok for
* the minix filesystem.
*/
struct file_operations minix_file_operations = {
NULL, /* lseek - default */
minix_file_read, /* read */
minix_file_write, /* write */
NULL, /* readdir - bad */
NULL, /* close - default */
NULL, /* select - default */
NULL /* ioctl - default */
};
struct file_operations minix_dir_operations = {
NULL, /* lseek - default */
minix_file_read, /* read */
NULL, /* write - bad */
minix_readdir, /* readdir */
NULL, /* close - default */
NULL, /* select - default */
NULL /* ioctl - default */
};
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.
......@@ -72,8 +72,6 @@ enum machine_type {
/* Code indicating demand-paged executable. */
#define ZMAGIC 0413
/* Code indicating core file. */
#define CMAGIC 0421
#if !defined (N_BADMAG)
#define N_BADMAG(x) \
(N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \
......
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.
#define UTS_RELEASE "0.96b-63"
#define UTS_RELEASE "0.95c-54"
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