lkml.org 
[lkml]   [1999]   [Jun]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[patch] pagecache-2.3.9-E8, fixes against pre3-2.3.9

Linus,

the attached patch fixes all known pagecache/buffer cache related bugs in
pre3-2.3.9. It contains:

- David's Sparc DMA bugfix and page-uptodate bugfix. [i've modified his
bugfix slightly so that partial reads on 1k filesystems work correctly
too] These fixed the last, nasty 'beyond end of device' bugs.

- i reworked end_buffer_io_async() and mark_buffer_uptodate(), they were
rather redundant. mark_buffer_uptodate() does no more set the page
uptodate - this also speeds up lots of other places. Eg. what
mark_buffer_uptodate() does when called from filesystem drivers is
mostly unnecessery, metadata block's update bits is combined with
unrelated blocks, so setting the page uptodate makes no sense.

this is also a nice performance optimization, mark_buffer_uptodate() is
now nicely inlined into various filesystems - since the 'uptodate'
parameter is almost always constant.

[David also removed the reuse_list (noticed by V Ganesh), and i removed
BH_protected logic, these two were obsolete concepts.]

- to clean up some of the recent ext2fs changes and the ugly interfaces
that resulted, i changed the inode_operations API to have two bmap()
variants:

+ /*
+ * 'reading' variant of bmap. It provides a (supposedly) quick
+ * lookup of already existing blocks within an inode, 0 means
+ * a 'filesystem hole'.
+ */
+ long (*bmap) (struct inode *, long);
+ /*
+ * allocating variant of bmap. Compatible with bmap but doesnt
+ * preserve holes and is usually slower. Can signal out-of-space
+ * or other non-fatal exceptions.
+ */
+ long (*bmap_create) (struct inode *, long, int *, int *);
+
the 'normal', read-side bmap() is fast and can be heavily inlined, a good
example is ext2_bmap().

bmap_create() is a (conceptually) much heavier function, has to deal with
lots of side-effects and thus typically is not inlined and is slower as
well. It also includes fields for error code and 'new block' return codes.
The 'new block' information can be used by the generic block layer to
optimize certain things. [i'll send a separate patch that optimizes the
memset() in block_write_partial_page() and combines it with the
memcpy_from_user()]

this removed the very ugly 'create' parameter of get_fs_block(), and also
decreased the size of the call-chain within the write path and reduced the
number of parameters. block_write_partial|full_page() now depends on
bmap_create() purely - things are visibly nicer now, and the 'internal'
allocation-function-pointer passing is gone, it's now a 'public'
interface.
unfortunately this change broke 'other' filesystems again, so only the
core kernel file objects, swapping, ext2, procfs and NFSfs work. [all
tested]

- to not let yesterday's triple-indirection ext2fs bug happen again, i
cleaned up much of ext2_bmap_create() [formerly ext2_get_block], so it's
now i think much more maintainable. I have tested it with big files and
various workloads. Again i got rid of a couple of unnecessery parameters
and ugly parameter passing.

i've tested these changes and everything is fine now - first time in 4
weeks that i cannot crash my box or corrupt files :)

-- mingo
--- linux/fs/proc/array.c.orig Fri Jun 25 16:04:13 1999
+++ linux/fs/proc/array.c Fri Jun 25 16:48:34 1999
@@ -1520,6 +1520,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
@@ -1571,6 +1572,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/fs/proc/root.c.orig Fri Jun 25 16:05:01 1999
+++ linux/fs/proc/root.c Fri Jun 25 16:48:34 1999
@@ -72,6 +72,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
@@ -98,6 +99,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
@@ -143,6 +145,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
@@ -303,6 +306,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
@@ -491,6 +495,7 @@
proc_self_readlink, /* readlink */
proc_self_follow_link, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
@@ -514,6 +519,7 @@
proc_readlink, /* readlink */
proc_follow_link, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/fs/proc/mem.c.orig Fri Jun 25 16:42:59 1999
+++ linux/fs/proc/mem.c Fri Jun 25 16:48:34 1999
@@ -337,6 +337,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/fs/proc/base.c.orig Fri Jun 25 14:05:57 1999
+++ linux/fs/proc/base.c Fri Jun 25 16:48:34 1999
@@ -46,6 +46,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/fs/proc/fd.c.orig Fri Jun 25 14:05:57 1999
+++ linux/fs/proc/fd.c Fri Jun 25 16:48:34 1999
@@ -52,6 +52,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/fs/proc/generic.c.orig Fri Jun 25 14:05:57 1999
+++ linux/fs/proc/generic.c Fri Jun 25 16:48:35 1999
@@ -61,6 +61,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
@@ -87,6 +88,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/fs/proc/kmsg.c.orig Fri Jun 25 14:05:57 1999
+++ linux/fs/proc/kmsg.c Fri Jun 25 16:48:35 1999
@@ -73,6 +73,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/fs/proc/link.c.orig Fri Jun 25 14:05:57 1999
+++ linux/fs/proc/link.c Fri Jun 25 16:48:35 1999
@@ -50,6 +50,7 @@
proc_readlink, /* readlink */
proc_follow_link, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/fs/proc/net.c.orig Fri Jun 25 14:05:57 1999
+++ linux/fs/proc/net.c Fri Jun 25 16:48:35 1999
@@ -114,6 +114,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/fs/proc/omirr.c.orig Fri Jun 25 14:05:57 1999
+++ linux/fs/proc/omirr.c Fri Jun 25 16:48:35 1999
@@ -290,6 +290,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/fs/proc/openpromfs.c.orig Fri Jun 25 14:05:57 1999
+++ linux/fs/proc/openpromfs.c Fri Jun 25 16:48:35 1999
@@ -578,6 +578,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
@@ -615,6 +616,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
@@ -652,6 +654,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/fs/proc/proc_devtree.c.orig Fri Jun 25 14:05:57 1999
+++ linux/fs/proc/proc_devtree.c Fri Jun 25 16:48:35 1999
@@ -58,6 +58,7 @@
devtree_readlink, /* readlink */
devtree_follow_link, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/fs/proc/scsi.c.orig Fri Jun 25 14:05:57 1999
+++ linux/fs/proc/scsi.c Fri Jun 25 16:48:35 1999
@@ -72,6 +72,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/fs/proc/sysvipc.c.orig Fri Jun 25 14:05:57 1999
+++ linux/fs/proc/sysvipc.c Fri Jun 25 16:48:35 1999
@@ -131,6 +131,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/fs/nfs/dir.c.orig Fri Jun 25 14:05:22 1999
+++ linux/fs/nfs/dir.c Fri Jun 25 16:48:35 1999
@@ -79,6 +79,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/fs/nfs/symlink.c.orig Fri Jun 25 14:05:28 1999
+++ linux/fs/nfs/symlink.c Fri Jun 25 16:48:35 1999
@@ -44,6 +44,7 @@
nfs_readlink, /* readlink */
nfs_follow_link, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/fs/nfs/file.c.orig Fri Jun 25 10:42:40 1999
+++ linux/fs/nfs/file.c Fri Jun 25 16:48:35 1999
@@ -72,6 +72,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
nfs_readpage, /* readpage */
nfs_writepage, /* writepage */
NULL, /* flushpage */
@@ -167,7 +168,7 @@
* If the writer ends up delaying the write, the writer needs to
* increment the page use counts until he is done with the page.
*/
-static long nfs_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+static int nfs_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
{
long status;

--- linux/fs/ext2/inode.c.orig Fri Jun 25 09:32:31 1999
+++ linux/fs/ext2/inode.c Fri Jun 25 16:48:35 1999
@@ -130,11 +130,11 @@
}


