Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 174385
b: refs/heads/master
c: e636260
h: refs/heads/master
i:
  174383: aabdc8e
v: v3
  • Loading branch information
Theodore Ts'o committed Nov 23, 2009
1 parent e2c98a8 commit ba15539
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 89 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 4433871130f36585fde38e7dd817433296648945
refs/heads/master: e6362609b6c71c5b802026be9cf263bbdd67a50e
10 changes: 8 additions & 2 deletions trunk/fs/ext4/ext4.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,12 @@ struct ext4_new_group_data {
#define EXT4_GET_BLOCKS_DIO_CONVERT_EXT (EXT4_GET_BLOCKS_CONVERT|\
EXT4_GET_BLOCKS_DIO_CREATE_EXT)

/*
* Flags used by ext4_free_blocks
*/
#define EXT4_FREE_BLOCKS_METADATA 0x0001
#define EXT4_FREE_BLOCKS_FORGET 0x0002

/*
* ioctl commands
*/
Expand Down Expand Up @@ -1384,8 +1390,8 @@ extern void ext4_discard_preallocations(struct inode *);
extern int __init init_ext4_mballoc(void);
extern void exit_ext4_mballoc(void);
extern void ext4_free_blocks(handle_t *handle, struct inode *inode,
ext4_fsblk_t block, unsigned long count,
int metadata);
struct buffer_head *bh, ext4_fsblk_t block,
unsigned long count, int flags);
extern int ext4_mb_add_groupinfo(struct super_block *sb,
ext4_group_t i, struct ext4_group_desc *desc);
extern int ext4_mb_get_buddy_cache_lock(struct super_block *, ext4_group_t);
Expand Down
24 changes: 9 additions & 15 deletions trunk/fs/ext4/extents.c
Original file line number Diff line number Diff line change
Expand Up @@ -1007,7 +1007,8 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
for (i = 0; i < depth; i++) {
if (!ablocks[i])
continue;
ext4_free_blocks(handle, inode, ablocks[i], 1, 1);
ext4_free_blocks(handle, inode, 0, ablocks[i], 1,
EXT4_FREE_BLOCKS_METADATA);
}
}
kfree(ablocks);
Expand Down Expand Up @@ -1957,7 +1958,6 @@ ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block,
static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
struct ext4_ext_path *path)
{
struct buffer_head *bh;
int err;
ext4_fsblk_t leaf;

Expand All @@ -1973,9 +1973,8 @@ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
if (err)
return err;
ext_debug("index is empty, remove it, free block %llu\n", leaf);
bh = sb_find_get_block(inode->i_sb, leaf);
ext4_forget(handle, 1, inode, bh, leaf);
ext4_free_blocks(handle, inode, leaf, 1, 1);
ext4_free_blocks(handle, inode, 0, leaf, 1,
EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET);
return err;
}

