Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 273114
b: refs/heads/master
c: 8413019
h: refs/heads/master
v: v3
  • Loading branch information
Theodore Ts'o committed Sep 9, 2011
1 parent 732106c commit 0671b60
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 26 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: 53accfa9f819c80056db6f03f9c5cfa4bcba1ed8
refs/heads/master: 84130193e0e6568dfdfb823f0e1e19aec80aff6e
2 changes: 2 additions & 0 deletions trunk/fs/ext4/ext4.h
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,8 @@ struct ext4_new_group_data {
#define EXT4_FREE_BLOCKS_FORGET 0x0002
#define EXT4_FREE_BLOCKS_VALIDATED 0x0004
#define EXT4_FREE_BLOCKS_NO_QUOT_UPDATE 0x0008
#define EXT4_FREE_BLOCKS_NOFREE_FIRST_CLUSTER 0x0010
#define EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER 0x0020

/*
* Flags used by ext4_discard_partial_page_buffers
Expand Down
86 changes: 62 additions & 24 deletions trunk/fs/ext4/mballoc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2602,11 +2602,13 @@ int ext4_mb_release(struct super_block *sb)
}

static inline int ext4_issue_discard(struct super_block *sb,
ext4_group_t block_group, ext4_grpblk_t block, int count)
ext4_group_t block_group, ext4_grpblk_t cluster, int count)
{
ext4_fsblk_t discard_block;

discard_block = block + ext4_group_first_block_no(sb, block_group);
discard_block = (EXT4_C2B(EXT4_SB(sb), cluster) +
ext4_group_first_block_no(sb, block_group));
count = EXT4_C2B(EXT4_SB(sb), count);
trace_ext4_discard_blocks(sb,
(unsigned long long) discard_block, count);
return sb_issue_discard(sb, discard_block, count, GFP_NOFS, 0);
Expand All @@ -2633,7 +2635,7 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)

if (test_opt(sb, DISCARD))
ext4_issue_discard(sb, entry->group,
entry->start_blk, entry->count);
entry->start_cluster, entry->count);

err = ext4_mb_load_buddy(sb, entry->group, &e4b);
/* we expect to find existing buddy because it's pinned */
Expand All @@ -2646,7 +2648,7 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)
ext4_lock_group(sb, entry->group);
/* Take it out of per group rb tree */
rb_erase(&entry->node, &(db->bb_free_root));
mb_free_blocks(NULL, &e4b, entry->start_blk, entry->count);
mb_free_blocks(NULL, &e4b, entry->start_cluster, entry->count);

/*
* Clear the trimmed flag for the group so that the next
Expand Down Expand Up @@ -3300,7 +3302,7 @@ static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap,

while (n) {
entry = rb_entry(n, struct ext4_free_data, node);
ext4_set_bits(bitmap, entry->start_blk, entry->count);
ext4_set_bits(bitmap, entry->start_cluster, entry->count);
n = rb_next(n);
}
return;
Expand Down Expand Up @@ -4401,7 +4403,7 @@ static int can_merge(struct ext4_free_data *entry1,
{
if ((entry1->t_tid == entry2->t_tid) &&
(entry1->group == entry2->group) &&
((entry1->start_blk + entry1->count) == entry2->start_blk))
((entry1->start_cluster + entry1->count) == entry2->start_cluster))
return 1;
return 0;
}
Expand All @@ -4411,7 +4413,7 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
struct ext4_free_data *new_entry)
{
ext4_group_t group = e4b->bd_group;
ext4_grpblk_t block;
ext4_grpblk_t cluster;
struct ext4_free_data *entry;
struct ext4_group_info *db = e4b->bd_info;
struct super_block *sb = e4b->bd_sb;
Expand All @@ -4424,7 +4426,7 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
BUG_ON(e4b->bd_buddy_page == NULL);

new_node = &new_entry->node;
block = new_entry->start_blk;
cluster = new_entry->start_cluster;

if (!*n) {
/* first free block exent. We need to
Expand All @@ -4438,13 +4440,14 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
while (*n) {
parent = *n;
entry = rb_entry(parent, struct ext4_free_data, node);
if (block < entry->start_blk)
if (cluster < entry->start_cluster)
n = &(*n)->rb_left;
else if (block >= (entry->start_blk + entry->count))
else if (cluster >= (entry->start_cluster + entry->count))
n = &(*n)->rb_right;
else {
ext4_grp_locked_error(sb, group, 0,
ext4_group_first_block_no(sb, group) + block,
ext4_group_first_block_no(sb, group) +
EXT4_C2B(sbi, cluster),
"Block already on to-be-freed list");
return 0;
}
Expand All @@ -4458,7 +4461,7 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
if (node) {
entry = rb_entry(node, struct ext4_free_data, node);
if (can_merge(entry, new_entry)) {
new_entry->start_blk = entry->start_blk;
new_entry->start_cluster = entry->start_cluster;
new_entry->count += entry->count;
rb_erase(node, &(db->bb_free_root));
spin_lock(&sbi->s_md_lock);
Expand Down Expand Up @@ -4509,6 +4512,7 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
ext4_group_t block_group;
struct ext4_sb_info *sbi;
struct ext4_buddy e4b;
unsigned int count_clusters;
int err = 0;
int ret;

Expand Down Expand Up @@ -4557,6 +4561,38 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
if (!ext4_should_writeback_data(inode))
flags |= EXT4_FREE_BLOCKS_METADATA;

/*
* If the extent to be freed does not begin on a cluster
* boundary, we need to deal with partial clusters at the
* beginning and end of the extent. Normally we will free
* blocks at the beginning or the end unless we are explicitly
* requested to avoid doing so.
*/
overflow = block & (sbi->s_cluster_ratio - 1);
if (overflow) {
if (flags & EXT4_FREE_BLOCKS_NOFREE_FIRST_CLUSTER) {
overflow = sbi->s_cluster_ratio - overflow;
block += overflow;
if (count > overflow)
count -= overflow;
else
return;
} else {
block -= overflow;
count += overflow;
}
}
overflow = count & (sbi->s_cluster_ratio - 1);
if (overflow) {
if (flags & EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER) {
if (count > overflow)
count -= overflow;
else
return;
} else
count += sbi->s_cluster_ratio - overflow;
}

