summaryrefslogtreecommitdiffstats
path: root/fs/ufs/inode.c
diff options
context:
space:
mode:
authorEvgeniy Dushistov <dushistov@mail.ru>2006-06-25 05:47:20 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-25 10:01:01 -0700
commit6ef4d6bf86a82965896eaa1a189177239ec2bbab (patch)
tree3217c5601d8cf6701f8783ec776aa96d0dd75d4a /fs/ufs/inode.c
parentc9a27b5dca52bbd0955e065e49e56eb313d02c34 (diff)
downloadkernel-crypto-6ef4d6bf86a82965896eaa1a189177239ec2bbab.tar.gz
kernel-crypto-6ef4d6bf86a82965896eaa1a189177239ec2bbab.tar.xz
kernel-crypto-6ef4d6bf86a82965896eaa1a189177239ec2bbab.zip
[PATCH] ufs: change block number on the fly
First of all some necessary notes about UFS by it self: To avoid waste of disk space the tail of file consists not from blocks (which is ordinary big enough, 16K usually), it consists from fragments(which is ordinary 2K). When file is growing its tail occupy 1 fragment, 2 fragments... At some stage decision to allocate whole block is made and all fragments are moved to one block. How this situation was handled before: ufs_prepare_write ->block_prepare_write ->ufs_getfrag_block ->... ->ufs_new_fragments: bh = sb_bread bh->b_blocknr = result + i; mark_buffer_dirty (bh); This is wrong solution, because: - it didn't take into consideration that there is another cache: "inode page cache" - because of sb_getblk uses not b_blocknr, (it uses page->index) to find certain block, this breaks sb_getblk. How this situation is handled now: we go though all "page inode cache", if there are no such page in cache we load it into cache, and change b_blocknr. Signed-off-by: Evgeniy Dushistov <dushistov@mail.ru> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/ufs/inode.c')
-rw-r--r--fs/ufs/inode.c44
1 files changed, 25 insertions, 19 deletions
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index 2b2366360e5..ea2267316a7 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -172,9 +172,10 @@ static void ufs_clear_block(struct inode *inode, struct buffer_head *bh)
sync_dirty_buffer(bh);
}
-static struct buffer_head * ufs_inode_getfrag (struct inode *inode,
- unsigned int fragment, unsigned int new_fragment,
- unsigned int required, int *err, int metadata, long *phys, int *new)
+static struct buffer_head *ufs_inode_getfrag(struct inode *inode,
+ unsigned int fragment, unsigned int new_fragment,
+ unsigned int required, int *err, int metadata,
+ long *phys, int *new, struct page *locked_page)
{
struct ufs_inode_info *ufsi = UFS_I(inode);
struct super_block * sb;
@@ -232,7 +233,8 @@ repeat:
if (lastblockoff) {
p2 = ufsi->i_u1.i_data + lastblock;
tmp = ufs_new_fragments (inode, p2, lastfrag,
- fs32_to_cpu(sb, *p2), uspi->s_fpb - lastblockoff, err);
+ fs32_to_cpu(sb, *p2), uspi->s_fpb - lastblockoff,
+ err, locked_page);
if (!tmp) {
if (lastfrag != ufsi->i_lastfrag)
goto repeat;
@@ -244,14 +246,16 @@ repeat:
}
goal = fs32_to_cpu(sb, ufsi->i_u1.i_data[lastblock]) + uspi->s_fpb;
tmp = ufs_new_fragments (inode, p, fragment - blockoff,
- goal, required + blockoff, err);
+ goal, required + blockoff,
+ err, locked_page);
}
/*
* We will extend last allocated block
*/
else if (lastblock == block) {
- tmp = ufs_new_fragments (inode, p, fragment - (blockoff - lastblockoff),
- fs32_to_cpu(sb, *p), required + (blockoff - lastblockoff), err);
+ tmp = ufs_new_fragments(inode, p, fragment - (blockoff - lastblockoff),
+ fs32_to_cpu(sb, *p), required + (blockoff - lastblockoff),
+ err, locked_page);
}
/*
* We will allocate new block before last allocated block
@@ -259,8 +263,8 @@ repeat:
else /* (lastblock > block) */ {
if (lastblock && (tmp = fs32_to_cpu(sb, ufsi->i_u1.i_data[lastblock-1])))
goal = tmp + uspi->s_fpb;
- tmp = ufs_new_fragments (inode, p, fragment - blockoff,
- goal, uspi->s_fpb, err);
+ tmp = ufs_new_fragments(inode, p, fragment - blockoff,
+ goal, uspi->s_fpb, err, locked_page);
}
if (!tmp) {
if ((!blockoff && *p) ||
@@ -303,9 +307,10 @@ repeat2:
*/
}
-static struct buffer_head * ufs_block_getfrag (struct inode *inode,
- struct buffer_head *bh, unsigned int fragment, unsigned int new_fragment,
- unsigned int blocksize, int * err, int metadata, long *phys, int *new)
+static struct buffer_head *ufs_block_getfrag(struct inode *inode, struct buffer_head *bh,
+ unsigned int fragment, unsigned int new_fragment,
+ unsigned int blocksize, int * err, int metadata,
+ long *phys, int *new, struct page *locked_page)
{
struct super_block * sb;
struct ufs_sb_private_info * uspi;
@@ -350,7 +355,8 @@ repeat:
goal = tmp + uspi->s_fpb;
else
goal = bh->b_blocknr + uspi->s_fpb;
- tmp = ufs_new_fragments (inode, p, ufs_blknum(new_fragment), goal, uspi->s_fpb, err);
+ tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), goal,
+ uspi->s_fpb, err, locked_page);
if (!tmp) {
if (fs32_to_cpu(sb, *p))
goto repeat;
@@ -424,15 +430,15 @@ int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_hea
* it much more readable:
*/
#define GET_INODE_DATABLOCK(x) \
- ufs_inode_getfrag(inode, x, fragment, 1, &err, 0, &phys, &new)
+ ufs_inode_getfrag(inode, x, fragment, 1, &err, 0, &phys, &new, bh_result->b_page)
#define GET_INODE_PTR(x) \
- ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, 1, NULL, NULL)
+ ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, 1, NULL, NULL, bh_result->b_page)
#define GET_INDIRECT_DATABLOCK(x) \
- ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \
- &err, 0, &phys, &new);
+ ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \
+ &err, 0, &phys, &new, bh_result->b_page);
#define GET_INDIRECT_PTR(x) \
- ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \
- &err, 1, NULL, NULL);
+ ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \
+ &err, 1, NULL, NULL, bh_result->b_page);
if (ptr < UFS_NDIR_FRAGMENT) {
bh = GET_INODE_DATABLOCK(ptr);