diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-04-05 13:21:15 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-04-05 13:21:15 -0700 |
commit | 795d580baec0d5386b83a8b557df47c20810e86b (patch) | |
tree | d0387c37562e9e27a4f43cf7ae425319cbdad359 /fs/btrfs | |
parent | 449cedf099b23a250e7d61982e35555ccb871182 (diff) | |
parent | 109f6aef5fc436f355ad027f4d97bd696df2049a (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable
* git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable:
Btrfs: add check for changed leaves in setup_leaf_for_split
Btrfs: create snapshot references in same commit as snapshot
Btrfs: fix small race with delalloc flushing waitqueue's
Btrfs: use add_to_page_cache_lru, use __page_cache_alloc
Btrfs: fix chunk allocate size calculation
Btrfs: kill max_extent mount option
Btrfs: fail to mount if we have problems reading the block groups
Btrfs: check btrfs_get_extent return for IS_ERR()
Btrfs: handle kmalloc() failure in inode lookup ioctl
Btrfs: dereferencing freed memory
Btrfs: Simplify num_stripes's calculation logical for __btrfs_alloc_chunk()
Btrfs: Add error handle for btrfs_search_slot() in btrfs_read_chunk_tree()
Btrfs: Remove unnecessary finish_wait() in wait_current_trans()
Btrfs: add NULL check for do_walk_down()
Btrfs: remove duplicate include in ioctl.c
Fix trivial conflict in fs/btrfs/compression.c due to slab.h include
cleanups.
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/compression.c | 22 | ||||
-rw-r--r-- | fs/btrfs/ctree.c | 4 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 1 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 12 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 23 | ||||
-rw-r--r-- | fs/btrfs/extent_io.c | 15 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 59 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 7 | ||||
-rw-r--r-- | fs/btrfs/ordered-data.c | 6 | ||||
-rw-r--r-- | fs/btrfs/super.c | 23 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 112 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 10 |
12 files changed, 90 insertions, 204 deletions
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index 629880ec8ac..396039b3a8a 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -31,7 +31,6 @@ #include <linux/swap.h> #include <linux/writeback.h> #include <linux/bit_spinlock.h> -#include <linux/pagevec.h> #include <linux/slab.h> #include "compat.h" #include "ctree.h" @@ -446,7 +445,6 @@ static noinline int add_ra_bio_pages(struct inode *inode, unsigned long nr_pages = 0; struct extent_map *em; struct address_space *mapping = inode->i_mapping; - struct pagevec pvec; struct extent_map_tree *em_tree; struct extent_io_tree *tree; u64 end; @@ -462,7 +460,6 @@ static noinline int add_ra_bio_pages(struct inode *inode, end_index = (i_size_read(inode) - 1) >> PAGE_CACHE_SHIFT; - pagevec_init(&pvec, 0); while (last_offset < compressed_end) { page_index = last_offset >> PAGE_CACHE_SHIFT; @@ -479,26 +476,17 @@ static noinline int add_ra_bio_pages(struct inode *inode, goto next; } - page = alloc_page(mapping_gfp_mask(mapping) & ~__GFP_FS); + page = __page_cache_alloc(mapping_gfp_mask(mapping) & + ~__GFP_FS); if (!page) break; - page->index = page_index; - /* - * what we want to do here is call add_to_page_cache_lru, - * but that isn't exported, so we reproduce it here - */ - if (add_to_page_cache(page, mapping, - page->index, GFP_NOFS)) { + if (add_to_page_cache_lru(page, mapping, page_index, + GFP_NOFS)) { page_cache_release(page); goto next; } - /* open coding of lru_cache_add, also not exported */ - page_cache_get(page); - if (!pagevec_add(&pvec, page)) - __pagevec_lru_add_file(&pvec); - end = last_offset + PAGE_CACHE_SIZE - 1; /* * at this point, we have a locked page in the page cache @@ -552,8 +540,6 @@ static noinline int add_ra_bio_pages(struct inode *inode, next: last_offset += PAGE_CACHE_SIZE; } - if (pagevec_count(&pvec)) - __pagevec_lru_add_file(&pvec); return 0; } diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 8e29260cd0b..6795a713b20 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -3041,6 +3041,10 @@ static noinline int setup_leaf_for_split(struct btrfs_trans_handle *trans, if (ret > 0 || item_size != btrfs_item_size_nr(leaf, path->slots[0])) goto err; + /* the leaf has changed, it now has room. return now */ + if (btrfs_leaf_free_space(root, path->nodes[0]) >= ins_len) + goto err; + if (key.type == BTRFS_EXTENT_DATA_KEY) { fi = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item); diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 8a6518a3f04..746a7248678 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -835,7 +835,6 @@ struct btrfs_fs_info { u64 last_trans_log_full_commit; u64 open_ioctl_trans; unsigned long mount_opt; - u64 max_extent; u64 max_inline; u64 alloc_start; struct btrfs_transaction *running_transaction; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index e57ded75d91..e7b8f2c89cc 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1635,7 +1635,6 @@ struct btrfs_root *open_ctree(struct super_block *sb, atomic_set(&fs_info->async_submit_draining, 0); atomic_set(&fs_info->nr_async_bios, 0); fs_info->sb = sb; - fs_info->max_extent = (u64)-1; fs_info->max_inline = 8192 * 1024; fs_info->metadata_ratio = 0; @@ -1923,7 +1922,11 @@ struct btrfs_root *open_ctree(struct super_block *sb, csum_root->track_dirty = 1; - btrfs_read_block_groups(extent_root); + ret = btrfs_read_block_groups(extent_root); + if (ret) { + printk(KERN_ERR "Failed to read block groups: %d\n", ret); + goto fail_block_groups; + } fs_info->generation = generation; fs_info->last_trans_committed = generation; @@ -1933,7 +1936,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, fs_info->cleaner_kthread = kthread_run(cleaner_kthread, tree_root, "btrfs-cleaner"); if (IS_ERR(fs_info->cleaner_kthread)) - goto fail_csum_root; + goto fail_block_groups; fs_info->transaction_kthread = kthread_run(transaction_kthread, tree_root, @@ -2021,7 +2024,8 @@ fail_cleaner: filemap_write_and_wait(fs_info->btree_inode->i_mapping); invalidate_inode_pages2(fs_info->btree_inode->i_mapping); -fail_csum_root: +fail_block_groups: + btrfs_free_block_groups(fs_info); free_extent_buffer(csum_root->node); free_extent_buffer(csum_root->commit_root); fail_dev_root: diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index fa2907d531a..9e23ffea7f5 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2677,6 +2677,8 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, INIT_LIST_HEAD(&found->block_groups); init_rwsem(&found->groups_sem); + init_waitqueue_head(&found->flush_wait); + init_waitqueue_head(&found->allocate_wait); spin_lock_init(&found->lock); found->flags = flags; found->total_bytes = total_bytes; @@ -2847,7 +2849,7 @@ int btrfs_unreserve_metadata_for_delalloc(struct btrfs_root *root, } spin_unlock(&BTRFS_I(inode)->accounting_lock); - BTRFS_I(inode)->reserved_extents--; + BTRFS_I(inode)->reserved_extents -= num_items; BUG_ON(BTRFS_I(inode)->reserved_extents < 0); if (meta_sinfo->bytes_delalloc < num_bytes) { @@ -2945,12 +2947,10 @@ static void flush_delalloc(struct btrfs_root *root, spin_lock(&info->lock); - if (!info->flushing) { + if (!info->flushing) info->flushing = 1; - init_waitqueue_head(&info->flush_wait); - } else { + else wait = true; - } spin_unlock(&info->lock); @@ -3012,7 +3012,6 @@ static int maybe_allocate_chunk(struct btrfs_root *root, if (!info->allocating_chunk) { info->force_alloc = 1; info->allocating_chunk = 1; - init_waitqueue_head(&info->allocate_wait); } else { wait = true; } @@ -3112,7 +3111,7 @@ again: return -ENOSPC; } - BTRFS_I(inode)->reserved_extents++; + BTRFS_I(inode)->reserved_extents += num_items; check_force_delalloc(meta_sinfo); spin_unlock(&meta_sinfo->lock); @@ -4171,6 +4170,10 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans, ins->offset = 0; space_info = __find_space_info(root->fs_info, data); + if (!space_info) { + printk(KERN_ERR "No space info for %d\n", data); + return -ENOSPC; + } if (orig_root->ref_cows || empty_size) allowed_chunk_alloc = 1; @@ -5206,6 +5209,8 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans, next = btrfs_find_tree_block(root, bytenr, blocksize); if (!next) { next = btrfs_find_create_tree_block(root, bytenr, blocksize); + if (!next) + return -ENOMEM; reada = 1; } btrfs_tree_lock(next); @@ -5418,7 +5423,8 @@ static noinline int walk_down_tree(struct btrfs_trans_handle *trans, if (ret > 0) { path->slots[level]++; continue; - } + } else if (ret < 0) + return ret; level = wc->level; } return 0; @@ -7370,7 +7376,6 @@ static int find_first_block_group(struct btrfs_root *root, } path->slots[0]++; } - ret = -ENOENT; out: return ret; } diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 0adceb52516..d2d03684fab 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2678,33 +2678,20 @@ int extent_readpages(struct extent_io_tree *tree, { struct bio *bio = NULL; unsigned page_idx; - struct pagevec pvec; unsigned long bio_flags = 0; - pagevec_init(&pvec, 0); for (page_idx = 0; page_idx < nr_pages; page_idx++) { struct page *page = list_entry(pages->prev, struct page, lru); prefetchw(&page->flags); list_del(&page->lru); - /* - * what we want to do here is call add_to_page_cache_lru, - * but that isn't exported, so we reproduce it here - */ - if (!add_to_page_cache(page, mapping, + if (!add_to_page_cache_lru(page, mapping, page->index, GFP_KERNEL)) { - - /* open coding of lru_cache_add, also not exported */ - page_cache_get(page); - if (!pagevec_add(&pvec, page)) - __pagevec_lru_add_file(&pvec); __extent_read_full_page(tree, page, get_extent, &bio, 0, &bio_flags); } page_cache_release(page); } - if (pagevec_count(&pvec)) - __pagevec_lru_add_file(&pvec); BUG_ON(!list_empty(pages)); if (bio) submit_one_bio(READ, bio, 0, bio_flags); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 2fe494c84e6..2bfdc641d4e 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -797,7 +797,7 @@ static noinline int cow_file_range(struct inode *inode, while (disk_num_bytes > 0) { unsigned long op; - cur_alloc_size = min(disk_num_bytes, root->fs_info->max_extent); + cur_alloc_size = disk_num_bytes; ret = btrfs_reserve_extent(trans, root, cur_alloc_size, root->sectorsize, 0, alloc_hint, (u64)-1, &ins, 1); @@ -1228,30 +1228,9 @@ static int run_delalloc_range(struct inode *inode, struct page *locked_page, static int btrfs_split_extent_hook(struct inode *inode, struct extent_state *orig, u64 split) { - struct btrfs_root *root = BTRFS_I(inode)->root; - u64 size; - if (!(orig->state & EXTENT_DELALLOC)) return 0; - size = orig->end - orig->start + 1; - if (size > root->fs_info->max_extent) { - u64 num_extents; - u64 new_size; - - new_size = orig->end - split + 1; - num_extents = div64_u64(size + root->fs_info->max_extent - 1, - root->fs_info->max_extent); - - /* - * if we break a large extent up then leave oustanding_extents - * be, since we've already accounted for the large extent. - */ - if (div64_u64(new_size + root->fs_info->max_extent - 1, - root->fs_info->max_extent) < num_extents) - return 0; - } - spin_lock(&BTRFS_I(inode)->accounting_lock); BTRFS_I(inode)->outstanding_extents++; spin_unlock(&BTRFS_I(inode)->accounting_lock); @@ -1269,38 +1248,10 @@ static int btrfs_merge_extent_hook(struct inode *inode, struct extent_state *new, struct extent_state *other) { - struct btrfs_root *root = BTRFS_I(inode)->root; - u64 new_size, old_size; - u64 num_extents; - /* not delalloc, ignore it */ if (!(other->state & EXTENT_DELALLOC)) return 0; - old_size = other->end - other->start + 1; - if (new->start < other->start) - new_size = other->end - new->start + 1; - else - new_size = new->end - other->start + 1; - - /* we're not bigger than the max, unreserve the space and go */ - if (new_size <= root->fs_info->max_extent) { - spin_lock(&BTRFS_I(inode)->accounting_lock); - BTRFS_I(inode)->outstanding_extents--; - spin_unlock(&BTRFS_I(inode)->accounting_lock); - return 0; - } - - /* - * If we grew by another max_extent, just return, we want to keep that - * reserved amount. - */ - num_extents = div64_u64(old_size + root->fs_info->max_extent - 1, - root->fs_info->max_extent); - if (div64_u64(new_size + root->fs_info->max_extent - 1, - root->fs_info->max_extent) > num_extents) - return 0; - spin_lock(&BTRFS_I(inode)->accounting_lock); BTRFS_I(inode)->outstanding_extents--; spin_unlock(&BTRFS_I(inode)->accounting_lock); @@ -1329,6 +1280,7 @@ static int btrfs_set_bit_hook(struct inode *inode, u64 start, u64 end, BTRFS_I(inode)->outstanding_extents++; spin_unlock(&BTRFS_I(inode)->accounting_lock); btrfs_delalloc_reserve_space(root, inode, end - start + 1); + spin_lock(&root->fs_info->delalloc_lock); BTRFS_I(inode)->delalloc_bytes += end - start + 1; root->fs_info->delalloc_bytes += end - start + 1; @@ -1357,6 +1309,7 @@ static int btrfs_clear_bit_hook(struct inode *inode, if (bits & EXTENT_DO_ACCOUNTING) { spin_lock(&BTRFS_I(inode)->accounting_lock); + WARN_ON(!BTRFS_I(inode)->outstanding_extents); BTRFS_I(inode)->outstanding_extents--; spin_unlock(&BTRFS_I(inode)->accounting_lock); btrfs_unreserve_metadata_for_delalloc(root, inode, 1); @@ -5385,7 +5338,6 @@ free: void btrfs_drop_inode(struct inode *inode) { struct btrfs_root *root = BTRFS_I(inode)->root; - if (inode->i_nlink > 0 && btrfs_root_refs(&root->root_item) == 0) generic_delete_inode(inode); else @@ -5789,18 +5741,15 @@ static int prealloc_file_range(struct inode *inode, u64 start, u64 end, struct btrfs_trans_handle *trans; struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_key ins; - u64 alloc_size; u64 cur_offset = start; u64 num_bytes = end - start; int ret = 0; u64 i_size; while (num_bytes > 0) { - alloc_size = min(num_bytes, root->fs_info->max_extent); - trans = btrfs_start_transaction(root, 1); - ret = btrfs_reserve_extent(trans, root, alloc_size, + ret = btrfs_reserve_extent(trans, root, num_bytes, root->sectorsize, 0, alloc_hint, (u64)-1, &ins, 1); if (ret) { diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 9b3d73a0fdc..e84ef60ffe3 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -49,7 +49,6 @@ #include "print-tree.h" #include "volumes.h" #include "locking.h" -#include "ctree.h" /* Mask out flags that are inappropriate for the given type of inode. */ static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags) @@ -512,7 +511,7 @@ static int should_defrag_range(struct inode *inode, u64 start, u64 len, em = btrfs_get_extent(inode, NULL, 0, start, len, 0); unlock_extent(io_tree, start, start + len - 1, GFP_NOFS); - if (!em) + if (IS_ERR(em)) return 0; } @@ -1213,6 +1212,9 @@ static noinline int btrfs_ioctl_ino_lookup(struct file *file, return -EPERM; args = kmalloc(sizeof(*args), GFP_KERNEL); + if (!args) + return -ENOMEM; + if (copy_from_user(args, argp, sizeof(*args))) { kfree(args); return -EFAULT; @@ -1376,6 +1378,7 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) sizeof(*range))) { ret = -EFAULT; kfree(range); + goto out; } /* compression requires us to start the IO */ if ((range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)) { diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index ecb22ff7d1f..a127c0ebb2d 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -302,6 +302,7 @@ static int __btrfs_remove_ordered_extent(struct inode *inode, struct btrfs_ordered_extent *entry) { struct btrfs_ordered_inode_tree *tree; + struct btrfs_root *root = BTRFS_I(inode)->root; struct rb_node *node; tree = &BTRFS_I(inode)->ordered_tree; @@ -311,12 +312,13 @@ static int __btrfs_remove_ordered_extent(struct inode *inode, set_bit(BTRFS_ORDERED_COMPLETE, &entry->flags); spin_lock(&BTRFS_I(inode)->accounting_lock); + WARN_ON(!BTRFS_I(inode)->outstanding_extents); BTRFS_I(inode)->outstanding_extents--; spin_unlock(&BTRFS_I(inode)->accounting_lock); btrfs_unreserve_metadata_for_delalloc(BTRFS_I(inode)->root, inode, 1); - spin_lock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock); + spin_lock(&root->fs_info->ordered_extent_lock); list_del_init(&entry->root_extent_list); /* @@ -328,7 +330,7 @@ static int __btrfs_remove_ordered_extent(struct inode *inode, !mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY)) { list_del_init(&BTRFS_I(inode)->ordered_operations); } - spin_unlock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock); + spin_unlock(&root->fs_info->ordered_extent_lock); return 0; } diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 693a664318f..1866dff0538 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -65,10 +65,9 @@ static void btrfs_put_super(struct super_block *sb) enum { Opt_degraded, Opt_subvol, Opt_subvolid, Opt_device, Opt_nodatasum, - Opt_nodatacow, Opt_max_extent, Opt_max_inline, Opt_alloc_start, - Opt_nobarrier, Opt_ssd, Opt_nossd, Opt_ssd_spread, Opt_thread_pool, - Opt_noacl, Opt_compress, Opt_compress_force, Opt_notreelog, Opt_ratio, - Opt_flushoncommit, + Opt_nodatacow, Opt_max_inline, Opt_alloc_start, Opt_nobarrier, Opt_ssd, + Opt_nossd, Opt_ssd_spread, Opt_thread_pool, Opt_noacl, Opt_compress, + Opt_compress_force, Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_discard, Opt_err, }; @@ -80,7 +79,6 @@ static match_table_t tokens = { {Opt_nodatasum, "nodatasum"}, {Opt_nodatacow, "nodatacow"}, {Opt_nobarrier, "nobarrier"}, - {Opt_max_extent, "max_extent=%s"}, {Opt_max_inline, "max_inline=%s"}, {Opt_alloc_start, "alloc_start=%s"}, {Opt_thread_pool, "thread_pool=%d"}, @@ -189,18 +187,6 @@ int btrfs_parse_options(struct btrfs_root *root, char *options) info->thread_pool_size); } break; - case Opt_max_extent: - num = match_strdup(&args[0]); - if (num) { - info->max_extent = memparse(num, NULL); - kfree(num); - - info->max_extent = max_t(u64, - info->max_extent, root->sectorsize); - printk(KERN_INFO "btrfs: max_extent at %llu\n", - (unsigned long long)info->max_extent); - } - break; case Opt_max_inline: num = match_strdup(&args[0]); if (num) { @@ -530,9 +516,6 @@ static int btrfs_show_options(struct seq_file *seq, struct vfsmount *vfs) seq_puts(seq, ",nodatacow"); if (btrfs_test_opt(root, NOBARRIER)) seq_puts(seq, ",nobarrier"); - if (info->max_extent != (u64)-1) - seq_printf(seq, ",max_extent=%llu", - (unsigned long long)info->max_extent); if (info->max_inline != 8192 * 1024) seq_printf(seq, ",max_inline=%llu", (unsigned long long)info->max_inline); diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index c0d0e3e7bc6..2cb116099b9 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -148,18 +148,13 @@ static void wait_current_trans(struct btrfs_root *root) while (1) { prepare_to_wait(&root->fs_info->transaction_wait, &wait, TASK_UNINTERRUPTIBLE); - if (cur_trans->blocked) { - mutex_unlock(&root->fs_info->trans_mutex); - schedule(); - mutex_lock(&root->fs_info->trans_mutex); - finish_wait(&root->fs_info->transaction_wait, - &wait); - } else { - finish_wait(&root->fs_info->transaction_wait, - &wait); + if (!cur_trans->blocked) break; - } + mutex_unlock(&root->fs_info->trans_mutex); + schedule(); + mutex_lock(&root->fs_info->trans_mutex); } + finish_wait(&root->fs_info->transaction_wait, &wait); put_transaction(cur_trans); } } @@ -761,10 +756,17 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root_item *new_root_item; struct btrfs_root *tree_root = fs_info->tree_root; struct btrfs_root *root = pending->root; + struct btrfs_root *parent_root; + struct inode *parent_inode; struct extent_buffer *tmp; struct extent_buffer *old; int ret; u64 objectid; + int namelen; + u64 index = 0; + + parent_inode = pending->dentry->d_parent->d_inode; + parent_root = BTRFS_I(parent_inode)->root; new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); if (!new_root_item) { @@ -775,79 +777,59 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, if (ret) goto fail; - record_root_in_trans(trans, root); - btrfs_set_root_last_snapshot(&root->root_item, trans->transid); - memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); - key.objectid = objectid; /* record when the snapshot was created in key.offset */ key.offset = trans->transid; btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); - old = btrfs_lock_root_node(root); - btrfs_cow_block(trans, root, old, NULL, 0, &old); - btrfs_set_lock_blocking(old); - - btrfs_copy_root(trans, root, old, &tmp, objectid); - btrfs_tree_unlock(old); - free_extent_buffer(old); - - btrfs_set_root_node(new_root_item, tmp); - ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, - new_root_item); - btrfs_tree_unlock(tmp); - free_extent_buffer(tmp); - if (ret) - goto fail; - - key.offset = (u64)-1; memcpy(&pending->root_key, &key, sizeof(key)); -fail: - kfree(new_root_item); - return ret; -} - -static noinline int finish_pending_snapshot(struct btrfs_fs_info *fs_info, - struct btrfs_pending_snapshot *pending) -{ - int ret; - int namelen; - u64 index = 0; - struct btrfs_trans_handle *trans; - struct inode *parent_inode; - struct btrfs_root *parent_root; - - parent_inode = pending->dentry->d_parent->d_inode; - parent_root = BTRFS_I(parent_inode)->root; - trans = btrfs_join_transaction(parent_root, 1); + pending->root_key.offset = (u64)-1; + record_root_in_trans(trans, parent_root); /* * insert the directory item */ namelen = strlen(pending->name); ret = btrfs_set_inode_index(parent_inode, &index); + BUG_ON(ret); ret = btrfs_insert_dir_item(trans, parent_root, pending->name, namelen, parent_inode->i_ino, &pending->root_key, BTRFS_FT_DIR, index); - - if (ret) - goto fail; + BUG_ON(ret); btrfs_i_size_write(parent_inode, parent_inode->i_size + namelen * 2); ret = btrfs_update_inode(trans, parent_root, parent_inode); BUG_ON(ret); + record_root_in_trans(trans, root); + btrfs_set_root_last_snapshot(&root->root_item, trans->transid); + memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); + + old = btrfs_lock_root_node(root); + btrfs_cow_block(trans, root, old, NULL, 0, &old); + btrfs_set_lock_blocking(old); + + btrfs_copy_root(trans, root, old, &tmp, objectid); + btrfs_tree_unlock(old); + free_extent_buffer(old); + + btrfs_set_root_node(new_root_item, tmp); + ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, + new_root_item); + BUG_ON(ret); + btrfs_tree_unlock(tmp); + free_extent_buffer(tmp); + ret = btrfs_add_root_ref(trans, parent_root->fs_info->tree_root, pending->root_key.objectid, parent_root->root_key.objectid, parent_inode->i_ino, index, pending->name, namelen); - BUG_ON(ret); fail: - btrfs_end_transaction(trans, fs_info->fs_root); + kfree(new_root_item); return ret; } @@ -868,25 +850,6 @@ static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans, return 0; } -static noinline int finish_pending_snapshots(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info) -{ - struct btrfs_pending_snapshot *pending; - struct list_head *head = &trans->transaction->pending_snapshots; - int ret; - - while (!list_empty(head)) { - pending = list_entry(head->next, - struct btrfs_pending_snapshot, list); - ret = finish_pending_snapshot(fs_info, pending); - BUG_ON(ret); - list_del(&pending->list); - kfree(pending->name); - kfree(pending); - } - return 0; -} - static void update_super_roots(struct btrfs_root *root) { struct btrfs_root_item *root_item; @@ -1098,9 +1061,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, btrfs_finish_extent_commit(trans, root); - /* do the directory inserts of any pending snapshot creations */ - finish_pending_snapshots(trans, root->fs_info); - mutex_lock(&root->fs_info->trans_mutex); cur_trans->commit_done = 1; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 1692ec9cd7b..aa7dc36dac7 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2199,9 +2199,9 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, min_stripes = 2; } if (type & (BTRFS_BLOCK_GROUP_RAID1)) { - num_stripes = min_t(u64, 2, fs_devices->rw_devices); - if (num_stripes < 2) + if (fs_devices->rw_devices < 2) return -ENOSPC; + num_stripes = 2; min_stripes = 2; } if (type & (BTRFS_BLOCK_GROUP_RAID10)) { @@ -2245,8 +2245,10 @@ again: do_div(calc_size, stripe_len); calc_size *= stripe_len; } + /* we don't want tiny stripes */ - calc_size = max_t(u64, min_stripe_size, calc_size); + if (!looped) + calc_size = max_t(u64, min_stripe_size, calc_size); do_div(calc_size, stripe_len); calc_size *= stripe_len; @@ -3390,6 +3392,8 @@ int btrfs_read_chunk_tree(struct btrfs_root *root) key.type = 0; again: ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) + goto error; while (1) { leaf = path->nodes[0]; slot = path->slots[0]; |