Expand Down Expand Up @@ -2042,12 +2041,11 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
struct ext4_extent *ex,
ext4_lblk_t from, ext4_lblk_t to)
{
struct buffer_head *bh;
unsigned short ee_len = ext4_ext_get_actual_len(ex);
int i, metadata = 0;
int flags = EXT4_FREE_BLOCKS_FORGET;

if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
metadata = 1;
flags |= EXT4_FREE_BLOCKS_METADATA;
#ifdef EXTENTS_STATS
{
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
Expand All @@ -2072,11 +2070,7 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
num = le32_to_cpu(ex->ee_block) + ee_len - from;
start = ext_pblock(ex) + ee_len - num;
ext_debug("free last %u blocks starting %llu\n", num, start);
for (i = 0; i < num; i++) {
bh = sb_find_get_block(inode->i_sb, start + i);
ext4_forget(handle, metadata, inode, bh, start + i);
}
ext4_free_blocks(handle, inode, start, num, metadata);
ext4_free_blocks(handle, inode, 0, start, num, flags);
} else if (from == le32_to_cpu(ex->ee_block)
&& to <= le32_to_cpu(ex->ee_block) + ee_len - 1) {
printk(KERN_INFO "strange request: removal %u-%u from %u:%u\n",
Expand Down Expand Up @@ -3319,8 +3313,8 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
/* not a good idea to call discard here directly,
* but otherwise we'd need to call it every free() */
ext4_discard_preallocations(inode);
ext4_free_blocks(handle, inode, ext_pblock(&newex),
ext4_ext_get_actual_len(&newex), 0);
ext4_free_blocks(handle, inode, 0, ext_pblock(&newex),
ext4_ext_get_actual_len(&newex), 0);
goto out2;
}

Expand Down
67 changes: 26 additions & 41 deletions trunk/fs/ext4/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,7 @@ static int ext4_alloc_blocks(handle_t *handle, struct inode *inode,
return ret;
failed_out:
for (i = 0; i < index; i++)
ext4_free_blocks(handle, inode, new_blocks[i], 1, 0);
ext4_free_blocks(handle, inode, 0, new_blocks[i], 1, 0);
return ret;
}

Expand Down Expand Up @@ -765,20 +765,20 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
return err;
failed:
/* Allocation failed, free what we already allocated */
ext4_free_blocks(handle, inode, 0, new_blocks[0], 1, 0);
for (i = 1; i <= n ; i++) {
BUFFER_TRACE(branch[i].bh, "call jbd2_journal_forget");
/*
* Note: is_metadata is 0 because branch[i].bh is
* newly allocated, so there is no need to revoke the
* block. If we do, it's harmless, but not necessary.
* branch[i].bh is newly allocated, so there is no
* need to revoke the block, which is why we don't
* need to set EXT4_FREE_BLOCKS_METADATA.
*/
ext4_forget(handle, 0, inode, branch[i].bh,
branch[i].bh->b_blocknr);
ext4_free_blocks(handle, inode, 0, new_blocks[i], 1,
EXT4_FREE_BLOCKS_FORGET);
}
for (i = 0; i < indirect_blks; i++)
ext4_free_blocks(handle, inode, new_blocks[i], 1, 0);
for (i = n+1; i < indirect_blks; i++)
ext4_free_blocks(handle, inode, 0, new_blocks[i], 1, 0);

ext4_free_blocks(handle, inode, new_blocks[i], num, 0);
ext4_free_blocks(handle, inode, 0, new_blocks[i], num, 0);

return err;
}
Expand Down Expand Up @@ -857,18 +857,16 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,

err_out:
for (i = 1; i <= num; i++) {
BUFFER_TRACE(where[i].bh, "call jbd2_journal_forget");
/*
* Note: is_metadata is 0 because branch[i].bh is
* newly allocated, so there is no need to revoke the
* block. If we do, it's harmless, but not necessary.
* branch[i].bh is newly allocated, so there is no
* need to revoke the block, which is why we don't
* need to set EXT4_FREE_BLOCKS_METADATA.
*/
ext4_forget(handle, 0, inode, where[i].bh,
where[i].bh->b_blocknr);
ext4_free_blocks(handle, inode,
le32_to_cpu(where[i-1].key), 1, 0);
ext4_free_blocks(handle, inode, where[i].bh, 0, 1,
EXT4_FREE_BLOCKS_FORGET);
}
ext4_free_blocks(handle, inode, le32_to_cpu(where[num].key), blks, 0);
ext4_free_blocks(handle, inode, 0, le32_to_cpu(where[num].key),
blks, 0);

return err;
}
Expand Down Expand Up @@ -4080,7 +4078,10 @@ static void ext4_clear_blocks(handle_t *handle, struct inode *inode,
__le32 *last)
{
__le32 *p;
int is_metadata = S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode);
int flags = EXT4_FREE_BLOCKS_FORGET;

if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
flags |= EXT4_FREE_BLOCKS_METADATA;