-int ext2_bmap (struct inode * inode, int block)
+long ext2_bmap (struct inode * inode, long block)
{
int i, ret;
- int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
- int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
+ int ptrs = EXT2_ADDR_PER_BLOCK(inode->i_sb);
+ int ptrs_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);

ret = 0;
lock_kernel();
@@ -142,9 +142,9 @@
ext2_warning (inode->i_sb, "ext2_bmap", "block < 0");
goto out;
}
- if (block >= EXT2_NDIR_BLOCKS + addr_per_block +
- (1 << (addr_per_block_bits * 2)) +
- ((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
+ if (block >= EXT2_NDIR_BLOCKS + ptrs +
+ (1 << (ptrs_bits * 2)) +
+ ((1 << (ptrs_bits * 2)) << ptrs_bits)) {
ext2_warning (inode->i_sb, "ext2_bmap", "block > big");
goto out;
}
@@ -153,7 +153,7 @@
goto out;
}
block -= EXT2_NDIR_BLOCKS;
- if (block < addr_per_block) {
+ if (block < ptrs) {
i = inode_bmap (inode, EXT2_IND_BLOCK);
if (!i)
goto out;
@@ -161,123 +161,64 @@
inode->i_sb->s_blocksize), block);
goto out;
}
- block -= addr_per_block;
- if (block < (1 << (addr_per_block_bits * 2))) {
+ block -= ptrs;
+ if (block < (1 << (ptrs_bits * 2))) {
i = inode_bmap (inode, EXT2_DIND_BLOCK);
if (!i)
goto out;
i = block_bmap (bread (inode->i_dev, i,
inode->i_sb->s_blocksize),
- block >> addr_per_block_bits);
+ block >> ptrs_bits);
if (!i)
goto out;
ret = block_bmap (bread (inode->i_dev, i,
inode->i_sb->s_blocksize),
- block & (addr_per_block - 1));
+ block & (ptrs - 1));
goto out;
}
- block -= (1 << (addr_per_block_bits * 2));
+ block -= (1 << (ptrs_bits * 2));
i = inode_bmap (inode, EXT2_TIND_BLOCK);
if (!i)
goto out;
i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- block >> (addr_per_block_bits * 2));
+ block >> (ptrs_bits * 2));
if (!i)
goto out;
i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- (block >> addr_per_block_bits) & (addr_per_block - 1));
+ (block >> ptrs_bits) & (ptrs - 1));
if (!i)
goto out;
ret = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- block & (addr_per_block - 1));
+ block & (ptrs - 1));
out:
unlock_kernel();
return ret;
}

-int ext2_bmap_create (struct inode * inode, int block)
-{
- int i;
- int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
- int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
-
- if (block < 0) {
- ext2_warning (inode->i_sb, "ext2_bmap", "block < 0");
- return 0;
- }
- if (block >= EXT2_NDIR_BLOCKS + addr_per_block +
- (1 << (addr_per_block_bits * 2)) +
- ((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
- ext2_warning (inode->i_sb, "ext2_bmap", "block > big");
- return 0;
- }
- if (block < EXT2_NDIR_BLOCKS)
- return inode_bmap (inode, block);
- block -= EXT2_NDIR_BLOCKS;
- if (block < addr_per_block) {
- i = inode_bmap (inode, EXT2_IND_BLOCK);
- if (!i)
- return 0;
- return block_bmap (bread (inode->i_dev, i,
- inode->i_sb->s_blocksize), block);
- }
- block -= addr_per_block;
- if (block < (1 << (addr_per_block_bits * 2))) {
- i = inode_bmap (inode, EXT2_DIND_BLOCK);
- if (!i)
- return 0;
- i = block_bmap (bread (inode->i_dev, i,
- inode->i_sb->s_blocksize),
- block >> addr_per_block_bits);
- if (!i)
- return 0;
- return block_bmap (bread (inode->i_dev, i,
- inode->i_sb->s_blocksize),
- block & (addr_per_block - 1));
- }
- block -= (1 << (addr_per_block_bits * 2));
- i = inode_bmap (inode, EXT2_TIND_BLOCK);
- if (!i)
- return 0;
- i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- block >> (addr_per_block_bits * 2));
- if (!i)
- return 0;
- i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- (block >> addr_per_block_bits) & (addr_per_block - 1));
- if (!i)
- return 0;
- return block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- block & (addr_per_block - 1));
-}
-
static struct buffer_head * inode_getblk (struct inode * inode, int nr,
- int create, int new_block, int * err, int metadata,
- int *phys_block, int *created)
+ int new_block, int * err, int metadata, long *phys, int *new)
{
u32 * p;
int tmp, goal = 0;
struct buffer_head * result;
- int blocks = inode->i_sb->s_blocksize / 512;
+ int blocksize = inode->i_sb->s_blocksize;

p = inode->u.ext2_i.i_data + nr;
repeat:
tmp = le32_to_cpu(*p);
if (tmp) {
if (metadata) {
- struct buffer_head * result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
+ result = getblk (inode->i_dev, tmp, blocksize);
if (tmp == le32_to_cpu(*p))
return result;
brelse (result);
goto repeat;
} else {
- *phys_block = tmp;
+ *phys = tmp;
return NULL;
}
}
*err = -EFBIG;
- if (!create)
- goto dont_create;

/* Check file limits.. */
{
@@ -286,7 +227,6 @@
limit >>= EXT2_BLOCK_SIZE_BITS(inode->i_sb);
if (new_block >= limit) {
send_sig(SIGXFSZ, current, 0);
-dont_create:
*err = -EFBIG;
return NULL;
}
@@ -314,34 +254,41 @@
ext2_debug ("goal = %d.\n", goal);

tmp = ext2_alloc_block (inode, goal, err);
- if (!tmp)
+ if (!tmp) {
+ *err = -ENOSPC;
return NULL;
+ }
if (metadata) {
- result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
+ result = getblk (inode->i_dev, tmp, blocksize);
if (*p) {
ext2_free_blocks (inode, tmp, 1);
brelse (result);
goto repeat;
}
- memset(result->b_data, 0, inode->i_sb->s_blocksize);
+ memset(result->b_data, 0, blocksize);
mark_buffer_uptodate(result, 1);
mark_buffer_dirty(result, 1);
} else {
if (*p) {
+ /*
+ * Nobody is allowed to change block allocation
+ * state under us:
+ */
+ BUG();
ext2_free_blocks (inode, tmp, 1);
goto repeat;
}
- *phys_block = tmp;
+ *phys = tmp;
result = NULL;
*err = 0;
- *created = 1;
+ *new = 1;
}
*p = cpu_to_le32(tmp);

inode->u.ext2_i.i_next_alloc_block = new_block;
inode->u.ext2_i.i_next_alloc_goal = tmp;
inode->i_ctime = CURRENT_TIME;
- inode->i_blocks += blocks;
+ inode->i_blocks += blocksize/512;
if (IS_SYNC(inode) || inode->u.ext2_i.i_osync)
ext2_sync_inode (inode);
else
@@ -358,24 +305,23 @@
* NULL return in the data case is mandatory.
*/
static struct buffer_head * block_getblk (struct inode * inode,
- struct buffer_head * bh, int nr, int create, int blocksize,
- int new_block, int * err, int metadata, int *phys_block, int *created)
+ struct buffer_head * bh, int nr,
+ int new_block, int * err, int metadata, long *phys, int *new)
{
int tmp, goal = 0;
u32 * p;
struct buffer_head * result;
- int blocks = inode->i_sb->s_blocksize / 512;
+ int blocksize = inode->i_sb->s_blocksize;
unsigned long limit;
-
+
+ result = NULL;
if (!bh)
- return NULL;
+ goto out;
if (!buffer_uptodate(bh)) {
ll_rw_block (READ, 1, &bh);
wait_on_buffer (bh);
- if (!buffer_uptodate(bh)) {
- brelse (bh);
- return NULL;
- }
+ if (!buffer_uptodate(bh))
+ goto out;
}
p = (u32 *) bh->b_data + nr;
repeat:
@@ -383,31 +329,24 @@
if (tmp) {
if (metadata) {
result = getblk (bh->b_dev, tmp, blocksize);
- if (tmp == le32_to_cpu(*p)) {
- brelse (bh);
- return result;
- }
+ if (tmp == le32_to_cpu(*p))
+ goto out;
brelse (result);
goto repeat;
} else {
- *phys_block = tmp;
- brelse (bh);
- return NULL;
+ *phys = tmp;
+ /* result == NULL */
+ goto out;
}
}
*err = -EFBIG;
- if (!create) {
- brelse (bh);
- return NULL;
- }

limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
if (limit < RLIM_INFINITY) {
limit >>= EXT2_BLOCK_SIZE_BITS(inode->i_sb);
if (new_block >= limit) {
- brelse (bh);
send_sig(SIGXFSZ, current, 0);
- return NULL;
+ goto out;
}
}

@@ -424,10 +363,8 @@
goal = bh->b_blocknr;
}
tmp = ext2_alloc_block (inode, goal, err);
- if (!tmp) {
- brelse (bh);
- return NULL;
- }
+ if (!tmp)
+ goto out;
if (metadata) {
result = getblk (bh->b_dev, tmp, blocksize);
if (*p) {
@@ -439,10 +376,8 @@
mark_buffer_uptodate(result, 1);
mark_buffer_dirty(result, 1);
} else {
- *phys_block = tmp;
- result = NULL;
- *err = 0;
- *created = 1;
+ *phys = tmp;
+ *new = 1;
}
if (*p) {
ext2_free_blocks (inode, tmp, 1);
@@ -456,116 +391,152 @@
wait_on_buffer (bh);
}
inode->i_ctime = CURRENT_TIME;
- inode->i_blocks += blocks;
+ inode->i_blocks += blocksize/512;
mark_inode_dirty(inode);
inode->u.ext2_i.i_next_alloc_block = new_block;
inode->u.ext2_i.i_next_alloc_goal = tmp;
+ *err = 0;
+out:
brelse (bh);
return result;
}

-int ext2_getblk_block (struct inode * inode, long block,
- int create, int * err, int * created)
+long ext2_bmap_create (struct inode *inode, long iblock, int *err, int *new)
{
- struct buffer_head * bh, *tmp;
- unsigned long b;
- unsigned long addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
- int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
- int phys_block, ret;
+ int ret;
+ struct buffer_head *bh;
+ unsigned long ptr, phys;
+ /*
+ * block pointers per block
+ */
+ unsigned long ptrs = EXT2_ADDR_PER_BLOCK(inode->i_sb);
+ int ptrs_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
+ const int direct_blocks = EXT2_NDIR_BLOCKS,
+ indirect_blocks = ptrs,
+ double_blocks = (1 << (ptrs_bits * 2)),
+ triple_blocks = (1 << (ptrs_bits * 3));

- lock_kernel();
- ret = 0;
*err = -EIO;
- if (block < 0) {
- ext2_warning (inode->i_sb, "ext2_getblk", "block < 0");
- goto abort;
- }
- if (block > EXT2_NDIR_BLOCKS + addr_per_block +
- (1 << (addr_per_block_bits * 2)) +
- ((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
- ext2_warning (inode->i_sb, "ext2_getblk", "block > big");
- goto abort;
- }
+ *new = 0;
+ ret = 0;
+ bh = NULL;
+
+ lock_kernel();
+
+ if (iblock < 0)
+ goto abort_negative;
+ if (iblock > direct_blocks + indirect_blocks +
+ double_blocks + triple_blocks)
+ goto abort_too_big;
+
/*
* If this is a sequential block allocation, set the next_alloc_block
* to this block now so that all the indblock and data block
* allocations use the same goal zone
*/

- ext2_debug ("block %lu, next %lu, goal %lu.\n", block,
+ ext2_debug ("block %lu, next %lu, goal %lu.\n", iblock,
inode->u.ext2_i.i_next_alloc_block,
inode->u.ext2_i.i_next_alloc_goal);

- if (block == inode->u.ext2_i.i_next_alloc_block + 1) {
+ if (iblock == inode->u.ext2_i.i_next_alloc_block + 1) {
inode->u.ext2_i.i_next_alloc_block++;
inode->u.ext2_i.i_next_alloc_goal++;
}

- *err = 0; // -ENOSPC;
- b = block;
- *created = 0;
- if (block < EXT2_NDIR_BLOCKS) {
- /*
- * data page.
- */
- tmp = inode_getblk (inode, block, create, b,
- err, 0, &phys_block, created);
- goto out;
- }
- block -= EXT2_NDIR_BLOCKS;
- if (block < addr_per_block) {
- bh = inode_getblk (inode, EXT2_IND_BLOCK, create, b, err, 1, NULL, NULL);
- tmp = block_getblk (inode, bh, block, create,
- inode->i_sb->s_blocksize, b, err, 0, &phys_block, created);
- goto out;
- }
- block -= addr_per_block;
- if (block < (1 << (addr_per_block_bits * 2))) {
- bh = inode_getblk (inode, EXT2_DIND_BLOCK, create, b, err, 1, NULL, NULL);
- bh = block_getblk (inode, bh, block >> addr_per_block_bits,
- create, inode->i_sb->s_blocksize, b, err, 1, NULL, NULL);
- tmp = block_getblk (inode, bh, block & (addr_per_block - 1),
- create, inode->i_sb->s_blocksize, b, err, 0, &phys_block, created);
- goto out;
- }
- block -= (1 << (addr_per_block_bits * 2));
- bh = inode_getblk (inode, EXT2_TIND_BLOCK, create, b, err, 1, NULL,NULL);
- bh = block_getblk (inode, bh, block >> (addr_per_block_bits * 2),
- create, inode->i_sb->s_blocksize, b, err, 1, NULL,NULL);
- bh = block_getblk (inode, bh, (block >> addr_per_block_bits) &
- (addr_per_block - 1), create, inode->i_sb->s_blocksize,
- b, err, 1, NULL,NULL);
- tmp = block_getblk (inode, bh, block & (addr_per_block - 1), create,
- inode->i_sb->s_blocksize, b, err, 0, &phys_block, created);
+ *err = 0;
+ ptr = iblock;
+
+ /*
+ * ok, these macros clean the logic up a bit and make
+ * it much more readable:
+ */
+#define GET_INODE_DATABLOCK(x) \
+ inode_getblk(inode, x, iblock, err, 0, &phys, new)
+#define GET_INODE_PTR(x) \
+ inode_getblk(inode, x, iblock, err, 1, NULL, NULL)
+#define GET_INDIRECT_DATABLOCK(x) \
+ block_getblk (inode, bh, x, iblock, err, 0, &phys, new);
+#define GET_INDIRECT_PTR(x) \
+ block_getblk (inode, bh, x, iblock, err, 1, NULL, NULL);
+
+ if (ptr < direct_blocks) {
+ bh = GET_INODE_DATABLOCK(ptr);
+ goto out;
+ }
+ ptr -= direct_blocks;
+ if (ptr < indirect_blocks) {
+ bh = GET_INODE_PTR(EXT2_IND_BLOCK);
+ goto get_indirect;
+ }
+ ptr -= indirect_blocks;
+ if (ptr < double_blocks) {
+ bh = GET_INODE_PTR(EXT2_DIND_BLOCK);
+ goto get_double;
+ }
+ ptr -= double_blocks;
+ bh = GET_INODE_PTR(EXT2_TIND_BLOCK);
+ bh = GET_INDIRECT_PTR(ptr >> (ptrs_bits * 2));
+get_double:
+ bh = GET_INDIRECT_PTR((ptr >> ptrs_bits) & (ptrs - 1));
+get_indirect:
+ bh = GET_INDIRECT_DATABLOCK(ptr & (ptrs - 1));
+
+#undef GET_INODE_DATABLOCK
+#undef GET_INODE_PTR
+#undef GET_INDIRECT_DATABLOCK
+#undef GET_INDIRECT_PTR

out:
- if (!phys_block)
+ if (bh)
+ BUG(); // temporary debugging check
+ if (*err) {
+ BUG();
goto abort;
- if (*err)
+ }
+ if (!phys) {
+ BUG();
goto abort;
- ret = phys_block;
+ }
+ ret = phys;
abort:
unlock_kernel();
return ret;
+
+abort_negative:
+ ext2_warning (inode->i_sb, "ext2_bmap_create", "block < 0");
+ goto abort;
+
+abort_too_big:
+ ext2_warning (inode->i_sb, "ext2_bmap_create", "block > big");
+ goto abort;
}

struct buffer_head * ext2_getblk (struct inode * inode, long block,
int create, int * err)
{
struct buffer_head *tmp = NULL;
- int phys_block;
- int created;
-
- phys_block = ext2_getblk_block (inode, block, create, err, &created);
+ long phys;
+ int new = 0;

- if (phys_block) {
- tmp = getblk (inode->i_dev, phys_block, inode->i_sb->s_blocksize);
- if (created) {
+ if (create) {
+ phys = ext2_bmap_create (inode, block, err, &new);
+ if (*err)
+ goto out;
+ } else {
+ phys = ext2_bmap (inode, block);
+ *err = 0;
+ }
+
+ if (phys) {
+ tmp = getblk (inode->i_dev, phys, inode->i_sb->s_blocksize);
+ if (new) {
memset(tmp->b_data, 0, inode->i_sb->s_blocksize);
mark_buffer_uptodate(tmp, 1);
mark_buffer_dirty(tmp, 1);
}
}
+out:
return tmp;
}

--- linux/fs/ext2/file.c.orig Fri Jun 25 10:36:59 1999
+++ linux/fs/ext2/file.c Fri Jun 25 16:48:35 1999
@@ -37,7 +37,6 @@
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))

-static int ext2_writepage (struct file * file, struct page * page);
static long long ext2_file_lseek(struct file *, long long, int);
#if BITS_PER_LONG < 64
static int ext2_open_file (struct inode *, struct file *);
@@ -106,60 +105,16 @@
}
}

-static int ext2_get_block(struct inode *inode, unsigned long block, struct buffer_head *bh, int update)
-{
- if (!bh->b_blocknr) {
- int error, created;
- unsigned long blocknr;
-
- blocknr = ext2_getblk_block(inode, block, 1, &error, &created);
- if (!blocknr) {
- if (!error)
- error = -ENOSPC;
- return error;
- }
-
- bh->b_dev = inode->i_dev;
- bh->b_blocknr = blocknr;
-
- if (!update)
- return 0;
-
- if (created) {
- memset(bh->b_data, 0, bh->b_size);
- set_bit(BH_Uptodate, &bh->b_state);
- return 0;
- }
- }
-
- if (!update)
- return 0;
-
- lock_kernel();
- ll_rw_block(READ, 1, &bh);
- wait_on_buffer(bh);
- unlock_kernel();
-
- return buffer_uptodate(bh) ? 0 : -EIO;
-}
-
-static int ext2_writepage (struct file * file, struct page * page)
-{
- return block_write_full_page(file, page, ext2_get_block);
-}
-
-static long ext2_write_one_page (struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
-{
- return block_write_partial_page(file, page, offset, bytes, buf, ext2_get_block);
-}
-
/*
* Write to a file (through the page cache).
*/
static ssize_t
ext2_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
- ssize_t retval = generic_file_write(file, buf, count, ppos, ext2_write_one_page);
+ ssize_t retval;
+
+ retval = generic_file_write(file, buf, count,
+ ppos, block_write_partial_page);
if (retval > 0) {
struct inode *inode = file->f_dentry->d_inode;
remove_suid(inode);
@@ -233,8 +188,9 @@
NULL, /* readlink */
NULL, /* follow_link */
ext2_bmap, /* bmap */
+ ext2_bmap_create, /* bmap */
block_read_full_page, /* readpage */
- ext2_writepage, /* writepage */
+ block_write_full_page, /* writepage */
block_flushpage, /* flushpage */
ext2_truncate, /* truncate */
ext2_permission, /* permission */
--- linux/fs/ext2/dir.c.orig Fri Jun 25 14:12:39 1999
+++ linux/fs/ext2/dir.c Fri Jun 25 16:48:35 1999
@@ -68,6 +68,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/fs/ext2/symlink.c.orig Fri Jun 25 14:12:44 1999
+++ linux/fs/ext2/symlink.c Fri Jun 25 16:48:35 1999
@@ -44,6 +44,7 @@
ext2_readlink, /* readlink */
ext2_follow_link, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/fs/buffer.c.orig Fri Jun 25 14:11:36 1999
+++ linux/fs/buffer.c Fri Jun 25 16:48:35 1999
@@ -71,7 +71,6 @@
static kmem_cache_t *bh_cachep;

static struct buffer_head * unused_list = NULL;
-static struct buffer_head * reuse_list = NULL;
static DECLARE_WAIT_QUEUE_HEAD(buffer_wait);

static int nr_buffers = 0;
@@ -411,7 +410,6 @@
if (bh->b_count)
continue;
bh->b_flushtime = 0;
- clear_bit(BH_Protected, &bh->b_state);
clear_bit(BH_Uptodate, &bh->b_state);
clear_bit(BH_Dirty, &bh->b_state);
clear_bit(BH_Req, &bh->b_state);
@@ -703,31 +701,28 @@
struct page *page;
int free;

- mark_buffer_uptodate(bh, uptodate);
-
- /* This is a temporary buffer used for page I/O. */
page = mem_map + MAP_NR(bh->b_data);
-
+ mark_buffer_uptodate(bh, uptodate);
if (!uptodate)
SetPageError(page);

+ /* This is a temporary buffer used for page I/O. */
+
/*
* Be _very_ careful from here on. Bad things can happen if
* two buffer heads end IO at almost the same time and both
* decide that the page is now completely done.
*
- * Async buffer_heads are here only as labels for IO, and get
- * thrown away once the IO for this page is complete. IO is
- * deemed complete once all buffers have been visited
- * (b_count==0) and are now unlocked. We must make sure that
- * only the _last_ buffer that decrements its count is the one
- * that free's the page..
+ * IO here is deemed complete once all asynchron buffers have
+ * gone unused. (note that an asynchron buffer can go synchron
+ * by getting dirtied)
*/
spin_lock_irqsave(&page_uptodate_lock, flags);
unlock_buffer(bh);
+ bh->b_count--;
tmp = bh->b_this_page;
while (tmp != bh) {
- if (buffer_locked(tmp))
+ if ((tmp->b_end_io == end_buffer_io_async) && tmp->b_count)
goto still_busy;
tmp = tmp->b_this_page;
}
@@ -918,6 +913,7 @@
return;
}
printk("VFS: brelse: Trying to free free buffer\n");
+ BUG();
}

/*
@@ -1042,35 +1038,6 @@
unused_list = bh;
}

-/*
- * We can't put completed temporary IO buffer_heads directly onto the
- * unused_list when they become unlocked, since the device driver
- * end_request routines still expect access to the buffer_head's
- * fields after the final unlock. So, the device driver puts them on
- * the reuse_list instead once IO completes, and we recover these to
- * the unused_list here.
- *
- * Note that we don't do a wakeup here, but return a flag indicating
- * whether we got any buffer heads. A task ready to sleep can check
- * the returned value, and any tasks already sleeping will have been
- * awakened when the buffer heads were added to the reuse list.
- */
-static inline int recover_reusable_buffer_heads(void)
-{
- struct buffer_head *head = xchg(&reuse_list, NULL);
- int found = 0;
-
- if (head) {
- do {
- struct buffer_head *bh = head;
- head = head->b_next_free;
- put_unused_buffer_head(bh);
- } while (head);
- found = 1;
- }
- return found;
-}
-
/*
* Reserve NR_RESERVED buffer heads for async IO requests to avoid
* no-buffer-head deadlock. Return NULL on failure; waiting for
@@ -1080,7 +1047,6 @@
{
struct buffer_head * bh;

- recover_reusable_buffer_heads();
if (nr_unused_buffer_heads > NR_RESERVED) {
bh = unused_list;
unused_list = bh->b_next_free;
@@ -1204,8 +1170,10 @@
*/
add_wait_queue(&buffer_wait, &wait);
current->state = TASK_UNINTERRUPTIBLE;
- if (!recover_reusable_buffer_heads())
+ if (nr_unused_buffer_heads < MAX_BUF_PER_PAGE) {
+ current->policy |= SCHED_YIELD;
schedule();
+ }
remove_wait_queue(&buffer_wait, &wait);
current->state = TASK_RUNNING;
goto try_again;
@@ -1344,7 +1312,7 @@
* block_write_full_page() is SMP-safe - currently it's still
* being called with the kernel lock held, but the code is ready.
*/
-int block_write_full_page (struct file *file, struct page *page, fs_getblock_t fs_get_block)
+int block_write_full_page (struct file *file, struct page *page)
{
struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
@@ -1381,12 +1349,18 @@
* decisions (block #0 may actually be a valid block)
*/
bh->b_end_io = end_buffer_io_sync;
- if (!buffer_uptodate(bh)) {
- err = fs_get_block(inode, block, bh, 0);
+ if (!buffer_allocated(bh)) {
+ int phys, new = 0;
+ err = -EIO;
+ phys = inode->i_op->bmap_create(inode, block,
+ &err,&new);
if (err)
goto out;
+ bh->b_dev = inode->i_dev;
+ bh->b_blocknr = phys;
+ bh->b_state |= (1UL << BH_Allocated); /* safe */
}
- set_bit(BH_Uptodate, &bh->b_state);
+ bh->b_state |= (1UL << BH_Uptodate); /* safe */
atomic_mark_buffer_dirty(bh,0);

bh = bh->b_this_page;
@@ -1400,7 +1374,7 @@
return err;
}

-int block_write_partial_page (struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf, fs_getblock_t fs_get_block)
+int block_write_partial_page (struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
{
struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
@@ -1470,13 +1444,44 @@
* not going to fill it completely.
*/
bh->b_end_io = end_buffer_io_sync;
- if (!buffer_uptodate(bh)) {
- int update = start_offset || (end_bytes && (i == end_block));

- err = fs_get_block(inode, block, bh, update);
- if (err)
+ if (!buffer_allocated(bh)) {
+ int phys, new = 0;
+ err = -EIO;
+ phys = inode->i_op->bmap_create(inode, block,
+ &err,&new);
+ if (!phys)
goto out;
- }
+ bh->b_dev = inode->i_dev;
+ bh->b_blocknr = phys;
+ bh->b_state |= (1UL<<BH_Allocated);
+ /*
+ * if partially written block which has contents on
+ * disk, then we have to read it first.
+ * We also rely on the fact that filesystem holes
+ * cannot be written.
+ */
+ if (start_offset || (end_bytes && (i == end_block))) {
+ if (new) {
+ memset(bh->b_data, 0, bh->b_size);
+ } else {
+ bh->b_state = 0;
+ ll_rw_block(READ, 1, &bh);
+ lock_kernel();
+ wait_on_buffer(bh);
+ unlock_kernel();
+ err = -EIO;
+ if (!buffer_uptodate(bh))
+ goto out;
+ }
+ }
+ } else {
+ /*
+ * block already exists, just mark it uptodate:
+ */
+ bh->b_end_io = end_buffer_io_sync;
+ }
+ bh->b_state |= (1UL << BH_Uptodate); /* safe */

err = -EFAULT;
len = blocksize;
@@ -1586,6 +1591,7 @@
BUG();
if (!buffer_uptodate(bh)) {
arr[nr++] = bh;
+ bh->b_count++;
}
}
} else { /* WRITE */
@@ -1600,6 +1606,7 @@
set_bit(BH_Uptodate, &bh->b_state);
set_bit(BH_Dirty, &bh->b_state);
arr[nr++] = bh;
+ bh->b_count++;
}
bh = bh->b_this_page;
} while (bh != head);
@@ -1622,30 +1629,7 @@
}

/*
- * This is called by end_request() when I/O has completed.
- */
-void mark_buffer_uptodate(struct buffer_head * bh, int on)
-{
- if (on) {
- struct buffer_head *tmp = bh;
- struct page *page;
- set_bit(BH_Uptodate, &bh->b_state);
- /* If a page has buffers and all these buffers are uptodate,
- * then the page is uptodate. */
- do {
- if (!test_bit(BH_Uptodate, &tmp->b_state))
- return;
- tmp=tmp->b_this_page;
- } while (tmp && tmp != bh);
- page = mem_map + MAP_NR(bh->b_data);
- SetPageUptodate(page);
- return;
- }
- clear_bit(BH_Uptodate, &bh->b_state);
-}
-
-/*
- * Generic "readpage" function for block devices that have the normal
+ * Generic "read page" function for block devices that have the normal
* bmap functionality. This is most of the block device filesystems.
* Reads the page asynchronously --- the unlock_buffer() and
* mark_buffer_uptodate() functions propagate buffer state into the
@@ -1655,7 +1639,7 @@
{
struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
- unsigned long iblock, phys_block;
+ unsigned long iblock;
struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
unsigned int blocksize, blocks;
int nr;
@@ -1674,28 +1658,33 @@
bh = head;
nr = 0;
do {
- phys_block = bh->b_blocknr;
/*
* important, we have to retry buffers that already have
- * their bnr cached but had an IO error!
+ * their bnr cached but had an IO error.
*/
if (!buffer_uptodate(bh)) {
+ unsigned long phys_block;
phys_block = inode->i_op->bmap(inode, iblock);
/*
* this is safe to do because we hold the page lock:
*/
if (phys_block) {
init_buffer(bh, inode->i_dev, phys_block, end_buffer_io_async, NULL);
+ bh->b_state |= (1UL << BH_Allocated); /* safe */
arr[nr] = bh;
+ bh->b_count++;
nr++;
} else {
/*
* filesystem 'hole' represents zero-contents.
*
- * Don't mark the buffer up-to-date (that also implies
- * that it is ok on disk, which it isn't), but _do_
- * zero out the contents so that readers see the zeroes.
+ * It's the BH_Allocated flag that distincts
+ * on-disk and fs-hole buffers, but both are
+ * uptodate in a sense that on-disk content
+ * is not more uptodate than in-memory
+ * content.
*/
+ bh->b_state |= (1UL << BH_Uptodate); /* safe */
memset(bh->b_data, 0, blocksize);
}
}
@@ -1774,8 +1763,8 @@
/*
* Can the buffer be thrown out?
*/
-#define BUFFER_BUSY_BITS ((1<<BH_Dirty) | (1<<BH_Lock) | (1<<BH_Protected))
-#define buffer_busy(bh) ((bh)->b_count | ((bh)->b_state & BUFFER_BUSY_BITS))
+#define BUFFER_BUSY_BITS ((1<<BH_Dirty) | (1<<BH_Lock))
+#define buffer_busy(bh) ((bh)->b_count | ((bh)->b_state & BUFFER_BUSY_BITS))

/*
* try_to_free_buffers() checks if all the buffers on this particular page
@@ -1820,7 +1809,7 @@
return 1;

busy_buffer_page:
- /* Uhhuh, star writeback so that we don't end up with all dirty pages */
+ /* Uhhuh, start writeback so that we don't end up with all dirty pages */
too_many_dirty_buffers = 1;
wakeup_bdflush(0);
return 0;
@@ -1832,7 +1821,6 @@
{
struct buffer_head * bh;
int found = 0, locked = 0, dirty = 0, used = 0, lastused = 0;
- int protected = 0;
int nlist;
static char *buf_types[NR_LIST] = {"CLEAN","LOCKED","DIRTY"};

@@ -1842,7 +1830,7 @@
printk("Buffer hashed: %6d\n",nr_hashed_buffers);

for(nlist = 0; nlist < NR_LIST; nlist++) {
- found = locked = dirty = used = lastused = protected = 0;
+ found = locked = dirty = used = lastused = 0;
bh = lru_list[nlist];
if(!bh) continue;

@@ -1850,8 +1838,6 @@
found++;
if (buffer_locked(bh))
locked++;
- if (buffer_protected(bh))
- protected++;
if (buffer_dirty(bh))
dirty++;
if (bh->b_count)
@@ -1859,9 +1845,9 @@
bh = bh->b_next_free;
} while (bh != lru_list[nlist]);
printk("%8s: %d buffers, %d used (last=%d), "
- "%d locked, %d protected, %d dirty\n",
+ "%d locked, %d dirty\n",
buf_types[nlist], found, used, lastused,
- locked, protected, dirty);
+ locked, dirty);
};
}

--- linux/fs/bad_inode.c.orig Fri Jun 25 14:11:36 1999
+++ linux/fs/bad_inode.c Fri Jun 25 16:48:35 1999
@@ -61,6 +61,7 @@
EIO_ERROR, /* readlink */
bad_follow_link, /* follow_link */
EIO_ERROR, /* bmap */
+ EIO_ERROR, /* bmap_create */
EIO_ERROR, /* readpage */
EIO_ERROR, /* writepage */
EIO_ERROR, /* flushpage */
--- linux/fs/devices.c.orig Fri Jun 25 14:11:36 1999
+++ linux/fs/devices.c Fri Jun 25 16:48:35 1999
@@ -278,6 +278,7 @@
NULL, /* rename */
NULL, /* readlink */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
@@ -334,6 +335,7 @@
NULL, /* rename */
NULL, /* readlink */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/fs/fifo.c.orig Fri Jun 25 14:11:36 1999
+++ linux/fs/fifo.c Fri Jun 25 16:48:35 1999
@@ -180,6 +180,7 @@
NULL, /* rename */
NULL, /* readlink */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/fs/pipe.c.orig Fri Jun 25 14:11:36 1999
+++ linux/fs/pipe.c Fri Jun 25 16:48:35 1999
@@ -462,6 +462,7 @@
NULL, /* rename */
NULL, /* readlink */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/kernel/sysctl.c.orig Fri Jun 25 14:11:36 1999
+++ linux/kernel/sysctl.c Fri Jun 25 16:48:35 1999
@@ -121,6 +121,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
--- linux/mm/swap_state.c.orig Fri Jun 25 14:11:37 1999
+++ linux/mm/swap_state.c Fri Jun 25 16:48:36 1999
@@ -40,6 +40,7 @@
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
+ NULL, /* bmap_create */
NULL, /* readpage */
NULL, /* writepage */
block_flushpage, /* flushpage */
--- linux/include/linux/fs.h.orig Fri Jun 25 09:32:31 1999
+++ linux/include/linux/fs.h Fri Jun 25 16:48:36 1999
@@ -188,7 +188,7 @@
#define BH_Dirty 1 /* 1 if the buffer is dirty */
#define BH_Lock 2 /* 1 if the buffer is locked */
#define BH_Req 3 /* 0 if the buffer has been invalidated */
-#define BH_Protected 6 /* 1 if the buffer is protected */
+#define BH_Allocated 4 /* is b_blocknr a cached bmap() value */
/*
* Try to keep the most commonly used fields in single cache lines (16
* bytes) to improve performance. This ordering should be
@@ -240,7 +240,7 @@
#define buffer_dirty(bh) __buffer_state(bh,Dirty)
#define buffer_locked(bh) __buffer_state(bh,Lock)
#define buffer_req(bh) __buffer_state(bh,Req)
-#define buffer_protected(bh) __buffer_state(bh,Protected)
+#define buffer_allocated(bh) __buffer_state(bh,Allocated)

#define buffer_page(bh) (mem_map + MAP_NR((bh)->b_data))
#define touch_buffer(bh) set_bit(PG_referenced, &buffer_page(bh)->flags)
@@ -604,7 +604,19 @@
* now in most cases this means a lock/unlock_kernel at entry/exit.
* [The new order is also slightly more logical :)]
*/
- int (*bmap) (struct inode *,int);
+ /*
+ * 'reading' variant of bmap. It provides a (supposedly) quick
+ * lookup of already existing blocks within an inode, 0 means
+ * a 'filesystem hole'.
+ */
+ long (*bmap) (struct inode *, long);
+ /*
+ * allocating variant of bmap. Compatible with bmap but doesnt
+ * preserve holes and is usually slower. Can signal out-of-space
+ * or other non-fatal exceptions.
+ */
+ long (*bmap_create) (struct inode *, long, int *, int *);
+
int (*readpage) (struct file *, struct page *);
int (*writepage) (struct file *, struct page *);
int (*flushpage) (struct inode *, struct page *, unsigned long);
@@ -748,12 +760,28 @@
#define BUF_DIRTY 2 /* Dirty buffers, not yet scheduled for write */
#define NR_LIST 3

-void mark_buffer_uptodate(struct buffer_head *, int);
+/*
+ * This is called by bh->b_end_io() handlers when I/O has completed.
+ */
+extern inline void mark_buffer_uptodate(struct buffer_head * bh, int on)
+{
+ if (on)
+ set_bit(BH_Uptodate, &bh->b_state);
+ else
+ clear_bit(BH_Uptodate, &bh->b_state);
+}
+
+#define atomic_set_buffer_clean(bh) test_and_clear_bit(BH_Dirty, &(bh)->b_state)
+
+extern inline void __mark_buffer_clean(struct buffer_head *bh)
+{
+ refile_buffer(bh);
+}

extern inline void mark_buffer_clean(struct buffer_head * bh)
{
- if (test_and_clear_bit(BH_Dirty, &bh->b_state))
- refile_buffer(bh);
+ if (atomic_set_buffer_clean(bh))
+ __mark_buffer_clean(bh);
}

extern void FASTCALL(__mark_buffer_dirty(struct buffer_head *bh, int flag));
@@ -869,13 +897,12 @@

extern int brw_page(int, struct page *, kdev_t, int [], int, int);

-typedef long (*writepage_t)(struct file *, struct page *, unsigned long, unsigned long, const char *);
-typedef int (*fs_getblock_t)(struct inode *, unsigned long, struct buffer_head *, int);
+typedef int (*writepage_t)(struct file *, struct page *, unsigned long, unsigned long, const char *);

/* Generic buffer handling for block filesystems.. */
extern int block_read_full_page(struct file *, struct page *);
-extern int block_write_full_page (struct file *, struct page *, fs_getblock_t);
-extern int block_write_partial_page (struct file *, struct page *, unsigned long, unsigned long, const char *, fs_getblock_t);
+extern int block_write_full_page (struct file *, struct page *);
+extern int block_write_partial_page (struct file *, struct page *, unsigned long, unsigned long, const char *);
extern int block_flushpage(struct inode *, struct page *, unsigned long);

extern int generic_file_mmap(struct file *, struct vm_area_struct *);
--- linux/include/linux/ext2_fs.h.orig Fri Jun 25 12:23:32 1999
+++ linux/include/linux/ext2_fs.h Fri Jun 25 16:48:36 1999
@@ -553,7 +553,8 @@
extern void ext2_check_inodes_bitmap (struct super_block *);

/* inode.c */
-extern int ext2_bmap (struct inode *, int);
+extern long ext2_bmap (struct inode *, long);
+extern long ext2_bmap_create (struct inode *, long, int *, int *);

extern struct buffer_head * ext2_getblk (struct inode *, long, int, int *);
extern int ext2_getblk_block (struct inode *, long, int, int *, int *);
--- linux/drivers/block/ll_rw_blk.c.orig Fri Jun 25 09:32:31 1999
+++ linux/drivers/block/ll_rw_blk.c Fri Jun 25 16:48:36 1999
@@ -384,12 +384,9 @@
count = bh->b_size >> 9;
sector = bh->b_rsector;

- /* Uhhuh.. Nasty dead-lock possible here.. */
- if (buffer_locked(bh))
+ /* Only one thread can actually submit the I/O. */
+ if (test_and_set_bit(BH_Lock, &bh->b_state))
return;
- /* Maybe the above fixes it, and maybe it doesn't boot. Life is interesting */
-
- lock_buffer(bh);

if (blk_size[major]) {
unsigned long maxsector = (blk_size[major][MINOR(bh->b_rdev)] << 1) + 1;
--- linux/arch/sparc64/kernel/sys_sparc32.c.orig Fri Jun 25 09:32:31 1999
+++ linux/arch/sparc64/kernel/sys_sparc32.c Fri Jun 25 16:48:36 1999
@@ -2834,7 +2834,6 @@
bprm.dentry = dentry;
bprm.filename = filename;
bprm.sh_bang = 0;
- bprm.java = 0;
bprm.loader = 0;
bprm.exec = 0;
if ((bprm.argc = count32(argv)) < 0) {
--- linux/arch/sparc64/mm/init.c.orig Wed Jun 16 23:01:23 1999
+++ linux/arch/sparc64/mm/init.c Fri Jun 25 16:48:36 1999
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.128 1999/05/25 16:53:24 jj Exp $
+/* $Id: init.c,v 1.129 1999/06/25 10:32:08 davem Exp $
* arch/sparc64/mm/init.c
*
* Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -419,10 +419,12 @@
}

if (iommu->strbuf_enabled) {
+ volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush;
+
spin_lock_irqsave(&iommu->iommu_lock, flags);
iommu->flushflag = 0;
while(start < end) {
- sregs->sbuf_pflush = start;
+ *sbuf_pflush = start;
start += PAGE_SIZE;
}
sregs->sbuf_fsync = __pa(&(iommu->flushflag));
@@ -447,6 +449,8 @@
start &= PAGE_MASK;

if (iommu->strbuf_enabled) {
+ volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush;
+
spin_lock_irqsave(&iommu->iommu_lock, flags);

/* 1) Clear the flush flag word */
@@ -456,7 +460,7 @@
* we want flushed.
*/
while(start < end) {
- sregs->sbuf_pflush = start;
+ *sbuf_pflush = start;
start += PAGE_SIZE;
}

@@ -484,6 +488,8 @@
volatile u64 *sbctrl = (volatile u64 *) &sregs->sbus_control;

if (iommu->strbuf_enabled) {
+ volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush;
+
spin_lock_irqsave(&iommu->iommu_lock, flags);
iommu->flushflag = 0;

@@ -500,7 +506,7 @@
sg[sz--].dvma_addr = sbus_dvma_addr(start);
start &= PAGE_MASK;
while(start < end) {
- sregs->sbuf_pflush = start;
+ *sbuf_pflush = start;
start += PAGE_SIZE;
}
}
@@ -535,6 +541,8 @@
unsigned long flags, tmp;

if (iommu->strbuf_enabled) {
+ volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush;
+
spin_lock_irqsave(&iommu->iommu_lock, flags);

/* 1) Clear the flush flag word */
@@ -549,7 +557,7 @@

start &= PAGE_MASK;
while(start < end) {
- sregs->sbuf_pflush = start;
+ *sbuf_pflush = start;
start += PAGE_SIZE;
}
sz--;
\
 
 \ /
  Last update: 2005-03-22 13:52    [from the cache]
©2003-2011 Jasper Spaans