diff -u --recursive --new-file v1.1.2/linux/Configure linux/Configure --- v1.1.2/linux/Configure Mon Feb 21 20:38:30 1994 +++ linux/Configure Wed Apr 13 11:15:06 1994 @@ -11,87 +11,6 @@ # # Each line in the config file is a command. # -# # internal comment -# -# Lines beginning with a `#' are ignored. -# -# : message -# -# `:' causes the line to be echoed to the screen. -# -# * external comment -# -# `*' causes the line to be placed in the output -# configuration file as a comment as well as being -# echoed to the screen. -# -# if condition -# ... commands ... -# else -# ... commands ... -# fi -# -# This does the obvious thing. The `else' clause is -# optional. Conditionals can be nested. -# -# The `condition' can be any valid bash expression. -# They typically involve tests against environment -# variables set by configuration options. For example, -# -# if [ "$CONFIG_SCSI" = "y" ] -# ...More stuff... -# fi -# -# Note! That there is no `then' keyword. -# -# bool 'prompt' CONFIG_VARIABLE default -# -# This prompts the user for a boolean value. -# The prompt may not contain an apostrophe. -# `default' should be either `y' or `n'. -# The user's response is recorded in four places. -# -# In .config, if `y' -# CONFIG_VARIABLE = CONFIG_VARIABLE -# In .config, if `n' -# # CONFIG_VARIABLE is not set -# -# In autoconf.h, if `y' -# #define CONFIG_VARIABLE 1 -# In autoconf.h, if `n' -# #undef CONFIG_VARIABLE -# -# In config.in, if `y' -# bool 'prompt' CONFIG_VARIABLE y -# In config.in, if `n' -# bool 'prompt' CONFIG_VARIABLE n -# -# In the environment of the Configure script, if `y' -# CONFIG_VARIABLE = y -# In the environment of the Configure script, if `n' -# CONFIG_VARIABLE = n -# -# The value is placed into the environment of the Configure -# script so that later parts of config.in can use the `if' -# command to inspect the results of previous queries. -# -# int 'prompt' CONFIG_VARIABLE default -# -# This prompts the user for an integer value. -# The prompt may not contain an apostrophe. -# `default' should be an integer. -# -# The response is recorded as follows. -# -# In .config -# CONFIG_VARIABLE = response -# In autoconf.h -# #define CONFIG_VARIABLE (response) -# In config.in -# int 'prompt' CONFIG_VARIABLE response -# In the environment of the Configure script -# CONFIG_VARIABLE = response -# # 050793 - use IFS='@' to get around a bug in a pre-version of bash-1.13 # with an empty IFS. @@ -114,58 +33,85 @@ # readln prompt default # function readln () { - echo -n "$1" - IFS='@' read ans .tmpc + mv .tmpc $CONFIG_NEW + fi +} + +# +# comment does some pretty-printing +# +# comment 'xxx' +# +function comment () { + echo "*"; echo "* $1" ; echo "*" + (echo "" ; echo "#"; echo "# $1" ; echo "#") >>$CONFIG + (echo "" ; echo "/*"; echo " * $1" ; echo " */") >>$CONFIG_H } +# # bool processes a boolean argument # -# bool tail +# bool question define default # function bool () { - # Slimier hack to get bash to rescan a line. - eval "set -- $1" ans="" while [ "$ans" != "y" -a "$ans" != "n" ]; do readln "$1 ($2) [$3] " "$3" done if [ "$ans" = "y" ]; then - echo "$2 = $2" >>$CONFIG + echo " $2 = $2" >>$CONFIG echo "#define $2 1" >>$CONFIG_H else echo "# $2 is not set" >>$CONFIG - echo "#undef $2" >>$CONFIG_H + echo "#undef $2" >>$CONFIG_H fi - raw_input_line="bool '$1' $2 $ans" + change $2 $3 $ans eval "$2=$ans" } +# # int processes an integer argument # -# int tail +# int question define default # function int () { # Slimier hack to get bash to rescan a line. - eval "set -- $1" ans="x" while [ $[$ans+0] != "$ans" ]; do readln "$1 ($2) [$3] " "$3" done - echo "$2 = $ans" >>$CONFIG + echo " $2 = $ans" >>$CONFIG echo "#define $2 ($ans)" >>$CONFIG_H - raw_input_line="int '$1' $2 $ans" eval "$2=$ans" } CONFIG=.tmpconfig -CONFIG_H=include/linux/autoconf.h -trap "rm -f $CONFIG $CONFIG_H config.new ; exit 1" 1 2 +CONFIG_H=.tmpconfig.h +CONFIG_NEW=config.new +trap "rm -f $CONFIG $CONFIG_H $CONFIG_NEW ; exit 1" 1 2 # # Make sure we start out with a clean slate. # -> config.new +cp config.in $CONFIG_NEW echo "#" > $CONFIG echo "# Automatically generated make config: don't edit" >> $CONFIG echo "#" >> $CONFIG @@ -174,62 +120,16 @@ echo " * Automatically generated C config: don't edit" >> $CONFIG_H echo " */" >> $CONFIG_H -stack='' -branch='t' +DEFAULT=$1 -while IFS='@' read raw_input_line -do - # Slimy hack to get bash to rescan a line. - read cmd rest <<-END_OF_COMMAND - $raw_input_line - END_OF_COMMAND - - if [ "$cmd" = "*" ]; then - if [ "$branch" = "t" ]; then - echo "$raw_input_line" - echo "# $rest" >>$CONFIG - if [ "$prevcmd" != "*" ]; then - echo >>$CONFIG_H - echo "/* $rest" >>$CONFIG_H - else - echo " * $rest" >>$CONFIG_H - fi - prevcmd="*" - fi - else - [ "$prevcmd" = "*" ] && echo " */" >>$CONFIG_H - prevcmd="" - case "$cmd" in - :) [ "$branch" = "t" ] && echo "$raw_input_line" ;; - int) [ "$branch" = "t" ] && int "$rest" ;; - bool) [ "$branch" = "t" ] && bool "$rest" ;; - exec) [ "$branch" = "t" ] && ( sh -c "$rest" ) ;; - if) stack="$branch $stack" - if [ "$branch" = "t" ] && eval "$rest"; then - branch=t - else - branch=f - fi ;; - else) if [ "$branch" = "t" ]; then - branch=f - else - read branch rest <<-END_OF_STACK - $stack - END_OF_STACK - fi ;; - fi) [ -z "$stack" ] && echo "Error! Extra fi." 1>&2 - read branch stack <<-END_OF_STACK - $stack - END_OF_STACK - ;; - esac - fi - echo "$raw_input_line" >>config.new -done -[ "$prevcmd" = "*" ] && echo " */" >>$CONFIG_H +. ./config.in -[ -z "$stack" ] || echo "Error! Untermiated if." 1>&2 +if [ "$CONFIG_SOUND" = "y" ] ; then + $MAKE -C drivers/sound config || exit 1 +fi +mv .tmpconfig .config +mv .tmpconfig.h include/linux/autoconf.h mv config.in config.old mv config.new config.in diff -u --recursive --new-file v1.1.2/linux/Makefile linux/Makefile --- v1.1.2/linux/Makefile Wed Apr 13 11:33:50 1994 +++ linux/Makefile Wed Apr 13 11:33:02 1994 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 1 -SUBLEVEL = 2 +SUBLEVEL = 3 all: Version zImage @@ -116,12 +116,11 @@ Version: dummy rm -f tools/version.h +oldconfig: + $(CONFIG_SHELL) Configure -d $(OPTS) + config: - $(CONFIG_SHELL) Configure $(OPTS) < config.in - @if grep -s '^CONFIG_SOUND' .tmpconfig ; then \ - $(MAKE) -C drivers/sound config; \ - else : ; fi - mv .tmpconfig .config + $(CONFIG_SHELL) Configure $(OPTS) linuxsubdirs: dummy set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done diff -u --recursive --new-file v1.1.2/linux/config.in linux/config.in --- v1.1.2/linux/config.in Wed Apr 6 08:57:38 1994 +++ linux/config.in Wed Apr 13 11:28:12 1994 @@ -2,9 +2,9 @@ # For a description of the syntax of this configuration file, # see the Configure script. # -* -* General setup -* + +comment 'General setup' + bool 'Kernel math emulation' CONFIG_MATH_EMULATION y bool 'Normal harddisk support' CONFIG_BLK_DEV_HD y bool 'XT harddisk support' CONFIG_BLK_DEV_XD n @@ -12,59 +12,60 @@ bool 'Limit memory to low 16MB' CONFIG_MAX_16M n bool 'System V IPC' CONFIG_SYSVIPC y bool 'Use -m486 flag for 486-specific optimizations' CONFIG_M486 y -* -* Program binary formats -* + +comment 'Program binary formats' + bool 'Elf executables' CONFIG_BINFMT_ELF y bool 'COFF executables' CONFIG_BINFMT_COFF y -* -* SCSI support -* + +comment 'SCSI support' + bool 'SCSI support?' CONFIG_SCSI n -if [ "$CONFIG_SCSI" = "n" ] -: -: Skipping SCSI configuration options... -: + +if [ "$CONFIG_SCSI" = "n" ]; then + +comment 'Skipping SCSI configuration options...' + else - * - * SCSI support type (disk, tape, CDrom) - * + +comment 'SCSI support type (disk, tape, CDrom)' + bool 'Scsi disk support' CONFIG_BLK_DEV_SD y -bool 'Scsi tape support' CONFIG_CHR_DEV_ST y -bool 'Scsi CDROM support' CONFIG_BLK_DEV_SR y -bool 'Scsi generic support' CONFIG_CHR_DEV_SG y - * - * SCSI low-level drivers - * -bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X y +bool 'Scsi tape support' CONFIG_CHR_DEV_ST n +bool 'Scsi CDROM support' CONFIG_BLK_DEV_SR n +bool 'Scsi generic support' CONFIG_CHR_DEV_SG n + +comment 'SCSI low-level drivers' + +bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X n bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 y -bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 y -bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN y -bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 y -bool 'PAS16 SCSI support' CONFIG_SCSI_PAS16 y -bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE y -bool 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 y -bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR y -bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST y -fi -* -* Network device support -* +bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 n +bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n +bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 n +bool 'PAS16 SCSI support' CONFIG_SCSI_PAS16 n +bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE n +bool 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 n +bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR n +bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST n +fi + +comment 'Network device support' + bool 'Network device support?' CONFIG_ETHERCARDS y -if [ "$CONFIG_ETHERCARDS" = "n" ] -: -: Skipping ethercard configuration options... -: +if [ "$CONFIG_ETHERCARDS" = "n" ]; then + +comment 'Skipping ethercard configuration options...' + else bool 'SLIP (serial line) support' CONFIG_SLIP n -if [ "$CONFIG_SLIP" = "y" ] +if [ "$CONFIG_SLIP" = "y" ]; then bool ' CSLIP compressed headers' SL_COMPRESSED y # bool ' SLIP debugging on' SL_DUMP y fi #bool 'PPP (point-to-point) support' CONFIG_PPP n bool 'PLIP (parallel port) support' CONFIG_PLIP n bool 'NE2000/NE1000 support' CONFIG_NE2000 n -bool 'WD80*3 support' CONFIG_WD80x3 y +bool 'WD80E3 support' CONFIG_WD80x3 y bool 'SMC Ultra support' CONFIG_ULTRA n bool '3c501 support' CONFIG_EL1 n bool '3c503 support' CONFIG_EL2 n @@ -77,20 +78,22 @@ #bool 'Zenith Z-Note support' CONFIG_ZNET n #bool 'EtherExpress support' CONFIG_EEXPRESS n bool 'DEPCA support' CONFIG_DEPCA n -#bool 'NI52** support' CONFIG_NI52 n -#bool 'NI65** support' CONFIG_NI65 n +#bool 'NI52EE support' CONFIG_NI52 n +#bool 'NI65EE support' CONFIG_NI65 n #bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n #bool 'Cabletron E21xx support (not recommended)' CONFIG_E21 n bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n fi -* + +comment 'CD-ROM drivers' + bool 'Sony CDU31A CDROM driver support' CONFIG_CDU31A n bool 'Mitsumi CDROM driver support' CONFIG_MCD n bool 'Matsushita/Panasonic CDROM driver support' CONFIG_SBPCD n -* -* Filesystems -* + +comment 'Filesystems' + bool 'Standard (minix) fs support' CONFIG_MINIX_FS y bool 'Extended fs support' CONFIG_EXT_FS n bool 'Second extended fs support' CONFIG_EXT2_FS y @@ -101,13 +104,13 @@ bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n bool 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n -* -* character devices -* + +comment 'character devices' + bool 'Parallel printer support' CONFIG_PRINTER n bool 'Logitech busmouse support' CONFIG_BUSMOUSE n bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE y -if [ "$CONFIG_PSMOUSE" = "y" ] +if [ "$CONFIG_PSMOUSE" = "y" ]; then bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE y fi bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n @@ -115,23 +118,18 @@ bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION n bool 'QIC-02 tape support' CONFIG_TAPE_QIC02 n bool 'QIC-117 tape support' CONFIG_FTAPE n -if [ "$CONFIG_FTAPE" = "y" ] +if [ "$CONFIG_FTAPE" = "y" ]; then int ' number of ftape buffers' NR_FTAPE_BUFFERS 3 fi -* -* Sound -* + +comment 'Sound' + bool 'Sound card support' CONFIG_SOUND n -* -* Kernel hacking -* + +comment 'Kernel hacking' + #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n bool 'Kernel profiling support' CONFIG_PROFILE n -if [ "$CONFIG_SCSI" = "y" ] +if [ "$CONFIG_SCSI" = "y" ]; then bool 'Verbose scsi error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS y -fi -if [ "$CONFIG_SOUND" = "y" ] - exec touch .makesound -else - exec rm -f .makesound fi diff -u --recursive --new-file v1.1.2/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v1.1.2/linux/drivers/block/ll_rw_blk.c Tue Feb 1 09:03:51 1994 +++ linux/drivers/block/ll_rw_blk.c Wed Apr 13 11:35:38 1994 @@ -156,7 +156,7 @@ req->next = NULL; cli(); if (req->bh) - req->bh->b_dirt = 0; + mark_buffer_clean(req->bh); if (!(tmp = dev->current_request)) { dev->current_request = req; (dev->request_fn)(); @@ -240,12 +240,12 @@ !req->waiting && req->cmd == rw && req->sector + req->nr_sectors == sector && - req->nr_sectors < 254) + req->nr_sectors < 244) { req->bhtail->b_reqnext = bh; req->bhtail = bh; req->nr_sectors += count; - bh->b_dirt = 0; + mark_buffer_clean(bh); sti(); return; } @@ -254,14 +254,14 @@ !req->waiting && req->cmd == rw && req->sector - count == sector && - req->nr_sectors < 254) + req->nr_sectors < 244) { req->nr_sectors += count; bh->b_reqnext = req->bh; req->buffer = bh->b_data; req->current_nr_sectors = count; req->sector = sector; - bh->b_dirt = 0; + mark_buffer_clean(bh); req->bh = bh; sti(); return; diff -u --recursive --new-file v1.1.2/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c --- v1.1.2/linux/drivers/scsi/fdomain.c Thu Apr 7 11:57:31 1994 +++ linux/drivers/scsi/fdomain.c Tue Apr 12 06:33:14 1994 @@ -1,10 +1,10 @@ /* fdomain.c -- Future Domain TMC-16x0 SCSI driver * Created: Sun May 3 18:53:19 1992 by faith@cs.unc.edu - * Revised: Fri Apr 1 23:47:55 1994 by faith@cs.unc.edu + * Revised: Thu Apr 7 20:30:09 1994 by faith@cs.unc.edu * Author: Rickard E. Faith, faith@cs.unc.edu * Copyright 1992, 1993, 1994 Rickard E. Faith * - * $Id: fdomain.c,v 5.15 1994/04/02 04:48:04 root Exp $ + * $Id: fdomain.c,v 5.16 1994/04/08 00:30:15 root Exp $ * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -168,7 +168,7 @@ #include #include -#define VERSION "$Revision: 5.15 $" +#define VERSION "$Revision: 5.16 $" /* START OF USER DEFINABLE OPTIONS */ @@ -282,6 +282,9 @@ static int Write_FIFO_port; static int Write_SCSI_Data_port; +static int FIFO_Size = 0x2000; /* 8k FIFO for + pre-tmc18c30 chips */ + extern void fdomain_16x0_intr( int unused ); static void *addresses[] = { @@ -421,7 +424,10 @@ outb( 0x80, port + IO_Control ); if (inb( port + Configuration2 ) & 0x80 == 0x80) { outb( 0x00, port + IO_Control ); - if (inb( port + Configuration2 ) & 0x80 == 0x00) chip = tmc18c30; + if (inb( port + Configuration2 ) & 0x80 == 0x00) { + chip = tmc18c30; + FIFO_Size = 0x800; /* 2k FIFO */ + } } #else @@ -429,7 +435,10 @@ have problems. Lets assume it is an 18c30 if the RAM is disabled. */ - if (inb( port + Configuration2 ) & 0x02) chip = tmc18c30; + if (inb( port + Configuration2 ) & 0x02) { + chip = tmc18c30; + FIFO_Size = 0x800; /* 2k FIFO */ + } #endif /* If that failed, we are an 18c50. */ } @@ -1127,7 +1136,7 @@ } if (current_SC->SCp.have_data_in == -1) { /* DATA OUT */ - while ( (data_count = 0x2000 - inw( FIFO_Data_Count_port )) > 512 ) { + while ( (data_count = FIFO_Size - inw( FIFO_Data_Count_port )) > 512 ) { #if EVERY_ACCESS printk( "DC=%d, ", data_count ) ; #endif diff -u --recursive --new-file v1.1.2/linux/fs/block_dev.c linux/fs/block_dev.c --- v1.1.2/linux/fs/block_dev.c Wed Apr 13 11:33:53 1994 +++ linux/fs/block_dev.c Wed Apr 13 11:26:14 1994 @@ -14,13 +14,18 @@ extern int *blk_size[]; extern int *blksize_size[]; +#define NBUF 64 + int block_write(struct inode * inode, struct file * filp, char * buf, int count) { - int blocksize, blocksize_bits, i; - int block; + int blocksize, blocksize_bits, i, j; + int block, blocks; int offset; int chars; int written = 0; + int cluster_list[4]; + struct buffer_head * bhlist[NBUF]; + int blocks_per_cluster; unsigned int size; unsigned int dev; struct buffer_head * bh; @@ -38,6 +43,8 @@ i >>= 1; } + blocks_per_cluster = PAGE_SIZE / blocksize; + block = filp->f_pos >> blocksize_bits; offset = filp->f_pos & (blocksize-1); @@ -51,11 +58,50 @@ chars = blocksize - offset; if (chars > count) chars=count; + +#if 0 if (chars == blocksize) bh = getblk(dev, block, blocksize); else - bh = breada(dev, block, blocksize, offset, - size << blocksize_bits); + bh = breada(dev,block,block+1,block+2,-1); + +#else + for(i=0; ib_uptodate) { + if(!filp->f_reada || + !read_ahead[MAJOR(dev)]) { + /* We do this to force the read of a single buffer */ + brelse(bh); + bh = bread(dev,block,blocksize); + } else { + /* Read-ahead before write */ + blocks = read_ahead[MAJOR(dev)] / (blocksize >> 9) / 2; + if (block + blocks > size) blocks = size - block; + if (blocks > NBUF) blocks=NBUF; + blocks -= (block % blocks_per_cluster); + if(!blocks) blocks = 1; + bhlist[0] = bh; + for(i=1; i= 0) brelse(bhlist[i--]); + return written? written: -EIO; + }; + }; + ll_rw_block(READ, blocks, bhlist); + for(i=1; ib_uptodate = 1; - dirtify_buffer(bh, 0); + mark_buffer_dirty(bh, 0); brelse(bh); } + filp->f_reada = 1; return written; } -#define NBUF 32 - int block_read(struct inode * inode, struct file * filp, char * buf, int count) { unsigned int block; unsigned int offset; int blocksize; int blocksize_bits, i; - unsigned int left; - unsigned int blocks; + unsigned int blocks, rblocks, left; int bhrequest, uptodate; + int cluster_list[4]; + int blocks_per_cluster; struct buffer_head ** bhb, ** bhe; struct buffer_head * buflist[NBUF]; struct buffer_head * bhreq[NBUF]; @@ -110,6 +156,8 @@ else size = INT_MAX; + blocks_per_cluster = PAGE_SIZE / blocksize; + if (offset > size) left = 0; else @@ -122,12 +170,16 @@ block = offset >> blocksize_bits; offset &= blocksize-1; size >>= blocksize_bits; - blocks = (left + offset + blocksize - 1) >> blocksize_bits; + rblocks = blocks = (left + offset + blocksize - 1) >> blocksize_bits; bhb = bhe = buflist; if (filp->f_reada) { - blocks += read_ahead[MAJOR(dev)] / (blocksize >> 9); + if(blocks < read_ahead[MAJOR(dev)] / (blocksize >> 9)) + blocks = read_ahead[MAJOR(dev)] / (blocksize >> 9); if (block + blocks > size) blocks = size - block; + blocks -= (block % blocks_per_cluster); + if(rblocks > blocks) blocks = rblocks; + } /* We do this in a two stage process. We first try and request @@ -145,6 +197,12 @@ uptodate = 1; while (blocks) { --blocks; +#if 1 + if((block % blocks_per_cluster) == 0) { + for(i=0; ib_uptodate) { uptodate = 0; @@ -163,8 +221,10 @@ } /* Now request them all */ - if (bhrequest) + if (bhrequest) { ll_rw_block(READ, bhrequest, bhreq); + refill_freelist(blocksize); + } do { /* Finish off all I/O that has actually completed */ if (*bhe) { diff -u --recursive --new-file v1.1.2/linux/fs/buffer.c linux/fs/buffer.c --- v1.1.2/linux/fs/buffer.c Wed Apr 13 11:33:53 1994 +++ linux/fs/buffer.c Wed Apr 13 11:24:06 1994 @@ -26,8 +26,10 @@ #include #include #include +#include #include +#include #include #ifdef CONFIG_SCSI @@ -46,23 +48,76 @@ extern int check_mcd_media_change(int, int); #endif +#define NR_SIZES 4 static char buffersize_index[9] = {-1, 0, 1, -1, 2, -1, -1, -1, 3}; +static short int bufferindex_size[NR_SIZES] = {512, 1024, 2048, 4096}; #define BUFSIZE_INDEX(X) (buffersize_index[(X)>>9]) static int grow_buffers(int pri, int size); +static int shrink_specific_buffers(unsigned int priority, int size); +static int maybe_shrink_lav_buffers(int); -static struct buffer_head * hash_table[NR_HASH]; -static struct buffer_head * free_list = NULL; +static int nr_hash = 0; /* Size of hash table */ +static struct buffer_head ** hash_table; +struct buffer_head ** buffer_pages; +static struct buffer_head * lru_list[NR_LIST] = {NULL, }; +static struct buffer_head * free_list[NR_SIZES] = {NULL, }; static struct buffer_head * unused_list = NULL; static struct wait_queue * buffer_wait = NULL; int nr_buffers = 0; +int nr_buffers_type[NR_LIST] = {0,}; +int nr_buffers_size[NR_SIZES] = {0,}; +int nr_buffers_st[NR_SIZES][NR_LIST] = {{0,},}; +int buffer_usage[NR_SIZES] = {0,}; /* Usage counts used to determine load average */ +int buffers_lav[NR_SIZES] = {0,}; /* Load average of buffer usage */ +int nr_free[NR_SIZES] = {0,}; int buffermem = 0; int nr_buffer_heads = 0; static int min_free_pages = 20; /* nr free pages needed before buffer grows */ extern int *blksize_size[]; +/* Here is the parameter block for the bdflush process. */ +static void wakeup_bdflush(int); + +#define N_PARAM 9 +#define LAV + +static union bdflush_param{ + struct { + int nfract; /* Percentage of buffer cache dirty to + activate bdflush */ + int ndirty; /* Maximum number of dirty blocks to write out per + wake-cycle */ + int nrefill; /* Number of clean buffers to try and obtain + each time we call refill */ + int nref_dirt; /* Dirty buffer threshold for activating bdflush + when trying to refill buffers. */ + int clu_nfract; /* Percentage of buffer cache to scan to + search for free clusters */ + int age_buffer; /* Time for normal buffer to age before + we flush it */ + int age_super; /* Time for superblock to age before we + flush it */ + int lav_const; /* Constant used for load average (time + constant */ + int lav_ratio; /* Used to determine how low a lav for a + particular size can go before we start to + trim back the buffers */ + } b_un; + unsigned int data[N_PARAM]; +} bdf_prm = {{25, 500, 64, 256, 15, 3000, 500, 1884, 2}}; + +/* The lav constant is set for 1 minute, as long as the update process runs + every 5 seconds. If you change the frequency of update, the time + constant will also change. */ + + +/* These are the min and max parameter values that we will allow to be assigned */ +static int bdflush_min[N_PARAM] = { 0, 10, 5, 25, 0, 100, 100, 1, 1}; +static int bdflush_max[N_PARAM] = {100,5000, 2000, 2000,100, 60000, 60000, 2047, 5}; + /* * Rewrote the wait-routines to use the "new" wait-queue functionality, * and getting rid of the cli-sti pairs. The wait-queue routines still @@ -93,61 +148,81 @@ return until all buffer writes have completed. Sync() may return before the writes have finished; fsync() may not. */ + +/* Godamity-damn. Some buffers (bitmaps for filesystems) + spontaneously dirty themselves without ever brelse being called. + We will ultimately want to put these in a separate list, but for + now we search all of the lists for dirty buffers */ + static int sync_buffers(dev_t dev, int wait) { int i, retry, pass = 0, err = 0; - struct buffer_head * bh; + int nlist, ncount; + struct buffer_head * bh, *next; /* One pass for no-wait, three for wait: 0) write out all dirty, unlocked buffers; 1) write out all dirty buffers, waiting if locked; - 2) wait for completion by waiting for all buffers to unlock. - */ -repeat: + 2) wait for completion by waiting for all buffers to unlock. */ + repeat: retry = 0; - bh = free_list; - for (i = nr_buffers*2 ; i-- > 0 ; bh = bh->b_next_free) { - if (dev && bh->b_dev != dev) - continue; -#ifdef 0 /* Disable bad-block debugging code */ - if (bh->b_req && !bh->b_lock && - !bh->b_dirt && !bh->b_uptodate) - printk ("Warning (IO error) - orphaned block %08x on %04x\n", - bh->b_blocknr, bh->b_dev); -#endif - if (bh->b_lock) - { - /* Buffer is locked; skip it unless wait is - requested AND pass > 0. */ - if (!wait || !pass) { - retry = 1; - continue; - } - wait_on_buffer (bh); - } - /* If an unlocked buffer is not uptodate, there has been - an IO error. Skip it. */ - if (wait && bh->b_req && !bh->b_lock && - !bh->b_dirt && !bh->b_uptodate) - { - err = 1; - continue; - } - /* Don't write clean buffers. Don't write ANY buffers - on the third pass. */ - if (!bh->b_dirt || pass>=2) - continue; - bh->b_count++; - ll_rw_block(WRITE, 1, &bh); - bh->b_count--; - retry = 1; - } + ncount = 0; + /* We search all lists as a failsafe mechanism, not because we expect + there to be dirty buffers on any of the other lists. */ + for(nlist = 0; nlist < NR_LIST; nlist++) + { + repeat1: + bh = lru_list[nlist]; + if(!bh) continue; + for (i = nr_buffers_type[nlist]*2 ; i-- > 0 ; bh = next) { + if(bh->b_list != nlist) goto repeat1; + next = bh->b_next_free; + if(!lru_list[nlist]) break; + if (dev && bh->b_dev != dev) + continue; + if (bh->b_lock) + { + /* Buffer is locked; skip it unless wait is + requested AND pass > 0. */ + if (!wait || !pass) { + retry = 1; + continue; + } + wait_on_buffer (bh); + } + /* If an unlocked buffer is not uptodate, there has + been an IO error. Skip it. */ + if (wait && bh->b_req && !bh->b_lock && + !bh->b_dirt && !bh->b_uptodate) + { + err = 1; + printk("Weird - unlocked, clean and not uptodate buffer on %d list %d\n", nlist); + continue; + } + /* Don't write clean buffers. Don't write ANY buffers + on the third pass. */ + if (!bh->b_dirt || pass>=2) + continue; + bh->b_count++; + bh->b_flushtime = 0; + ll_rw_block(WRITE, 1, &bh); + + if(nlist != BUF_DIRTY) { + printk("[%d %x %d] ", nlist, bh->b_dev, bh->b_blocknr); + ncount++; + }; + bh->b_count--; + retry = 1; + } + } + if (ncount) printk("sys_sync: %d dirty buffers not on dirty list\n", ncount); + /* If we are waiting for the sync to succeed, and if any dirty blocks were written, then repeat; on the second pass, only wait for buffers being written (do not pass to write any more buffers on the second pass). */ if (wait && retry && ++pass<=2) - goto repeat; + goto repeat; return err; } @@ -195,15 +270,20 @@ void invalidate_buffers(dev_t dev) { int i; + int nlist; struct buffer_head * bh; - bh = free_list; - for (i = nr_buffers*2 ; --i > 0 ; bh = bh->b_next_free) { - if (bh->b_dev != dev) - continue; - wait_on_buffer(bh); - if (bh->b_dev == dev) - bh->b_uptodate = bh->b_dirt = bh->b_req = 0; + for(nlist = 0; nlist < NR_LIST; nlist++) { + bh = lru_list[nlist]; + for (i = nr_buffers_type[nlist]*2 ; --i > 0 ; + bh = bh->b_next_free) { + if (bh->b_dev != dev) + continue; + wait_on_buffer(bh); + if (bh->b_dev == dev) + bh->b_flushtime = bh->b_uptodate = + bh->b_dirt = bh->b_req = 0; + } } } @@ -280,7 +360,7 @@ #endif } -#define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH) +#define _hashfn(dev,block) (((unsigned)(dev^block))%nr_hash) #define hash(dev,block) hash_table[_hashfn(dev,block)] static inline void remove_from_hash_queue(struct buffer_head * bh) @@ -294,59 +374,118 @@ bh->b_next = bh->b_prev = NULL; } -static inline void remove_from_free_list(struct buffer_head * bh) +static inline void remove_from_lru_list(struct buffer_head * bh) { if (!(bh->b_prev_free) || !(bh->b_next_free)) - panic("VFS: Free block list corrupted"); + panic("VFS: LRU block list corrupted"); + if (bh->b_dev == 0xffff) panic("LRU list corrupted"); bh->b_prev_free->b_next_free = bh->b_next_free; bh->b_next_free->b_prev_free = bh->b_prev_free; - if (free_list == bh) - free_list = bh->b_next_free; + + if (lru_list[bh->b_list] == bh) + lru_list[bh->b_list] = bh->b_next_free; + if(lru_list[bh->b_list] == bh) + lru_list[bh->b_list] = NULL; + bh->b_next_free = bh->b_prev_free = NULL; +} + +static inline void remove_from_free_list(struct buffer_head * bh) +{ + int isize = BUFSIZE_INDEX(bh->b_size); + if (!(bh->b_prev_free) || !(bh->b_next_free)) + panic("VFS: Free block list corrupted"); + if(bh->b_dev != 0xffff) panic("Free list corrupted"); + if(!free_list[isize]) + panic("Free list empty"); + nr_free[isize]--; + if(bh->b_next_free == bh) + free_list[isize] = NULL; + else { + bh->b_prev_free->b_next_free = bh->b_next_free; + bh->b_next_free->b_prev_free = bh->b_prev_free; + if (free_list[isize] == bh) + free_list[isize] = bh->b_next_free; + }; bh->b_next_free = bh->b_prev_free = NULL; } static inline void remove_from_queues(struct buffer_head * bh) { + if(bh->b_dev == 0xffff) { + remove_from_free_list(bh); /* Free list entries should not be + in the hash queue */ + return; + }; + nr_buffers_type[bh->b_list]--; + nr_buffers_st[BUFSIZE_INDEX(bh->b_size)][bh->b_list]--; remove_from_hash_queue(bh); - remove_from_free_list(bh); + remove_from_lru_list(bh); } -static inline void put_first_free(struct buffer_head * bh) +static inline void put_last_lru(struct buffer_head * bh) { - if (!bh || (bh == free_list)) + if (!bh) return; - remove_from_free_list(bh); -/* add to front of free list */ - bh->b_next_free = free_list; - bh->b_prev_free = free_list->b_prev_free; - free_list->b_prev_free->b_next_free = bh; - free_list->b_prev_free = bh; - free_list = bh; + if (bh == lru_list[bh->b_list]) { + lru_list[bh->b_list] = bh->b_next_free; + return; + } + if(bh->b_dev == 0xffff) panic("Wrong block for lru list"); + remove_from_lru_list(bh); +/* add to back of free list */ + + if(!lru_list[bh->b_list]) { + lru_list[bh->b_list] = bh; + lru_list[bh->b_list]->b_prev_free = bh; + }; + + bh->b_next_free = lru_list[bh->b_list]; + bh->b_prev_free = lru_list[bh->b_list]->b_prev_free; + lru_list[bh->b_list]->b_prev_free->b_next_free = bh; + lru_list[bh->b_list]->b_prev_free = bh; } static inline void put_last_free(struct buffer_head * bh) { + int isize; if (!bh) return; - if (bh == free_list) { - free_list = bh->b_next_free; - return; - } - remove_from_free_list(bh); + + isize = BUFSIZE_INDEX(bh->b_size); + bh->b_dev = 0xffff; /* So it is obvious we are on the free list */ /* add to back of free list */ - bh->b_next_free = free_list; - bh->b_prev_free = free_list->b_prev_free; - free_list->b_prev_free->b_next_free = bh; - free_list->b_prev_free = bh; + + if(!free_list[isize]) { + free_list[isize] = bh; + bh->b_prev_free = bh; + }; + + nr_free[isize]++; + bh->b_next_free = free_list[isize]; + bh->b_prev_free = free_list[isize]->b_prev_free; + free_list[isize]->b_prev_free->b_next_free = bh; + free_list[isize]->b_prev_free = bh; } static inline void insert_into_queues(struct buffer_head * bh) { /* put at end of free list */ - bh->b_next_free = free_list; - bh->b_prev_free = free_list->b_prev_free; - free_list->b_prev_free->b_next_free = bh; - free_list->b_prev_free = bh; + + if(bh->b_dev == 0xffff) { + put_last_free(bh); + return; + }; + if(!lru_list[bh->b_list]) { + lru_list[bh->b_list] = bh; + bh->b_prev_free = bh; + }; + if (bh->b_next_free) panic("VFS: buffer LRU pointers corrupted"); + bh->b_next_free = lru_list[bh->b_list]; + bh->b_prev_free = lru_list[bh->b_list]->b_prev_free; + lru_list[bh->b_list]->b_prev_free->b_next_free = bh; + lru_list[bh->b_list]->b_prev_free = bh; + nr_buffers_type[bh->b_list]++; + nr_buffers_st[BUFSIZE_INDEX(bh->b_size)][bh->b_list]++; /* put the buffer in new hash-queue if it has a device */ bh->b_prev = NULL; bh->b_next = NULL; @@ -398,7 +537,7 @@ void set_blocksize(dev_t dev, int size) { - int i; + int i, nlist; struct buffer_head * bh, *bhnext; if (!blksize_size[MAJOR(dev)]) @@ -421,20 +560,206 @@ /* We need to be quite careful how we do this - we are moving entries around on the free list, and we can get in a loop if we are not careful.*/ - bh = free_list; - for (i = nr_buffers*2 ; --i > 0 ; bh = bhnext) { - bhnext = bh->b_next_free; - if (bh->b_dev != dev) - continue; - if (bh->b_size == size) - continue; + for(nlist = 0; nlist < NR_LIST; nlist++) { + bh = lru_list[nlist]; + for (i = nr_buffers_type[nlist]*2 ; --i > 0 ; bh = bhnext) { + if(!bh) break; + bhnext = bh->b_next_free; + if (bh->b_dev != dev) + continue; + if (bh->b_size == size) + continue; + + wait_on_buffer(bh); + if (bh->b_dev == dev && bh->b_size != size) { + bh->b_uptodate = bh->b_dirt = + bh->b_flushtime = 0; + }; + remove_from_hash_queue(bh); + } + } +} - wait_on_buffer(bh); - if (bh->b_dev == dev && bh->b_size != size) - bh->b_uptodate = bh->b_dirt = 0; - remove_from_hash_queue(bh); -/* put_first_free(bh); */ +#define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock) + +void refill_freelist(int size) +{ + struct buffer_head * bh, * tmp; + struct buffer_head * candidate[NR_LIST]; + unsigned int best_time, winner; + int isize = BUFSIZE_INDEX(size); + int buffers[NR_LIST]; + int i; + int needed; + + /* First see if we even need this. Sometimes it is advantageous + to request some blocks in a filesystem that we know that we will + be needing ahead of time. */ + + if(nr_free[isize] > 100) return 0; + + /* If there are too many dirty buffers, we wake up the update process + now so as to ensure that there are still clean buffers available + for user processes to use (and dirty) */ + + /* We are going to try and locate this much memory */ + needed =bdf_prm.b_un.nrefill * size; + + while (nr_free_pages > min_free_pages && needed > 0 && + grow_buffers(GFP_BUFFER, size)) { + needed -= PAGE_SIZE; + } + + if(needed <= 0) return; + + /* See if there are too many buffers of a different size. + If so, victimize them */ + + while(maybe_shrink_lav_buffers(size)) + { + if(!grow_buffers(GFP_BUFFER, size)) break; + needed -= PAGE_SIZE; + if(needed <= 0) return; + }; + + /* OK, we cannot grow the buffer cache, now try and get some + from the lru list */ + + /* First set the candidate pointers to usable buffers. This + should be quick nearly all of the time. */ + +repeat0: + for(i=0; i 0; bh = tmp, buffers[i]--) + { + if(buffers[i] < 0) panic("Here is the problem"); + tmp = bh->b_next_free; + if (!bh) break; + + if (mem_map[MAP_NR((unsigned long) bh->b_data)] != 1 || + bh->b_dirt) { + refile_buffer(bh); + continue; + }; + + if (bh->b_count || bh->b_size != size) + continue; + + /* Buffers are written in the order they are placed + on the locked list. If we encounter a locked + buffer here, this means that the rest of them + are also locked */ + if(bh->b_lock && (i == BUF_LOCKED || i == BUF_LOCKED1)) { + buffers[i] = 0; + break; + } + + if (BADNESS(bh)) continue; + break; + }; + if(!buffers[i]) candidate[i] = NULL; /* Nothing on this list */ + else candidate[i] = bh; + if(candidate[i] && candidate[i]->b_count) panic("Here is the problem"); + } + + repeat: + if(needed <= 0) return; + + /* Now see which candidate wins the election */ + + winner = best_time = UINT_MAX; + for(i=0; ib_lru_time < best_time){ + best_time = candidate[i]->b_lru_time; + winner = i; + } + } + + /* If we have a winner, use it, and then get a new candidate from that list */ + if(winner != UINT_MAX) { + i = winner; + bh = candidate[i]; + candidate[i] = bh->b_next_free; + if(candidate[i] == bh) candidate[i] = NULL; /* Got last one */ + if (bh->b_count || bh->b_size != size) + panic("Busy buffer in candidate list\n"); + if (mem_map[MAP_NR((unsigned long) bh->b_data)] != 1) + panic("Shared buffer in candidate list\n"); + if (BADNESS(bh)) panic("Buffer in candidate list with BADNESS != 0\n"); + + if(bh->b_dev == 0xffff) panic("Wrong list"); + remove_from_queues(bh); + bh->b_dev = 0xffff; + put_last_free(bh); + needed -= bh->b_size; + buffers[i]--; + if(buffers[i] < 0) panic("Here is the problem"); + + if(buffers[i] == 0) candidate[i] = NULL; + + /* Now all we need to do is advance the candidate pointer + from the winner list to the next usable buffer */ + if(candidate[i] && buffers[i] > 0){ + if(buffers[i] <= 0) panic("Here is another problem"); + for (bh = candidate[i]; buffers[i] > 0; bh = tmp, buffers[i]--) { + if(buffers[i] < 0) panic("Here is the problem"); + tmp = bh->b_next_free; + if (!bh) break; + + if (mem_map[MAP_NR((unsigned long) bh->b_data)] != 1 || + bh->b_dirt) { + refile_buffer(bh); + continue; + }; + + if (bh->b_count || bh->b_size != size) + continue; + + /* Buffers are written in the order they are + placed on the locked list. If we encounter + a locked buffer here, this means that the + rest of them are also locked */ + if(bh->b_lock && (i == BUF_LOCKED || i == BUF_LOCKED1)) { + buffers[i] = 0; + break; + } + + if (BADNESS(bh)) continue; + break; + }; + if(!buffers[i]) candidate[i] = NULL; /* Nothing here */ + else candidate[i] = bh; + if(candidate[i] && candidate[i]->b_count) + panic("Here is the problem"); + } + + goto repeat; + } + + if(needed <= 0) return; + + /* Too bad, that was not enough. Try a little harder to grow some. */ + + if (nr_free_pages > 5) { + if (grow_buffers(GFP_BUFFER, size)) { + needed -= PAGE_SIZE; + goto repeat0; + }; } + + /* and repeat until we find something good */ + if (!grow_buffers(GFP_ATOMIC, size)) + wakeup_bdflush(1); + needed -= PAGE_SIZE; + goto repeat0; } /* @@ -447,85 +772,105 @@ * 14.02.92: changed it to sync dirty buffers a bit: better performance * when the filesystem starts to get full of dirty blocks (I hope). */ -#define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock) struct buffer_head * getblk(dev_t dev, int block, int size) { - struct buffer_head * bh, * tmp; - int buffers; - static int grow_size = 0; + struct buffer_head * bh; + int isize = BUFSIZE_INDEX(size); + + /* Update this for the buffer size lav. */ + buffer_usage[isize]++; + /* If there are too many dirty buffers, we wake up the update process + now so as to ensure that there are still clean buffers available + for user processes to use (and dirty) */ repeat: bh = get_hash_table(dev, block, size); if (bh) { if (bh->b_uptodate && !bh->b_dirt) - put_last_free(bh); + put_last_lru(bh); + if(!bh->b_dirt) bh->b_flushtime = 0; return bh; } - grow_size -= size; - if (nr_free_pages > min_free_pages && grow_size <= 0) { - if (grow_buffers(GFP_BUFFER, size)) - grow_size = PAGE_SIZE; - } - buffers = nr_buffers; - bh = NULL; - for (tmp = free_list; buffers-- > 0 ; tmp = tmp->b_next_free) { - if (tmp->b_count || tmp->b_size != size) - continue; - if (mem_map[MAP_NR((unsigned long) tmp->b_data)] != 1) - continue; - if (!bh || BADNESS(tmp)b_dirt) { - tmp->b_count++; - ll_rw_block(WRITEA, 1, &tmp); - tmp->b_count--; - } -#endif - } + while(!free_list[isize]) refill_freelist(size); + + if (find_buffer(dev,block,size)) + goto repeat; - if (!bh) { - if (nr_free_pages > 5) - if (grow_buffers(GFP_BUFFER, size)) - goto repeat; - if (!grow_buffers(GFP_ATOMIC, size)) - sleep_on(&buffer_wait); - goto repeat; - } + bh = free_list[isize]; + remove_from_free_list(bh); - wait_on_buffer(bh); - if (bh->b_count || bh->b_size != size) - goto repeat; - if (bh->b_dirt) { - sync_buffers(0,0); - goto repeat; - } -/* NOTE!! While we slept waiting for this block, somebody else might */ -/* already have added "this" block to the cache. check it */ - if (find_buffer(dev,block,size)) - goto repeat; -/* OK, FINALLY we know that this buffer is the only one of its kind, */ +/* OK, FINALLY we know that this buffer is the only one of it's kind, */ /* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */ bh->b_count=1; bh->b_dirt=0; + bh->b_lock=0; bh->b_uptodate=0; + bh->b_flushtime = 0; bh->b_req=0; - remove_from_queues(bh); bh->b_dev=dev; bh->b_blocknr=block; insert_into_queues(bh); return bh; } +void set_writetime(struct buffer_head * buf, int flag) +{ + int newtime; + + if (buf->b_dirt){ + /* Move buffer to dirty list if jiffies is clear */ + newtime = jiffies + (flag ? bdf_prm.b_un.age_super : + bdf_prm.b_un.age_buffer); + if(!buf->b_flushtime || buf->b_flushtime > newtime) + buf->b_flushtime = newtime; + } else { + buf->b_flushtime = 0; + } +} + + +static char buffer_disposition[] = {BUF_CLEAN, BUF_SHARED, BUF_LOCKED, BUF_SHARED, + BUF_DIRTY, BUF_DIRTY, BUF_DIRTY, BUF_DIRTY}; + +void refile_buffer(struct buffer_head * buf){ + int i, dispose; + i = 0; + if(buf->b_dev == 0xffff) panic("Attempt to refile free buffer\n"); + if(mem_map[MAP_NR((unsigned long) buf->b_data)] != 1) i = 1; + if(buf->b_lock) i |= 2; + if(buf->b_dirt) i |= 4; + dispose = buffer_disposition[i]; + if(buf->b_list == BUF_SHARED && dispose == BUF_CLEAN) + dispose = BUF_UNSHARED; + if(dispose == -1) panic("Bad buffer settings (%d)\n", i); + if(dispose == BUF_CLEAN) buf->b_lru_time = jiffies; + if(dispose != buf->b_list) { + if(dispose == BUF_DIRTY || dispose == BUF_UNSHARED) + buf->b_lru_time = jiffies; + if(dispose == BUF_LOCKED && + (buf->b_flushtime - buf->b_lru_time) <= bdf_prm.b_un.age_super) + dispose = BUF_LOCKED1; + remove_from_queues(buf); + buf->b_list = dispose; + insert_into_queues(buf); + if(dispose == BUF_DIRTY && nr_buffers_type[BUF_DIRTY] > + (nr_buffers - nr_buffers_type[BUF_SHARED]) * + bdf_prm.b_un.nfract/100) + wakeup_bdflush(0); + } +} + void brelse(struct buffer_head * buf) { if (!buf) return; wait_on_buffer(buf); + + /* If dirty, mark the time this buffer should be written back */ + set_writetime(buf, 0); + refile_buffer(buf); + if (buf->b_count) { if (--buf->b_count) return; @@ -560,7 +905,8 @@ /* * Ok, breada can be used as bread, but additionally to mark other - * blocks for reading as well. + * blocks for reading as well. End the argument list with a negative + * number. */ #define NBUF 16 @@ -686,6 +1032,7 @@ head = bh; bh->b_data = (char *) (page+offset); bh->b_size = size; + bh->b_dev = 0xffff; /* Flag as unused */ } return head; /* @@ -766,6 +1113,7 @@ { struct buffer_head * bh, * tmp, * arr[8]; unsigned long offset; + int isize = BUFSIZE_INDEX(size); int * p; int block; @@ -788,10 +1136,14 @@ arr[block++] = bh; bh->b_count = 1; bh->b_dirt = 0; + bh->b_flushtime = 0; bh->b_uptodate = 0; + bh->b_req = 0; bh->b_dev = dev; bh->b_blocknr = *(p++); + bh->b_list = BUF_CLEAN; nr_buffers++; + nr_buffers_size[isize]++; insert_into_queues(bh); if (bh->b_this_page) bh = bh->b_this_page; @@ -801,6 +1153,7 @@ buffermem += PAGE_SIZE; bh->b_this_page = tmp; mem_map[MAP_NR(address)]++; + buffer_pages[address >> PAGE_SHIFT] = bh; read_buffers(arr,block); while (block-- > 0) brelse(arr[block]); @@ -889,11 +1242,16 @@ { unsigned long page; struct buffer_head *bh, *tmp; + struct buffer_head * insert_point; + int isize; if ((size & 511) || (size > PAGE_SIZE)) { printk("VFS: grow_buffers: size = %d\n",size); return 0; } + + isize = BUFSIZE_INDEX(size); + if (!(page = __get_free_page(pri))) return 0; bh = create_buffers(page, size); @@ -901,25 +1259,32 @@ free_page(page); return 0; } + + insert_point = free_list[isize]; + tmp = bh; while (1) { - if (free_list) { - tmp->b_next_free = free_list; - tmp->b_prev_free = free_list->b_prev_free; - free_list->b_prev_free->b_next_free = tmp; - free_list->b_prev_free = tmp; + nr_free[isize]++; + if (insert_point) { + tmp->b_next_free = insert_point->b_next_free; + tmp->b_prev_free = insert_point; + insert_point->b_next_free->b_prev_free = tmp; + insert_point->b_next_free = tmp; } else { tmp->b_prev_free = tmp; tmp->b_next_free = tmp; } - free_list = tmp; + insert_point = tmp; ++nr_buffers; if (tmp->b_this_page) tmp = tmp->b_this_page; else break; } + free_list[isize] = bh; + buffer_pages[page >> PAGE_SHIFT] = bh; tmp->b_this_page = bh; + wake_up(&buffer_wait); buffermem += PAGE_SIZE; return 1; } @@ -932,6 +1297,7 @@ { unsigned long page; struct buffer_head * tmp, * p; + int isize = BUFSIZE_INDEX(bh->b_size); *bhp = bh; page = (unsigned long) bh->b_data; @@ -949,16 +1315,72 @@ p = tmp; tmp = tmp->b_this_page; nr_buffers--; + nr_buffers_size[isize]--; if (p == *bhp) - *bhp = p->b_prev_free; + { + *bhp = p->b_prev_free; + if (p == *bhp) /* Was this the last in the list? */ + *bhp = NULL; + } remove_from_queues(p); put_unused_buffer_head(p); } while (tmp != bh); buffermem -= PAGE_SIZE; + buffer_pages[page >> PAGE_SHIFT] = NULL; free_page(page); return !mem_map[MAP_NR(page)]; } + +/* + * Consult the load average for buffers and decide whether or not + * we should shrink the buffers of one size or not. If we decide yes, + * do it and return 1. Else return 0. Do not attempt to shrink size + * that is specified. + * + * I would prefer not to use a load average, but the way things are now it + * seems unavoidable. The way to get rid of it would be to force clustering + * universally, so that when we reclaim buffers we always reclaim an entire + * page. Doing this would mean that we all need to move towards QMAGIC. + */ + +static int maybe_shrink_lav_buffers(int size) +{ + int nlist; + int isize; + int total_lav, total_n_buffers, n_sizes; + + /* Do not consider the shared buffers since they would not tend + to have getblk called very often, and this would throw off + the lav. They are not easily reclaimable anyway (let the swapper + make the first move). */ + + total_lav = total_n_buffers = n_sizes = 0; + for(nlist = 0; nlist < NR_SIZES; nlist++) + { + total_lav += buffers_lav[nlist]; + if(nr_buffers_size[nlist]) n_sizes++; + total_n_buffers += nr_buffers_size[nlist]; + total_n_buffers -= nr_buffers_st[nlist][BUF_SHARED]; + } + + /* See if we have an excessive number of buffers of a particular + size - if so, victimize that bunch. */ + + isize = (size ? BUFSIZE_INDEX(size) : -1); + + if (n_sizes > 1) + for(nlist = 0; nlist < NR_SIZES; nlist++) + { + if(nlist == isize) continue; + if(nr_buffers_size[nlist] && + bdf_prm.b_un.lav_const * buffers_lav[nlist]*total_n_buffers < + total_lav * (nr_buffers_size[nlist] - nr_buffers_st[nlist][BUF_SHARED])) + if(shrink_specific_buffers(6, bufferindex_size[nlist])) + return 1; + } + return 0; +} /* * Try to free up some pages by shrinking the buffer-cache * @@ -968,64 +1390,288 @@ */ int shrink_buffers(unsigned int priority) { + if (priority < 2) { + sync_buffers(0,0); + } + + if(priority == 2) wakeup_bdflush(1); + + if(maybe_shrink_lav_buffers(0)) return 1; + + /* No good candidate size - take any size we can find */ + return shrink_specific_buffers(priority, 0); +} + +static int shrink_specific_buffers(unsigned int priority, int size) +{ struct buffer_head *bh; - int i; + int nlist; + int i, isize, isize1; - if (priority < 2) - sync_buffers(0,0); - bh = free_list; - i = nr_buffers >> priority; - for ( ; i-- > 0 ; bh = bh->b_next_free) { - if (bh->b_count || - (priority >= 5 && - mem_map[MAP_NR((unsigned long) bh->b_data)] > 1)) { - put_last_free(bh); - continue; +#ifdef DEBUG + if(size) printk("Shrinking buffers of size %d\n", size); +#endif + /* First try the free lists, and see if we can get a complete page + from here */ + isize1 = (size ? BUFSIZE_INDEX(size) : -1); + + for(isize = 0; isizeb_next_free, i++) { + if (bh->b_count || !bh->b_this_page) + continue; + if (try_to_free(bh, &bh)) + return 1; + if(!bh) break; /* Some interrupt must have used it after we + freed the page. No big deal - keep looking */ } - if (!bh->b_this_page) - continue; - if (bh->b_lock) - if (priority) + } + + /* Not enough in the free lists, now try the lru list */ + + for(nlist = 0; nlist < NR_LIST; nlist++) { + repeat1: + if(priority > 3 && nlist == BUF_SHARED) continue; + bh = lru_list[nlist]; + if(!bh) continue; + i = nr_buffers_type[nlist] >> priority; + for ( ; i-- > 0 ; bh = bh->b_next_free) { + /* We may have stalled while waiting for I/O to complete. */ + if(bh->b_list != nlist) goto repeat1; + if (bh->b_count || !bh->b_this_page) + continue; + if(size && bh->b_size != size) continue; + if (bh->b_lock) + if (priority) + continue; + else + wait_on_buffer(bh); + if (bh->b_dirt) { + bh->b_count++; + bh->b_flushtime = 0; + ll_rw_block(WRITEA, 1, &bh); + bh->b_count--; continue; - else - wait_on_buffer(bh); - if (bh->b_dirt) { - bh->b_count++; - ll_rw_block(WRITEA, 1, &bh); - bh->b_count--; - continue; + } + if (try_to_free(bh, &bh)) + return 1; + if(!bh) break; } - if (try_to_free(bh, &bh)) - return 1; } return 0; } + void show_buffers(void) { struct buffer_head * bh; int found = 0, locked = 0, dirty = 0, used = 0, lastused = 0; + int shared; + int nlist, isize; printk("Buffer memory: %6dkB\n",buffermem>>10); printk("Buffer heads: %6d\n",nr_buffer_heads); printk("Buffer blocks: %6d\n",nr_buffers); - bh = free_list; - do { + + for(nlist = 0; nlist < NR_LIST; nlist++) { + shared = found = locked = dirty = used = lastused = 0; + bh = lru_list[nlist]; + if(!bh) continue; + do { found++; if (bh->b_lock) locked++; if (bh->b_dirt) dirty++; + if(mem_map[MAP_NR(((unsigned long) bh->b_data))] !=1) shared++; if (bh->b_count) used++, lastused = found; bh = bh->b_next_free; - } while (bh != free_list); - printk("Buffer mem: %d buffers, %d used (last=%d), %d locked, %d dirty\n", - found, used, lastused, locked, dirty); + } while (bh != lru_list[nlist]); + printk("Buffer[%d] mem: %d buffers, %d used (last=%d), %d locked, %d dirty %d shrd\n", + nlist, found, used, lastused, locked, dirty, shared); + }; + printk("Size [LAV] Free Clean Unshar Lck Lck1 Dirty Shared\n"); + for(isize = 0; isizeb_data; + page &= PAGE_MASK; + if(mem_map[MAP_NR(page)] != 1) return 0; + tmp = bh; + do { + if (!tmp) + return 0; + + if (tmp->b_count || tmp->b_dirt || tmp->b_lock) + return 0; + tmp = tmp->b_this_page; + } while (tmp != bh); + tmp = bh; + + while((unsigned int) tmp->b_data & (PAGE_SIZE - 1)) + tmp = tmp->b_this_page; + + /* This is the buffer at the head of the page */ + bh = tmp; + do { + p = tmp; + tmp = tmp->b_this_page; + remove_from_queues(p); + p->b_dev=dev; + p->b_uptodate = 0; + p->b_req = 0; + p->b_blocknr=starting_block++; + insert_into_queues(p); + } while (tmp != bh); + return 1; +} + +/* + * Try to find a free cluster by locating a page where + * all of the buffers are unused. We would like this function + * to be atomic, so we do not call anything that might cause + * the process to sleep. The priority is somewhat similar to + * the priority used in shrink_buffers. + * + * My thinking is that the kernel should end up using whole + * pages for the buffer cache as much of the time as possible. + * This way the other buffers on a particular page are likely + * to be very near each other on the free list, and we will not + * be expiring data prematurely. For now we only canibalize buffers + * of the same size to keep the code simpler. + */ +static int reassign_cluster(dev_t dev, + unsigned int starting_block, int size) +{ + struct buffer_head *bh; + int isize = BUFSIZE_INDEX(size); + int i; + + /* We want to give ourselves a really good shot at generating + a cluster, and since we only take buffers from the free + list, we "overfill" it a little. */ + + while(nr_free[isize] < 32) refill_freelist(size); + + bh = free_list[isize]; + if(bh) + for (i=0 ; !i || bh != free_list[isize] ; bh = bh->b_next_free, i++) { + if (!bh->b_this_page) continue; + if (try_to_reassign(bh, &bh, dev, starting_block)) + return 4; + } + return 0; +} + +/* This function tries to generate a new cluster of buffers + * from a new page in memory. We should only do this if we have + * not expanded the buffer cache to the maximum size that we allow. + */ +static unsigned long try_to_generate_cluster(dev_t dev, int block, int size) +{ + struct buffer_head * bh, * tmp, * arr[8]; + int isize = BUFSIZE_INDEX(size); + unsigned long offset; + unsigned long page; + int nblock; + + page = get_free_page(GFP_NOBUFFER); + if(!page) return 0; + + bh = create_buffers(page, size); + if (!bh) { + free_page(page); + return 0; + }; + nblock = block; + for (offset = 0 ; offset < PAGE_SIZE ; offset += size) { + if (find_buffer(dev, nblock++, size)) + goto not_aligned; + } + tmp = bh; + nblock = 0; + while (1) { + arr[nblock++] = bh; + bh->b_count = 1; + bh->b_dirt = 0; + bh->b_flushtime = 0; + bh->b_lock = 0; + bh->b_uptodate = 0; + bh->b_req = 0; + bh->b_dev = dev; + bh->b_list = BUF_CLEAN; + bh->b_blocknr = block++; + nr_buffers++; + nr_buffers_size[isize]++; + insert_into_queues(bh); + if (bh->b_this_page) + bh = bh->b_this_page; + else + break; + } + buffermem += PAGE_SIZE; + buffer_pages[page >> PAGE_SHIFT] = bh; + bh->b_this_page = tmp; + while (nblock-- > 0) + brelse(arr[nblock]); + return 4; +not_aligned: + while ((tmp = bh) != NULL) { + bh = bh->b_this_page; + put_unused_buffer_head(tmp); + } + free_page(page); + return 0; +} + +unsigned long generate_cluster(dev_t dev, int b[], int size) +{ + int i, offset; + + for (i = 0, offset = 0 ; offset < PAGE_SIZE ; i++, offset += size) { + if(i && b[i]-1 != b[i-1]) return 0; /* No need to cluster */ + if(find_buffer(dev, b[i], size)) return 0; + }; + + /* OK, we have a candidate for a new cluster */ + + /* See if one size of buffer is over-represented in the buffer cache, + if so reduce the numbers of buffers */ + if(maybe_shrink_lav_buffers(size)) + { + int retval; + retval = try_to_generate_cluster(dev, b[0], size); + if(retval) return retval; + }; + + if (nr_free_pages > min_free_pages) + return try_to_generate_cluster(dev, b[0], size); + else + return reassign_cluster(dev, b[0], size); } /* - * This initializes the initial buffer free list. nr_buffers is set + * This initializes the initial buffer free list. nr_buffers_type is set * to one less the actual number of buffers, as a sop to backwards * compatibility --- the old code did this (I think unintentionally, * but I'm not sure), and programs in the ps package expect it. @@ -1034,16 +1680,254 @@ void buffer_init(void) { int i; + int isize = BUFSIZE_INDEX(BLOCK_SIZE); - if (high_memory >= 4*1024*1024) + if (high_memory >= 4*1024*1024) { min_free_pages = 200; - else + if(high_memory >= 16*1024*1024) + nr_hash = 16381; + else + nr_hash = 4093; + } else { min_free_pages = 20; - for (i = 0 ; i < NR_HASH ; i++) + nr_hash = 997; + }; + + hash_table = (struct buffer_head **) vmalloc(nr_hash * + sizeof(struct buffer_head *)); + + + buffer_pages = (struct buffer_head **) vmalloc((high_memory >>PAGE_SHIFT) * + sizeof(struct buffer_head *)); + for (i = 0 ; i < high_memory >> PAGE_SHIFT ; i++) + buffer_pages[i] = NULL; + + for (i = 0 ; i < nr_hash ; i++) hash_table[i] = NULL; - free_list = 0; + lru_list[BUF_CLEAN] = 0; grow_buffers(GFP_KERNEL, BLOCK_SIZE); - if (!free_list) + if (!free_list[isize]) panic("VFS: Unable to initialize buffer free list!"); return; } + +/* This is a simple kernel daemon, whose job it is to provide a dynamicly + * response to dirty buffers. Once this process is activated, we write back + * a limited number of buffers to the disks and then go back to sleep again. + * In effect this is a process which never leaves kernel mode, and does not have + * any user memory associated with it except for the stack. There is also + * a kernel stack page, which obviously must be separate from the user stack. + */ +struct wait_queue * bdflush_wait = NULL; +struct wait_queue * bdflush_done = NULL; + +static int bdflush_running = 0; + +static void wakeup_bdflush(int wait) +{ + if(!bdflush_running){ + printk("Warning - bdflush not running\n"); + sync_buffers(0,0); + return; + }; + wake_up(&bdflush_wait); + if(wait) sleep_on(&bdflush_done); +} + + + +/* + * Here we attempt to write back old buffers. We also try and flush indoes + * and supers as well, since this function is essentially "update", and + * otherwise there would be no way of ensuring that these quantities ever + * get written back. Ideally, we would have a timestamp on the inodes + * and superblocks so that we could write back only the old ones as well + */ + +asmlinkage int sync_old_buffers(void) +{ + int i, isize; + int ndirty, nwritten; + int nlist; + int ncount; + struct buffer_head * bh, *next; + + sync_supers(0); + sync_inodes(0); + + ncount = 0; +#ifdef DEBUG + for(nlist = 0; nlist < NR_LIST; nlist++) +#else + for(nlist = BUF_DIRTY; nlist <= BUF_DIRTY; nlist++) +#endif + { + ndirty = 0; + nwritten = 0; + repeat: + bh = lru_list[nlist]; + if(bh) + for (i = nr_buffers_type[nlist]; --i > 0; bh = next) { + /* We may have stalled while waiting for I/O to complete. */ + if(bh->b_list != nlist) goto repeat; + next = bh->b_next_free; + if(!lru_list[nlist]) { + printk("Dirty list empty %d\n", i); + break; + } + + /* Clean buffer on dirty list? Refile it */ + if (nlist == BUF_DIRTY && !bh->b_dirt && !bh->b_lock) + { + refile_buffer(bh); + continue; + } + + if (bh->b_lock || !bh->b_dirt) + continue; + ndirty++; + if(bh->b_flushtime > jiffies) continue; + nwritten++; + bh->b_count++; + bh->b_flushtime = 0; +#ifdef DEBUG + if(nlist != BUF_DIRTY) ncount++; +#endif + ll_rw_block(WRITE, 1, &bh); + bh->b_count--; + } + } +#ifdef DEBUG + if (ncount) printk("sync_old_buffers: %d dirty buffers not on dirty list\n", ncount); + printk("Wrote %d/%d buffers\n", nwritten, ndirty); +#endif + + /* We assume that we only come through here on a regular + schedule, like every 5 seconds. Now update load averages. + Shift usage counts to prevent overflow. */ + for(isize = 0; isize= 2){ + i = (func-2) >> 1; + if (i < 0 || i >= N_PARAM) return -EINVAL; + if((func & 1) == 0) { + error = verify_area(VERIFY_WRITE, (void *) data, sizeof(int)); + if(error) return error; + put_fs_long(bdf_prm.data[i], data); + return 0; + }; + if(data < bdflush_min[i] || data > bdflush_max[i]) return -EINVAL; + bdf_prm.data[i] = data; + return 0; + }; + + if(bdflush_running++) return -EBUSY; /* Only one copy of this running at one time */ + + /* OK, from here on is the daemon */ + + while(1==1){ +#ifdef DEBUG + printk("bdflush() activated..."); +#endif + + ncount = 0; +#ifdef DEBUG + for(nlist = 0; nlist < NR_LIST; nlist++) +#else + for(nlist = BUF_DIRTY; nlist <= BUF_DIRTY; nlist++) +#endif + { + ndirty = 0; + repeat: + bh = lru_list[nlist]; + if(bh) + for (i = nr_buffers_type[nlist]; --i > 0 && ndirty < bdf_prm.b_un.ndirty; + bh = next) { + /* We may have stalled while waiting for I/O to complete. */ + if(bh->b_list != nlist) goto repeat; + next = bh->b_next_free; + if(!lru_list[nlist]) { + printk("Dirty list empty %d\n", i); + break; + } + + /* Clean buffer on dirty list? Refile it */ + if (nlist == BUF_DIRTY && !bh->b_dirt && !bh->b_lock) + { + refile_buffer(bh); + continue; + } + + if (bh->b_lock || !bh->b_dirt) + continue; + /* Should we write back buffers that are shared or not?? + currently dirty buffers are not shared, so it does not matter */ + bh->b_count++; + ndirty++; + bh->b_flushtime = 0; + ll_rw_block(WRITE, 1, &bh); +#ifdef DEBUG + if(nlist != BUF_DIRTY) ncount++; +#endif + bh->b_count--; + } + } +#ifdef DEBUG + if (ncount) printk("sys_bdflush: %d dirty buffers not on dirty list\n", ncount); + printk("sleeping again.\n"); +#endif + wake_up(&bdflush_done); + + /* If there are still a lot of dirty buffers around, skip the sleep + and flush some more */ + + if(nr_buffers_type[BUF_DIRTY] < (nr_buffers - nr_buffers_type[BUF_SHARED]) * + bdf_prm.b_un.nfract/100) { + interruptible_sleep_on(&bdflush_wait); + } + } +} + + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --recursive --new-file v1.1.2/linux/fs/devices.c linux/fs/devices.c --- v1.1.2/linux/fs/devices.c Mon Dec 27 07:35:48 1993 +++ linux/fs/devices.c Wed Apr 13 09:14:07 1994 @@ -28,6 +28,26 @@ { NULL, NULL }, }; +int get_device_list(char * page) +{ + int i; + int len; + + len = sprintf(page, "Character devices:\n"); + for (i = 0; i < MAX_CHRDEV ; i++) { + if (chrdevs[i].fops) { + len += sprintf(page+len, "%2d %s\n", i, chrdevs[i].name); + } + } + len += sprintf(page+len, "\nBlock devices:\n"); + for (i = 0; i < MAX_BLKDEV ; i++) { + if (blkdevs[i].fops) { + len += sprintf(page+len, "%2d %s\n", i, blkdevs[i].name); + } + } + return len; +} + struct file_operations * get_blkfops(unsigned int major) { if (major >= MAX_BLKDEV) diff -u --recursive --new-file v1.1.2/linux/fs/ext/file.c linux/fs/ext/file.c --- v1.1.2/linux/fs/ext/file.c Wed Apr 13 11:33:53 1994 +++ linux/fs/ext/file.c Wed Apr 13 11:16:27 1994 @@ -248,7 +248,7 @@ memcpy_fromfs(p,buf,c); buf += c; bh->b_uptodate = 1; - dirtify_buffer(bh, 0); + mark_buffer_dirty(bh, 0); brelse(bh); } inode->i_mtime = inode->i_ctime = CURRENT_TIME; diff -u --recursive --new-file v1.1.2/linux/fs/ext/freelists.c linux/fs/ext/freelists.c --- v1.1.2/linux/fs/ext/freelists.c Wed Apr 13 11:33:53 1994 +++ linux/fs/ext/freelists.c Wed Apr 13 11:16:28 1994 @@ -83,7 +83,7 @@ } sb->u.ext_sb.s_freeblockscount ++; sb->s_dirt = 1; - dirtify_buffer(sb->u.ext_sb.s_firstfreeblock, 1); + mark_buffer_dirty(sb->u.ext_sb.s_firstfreeblock, 1); unlock_super (sb); return; } @@ -104,7 +104,7 @@ efb = (struct ext_free_block *) sb->u.ext_sb.s_firstfreeblock->b_data; if (efb->count) { j = efb->free[--efb->count]; - dirtify_buffer(sb->u.ext_sb.s_firstfreeblock, 1); + mark_buffer_dirty(sb->u.ext_sb.s_firstfreeblock, 1); } else { #ifdef EXTFS_DEBUG printk("ext_new_block: block empty, skipping to %d\n", efb->next); @@ -135,7 +135,7 @@ } clear_block(bh->b_data); bh->b_uptodate = 1; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); #ifdef EXTFS_DEBUG printk("ext_new_block: allocating block %d\n", j); @@ -239,7 +239,7 @@ } sb->u.ext_sb.s_freeinodescount ++; sb->s_dirt = 1; - dirtify_buffer(sb->u.ext_sb.s_firstfreeinodeblock, 1); + mark_buffer_dirty(sb->u.ext_sb.s_firstfreeinodeblock, 1); unlock_super (sb); } @@ -263,7 +263,7 @@ (sb->u.ext_sb.s_firstfreeinodenumber-1)%EXT_INODES_PER_BLOCK; if (efi->count) { j = efi->free[--efi->count]; - dirtify_buffer(sb->u.ext_sb.s_firstfreeinodeblock, 1); + mark_buffer_dirty(sb->u.ext_sb.s_firstfreeinodeblock, 1); } else { #ifdef EXTFS_DEBUG printk("ext_free_inode: inode empty, skipping to %d\n", efi->next); diff -u --recursive --new-file v1.1.2/linux/fs/ext/inode.c linux/fs/ext/inode.c --- v1.1.2/linux/fs/ext/inode.c Wed Apr 13 11:33:53 1994 +++ linux/fs/ext/inode.c Wed Apr 13 11:16:28 1994 @@ -139,7 +139,7 @@ es->s_freeblockscount = sb->u.ext_sb.s_freeblockscount; es->s_firstfreeinode = sb->u.ext_sb.s_firstfreeinodenumber; es->s_freeinodescount = sb->u.ext_sb.s_freeinodescount; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse (bh); sb->s_dirt = 0; } @@ -296,7 +296,7 @@ goto repeat; } *p = tmp; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); return result; } @@ -407,7 +407,7 @@ raw_inode->i_zone[0] = inode->i_rdev; else for (block = 0; block < 12; block++) raw_inode->i_zone[block] = inode->u.ext_i.i_data[block]; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); inode->i_dirt=0; return bh; } diff -u --recursive --new-file v1.1.2/linux/fs/ext/namei.c linux/fs/ext/namei.c --- v1.1.2/linux/fs/ext/namei.c Wed Apr 13 11:33:54 1994 +++ linux/fs/ext/namei.c Wed Apr 13 11:16:28 1994 @@ -249,7 +249,7 @@ #if 0 dir->i_ctime = CURRENT_TIME; #endif - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); } brelse (bh); bh = NULL; @@ -296,7 +296,7 @@ de->name_len = namelen; for (i=0; i < namelen ; i++) de->name[i] = name[i]; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); *res_dir = de; return bh; } @@ -334,7 +334,7 @@ return -ENOSPC; } de->inode = inode->i_ino; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); iput(dir); *result = inode; @@ -393,7 +393,7 @@ return -ENOSPC; } de->inode = inode->i_ino; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); iput(dir); iput(inode); @@ -445,7 +445,7 @@ de->name_len=2; strcpy(de->name,".."); inode->i_nlink = 2; - dirtify_buffer(dir_block, 1); + mark_buffer_dirty(dir_block, 1); brelse(dir_block); inode->i_mode = S_IFDIR | (mode & 0777 & ~current->umask); if (dir->i_mode & S_ISGID) @@ -459,7 +459,7 @@ return -ENOSPC; } de->inode = inode->i_ino; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); dir->i_nlink++; dir->i_dirt = 1; iput(dir); @@ -567,7 +567,7 @@ de->inode = 0; de->name_len = 0; ext_merge_entries (de, pde, nde); - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); inode->i_nlink=0; inode->i_dirt=1; dir->i_nlink--; @@ -610,7 +610,7 @@ de->inode = 0; de->name_len = 0; ext_merge_entries (de, pde, nde); - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); inode->i_nlink--; inode->i_dirt = 1; inode->i_ctime = CURRENT_TIME; @@ -650,7 +650,7 @@ while (i < 1023 && (c = *(symname++))) name_block->b_data[i++] = c; name_block->b_data[i] = 0; - dirtify_buffer(name_block, 1); + mark_buffer_dirty(name_block, 1); brelse(name_block); inode->i_size = i; inode->i_dirt = 1; @@ -672,7 +672,7 @@ return -ENOSPC; } de->inode = inode->i_ino; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); iput(dir); iput(inode); @@ -708,7 +708,7 @@ return -ENOSPC; } de->inode = oldinode->i_ino; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); iput(dir); oldinode->i_nlink++; @@ -851,11 +851,11 @@ new_inode->i_nlink--; new_inode->i_dirt = 1; } - dirtify_buffer(old_bh, 1); - dirtify_buffer(new_bh, 1); + mark_buffer_dirty(old_bh, 1); + mark_buffer_dirty(new_bh, 1); if (dir_bh) { PARENT_INO(dir_bh->b_data) = new_dir->i_ino; - dirtify_buffer(dir_bh, 1); + mark_buffer_dirty(dir_bh, 1); old_dir->i_nlink--; new_dir->i_nlink++; old_dir->i_dirt = 1; diff -u --recursive --new-file v1.1.2/linux/fs/ext/truncate.c linux/fs/ext/truncate.c --- v1.1.2/linux/fs/ext/truncate.c Wed Apr 13 11:33:54 1994 +++ linux/fs/ext/truncate.c Wed Apr 13 11:16:28 1994 @@ -102,7 +102,7 @@ continue; } *ind = 0; - dirtify_buffer(ind_bh, 1); + mark_buffer_dirty(ind_bh, 1); brelse(bh); ext_free_block(inode->i_sb,tmp); } @@ -154,7 +154,7 @@ if (!tmp) continue; retry |= trunc_indirect(inode,offset+(i<<8),dind); - dirtify_buffer(dind_bh, 1); + mark_buffer_dirty(dind_bh, 1); } dind = (unsigned long *) dind_bh->b_data; for (i = 0; i < 256; i++) @@ -201,7 +201,7 @@ goto repeat; tind = i+(unsigned long *) tind_bh->b_data; retry |= trunc_dindirect(inode,9+256+256*256+(i<<16),tind); - dirtify_buffer(tind_bh, 1); + mark_buffer_dirty(tind_bh, 1); } tind = (unsigned long *) tind_bh->b_data; for (i = 0; i < 256; i++) diff -u --recursive --new-file v1.1.2/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c --- v1.1.2/linux/fs/ext2/balloc.c Wed Apr 13 11:33:54 1994 +++ linux/fs/ext2/balloc.c Wed Apr 13 11:16:28 1994 @@ -310,10 +310,10 @@ } } - dirtify_buffer(bh2, 1); - dirtify_buffer(sb->u.ext2_sb.s_sbh, 1); + mark_buffer_dirty(bh2, 1); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); if (sb->s_flags & MS_SYNC) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -524,7 +524,7 @@ j = tmp; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); if (sb->s_flags & MS_SYNC) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -544,16 +544,16 @@ } clear_block (bh->b_data, sb->s_blocksize); bh->b_uptodate = 1; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse (bh); ext2_debug ("allocating block %d. " "Goal hits %d of %d.\n", j, goal_hits, goal_attempts); gdp->bg_free_blocks_count--; - dirtify_buffer(bh2, 1); + mark_buffer_dirty(bh2, 1); es->s_free_blocks_count--; - dirtify_buffer(sb->u.ext2_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); sb->s_dirt = 1; unlock_super (sb); return j; diff -u --recursive --new-file v1.1.2/linux/fs/ext2/file.c linux/fs/ext2/file.c --- v1.1.2/linux/fs/ext2/file.c Wed Apr 13 11:33:54 1994 +++ linux/fs/ext2/file.c Wed Apr 13 11:17:48 1994 @@ -78,6 +78,7 @@ int read, left, chars; int block, blocks, offset; int bhrequest, uptodate; + int clusterblocks; struct buffer_head ** bhb, ** bhe; struct buffer_head * bhreq[NBUF]; struct buffer_head * buflist[NBUF]; @@ -130,11 +131,18 @@ * buffers and caches. */ + clusterblocks = 0; + do { bhrequest = 0; uptodate = 1; while (blocks) { --blocks; +#if 1 + if(!clusterblocks) clusterblocks = ext2_getcluster(inode, block); + if(clusterblocks) clusterblocks--; +#endif + *bhb = ext2_getblk (inode, block++, 0, &err); if (*bhb && !(*bhb)->b_uptodate) { uptodate = 0; @@ -277,7 +285,7 @@ memcpy_fromfs (p, buf, c); buf += c; bh->b_uptodate = 1; - dirtify_buffer(bh, 0); + mark_buffer_dirty(bh, 0); brelse (bh); } up(&inode->i_sem); diff -u --recursive --new-file v1.1.2/linux/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c --- v1.1.2/linux/fs/ext2/ialloc.c Wed Apr 13 11:33:54 1994 +++ linux/fs/ext2/ialloc.c Wed Apr 13 11:16:29 1994 @@ -202,7 +202,7 @@ EXT2_INODES_PER_BLOCK(inode->i_sb)); raw_inode->i_links_count = 0; raw_inode->i_dtime = CURRENT_TIME; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); if (IS_SYNC(inode)) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -266,12 +266,12 @@ gdp->bg_free_inodes_count++; if (S_ISDIR(inode->i_mode)) gdp->bg_used_dirs_count--; - dirtify_buffer(bh2, 1); + mark_buffer_dirty(bh2, 1); es->s_free_inodes_count++; - dirtify_buffer(sb->u.ext2_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); set_inode_dtime (inode, gdp); } - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); if (sb->s_flags & MS_SYNC) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -313,7 +313,7 @@ EXT2_INODES_PER_BLOCK(inode->i_sb)); raw_inode->i_version++; inode->u.ext2_i.i_version = raw_inode->i_version; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse (bh); } @@ -438,7 +438,7 @@ "bit already set for inode %d", j); goto repeat; } - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); if (sb->s_flags & MS_SYNC) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -466,9 +466,9 @@ gdp->bg_free_inodes_count--; if (S_ISDIR(mode)) gdp->bg_used_dirs_count++; - dirtify_buffer(bh2, 1); + mark_buffer_dirty(bh2, 1); es->s_free_inodes_count--; - dirtify_buffer(sb->u.ext2_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); sb->s_dirt = 1; inode->i_mode = mode; inode->i_sb = sb; diff -u --recursive --new-file v1.1.2/linux/fs/ext2/inode.c linux/fs/ext2/inode.c --- v1.1.2/linux/fs/ext2/inode.c Wed Apr 13 11:33:54 1994 +++ linux/fs/ext2/inode.c Wed Apr 13 11:17:49 1994 @@ -109,7 +109,7 @@ } clear_block (bh->b_data, inode->i_sb->s_blocksize); bh->b_uptodate = 1; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse (bh); } else { ext2_discard_prealloc (inode); @@ -314,7 +314,7 @@ goto repeat; } *p = tmp; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); if (IS_SYNC(inode)) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -328,6 +328,41 @@ return result; } +static int block_getcluster (struct inode * inode, struct buffer_head * bh, + int nr, + int blocksize) +{ + unsigned long * p; + int firstblock = 0; + int result = 0; + int i; + + /* Check to see if clustering possible here. */ + + if(!bh) return 0; + + if(nr % (PAGE_SIZE / inode->i_sb->s_blocksize) != 0) goto out; + if(nr + 3 > EXT2_ADDR_PER_BLOCK(inode->i_sb)) goto out; + + for(i=0; i< (PAGE_SIZE / inode->i_sb->s_blocksize); i++) { + p = (unsigned long *) bh->b_data + nr + i; + + /* All blocks in cluster must already be allocated */ + if(*p == 0) goto out; + + /* See if aligned correctly */ + if(i==0) firstblock = *p; + else if(*p != firstblock + i) goto out; + }; + + p = (unsigned long *) bh->b_data + nr; + result = generate_cluster(bh->b_dev, (int *) p, blocksize); + + out: + brelse(bh); + return result; +} + struct buffer_head * ext2_getblk (struct inode * inode, long block, int create, int * err) { @@ -389,6 +424,55 @@ inode->i_sb->s_blocksize, b, err); } +int ext2_getcluster (struct inode * inode, long block) +{ + struct buffer_head * bh; + int err, create; + unsigned long b; + unsigned long addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); + + create = 0; + err = -EIO; + if (block < 0) { + ext2_warning (inode->i_sb, "ext2_getblk", "block < 0"); + return 0; + } + if (block > EXT2_NDIR_BLOCKS + addr_per_block + + addr_per_block * addr_per_block + + addr_per_block * addr_per_block * addr_per_block) { + ext2_warning (inode->i_sb, "ext2_getblk", "block > big"); + return 0; + } + + err = -ENOSPC; + b = block; + if (block < EXT2_NDIR_BLOCKS) return 0; + + block -= EXT2_NDIR_BLOCKS; + + if (block < addr_per_block) { + bh = inode_getblk (inode, EXT2_IND_BLOCK, create, b, &err); + return block_getcluster (inode, bh, block, + inode->i_sb->s_blocksize); + } + block -= addr_per_block; + if (block < addr_per_block * addr_per_block) { + bh = inode_getblk (inode, EXT2_DIND_BLOCK, create, b, &err); + bh = block_getblk (inode, bh, block / addr_per_block, create, + inode->i_sb->s_blocksize, b, &err); + return block_getcluster (inode, bh, block & (addr_per_block - 1), + inode->i_sb->s_blocksize); + } + block -= addr_per_block * addr_per_block; + bh = inode_getblk (inode, EXT2_TIND_BLOCK, create, b, &err); + bh = block_getblk (inode, bh, block/(addr_per_block * addr_per_block), + create, inode->i_sb->s_blocksize, b, &err); + bh = block_getblk (inode, bh, (block/addr_per_block) & (addr_per_block - 1), + create, inode->i_sb->s_blocksize, b, &err); + return block_getcluster (inode, bh, block & (addr_per_block - 1), + inode->i_sb->s_blocksize); +} + struct buffer_head * ext2_bread (struct inode * inode, int block, int create, int *err) { @@ -549,7 +633,7 @@ raw_inode->i_block[0] = inode->i_rdev; else for (block = 0; block < EXT2_N_BLOCKS; block++) raw_inode->i_block[block] = inode->u.ext2_i.i_data[block]; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); inode->i_dirt = 0; return bh; } diff -u --recursive --new-file v1.1.2/linux/fs/ext2/namei.c linux/fs/ext2/namei.c --- v1.1.2/linux/fs/ext2/namei.c Wed Apr 13 11:33:54 1994 +++ linux/fs/ext2/namei.c Wed Apr 13 11:16:29 1994 @@ -320,7 +320,7 @@ */ dir->i_mtime = dir->i_ctime = CURRENT_TIME; dir->i_dirt = 1; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); *res_dir = de; *err = 0; return bh; @@ -394,7 +394,7 @@ ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len, de->inode); #endif - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -460,7 +460,7 @@ ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len, de->inode); #endif - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -517,7 +517,7 @@ de->name_len = 2; strcpy (de->name, ".."); inode->i_nlink = 2; - dirtify_buffer(dir_block, 1); + mark_buffer_dirty(dir_block, 1); brelse (dir_block); inode->i_mode = S_IFDIR | (mode & S_IRWXUGO & ~current->umask); if (dir->i_mode & S_ISGID) @@ -536,7 +536,7 @@ ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len, de->inode); #endif - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -660,7 +660,7 @@ up(&inode->i_sem); if (retval) goto end_rmdir; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -728,7 +728,7 @@ retval = ext2_delete_entry (de, bh); if (retval) goto end_unlink; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -793,7 +793,7 @@ link[i++] = c; link[i] = 0; if (name_block) { - dirtify_buffer(name_block, 1); + mark_buffer_dirty(name_block, 1); brelse (name_block); } inode->i_size = i; @@ -820,7 +820,7 @@ ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len, de->inode); #endif - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -866,7 +866,7 @@ ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len, de->inode); #endif - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -1042,19 +1042,19 @@ } old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; old_dir->i_dirt = 1; - dirtify_buffer(old_bh, 1); + mark_buffer_dirty(old_bh, 1); if (IS_SYNC(old_dir)) { ll_rw_block (WRITE, 1, &old_bh); wait_on_buffer (old_bh); } - dirtify_buffer(new_bh, 1); + mark_buffer_dirty(new_bh, 1); if (IS_SYNC(new_dir)) { ll_rw_block (WRITE, 1, &new_bh); wait_on_buffer (new_bh); } if (dir_bh) { PARENT_INO(dir_bh->b_data) = new_dir->i_ino; - dirtify_buffer(dir_bh, 1); + mark_buffer_dirty(dir_bh, 1); old_dir->i_nlink--; old_dir->i_dirt = 1; if (new_inode) { diff -u --recursive --new-file v1.1.2/linux/fs/ext2/super.c linux/fs/ext2/super.c --- v1.1.2/linux/fs/ext2/super.c Wed Apr 13 11:33:55 1994 +++ linux/fs/ext2/super.c Wed Apr 13 11:16:29 1994 @@ -36,7 +36,7 @@ if (!(sb->s_flags & MS_RDONLY)) { sb->u.ext2_sb.s_mount_state |= EXT2_ERROR_FS; sb->u.ext2_sb.s_es->s_state |= EXT2_ERROR_FS; - dirtify_buffer(sb->u.ext2_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); sb->s_dirt = 1; } va_start (args, fmt); @@ -66,7 +66,7 @@ if (!(sb->s_flags & MS_RDONLY)) { sb->u.ext2_sb.s_mount_state |= EXT2_ERROR_FS; sb->u.ext2_sb.s_es->s_state |= EXT2_ERROR_FS; - dirtify_buffer(sb->u.ext2_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); sb->s_dirt = 1; } va_start (args, fmt); @@ -96,7 +96,7 @@ lock_super (sb); if (!(sb->s_flags & MS_RDONLY)) { sb->u.ext2_sb.s_es->s_state = sb->u.ext2_sb.s_mount_state; - dirtify_buffer(sb->u.ext2_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); } #ifndef DONT_USE_DCACHE ext2_dcache_invalidate (sb->s_dev); @@ -159,10 +159,10 @@ gdp[i].bg_free_blocks_count = old_group_desc[i].bg_free_blocks_count; gdp[i].bg_free_inodes_count = old_group_desc[i].bg_free_inodes_count; } - dirtify_buffer(bh2, 1); + mark_buffer_dirty(bh2, 1); brelse (bh2); es->s_magic = EXT2_SUPER_MAGIC; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); sb->s_magic = EXT2_SUPER_MAGIC; return 1; } @@ -287,7 +287,7 @@ es->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT; es->s_mnt_count++; es->s_mtime = CURRENT_TIME; - dirtify_buffer(sb->u.ext2_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); sb->s_dirt = 1; if (test_opt (sb, DEBUG)) printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, " @@ -570,7 +570,7 @@ #ifdef EXT2FS_PRE_02B_COMPAT if (fs_converted) { for (i = 0; i < bh_count; i++) - dirtify_buffer(sb->u.ext2_sb.s_group_desc[i], 1); + mark_buffer_dirty(sb->u.ext2_sb.s_group_desc[i], 1); sb->s_dirt = 1; } #endif @@ -582,7 +582,7 @@ struct ext2_super_block * es) { es->s_wtime = CURRENT_TIME; - dirtify_buffer(sb->u.ext2_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); sb->s_dirt = 0; } @@ -639,7 +639,7 @@ */ es->s_state = sb->u.ext2_sb.s_mount_state; es->s_mtime = CURRENT_TIME; - dirtify_buffer(sb->u.ext2_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); sb->s_dirt = 1; ext2_commit_super (sb, es); } diff -u --recursive --new-file v1.1.2/linux/fs/ext2/truncate.c linux/fs/ext2/truncate.c --- v1.1.2/linux/fs/ext2/truncate.c Wed Apr 13 11:33:55 1994 +++ linux/fs/ext2/truncate.c Wed Apr 13 11:16:29 1994 @@ -90,7 +90,7 @@ if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) { clear_block (bh->b_data, inode->i_sb->s_blocksize, RANDOM_INT); - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); } brelse (bh); if (free_count == 0) { @@ -162,11 +162,11 @@ continue; } *ind = 0; - dirtify_buffer(ind_bh, 1); + mark_buffer_dirty(ind_bh, 1); if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) { clear_block (bh->b_data, inode->i_sb->s_blocksize, RANDOM_INT); - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); } brelse (bh); if (free_count == 0) { @@ -243,7 +243,7 @@ continue; retry |= trunc_indirect (inode, offset + (i * addr_per_block), dind); - dirtify_buffer(dind_bh, 1); + mark_buffer_dirty(dind_bh, 1); } dind = (unsigned long *) dind_bh->b_data; for (i = 0; i < addr_per_block; i++) @@ -302,7 +302,7 @@ retry |= trunc_dindirect(inode, EXT2_NDIR_BLOCKS + addr_per_block + (i + 1) * addr_per_block * addr_per_block, tind); - dirtify_buffer(tind_bh, 1); + mark_buffer_dirty(tind_bh, 1); } tind = (unsigned long *) tind_bh->b_data; for (i = 0; i < addr_per_block; i++) diff -u --recursive --new-file v1.1.2/linux/fs/minix/bitmap.c linux/fs/minix/bitmap.c --- v1.1.2/linux/fs/minix/bitmap.c Wed Apr 13 11:33:56 1994 +++ linux/fs/minix/bitmap.c Wed Apr 13 11:16:30 1994 @@ -93,7 +93,7 @@ } if (!clear_bit(bit,bh->b_data)) printk("free_block (%04x:%d): bit already cleared\n",sb->s_dev,block); - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); return; } @@ -118,7 +118,7 @@ printk("new_block: bit already set"); goto repeat; } - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); j += i*8192 + sb->u.minix_sb.s_firstdatazone-1; if (j < sb->u.minix_sb.s_firstdatazone || j >= sb->u.minix_sb.s_nzones) @@ -129,7 +129,7 @@ } clear_block(bh->b_data); bh->b_uptodate = 1; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); return j; } @@ -175,7 +175,7 @@ clear_inode(inode); if (!clear_bit(ino & 8191, bh->b_data)) printk("free_inode: bit %lu already cleared.\n",ino); - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); } struct inode * minix_new_inode(const struct inode * dir) @@ -204,7 +204,7 @@ iput(inode); return NULL; } - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); j += i*8192; if (!j || j >= inode->i_sb->u.minix_sb.s_ninodes) { iput(inode); diff -u --recursive --new-file v1.1.2/linux/fs/minix/file.c linux/fs/minix/file.c --- v1.1.2/linux/fs/minix/file.c Wed Apr 13 11:33:56 1994 +++ linux/fs/minix/file.c Wed Apr 13 11:16:30 1994 @@ -240,7 +240,7 @@ memcpy_fromfs(p,buf,c); buf += c; bh->b_uptodate = 1; - dirtify_buffer(bh, 0); + mark_buffer_dirty(bh, 0); brelse(bh); } inode->i_mtime = inode->i_ctime = CURRENT_TIME; diff -u --recursive --new-file v1.1.2/linux/fs/minix/inode.c linux/fs/minix/inode.c --- v1.1.2/linux/fs/minix/inode.c Wed Apr 13 11:33:56 1994 +++ linux/fs/minix/inode.c Wed Apr 13 11:16:30 1994 @@ -28,7 +28,7 @@ static void minix_commit_super (struct super_block * sb, struct minix_super_block * ms) { - dirtify_buffer(sb->u.minix_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1); sb->s_dirt = 0; } @@ -54,7 +54,7 @@ lock_super(sb); if (!(sb->s_flags & MS_RDONLY)) { sb->u.minix_sb.s_ms->s_state = sb->u.minix_sb.s_mount_state; - dirtify_buffer(sb->u.minix_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1); } sb->s_dev = 0; for(i = 0 ; i < MINIX_I_MAP_SLOTS ; i++) @@ -90,7 +90,7 @@ return 0; /* Mounting a rw partition read-only. */ ms->s_state = sb->u.minix_sb.s_mount_state; - dirtify_buffer(sb->u.minix_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1); sb->s_dirt = 1; minix_commit_super (sb, ms); } @@ -98,7 +98,7 @@ /* Mount a partition which is read-only, read-write. */ sb->u.minix_sb.s_mount_state = ms->s_state; ms->s_state &= ~MINIX_VALID_FS; - dirtify_buffer(sb->u.minix_sb.s_sbh, 1); + mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1); sb->s_dirt = 1; if (!(sb->u.minix_sb.s_mount_state & MINIX_VALID_FS)) @@ -197,7 +197,7 @@ } if (!(s->s_flags & MS_RDONLY)) { ms->s_state &= ~MINIX_VALID_FS; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); s->s_dirt = 1; } if (!(s->u.minix_sb.s_mount_state & MINIX_VALID_FS)) @@ -349,7 +349,7 @@ goto repeat; } *p = tmp; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); return result; } @@ -477,7 +477,7 @@ else for (block = 0; block < 9; block++) raw_inode->i_zone[block] = inode->u.minix_i.i_data[block]; inode->i_dirt=0; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); return bh; } diff -u --recursive --new-file v1.1.2/linux/fs/minix/namei.c linux/fs/minix/namei.c --- v1.1.2/linux/fs/minix/namei.c Wed Apr 13 11:33:56 1994 +++ linux/fs/minix/namei.c Wed Apr 13 11:16:30 1994 @@ -195,7 +195,7 @@ dir->i_mtime = dir->i_ctime = CURRENT_TIME; for (i = 0; i < info->s_namelen ; i++) de->name[i] = (i < namelen) ? name[i] : 0; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); *res_dir = de; break; } @@ -238,7 +238,7 @@ return error; } de->inode = inode->i_ino; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); iput(dir); *result = inode; @@ -295,7 +295,7 @@ return error; } de->inode = inode->i_ino; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); iput(dir); iput(inode); @@ -347,7 +347,7 @@ de->inode = dir->i_ino; strcpy(de->name,".."); inode->i_nlink = 2; - dirtify_buffer(dir_block, 1); + mark_buffer_dirty(dir_block, 1); brelse(dir_block); inode->i_mode = S_IFDIR | (mode & 0777 & ~current->umask); if (dir->i_mode & S_ISGID) @@ -361,7 +361,7 @@ return error; } de->inode = inode->i_ino; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); dir->i_nlink++; dir->i_dirt = 1; iput(dir); @@ -469,7 +469,7 @@ if (inode->i_nlink != 2) printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink); de->inode = 0; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); inode->i_nlink=0; inode->i_dirt=1; dir->i_nlink--; @@ -522,7 +522,7 @@ inode->i_nlink=1; } de->inode = 0; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); dir->i_ctime = dir->i_mtime = CURRENT_TIME; dir->i_dirt = 1; inode->i_nlink--; @@ -562,7 +562,7 @@ while (i < 1023 && (c=*(symname++))) name_block->b_data[i++] = c; name_block->b_data[i] = 0; - dirtify_buffer(name_block, 1); + mark_buffer_dirty(name_block, 1); brelse(name_block); inode->i_size = i; inode->i_dirt = 1; @@ -584,7 +584,7 @@ return i; } de->inode = inode->i_ino; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); iput(dir); iput(inode); @@ -621,7 +621,7 @@ return error; } de->inode = oldinode->i_ino; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); iput(dir); oldinode->i_nlink++; @@ -774,11 +774,11 @@ new_inode->i_ctime = CURRENT_TIME; new_inode->i_dirt = 1; } - dirtify_buffer(old_bh, 1); - dirtify_buffer(new_bh, 1); + mark_buffer_dirty(old_bh, 1); + mark_buffer_dirty(new_bh, 1); if (dir_bh) { PARENT_INO(dir_bh->b_data) = new_dir->i_ino; - dirtify_buffer(dir_bh, 1); + mark_buffer_dirty(dir_bh, 1); old_dir->i_nlink--; old_dir->i_dirt = 1; if (new_inode) { diff -u --recursive --new-file v1.1.2/linux/fs/minix/truncate.c linux/fs/minix/truncate.c --- v1.1.2/linux/fs/minix/truncate.c Wed Apr 13 11:33:56 1994 +++ linux/fs/minix/truncate.c Wed Apr 13 11:16:30 1994 @@ -96,7 +96,7 @@ continue; } *ind = 0; - dirtify_buffer(ind_bh, 1); + mark_buffer_dirty(ind_bh, 1); brelse(bh); minix_free_block(inode->i_sb,tmp); } @@ -144,7 +144,7 @@ goto repeat; dind = i+(unsigned short *) dind_bh->b_data; retry |= trunc_indirect(inode,7+512+(i<<9),dind); - dirtify_buffer(dind_bh, 1); + mark_buffer_dirty(dind_bh, 1); } dind = (unsigned short *) dind_bh->b_data; for (i = 0; i < 512; i++) diff -u --recursive --new-file v1.1.2/linux/fs/msdos/fat.c linux/fs/msdos/fat.c --- v1.1.2/linux/fs/msdos/fat.c Wed Apr 13 11:33:56 1994 +++ linux/fs/msdos/fat.c Wed Apr 13 11:16:30 1994 @@ -72,15 +72,15 @@ *p_first = new_value & 0xff; *p_last = (*p_last & 0xf0) | (new_value >> 8); } - dirtify_buffer(bh2, 1); + mark_buffer_dirty(bh2, 1); } - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); for (copy = 1; copy < MSDOS_SB(sb)->fats; copy++) { if (!(c_bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)-> fat_start+(first >> SECTOR_BITS)+MSDOS_SB(sb)-> fat_length*copy,&c_data))) break; memcpy(c_data,data,SECTOR_SIZE); - dirtify_buffer(c_bh, 1); + mark_buffer_dirty(c_bh, 1); if (data != data2 || bh != bh2) { if (!(c_bh2 = msdos_sread(sb->s_dev, MSDOS_SB(sb)->fat_start+(first >> diff -u --recursive --new-file v1.1.2/linux/fs/msdos/file.c linux/fs/msdos/file.c --- v1.1.2/linux/fs/msdos/file.c Wed Apr 13 11:33:56 1994 +++ linux/fs/msdos/file.c Wed Apr 13 11:16:30 1994 @@ -200,7 +200,7 @@ inode->i_size = filp->f_pos; inode->i_dirt = 1; } - dirtify_buffer(bh, 0); + mark_buffer_dirty(bh, 0); brelse(bh); } if (start == buf) diff -u --recursive --new-file v1.1.2/linux/fs/msdos/inode.c linux/fs/msdos/inode.c --- v1.1.2/linux/fs/msdos/inode.c Wed Apr 13 11:33:56 1994 +++ linux/fs/msdos/inode.c Wed Apr 13 11:16:31 1994 @@ -415,7 +415,7 @@ date_unix2dos(inode->i_mtime,&raw_entry->time,&raw_entry->date); raw_entry->time = CT_LE_W(raw_entry->time); raw_entry->date = CT_LE_W(raw_entry->date); - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); } diff -u --recursive --new-file v1.1.2/linux/fs/msdos/misc.c linux/fs/msdos/misc.c --- v1.1.2/linux/fs/msdos/misc.c Wed Apr 13 11:33:56 1994 +++ linux/fs/msdos/misc.c Wed Apr 13 11:16:31 1994 @@ -185,7 +185,7 @@ else memset(data,0,SECTOR_SIZE); } if (bh) { - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); } } diff -u --recursive --new-file v1.1.2/linux/fs/msdos/namei.c linux/fs/msdos/namei.c --- v1.1.2/linux/fs/msdos/namei.c Wed Apr 13 11:33:57 1994 +++ linux/fs/msdos/namei.c Wed Apr 13 11:16:31 1994 @@ -181,7 +181,7 @@ de->start = 0; date_unix2dos(dir->i_mtime,&de->time,&de->date); de->size = 0; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); if ((*result = iget(dir->i_sb,ino)) != NULL) msdos_read_inode(*result); brelse(bh); @@ -350,7 +350,7 @@ dir->i_nlink--; inode->i_dirt = dir->i_dirt = 1; de->name[0] = DELETED_FLAG; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); res = 0; rmdir_done: brelse(bh); @@ -384,7 +384,7 @@ MSDOS_I(inode)->i_busy = 1; inode->i_dirt = dir->i_dirt = 1; de->name[0] = DELETED_FLAG; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); unlink_done: brelse(bh); iput(inode); @@ -429,12 +429,12 @@ MSDOS_I(new_inode)->i_busy = 1; new_inode->i_dirt = 1; new_de->name[0] = DELETED_FLAG; - dirtify_buffer(new_bh, 1); + mark_buffer_dirty(new_bh, 1); iput(new_inode); brelse(new_bh); } memcpy(old_de->name,new_name,MSDOS_NAME); - dirtify_buffer(old_bh, 1); + mark_buffer_dirty(old_bh, 1); if (MSDOS_SB(old_dir->i_sb)->conversion == 'a') /* update binary info */ if ((old_inode = iget(old_dir->i_sb,old_ino)) != NULL) { msdos_read_inode(old_inode); @@ -503,7 +503,7 @@ MSDOS_I(new_inode)->i_busy = 1; new_inode->i_dirt = 1; new_de->name[0] = DELETED_FLAG; - dirtify_buffer(new_bh, 1); + mark_buffer_dirty(new_bh, 1); } memcpy(free_de,old_de,sizeof(struct msdos_dir_entry)); memcpy(free_de->name,new_name,MSDOS_NAME); @@ -526,8 +526,8 @@ cache_inval_inode(old_inode); old_inode->i_dirt = 1; old_de->name[0] = DELETED_FLAG; - dirtify_buffer(old_bh, 1); - dirtify_buffer(free_bh, 1); + mark_buffer_dirty(old_bh, 1); + mark_buffer_dirty(free_bh, 1); if (!exists) iput(free_inode); else { MSDOS_I(new_inode)->i_depend = free_inode; @@ -547,7 +547,7 @@ dotdot_de->start = MSDOS_I(dotdot_inode)->i_start = MSDOS_I(new_dir)->i_start; dotdot_inode->i_dirt = 1; - dirtify_buffer(dotdot_bh, 1); + mark_buffer_dirty(dotdot_bh, 1); old_dir->i_nlink--; new_dir->i_nlink++; /* no need to mark them dirty */ diff -u --recursive --new-file v1.1.2/linux/fs/proc/array.c linux/fs/proc/array.c --- v1.1.2/linux/fs/proc/array.c Thu Mar 31 12:56:13 1994 +++ linux/fs/proc/array.c Wed Apr 13 08:48:46 1994 @@ -465,6 +465,7 @@ } extern int get_module_list(char *); +extern int get_device_list(char *); static int array_read(struct inode * inode, struct file * file,char * buf, int count) { @@ -521,6 +522,9 @@ break; case 17: length = get_kstat(page); + break; + case 18: + length = get_device_list(page); break; default: free_page((unsigned long) page); diff -u --recursive --new-file v1.1.2/linux/fs/proc/root.c linux/fs/proc/root.c --- v1.1.2/linux/fs/proc/root.c Tue Feb 1 09:03:51 1994 +++ linux/fs/proc/root.c Wed Apr 13 09:13:30 1994 @@ -67,6 +67,7 @@ {14,5,"kcore" }, {16,7,"modules" }, {17,4,"stat" }, + {18,7,"devices" }, }; #define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0]))) diff -u --recursive --new-file v1.1.2/linux/fs/sysv/balloc.c linux/fs/sysv/balloc.c --- v1.1.2/linux/fs/sysv/balloc.c Wed Apr 13 11:33:57 1994 +++ linux/fs/sysv/balloc.c Wed Apr 13 11:16:31 1994 @@ -96,7 +96,7 @@ } *flc_count = *sb->sv_sb_flc_count; /* = sb->sv_flc_size */ memcpy(flc_blocks, sb->sv_sb_flc_blocks, *flc_count * sizeof(sysv_zone_t)); - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); bh->b_uptodate = 1; brelse(bh); *sb->sv_sb_flc_count = 0; @@ -117,7 +117,7 @@ bh_data = bh->b_data + ((block & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits); memzero(bh_data, sb->sv_block_size); /* this implies ((struct ..._freelist_chunk *) bh_data)->flc_count = 0; */ - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); bh->b_uptodate = 1; brelse(bh); /* still *sb->sv_sb_flc_count = 0 */ @@ -138,7 +138,7 @@ to_coh_ulong(from_coh_ulong(*sb->sv_sb_total_free_blocks) + 1); else *sb->sv_sb_total_free_blocks = *sb->sv_sb_total_free_blocks + 1; - dirtify_buffer(sb->sv_bh, 1); /* super-block has been modified */ + mark_buffer_dirty(sb->sv_bh, 1); /* super-block has been modified */ sb->s_dirt = 1; /* and needs time stamp */ unlock_super(sb); } @@ -229,7 +229,7 @@ return 0; } memzero(bh_data,sb->sv_block_size); - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); bh->b_uptodate = 1; brelse(bh); if (sb->sv_convert) @@ -237,7 +237,7 @@ to_coh_ulong(from_coh_ulong(*sb->sv_sb_total_free_blocks) - 1); else *sb->sv_sb_total_free_blocks = *sb->sv_sb_total_free_blocks - 1; - dirtify_buffer(sb->sv_bh, 1); /* super-block has been modified */ + mark_buffer_dirty(sb->sv_bh, 1); /* super-block has been modified */ sb->s_dirt = 1; /* and needs time stamp */ unlock_super(sb); return block; @@ -331,7 +331,7 @@ printk("sysv_count_free_blocks: free block count was %d, correcting to %d\n",old_count,count); if (!(sb->s_flags & MS_RDONLY)) { *sb->sv_sb_total_free_blocks = (sb->sv_convert ? to_coh_ulong(count) : count); - dirtify_buffer(sb->sv_bh, 1); /* super-block has been modified */ + mark_buffer_dirty(sb->sv_bh, 1); /* super-block has been modified */ sb->s_dirt = 1; /* and needs time stamp */ } } diff -u --recursive --new-file v1.1.2/linux/fs/sysv/file.c linux/fs/sysv/file.c --- v1.1.2/linux/fs/sysv/file.c Wed Apr 13 11:33:57 1994 +++ linux/fs/sysv/file.c Wed Apr 13 11:16:31 1994 @@ -301,7 +301,7 @@ memcpy_fromfs(p,buf,c); buf += c; bh->b_uptodate = 1; - dirtify_buffer(bh, 0); + mark_buffer_dirty(bh, 0); brelse(bh); } inode->i_mtime = inode->i_ctime = CURRENT_TIME; diff -u --recursive --new-file v1.1.2/linux/fs/sysv/ialloc.c linux/fs/sysv/ialloc.c --- v1.1.2/linux/fs/sysv/ialloc.c Wed Apr 13 11:33:57 1994 +++ linux/fs/sysv/ialloc.c Wed Apr 13 11:16:31 1994 @@ -74,10 +74,10 @@ if (*sb->sv_sb_fic_count < sb->sv_fic_size) sb->sv_sb_fic_inodes[(*sb->sv_sb_fic_count)++] = ino; (*sb->sv_sb_total_free_inodes)++; - dirtify_buffer(sb->sv_bh, 1); /* super-block has been modified */ + mark_buffer_dirty(sb->sv_bh, 1); /* super-block has been modified */ sb->s_dirt = 1; /* and needs time stamp */ memset(raw_inode, 0, sizeof(struct sysv_inode)); - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); unlock_super(sb); brelse(bh); clear_inode(inode); @@ -130,7 +130,7 @@ } /* Now *sb->sv_sb_fic_count > 0. */ ino = sb->sv_sb_fic_inodes[--(*sb->sv_sb_fic_count)]; - dirtify_buffer(sb->sv_bh, 1); /* super-block has been modified */ + mark_buffer_dirty(sb->sv_bh, 1); /* super-block has been modified */ sb->s_dirt = 1; /* and needs time stamp */ inode->i_count = 1; inode->i_nlink = 1; @@ -152,7 +152,7 @@ inode->i_dirt = 1; /* cleared by sysv_write_inode() */ /* That's it. */ (*sb->sv_sb_total_free_inodes)--; - dirtify_buffer(sb->sv_bh, 1); /* super-block has been modified again */ + mark_buffer_dirty(sb->sv_bh, 1); /* super-block has been modified again */ sb->s_dirt = 1; /* and needs time stamp again */ unlock_super(sb); return inode; @@ -191,7 +191,7 @@ printk("sysv_count_free_inodes: free inode count was %d, correcting to %d\n",(short)(*sb->sv_sb_total_free_inodes),count); if (!(sb->s_flags & MS_RDONLY)) { *sb->sv_sb_total_free_inodes = count; - dirtify_buffer(sb->sv_bh, 1); /* super-block has been modified */ + mark_buffer_dirty(sb->sv_bh, 1); /* super-block has been modified */ sb->s_dirt = 1; /* and needs time stamp */ } } diff -u --recursive --new-file v1.1.2/linux/fs/sysv/inode.c linux/fs/sysv/inode.c --- v1.1.2/linux/fs/sysv/inode.c Wed Apr 13 11:33:57 1994 +++ linux/fs/sysv/inode.c Wed Apr 13 11:16:31 1994 @@ -557,7 +557,7 @@ goto repeat; } *p = (sb->sv_convert ? to_coh_ulong(block) : block); - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); *start = result->b_data + ((block & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits); return result; @@ -773,7 +773,7 @@ for (block = 0; block < 10+1+1+1; block++) write3byte(&raw_inode->i_a.i_addb[3*block],inode->u.sysv_i.i_data[block]); inode->i_dirt=0; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); return bh; } diff -u --recursive --new-file v1.1.2/linux/fs/sysv/namei.c linux/fs/sysv/namei.c --- v1.1.2/linux/fs/sysv/namei.c Wed Apr 13 11:33:57 1994 +++ linux/fs/sysv/namei.c Wed Apr 13 11:16:32 1994 @@ -193,7 +193,7 @@ dir->i_mtime = dir->i_ctime = CURRENT_TIME; for (i = 0; i < SYSV_NAMELEN ; i++) de->name[i] = (i < namelen) ? name[i] : 0; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); *res_dir = de; break; } @@ -238,7 +238,7 @@ return error; } de->inode = inode->i_ino; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); iput(dir); *result = inode; @@ -298,7 +298,7 @@ return error; } de->inode = inode->i_ino; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); iput(dir); iput(inode); @@ -349,7 +349,7 @@ de->inode = dir->i_ino; strcpy(de->name,".."); /* rest of de->name is zero, see sysv_new_block */ inode->i_nlink = 2; - dirtify_buffer(dir_block, 1); + mark_buffer_dirty(dir_block, 1); brelse(dir_block); inode->i_mode = S_IFDIR | (mode & 0777 & ~current->umask); if (dir->i_mode & S_ISGID) @@ -363,7 +363,7 @@ return error; } de->inode = inode->i_ino; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); dir->i_nlink++; dir->i_dirt = 1; iput(dir); @@ -473,7 +473,7 @@ if (inode->i_nlink != 2) printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink); de->inode = 0; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); inode->i_nlink=0; inode->i_dirt=1; dir->i_nlink--; @@ -526,7 +526,7 @@ inode->i_nlink=1; } de->inode = 0; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); dir->i_ctime = dir->i_mtime = CURRENT_TIME; dir->i_dirt = 1; inode->i_nlink--; @@ -570,7 +570,7 @@ while (i < sb->sv_block_size_1 && (c = *(symname++))) name_block_data[i++] = c; name_block_data[i] = 0; - dirtify_buffer(name_block, 1); + mark_buffer_dirty(name_block, 1); brelse(name_block); inode->i_size = i; inode->i_dirt = 1; @@ -592,7 +592,7 @@ return i; } de->inode = inode->i_ino; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); iput(dir); iput(inode); @@ -629,7 +629,7 @@ return error; } de->inode = oldinode->i_ino; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); iput(dir); oldinode->i_nlink++; @@ -782,11 +782,11 @@ new_inode->i_ctime = CURRENT_TIME; new_inode->i_dirt = 1; } - dirtify_buffer(old_bh, 1); - dirtify_buffer(new_bh, 1); + mark_buffer_dirty(old_bh, 1); + mark_buffer_dirty(new_bh, 1); if (dir_bh) { PARENT_INO(dir_bh_data) = new_dir->i_ino; - dirtify_buffer(dir_bh, 1); + mark_buffer_dirty(dir_bh, 1); old_dir->i_nlink--; old_dir->i_dirt = 1; if (new_inode) { diff -u --recursive --new-file v1.1.2/linux/fs/sysv/truncate.c linux/fs/sysv/truncate.c --- v1.1.2/linux/fs/sysv/truncate.c Wed Apr 13 11:33:57 1994 +++ linux/fs/sysv/truncate.c Wed Apr 13 11:16:32 1994 @@ -84,7 +84,7 @@ if (!indblock) continue; *ind = 0; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); sysv_free_block(sb,indblock); } for (i = 0; i < sb->sv_ind_per_block; i++) @@ -338,7 +338,7 @@ continue; } *ind = 0; - dirtify_buffer(indbh, 1); + mark_buffer_dirty(indbh, 1); brelse(bh); sysv_free_block(sb,block); } diff -u --recursive --new-file v1.1.2/linux/fs/xiafs/bitmap.c linux/fs/xiafs/bitmap.c --- v1.1.2/linux/fs/xiafs/bitmap.c Wed Apr 13 11:33:57 1994 +++ linux/fs/xiafs/bitmap.c Wed Apr 13 11:16:32 1994 @@ -65,7 +65,7 @@ start_bit=j + (i << 5) + 1; goto repeat; } - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); return j + (i << 5); } @@ -245,7 +245,7 @@ printk("XIA-FS: dev %04x" " block bit %u (0x%x) already cleared (%s %d)\n", sb->s_dev, bit, bit, WHERE_ERR); - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); xiafs_unlock_super(sb, sb->u.xiafs_sb.s_zmap_cached); } @@ -277,7 +277,7 @@ } clear_buf(bh); bh->b_uptodate = 1; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); return tmp; } @@ -305,7 +305,7 @@ printk("XIA-FS: dev %04x" "inode bit %ld (0x%lx) already cleared (%s %d)\n", inode->i_dev, ino, ino, WHERE_ERR); - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); xiafs_unlock_super(sb, sb->u.xiafs_sb.s_imap_cached); } diff -u --recursive --new-file v1.1.2/linux/fs/xiafs/file.c linux/fs/xiafs/file.c --- v1.1.2/linux/fs/xiafs/file.c Wed Apr 13 11:33:58 1994 +++ linux/fs/xiafs/file.c Wed Apr 13 11:16:32 1994 @@ -241,7 +241,7 @@ memcpy_fromfs(cp,buf,c); buf += c; bh->b_uptodate = 1; - dirtify_buffer(bh, 0); + mark_buffer_dirty(bh, 0); brelse(bh); } inode->i_mtime = inode->i_ctime = CURRENT_TIME; diff -u --recursive --new-file v1.1.2/linux/fs/xiafs/inode.c linux/fs/xiafs/inode.c --- v1.1.2/linux/fs/xiafs/inode.c Wed Apr 13 11:33:58 1994 +++ linux/fs/xiafs/inode.c Wed Apr 13 11:16:32 1994 @@ -306,7 +306,7 @@ } *lp = tmp; inode->i_blocks+=2 << XIAFS_ZSHIFT(inode->i_sb); - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); return result; } @@ -466,7 +466,7 @@ | (inode->u.xiafs_i.i_dind_zone & 0xffffff); } inode->i_dirt=0; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); return bh; } diff -u --recursive --new-file v1.1.2/linux/fs/xiafs/namei.c linux/fs/xiafs/namei.c --- v1.1.2/linux/fs/xiafs/namei.c Wed Apr 13 11:33:58 1994 +++ linux/fs/xiafs/namei.c Wed Apr 13 11:16:33 1994 @@ -221,7 +221,7 @@ memcpy(de->d_name, name, namelen); de->d_name[namelen]=0; de->d_name_len=namelen; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); *res_dir = de; if (res_pre) *res_pre = de_pre; @@ -268,7 +268,7 @@ return -ENOSPC; } de->d_ino = inode->i_ino; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); iput(dir); *result = inode; @@ -325,7 +325,7 @@ return -ENOSPC; } de->d_ino = inode->i_ino; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); iput(dir); iput(inode); @@ -375,7 +375,7 @@ de->d_name_len=2; de->d_rec_len=XIAFS_ZSIZE(dir->i_sb)-12; inode->i_nlink = 2; - dirtify_buffer(dir_block, 1); + mark_buffer_dirty(dir_block, 1); brelse(dir_block); inode->i_mode = S_IFDIR | (mode & S_IRWXUGO & ~current->umask); if (dir->i_mode & S_ISGID) @@ -389,7 +389,7 @@ return -ENOSPC; } de->d_ino = inode->i_ino; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); dir->i_nlink++; dir->i_dirt = 1; iput(dir); @@ -518,7 +518,7 @@ if (inode->i_nlink != 2) printk("XIA-FS: empty directory has nlink!=2 (%s %d)\n", WHERE_ERR); xiafs_rm_entry(de, de_pre); - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); inode->i_nlink=0; inode->i_dirt=1; dir->i_nlink--; @@ -566,7 +566,7 @@ inode->i_nlink=1; } xiafs_rm_entry(de, de_pre); - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; dir->i_dirt = 1; inode->i_nlink--; @@ -611,7 +611,7 @@ for (i = 0; i < BLOCK_SIZE-1 && (c=*symname++); i++) name_block->b_data[i] = c; name_block->b_data[i] = 0; - dirtify_buffer(name_block, 1); + mark_buffer_dirty(name_block, 1); brelse(name_block); inode->i_size = i; inode->i_dirt = 1; @@ -624,7 +624,7 @@ return -ENOSPC; } de->d_ino = inode->i_ino; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); iput(dir); iput(inode); @@ -661,7 +661,7 @@ return -ENOSPC; } de->d_ino = oldinode->i_ino; - dirtify_buffer(bh, 1); + mark_buffer_dirty(bh, 1); brelse(bh); iput(dir); oldinode->i_nlink++; @@ -798,11 +798,11 @@ new_inode->i_nlink--; new_inode->i_dirt = 1; } - dirtify_buffer(old_bh, 1); - dirtify_buffer(new_bh, 1); + mark_buffer_dirty(old_bh, 1); + mark_buffer_dirty(new_bh, 1); if (dir_bh) { PARENT_INO(dir_bh->b_data) = new_dir->i_ino; - dirtify_buffer(dir_bh, 1); + mark_buffer_dirty(dir_bh, 1); old_dir->i_nlink--; new_dir->i_nlink++; old_dir->i_dirt = 1; diff -u --recursive --new-file v1.1.2/linux/fs/xiafs/truncate.c linux/fs/xiafs/truncate.c --- v1.1.2/linux/fs/xiafs/truncate.c Wed Apr 13 11:33:58 1994 +++ linux/fs/xiafs/truncate.c Wed Apr 13 11:16:33 1994 @@ -104,7 +104,7 @@ retry = 1; else { *indp = 0; - dirtify_buffer(ind_bh, 1); + mark_buffer_dirty(ind_bh, 1); inode->i_blocks-= 2 << XIAFS_ZSHIFT(inode->i_sb); xiafs_free_zone(inode->i_sb, tmp); } @@ -157,7 +157,7 @@ retry |= trunc_indirect(inode, 8+((1+i)<i_sb)), dindp); - dirtify_buffer(dind_bh, 1); + mark_buffer_dirty(dind_bh, 1); } dindp = (u_long *) dind_bh->b_data; for (i = 0; i < XIAFS_ADDRS_PER_Z(inode->i_sb) && !(*dindp++); i++); diff -u --recursive --new-file v1.1.2/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h --- v1.1.2/linux/include/linux/ext2_fs.h Thu Mar 10 18:48:36 1994 +++ linux/include/linux/ext2_fs.h Wed Apr 13 11:17:49 1994 @@ -390,6 +390,7 @@ extern struct buffer_head * ext2_getblk (struct inode *, long, int, int *); extern struct buffer_head * ext2_bread (struct inode *, int, int, int *); +extern int ext2_getcluster (struct inode * inode, long block); extern void ext2_read_inode (struct inode *); extern void ext2_write_inode (struct inode *); extern void ext2_put_inode (struct inode *); diff -u --recursive --new-file v1.1.2/linux/include/linux/fs.h linux/include/linux/fs.h --- v1.1.2/linux/include/linux/fs.h Wed Apr 13 11:33:58 1994 +++ linux/include/linux/fs.h Wed Apr 13 11:17:49 1994 @@ -28,7 +28,6 @@ #define NR_INODE 2048 /* this should be bigger than NR_FILE */ #define NR_FILE 1024 /* this can well be larger on a larger system */ #define NR_SUPER 32 -#define NR_HASH 997 #define NR_IHASH 131 #define NR_FILE_LOCKS 64 #define BLOCK_SIZE 1024 @@ -138,6 +137,11 @@ unsigned char b_dirt; /* 0-clean,1-dirty */ unsigned char b_lock; /* 0 - ok, 1 -locked */ unsigned char b_req; /* 0 if the buffer has been invalidated */ + unsigned char b_list; /* List that this buffer appears */ + unsigned char b_retain; /* Expected number of times this will + be used. Put on freelist when 0 */ + unsigned long b_flushtime; /* Time when this (dirty) buffer should be written */ + unsigned long b_lru_time; /* Time when this buffer was last used. */ struct wait_queue * b_wait; struct buffer_head * b_prev; /* doubly linked list of hash-queue */ struct buffer_head * b_next; @@ -356,16 +360,41 @@ extern int shrink_buffers(unsigned int priority); +extern void refile_buffer(struct buffer_head * buf); +void set_writetime(struct buffer_head * buf, int flag); + +struct buffer_head ** buffer_pages; + extern int nr_buffers; extern int buffermem; extern int nr_buffer_heads; -/* Once the full cluster diffs are in place, this will be filled out a bit. */ -extern inline void dirtify_buffer(struct buffer_head * bh, int flag) +#define BUF_CLEAN 0 +#define BUF_UNSHARED 1 /* Buffers that were shared but are not any more */ +#define BUF_LOCKED 2 /* Buffers scheduled for write */ +#define BUF_LOCKED1 3 /* Supers, inodes */ +#define BUF_DIRTY 4 /* Dirty buffers, not yet scheduled for write */ +#define BUF_SHARED 5 /* Buffers shared */ +#define NR_LIST 6 + +extern inline void mark_buffer_clean(struct buffer_head * bh) +{ + if(bh->b_dirt) { + bh->b_dirt = 0; + if(bh->b_list == BUF_DIRTY) refile_buffer(bh); + } +} + +extern inline void mark_buffer_dirty(struct buffer_head * bh, int flag) { - bh->b_dirt = 1; + if(!bh->b_dirt) { + bh->b_dirt = 1; + set_writetime(bh, flag); + if(bh->b_list != BUF_DIRTY) refile_buffer(bh); + } } + extern void check_disk_change(dev_t dev); extern void invalidate_inodes(dev_t dev); extern void invalidate_buffers(dev_t dev); @@ -402,6 +431,7 @@ extern struct buffer_head * breada(dev_t dev,int block, int size, unsigned int pos, unsigned int filesize); extern void put_super(dev_t dev); +unsigned long generate_cluster(dev_t dev, int b[], int size); extern dev_t ROOT_DEV; extern void show_buffers(void); diff -u --recursive --new-file v1.1.2/linux/include/linux/mm.h linux/include/linux/mm.h --- v1.1.2/linux/include/linux/mm.h Wed Apr 6 11:39:19 1994 +++ linux/include/linux/mm.h Wed Apr 13 11:17:49 1994 @@ -217,6 +217,7 @@ #define GFP_ATOMIC 0x01 #define GFP_USER 0x02 #define GFP_KERNEL 0x03 +#define GFP_NOBUFFER 0x04 /* vm_ops not present page codes */ diff -u --recursive --new-file v1.1.2/linux/include/linux/sys.h linux/include/linux/sys.h --- v1.1.2/linux/include/linux/sys.h Tue Apr 5 09:00:20 1994 +++ linux/include/linux/sys.h Wed Apr 13 11:17:49 1994 @@ -14,6 +14,7 @@ /* * These are system calls that will be removed at some time * due to newer versions existing.. + * (please be careful - ibcs2 may need some of these). */ #ifdef notdef #define _sys_waitpid _sys_old_syscall /* _sys_wait4 */ @@ -32,6 +33,5 @@ * but have an entry in the table for future expansion.. */ #define _sys_quotactl _sys_ni_syscall -#define _sys_bdflush _sys_ni_syscall #endif diff -u --recursive --new-file v1.1.2/linux/mm/swap.c linux/mm/swap.c --- v1.1.2/linux/mm/swap.c Wed Apr 6 11:48:16 1994 +++ linux/mm/swap.c Wed Apr 13 11:17:49 1994 @@ -470,12 +470,12 @@ #endif -static int try_to_free_page(void) +static int try_to_free_page(int priority) { int i=6; while (i--) { - if (shrink_buffers(i)) + if (priority != GFP_NOBUFFER && shrink_buffers(i)) return 1; if (shm_swap(i)) return 1; @@ -545,6 +545,17 @@ if (!--*map) free_pages_ok(addr, order); restore_flags(flag); + if(*map == 1) { + int j; + struct buffer_head * bh, *tmp; + + bh = buffer_pages[MAP_NR(addr)]; + if(bh) + for(j = 0, tmp = bh; tmp && (!j || tmp != bh); + tmp = tmp->b_this_page, j++) + if(tmp->b_list == BUF_SHARED && tmp->b_dev != 0xffff) + refile_buffer(tmp); + } } return; } @@ -610,7 +621,7 @@ return 0; } restore_flags(flags); - if (priority != GFP_BUFFER && try_to_free_page()) + if (priority != GFP_BUFFER && try_to_free_page(priority)) goto repeat; return 0; }