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
This commit is contained in:
commit
175d58cfed
7 changed files with 35 additions and 17 deletions
|
@ -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 @@ retry_root_backup:
|
||||||
!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,
|
||||||
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,
|
||||||
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,
|
||||||
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 @@ again:
|
||||||
#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 @@ again:
|
||||||
}
|
}
|
||||||
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 @@ out:
|
||||||
* 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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
__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,
|
||||||
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,
|
||||||
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,
|
||||||
/*
|
/*
|
||||||
* 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 @@ again:
|
||||||
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 {
|
||||||
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;
|
||||||
|
|
Loading…
Reference in a new issue