dect
/
linux-2.6
Archived
13
0
Fork 0

Merge branch 'for-linus-min' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs

Pull the minimal btrfs branch from Chris Mason:
 "We have a use-after-free in there, along with errors when mount -o
  discard is enabled, and a BUG_ON(we should compile with UP more
  often)."

* 'for-linus-min' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  Btrfs: use commit root when loading free space cache
  Btrfs: fix use-after-free in __btrfs_end_transaction
  Btrfs: check return value of bio_alloc() properly
  Btrfs: remove lock assert from get_restripe_target()
  Btrfs: fix eof while discarding extents
  Btrfs: fix uninit variable in repair_eb_io_failure
  Revert "Btrfs: increase the global block reserve estimates"
This commit is contained in:
Linus Torvalds 2012-04-13 19:41:27 -07:00
commit 659e45d8a0
7 changed files with 40 additions and 21 deletions

View File

@ -405,6 +405,7 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
bio_put(bio); bio_put(bio);
bio = compressed_bio_alloc(bdev, first_byte, GFP_NOFS); bio = compressed_bio_alloc(bdev, first_byte, GFP_NOFS);
BUG_ON(!bio);
bio->bi_private = cb; bio->bi_private = cb;
bio->bi_end_io = end_compressed_bio_write; bio->bi_end_io = end_compressed_bio_write;
bio_add_page(bio, page, PAGE_CACHE_SIZE, 0); bio_add_page(bio, page, PAGE_CACHE_SIZE, 0);
@ -687,6 +688,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
comp_bio = compressed_bio_alloc(bdev, cur_disk_byte, comp_bio = compressed_bio_alloc(bdev, cur_disk_byte,
GFP_NOFS); GFP_NOFS);
BUG_ON(!comp_bio);
comp_bio->bi_private = cb; comp_bio->bi_private = cb;
comp_bio->bi_end_io = end_compressed_bio_read; comp_bio->bi_end_io = end_compressed_bio_read;

View File

