#
# 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.
# readln prompt default
#
function readln () {
- echo -n "$1"
- IFS='@' read ans </dev/tty || exit 1
- [ -z "$ans" ] && ans=$2
+ if [ "$DEFAULT" = "-d" ]; then
+ echo "$1"
+ ans=$2
+ else
+ echo -n "$1"
+ IFS='@' read ans </dev/tty || exit 1
+ [ -z "$ans" ] && ans=$2
+ fi
+}
+
+#
+# change updates the "config.new" file according to the answer
+#
+# change define old new
+#
+function change () {
+ if [ "$2" != "$3" ]; then
+ sed "s/$1 $2$/$1 $3/" < $CONFIG_NEW > .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
echo " * Automatically generated C config: don't edit" >> $CONFIG_H
echo " */" >> $CONFIG_H
-stack=''
-branch='t'
-
-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
+DEFAULT=$1
+
+. ./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
VERSION = 1
PATCHLEVEL = 1
-SUBLEVEL = 2
+SUBLEVEL = 3
all: Version zImage
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
# 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
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
+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
-*
-* Network device support
-*
+
+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
#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
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
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
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)();
!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;
}
!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;
/* 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
#include <linux/string.h>
#include <linux/ioport.h>
-#define VERSION "$Revision: 5.15 $"
+#define VERSION "$Revision: 5.16 $"
/* START OF USER DEFINABLE OPTIONS */
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[] = {
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
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. */
}
}
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
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;
i >>= 1;
}
+ blocks_per_cluster = PAGE_SIZE / blocksize;
+
block = filp->f_pos >> blocksize_bits;
offset = filp->f_pos & (blocksize-1);
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; i<blocks_per_cluster; i++) cluster_list[i] = block+i;
+ if((block % blocks_per_cluster) == 0)
+ generate_cluster(dev, cluster_list, blocksize);
+ bh = getblk(dev, block, blocksize);
+
+ if (chars != blocksize && !bh->b_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<blocks; i++){
+ if(((i+block) % blocks_per_cluster) == 0) {
+ for(j=0; j<blocks_per_cluster; j++) cluster_list[j] = block+i+j;
+ generate_cluster(dev, cluster_list, blocksize);
+ };
+ bhlist[i] = getblk (dev, block+i, blocksize);
+ if(!bhlist[i]){
+ while(i >= 0) brelse(bhlist[i--]);
+ return written? written: -EIO;
+ };
+ };
+ ll_rw_block(READ, blocks, bhlist);
+ for(i=1; i<blocks; i++) brelse(bhlist[i]);
+
+ };
+ };
+#endif
block++;
if (!bh)
return written?written:-EIO;
p += chars;
buf += chars;
bh->b_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];
else
size = INT_MAX;
+ blocks_per_cluster = PAGE_SIZE / blocksize;
+
if (offset > size)
left = 0;
else
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
uptodate = 1;
while (blocks) {
--blocks;
+#if 1
+ if((block % blocks_per_cluster) == 0) {
+ for(i=0; i<blocks_per_cluster; i++) cluster_list[i] = block+i;
+ generate_cluster(dev, cluster_list, blocksize);
+ }
+#endif
*bhb = getblk(dev, block++, blocksize);
if (*bhb && !(*bhb)->b_uptodate) {
uptodate = 0;
}
/* 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) {
#include <linux/string.h>
#include <linux/locks.h>
#include <linux/errno.h>
+#include <linux/malloc.h>
#include <asm/system.h>
+#include <asm/segment.h>
#include <asm/io.h>
#ifdef CONFIG_SCSI
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 struct buffer_head * hash_table[NR_HASH];
-static struct buffer_head * free_list = NULL;
+static int shrink_specific_buffers(unsigned int priority, int size);
+static int maybe_shrink_lav_buffers(int);
+
+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
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;
}
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;
+ }
}
}
#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)
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;
void set_blocksize(dev_t dev, int size)
{
- int i;
+ int i, nlist;
struct buffer_head * bh, *bhnext;
if (!blksize_size[MAJOR(dev)])
/* 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<NR_LIST; i++){
+ if(i == BUF_DIRTY || i == BUF_SHARED ||
+ nr_buffers_type[i] == 0) {
+ candidate[i] = NULL;
+ buffers[i] = 0;
+ continue;
+ }
+ buffers[i] = nr_buffers_type[i];
+ for (bh = lru_list[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 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; i<NR_LIST; i++){
+ if(!candidate[i]) continue;
+ if(candidate[i]->b_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;
}
/*
* 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)<BADNESS(bh)) {
- bh = tmp;
- if (!BADNESS(tmp))
- break;
- }
-#if 0
- if (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;
/*
* 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
head = bh;
bh->b_data = (char *) (page+offset);
bh->b_size = size;
+ bh->b_dev = 0xffff; /* Flag as unused */
}
return head;
/*
{
struct buffer_head * bh, * tmp, * arr[8];
unsigned long offset;
+ int isize = BUFSIZE_INDEX(size);
int * p;
int block;
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;
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]);
{
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);
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;
}
{
unsigned long page;
struct buffer_head * tmp, * p;
+ int isize = BUFSIZE_INDEX(bh->b_size);
*bhp = bh;
page = (unsigned long) bh->b_data;
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
*
* of 0 means "we'd better get some free pages now".
*/
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; isize<NR_SIZES; isize++){
+ if(isize1 != -1 && isize1 != isize) continue;
+ bh = free_list[isize];
+ if(!bh) continue;
+ for (i=0 ; !i || bh != free_list[isize]; bh = bh->b_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; isize<NR_SIZES; isize++){
+ printk("%5d [%5d]: %7d ", bufferindex_size[isize],
+ buffers_lav[isize], nr_free[isize]);
+ for(nlist = 0; nlist < NR_LIST; nlist++)
+ printk("%7d ", nr_buffers_st[isize][nlist]);
+ printk("\n");
+ }
+}
+
+/*
+ * try_to_reassign() checks if all the buffers on this particular page
+ * are unused, and reassign to a new cluster them if this is true.
+ */
+static inline int try_to_reassign(struct buffer_head * bh, struct buffer_head ** bhp,
+ dev_t dev, unsigned int starting_block)
+{
+ unsigned long page;
+ struct buffer_head * tmp, * p;
+
+ *bhp = bh;
+ page = (unsigned long) bh->b_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.
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<NR_SIZES; isize++){
+ CALC_LOAD(buffers_lav[isize], bdf_prm.b_un.lav_const, buffer_usage[isize]);
+ buffer_usage[isize] = 0;
+ };
+ return 0;
+}
+
+
+/* This is the interface to bdflush. As we get more sophisticated, we can
+ * pass tuning parameters to this "process", to adjust how it behaves. If you
+ * invoke this again after you have done this once, you would simply modify
+ * the tuning parameters. We would want to verify each parameter, however,
+ * to make sure that it is reasonable. */
+
+asmlinkage int sys_bdflush(int func, int data)
+{
+ int i, error;
+ int ndirty;
+ int nlist;
+ int ncount;
+ struct buffer_head * bh, *next;
+
+ if(!suser()) return -EPERM;
+
+ if(func == 1)
+ return sync_old_buffers();
+
+ /* Basically func 0 means start, 1 means read param 1, 2 means write param 1, etc */
+ if(func >= 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:
+ */
{ 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)
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;
}
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;
}
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);
}
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);
}
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);
}
(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);
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;
}
goto repeat;
}
*p = tmp;
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
return result;
}
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;
}
#if 0
dir->i_ctime = CURRENT_TIME;
#endif
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
}
brelse (bh);
bh = NULL;
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;
}
return -ENOSPC;
}
de->inode = inode->i_ino;
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
iput(dir);
*result = inode;
return -ENOSPC;
}
de->inode = inode->i_ino;
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
iput(dir);
iput(inode);
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)
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);
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--;
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;
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;
return -ENOSPC;
}
de->inode = inode->i_ino;
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
iput(dir);
iput(inode);
return -ENOSPC;
}
de->inode = oldinode->i_ino;
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
iput(dir);
oldinode->i_nlink++;
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;
continue;
}
*ind = 0;
- dirtify_buffer(ind_bh, 1);
+ mark_buffer_dirty(ind_bh, 1);
brelse(bh);
ext_free_block(inode->i_sb,tmp);
}
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++)
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++)
}
}
- 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);
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);
}
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;
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];
* 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;
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);
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);
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);
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);
}
"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);
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;
}
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);
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);
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)
{
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)
{
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;
}
*/
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;
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);
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);
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)
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);
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);
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);
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;
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);
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);
}
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) {
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);
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);
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);
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;
}
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, "
#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
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;
}
*/
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);
}
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) {
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) {
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++)
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++)
}
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;
}
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)
}
clear_block(bh->b_data);
bh->b_uptodate = 1;
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
return j;
}
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)
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);
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;
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;
}
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++)
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);
}
/* 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))
}
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))
goto repeat;
}
*p = tmp;
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
return result;
}
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;
}
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;
}
return error;
}
de->inode = inode->i_ino;
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
iput(dir);
*result = inode;
return error;
}
de->inode = inode->i_ino;
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
iput(dir);
iput(inode);
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)
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);
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--;
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--;
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;
return i;
}
de->inode = inode->i_ino;
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
iput(dir);
iput(inode);
return error;
}
de->inode = oldinode->i_ino;
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
iput(dir);
oldinode->i_nlink++;
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) {
continue;
}
*ind = 0;
- dirtify_buffer(ind_bh, 1);
+ mark_buffer_dirty(ind_bh, 1);
brelse(bh);
minix_free_block(inode->i_sb,tmp);
}
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++)
*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 >>
inode->i_size = filp->f_pos;
inode->i_dirt = 1;
}
- dirtify_buffer(bh, 0);
+ mark_buffer_dirty(bh, 0);
brelse(bh);
}
if (start == buf)
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);
}
else memset(data,0,SECTOR_SIZE);
}
if (bh) {
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
}
}
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);
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);
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);
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);
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);
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;
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 */
}
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)
{
case 17:
length = get_kstat(page);
break;
+ case 18:
+ length = get_device_list(page);
+ break;
default:
free_page((unsigned long) page);
return -EBADF;
{14,5,"kcore" },
{16,7,"modules" },
{17,4,"stat" },
+ {18,7,"devices" },
};
#define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0])))
}
*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;
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 */
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 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)
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;
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 */
}
}
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;
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);
}
/* 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;
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;
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 */
}
}
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;
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;
}
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;
}
return error;
}
de->inode = inode->i_ino;
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
iput(dir);
*result = inode;
return error;
}
de->inode = inode->i_ino;
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
iput(dir);
iput(inode);
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)
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);
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--;
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--;
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;
return i;
}
de->inode = inode->i_ino;
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
iput(dir);
iput(inode);
return error;
}
de->inode = oldinode->i_ino;
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
iput(dir);
oldinode->i_nlink++;
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) {
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++)
continue;
}
*ind = 0;
- dirtify_buffer(indbh, 1);
+ mark_buffer_dirty(indbh, 1);
brelse(bh);
sysv_free_block(sb,block);
}
start_bit=j + (i << 5) + 1;
goto repeat;
}
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
return j + (i << 5);
}
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);
}
}
clear_buf(bh);
bh->b_uptodate = 1;
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
return tmp;
}
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);
}
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;
}
*lp = tmp;
inode->i_blocks+=2 << XIAFS_ZSHIFT(inode->i_sb);
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
return result;
}
| (inode->u.xiafs_i.i_dind_zone & 0xffffff);
}
inode->i_dirt=0;
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
return bh;
}
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;
return -ENOSPC;
}
de->d_ino = inode->i_ino;
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
iput(dir);
*result = inode;
return -ENOSPC;
}
de->d_ino = inode->i_ino;
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
iput(dir);
iput(inode);
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)
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);
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--;
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--;
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;
return -ENOSPC;
}
de->d_ino = inode->i_ino;
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
iput(dir);
iput(inode);
return -ENOSPC;
}
de->d_ino = oldinode->i_ino;
- dirtify_buffer(bh, 1);
+ mark_buffer_dirty(bh, 1);
brelse(bh);
iput(dir);
oldinode->i_nlink++;
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;
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);
}
retry |= trunc_indirect(inode,
8+((1+i)<<XIAFS_ADDRS_PER_Z_BITS(inode->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++);
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 *);
#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
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;
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)
{
- bh->b_dirt = 1;
+ 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)
+{
+ 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);
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);
#define GFP_ATOMIC 0x01
#define GFP_USER 0x02
#define GFP_KERNEL 0x03
+#define GFP_NOBUFFER 0x04
/* vm_ops not present page codes */
/*
* 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 */
* but have an entry in the table for future expansion..
*/
#define _sys_quotactl _sys_ni_syscall
-#define _sys_bdflush _sys_ni_syscall
#endif
#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;
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;
}
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;
}