Commit 175d58cf authored by Linus Torvalds's avatar Linus Torvalds

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

Pull btrfs fixes from Chris Mason:
 "These are small and assorted.  Neil's is the oldest, I dropped the
  ball thinking he was going to send it in"

* 'for-linus-4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  Btrfs: support NFSv2 export
  Btrfs: open_ctree: Fix possible memory leak
  Btrfs: fix deadlock when finalizing block group creation
  Btrfs: update fix for read corruption of compressed and shared extents
  Btrfs: send, fix corner case for reference overwrite detection
parents 38aa0a59 7d35199e
...@@ -2847,6 +2847,8 @@ int open_ctree(struct super_block *sb, ...@@ -2847,6 +2847,8 @@ int open_ctree(struct super_block *sb,
!extent_buffer_uptodate(chunk_root->node)) { !extent_buffer_uptodate(chunk_root->node)) {
printk(KERN_ERR "BTRFS: failed to read chunk root on %s\n", printk(KERN_ERR "BTRFS: failed to read chunk root on %s\n",
sb->s_id); sb->s_id);
if (!IS_ERR(chunk_root->node))
free_extent_buffer(chunk_root->node);
chunk_root->node = NULL; chunk_root->node = NULL;
goto fail_tree_roots; goto fail_tree_roots;
} }
...@@ -2885,6 +2887,8 @@ int open_ctree(struct super_block *sb, ...@@ -2885,6 +2887,8 @@ int open_ctree(struct super_block *sb,
!extent_buffer_uptodate(tree_root->node)) { !extent_buffer_uptodate(tree_root->node)) {
printk(KERN_WARNING "BTRFS: failed to read tree root on %s\n", printk(KERN_WARNING "BTRFS: failed to read tree root on %s\n",
sb->s_id); sb->s_id);
if (!IS_ERR(tree_root->node))
free_extent_buffer(tree_root->node);
tree_root->node = NULL; tree_root->node = NULL;
goto recovery_tree_root; goto recovery_tree_root;
} }
......
...@@ -112,11 +112,11 @@ static struct dentry *btrfs_fh_to_parent(struct super_block *sb, struct fid *fh, ...@@ -112,11 +112,11 @@ static struct dentry *btrfs_fh_to_parent(struct super_block *sb, struct fid *fh,
u32 generation; u32 generation;
if (fh_type == FILEID_BTRFS_WITH_PARENT) { if (fh_type == FILEID_BTRFS_WITH_PARENT) {
if (fh_len != BTRFS_FID_SIZE_CONNECTABLE) if (fh_len < BTRFS_FID_SIZE_CONNECTABLE)
return NULL; return NULL;
root_objectid = fid->root_objectid; root_objectid = fid->root_objectid;
} else if (fh_type == FILEID_BTRFS_WITH_PARENT_ROOT) { } else if (fh_type == FILEID_BTRFS_WITH_PARENT_ROOT) {
if (fh_len != BTRFS_FID_SIZE_CONNECTABLE_ROOT) if (fh_len < BTRFS_FID_SIZE_CONNECTABLE_ROOT)
return NULL; return NULL;
root_objectid = fid->parent_root_objectid; root_objectid = fid->parent_root_objectid;
} else } else
...@@ -136,11 +136,11 @@ static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh, ...@@ -136,11 +136,11 @@ static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh,
u32 generation; u32 generation;
if ((fh_type != FILEID_BTRFS_WITH_PARENT || if ((fh_type != FILEID_BTRFS_WITH_PARENT ||
fh_len != BTRFS_FID_SIZE_CONNECTABLE) && fh_len < BTRFS_FID_SIZE_CONNECTABLE) &&
(fh_type != FILEID_BTRFS_WITH_PARENT_ROOT || (fh_type != FILEID_BTRFS_WITH_PARENT_ROOT ||
fh_len != BTRFS_FID_SIZE_CONNECTABLE_ROOT) && fh_len < BTRFS_FID_SIZE_CONNECTABLE_ROOT) &&
(fh_type != FILEID_BTRFS_WITHOUT_PARENT || (fh_type != FILEID_BTRFS_WITHOUT_PARENT ||
fh_len != BTRFS_FID_SIZE_NON_CONNECTABLE)) fh_len < BTRFS_FID_SIZE_NON_CONNECTABLE))
return NULL; return NULL;
objectid = fid->objectid; objectid = fid->objectid;
......
...@@ -2828,6 +2828,7 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, ...@@ -2828,6 +2828,7 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
struct btrfs_delayed_ref_head *head; struct btrfs_delayed_ref_head *head;
int ret; int ret;
int run_all = count == (unsigned long)-1; int run_all = count == (unsigned long)-1;
bool can_flush_pending_bgs = trans->can_flush_pending_bgs;
/* We'll clean this up in btrfs_cleanup_transaction */ /* We'll clean this up in btrfs_cleanup_transaction */
if (trans->aborted) if (trans->aborted)
...@@ -2844,6 +2845,7 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, ...@@ -2844,6 +2845,7 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
#ifdef SCRAMBLE_DELAYED_REFS #ifdef SCRAMBLE_DELAYED_REFS
delayed_refs->run_delayed_start = find_middle(&delayed_refs->root); delayed_refs->run_delayed_start = find_middle(&delayed_refs->root);
#endif #endif
trans->can_flush_pending_bgs = false;
ret = __btrfs_run_delayed_refs(trans, root, count); ret = __btrfs_run_delayed_refs(trans, root, count);
if (ret < 0) { if (ret < 0) {
btrfs_abort_transaction(trans, root, ret); btrfs_abort_transaction(trans, root, ret);
...@@ -2893,6 +2895,7 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, ...@@ -2893,6 +2895,7 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
} }
out: out:
assert_qgroups_uptodate(trans); assert_qgroups_uptodate(trans);
trans->can_flush_pending_bgs = can_flush_pending_bgs;
return 0; return 0;
} }
...@@ -4306,7 +4309,8 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, ...@@ -4306,7 +4309,8 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
* the block groups that were made dirty during the lifetime of the * the block groups that were made dirty during the lifetime of the
* transaction. * transaction.
*/ */
if (trans->chunk_bytes_reserved >= (2 * 1024 * 1024ull)) { if (trans->can_flush_pending_bgs &&
trans->chunk_bytes_reserved >= (2 * 1024 * 1024ull)) {
btrfs_create_pending_block_groups(trans, trans->root); btrfs_create_pending_block_groups(trans, trans->root);
btrfs_trans_release_chunk_metadata(trans); btrfs_trans_release_chunk_metadata(trans);
} }
...@@ -9560,7 +9564,9 @@ void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans, ...@@ -9560,7 +9564,9 @@ void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans,
struct btrfs_block_group_item item; struct btrfs_block_group_item item;
struct btrfs_key key; struct btrfs_key key;
int ret = 0; int ret = 0;
bool can_flush_pending_bgs = trans->can_flush_pending_bgs;
trans->can_flush_pending_bgs = false;
list_for_each_entry_safe(block_group, tmp, &trans->new_bgs, bg_list) { list_for_each_entry_safe(block_group, tmp, &trans->new_bgs, bg_list) {
if (ret) if (ret)
goto next; goto next;
...@@ -9581,6 +9587,7 @@ void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans, ...@@ -9581,6 +9587,7 @@ void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans,
next: next:
list_del_init(&block_group->bg_list); list_del_init(&block_group->bg_list);
} }
trans->can_flush_pending_bgs = can_flush_pending_bgs;
} }
int btrfs_make_block_group(struct btrfs_trans_handle *trans, int btrfs_make_block_group(struct btrfs_trans_handle *trans,
......
...@@ -3132,12 +3132,12 @@ static inline void __do_contiguous_readpages(struct extent_io_tree *tree, ...@@ -3132,12 +3132,12 @@ static inline void __do_contiguous_readpages(struct extent_io_tree *tree,
get_extent_t *get_extent, get_extent_t *get_extent,
struct extent_map **em_cached, struct extent_map **em_cached,
struct bio **bio, int mirror_num, struct bio **bio, int mirror_num,
unsigned long *bio_flags, int rw) unsigned long *bio_flags, int rw,
u64 *prev_em_start)
{ {
struct inode *inode; struct inode *inode;
struct btrfs_ordered_extent *ordered; struct btrfs_ordered_extent *ordered;
int index; int index;
u64 prev_em_start = (u64)-1;
inode = pages[0]->mapping->host; inode = pages[0]->mapping->host;
while (1) { while (1) {
...@@ -3153,7 +3153,7 @@ static inline void __do_contiguous_readpages(struct extent_io_tree *tree, ...@@ -3153,7 +3153,7 @@ static inline void __do_contiguous_readpages(struct extent_io_tree *tree,
for (index = 0; index < nr_pages; index++) { for (index = 0; index < nr_pages; index++) {
__do_readpage(tree, pages[index], get_extent, em_cached, bio, __do_readpage(tree, pages[index], get_extent, em_cached, bio,
mirror_num, bio_flags, rw, &prev_em_start); mirror_num, bio_flags, rw, prev_em_start);
page_cache_release(pages[index]); page_cache_release(pages[index]);
} }
} }
...@@ -3163,7 +3163,8 @@ static void __extent_readpages(struct extent_io_tree *tree, ...@@ -3163,7 +3163,8 @@ static void __extent_readpages(struct extent_io_tree *tree,
int nr_pages, get_extent_t *get_extent, int nr_pages, get_extent_t *get_extent,
struct extent_map **em_cached, struct extent_map **em_cached,
struct bio **bio, int mirror_num, struct bio **bio, int mirror_num,
unsigned long *bio_flags, int rw) unsigned long *bio_flags, int rw,
u64 *prev_em_start)
{ {
u64 start = 0; u64 start = 0;
u64 end = 0; u64 end = 0;
...@@ -3184,7 +3185,7 @@ static void __extent_readpages(struct extent_io_tree *tree, ...@@ -3184,7 +3185,7 @@ static void __extent_readpages(struct extent_io_tree *tree,
index - first_index, start, index - first_index, start,
end, get_extent, em_cached, end, get_extent, em_cached,
bio, mirror_num, bio_flags, bio, mirror_num, bio_flags,
rw); rw, prev_em_start);
start = page_start; start = page_start;
end = start + PAGE_CACHE_SIZE - 1; end = start + PAGE_CACHE_SIZE - 1;
first_index = index; first_index = index;
...@@ -3195,7 +3196,8 @@ static void __extent_readpages(struct extent_io_tree *tree, ...@@ -3195,7 +3196,8 @@ static void __extent_readpages(struct extent_io_tree *tree,
__do_contiguous_readpages(tree, &pages[first_index], __do_contiguous_readpages(tree, &pages[first_index],
index - first_index, start, index - first_index, start,
end, get_extent, em_cached, bio, end, get_extent, em_cached, bio,
mirror_num, bio_flags, rw); mirror_num, bio_flags, rw,
prev_em_start);
} }
static int __extent_read_full_page(struct extent_io_tree *tree, static int __extent_read_full_page(struct extent_io_tree *tree,
...@@ -4207,6 +4209,7 @@ int extent_readpages(struct extent_io_tree *tree, ...@@ -4207,6 +4209,7 @@ int extent_readpages(struct extent_io_tree *tree,
struct page *page; struct page *page;
struct extent_map *em_cached = NULL; struct extent_map *em_cached = NULL;
int nr = 0; int nr = 0;
u64 prev_em_start = (u64)-1;
for (page_idx = 0; page_idx < nr_pages; page_idx++) { for (page_idx = 0; page_idx < nr_pages; page_idx++) {
page = list_entry(pages->prev, struct page, lru); page = list_entry(pages->prev, struct page, lru);
...@@ -4223,12 +4226,12 @@ int extent_readpages(struct extent_io_tree *tree, ...@@ -4223,12 +4226,12 @@ int extent_readpages(struct extent_io_tree *tree,
if (nr < ARRAY_SIZE(pagepool)) if (nr < ARRAY_SIZE(pagepool))
continue; continue;
__extent_readpages(tree, pagepool, nr, get_extent, &em_cached, __extent_readpages(tree, pagepool, nr, get_extent, &em_cached,
&bio, 0, &bio_flags, READ); &bio, 0, &bio_flags, READ, &prev_em_start);
nr = 0; nr = 0;
} }
if (nr) if (nr)
__extent_readpages(tree, pagepool, nr, get_extent, &em_cached, __extent_readpages(tree, pagepool, nr, get_extent, &em_cached,
&bio, 0, &bio_flags, READ); &bio, 0, &bio_flags, READ, &prev_em_start);
if (em_cached) if (em_cached)
free_extent_map(em_cached); free_extent_map(em_cached);
......
...@@ -1920,10 +1920,12 @@ static int did_overwrite_ref(struct send_ctx *sctx, ...@@ -1920,10 +1920,12 @@ static int did_overwrite_ref(struct send_ctx *sctx,
/* /*
* We know that it is or will be overwritten. Check this now. * We know that it is or will be overwritten. Check this now.
* The current inode being processed might have been the one that caused * The current inode being processed might have been the one that caused
* inode 'ino' to be orphanized, therefore ow_inode can actually be the * inode 'ino' to be orphanized, therefore check if ow_inode matches
* same as sctx->send_progress. * the current inode being processed.
*/ */
if (ow_inode <= sctx->send_progress) if ((ow_inode < sctx->send_progress) ||
(ino != sctx->cur_ino && ow_inode == sctx->cur_ino &&
gen == sctx->cur_inode_gen))
ret = 1; ret = 1;
else else
ret = 0; ret = 0;
......
...@@ -557,6 +557,7 @@ start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type, ...@@ -557,6 +557,7 @@ start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
h->delayed_ref_elem.seq = 0; h->delayed_ref_elem.seq = 0;
h->type = type; h->type = type;
h->allocating_chunk = false; h->allocating_chunk = false;
h->can_flush_pending_bgs = true;
h->reloc_reserved = false; h->reloc_reserved = false;
h->sync = false; h->sync = false;
INIT_LIST_HEAD(&h->qgroup_ref_list); INIT_LIST_HEAD(&h->qgroup_ref_list);
......
...@@ -118,6 +118,7 @@ struct btrfs_trans_handle { ...@@ -118,6 +118,7 @@ struct btrfs_trans_handle {
short aborted; short aborted;
short adding_csums; short adding_csums;
bool allocating_chunk; bool allocating_chunk;
bool can_flush_pending_bgs;
bool reloc_reserved; bool reloc_reserved;
bool sync; bool sync;
unsigned int type; unsigned int type;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment