summaryrefslogtreecommitdiffstats
path: root/fs/buffer.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-12-04 03:58:56 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-12-04 03:58:56 +0000
commit1d67e90f19a7acfd9a05dc59678e7d0c5090bd0d (patch)
tree357efc7b93f8f5102110d20d293f41360ec212fc /fs/buffer.c
parentaea27b2e18d69af87e673972246e66657b4fa274 (diff)
Merge with Linux 2.3.21.
Diffstat (limited to 'fs/buffer.c')
-rw-r--r--fs/buffer.c44
1 files changed, 32 insertions, 12 deletions
diff --git a/fs/buffer.c b/fs/buffer.c
index c4fefe5cc..d77dc86bc 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1205,6 +1205,18 @@ static int create_page_buffers(int rw, struct page *page, kdev_t dev, int b[], i
return 0;
}
+static void unmap_buffer(struct buffer_head * bh)
+{
+ if (buffer_mapped(bh))
+ {
+ mark_buffer_clean(bh);
+ wait_on_buffer(bh);
+ clear_bit(BH_Uptodate, &bh->b_state);
+ clear_bit(BH_Mapped, &bh->b_state);
+ clear_bit(BH_Req, &bh->b_state);
+ }
+}
+
/*
* We don't have to release all buffers here, but
* we have to be sure that no dirty buffer is left
@@ -1231,16 +1243,8 @@ int block_flushpage(struct inode *inode, struct page *page, unsigned long offset
/*
* is this block fully flushed?
*/
- if (offset <= curr_off) {
- if (buffer_mapped(bh)) {
- mark_buffer_clean(bh);
- wait_on_buffer(bh);
- clear_bit(BH_Uptodate, &bh->b_state);
- clear_bit(BH_Mapped, &bh->b_state);
- clear_bit(BH_Req, &bh->b_state);
- bh->b_blocknr = 0;
- }
- }
+ if (offset <= curr_off)
+ unmap_buffer(bh);
curr_off = next_off;
bh = next;
} while (bh != head);
@@ -1286,6 +1290,19 @@ static void create_empty_buffers(struct page *page, struct inode *inode, unsigne
get_page(page);
}
+static void unmap_underlying_metadata(struct buffer_head * bh)
+{
+ bh = get_hash_table(bh->b_dev, bh->b_blocknr, bh->b_size);
+ if (bh)
+ {
+ unmap_buffer(bh);
+ /* Here we could run brelse or bforget. We use
+ bforget because it will try to put the buffer
+ in the freelist. */
+ __bforget(bh);
+ }
+}
+
/*
* block_write_full_page() is SMP-safe - currently it's still
* being called with the kernel lock held, but the code is ready.
@@ -1331,6 +1348,7 @@ int block_write_full_page(struct file *file, struct page *page)
err = inode->i_op->get_block(inode, block, bh, 1);
if (err)
goto out;
+ unmap_underlying_metadata(bh);
}
set_bit(BH_Uptodate, &bh->b_state);
mark_buffer_dirty(bh,0);
@@ -1420,6 +1438,7 @@ int block_write_partial_page(struct file *file, struct page *page, unsigned long
err = inode->i_op->get_block(inode, block, bh, 1);
if (err)
goto out;
+ unmap_underlying_metadata(bh);
}
if (!buffer_uptodate(bh) && (start_offset || (end_bytes && (i == end_block)))) {
@@ -1512,8 +1531,8 @@ int block_write_cont_page(struct file *file, struct page *page, unsigned long of
char * target_buf, *target_data;
unsigned long data_offset = offset;
- offset = page->offset-inode->i_size;
- if (offset < 0)
+ offset = inode->i_size - page->offset;
+ if (page->offset>inode->i_size)
offset = 0;
else if (offset >= data_offset)
offset = data_offset;
@@ -1582,6 +1601,7 @@ int block_write_cont_page(struct file *file, struct page *page, unsigned long of
err = inode->i_op->get_block(inode, block, bh, 1);
if (err)
goto out;
+ unmap_underlying_metadata(bh);
}
if (!buffer_uptodate(bh) && (start_offset || (end_bytes && (i == end_block)))) {