if (try_to_extend_transaction(handle, inode)) {
if (bh) {
Expand All @@ -4096,27 +4097,10 @@ static void ext4_clear_blocks(handle_t *handle, struct inode *inode,
}
}

/*
* Any buffers which are on the journal will be in memory. We
* find them on the hash table so jbd2_journal_revoke() will
* run jbd2_journal_forget() on them. We've already detached
* each block from the file, so bforget() in
* jbd2_journal_forget() should be safe.
*
* AKPM: turn on bforget in jbd2_journal_forget()!!!
*/
for (p = first; p < last; p++) {
u32 nr = le32_to_cpu(*p);
if (nr) {
struct buffer_head *tbh;

*p = 0;
tbh = sb_find_get_block(inode->i_sb, nr);
ext4_forget(handle, is_metadata, inode, tbh, nr);
}
}
for (p = first; p < last; p++)
*p = 0;

ext4_free_blocks(handle, inode, block_to_free, count, is_metadata);
ext4_free_blocks(handle, inode, 0, block_to_free, count, flags);
}

/**
Expand Down Expand Up @@ -4304,7 +4288,8 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
blocks_for_truncate(inode));
}

ext4_free_blocks(handle, inode, nr, 1, 1);
ext4_free_blocks(handle, inode, 0, nr, 1,
EXT4_FREE_BLOCKS_METADATA);

if (parent_bh) {
/*
Expand Down
49 changes: 36 additions & 13 deletions trunk/fs/ext4/mballoc.c
Original file line number Diff line number Diff line change
Expand Up @@ -4436,8 +4436,8 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
* @metadata: Are these metadata blocks
*/
void ext4_free_blocks(handle_t *handle, struct inode *inode,
ext4_fsblk_t block, unsigned long count,
int metadata)
struct buffer_head *bh, ext4_fsblk_t block,
unsigned long count, int flags)
{
struct buffer_head *bitmap_bh = NULL;
struct super_block *sb = inode->i_sb;
Expand All @@ -4454,15 +4454,12 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
int err = 0;
int ret;

/*
* We need to make sure we don't reuse the freed block until
* after the transaction is committed, which we can do by
* treating the block as metadata, below. We make an
* exception if the inode is to be written in writeback mode
* since writeback mode has weak data consistency guarantees.
*/
if (!ext4_should_writeback_data(inode))
metadata = 1;
if (bh) {
if (block)
BUG_ON(block != bh->b_blocknr);
else
block = bh->b_blocknr;
}

sbi = EXT4_SB(sb);
es = EXT4_SB(sb)->s_es;
Expand All @@ -4476,7 +4473,32 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
}

ext4_debug("freeing block %llu\n", block);
trace_ext4_free_blocks(inode, block, count, metadata);
trace_ext4_free_blocks(inode, block, count, flags);

if (flags & EXT4_FREE_BLOCKS_FORGET) {
struct buffer_head *tbh = bh;
int i;

BUG_ON(bh && (count > 1));

for (i = 0; i < count; i++) {
if (!bh)
tbh = sb_find_get_block(inode->i_sb,
block + i);
ext4_forget(handle, flags & EXT4_FREE_BLOCKS_METADATA,
inode, tbh, block + i);
}
}