do_more:
overflow = 0;
ext4_get_group_no_and_offset(sb, block, &block_group, &bit);
Expand All @@ -4565,10 +4601,12 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
* Check to see if we are freeing blocks across a group
* boundary.
*/
if (bit + count > EXT4_CLUSTERS_PER_GROUP(sb)) {
overflow = bit + count - EXT4_CLUSTERS_PER_GROUP(sb);
if (EXT4_C2B(sbi, bit) + count > EXT4_BLOCKS_PER_GROUP(sb)) {
overflow = EXT4_C2B(sbi, bit) + count -
EXT4_BLOCKS_PER_GROUP(sb);
count -= overflow;
}
count_clusters = EXT4_B2C(sbi, count);
bitmap_bh = ext4_read_block_bitmap(sb, block_group);
if (!bitmap_bh) {
err = -EIO;
Expand All @@ -4583,9 +4621,9 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
if (in_range(ext4_block_bitmap(sb, gdp), block, count) ||
in_range(ext4_inode_bitmap(sb, gdp), block, count) ||
in_range(block, ext4_inode_table(sb, gdp),
EXT4_SB(sb)->s_itb_per_group) ||
EXT4_SB(sb)->s_itb_per_group) ||
in_range(block + count - 1, ext4_inode_table(sb, gdp),
EXT4_SB(sb)->s_itb_per_group)) {
EXT4_SB(sb)->s_itb_per_group)) {

ext4_error(sb, "Freeing blocks in system zone - "
"Block = %llu, count = %lu", block, count);
Expand All @@ -4610,11 +4648,11 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
#ifdef AGGRESSIVE_CHECK
{
int i;
for (i = 0; i < count; i++)
for (i = 0; i < count_clusters; i++)
BUG_ON(!mb_test_bit(bit + i, bitmap_bh->b_data));
}
#endif
trace_ext4_mballoc_free(sb, inode, block_group, bit, count);
trace_ext4_mballoc_free(sb, inode, block_group, bit, count_clusters);

err = ext4_mb_load_buddy(sb, block_group, &e4b);
if (err)
Expand All @@ -4631,25 +4669,25 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
err = -ENOMEM;
goto error_return;
}
new_entry->start_blk = bit;
new_entry->start_cluster = bit;
new_entry->group = block_group;
new_entry->count = count;
new_entry->count = count_clusters;
new_entry->t_tid = handle->h_transaction->t_tid;

ext4_lock_group(sb, block_group);
mb_clear_bits(bitmap_bh->b_data, bit, count);
mb_clear_bits(bitmap_bh->b_data, bit, count_clusters);
ext4_mb_free_metadata(handle, &e4b, new_entry);
} else {
/* need to update group_info->bb_free and bitmap
* with group lock held. generate_buddy look at
* them with group lock_held
*/
ext4_lock_group(sb, block_group);
mb_clear_bits(bitmap_bh->b_data, bit, count);
mb_free_blocks(inode, &e4b, bit, count);
mb_clear_bits(bitmap_bh->b_data, bit, count_clusters);
mb_free_blocks(inode, &e4b, bit, count_clusters);
}

ret = ext4_free_blks_count(sb, gdp) + count;
ret = ext4_free_blks_count(sb, gdp) + count_clusters;
ext4_free_blks_set(sb, gdp, ret);
gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp);
ext4_unlock_group(sb, block_group);
Expand Down
2 changes: 1 addition & 1 deletion trunk/fs/ext4/mballoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ struct ext4_free_data {
ext4_group_t group;

/* free block extent */
ext4_grpblk_t start_blk;
ext4_grpblk_t start_cluster;
ext4_grpblk_t count;

/* transaction which freed this extent */
Expand Down

0 comments on commit 0671b60

Please sign in to comment.