Commit f65d0bc9 authored by Linus Torvalds's avatar Linus Torvalds

[PATCH] Linux-0.99.7 (March 13, 1993)

Nigel Gamble makes lp driver able to use interrupts.

The mmap() code is finally starting to really happen.  In particular,
this means that "verify_area()" is doing more - it can check the actual
areas that have been mapped, rather than just blindly assume that the
user can access anything in the first 3GB.

For now, the mmap code only does anonymous mappings and /dev/mem.
Executables are still read into memory.  But the infrastructure is
there.

The VFS layer stops using names directly in user space - the race
conditions were just too hard to handle.  So pathnames are copied into
kernel space before they are looked up.

Ext2fs (Remy Card) and xiafs (Frank Xia) are merged.  Both are much
faster filesystems using bitmaps rather than freelists, and can handle
big disks and big files.

Ext2fs is based on extfs, while xiafs is a simpler straightforward
extension of the old minixfs.

Xiafs obviously was eventually dropped.

[Original announcement below]

It has been two weeks since the last release, so it's high time you
should once more enjoy the pleasures of patching up your kernel to a
higher version number if you are into those kinds of perversions.  Linux
0.99pl7 is available as both full source and diffs against pl6 on
nic.funet.fi: pub/OS/Linux/PEOPLE/Linus, and it will probably show up on
the other major sites within days.

As of pl7, I'm trying out a new format: both the full distribution and
the diffs are now compressed with gzip as it is now available at most
machines.  Also, the diffs are no longer context diffs: they use the
smaller unified diff format.  At least the stock SunOS 'patch' binary
seems not to understand them at all, but GNU patch has no problems, and
unified diffs are a bit smaller (not that it matters much after gzip has
done its deed on them).

As to the changes in pl7: they are many and varied, and hopefully all to
the better (-"Dream on Linus" -"Shut up").  Short list follows, hope I
haven't forgotten anything major.

 - ext2fs is in: note that this is version 0.2c and that if you are
   currently using an older version there are some changes.  Small
   filesystems (< 256MB) should reportedly be automatically converted,
   bigger filesystems need some assistance. Ext2fs written by Remy Card.
 - xiafs is also in: again, the final version uses a slightly different
   layout to support exact file block counts, so if you use the xiafs,
   you should make sure you have the latest fs-tools.  Xiafs written by
   Frank Xia.
 - updated Ultrastor SCSI driver with scatter/gather by Scott Taylor.
   It should be much faster, as well as support the Ultrastor-34F.
 - major changes in the memory manager.  Yours truly got carried away,
   and finally cleaned up the mm layer due to pmacdona wanting mmap() on
   /dev/zero.  This means that the IPC patches won't go in, and need
   updating.  Krishna?
 - more big changes: I rewrote most of the VFS filename-handling.
   Filenames are copied into kernel space before being used, which
   cleaned things up somewhat, as well as simplifying some race-
   condition handling.  As a result, I was also able to easily expand
   the minix fs to cover the "linux" fs that some people have been using
   (same layout, but with 30-character names).
 - updated the printer driver: Nigel Gamble.  It is now able to use
   interrupts, although the default behaviour is still to poll.
 - serial driver updates by tytso (but no SLIP yet)
 - various minor patches for POSIX compliace: Bruce Evans, Rick Sladkey
   and me.
 - other minor patches all over the place: scsi, tcpip etc.

All in all, the patches are almost half a megabyte even as unified
diffs: getting the full sources might be easier than patching it all up.

As always, some of the patches are actually tested by me, some aren't
(and just because I wrote some of them doesn't mean I actually *tested*
them: I have no idea if mmap() works on /dev/zero, although it should).
I have neither a printer nor an Ultrastor controller, and I haven't got
the diskspace to test out the new filesystems, so I can only hope they
work "as advertized".  If you have problems, I want to hear about them,
so keep the reports coming, and try to pinpoint the problem as well as
you can ("when I do *this* it happens every time..").

                Linus
parent 64e05a91
...@@ -70,23 +70,11 @@ KEYBOARD = -DKBD_FINNISH -DKBDFLAGS=0 ...@@ -70,23 +70,11 @@ KEYBOARD = -DKBD_FINNISH -DKBDFLAGS=0
SVGA_MODE= -DSVGA_MODE=1 SVGA_MODE= -DSVGA_MODE=1
#
# Edit the SOUND_SUPPORT line to suit your setup if you have configured
# the sound driver to be in the kernel (not really there yet).
#
# The DSP_BUFFSIZE defines size of the DMA buffer used for PCM voice I/O.
# You should use one of the values 4096 (SB), 16384 (SB Pro), 32768 (PAS+)
# or 65536 (PAS16). The SBC_IRQ defines the IRQ line used by SoundBlaster and
# the PAS_IRQ is the IRQ number for ProAudioSpectrum.
#
SOUND_SUPPORT = -DKERNEL_SOUNDCARD -DDSP_BUFFSIZE=16384 -DSBC_IRQ=7 -DPAS_IRQ=5
# #
# standard CFLAGS # standard CFLAGS
# #
CFLAGS = -Wall -O6 -fomit-frame-pointer CFLAGS = -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer
ifdef CONFIG_M486 ifdef CONFIG_M486
CFLAGS := $(CFLAGS) -m486 CFLAGS := $(CFLAGS) -m486
...@@ -139,6 +127,10 @@ lilo: $(CONFIGURE) Image ...@@ -139,6 +127,10 @@ lilo: $(CONFIGURE) Image
config: config:
sh Configure < config.in sh Configure < config.in
mv .config~ .config mv .config~ .config
$(MAKE) soundconf
soundconf:
cd kernel/chr_drv/sound;$(MAKE) config
linuxsubdirs: dummy linuxsubdirs: dummy
@for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE)) || exit; done @for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE)) || exit; done
...@@ -147,7 +139,7 @@ tools/./version.h: tools/version.h ...@@ -147,7 +139,7 @@ tools/./version.h: tools/version.h
tools/version.h: $(CONFIGURE) Makefile tools/version.h: $(CONFIGURE) Makefile
@./makever.sh @./makever.sh
@echo \#define UTS_RELEASE \"0.99.pl6-`cat .version`\" > tools/version.h @echo \#define UTS_RELEASE \"0.99.pl7-`cat .version`\" > tools/version.h
@echo \#define UTS_VERSION \"`date +%D`\" >> tools/version.h @echo \#define UTS_VERSION \"`date +%D`\" >> tools/version.h
@echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> tools/version.h @echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> tools/version.h
@echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h @echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h
...@@ -201,10 +193,7 @@ zBoot/zSystem: zBoot/*.c zBoot/*.S tools/zSystem ...@@ -201,10 +193,7 @@ zBoot/zSystem: zBoot/*.c zBoot/*.S tools/zSystem
cd zBoot;$(MAKE) cd zBoot;$(MAKE)
zImage: $(CONFIGURE) boot/bootsect boot/setup zBoot/zSystem tools/build zImage: $(CONFIGURE) boot/bootsect boot/setup zBoot/zSystem tools/build
cp zBoot/zSystem system.tmp tools/build boot/bootsect boot/setup zBoot/zSystem $(ROOT_DEV) > zImage
$(STRIP) system.tmp
tools/build boot/bootsect boot/setup system.tmp $(ROOT_DEV) > zImage
rm system.tmp
sync sync
zdisk: zImage zdisk: zImage
...@@ -240,14 +229,21 @@ clean: ...@@ -240,14 +229,21 @@ clean:
rm -f init/*.o tools/system tools/build boot/*.o tools/*.o rm -f init/*.o tools/system tools/build boot/*.o tools/*.o
for i in zBoot $(SUBDIRS); do (cd $$i && $(MAKE) clean); done for i in zBoot $(SUBDIRS); do (cd $$i && $(MAKE) clean); done
mrproper: clean
rm -f include/linux/autoconf.h tools/version.h
rm -f .version .config*
rm -f `find . -name .depend -print`
backup: clean backup: clean
cd .. && tar cf - linux | compress - > backup.Z cd .. && tar cf - linux | gzip -9 > backup.z
sync sync
depend dep: depend dep:
touch tools/version.h
for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done > .depend~ for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done > .depend~
for i in tools/*.c;do echo -n "tools/";$(CPP) -M $$i;done >> .depend~ for i in tools/*.c;do echo -n "tools/";$(CPP) -M $$i;done >> .depend~
for i in $(SUBDIRS); do (cd $$i && $(MAKE) dep) || exit; done for i in $(SUBDIRS); do (cd $$i && $(MAKE) dep) || exit; done
rm -f tools/version.h
mv .depend~ .depend mv .depend~ .depend
ifdef CONFIGURATION ifdef CONFIGURATION
......
...@@ -35,7 +35,6 @@ BOOTSEG = 0x07C0 ! original address of boot-sector ...@@ -35,7 +35,6 @@ BOOTSEG = 0x07C0 ! original address of boot-sector
INITSEG = DEF_INITSEG ! we move boot here - out of the way INITSEG = DEF_INITSEG ! we move boot here - out of the way
SETUPSEG = DEF_SETUPSEG ! setup starts here SETUPSEG = DEF_SETUPSEG ! setup starts here
SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536). SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536).
ENDSEG = SYSSEG + SYSSIZE ! where to stop loading
! ROOT_DEV & SWAP_DEV are now written by "build". ! ROOT_DEV & SWAP_DEV are now written by "build".
ROOT_DEV = 0 ROOT_DEV = 0
...@@ -256,8 +255,9 @@ die: jne die ! es must be at 64kB boundary ...@@ -256,8 +255,9 @@ die: jne die ! es must be at 64kB boundary
xor bx,bx ! bx is starting address within segment xor bx,bx ! bx is starting address within segment
rp_read: rp_read:
mov ax,es mov ax,es
cmp ax,#ENDSEG ! have we loaded all yet? sub ax,#SYSSEG
jb ok1_read cmp ax,syssize ! have we loaded all yet?
jbe ok1_read
ret ret
ok1_read: ok1_read:
seg cs seg cs
...@@ -429,7 +429,9 @@ msg1: ...@@ -429,7 +429,9 @@ msg1:
.byte 13,10 .byte 13,10
.ascii "Loading" .ascii "Loading"
.org 502 .org 500
syssize:
.word SYSSIZE
swap_dev: swap_dev:
.word SWAP_DEV .word SWAP_DEV
ram_size: ram_size:
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
.globl _swapper_pg_dir,_pg0 .globl _swapper_pg_dir,_pg0
.globl _empty_bad_page .globl _empty_bad_page
.globl _empty_bad_page_table .globl _empty_bad_page_table
.globl _empty_zero_page
.globl _tmp_floppy_area,_floppy_track_buffer .globl _tmp_floppy_area,_floppy_track_buffer
#include <linux/tasks.h> #include <linux/tasks.h>
...@@ -206,6 +207,9 @@ _empty_bad_page: ...@@ -206,6 +207,9 @@ _empty_bad_page:
_empty_bad_page_table: _empty_bad_page_table:
.org 0x5000 .org 0x5000
_empty_zero_page:
.org 0x6000
/* /*
* tmp_floppy_area is used by the floppy-driver when DMA cannot * tmp_floppy_area is used by the floppy-driver when DMA cannot
* reach to a buffer-block. It needs to be aligned, so that it isn't * reach to a buffer-block. It needs to be aligned, so that it isn't
...@@ -224,7 +228,7 @@ _floppy_track_buffer: ...@@ -224,7 +228,7 @@ _floppy_track_buffer:
/* This is the default interrupt "handler" :-) */ /* This is the default interrupt "handler" :-) */
int_msg: int_msg:
.asciz "Unknown interrupt\n\r" .asciz "Unknown interrupt\n"
.align 2 .align 2
ignore_int: ignore_int:
cld cld
......
...@@ -48,6 +48,10 @@ Standard (minix) fs support ...@@ -48,6 +48,10 @@ Standard (minix) fs support
CONFIG_MINIX_FS y/n y CONFIG_MINIX_FS y/n y
Extended fs support Extended fs support
CONFIG_EXT_FS y/n n CONFIG_EXT_FS y/n n
Second extended fs support
CONFIG_EXT2_FS y/n n
xiafs filesystem support
CONFIG_XIA_FS y/n n
msdos fs support msdos fs support
CONFIG_MSDOS_FS y/n y CONFIG_MSDOS_FS y/n y
/proc filesystem support /proc filesystem support
...@@ -75,5 +79,5 @@ MicroSoft busmouse support ...@@ -75,5 +79,5 @@ MicroSoft busmouse support
CONFIG_MS_BUSMOUSE y/n n CONFIG_MS_BUSMOUSE y/n n
ATIXL busmouse support ATIXL busmouse support
CONFIG_ATIXL_BUSMOUSE y/n n CONFIG_ATIXL_BUSMOUSE y/n n
Soundcard support (not really there yet) Soundcard support (distributed separately)
CONFIG_SOUND y/n n CONFIG_SOUND y/n n
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
# #
# Note 2! The CFLAGS definitions are now in the main makefile... # Note 2! The CFLAGS definitions are now in the main makefile...
SUBDIRS = minix ext msdos proc isofs nfs SUBDIRS = minix ext ext2 msdos proc isofs nfs xiafs
ifdef CONFIG_MINIX_FS ifdef CONFIG_MINIX_FS
FS_SUBDIRS := $(FS_SUBDIRS) minix FS_SUBDIRS := $(FS_SUBDIRS) minix
...@@ -15,6 +15,9 @@ endif ...@@ -15,6 +15,9 @@ endif
ifdef CONFIG_EXT_FS ifdef CONFIG_EXT_FS
FS_SUBDIRS := $(FS_SUBDIRS) ext FS_SUBDIRS := $(FS_SUBDIRS) ext
endif endif
ifdef CONFIG_EXT2_FS
FS_SUBDIRS := $(FS_SUBDIRS) ext2
endif
ifdef CONFIG_MSDOS_FS ifdef CONFIG_MSDOS_FS
FS_SUBDIRS := $(FS_SUBDIRS) msdos FS_SUBDIRS := $(FS_SUBDIRS) msdos
endif endif
...@@ -27,6 +30,10 @@ endif ...@@ -27,6 +30,10 @@ endif
ifdef CONFIG_NFS_FS ifdef CONFIG_NFS_FS
FS_SUBDIRS := $(FS_SUBDIRS) nfs FS_SUBDIRS := $(FS_SUBDIRS) nfs
endif endif
ifdef CONFIG_XIA_FS
FS_SUBDIRS := $(FS_SUBDIRS) xiafs
endif
.c.s: .c.s:
$(CC) $(CFLAGS) -S $< $(CC) $(CFLAGS) -S $<
......
...@@ -78,6 +78,8 @@ static void sync_buffers(dev_t dev) ...@@ -78,6 +78,8 @@ static void sync_buffers(dev_t dev)
bh = free_list; bh = free_list;
for (i = nr_buffers*2 ; i-- > 0 ; bh = bh->b_next_free) { for (i = nr_buffers*2 ; i-- > 0 ; bh = bh->b_next_free) {
if (dev && bh->b_dev != dev)
continue;
if (bh->b_lock) if (bh->b_lock)
continue; continue;
if (!bh->b_dirt) if (!bh->b_dirt)
...@@ -145,14 +147,12 @@ void check_disk_change(dev_t dev) ...@@ -145,14 +147,12 @@ void check_disk_change(dev_t dev)
#if defined(CONFIG_BLK_DEV_SD) && defined(CONFIG_SCSI) #if defined(CONFIG_BLK_DEV_SD) && defined(CONFIG_SCSI)
case 8: /* Removable scsi disk */ case 8: /* Removable scsi disk */
i = check_scsidisk_media_change(dev, 0); i = check_scsidisk_media_change(dev, 0);
if (i) printk("Flushing buffers and inodes for SCSI disk\n");
break; break;
#endif #endif
#if defined(CONFIG_BLK_DEV_SR) && defined(CONFIG_SCSI) #if defined(CONFIG_BLK_DEV_SR) && defined(CONFIG_SCSI)
case 11: /* CDROM */ case 11: /* CDROM */
i = check_cdrom_media_change(dev, 0); i = check_cdrom_media_change(dev, 0);
if (i) printk("Flushing buffers and inodes for CDROM\n");
break; break;
#endif #endif
...@@ -162,6 +162,8 @@ void check_disk_change(dev_t dev) ...@@ -162,6 +162,8 @@ void check_disk_change(dev_t dev)
if (!i) return; if (!i) return;
printk("VFS: Disk change detected on device %d/%d\n",
MAJOR(dev), MINOR(dev));
for (i=0 ; i<NR_SUPER ; i++) for (i=0 ; i<NR_SUPER ; i++)
if (super_block[i].s_dev == dev) if (super_block[i].s_dev == dev)
put_super(super_block[i].s_dev); put_super(super_block[i].s_dev);
...@@ -193,7 +195,7 @@ static inline void remove_from_hash_queue(struct buffer_head * bh) ...@@ -193,7 +195,7 @@ static inline void remove_from_hash_queue(struct buffer_head * bh)
static inline void remove_from_free_list(struct buffer_head * bh) static inline void remove_from_free_list(struct buffer_head * bh)
{ {
if (!(bh->b_prev_free) || !(bh->b_next_free)) if (!(bh->b_prev_free) || !(bh->b_next_free))
panic("Free block list corrupted"); panic("VFS: Free block list corrupted");
bh->b_prev_free->b_next_free = bh->b_next_free; bh->b_prev_free->b_next_free = bh->b_next_free;
bh->b_next_free->b_prev_free = bh->b_prev_free; bh->b_next_free->b_prev_free = bh->b_prev_free;
if (free_list == bh) if (free_list == bh)
...@@ -263,7 +265,8 @@ static struct buffer_head * find_buffer(dev_t dev, int block, int size) ...@@ -263,7 +265,8 @@ static struct buffer_head * find_buffer(dev_t dev, int block, int size)
if (tmp->b_size == size) if (tmp->b_size == size)
return tmp; return tmp;
else { else {
printk("wrong block-size on device %04x\n",dev); printk("VFS: Wrong blocksize on device %d/%d\n",
MAJOR(dev), MINOR(dev));
return NULL; return NULL;
} }
return NULL; return NULL;
...@@ -328,6 +331,8 @@ struct buffer_head * getblk(dev_t dev, int block, int size) ...@@ -328,6 +331,8 @@ struct buffer_head * getblk(dev_t dev, int block, int size)
for (tmp = free_list; buffers-- > 0 ; tmp = tmp->b_next_free) { for (tmp = free_list; buffers-- > 0 ; tmp = tmp->b_next_free) {
if (tmp->b_count || tmp->b_size != size) if (tmp->b_count || tmp->b_size != size)
continue; continue;
if (mem_map[MAP_NR((unsigned long) tmp->b_data)] != 1)
continue;
if (!bh || BADNESS(tmp)<BADNESS(bh)) { if (!bh || BADNESS(tmp)<BADNESS(bh)) {
bh = tmp; bh = tmp;
if (!BADNESS(tmp)) if (!BADNESS(tmp))
...@@ -383,7 +388,7 @@ void brelse(struct buffer_head * buf) ...@@ -383,7 +388,7 @@ void brelse(struct buffer_head * buf)
wake_up(&buffer_wait); wake_up(&buffer_wait);
return; return;
} }
printk("Trying to free free buffer\n"); printk("VFS: brelse: Trying to free free buffer\n");
} }
/* /*
...@@ -395,7 +400,8 @@ struct buffer_head * bread(dev_t dev, int block, int size) ...@@ -395,7 +400,8 @@ struct buffer_head * bread(dev_t dev, int block, int size)
struct buffer_head * bh; struct buffer_head * bh;
if (!(bh = getblk(dev, block, size))) { if (!(bh = getblk(dev, block, size))) {
printk("bread: getblk returned NULL\n"); printk("VFS: bread: READ error on device %d/%d\n",
MAJOR(dev), MINOR(dev));
return NULL; return NULL;
} }
if (bh->b_uptodate) if (bh->b_uptodate)
...@@ -408,46 +414,6 @@ struct buffer_head * bread(dev_t dev, int block, int size) ...@@ -408,46 +414,6 @@ struct buffer_head * bread(dev_t dev, int block, int size)
return NULL; return NULL;
} }
#define COPYBLK(from,to) \
__asm__("cld\n\t" \
"rep\n\t" \
"movsl\n\t" \
::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
:"cx","di","si")
/*
* bread_page reads four buffers into memory at the desired address. It's
* a function of its own, as there is some speed to be got by reading them
* all at the same time, not waiting for one to be read, and then another
* etc.
*/
void bread_page(unsigned long address, dev_t dev, int b[4])
{
struct buffer_head * bh[4];
struct buffer_head * bhr[4];
int bhnum = 0;
int i;
for (i=0 ; i<4 ; i++)
if (b[i]) {
bh[i] = getblk(dev, b[i], 1024);
if (bh[i] && !bh[i]->b_uptodate)
bhr[bhnum++] = bh[i];
} else
bh[i] = NULL;
if (bhnum)
ll_rw_block(READ, bhnum, bhr);
for (i=0 ; i<4 ; i++,address += BLOCK_SIZE)
if (bh[i]) {
wait_on_buffer(bh[i]);
if (bh[i]->b_uptodate)
COPYBLK((unsigned long) bh[i]->b_data,address);
brelse(bh[i]);
}
}
/* /*
* Ok, breada can be used as bread, but additionally to mark other * Ok, breada can be used as bread, but additionally to mark other
* blocks for reading as well. End the argument list with a negative * blocks for reading as well. End the argument list with a negative
...@@ -460,7 +426,8 @@ struct buffer_head * breada(dev_t dev,int first, ...) ...@@ -460,7 +426,8 @@ struct buffer_head * breada(dev_t dev,int first, ...)
va_start(args,first); va_start(args,first);
if (!(bh = getblk(dev, first, 1024))) { if (!(bh = getblk(dev, first, 1024))) {
printk("breada: getblk returned NULL\n"); printk("VFS: breada: READ error on device %d/%d\n",
MAJOR(dev), MINOR(dev));
return NULL; return NULL;
} }
if (!bh->b_uptodate) if (!bh->b_uptodate)
...@@ -528,6 +495,58 @@ static struct buffer_head * get_unused_buffer_head(void) ...@@ -528,6 +495,58 @@ static struct buffer_head * get_unused_buffer_head(void)
return bh; return bh;
} }
static inline unsigned long try_to_share_buffers(unsigned long address, dev_t dev, int b[], int size)
{
return 0;
}
#define COPYBLK(from,to) \
__asm__ __volatile__("rep ; movsl" \
::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \
:"cx","di","si")
/*
* bread_page reads four buffers into memory at the desired address. It's
* a function of its own, as there is some speed to be got by reading them
* all at the same time, not waiting for one to be read, and then another
* etc. This also allows us to optimize memory usage by sharing code pages
* and filesystem buffers.. This is not yet implemented.
*/
unsigned long bread_page(unsigned long address, dev_t dev, int b[], int size, int prot)
{
struct buffer_head * bh[4];
struct buffer_head * bhr[4];
unsigned long where;
int bhnum = 0;
int i;
if (!(prot & PAGE_RW)) {
where = try_to_share_buffers(address,dev,b,size);
if (where)
return where;
}
for (i=0 ; i<4 ; i++) {
bh[i] = NULL;
if (b[i]) {
bh[i] = getblk(dev, b[i], size);
if (bh[i] && !bh[i]->b_uptodate)
bhr[bhnum++] = bh[i];
}
}
if (bhnum)
ll_rw_block(READ, bhnum, bhr);
where = address;
for (i=0 ; i<4 ; i++,address += BLOCK_SIZE) {
if (bh[i]) {
wait_on_buffer(bh[i]);
if (bh[i]->b_uptodate)
COPYBLK((unsigned long) bh[i]->b_data,address);
brelse(bh[i]);
}
}
return where;
}
/* /*
* Try to increase the number of buffers available: the size argument * Try to increase the number of buffers available: the size argument
* is used to determine what kind of buffers we want. Currently only * is used to determine what kind of buffers we want. Currently only
...@@ -541,7 +560,7 @@ void grow_buffers(int size) ...@@ -541,7 +560,7 @@ void grow_buffers(int size)
struct buffer_head *bh, *tmp; struct buffer_head *bh, *tmp;
if ((size & 511) || (size > 4096)) { if ((size & 511) || (size > 4096)) {
printk("grow_buffers: size = %d\n",size); printk("VFS: grow_buffers: size = %d\n",size);
return; return;
} }
page = get_free_page(GFP_BUFFER); page = get_free_page(GFP_BUFFER);
...@@ -601,6 +620,10 @@ static int try_to_free(struct buffer_head * bh) ...@@ -601,6 +620,10 @@ static int try_to_free(struct buffer_head * bh)
unsigned long page; unsigned long page;
struct buffer_head * tmp, * p; struct buffer_head * tmp, * p;
page = (unsigned long) bh->b_data;
page &= 0xfffff000;
if (mem_map[MAP_NR(page)] != 1)
return 0;
tmp = bh; tmp = bh;
do { do {
if (!tmp) if (!tmp)
...@@ -609,8 +632,6 @@ static int try_to_free(struct buffer_head * bh) ...@@ -609,8 +632,6 @@ static int try_to_free(struct buffer_head * bh)
return 0; return 0;
tmp = tmp->b_this_page; tmp = tmp->b_this_page;
} while (tmp != bh); } while (tmp != bh);
page = (unsigned long) bh->b_data;
page &= 0xfffff000;
tmp = bh; tmp = bh;
do { do {
p = tmp; p = tmp;
...@@ -678,6 +699,6 @@ void buffer_init(void) ...@@ -678,6 +699,6 @@ void buffer_init(void)
free_list = 0; free_list = 0;
grow_buffers(BLOCK_SIZE); grow_buffers(BLOCK_SIZE);
if (!free_list) if (!free_list)
panic("Unable to initialize buffer free list!"); panic("VFS: Unable to initialize buffer free list!");
return; return;
} }
...@@ -184,6 +184,7 @@ int sys_uselib(const char * library) ...@@ -184,6 +184,7 @@ int sys_uselib(const char * library)
struct inode * inode; struct inode * inode;
struct buffer_head * bh; struct buffer_head * bh;
struct exec ex; struct exec ex;
unsigned long offset;
int error; int error;
if (!library || get_limit(0x17) != TASK_SIZE) if (!library || get_limit(0x17) != TASK_SIZE)
...@@ -211,18 +212,21 @@ int sys_uselib(const char * library) ...@@ -211,18 +212,21 @@ int sys_uselib(const char * library)
} }
ex = *(struct exec *) bh->b_data; ex = *(struct exec *) bh->b_data;
brelse(bh); brelse(bh);
if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize || if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize ||
ex.a_text+ex.a_data+ex.a_bss>0x3000000 || ex.a_drsize || ex.a_entry & 0xfff ||
inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) { inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
iput(inode); iput(inode);
return -ENOEXEC; return -ENOEXEC;
} }
current->libraries[libnum].library = inode; current->libraries[libnum].library = inode;
current->libraries[libnum].start = ex.a_entry; current->libraries[libnum].start = ex.a_entry;
current->libraries[libnum].length = (ex.a_data+ex.a_text+0xfff) & 0xfffff000; offset = (ex.a_data + ex.a_text + 0xfff) & 0xfffff000;
current->libraries[libnum].bss = (ex.a_bss+0xfff) & 0xfffff000; current->libraries[libnum].length = offset;
current->libraries[libnum].bss = ex.a_bss;
offset += ex.a_entry;
zeromap_page_range(offset, ex.a_bss, PAGE_COPY);
#if 0 #if 0
printk("Loaded library %d at %08x, length %08x\n", printk("VFS: Loaded library %d at %08x, length %08x\n",
libnum, libnum,
current->libraries[libnum].start, current->libraries[libnum].start,
current->libraries[libnum].length); current->libraries[libnum].length);
...@@ -315,7 +319,7 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, ...@@ -315,7 +319,7 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
if (from_kmem == 1) if (from_kmem == 1)
set_fs(new_fs); set_fs(new_fs);
if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc))) if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc)))
panic("argc is wrong"); panic("VFS: argc is wrong");
if (from_kmem == 1) if (from_kmem == 1)
set_fs(old_fs); set_fs(old_fs);
len=0; /* remember zero-padding */ len=0; /* remember zero-padding */
...@@ -432,7 +436,7 @@ int do_execve(unsigned long * eip,long tmp,char * filename, ...@@ -432,7 +436,7 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
int ch; int ch;
if ((0xffff & eip[1]) != 0x000f) if ((0xffff & eip[1]) != 0x000f)
panic("execve called from supervisor mode"); panic("VFS: execve called from supervisor mode");
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
page[i]=0; page[i]=0;
retval = namei(filename,&inode); /* get executable inode */ retval = namei(filename,&inode); /* get executable inode */
...@@ -551,24 +555,22 @@ int do_execve(unsigned long * eip,long tmp,char * filename, ...@@ -551,24 +555,22 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
} }
/* /*
* OK, now restart the process with the interpreter's inode. * OK, now restart the process with the interpreter's inode.
* Note that we use open_namei() as the name is now in kernel
* space, and we don't need to copy it.
*/ */
old_fs = get_fs(); retval = open_namei(interp,0,0,&inode,NULL);
set_fs(get_ds());
retval = namei(interp,&inode);
set_fs(old_fs);
if (retval) if (retval)
goto exec_error1; goto exec_error1;
goto restart_interp; goto restart_interp;
} }
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC) || if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC) ||
ex.a_trsize || ex.a_drsize || 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)) { inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) {
retval = -ENOEXEC; retval = -ENOEXEC;
goto exec_error2; goto exec_error2;
} }
if (N_TXTOFF(ex) != BLOCK_SIZE && N_MAGIC(ex) != OMAGIC) { if (N_TXTOFF(ex) != BLOCK_SIZE && N_MAGIC(ex) != OMAGIC) {
printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename); printk("VFS: N_TXTOFF != BLOCK_SIZE. See a.out.h.");
retval = -ENOEXEC; retval = -ENOEXEC;
goto exec_error2; goto exec_error2;
} }
...@@ -635,6 +637,7 @@ int do_execve(unsigned long * eip,long tmp,char * filename, ...@@ -635,6 +637,7 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
iput(inode); iput(inode);
} else } else
current->executable = inode; current->executable = inode;
zeromap_page_range((ex.a_text + ex.a_data + 0xfff) & 0xfffff000,ex.a_bss, PAGE_COPY);
eip[0] = ex.a_entry; /* eip, magic happens :-) */ eip[0] = ex.a_entry; /* eip, magic happens :-) */
eip[3] = p; /* stack pointer */ eip[3] = p; /* stack pointer */
if (current->flags & PF_PTRACED) if (current->flags & PF_PTRACED)
......
...@@ -65,7 +65,7 @@ static int ext_match(int len,const char * name,struct ext_dir_entry * de) ...@@ -65,7 +65,7 @@ static int ext_match(int len,const char * name,struct ext_dir_entry * de)
if (len < EXT_NAME_LEN && len != de->name_len) if (len < EXT_NAME_LEN && len != de->name_len)
return 0; return 0;
__asm__("cld\n\t" __asm__("cld\n\t"
"fs ; repe ; cmpsb\n\t" "repe ; cmpsb\n\t"
"setz %%al" "setz %%al"
:"=a" (same) :"=a" (same)
:"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len) :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
...@@ -291,7 +291,7 @@ printk ("ext_add_entry : creating next block\n"); ...@@ -291,7 +291,7 @@ printk ("ext_add_entry : creating next block\n");
dir->i_mtime = CURRENT_TIME; dir->i_mtime = CURRENT_TIME;
de->name_len = namelen; de->name_len = namelen;
for (i=0; i < namelen ; i++) for (i=0; i < namelen ; i++)
de->name[i]=get_fs_byte(name+i); de->name[i] = name[i];
bh->b_dirt = 1; bh->b_dirt = 1;
*res_dir = de; *res_dir = de;
return bh; return bh;
...@@ -612,6 +612,8 @@ int ext_unlink(struct inode * dir, const char * name, int len) ...@@ -612,6 +612,8 @@ int ext_unlink(struct inode * dir, const char * name, int len)
inode->i_nlink--; inode->i_nlink--;
inode->i_dirt = 1; inode->i_dirt = 1;
inode->i_ctime = CURRENT_TIME; inode->i_ctime = CURRENT_TIME;
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_dirt = 1;
retval = 0; retval = 0;
end_unlink: end_unlink:
brelse(bh); brelse(bh);
...@@ -643,7 +645,7 @@ int ext_symlink(struct inode * dir, const char * name, int len, const char * sym ...@@ -643,7 +645,7 @@ int ext_symlink(struct inode * dir, const char * name, int len, const char * sym
return -ENOSPC; return -ENOSPC;
} }
i = 0; i = 0;
while (i < 1023 && (c=get_fs_byte(symname++))) while (i < 1023 && (c = *(symname++)))
name_block->b_data[i++] = c; name_block->b_data[i++] = c;
name_block->b_data[i] = 0; name_block->b_data[i] = 0;
name_block->b_dirt = 1; name_block->b_dirt = 1;
...@@ -716,12 +718,9 @@ int ext_link(struct inode * oldinode, struct inode * dir, const char * name, int ...@@ -716,12 +718,9 @@ int ext_link(struct inode * oldinode, struct inode * dir, const char * name, int
static int subdir(struct inode * new, struct inode * old) static int subdir(struct inode * new, struct inode * old)
{ {
unsigned short fs;
int ino; int ino;
int result; int result;
__asm__("mov %%fs,%0":"=r" (fs));
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
new->i_count++; new->i_count++;
result = 0; result = 0;
for (;;) { for (;;) {
...@@ -738,7 +737,6 @@ static int subdir(struct inode * new, struct inode * old) ...@@ -738,7 +737,6 @@ static int subdir(struct inode * new, struct inode * old)
break; break;
} }
iput(new); iput(new);
__asm__("mov %0,%%fs"::"r" (fs));
return result; return result;
} }
......
...@@ -76,12 +76,9 @@ static int ext_follow_link(struct inode * dir, struct inode * inode, ...@@ -76,12 +76,9 @@ static int ext_follow_link(struct inode * dir, struct inode * inode,
return -EIO; return -EIO;
} }
iput(inode); iput(inode);
__asm__("mov %%fs,%0":"=r" (fs));
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
current->link_count++; current->link_count++;
error = open_namei(bh->b_data,flag,mode,res_inode,dir); error = open_namei(bh->b_data,flag,mode,res_inode,dir);
current->link_count--; current->link_count--;
__asm__("mov %0,%%fs"::"r" (fs));
brelse(bh); brelse(bh);
return error; return error;
} }
......
#
# Makefile for the linux ext2-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= balloc.o bitmap.o dcache.o dir.o file.o ialloc.o inode.o \
namei.o symlink.o truncate.o
ext2.o: $(OBJS)
$(LD) -r -o ext2.o $(OBJS)
clean:
rm -f core *.s *.o *.a
dep:
$(CPP) -M *.c > .depend
#
# include a dependency file if one exists
#
ifeq (.depend,$(wildcard .depend))
include .depend
endif
This diff is collapsed.
/*
* linux/fs/ext2/bitmap.c
*
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr)
*/
#include <linux/sched.h>
#include <linux/fs.h>
static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
unsigned long ext2_count_free (struct buffer_head * map, unsigned numchars)
{
unsigned i;
unsigned long sum = 0;
if (!map)
return (0);
for (i = 0; i < numchars; i++)
sum += nibblemap[map->b_data[i] & 0xf] +
nibblemap[(map->b_data[i] >> 4) & 0xf];
return (sum);
}
/*
* linux/fs/ext2/dcache.c
*
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr)
*
*/
/*
* dcache.c contains the code that handles the directory cache used by
* lookup() and readdir()
*/
#include <asm/segment.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/kernel.h>
#include <linux/string.h>
#ifndef DONT_USE_DCACHE
struct dir_cache_entry {
unsigned short dev;
unsigned long dir;
unsigned long ino;
char name[EXT2_NAME_LEN];
int len;
struct dir_cache_entry *queue_prev;
struct dir_cache_entry *queue_next;
struct dir_cache_entry *prev;
struct dir_cache_entry *next;
};
static struct dir_cache_entry *first = NULL;
static struct dir_cache_entry *last = NULL;
static struct dir_cache_entry *first_free = NULL;
static int cache_initialized = 0;
#ifdef EXT2FS_DEBUG_CACHE
static int hits = 0;
static int misses = 0;
#endif
#define CACHE_SIZE 128
static struct dir_cache_entry dcache[CACHE_SIZE];
#define HASH_QUEUES 16
static struct dir_cache_entry *queue_head[HASH_QUEUES];
static struct dir_cache_entry *queue_tail[HASH_QUEUES];
#define hash(dev,dir) ((dev ^ dir) % HASH_QUEUES)
/*
* Initialize the cache
*/
static void init_cache (void)
{
int i;
dcache[0].prev = NULL;
dcache[0].next = &dcache[1];
dcache[0].queue_next = dcache[0].queue_prev = NULL;
for (i = 1; i < CACHE_SIZE - 1; i++) {
dcache[i].prev = &dcache[i - 1];
dcache[i].next = &dcache[i + 1];
dcache[i].queue_next = dcache[i].queue_prev = NULL;
}
dcache[i].prev = &dcache[i - 1];
dcache[i].next = NULL;
dcache[i].queue_next = dcache[i].queue_prev = NULL;
first_free = &dcache[0];
for (i = 0; i < HASH_QUEUES; i++)
queue_tail[i] = queue_head[i] = NULL;
cache_initialized = 1;
}
/*
* Find a name in the cache
*/
static struct dir_cache_entry *find_name (int queue, unsigned short dev,
unsigned long dir, const char *name,
int len)
{
struct dir_cache_entry *p;
for (p = queue_head[queue]; p!= NULL && (p->dev != dev ||
p->dir != dir || p->len != len || strncmp (name, p->name, p->len));
p = p->queue_next)
;
return p;
}
#ifdef EXT2FS_DEBUG_CACHE
/*
* List the cache entries for debugging
*/
static void show_cache (const char *func_name)
{
struct dir_cache_entry *p;
printk ("%s: cache status\n", func_name);
for (p = first; p != NULL; p = p->next)
printk ("dev:%04x, dir=%4d, name=%s\n",
p->dev, p->dir, p->name);
}
#endif
/*
* Add an entry at the beginning of the cache
*/
static void add_to_cache (struct dir_cache_entry *p)
{
p->prev = NULL;
p->next = first;
if (first)
first->prev = p;
if (!last)
last = p;
first = p;
}
/*
* Add an entry at the beginning of a queue
*/
static void add_to_queue (int queue, struct dir_cache_entry *p)
{
p->queue_prev = NULL;
p->queue_next = queue_head[queue];
if (queue_head[queue])
queue_head[queue]->queue_prev = p;
if (!queue_tail[queue])
queue_tail[queue] = p;
queue_head[queue] = p;
}
/*
* Remove an entry from the cache
*/
static void remove_from_cache (struct dir_cache_entry *p)
{
if (p->prev)
p->prev->next = p->next;
else
first = p->next;
if (p->next)
p->next->prev = p->prev;
else
last = p->prev;
}
/*
* Remove an entry from a queue
*/
static void remove_from_queue (int queue, struct dir_cache_entry *p)
{
if (p->queue_prev)
p->queue_prev->queue_next = p->queue_next;
else
queue_head[queue] = p->queue_next;
if (p->queue_next)
p->queue_next->queue_prev = p->queue_prev;
else
queue_tail[queue] = p->queue_prev;
}
/*
* Invalidate all cache entries on a device (called by put_super() when
* a file system is unmounted)
*/
void ext2_dcache_invalidate (unsigned short dev)
{
struct dir_cache_entry *p;
struct dir_cache_entry *p2;
if (!cache_initialized)
init_cache ();
for (p = first; p != NULL; p = p2) {
p2 = p->next;
if (p->dev == dev) {
remove_from_cache (p);
remove_from_queue (hash (p->dev, p->dir), p);
p->next = first_free;
first_free = p;
}
}
#ifdef EXT2FS_DEBUG_CACHE
show_cache ("dcache_invalidate");
#endif
}
/*
* Lookup a directory entry in the cache
*
* Note: the name is in the caller's address space
*/
unsigned long ext2_dcache_lookup (unsigned short dev, unsigned long dir,
const char *name, int len)
{
char our_name[EXT2_NAME_LEN];
int queue;
struct dir_cache_entry *p;
if (!cache_initialized)
init_cache ();
if (len > EXT2_NAME_LEN)
len = EXT2_NAME_LEN;
memcpy (our_name, (char *) name, len);
our_name[len] = '\0';
#ifdef EXT2FS_DEBUG_CACHE
printk ("dcache_lookup (%04x, %d, %s, %d)\n", dev, dir, our_name, len);
#endif
queue = hash(dev, dir);
if ((p = find_name (queue, dev, dir, our_name, len))) {
if (p != first) {
remove_from_cache (p);
add_to_cache (p);
}
if (p != queue_head[queue]) {
remove_from_queue (queue, p);
add_to_queue (queue, p);
}
#ifdef EXT2FS_DEBUG_CACHE
hits ++;
printk ("dcache_lookup: %s,hit,inode=%d,hits=%d,misses=%d\n",
our_name, p->ino, hits, misses);
show_cache ("dcache_lookup");
#endif
return p->ino;
} else {
#ifdef EXT2FS_DEBUG_CACHE
misses ++;
printk ("dcache_lookup: %s,miss,hits=%d,misses=%d\n",
our_name, hits, misses);
show_cache ("dcache_lookup");
#endif
return 0;
}
}
/*
* Add a directory entry to the cache
*
* This function is called by ext2_lookup(), ext2_readdir()
* and the functions which create directory entries
*
* Note: the name is in the kernel address space
*/
void ext2_dcache_add (unsigned short dev, unsigned long dir, const char *name,
int len, int ino)
{
struct dir_cache_entry *p;
int queue;
if (!cache_initialized)
init_cache ();
#ifdef EXT2FS_DEBUG_CACHE
printk ("dcache_add (%04x, %d, %s, %d, %d)\n",
dev, dir, name, len, ino);
#endif
if (len > EXT2_NAME_LEN)
len = EXT2_NAME_LEN;
queue = hash(dev, dir);
if ((p = find_name (queue, dev, dir, name, len))) {
p->dir = dir;
p->ino = ino;
if (p != first) {
remove_from_cache (p);
add_to_cache (p);
}
if (p != queue_head[queue]) {
remove_from_queue (queue, p);
add_to_queue (queue, p);
}
} else {
if (first_free) {
p = first_free;
first_free = p->next;
} else {
if (!last)
panic ("dcache_add: last == NULL\n");
else {
p = last;
last = p->prev;
if (last)
last->next = NULL;
remove_from_queue (hash (p->dev, p->dir), p);
}
}
p->dev = dev;
p->dir = dir;
p->ino = ino;
strncpy (p->name, name, len);
p->len = len;
p->name[len] = '\0';
add_to_cache (p);
add_to_queue (queue, p);
}
#ifdef EXT2FS_DEBUG_CACHE
show_cache ("dcache_add");
#endif
}
/*
* Remove a directory from the cache
*
* This function is called by the functions which remove directory entries
*
* Note: the name is in the kernel address space
*/
void ext2_dcache_remove (unsigned short dev, unsigned long dir,
const char *name, int len)
{
struct dir_cache_entry *p;
int queue;
if (!cache_initialized)
init_cache ();
#ifdef EXT2FS_DEBUG_CACHE
printk ("dcache_remove (%04x, %d, %s, %d)\n", dev, dir, name, len);
#endif
if (len > EXT2_NAME_LEN)
len = EXT2_NAME_LEN;
queue = hash(dev, dir);
if ((p = find_name (queue, dev, dir, name, len))) {
remove_from_cache (p);
remove_from_queue (queue, p);
p->next = first_free;
first_free = p;
}
#ifdef EXT2FS_DEBUG_CACHE
show_cache ("dcache_remove");
#endif
}
#endif
/*
* linux/fs/ext2/dir.c
*
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr)
*
* from
*
* linux/fs/minix/dir.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* ext2 directory handling functions
*/
#include <asm/segment.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/stat.h>
#include <linux/sched.h>
#if 0
static int ext2_dir_read (struct inode * inode, struct file * filp,
char * buf, int count)
{
return -EISDIR;
}
#endif
/* static */ int ext2_file_read (struct inode *, struct file *, char *, int);
static int ext2_readdir (struct inode *, struct file *, struct dirent *, int);
static struct file_operations ext2_dir_operations = {
NULL, /* lseek - default */
ext2_file_read, /* read */
NULL, /* write - bad */
ext2_readdir, /* readdir */
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* mmap */
NULL, /* no special open code */
NULL, /* no special release code */
NULL /* fsync */
};
/*
* directories can handle most operations...
*/
struct inode_operations ext2_dir_inode_operations = {
&ext2_dir_operations, /* default directory file-ops */
ext2_create, /* create */
ext2_lookup, /* lookup */
ext2_link, /* link */
ext2_unlink, /* unlink */
ext2_symlink, /* symlink */
ext2_mkdir, /* mkdir */
ext2_rmdir, /* rmdir */
ext2_mknod, /* mknod */
ext2_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
ext2_truncate, /* truncate */
NULL /* permission */
};
static int ext2_readdir (struct inode * inode, struct file * filp,
struct dirent * dirent, int count)
{
unsigned int offset, i;
struct buffer_head * bh;
struct ext2_dir_entry * de;
struct super_block * sb;
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
sb = inode->i_sb;
while (filp->f_pos < inode->i_size) {
offset = filp->f_pos & (sb->s_blocksize - 1);
bh = ext2_bread (inode, (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb), 0);
if (!bh) {
filp->f_pos += sb->s_blocksize - offset;
continue;
}
de = (struct ext2_dir_entry *) (offset + bh->b_data);
while (offset < sb->s_blocksize && filp->f_pos < inode->i_size) {
if (de->rec_len < EXT2_DIR_REC_LEN(1) ||
de->rec_len % 4 != 0 ||
de->rec_len < EXT2_DIR_REC_LEN(de->name_len)) {
printk ("ext2_readdir: bad directory entry (dev %04x, dir %d)\n",
inode->i_dev, inode->i_ino);
printk ("offset=%d, inode=%d, rec_len=%d, name_len=%d\n",
offset, de->inode, de->rec_len, de->name_len);
brelse (bh);
return 0;
}
offset += de->rec_len;
filp->f_pos += de->rec_len;
if (de->inode) {
memcpy_tofs (dirent->d_name, de->name,
de->name_len);
put_fs_long (de->inode, &dirent->d_ino);
put_fs_byte (0, de->name_len + dirent->d_name);
put_fs_word (de->name_len, &dirent->d_reclen);
#ifndef DONT_USE_DCACHE
ext2_dcache_add (inode->i_dev, inode->i_ino,
de->name, de->name_len,
de->inode);
#endif
i = de->name_len;
brelse (bh);
return i;
}
de = (struct ext2_dir_entry *) ((char *) de +
de->rec_len);
}
brelse (bh);
}
return 0;
}
/*
* linux/fs/ext2/file.c
*
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr)
*
* from
*
* linux/fs/minix/file.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* ext2 fs regular file handling primitives
*/
#include <asm/segment.h>
#include <asm/system.h>
#include <linux/sched.h>
#include <linux/ext2_fs.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
#include <linux/locks.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/ext2_fs.h>
/* static */ int ext2_file_read (struct inode *, struct file *, char *, int);
static int ext2_file_write (struct inode *, struct file *, char *, int);
/*
* We have mostly NULL's here: the current defaults are ok for
* the ext2 filesystem.
*/
static struct file_operations ext2_file_operations = {
NULL, /* lseek - default */
ext2_file_read, /* read */
ext2_file_write, /* write */
NULL, /* readdir - bad */
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* mmap */
NULL, /* no special open is needed */
NULL, /* release */
NULL /* fsync */
};
struct inode_operations ext2_file_inode_operations = {
&ext2_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 */
ext2_bmap, /* bmap */
ext2_truncate, /* truncate */
NULL /* permission */
};
/* static */ int ext2_file_read (struct inode * inode, struct file * filp,
char * buf, int count)
{
int read, left, chars;
int block, blocks, offset;
int bhrequest, uptodate;
struct buffer_head ** bhb, ** bhe;
struct buffer_head * bhreq[NBUF];
struct buffer_head * buflist[NBUF];
struct super_block * sb;
unsigned int size;
if (!inode) {
printk ("ext2_file_read: inode = NULL\n");
return -EINVAL;
}
sb = inode->i_sb;
if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) {
printk ("ext2_file_read: mode = %07o\n", inode->i_mode);
return -EINVAL;
}
offset = filp->f_pos;
size = inode->i_size;
if (offset > size)
left = 0;
else
left = size - offset;
if (left > count)
left = count;
if (left <= 0)
return 0;
read = 0;
block = offset >> EXT2_BLOCK_SIZE_BITS(sb);
offset &= (sb->s_blocksize - 1);
size = (size + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb);
blocks = (left + offset + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb);
bhb = bhe = buflist;
if (filp->f_reada) {
blocks += read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9);
if (block + blocks > size)
blocks = size - block;
}
/* We do this in a two stage process. We first try and request
as many blocks as we can, then we wait for the first one to
complete, and then we try and wrap up as many as are actually
done. This routine is rather generic, in that it can be used
in a filesystem by substituting the appropriate function in
for getblk
This routine is optimized to make maximum use of the various
buffers and caches. */
do {
bhrequest = 0;
uptodate = 1;
while (blocks) {
--blocks;
*bhb = ext2_getblk (inode, block++, 0);
if (*bhb && !(*bhb)->b_uptodate) {
uptodate = 0;
bhreq[bhrequest++] = *bhb;
}
if (++bhb == &buflist[NBUF])
bhb = buflist;
/* If the block we have on hand is uptodate, go ahead
and complete processing */
if (uptodate)
break;
if (bhb == bhe)
break;
}
/* Now request them all */
if (bhrequest)
ll_rw_block (READ, bhrequest, bhreq);
do { /* Finish off all I/O that has actually completed */
if (*bhe) {
wait_on_buffer (*bhe);
if (!(*bhe)->b_uptodate) { /* read error? */
left = 0;
break;
}
}
if (left < sb->s_blocksize - offset)
chars = left;
else
chars = sb->s_blocksize - 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 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
} while (left > 0);
/* Release the read-ahead blocks */
while (bhe != bhb) {
brelse (*bhe);
if (++bhe == &buflist[NBUF])
bhe = buflist;
}
if (!read)
return -EIO;
filp->f_reada = 1;
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
}
return read;
}
static int ext2_file_write (struct inode * inode, struct file * filp,
char * buf, int count)
{
off_t pos;
int written, c;
struct buffer_head * bh;
char * p;
struct super_block * sb;
if (!inode) {
printk("ext2_file_write: inode = NULL\n");
return -EINVAL;
}
sb = inode->i_sb;
if (!S_ISREG(inode->i_mode)) {
printk ("ext2_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) {
bh = ext2_getblk (inode, pos / sb->s_blocksize, 1);
if (!bh) {
#ifdef EXT2FS_DEBUG
printk ("ext2_file_write: ext2_getblk returned NULL\n");
#endif
if (!written)
written = -ENOSPC;
break;
}
c = sb->s_blocksize - (pos % sb->s_blocksize);
if (c > count-written)
c = count - written;
if (c != sb->s_blocksize && !bh->b_uptodate) {
ll_rw_block (READ, 1, &bh);
wait_on_buffer (bh);
if (!bh->b_uptodate) {
brelse (bh);
if (!written)
written = -EIO;
break;
}
}
p = (pos % sb->s_blocksize) + bh->b_data;
pos += c;
if (pos > inode->i_size) {
inode->i_size = pos;
inode->i_dirt = 1;
}
written += c;
memcpy_fromfs (p, buf, c);
buf += c;
bh->b_uptodate = 1;
bh->b_dirt = 1;
brelse (bh);
}
inode->i_mtime = CURRENT_TIME;
inode->i_ctime = CURRENT_TIME;
filp->f_pos = pos;
inode->i_dirt = 1;
return written;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* linux/fs/ext2/symlink.c
*
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr)
*
* from
*
* linux/fs/minix/symlink.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* ext2 symlink handling code
*/
#include <asm/segment.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/stat.h>
static int ext2_readlink (struct inode *, char *, int);
static int ext2_follow_link (struct inode *, struct inode *, int, int,
struct inode **);
/*
* symlinks can't do much...
*/
struct inode_operations ext2_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 */
ext2_readlink, /* readlink */
ext2_follow_link, /* follow_link */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
static int ext2_follow_link(struct inode * dir, struct inode * inode,
int flag, int mode, struct inode ** res_inode)
{
int error;
struct buffer_head * bh = NULL;
char * link;
*res_inode = NULL;
if (!dir) {
dir = current->root;
dir->i_count ++;
}
if (!inode) {
iput (dir);
return -ENOENT;
}
if (!S_ISLNK(inode->i_mode)) {
iput (dir);
*res_inode = inode;
return 0;
}
if (current->link_count > 5) {
iput (dir);
iput (inode);
return -ELOOP;
}
if (inode->i_blocks) {
if (!(bh = ext2_bread (inode, 0, 0))) {
iput (dir);
iput (inode);
return -EIO;
}
link = bh->b_data;
} else
link = (char *) inode->u.ext2_i.i_data;
current->link_count ++;
error = open_namei (link, flag, mode, res_inode, dir);
current->link_count --;
iput (inode);
if (bh)
brelse (bh);
return error;
}
static int ext2_readlink (struct inode * inode, char * buffer, int buflen)
{
struct buffer_head * bh = NULL;
char * link;
int i;
char c;
if (!S_ISLNK(inode->i_mode)) {
iput (inode);
return -EINVAL;
}
if (buflen > inode->i_sb->s_blocksize - 1)
buflen = inode->i_sb->s_blocksize - 1;
if (inode->i_blocks) {
bh = ext2_bread (inode, 0, 0);
if (!bh) {
iput (inode);
return 0;
}
link = bh->b_data;
}
else
link = (char *) inode->u.ext2_i.i_data;
i = 0;
while (i < buflen && (c = link[i])) {
i ++;
put_fs_byte (c, buffer++);
}
iput (inode);
if (bh)
brelse (bh);
return i;
}
/*
* linux/fs/ext2/truncate.c
*
* Copyright (C) 1992, 1993 Remy Card (card@masi.ibp.fr)
*
* from
*
* linux/fs/minix/truncate.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/sched.h>
#include <linux/ext2_fs.h>
#include <linux/tty.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
/*
* Truncate has the most races in the whole filesystem: coding it is
* a pain in the a**. Especially as I don't do any locking...
*
* The code may look a bit weird, but that's just because I've tried to
* handle things like file-size changes in a somewhat graceful manner.
* Anyway, truncating a file at the same time somebody else writes to it
* is likely to result in pretty weird behaviour...
*
* The new code handles normal truncates (size = 0) as well as the more
* general case (size = XXX). I hope.
*/
static int trunc_direct (struct inode * inode)
{
int i, tmp;
unsigned long * p;
struct buffer_head * bh;
int retry = 0;
int blocks = inode->i_sb->s_blocksize / 512;
#define DIRECT_BLOCK ((inode->i_size + inode->i_sb->s_blocksize - 1) / \
inode->i_sb->s_blocksize)
int direct_block = DIRECT_BLOCK;
repeat:
for (i = direct_block ; i < EXT2_NDIR_BLOCKS ; i++) {
p = inode->u.ext2_i.i_data + i;
tmp = *p;
if (!tmp)
continue;
bh = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
if (i < direct_block) {
brelse (bh);
goto repeat;
}
if ((bh && bh->b_count != 1) || tmp != *p) {
retry = 1;
brelse (bh);
continue;
}
*p = 0;
inode->i_blocks -= blocks;
inode->i_dirt = 1;
brelse (bh);
ext2_free_block (inode->i_sb, tmp);
}
return retry;
}
static int trunc_indirect (struct inode * inode, int offset, unsigned long * p)
{
int i, tmp;
struct buffer_head * bh;
struct buffer_head * ind_bh;
unsigned long * ind;
int retry = 0;
int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
int blocks = inode->i_sb->s_blocksize / 512;
#define INDIRECT_BLOCK ((int)DIRECT_BLOCK - offset)
int indirect_block = INDIRECT_BLOCK;
tmp = *p;
if (!tmp)
return 0;
ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
if (tmp != *p) {
brelse (ind_bh);
return 1;
}
if (!ind_bh) {
*p = 0;
return 0;
}
repeat:
for (i = indirect_block ; i < addr_per_block ; i++) {
if (i < 0)
i = 0;
if (i < indirect_block)
goto repeat;
ind = i + (unsigned long *) ind_bh->b_data;
tmp = *ind;
if (!tmp)
continue;
bh = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
if (i < indirect_block) {
brelse (bh);
goto repeat;
}
if ((bh && bh->b_count != 1) || tmp != *ind) {
retry = 1;
brelse (bh);
continue;
}
*ind = 0;
ind_bh->b_dirt = 1;
brelse (bh);
ext2_free_block (inode->i_sb, tmp);
inode->i_blocks -= blocks;
inode->i_dirt = 1;
}
ind = (unsigned long *) ind_bh->b_data;
for (i = 0; i < addr_per_block; i++)
if (*(ind++))
break;
if (i >= addr_per_block)
if (ind_bh->b_count != 1)
retry = 1;
else {
tmp = *p;
*p = 0;
inode->i_blocks -= blocks;
inode->i_dirt = 1;
ext2_free_block (inode->i_sb, tmp);
}
brelse (ind_bh);
return retry;
}
static int trunc_dindirect (struct inode * inode, int offset,
unsigned long * p)
{
int i, tmp;
struct buffer_head * dind_bh;
unsigned long * dind;
int retry = 0;
int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
int blocks = inode->i_sb->s_blocksize / 512;
#define DINDIRECT_BLOCK (((int)DIRECT_BLOCK - offset) / addr_per_block)
int dindirect_block = DINDIRECT_BLOCK;
tmp = *p;
if (!tmp)
return 0;
dind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
if (tmp != *p) {
brelse (dind_bh);
return 1;
}
if (!dind_bh) {
*p = 0;
return 0;
}
repeat:
for (i = dindirect_block ; i < addr_per_block ; i ++) {
if (i < 0)
i = 0;
if (i < dindirect_block)
goto repeat;
dind = i + (unsigned long *) dind_bh->b_data;
tmp = *dind;
if (!tmp)
continue;
retry |= trunc_indirect (inode, offset + (i * addr_per_block),
dind);
dind_bh->b_dirt = 1;
}
dind = (unsigned long *) dind_bh->b_data;
for (i = 0; i < addr_per_block; i++)
if (*(dind++))
break;
if (i >= addr_per_block)
if (dind_bh->b_count != 1)
retry = 1;
else {
tmp = *p;
*p = 0;
inode->i_blocks -= blocks;
inode->i_dirt = 1;
ext2_free_block (inode->i_sb, tmp);
}
brelse (dind_bh);
return retry;
}
static int trunc_tindirect (struct inode * inode)
{
int i, tmp;
struct buffer_head * tind_bh;
unsigned long * tind, * p;
int retry = 0;
int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
int blocks = inode->i_sb->s_blocksize / 512;
#define TINDIRECT_BLOCK (((int)DIRECT_BLOCK - (addr_per_block * addr_per_block + \
addr_per_block + EXT2_NDIR_BLOCKS)) / \
(addr_per_block * addr_per_block))
int tindirect_block = TINDIRECT_BLOCK;
p = inode->u.ext2_i.i_data + EXT2_TIND_BLOCK;
if (!(tmp = *p))
return 0;
tind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
if (tmp != *p) {
brelse (tind_bh);
return 1;
}
if (!tind_bh) {
*p = 0;
return 0;
}
repeat:
for (i = tindirect_block ; i < addr_per_block ; i ++) {
if (i < 0)
i = 0;
if (i < tindirect_block)
goto repeat;
tind = i + (unsigned long *) tind_bh->b_data;
retry |= trunc_dindirect(inode, EXT2_NDIR_BLOCKS +
/* addr_per_block + addr_per_block * addr_per_block +
(i * (addr_per_block * addr_per_block)), tind); */
addr_per_block + (i + 1) * addr_per_block * addr_per_block,
tind);
tind_bh->b_dirt = 1;
}
tind = (unsigned long *) tind_bh->b_data;
for (i = 0; i < addr_per_block; i++)
if (*(tind++))
break;
if (i >= addr_per_block)
if (tind_bh->b_count != 1)
retry = 1;
else {
tmp = *p;
*p = 0;
inode->i_blocks -= blocks;
inode->i_dirt = 1;
ext2_free_block (inode->i_sb, tmp);
}
brelse (tind_bh);
return retry;
}
void ext2_truncate (struct inode * inode)
{
int retry;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
return;
while (1) {
retry = trunc_direct(inode);
retry |= trunc_indirect (inode, EXT2_IND_BLOCK,
(unsigned long *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK]);
retry |= trunc_dindirect (inode, EXT2_IND_BLOCK +
EXT2_ADDR_PER_BLOCK(inode->i_sb),
(unsigned long *) &inode->u.ext2_i.i_data[EXT2_DIND_BLOCK]);
retry |= trunc_tindirect (inode);
if (!retry)
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 ext2_open: open gets called at every open, but release
* gets called only when /all/ the files are closed.
*/
void ext2_release (struct inode * inode, struct file * filp)
{
printk ("ext2_release not implemented\n");
}
...@@ -41,6 +41,19 @@ int sys_dup2(unsigned int oldfd, unsigned int newfd) ...@@ -41,6 +41,19 @@ int sys_dup2(unsigned int oldfd, unsigned int newfd)
return -EBADF; return -EBADF;
if (newfd == oldfd) if (newfd == oldfd)
return newfd; return newfd;
/*
* errno's for dup2() are slightly different than for fcntl(F_DUPFD)
* for historical reasons.
*/
if (newfd > NR_OPEN) /* historical botch - should have been >= */
return -EBADF; /* dupfd() would return -EINVAL */
#if 1
if (newfd == NR_OPEN)
return -EBADF; /* dupfd() does return -EINVAL and that may
* even be the standard! But that is too
* weird for now.
*/
#endif
sys_close(newfd); sys_close(newfd);
return dupfd(oldfd,newfd); return dupfd(oldfd,newfd);
} }
......
...@@ -27,19 +27,28 @@ static int fifo_open(struct inode * inode,struct file * filp) ...@@ -27,19 +27,28 @@ static int fifo_open(struct inode * inode,struct file * filp)
* opened, even when there is no process writing the FIFO. * opened, even when there is no process writing the FIFO.
*/ */
filp->f_op = &read_pipe_fops; filp->f_op = &read_pipe_fops;
PIPE_READERS(*inode)++; if (!PIPE_READERS(*inode)++)
if (!(filp->f_flags & O_NONBLOCK)) wake_up(&PIPE_WRITE_WAIT(*inode));
if (!(filp->f_flags & O_NONBLOCK) && !PIPE_WRITERS(*inode)) {
PIPE_RD_OPENERS(*inode)++;
while (!PIPE_WRITERS(*inode)) { while (!PIPE_WRITERS(*inode)) {
#if 0
if (PIPE_HEAD(*inode) != PIPE_TAIL(*inode)) if (PIPE_HEAD(*inode) != PIPE_TAIL(*inode))
break; break;
#endif
if (current->signal & ~current->blocked) { if (current->signal & ~current->blocked) {
retval = -ERESTARTSYS; retval = -ERESTARTSYS;
break; break;
} }
interruptible_sleep_on(&PIPE_READ_WAIT(*inode)); interruptible_sleep_on(&PIPE_READ_WAIT(*inode));
} }
if (retval) if (!--PIPE_RD_OPENERS(*inode))
PIPE_READERS(*inode)--; wake_up(&PIPE_WRITE_WAIT(*inode));
}
while (PIPE_WR_OPENERS(*inode))
interruptible_sleep_on(&PIPE_READ_WAIT(*inode));
if (retval && !--PIPE_READERS(*inode))
wake_up(&PIPE_WRITE_WAIT(*inode));
break; break;
case 2: case 2:
...@@ -53,16 +62,24 @@ static int fifo_open(struct inode * inode,struct file * filp) ...@@ -53,16 +62,24 @@ static int fifo_open(struct inode * inode,struct file * filp)
break; break;
} }
filp->f_op = &write_pipe_fops; filp->f_op = &write_pipe_fops;
PIPE_WRITERS(*inode)++; if (!PIPE_WRITERS(*inode)++)
while (!PIPE_READERS(*inode)) { wake_up(&PIPE_READ_WAIT(*inode));
if (current->signal & ~current->blocked) { if (!PIPE_READERS(*inode)) {
retval = -ERESTARTSYS; PIPE_WR_OPENERS(*inode)++;
break; while (!PIPE_READERS(*inode)) {
if (current->signal & ~current->blocked) {
retval = -ERESTARTSYS;
break;
}
interruptible_sleep_on(&PIPE_WRITE_WAIT(*inode));
} }
interruptible_sleep_on(&PIPE_WRITE_WAIT(*inode)); if (!--PIPE_WR_OPENERS(*inode))
wake_up(&PIPE_READ_WAIT(*inode));
} }
if (retval) while (PIPE_RD_OPENERS(*inode))
PIPE_WRITERS(*inode)--; interruptible_sleep_on(&PIPE_WRITE_WAIT(*inode));
if (retval && !--PIPE_WRITERS(*inode))
wake_up(&PIPE_READ_WAIT(*inode));
break; break;
case 3: case 3:
...@@ -73,17 +90,19 @@ static int fifo_open(struct inode * inode,struct file * filp) ...@@ -73,17 +90,19 @@ static int fifo_open(struct inode * inode,struct file * filp)
* the process can at least talk to itself. * the process can at least talk to itself.
*/ */
filp->f_op = &rdwr_pipe_fops; filp->f_op = &rdwr_pipe_fops;
PIPE_WRITERS(*inode) += 1; if (!PIPE_READERS(*inode)++)
PIPE_READERS(*inode) += 1; wake_up(&PIPE_WRITE_WAIT(*inode));
while (PIPE_WR_OPENERS(*inode))
interruptible_sleep_on(&PIPE_READ_WAIT(*inode));
if (!PIPE_WRITERS(*inode)++)
wake_up(&PIPE_READ_WAIT(*inode));
while (PIPE_RD_OPENERS(*inode))
interruptible_sleep_on(&PIPE_WRITE_WAIT(*inode));
break; break;
default: default:
retval = -EINVAL; retval = -EINVAL;
} }
if (PIPE_WRITERS(*inode))
wake_up(&PIPE_READ_WAIT(*inode));
if (PIPE_READERS(*inode))
wake_up(&PIPE_WRITE_WAIT(*inode));
if (retval || PIPE_BASE(*inode)) if (retval || PIPE_BASE(*inode))
return retval; return retval;
page = get_free_page(GFP_KERNEL); page = get_free_page(GFP_KERNEL);
......
...@@ -11,9 +11,15 @@ ...@@ -11,9 +11,15 @@
#ifdef CONFIG_MINIX_FS #ifdef CONFIG_MINIX_FS
#include <linux/minix_fs.h> #include <linux/minix_fs.h>
#endif #endif
#ifdef CONFIG_XIA_FS
#include <linux/xia_fs.h>
#endif
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#endif #endif
#ifdef CONFIG_EXT2_FS
#include <linux/ext2_fs.h>
#endif
#ifdef CONFIG_EXT_FS #ifdef CONFIG_EXT_FS
#include <linux/ext_fs.h> #include <linux/ext_fs.h>
#endif #endif
...@@ -31,9 +37,15 @@ struct file_system_type file_systems[] = { ...@@ -31,9 +37,15 @@ struct file_system_type file_systems[] = {
#ifdef CONFIG_MINIX_FS #ifdef CONFIG_MINIX_FS
{minix_read_super, "minix", 1}, {minix_read_super, "minix", 1},
#endif #endif
#ifdef CONFIG_XIA_FS
{xiafs_read_super, "xiafs", 1},
#endif
#ifdef CONFIG_EXT_FS #ifdef CONFIG_EXT_FS
{ext_read_super, "ext", 1}, {ext_read_super, "ext", 1},
#endif #endif
#ifdef CONFIG_EXT2_FS
{ext2_read_super, "ext2", 1},
#endif
#ifdef CONFIG_MSDOS_FS #ifdef CONFIG_MSDOS_FS
{msdos_read_super, "msdos", 1}, {msdos_read_super, "msdos", 1},
#endif #endif
......
...@@ -164,7 +164,8 @@ void invalidate_inodes(dev_t dev) ...@@ -164,7 +164,8 @@ void invalidate_inodes(dev_t dev)
wait_on_inode(inode); wait_on_inode(inode);
if (inode->i_dev == dev) { if (inode->i_dev == dev) {
if (inode->i_count) { if (inode->i_count) {
printk("inode in use on removed disk\n\r"); printk("VFS: inode busy on removed device %d/%d\n",
MAJOR(dev), MINOR(dev));
continue; continue;
} }
clear_inode(inode); clear_inode(inode);
...@@ -191,9 +192,10 @@ void iput(struct inode * inode) ...@@ -191,9 +192,10 @@ void iput(struct inode * inode)
return; return;
wait_on_inode(inode); wait_on_inode(inode);
if (!inode->i_count) { if (!inode->i_count) {
printk("iput: trying to free free inode\n"); printk("VFS: iput: trying to free free inode\n");
printk("device %04x, inode %d, mode=%07o\n",inode->i_rdev, printk("VFS: device %d/%d, inode %d, mode=0%07o\n",
inode->i_ino,inode->i_mode); MAJOR(inode->i_rdev), MINOR(inode->i_rdev),
inode->i_ino, inode->i_mode);
return; return;
} }
if (inode->i_pipe) { if (inode->i_pipe) {
...@@ -242,7 +244,7 @@ struct inode * get_empty_inode(void) ...@@ -242,7 +244,7 @@ struct inode * get_empty_inode(void)
} }
} }
if (!inode) { if (!inode) {
printk("No free inodes - contact Linus\n"); printk("VFS: No free inodes - contact Linus\n");
sleep_on(&inode_wait); sleep_on(&inode_wait);
goto repeat; goto repeat;
} }
...@@ -275,8 +277,13 @@ struct inode * get_pipe_inode(void) ...@@ -275,8 +277,13 @@ struct inode * get_pipe_inode(void)
inode->i_count = 2; /* sum of readers/writers */ inode->i_count = 2; /* sum of readers/writers */
PIPE_READ_WAIT(*inode) = PIPE_WRITE_WAIT(*inode) = NULL; PIPE_READ_WAIT(*inode) = PIPE_WRITE_WAIT(*inode) = NULL;
PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0; PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1; PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
inode->i_pipe = 1; inode->i_pipe = 1;
inode->i_mode |= S_IFIFO;
inode->i_uid = current->euid;
inode->i_gid = current->egid;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
return inode; return inode;
} }
...@@ -285,7 +292,7 @@ struct inode * iget(struct super_block * sb,int nr) ...@@ -285,7 +292,7 @@ struct inode * iget(struct super_block * sb,int nr)
struct inode * inode, * empty; struct inode * inode, * empty;
if (!sb) if (!sb)
panic("iget with sb==NULL"); panic("VFS: iget with sb==NULL");
empty = get_empty_inode(); empty = get_empty_inode();
inode = inode_table; inode = inode_table;
while (inode < NR_INODE+inode_table) { while (inode < NR_INODE+inode_table) {
...@@ -306,21 +313,34 @@ struct inode * iget(struct super_block * sb,int nr) ...@@ -306,21 +313,34 @@ struct inode * iget(struct super_block * sb,int nr)
if (super_block[i].s_covered==inode) if (super_block[i].s_covered==inode)
break; break;
if (i >= NR_SUPER) { if (i >= NR_SUPER) {
printk("Mounted inode hasn't got sb\n"); printk("VFS: Mounted inode hasn't got sb\n");
if (empty) if (empty) {
if (last_inode > inode_table)
--last_inode;
else
last_inode
= inode_table + NR_INODE;
iput(empty); iput(empty);
}
return inode; return inode;
} }
iput(inode); iput(inode);
if (!(inode = super_block[i].s_mounted)) if (!(inode = super_block[i].s_mounted))
printk("iget: mounted dev has no rootinode\n"); printk("VFS: Mounted device %d/%d has no rootinode\n",
MAJOR(inode->i_dev), MINOR(inode->i_dev));
else { else {
inode->i_count++; inode->i_count++;
wait_on_inode(inode); wait_on_inode(inode);
} }
} }
if (empty) if (empty) {
if (last_inode > inode_table)
--last_inode;
else
last_inode
= inode_table + NR_INODE;
iput(empty); iput(empty);
}
return inode; return inode;
} }
if (!empty) if (!empty)
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg) static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
{ {
int error;
int block; int block;
switch (cmd) { switch (cmd) {
...@@ -23,7 +24,9 @@ static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg) ...@@ -23,7 +24,9 @@ static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
return -EBADF; return -EBADF;
if (filp->f_inode->i_op->bmap == NULL) if (filp->f_inode->i_op->bmap == NULL)
return -EINVAL; return -EINVAL;
verify_area((void *) arg,4); error = verify_area(VERIFY_WRITE,(void *) arg,4);
if (error)
return error;
block = get_fs_long((long *) arg); block = get_fs_long((long *) arg);
block = filp->f_inode->i_op->bmap(filp->f_inode,block); block = filp->f_inode->i_op->bmap(filp->f_inode,block);
put_fs_long(block,(long *) arg); put_fs_long(block,(long *) arg);
...@@ -31,12 +34,16 @@ static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg) ...@@ -31,12 +34,16 @@ static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
case FIGETBSZ: case FIGETBSZ:
if (filp->f_inode->i_sb == NULL) if (filp->f_inode->i_sb == NULL)
return -EBADF; return -EBADF;
verify_area((void *) arg,4); error = verify_area(VERIFY_WRITE,(void *) arg,4);
if (error)
return error;
put_fs_long(filp->f_inode->i_sb->s_blocksize, put_fs_long(filp->f_inode->i_sb->s_blocksize,
(long *) arg); (long *) arg);
return 0; return 0;
case FIONREAD: case FIONREAD:
verify_area((void *) arg,4); error = verify_area(VERIFY_WRITE,(void *) arg,4);
if (error)
return error;
put_fs_long(filp->f_inode->i_size - filp->f_pos, put_fs_long(filp->f_inode->i_size - filp->f_pos,
(long *) arg); (long *) arg);
return 0; return 0;
......
...@@ -477,8 +477,8 @@ int isofs_lookup_grandparent(struct inode * parent, int extent) { ...@@ -477,8 +477,8 @@ int isofs_lookup_grandparent(struct inode * parent, int extent) {
if (de->name_len[0] == 1 && de->name[0] == 1) if (de->name_len[0] == 1 && de->name[0] == 1)
{ {
brelse(bh);
parent_dir = find_rock_ridge_relocation(de, parent); parent_dir = find_rock_ridge_relocation(de, parent);
brelse(bh);
break; break;
}; };
} }
......
...@@ -45,7 +45,7 @@ static int isofs_match(int len,const char * name, char * compare, int dlen) ...@@ -45,7 +45,7 @@ static int isofs_match(int len,const char * name, char * compare, int dlen)
if (dlen != len) if (dlen != len)
return 0; return 0;
__asm__("cld\n\t" __asm__("cld\n\t"
"fs ; repe ; cmpsb\n\t" "repe ; cmpsb\n\t"
"setz %%al" "setz %%al"
:"=a" (same) :"=a" (same)
:"0" (0),"S" ((long) name),"D" ((long) compare),"c" (len) :"0" (0),"S" ((long) name),"D" ((long) compare),"c" (len)
...@@ -241,8 +241,8 @@ int isofs_lookup(struct inode * dir,const char * name, int len, ...@@ -241,8 +241,8 @@ int isofs_lookup(struct inode * dir,const char * name, int len,
/* We need this backlink for the .. entry */ /* We need this backlink for the .. entry */
if (ino_back) (*result)->u.isofs_i.i_backlink = ino_back; if (ino_back && !(*result)->i_pipe)
(*result)->u.isofs_i.i_backlink = ino_back;
iput(dir); iput(dir);
return 0; return 0;
} }
...@@ -60,14 +60,17 @@ ...@@ -60,14 +60,17 @@
if (offset >= 1024) block++; \ if (offset >= 1024) block++; \
offset &= 1023; \ offset &= 1023; \
bh = bread(DEV, block, 1024); \ bh = bread(DEV, block, 1024); \
memcpy(buffer, bh->b_data, cont_size); \ if (bh) { \
brelse(bh); \ memcpy(buffer, bh->b_data, cont_size); \
chr = buffer; \ brelse(bh); \
len = cont_size; \ chr = buffer; \
cont_extent = 0; \ len = cont_size; \
cont_size = 0; \ cont_extent = 0; \
cont_offset = 0; \ cont_size = 0; \
goto LABEL; \ cont_offset = 0; \
goto LABEL; \
} \
printk("Unable to read rock-ridge descriptor block\n"); \
}} }}
......
...@@ -45,7 +45,6 @@ static int isofs_follow_link(struct inode * dir, struct inode * inode, ...@@ -45,7 +45,6 @@ static int isofs_follow_link(struct inode * dir, struct inode * inode,
int flag, int mode, struct inode ** res_inode) int flag, int mode, struct inode ** res_inode)
{ {
int error; int error;
unsigned short fs;
char * pnt; char * pnt;
if (!dir) { if (!dir) {
...@@ -62,7 +61,6 @@ static int isofs_follow_link(struct inode * dir, struct inode * inode, ...@@ -62,7 +61,6 @@ static int isofs_follow_link(struct inode * dir, struct inode * inode,
*res_inode = inode; *res_inode = inode;
return 0; return 0;
} }
__asm__("mov %%fs,%0":"=r" (fs));
if ((current->link_count > 5) || if ((current->link_count > 5) ||
!(pnt = get_rock_ridge_symlink(inode))) { !(pnt = get_rock_ridge_symlink(inode))) {
iput(dir); iput(dir);
...@@ -71,11 +69,9 @@ static int isofs_follow_link(struct inode * dir, struct inode * inode, ...@@ -71,11 +69,9 @@ static int isofs_follow_link(struct inode * dir, struct inode * inode,
return -ELOOP; return -ELOOP;
} }
iput(inode); iput(inode);
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
current->link_count++; current->link_count++;
error = open_namei(pnt,flag,mode,res_inode,dir); error = open_namei(pnt,flag,mode,res_inode,dir);
current->link_count--; current->link_count--;
__asm__("mov %0,%%fs"::"r" (fs));
kfree(pnt); kfree(pnt);
return error; return error;
} }
......
...@@ -49,14 +49,17 @@ void fcntl_init_locks(void) ...@@ -49,14 +49,17 @@ void fcntl_init_locks(void)
} }
int fcntl_getlk(unsigned int fd, struct flock *l) int fcntl_getlk(unsigned int fd, struct flock *l)
{ {
int error;
struct flock flock; struct flock flock;
struct file *filp; struct file *filp;
struct file_lock *fl,file_lock; struct file_lock *fl,file_lock;
if (fd >= NR_OPEN || !(filp = current->filp[fd])) if (fd >= NR_OPEN || !(filp = current->filp[fd]))
return -EBADF; return -EBADF;
verify_area(l, sizeof(*l)); error = verify_area(VERIFY_WRITE,l, sizeof(*l));
if (error)
return error;
memcpy_fromfs(&flock, l, sizeof(flock)); memcpy_fromfs(&flock, l, sizeof(flock));
if (flock.l_type == F_UNLCK) if (flock.l_type == F_UNLCK)
return -EINVAL; return -EINVAL;
...@@ -86,7 +89,8 @@ int fcntl_getlk(unsigned int fd, struct flock *l) ...@@ -86,7 +89,8 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
*/ */
int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
{ {
int error;
struct file *filp; struct file *filp;
struct file_lock *fl,file_lock; struct file_lock *fl,file_lock;
struct flock flock; struct flock flock;
...@@ -97,7 +101,9 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) ...@@ -97,7 +101,9 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
if (fd >= NR_OPEN || !(filp = current->filp[fd])) if (fd >= NR_OPEN || !(filp = current->filp[fd]))
return -EBADF; return -EBADF;
verify_area(l, sizeof(*l)); error = verify_area(VERIFY_WRITE, l, sizeof(*l));
if (error)
return error;
memcpy_fromfs(&flock, l, sizeof(flock)); memcpy_fromfs(&flock, l, sizeof(flock));
if (!copy_flock(filp, &file_lock, &flock)) if (!copy_flock(filp, &file_lock, &flock))
return -EINVAL; return -EINVAL;
...@@ -145,7 +151,11 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) ...@@ -145,7 +151,11 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
* FIXME: We need to check for deadlocks here. * FIXME: We need to check for deadlocks here.
*/ */
if (cmd == F_SETLKW) { if (cmd == F_SETLKW) {
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
interruptible_sleep_on(&fl->fl_wait); interruptible_sleep_on(&fl->fl_wait);
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
goto repeat; goto repeat;
} }
return -EAGAIN; return -EAGAIN;
...@@ -330,7 +340,7 @@ static int lock_it(struct file *filp, struct file_lock *caller) ...@@ -330,7 +340,7 @@ static int lock_it(struct file *filp, struct file_lock *caller)
fl->fl_end = caller->fl_start - 1; fl->fl_end = caller->fl_start - 1;
/* must continue, may be more overlaps */ /* must continue, may be more overlaps */
} else { } else {
printk("lock_it: program bug: unanticipated overlap\n"); printk("VFS: lock_it: program bug: unanticipated overlap\n");
free_lock(filp, caller); free_lock(filp, caller);
return -ENOLCK; return -ENOLCK;
} }
...@@ -431,7 +441,7 @@ static struct file_lock *alloc_lock(struct file *filp, struct file_lock *templat ...@@ -431,7 +441,7 @@ static struct file_lock *alloc_lock(struct file *filp, struct file_lock *templat
if (file_lock_free_list == NULL) if (file_lock_free_list == NULL)
return NULL; /* no available entry */ return NULL; /* no available entry */
if (file_lock_free_list->fl_owner != NULL) if (file_lock_free_list->fl_owner != NULL)
panic("alloc_lock: broken free list\n"); panic("VFS: alloc_lock: broken free list\n");
new = file_lock_free_list; /* remove from free list */ new = file_lock_free_list; /* remove from free list */
file_lock_free_list = file_lock_free_list->fl_next; file_lock_free_list = file_lock_free_list->fl_next;
...@@ -457,7 +467,7 @@ static void free_lock(struct file *filp, struct file_lock *fl) ...@@ -457,7 +467,7 @@ static void free_lock(struct file *filp, struct file_lock *fl)
struct file_lock **fl_p; struct file_lock **fl_p;
if (fl->fl_owner == NULL) /* sanity check */ if (fl->fl_owner == NULL) /* sanity check */
panic("free_lock: broken lock list\n"); panic("VFS: free_lock: broken lock list\n");
/* /*
* We only use a singly linked list to save some memory space * We only use a singly linked list to save some memory space
...@@ -469,7 +479,7 @@ static void free_lock(struct file *filp, struct file_lock *fl) ...@@ -469,7 +479,7 @@ static void free_lock(struct file *filp, struct file_lock *fl)
break; break;
} }
if (*fl_p == NULL) { if (*fl_p == NULL) {
printk("free_lock: lock is not in file's lock list\n"); printk("VFS: free_lock: lock is not in file's lock list\n");
} else { } else {
*fl_p = (*fl_p)->fl_next; *fl_p = (*fl_p)->fl_next;
} }
......
...@@ -61,10 +61,12 @@ static int minix_readdir(struct inode * inode, struct file * filp, ...@@ -61,10 +61,12 @@ static int minix_readdir(struct inode * inode, struct file * filp,
char c; char c;
struct buffer_head * bh; struct buffer_head * bh;
struct minix_dir_entry * de; struct minix_dir_entry * de;
struct minix_sb_info * info;
if (!inode || !S_ISDIR(inode->i_mode)) if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode))
return -EBADF; return -EBADF;
if (filp->f_pos & (sizeof (struct minix_dir_entry) - 1)) info = &inode->i_sb->u.minix_sb;
if (filp->f_pos & (info->s_dirsize - 1))
return -EBADF; return -EBADF;
while (filp->f_pos < inode->i_size) { while (filp->f_pos < inode->i_size) {
offset = filp->f_pos & 1023; offset = filp->f_pos & 1023;
...@@ -73,12 +75,12 @@ static int minix_readdir(struct inode * inode, struct file * filp, ...@@ -73,12 +75,12 @@ static int minix_readdir(struct inode * inode, struct file * filp,
filp->f_pos += 1024-offset; filp->f_pos += 1024-offset;
continue; continue;
} }
de = (struct minix_dir_entry *) (offset + bh->b_data);
while (offset < 1024 && filp->f_pos < inode->i_size) { while (offset < 1024 && filp->f_pos < inode->i_size) {
offset += sizeof (struct minix_dir_entry); de = (struct minix_dir_entry *) (offset + bh->b_data);
filp->f_pos += sizeof (struct minix_dir_entry); offset += info->s_dirsize;
filp->f_pos += info->s_dirsize;
if (de->inode) { if (de->inode) {
for (i = 0; i < MINIX_NAME_LEN; i++) for (i = 0; i < info->s_namelen; i++)
if ((c = de->name[i]) != 0) if ((c = de->name[i]) != 0)
put_fs_byte(c,i+dirent->d_name); put_fs_byte(c,i+dirent->d_name);
else else
...@@ -91,7 +93,6 @@ static int minix_readdir(struct inode * inode, struct file * filp, ...@@ -91,7 +93,6 @@ static int minix_readdir(struct inode * inode, struct file * filp,
return i; return i;
} }
} }
de++;
} }
brelse(bh); brelse(bh);
} }
......
...@@ -241,8 +241,7 @@ static int minix_file_write(struct inode * inode, struct file * filp, char * buf ...@@ -241,8 +241,7 @@ static int minix_file_write(struct inode * inode, struct file * filp, char * buf
bh->b_dirt = 1; bh->b_dirt = 1;
brelse(bh); brelse(bh);
} }
inode->i_mtime = CURRENT_TIME; inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_ctime = CURRENT_TIME;
filp->f_pos = pos; filp->f_pos = pos;
inode->i_dirt = 1; inode->i_dirt = 1;
return written; return written;
......
...@@ -74,7 +74,13 @@ struct super_block *minix_read_super(struct super_block *s,void *data) ...@@ -74,7 +74,13 @@ struct super_block *minix_read_super(struct super_block *s,void *data)
s->u.minix_sb.s_max_size = ms->s_max_size; s->u.minix_sb.s_max_size = ms->s_max_size;
s->s_magic = ms->s_magic; s->s_magic = ms->s_magic;
brelse(bh); brelse(bh);
if (s->s_magic != MINIX_SUPER_MAGIC) { if (s->s_magic == MINIX_SUPER_MAGIC) {
s->u.minix_sb.s_dirsize = 16;
s->u.minix_sb.s_namelen = 14;
} else if (s->s_magic == MINIX_SUPER_MAGIC2) {
s->u.minix_sb.s_dirsize = 32;
s->u.minix_sb.s_namelen = 30;
} else {
s->s_dev = 0; s->s_dev = 0;
unlock_super(s); unlock_super(s);
printk("MINIX-fs magic match failed\n"); printk("MINIX-fs magic match failed\n");
......
This diff is collapsed.
...@@ -42,7 +42,6 @@ static int minix_follow_link(struct inode * dir, struct inode * inode, ...@@ -42,7 +42,6 @@ static int minix_follow_link(struct inode * dir, struct inode * inode,
int flag, int mode, struct inode ** res_inode) int flag, int mode, struct inode ** res_inode)
{ {
int error; int error;
unsigned short fs;
struct buffer_head * bh; struct buffer_head * bh;
*res_inode = NULL; *res_inode = NULL;
...@@ -70,12 +69,9 @@ static int minix_follow_link(struct inode * dir, struct inode * inode, ...@@ -70,12 +69,9 @@ static int minix_follow_link(struct inode * dir, struct inode * inode,
return -EIO; return -EIO;
} }
iput(inode); iput(inode);
__asm__("mov %%fs,%0":"=r" (fs));
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
current->link_count++; current->link_count++;
error = open_namei(bh->b_data,flag,mode,res_inode,dir); error = open_namei(bh->b_data,flag,mode,res_inode,dir);
current->link_count--; current->link_count--;
__asm__("mov %0,%%fs"::"r" (fs));
brelse(bh); brelse(bh);
return error; return error;
} }
......
...@@ -37,7 +37,7 @@ static int trunc_direct(struct inode * inode) ...@@ -37,7 +37,7 @@ static int trunc_direct(struct inode * inode)
p = i + inode->u.minix_i.i_data; p = i + inode->u.minix_i.i_data;
if (!(tmp = *p)) if (!(tmp = *p))
continue; continue;
bh = getblk(inode->i_dev,tmp,BLOCK_SIZE); bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
if (i < DIRECT_BLOCK) { if (i < DIRECT_BLOCK) {
brelse(bh); brelse(bh);
goto repeat; goto repeat;
...@@ -86,7 +86,7 @@ static int trunc_indirect(struct inode * inode, int offset, unsigned short * p) ...@@ -86,7 +86,7 @@ static int trunc_indirect(struct inode * inode, int offset, unsigned short * p)
tmp = *ind; tmp = *ind;
if (!tmp) if (!tmp)
continue; continue;
bh = getblk(inode->i_dev,tmp,BLOCK_SIZE); bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
if (i < INDIRECT_BLOCK) { if (i < INDIRECT_BLOCK) {
brelse(bh); brelse(bh);
goto repeat; goto repeat;
......
...@@ -36,9 +36,9 @@ static int msdos_format_name(char conv,const char *name,int len,char *res) ...@@ -36,9 +36,9 @@ static int msdos_format_name(char conv,const char *name,int len,char *res)
char c; char c;
int space; int space;
if (get_fs_byte(name) == DELETED_FLAG) return -EINVAL; if (*(unsigned char *)name == DELETED_FLAG) return -EINVAL;
if (get_fs_byte(name) == '.' && (len == 1 || (len == 2 && if (name[0] == '.' && (len == 1 || (len == 2 &&
get_fs_byte(name+1) == '.'))) { name[1] == '.'))) {
memset(res+1,' ',10); memset(res+1,' ',10);
while (len--) *res++ = '.'; while (len--) *res++ = '.';
return 0; return 0;
...@@ -46,7 +46,7 @@ static int msdos_format_name(char conv,const char *name,int len,char *res) ...@@ -46,7 +46,7 @@ static int msdos_format_name(char conv,const char *name,int len,char *res)
space = 0; /* to make GCC happy */ space = 0; /* to make GCC happy */
c = 0; c = 0;
for (walk = res; len && walk-res < 8; walk++) { for (walk = res; len && walk-res < 8; walk++) {
c = get_fs_byte(name++); c = *(name++);
len--; len--;
if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL; if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL; if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
...@@ -61,16 +61,16 @@ static int msdos_format_name(char conv,const char *name,int len,char *res) ...@@ -61,16 +61,16 @@ static int msdos_format_name(char conv,const char *name,int len,char *res)
} }
if (space) return -EINVAL; if (space) return -EINVAL;
if (conv == 's' && len && c != '.') { if (conv == 's' && len && c != '.') {
c = get_fs_byte(name++); c = *(name++);
len--; len--;
if (c != '.') return -EINVAL; if (c != '.') return -EINVAL;
} }
while (c != '.' && len--) c = get_fs_byte(name++); while (c != '.' && len--) c = *(name++);
if (walk == res) return -EINVAL; if (walk == res) return -EINVAL;
if (c == '.') { if (c == '.') {
while (walk-res < 8) *walk++ = ' '; while (walk-res < 8) *walk++ = ' ';
while (len > 0 && walk-res < MSDOS_NAME) { while (len > 0 && walk-res < MSDOS_NAME) {
c = get_fs_byte(name++); c = *(name++);
len--; len--;
if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL; if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
if (conv == 's' && strchr(bad_if_strict,c)) if (conv == 's' && strchr(bad_if_strict,c))
...@@ -122,11 +122,11 @@ int msdos_lookup(struct inode *dir,const char *name,int len, ...@@ -122,11 +122,11 @@ int msdos_lookup(struct inode *dir,const char *name,int len,
iput(dir); iput(dir);
return -ENOENT; return -ENOENT;
} }
if (len == 1 && get_fs_byte(name) == '.') { if (len == 1 && name[0] == '.') {
*result = dir; *result = dir;
return 0; return 0;
} }
if (len == 2 && get_fs_byte(name) == '.' && get_fs_byte(name+1) == '.') if (len == 2 && name[0] == '.' && name[1] == '.')
{ {
ino = msdos_parent_ino(dir,0); ino = msdos_parent_ino(dir,0);
iput(dir); iput(dir);
...@@ -139,7 +139,7 @@ int msdos_lookup(struct inode *dir,const char *name,int len, ...@@ -139,7 +139,7 @@ int msdos_lookup(struct inode *dir,const char *name,int len,
return res; return res;
} }
if (bh) brelse(bh); if (bh) brelse(bh);
/* printk("lookup: ino=%d\r\n",ino); */ /* printk("lookup: ino=%d\n",ino); */
if (!(*result = iget(dir->i_sb,ino))) { if (!(*result = iget(dir->i_sb,ino))) {
iput(dir); iput(dir);
return -EACCES; return -EACCES;
...@@ -305,8 +305,8 @@ int msdos_rmdir(struct inode *dir,const char *name,int len) ...@@ -305,8 +305,8 @@ int msdos_rmdir(struct inode *dir,const char *name,int len)
bh = NULL; bh = NULL;
inode = NULL; inode = NULL;
res = -EINVAL; res = -EINVAL;
if (get_fs_byte(name) == '.' && (len == 1 || (len == 2 && if (name[0] == '.' && (len == 1 || (len == 2 &&
get_fs_byte(name+1) == '.'))) goto rmdir_done; name[1] == '.'))) goto rmdir_done;
if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done; if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done;
res = -ENOENT; res = -ENOENT;
if (!(inode = iget(dir->i_sb,ino))) goto rmdir_done; if (!(inode = iget(dir->i_sb,ino))) goto rmdir_done;
......
This diff is collapsed.
This diff is collapsed.
...@@ -56,7 +56,7 @@ static inline int *xdr_decode_fhandle(int *p, struct nfs_fh *fhandle) ...@@ -56,7 +56,7 @@ static inline int *xdr_decode_fhandle(int *p, struct nfs_fh *fhandle)
return p; return p;
} }
static inline int *xdr_encode_string(int *p, char *string) static inline int *xdr_encode_string(int *p, const char *string)
{ {
int len, quadlen; int len, quadlen;
...@@ -215,7 +215,7 @@ int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -215,7 +215,7 @@ int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
} }
int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, char *name, int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *name,
struct nfs_fh *fhandle, struct nfs_fattr *fattr) struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{ {
int *p, *p0; int *p, *p0;
...@@ -343,7 +343,7 @@ int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -343,7 +343,7 @@ int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle,
} }
int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir, int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
char *name, struct nfs_sattr *sattr, const char *name, struct nfs_sattr *sattr,
struct nfs_fh *fhandle, struct nfs_fattr *fattr) struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{ {
int *p, *p0; int *p, *p0;
...@@ -372,7 +372,7 @@ int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir, ...@@ -372,7 +372,7 @@ int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
} }
int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, char *name) int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, const char *name)
{ {
int *p, *p0; int *p, *p0;
int status; int status;
...@@ -398,8 +398,8 @@ int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, char *name) ...@@ -398,8 +398,8 @@ int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, char *name)
} }
int nfs_proc_rename(struct nfs_server *server, int nfs_proc_rename(struct nfs_server *server,
struct nfs_fh *old_dir, char *old_name, struct nfs_fh *old_dir, const char *old_name,
struct nfs_fh *new_dir, char *new_name) struct nfs_fh *new_dir, const char *new_name)
{ {
int *p, *p0; int *p, *p0;
int status; int status;
...@@ -427,7 +427,7 @@ int nfs_proc_rename(struct nfs_server *server, ...@@ -427,7 +427,7 @@ int nfs_proc_rename(struct nfs_server *server,
} }
int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle, int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fh *dir, char *name) struct nfs_fh *dir, const char *name)
{ {
int *p, *p0; int *p, *p0;
int status; int status;
...@@ -454,7 +454,7 @@ int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -454,7 +454,7 @@ int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
} }
int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir, int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
char *name, char *path, struct nfs_sattr *sattr) const char *name, const char *path, struct nfs_sattr *sattr)
{ {
int *p, *p0; int *p, *p0;
int status; int status;
...@@ -482,7 +482,7 @@ int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir, ...@@ -482,7 +482,7 @@ int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
} }
int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir, int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
char *name, struct nfs_sattr *sattr, const char *name, struct nfs_sattr *sattr,
struct nfs_fh *fhandle, struct nfs_fattr *fattr) struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{ {
int *p, *p0; int *p, *p0;
...@@ -511,7 +511,7 @@ int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir, ...@@ -511,7 +511,7 @@ int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
} }
int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, char *name) int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *name)
{ {
int *p, *p0; int *p, *p0;
int status; int status;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/fcntl.h> #include <linux/fcntl.h>
#include <asm/segment.h>
#include <netinet/in.h> #include <netinet/in.h>
...@@ -63,8 +64,8 @@ static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end) ...@@ -63,8 +64,8 @@ static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end)
printk("nfs_rpc_call: socki_lookup failed\n"); printk("nfs_rpc_call: socki_lookup failed\n");
return -EBADF; return -EBADF;
} }
__asm__("mov %%fs,%0":"=r" (fs)); fs = get_fs();
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10)); set_fs(get_ds());
for (n = 0, timeout = init_timeout; ; n++, timeout <<= 1) { for (n = 0, timeout = init_timeout; ; n++, timeout <<= 1) {
result = sock->ops->send(sock, (void *) start, len, 0, 0); result = sock->ops->send(sock, (void *) start, len, 0, 0);
if (result < 0) { if (result < 0) {
...@@ -123,8 +124,10 @@ static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end) ...@@ -123,8 +124,10 @@ static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end)
NULL, &addrlen); NULL, &addrlen);
if (result < 0) { if (result < 0) {
if (result == -EAGAIN) { if (result == -EAGAIN) {
printk("nfs_rpc_call: bad select ready\n");
goto re_select; goto re_select;
#if 0
printk("nfs_rpc_call: bad select ready\n");
#endif
} }
if (result != -ERESTARTSYS) { if (result != -ERESTARTSYS) {
printk("nfs_rpc_call: recv error = %d\n", printk("nfs_rpc_call: recv error = %d\n",
...@@ -141,7 +144,7 @@ static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end) ...@@ -141,7 +144,7 @@ static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end)
printk("nfs_rpc_call: XID mismatch\n"); printk("nfs_rpc_call: XID mismatch\n");
#endif #endif
} }
__asm__("mov %0,%%fs"::"r" (fs)); set_fs(fs);
return result; return result;
} }
......
...@@ -43,7 +43,6 @@ static int nfs_follow_link(struct inode *dir, struct inode *inode, ...@@ -43,7 +43,6 @@ static int nfs_follow_link(struct inode *dir, struct inode *inode,
int flag, int mode, struct inode **res_inode) int flag, int mode, struct inode **res_inode)
{ {
int error; int error;
unsigned short fs;
char *res; char *res;
*res_inode = NULL; *res_inode = NULL;
...@@ -74,13 +73,10 @@ static int nfs_follow_link(struct inode *dir, struct inode *inode, ...@@ -74,13 +73,10 @@ static int nfs_follow_link(struct inode *dir, struct inode *inode,
return error; return error;
} }
iput(inode); iput(inode);
__asm__("mov %%fs,%0":"=r" (fs));
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
current->link_count++; current->link_count++;
error = open_namei(res, flag, mode, res_inode, dir); error = open_namei(res, flag, mode, res_inode, dir);
current->link_count--; current->link_count--;
kfree_s(res, NFS_MAXPATHLEN + 1); kfree_s(res, NFS_MAXPATHLEN + 1);
__asm__("mov %0,%%fs"::"r" (fs));
return error; return error;
} }
......
This diff is collapsed.
...@@ -110,11 +110,14 @@ static int bad_pipe_rw(struct inode * inode, struct file * filp, char * buf, int ...@@ -110,11 +110,14 @@ static int bad_pipe_rw(struct inode * inode, struct file * filp, char * buf, int
static int pipe_ioctl(struct inode *pino, struct file * filp, static int pipe_ioctl(struct inode *pino, struct file * filp,
unsigned int cmd, unsigned int arg) unsigned int cmd, unsigned int arg)
{ {
int error;
switch (cmd) { switch (cmd) {
case FIONREAD: case FIONREAD:
verify_area((void *) arg,4); error = verify_area(VERIFY_WRITE, (void *) arg,4);
put_fs_long(PIPE_SIZE(*pino),(unsigned long *) arg); if (!error)
return 0; put_fs_long(PIPE_SIZE(*pino),(unsigned long *) arg);
return error;
default: default:
return -EINVAL; return -EINVAL;
} }
...@@ -216,7 +219,9 @@ int sys_pipe(unsigned long * fildes) ...@@ -216,7 +219,9 @@ int sys_pipe(unsigned long * fildes)
int fd[2]; int fd[2];
int i,j; int i,j;
verify_area(fildes,8); j = verify_area(VERIFY_WRITE,fildes,8);
if (j)
return j;
for(j=0 ; j<2 ; j++) for(j=0 ; j<2 ; j++)
if (!(f[j] = get_empty_filp())) if (!(f[j] = get_empty_filp()))
break; break;
...@@ -246,9 +251,10 @@ int sys_pipe(unsigned long * fildes) ...@@ -246,9 +251,10 @@ int sys_pipe(unsigned long * fildes)
} }
f[0]->f_inode = f[1]->f_inode = inode; f[0]->f_inode = f[1]->f_inode = inode;
f[0]->f_pos = f[1]->f_pos = 0; f[0]->f_pos = f[1]->f_pos = 0;
f[0]->f_flags = f[1]->f_flags = 0; f[0]->f_flags = O_RDONLY;
f[0]->f_op = &read_pipe_fops; f[0]->f_op = &read_pipe_fops;
f[0]->f_mode = 1; /* read */ f[0]->f_mode = 1; /* read */
f[1]->f_flags = O_WRONLY;
f[1]->f_op = &write_pipe_fops; f[1]->f_op = &write_pipe_fops;
f[1]->f_mode = 2; /* write */ f[1]->f_mode = 2; /* write */
put_fs_long(fd[0],0+fildes); put_fs_long(fd[0],0+fildes);
......
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
#define LOAD_INT(x) ((x) >> FSHIFT) #define LOAD_INT(x) ((x) >> FSHIFT)
#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
#define KSTK_EIP(stack) (((char *)stack)[1019]) #define KSTK_EIP(stack) (((unsigned long *)stack)[1019])
#define KSTK_ESP(stack) (((char *)stack)[1022]) #define KSTK_ESP(stack) (((unsigned long *)stack)[1022])
#define _SSIZE(stack) (TASK_SIZE - KSTK_ESP(stack)) #define _SSIZE(stack) (TASK_SIZE - KSTK_ESP(stack))
#define SSIZE(stack) (KSTK_ESP(stack) ? _SSIZE(stack) : 0) #define SSIZE(stack) (KSTK_ESP(stack) ? _SSIZE(stack) : 0)
...@@ -161,7 +161,7 @@ static unsigned long get_wchan(struct task_struct *p) ...@@ -161,7 +161,7 @@ static unsigned long get_wchan(struct task_struct *p)
unsigned long stack_page; unsigned long stack_page;
int count = 0; int count = 0;
if (!p || p == current) if (!p || p == current || p->state == TASK_RUNNING)
return 0; return 0;
ebp = p->tss.ebp; ebp = p->tss.ebp;
stack_page = p->kernel_stack_page; stack_page = p->kernel_stack_page;
......
...@@ -79,7 +79,7 @@ int proc_match(int len,const char * name,struct proc_dir_entry * de) ...@@ -79,7 +79,7 @@ int proc_match(int len,const char * name,struct proc_dir_entry * de)
if (de->namelen != len) if (de->namelen != len)
return 0; return 0;
__asm__("cld\n\t" __asm__("cld\n\t"
"fs ; repe ; cmpsb\n\t" "repe ; cmpsb\n\t"
"setz %%al" "setz %%al"
:"=a" (same) :"=a" (same)
:"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len) :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
......
...@@ -70,8 +70,8 @@ static int proc_lookupfd(struct inode * dir,const char * name, int len, ...@@ -70,8 +70,8 @@ static int proc_lookupfd(struct inode * dir,const char * name, int len,
iput(dir); iput(dir);
return -ENOENT; return -ENOENT;
} }
if (!len || (get_fs_byte(name) == '.' && (len == 1 || if (!len || (name[0] == '.' && (len == 1 ||
(get_fs_byte(name+1) == '.' && len == 2)))) { (name[1] == '.' && len == 2)))) {
if (len < 2) { if (len < 2) {
*result = dir; *result = dir;
return 0; return 0;
...@@ -86,7 +86,7 @@ static int proc_lookupfd(struct inode * dir,const char * name, int len, ...@@ -86,7 +86,7 @@ static int proc_lookupfd(struct inode * dir,const char * name, int len,
iput(dir); iput(dir);
fd = 0; fd = 0;
while (len-- > 0) { while (len-- > 0) {
c = get_fs_byte(name) - '0'; c = *name - '0';
name++; name++;
if (c > 9) { if (c > 9) {
fd = 0xfffff; fd = 0xfffff;
......
...@@ -116,8 +116,7 @@ void proc_read_inode(struct inode * inode) ...@@ -116,8 +116,7 @@ void proc_read_inode(struct inode * inode)
return; return;
case 3: case 3:
inode->i_op = &proc_mem_inode_operations; inode->i_op = &proc_mem_inode_operations;
inode->i_mode = S_IFCHR | 0600; inode->i_mode = S_IFREG | 0600;
inode->i_rdev = 0x0101;
return; return;
case 4: case 4:
case 5: case 5:
......
...@@ -90,7 +90,7 @@ static int proc_lookuproot(struct inode * dir,const char * name, int len, ...@@ -90,7 +90,7 @@ static int proc_lookuproot(struct inode * dir,const char * name, int len,
} else { } else {
pid = 0; pid = 0;
while (len-- > 0) { while (len-- > 0) {
c = get_fs_byte(name) - '0'; c = *name - '0';
name++; name++;
if (c > 9) { if (c > 9) {
pid = 0; pid = 0;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -107,7 +107,7 @@ ...@@ -107,7 +107,7 @@
"movb _cache_A1,%al\n\t" \ "movb _cache_A1,%al\n\t" \
"outb %al,$0xA1\n\t" "outb %al,$0xA1\n\t"
#define IRQ_NAME2(nr) nr##_interrupt() #define IRQ_NAME2(nr) nr##_interrupt(void)
#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
#define FAST_IRQ_NAME(nr) IRQ_NAME2(fast_IRQ##nr) #define FAST_IRQ_NAME(nr) IRQ_NAME2(fast_IRQ##nr)
#define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr) #define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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