/*
* We need to make sure we don't reuse the freed block until
* after the transaction is committed, which we can do by
* treating the block as metadata, below. We make an
* exception if the inode is to be written in writeback mode
* since writeback mode has weak data consistency guarantees.
*/
if (!ext4_should_writeback_data(inode))
flags |= EXT4_FREE_BLOCKS_METADATA;

ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);
if (ac) {
Expand Down Expand Up @@ -4552,7 +4574,8 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
err = ext4_mb_load_buddy(sb, block_group, &e4b);
if (err)
goto error_return;
if (metadata && ext4_handle_valid(handle)) {

if ((flags & EXT4_FREE_BLOCKS_METADATA) && ext4_handle_valid(handle)) {
struct ext4_free_data *new_entry;
/*
* blocks being freed are metadata. these blocks shouldn't
Expand Down
23 changes: 16 additions & 7 deletions trunk/fs/ext4/migrate.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,13 +262,17 @@ static int free_dind_blocks(handle_t *handle,
for (i = 0; i < max_entries; i++) {
if (tmp_idata[i]) {
extend_credit_for_blkdel(handle, inode);
ext4_free_blocks(handle, inode,
le32_to_cpu(tmp_idata[i]), 1, 1);
ext4_free_blocks(handle, inode, 0,
le32_to_cpu(tmp_idata[i]), 1,
EXT4_FREE_BLOCKS_METADATA |
EXT4_FREE_BLOCKS_FORGET);
}
}
put_bh(bh);
extend_credit_for_blkdel(handle, inode);
ext4_free_blocks(handle, inode, le32_to_cpu(i_data), 1, 1);
ext4_free_blocks(handle, inode, 0, le32_to_cpu(i_data), 1,
EXT4_FREE_BLOCKS_METADATA |
EXT4_FREE_BLOCKS_FORGET);
return 0;
}

Expand Down Expand Up @@ -297,7 +301,9 @@ static int free_tind_blocks(handle_t *handle,
}
put_bh(bh);
extend_credit_for_blkdel(handle, inode);
ext4_free_blocks(handle, inode, le32_to_cpu(i_data), 1, 1);
ext4_free_blocks(handle, inode, 0, le32_to_cpu(i_data), 1,
EXT4_FREE_BLOCKS_METADATA |
EXT4_FREE_BLOCKS_FORGET);
return 0;
}

Expand All @@ -308,8 +314,10 @@ static int free_ind_block(handle_t *handle, struct inode *inode, __le32 *i_data)
/* ei->i_data[EXT4_IND_BLOCK] */
if (i_data[0]) {
extend_credit_for_blkdel(handle, inode);
ext4_free_blocks(handle, inode,
le32_to_cpu(i_data[0]), 1, 1);
ext4_free_blocks(handle, inode, 0,
le32_to_cpu(i_data[0]), 1,
EXT4_FREE_BLOCKS_METADATA |
EXT4_FREE_BLOCKS_FORGET);
}

/* ei->i_data[EXT4_DIND_BLOCK] */
Expand Down Expand Up @@ -419,7 +427,8 @@ static int free_ext_idx(handle_t *handle, struct inode *inode,
}
put_bh(bh);
extend_credit_for_blkdel(handle, inode);
ext4_free_blocks(handle, inode, block, 1, 1);
ext4_free_blocks(handle, inode, 0, block, 1,
EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET);
return retval;
}

Expand Down
8 changes: 5 additions & 3 deletions trunk/fs/ext4/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -482,9 +482,10 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode,
ea_bdebug(bh, "refcount now=0; freeing");
if (ce)
mb_cache_entry_free(ce);
ext4_free_blocks(handle, inode, bh->b_blocknr, 1, 1);
get_bh(bh);
ext4_forget(handle, 1, inode, bh, bh->b_blocknr);
ext4_free_blocks(handle, inode, bh, 0, 1,
EXT4_FREE_BLOCKS_METADATA |
EXT4_FREE_BLOCKS_FORGET);
} else {
le32_add_cpu(&BHDR(bh)->h_refcount, -1);
error = ext4_handle_dirty_metadata(handle, inode, bh);
Expand Down Expand Up @@ -832,7 +833,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
new_bh = sb_getblk(sb, block);
if (!new_bh) {
getblk_failed:
ext4_free_blocks(handle, inode, block, 1, 1);
ext4_free_blocks(handle, inode, 0, block, 1,
EXT4_FREE_BLOCKS_METADATA);
error = -EIO;
goto cleanup;
}
Expand Down
Loading

0 comments on commit ba15539

Please sign in to comment.