@ -529,9 +529,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
* allocate blocks for the tree root we can't do the fast caching since * allocate blocks for the tree root we can't do the fast caching since
* we likely hold important locks. * we likely hold important locks.
*/ */
if (trans && (!trans->transaction->in_commit) && if (fs_info->mount_opt & BTRFS_MOUNT_SPACE_CACHE) {
(root && root != root->fs_info->tree_root) &&
btrfs_test_opt(root, SPACE_CACHE)) {
ret = load_free_space_cache(fs_info, cache); ret = load_free_space_cache(fs_info, cache);
spin_lock(&cache->lock); spin_lock(&cache->lock);
@ -3152,15 +3150,14 @@ static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
/* /*
* returns target flags in extended format or 0 if restripe for this * returns target flags in extended format or 0 if restripe for this
* chunk_type is not in progress * chunk_type is not in progress
*
* should be called with either volume_mutex or balance_lock held
*/ */
static u64 get_restripe_target(struct btrfs_fs_info *fs_info, u64 flags) static u64 get_restripe_target(struct btrfs_fs_info *fs_info, u64 flags)
{ {
struct btrfs_balance_control *bctl = fs_info->balance_ctl; struct btrfs_balance_control *bctl = fs_info->balance_ctl;
u64 target = 0; u64 target = 0;
BUG_ON(!mutex_is_locked(&fs_info->volume_mutex) &&
!spin_is_locked(&fs_info->balance_lock));
if (!bctl) if (!bctl)
return 0; return 0;
@ -4205,7 +4202,7 @@ static u64 calc_global_metadata_size(struct btrfs_fs_info *fs_info)
num_bytes += div64_u64(data_used + meta_used, 50); num_bytes += div64_u64(data_used + meta_used, 50);
if (num_bytes * 3 > meta_used) if (num_bytes * 3 > meta_used)
num_bytes = div64_u64(meta_used, 3) * 2; num_bytes = div64_u64(meta_used, 3);
return ALIGN(num_bytes, fs_info->extent_root->leafsize << 10); return ALIGN(num_bytes, fs_info->extent_root->leafsize << 10);
} }

View File

@ -1937,7 +1937,7 @@ int repair_eb_io_failure(struct btrfs_root *root, struct extent_buffer *eb,
struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree; struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree;
u64 start = eb->start; u64 start = eb->start;
unsigned long i, num_pages = num_extent_pages(eb->start, eb->len); unsigned long i, num_pages = num_extent_pages(eb->start, eb->len);
int ret; int ret = 0;
for (i = 0; i < num_pages; i++) { for (i = 0; i < num_pages; i++) {
struct page *p = extent_buffer_page(eb, i); struct page *p = extent_buffer_page(eb, i);
@ -2180,6 +2180,10 @@ static int bio_readpage_error(struct bio *failed_bio, struct page *page,
} }
bio = bio_alloc(GFP_NOFS, 1); bio = bio_alloc(GFP_NOFS, 1);
if (!bio) {
free_io_failure(inode, failrec, 0);
return -EIO;
}
bio->bi_private = state; bio->bi_private = state;
bio->bi_end_io = failed_bio->bi_end_io; bio->bi_end_io = failed_bio->bi_end_io;
bio->bi_sector = failrec->logical >> 9; bio->bi_sector = failrec->logical >> 9;

View File

@ -747,13 +747,6 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
bool matched; bool matched;
u64 used = btrfs_block_group_used(&block_group->item); u64 used = btrfs_block_group_used(&block_group->item);
/*
* If we're unmounting then just return, since this does a search on the
* normal root and not the commit root and we could deadlock.
*/
if (btrfs_fs_closing(fs_info))
return 0;
/* /*
* If this block group has been marked to be cleared for one reason or * If this block group has been marked to be cleared for one reason or
* another then we can't trust the on disk cache, so just return. * another then we can't trust the on disk cache, so just return.
@ -768,6 +761,8 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
path = btrfs_alloc_path(); path = btrfs_alloc_path();
if (!path) if (!path)
return 0; return 0;
path->search_commit_root = 1;
path->skip_locking = 1;
inode = lookup_free_space_inode(root, block_group, path); inode = lookup_free_space_inode(root, block_group, path);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {

View File

@ -1044,6 +1044,8 @@ static int scrub_recheck_block(struct btrfs_fs_info *fs_info,
BUG_ON(!page->page); BUG_ON(!page->page);
bio = bio_alloc(GFP_NOFS, 1); bio = bio_alloc(GFP_NOFS, 1);
if (!bio)
return -EIO;
bio->bi_bdev = page->bdev; bio->bi_bdev = page->bdev;
bio->bi_sector = page->physical >> 9; bio->bi_sector = page->physical >> 9;
bio->bi_end_io = scrub_complete_bio_end_io; bio->bi_end_io = scrub_complete_bio_end_io;
@ -1171,6 +1173,8 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad,
DECLARE_COMPLETION_ONSTACK(complete); DECLARE_COMPLETION_ONSTACK(complete);
bio = bio_alloc(GFP_NOFS, 1); bio = bio_alloc(GFP_NOFS, 1);
if (!bio)
return -EIO;
bio->bi_bdev = page_bad->bdev; bio->bi_bdev = page_bad->bdev;
bio->bi_sector = page_bad->physical >> 9; bio->bi_sector = page_bad->physical >> 9;
bio->bi_end_io = scrub_complete_bio_end_io; bio->bi_end_io = scrub_complete_bio_end_io;

View File

@ -480,6 +480,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
struct btrfs_transaction *cur_trans = trans->transaction; struct btrfs_transaction *cur_trans = trans->transaction;
struct btrfs_fs_info *info = root->fs_info; struct btrfs_fs_info *info = root->fs_info;
int count = 0; int count = 0;
int err = 0;
if (--trans->use_count) { if (--trans->use_count) {
trans->block_rsv = trans->orig_rsv; trans->block_rsv = trans->orig_rsv;
@ -532,18 +533,18 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
if (current->journal_info == trans) if (current->journal_info == trans)
current->journal_info = NULL; current->journal_info = NULL;
memset(trans, 0, sizeof(*trans));
kmem_cache_free(btrfs_trans_handle_cachep, trans);
if (throttle) if (throttle)
btrfs_run_delayed_iputs(root); btrfs_run_delayed_iputs(root);
if (trans->aborted || if (trans->aborted ||
root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
return -EIO; err = -EIO;
} }
return 0; memset(trans, 0, sizeof(*trans));
kmem_cache_free(btrfs_trans_handle_cachep, trans);
return err;
} }
int btrfs_end_transaction(struct btrfs_trans_handle *trans, int btrfs_end_transaction(struct btrfs_trans_handle *trans,

View File

@ -3833,6 +3833,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
int sub_stripes = 0; int sub_stripes = 0;
u64 stripes_per_dev = 0; u64 stripes_per_dev = 0;
u32 remaining_stripes = 0; u32 remaining_stripes = 0;
u32 last_stripe = 0;
if (map->type & if (map->type &
(BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID10)) { (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID10)) {
@ -3846,6 +3847,8 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
stripe_nr_orig, stripe_nr_orig,
factor, factor,
&remaining_stripes); &remaining_stripes);
div_u64_rem(stripe_nr_end - 1, factor, &last_stripe);
last_stripe *= sub_stripes;
} }
for (i = 0; i < num_stripes; i++) { for (i = 0; i < num_stripes; i++) {
@ -3858,16 +3861,29 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
BTRFS_BLOCK_GROUP_RAID10)) { BTRFS_BLOCK_GROUP_RAID10)) {
bbio->stripes[i].length = stripes_per_dev * bbio->stripes[i].length = stripes_per_dev *
map->stripe_len; map->stripe_len;
if (i / sub_stripes < remaining_stripes) if (i / sub_stripes < remaining_stripes)
bbio->stripes[i].length += bbio->stripes[i].length +=
map->stripe_len; map->stripe_len;
/*
* Special for the first stripe and
* the last stripe:
*
* |-------|...|-------|
* |----------|
* off end_off
*/
if (i < sub_stripes) if (i < sub_stripes)
bbio->stripes[i].length -= bbio->stripes[i].length -=
stripe_offset; stripe_offset;
if ((i / sub_stripes + 1) %
sub_stripes == remaining_stripes) if (stripe_index >= last_stripe &&
stripe_index <= (last_stripe +
sub_stripes - 1))
bbio->stripes[i].length -= bbio->stripes[i].length -=
stripe_end_offset; stripe_end_offset;
if (i == sub_stripes - 1) if (i == sub_stripes - 1)
stripe_offset = 0; stripe_offset = 0;
} else } else