Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs
Quoth Chris: "This is later than I wanted because I got backed up running through btrfs bugs from the Oracle QA teams. But they are all bug fixes that we've queued and tested since rc1. Nothing in particular stands out, this just reflects bug fixing and QA done in parallel by all the btrfs developers. The most user visible of these is: Btrfs: clear the extent uptodate bits during parent transid failures Because that helps deal with out of date drives (say an iscsi disk that has gone away and come back). The old code wasn't always properly retrying the other mirror for this type of failure." * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: (24 commits) Btrfs: fix compiler warnings on 32 bit systems Btrfs: increase the global block reserve estimates Btrfs: clear the extent uptodate bits during parent transid failures Btrfs: add extra sanity checks on the path names in btrfs_mksubvol Btrfs: make sure we update latest_bdev Btrfs: improve error handling for btrfs_insert_dir_item callers Btrfs: be less strict on finding next node in clear_extent_bit Btrfs: fix a bug on overcommit stuff Btrfs: kick out redundant stuff in convert_extent_bit Btrfs: skip states when they does not contain bits to clear Btrfs: check return value of lookup_extent_mapping() correctly Btrfs: fix deadlock on page lock when doing auto-defragment Btrfs: fix return value check of extent_io_ops btrfs: honor umask when creating subvol root btrfs: silence warning in raid array setup btrfs: fix structs where bitfields and spinlock/atomic share 8B word btrfs: delalloc for page dirtied out-of-band in fixup worker Btrfs: fix memory leak in load_free_space_cache() btrfs: don't check DUP chunks twice Btrfs: fix trim 0 bytes after a device delete ...
This commit is contained in:
commit
855a85f704
17 changed files with 250 additions and 131 deletions
|
@ -892,6 +892,8 @@ static char *iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
|
|||
if (eb != eb_in)
|
||||
free_extent_buffer(eb);
|
||||
ret = inode_ref_info(parent, 0, fs_root, path, &found_key);
|
||||
if (ret > 0)
|
||||
ret = -ENOENT;
|
||||
if (ret)
|
||||
break;
|
||||
next_inum = found_key.offset;
|
||||
|
|
|
@ -644,7 +644,7 @@ static struct btrfsic_dev_state *btrfsic_dev_state_hashtable_lookup(
|
|||
static int btrfsic_process_superblock(struct btrfsic_state *state,
|
||||
struct btrfs_fs_devices *fs_devices)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
struct btrfs_super_block *selected_super;
|
||||
struct list_head *dev_head = &fs_devices->devices;
|
||||
struct btrfs_device *device;
|
||||
|
|
|
@ -588,6 +588,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
|
|||
page_offset(bio->bi_io_vec->bv_page),
|
||||
PAGE_CACHE_SIZE);
|
||||
read_unlock(&em_tree->lock);
|
||||
if (!em)
|
||||
return -EIO;
|
||||
|
||||
compressed_len = em->block_len;
|
||||
cb = kmalloc(compressed_bio_size(root, compressed_len), GFP_NOFS);
|
||||
|
|
|
@ -886,7 +886,7 @@ struct btrfs_block_rsv {
|
|||
u64 reserved;
|
||||
struct btrfs_space_info *space_info;
|
||||
spinlock_t lock;
|
||||
unsigned int full:1;
|
||||
unsigned int full;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -2260,6 +2260,12 @@ int open_ctree(struct super_block *sb,
|
|||
goto fail_sb_buffer;
|
||||
}
|
||||
|
||||
if (sectorsize < PAGE_SIZE) {
|
||||
printk(KERN_WARNING "btrfs: Incompatible sector size "
|
||||
"found on %s\n", sb->s_id);
|
||||
goto fail_sb_buffer;
|
||||
}
|
||||
|
||||
mutex_lock(&fs_info->chunk_mutex);
|
||||
ret = btrfs_read_sys_array(tree_root);
|
||||
mutex_unlock(&fs_info->chunk_mutex);
|
||||
|
@ -2301,6 +2307,12 @@ int open_ctree(struct super_block *sb,
|
|||
|
||||
btrfs_close_extra_devices(fs_devices);
|
||||
|
||||
if (!fs_devices->latest_bdev) {
|
||||
printk(KERN_CRIT "btrfs: failed to read devices on %s\n",
|
||||
sb->s_id);
|
||||
goto fail_tree_roots;
|
||||
}
|
||||
|
||||
retry_root_backup:
|
||||
blocksize = btrfs_level_size(tree_root,
|
||||
btrfs_super_root_level(disk_super));
|
||||
|
|
|
@ -3312,7 +3312,8 @@ int btrfs_check_data_free_space(struct inode *inode, u64 bytes)
|
|||
}
|
||||
data_sinfo->bytes_may_use += bytes;
|
||||
trace_btrfs_space_reservation(root->fs_info, "space_info",
|
||||
(u64)data_sinfo, bytes, 1);
|
||||
(u64)(unsigned long)data_sinfo,
|
||||
bytes, 1);
|
||||
spin_unlock(&data_sinfo->lock);
|
||||
|
||||
return 0;
|
||||
|
@ -3333,7 +3334,8 @@ void btrfs_free_reserved_data_space(struct inode *inode, u64 bytes)
|
|||
spin_lock(&data_sinfo->lock);
|
||||
data_sinfo->bytes_may_use -= bytes;
|
||||
trace_btrfs_space_reservation(root->fs_info, "space_info",
|
||||
(u64)data_sinfo, bytes, 0);
|
||||
(u64)(unsigned long)data_sinfo,
|
||||
bytes, 0);
|
||||
spin_unlock(&data_sinfo->lock);
|
||||
}
|
||||
|
||||
|
@ -3611,12 +3613,15 @@ static int may_commit_transaction(struct btrfs_root *root,
|
|||
if (space_info != delayed_rsv->space_info)
|
||||
return -ENOSPC;
|
||||
|
||||
spin_lock(&space_info->lock);
|
||||
spin_lock(&delayed_rsv->lock);
|
||||
if (delayed_rsv->size < bytes) {
|
||||
if (space_info->bytes_pinned + delayed_rsv->size < bytes) {
|
||||
spin_unlock(&delayed_rsv->lock);
|
||||
spin_unlock(&space_info->lock);
|
||||
return -ENOSPC;
|
||||
}
|
||||
spin_unlock(&delayed_rsv->lock);
|
||||
spin_unlock(&space_info->lock);
|
||||
|
||||
commit:
|
||||
trans = btrfs_join_transaction(root);
|
||||
|
@ -3695,9 +3700,9 @@ static int reserve_metadata_bytes(struct btrfs_root *root,
|
|||
if (used + orig_bytes <= space_info->total_bytes) {
|
||||
space_info->bytes_may_use += orig_bytes;
|
||||
trace_btrfs_space_reservation(root->fs_info,
|
||||
"space_info",
|
||||
(u64)space_info,
|
||||
orig_bytes, 1);
|
||||
"space_info",
|
||||
(u64)(unsigned long)space_info,
|
||||
orig_bytes, 1);
|
||||
ret = 0;
|
||||
} else {
|
||||
/*
|
||||
|
@ -3766,9 +3771,9 @@ static int reserve_metadata_bytes(struct btrfs_root *root,
|
|||
if (used + num_bytes < space_info->total_bytes + avail) {
|
||||
space_info->bytes_may_use += orig_bytes;
|
||||
trace_btrfs_space_reservation(root->fs_info,
|
||||
"space_info",
|
||||
(u64)space_info,
|
||||
orig_bytes, 1);
|
||||
"space_info",
|
||||
(u64)(unsigned long)space_info,
|
||||
orig_bytes, 1);
|
||||
ret = 0;
|
||||
} else {
|
||||
wait_ordered = true;
|
||||
|
@ -3913,8 +3918,8 @@ static void block_rsv_release_bytes(struct btrfs_fs_info *fs_info,
|
|||
spin_lock(&space_info->lock);
|
||||
space_info->bytes_may_use -= num_bytes;
|
||||
trace_btrfs_space_reservation(fs_info, "space_info",
|
||||
(u64)space_info,
|
||||
num_bytes, 0);
|
||||
(u64)(unsigned long)space_info,
|
||||
num_bytes, 0);
|
||||
space_info->reservation_progress++;
|
||||
spin_unlock(&space_info->lock);
|
||||
}
|
||||
|
@ -4105,7 +4110,7 @@ static u64 calc_global_metadata_size(struct btrfs_fs_info *fs_info)
|
|||
num_bytes += div64_u64(data_used + meta_used, 50);
|
||||
|
||||
if (num_bytes * 3 > meta_used)
|
||||
num_bytes = div64_u64(meta_used, 3);
|
||||
num_bytes = div64_u64(meta_used, 3) * 2;
|
||||
|
||||
return ALIGN(num_bytes, fs_info->extent_root->leafsize << 10);
|
||||
}
|
||||
|
@ -4132,14 +4137,14 @@ static void update_global_block_rsv(struct btrfs_fs_info *fs_info)
|
|||
block_rsv->reserved += num_bytes;
|
||||
sinfo->bytes_may_use += num_bytes;
|
||||
trace_btrfs_space_reservation(fs_info, "space_info",
|
||||
(u64)sinfo, num_bytes, 1);
|
||||
(u64)(unsigned long)sinfo, num_bytes, 1);
|
||||
}
|
||||
|
||||
if (block_rsv->reserved >= block_rsv->size) {
|
||||
num_bytes = block_rsv->reserved - block_rsv->size;
|
||||
sinfo->bytes_may_use -= num_bytes;
|
||||
trace_btrfs_space_reservation(fs_info, "space_info",
|
||||
(u64)sinfo, num_bytes, 0);
|
||||
(u64)(unsigned long)sinfo, num_bytes, 0);
|
||||
sinfo->reservation_progress++;
|
||||
block_rsv->reserved = block_rsv->size;
|
||||
block_rsv->full = 1;
|
||||
|
@ -4192,7 +4197,8 @@ void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
|
|||
if (!trans->bytes_reserved)
|
||||
return;
|
||||
|
||||
trace_btrfs_space_reservation(root->fs_info, "transaction", (u64)trans,
|
||||
trace_btrfs_space_reservation(root->fs_info, "transaction",
|
||||
(u64)(unsigned long)trans,
|
||||
trans->bytes_reserved, 0);
|
||||
btrfs_block_rsv_release(root, trans->block_rsv, trans->bytes_reserved);
|
||||
trans->bytes_reserved = 0;
|
||||
|
@ -4710,9 +4716,9 @@ static int btrfs_update_reserved_bytes(struct btrfs_block_group_cache *cache,
|
|||
space_info->bytes_reserved += num_bytes;
|
||||
if (reserve == RESERVE_ALLOC) {
|
||||
trace_btrfs_space_reservation(cache->fs_info,
|
||||
"space_info",
|
||||
(u64)space_info,
|
||||
num_bytes, 0);
|
||||
"space_info",
|
||||
(u64)(unsigned long)space_info,
|
||||
num_bytes, 0);
|
||||
space_info->bytes_may_use -= num_bytes;
|
||||
}
|
||||
}
|
||||
|
@ -7886,9 +7892,16 @@ int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range)
|
|||
u64 start;
|
||||
u64 end;
|
||||
u64 trimmed = 0;
|
||||
u64 total_bytes = btrfs_super_total_bytes(fs_info->super_copy);
|
||||
int ret = 0;
|
||||
|
||||
cache = btrfs_lookup_block_group(fs_info, range->start);
|
||||
/*
|
||||
* try to trim all FS space, our block group may start from non-zero.
|
||||
*/
|
||||
if (range->len == total_bytes)
|
||||
cache = btrfs_lookup_first_block_group(fs_info, range->start);
|
||||
else
|
||||
cache = btrfs_lookup_block_group(fs_info, range->start);
|
||||
|
||||
while (cache) {
|
||||
if (cache->key.objectid >= (range->start + range->len)) {
|
||||
|
|
|
@ -513,6 +513,15 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
|
|||
WARN_ON(state->end < start);
|
||||
last_end = state->end;
|
||||
|
||||
if (state->end < end && !need_resched())
|
||||
next_node = rb_next(&state->rb_node);
|
||||
else
|
||||
next_node = NULL;
|
||||
|
||||
/* the state doesn't have the wanted bits, go ahead */
|
||||
if (!(state->state & bits))
|
||||
goto next;
|
||||
|
||||
/*
|
||||
* | ---- desired range ---- |
|
||||
* | state | or
|
||||
|
@ -565,20 +574,15 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (state->end < end && prealloc && !need_resched())
|
||||
next_node = rb_next(&state->rb_node);
|
||||
else
|
||||
next_node = NULL;
|
||||
|
||||
set |= clear_state_bit(tree, state, &bits, wake);
|
||||
next:
|
||||
if (last_end == (u64)-1)
|
||||
goto out;
|
||||
start = last_end + 1;
|
||||
if (start <= end && next_node) {
|
||||
state = rb_entry(next_node, struct extent_state,
|
||||
rb_node);
|
||||
if (state->start == start)
|
||||
goto hit_next;
|
||||
goto hit_next;
|
||||
}
|
||||
goto search_again;
|
||||
|
||||
|
@ -961,8 +965,6 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
|
|||
|
||||
set_state_bits(tree, state, &bits);
|
||||
clear_state_bit(tree, state, &clear_bits, 0);
|
||||
|
||||
merge_state(tree, state);
|
||||
if (last_end == (u64)-1)
|
||||
goto out;
|
||||
|
||||
|
@ -1007,7 +1009,6 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
|
|||
if (state->end <= end) {
|
||||
set_state_bits(tree, state, &bits);
|
||||
clear_state_bit(tree, state, &clear_bits, 0);
|
||||
merge_state(tree, state);
|
||||
if (last_end == (u64)-1)
|
||||
goto out;
|
||||
start = last_end + 1;
|
||||
|
@ -1068,8 +1069,6 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
|
|||
|
||||
set_state_bits(tree, prealloc, &bits);
|
||||
clear_state_bit(tree, prealloc, &clear_bits, 0);
|
||||
|
||||
merge_state(tree, prealloc);
|
||||
prealloc = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
@ -2154,13 +2153,46 @@ static int bio_readpage_error(struct bio *failed_bio, struct page *page,
|
|||
"this_mirror=%d, num_copies=%d, in_validation=%d\n", read_mode,
|
||||
failrec->this_mirror, num_copies, failrec->in_validation);
|
||||
|
||||
tree->ops->submit_bio_hook(inode, read_mode, bio, failrec->this_mirror,
|
||||
failrec->bio_flags, 0);
|
||||
return 0;
|
||||
ret = tree->ops->submit_bio_hook(inode, read_mode, bio,
|
||||
failrec->this_mirror,
|
||||
failrec->bio_flags, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* lots and lots of room for performance fixes in the end_bio funcs */
|
||||
|
||||
int end_extent_writepage(struct page *page, int err, u64 start, u64 end)
|
||||
{
|
||||
int uptodate = (err == 0);
|
||||
struct extent_io_tree *tree;
|
||||
int ret;
|
||||
|
||||
tree = &BTRFS_I(page->mapping->host)->io_tree;
|
||||
|
||||
if (tree->ops && tree->ops->writepage_end_io_hook) {
|
||||
ret = tree->ops->writepage_end_io_hook(page, start,
|
||||
end, NULL, uptodate);
|
||||
if (ret)
|
||||
uptodate = 0;
|
||||
}
|
||||
|
||||
if (!uptodate && tree->ops &&
|
||||
tree->ops->writepage_io_failed_hook) {
|
||||
ret = tree->ops->writepage_io_failed_hook(NULL, page,
|
||||
start, end, NULL);
|
||||
/* Writeback already completed */
|
||||
if (ret == 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!uptodate) {
|
||||
clear_extent_uptodate(tree, start, end, NULL, GFP_NOFS);
|
||||
ClearPageUptodate(page);
|
||||
SetPageError(page);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* after a writepage IO is done, we need to:
|
||||
* clear the uptodate bits on error
|
||||
|
@ -2172,13 +2204,11 @@ static int bio_readpage_error(struct bio *failed_bio, struct page *page,
|
|||
*/
|
||||
static void end_bio_extent_writepage(struct bio *bio, int err)
|
||||
{
|
||||
int uptodate = err == 0;
|
||||
struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
|
||||
struct extent_io_tree *tree;
|
||||
u64 start;
|
||||
u64 end;
|
||||
int whole_page;
|
||||
int ret;
|
||||
|
||||
do {
|
||||
struct page *page = bvec->bv_page;
|
||||
|
@ -2195,28 +2225,9 @@ static void end_bio_extent_writepage(struct bio *bio, int err)
|
|||
|
||||
if (--bvec >= bio->bi_io_vec)
|
||||
prefetchw(&bvec->bv_page->flags);
|
||||
if (tree->ops && tree->ops->writepage_end_io_hook) {
|
||||
ret = tree->ops->writepage_end_io_hook(page, start,
|
||||
end, NULL, uptodate);
|
||||
if (ret)
|
||||
uptodate = 0;
|
||||
}
|
||||
|
||||
if (!uptodate && tree->ops &&
|
||||
tree->ops->writepage_io_failed_hook) {
|
||||
ret = tree->ops->writepage_io_failed_hook(bio, page,
|
||||
start, end, NULL);
|
||||
if (ret == 0) {
|
||||
uptodate = (err == 0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!uptodate) {
|
||||
clear_extent_uptodate(tree, start, end, NULL, GFP_NOFS);
|
||||
ClearPageUptodate(page);
|
||||
SetPageError(page);
|
||||
}
|
||||
if (end_extent_writepage(page, err, start, end))
|
||||
continue;
|
||||
|
||||
if (whole_page)
|
||||
end_page_writeback(page);
|
||||
|
@ -2779,9 +2790,12 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
|
|||
delalloc_start = delalloc_end + 1;
|
||||
continue;
|
||||
}
|
||||
tree->ops->fill_delalloc(inode, page, delalloc_start,
|
||||
delalloc_end, &page_started,
|
||||
&nr_written);
|
||||
ret = tree->ops->fill_delalloc(inode, page,
|
||||
delalloc_start,
|
||||
delalloc_end,
|
||||
&page_started,
|
||||
&nr_written);
|
||||
BUG_ON(ret);
|
||||
/*
|
||||
* delalloc_end is already one less than the total
|
||||
* length, so we don't subtract one from
|
||||
|
@ -2818,8 +2832,12 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
|
|||
if (tree->ops && tree->ops->writepage_start_hook) {
|
||||
ret = tree->ops->writepage_start_hook(page, start,
|
||||
page_end);
|
||||
if (ret == -EAGAIN) {
|
||||
redirty_page_for_writepage(wbc, page);
|
||||
if (ret) {
|
||||
/* Fixup worker will requeue */
|
||||
if (ret == -EBUSY)
|
||||
wbc->pages_skipped++;
|
||||
else
|
||||
redirty_page_for_writepage(wbc, page);
|
||||
update_nr_written(page, wbc, nr_written);
|
||||
unlock_page(page);
|
||||
ret = 0;
|
||||
|
@ -3289,7 +3307,7 @@ int try_release_extent_mapping(struct extent_map_tree *map,
|
|||
len = end - start + 1;
|
||||
write_lock(&map->lock);
|
||||
em = lookup_extent_mapping(map, start, len);
|
||||
if (IS_ERR_OR_NULL(em)) {
|
||||
if (!em) {
|
||||
write_unlock(&map->lock);
|
||||
break;
|
||||
}
|
||||
|
@ -3853,10 +3871,9 @@ int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
|
|||
num_pages = num_extent_pages(eb->start, eb->len);
|
||||
clear_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
|
||||
|
||||
if (eb_straddles_pages(eb)) {
|
||||
clear_extent_uptodate(tree, eb->start, eb->start + eb->len - 1,
|
||||
cached_state, GFP_NOFS);
|
||||
}
|
||||
clear_extent_uptodate(tree, eb->start, eb->start + eb->len - 1,
|
||||
cached_state, GFP_NOFS);
|
||||
|
||||
for (i = 0; i < num_pages; i++) {
|
||||
page = extent_buffer_page(eb, i);
|
||||
if (page)
|
||||
|
|
|
@ -319,4 +319,5 @@ struct btrfs_mapping_tree;
|
|||
int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start,
|
||||
u64 length, u64 logical, struct page *page,
|
||||
int mirror_num);
|
||||
int end_extent_writepage(struct page *page, int err, u64 start, u64 end);
|
||||
#endif
|
||||
|
|
|
@ -26,8 +26,8 @@ struct extent_map {
|
|||
unsigned long flags;
|
||||
struct block_device *bdev;
|
||||
atomic_t refs;
|
||||
unsigned int in_tree:1;
|
||||
unsigned int compress_type:4;
|
||||
unsigned int in_tree;
|
||||
unsigned int compress_type;
|
||||
};
|
||||
|
||||
struct extent_map_tree {
|
||||
|
|
|
@ -1604,6 +1604,14 @@ static long btrfs_fallocate(struct file *file, int mode,
|
|||
if (mode & ~FALLOC_FL_KEEP_SIZE)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/*
|
||||
* Make sure we have enough space before we do the
|
||||
* allocation.
|
||||
*/
|
||||
ret = btrfs_check_data_free_space(inode, len);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* wait for ordered IO before we have any locks. We'll loop again
|
||||
* below with the locks held.
|
||||
|
@ -1667,27 +1675,12 @@ static long btrfs_fallocate(struct file *file, int mode,
|
|||
if (em->block_start == EXTENT_MAP_HOLE ||
|
||||
(cur_offset >= inode->i_size &&
|
||||
!test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) {
|
||||
|
||||
/*
|
||||
* Make sure we have enough space before we do the
|
||||
* allocation.
|
||||
*/
|
||||
ret = btrfs_check_data_free_space(inode, last_byte -
|
||||
cur_offset);
|
||||
if (ret) {
|
||||
free_extent_map(em);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = btrfs_prealloc_file_range(inode, mode, cur_offset,
|
||||
last_byte - cur_offset,
|
||||
1 << inode->i_blkbits,
|
||||
offset + len,
|
||||
&alloc_hint);
|
||||
|
||||
/* Let go of our reservation. */
|
||||
btrfs_free_reserved_data_space(inode, last_byte -
|
||||
cur_offset);
|
||||
if (ret < 0) {
|
||||
free_extent_map(em);
|
||||
break;
|
||||
|
@ -1715,6 +1708,8 @@ static long btrfs_fallocate(struct file *file, int mode,
|
|||
&cached_state, GFP_NOFS);
|
||||
out:
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
/* Let go of our reservation. */
|
||||
btrfs_free_reserved_data_space(inode, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1761,7 +1756,7 @@ static int find_desired_extent(struct inode *inode, loff_t *offset, int origin)
|
|||
start - root->sectorsize,
|
||||
root->sectorsize, 0);
|
||||
if (IS_ERR(em)) {
|
||||
ret = -ENXIO;
|
||||
ret = PTR_ERR(em);
|
||||
goto out;
|
||||
}
|
||||
last_end = em->start + em->len;
|
||||
|
@ -1773,7 +1768,7 @@ static int find_desired_extent(struct inode *inode, loff_t *offset, int origin)
|
|||
while (1) {
|
||||
em = btrfs_get_extent_fiemap(inode, NULL, 0, start, len, 0);
|
||||
if (IS_ERR(em)) {
|
||||
ret = -ENXIO;
|
||||
ret = PTR_ERR(em);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -777,6 +777,7 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
|
|||
spin_lock(&block_group->lock);
|
||||
if (block_group->disk_cache_state != BTRFS_DC_WRITTEN) {
|
||||
spin_unlock(&block_group->lock);
|
||||
btrfs_free_path(path);
|
||||
goto out;
|
||||
}
|
||||
spin_unlock(&block_group->lock);
|
||||
|
|
|
@ -438,7 +438,8 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
|
|||
trans->bytes_reserved);
|
||||
if (ret)
|
||||
goto out;
|
||||
trace_btrfs_space_reservation(root->fs_info, "ino_cache", (u64)trans,
|
||||
trace_btrfs_space_reservation(root->fs_info, "ino_cache",
|
||||
(u64)(unsigned long)trans,
|
||||
trans->bytes_reserved, 1);
|
||||
again:
|
||||
inode = lookup_free_ino_inode(root, path);
|
||||
|
@ -500,7 +501,8 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
|
|||
out_put:
|
||||
iput(inode);
|
||||
out_release:
|
||||
trace_btrfs_space_reservation(root->fs_info, "ino_cache", (u64)trans,
|
||||
trace_btrfs_space_reservation(root->fs_info, "ino_cache",
|
||||
(u64)(unsigned long)trans,
|
||||
trans->bytes_reserved, 0);
|
||||
btrfs_block_rsv_release(root, trans->block_rsv, trans->bytes_reserved);
|
||||
out:
|
||||
|
|
|
@ -1555,6 +1555,7 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work)
|
|||
struct inode *inode;
|
||||
u64 page_start;
|
||||
u64 page_end;
|
||||
int ret;
|
||||
|
||||
fixup = container_of(work, struct btrfs_writepage_fixup, work);
|
||||
page = fixup->page;
|
||||
|
@ -1582,12 +1583,21 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work)
|
|||
page_end, &cached_state, GFP_NOFS);
|
||||
unlock_page(page);
|
||||
btrfs_start_ordered_extent(inode, ordered, 1);
|
||||
btrfs_put_ordered_extent(ordered);
|
||||
goto again;
|
||||
}
|
||||
|
||||
BUG();
|
||||
ret = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE);
|
||||
if (ret) {
|
||||
mapping_set_error(page->mapping, ret);
|
||||
end_extent_writepage(page, ret, page_start, page_end);
|
||||
ClearPageChecked(page);
|
||||
goto out;
|
||||
}
|
||||
|
||||
btrfs_set_extent_delalloc(inode, page_start, page_end, &cached_state);
|
||||
ClearPageChecked(page);
|
||||
set_page_dirty(page);
|
||||
out:
|
||||
unlock_extent_cached(&BTRFS_I(inode)->io_tree, page_start, page_end,
|
||||
&cached_state, GFP_NOFS);
|
||||
|
@ -1630,7 +1640,7 @@ static int btrfs_writepage_start_hook(struct page *page, u64 start, u64 end)
|
|||
fixup->work.func = btrfs_writepage_fixup_worker;
|
||||
fixup->page = page;
|
||||
btrfs_queue_worker(&root->fs_info->fixup_workers, &fixup->work);
|
||||
return -EAGAIN;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
|
||||
|
@ -4575,7 +4585,8 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
|
|||
ret = btrfs_insert_dir_item(trans, root, name, name_len,
|
||||
parent_inode, &key,
|
||||
btrfs_inode_type(inode), index);
|
||||
BUG_ON(ret);
|
||||
if (ret)
|
||||
goto fail_dir_item;
|
||||
|
||||
btrfs_i_size_write(parent_inode, parent_inode->i_size +
|
||||
name_len * 2);
|
||||
|
@ -4583,6 +4594,23 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
|
|||
ret = btrfs_update_inode(trans, root, parent_inode);
|
||||
}
|
||||
return ret;
|
||||
|
||||
fail_dir_item:
|
||||
if (unlikely(ino == BTRFS_FIRST_FREE_OBJECTID)) {
|
||||
u64 local_index;
|
||||
int err;
|
||||
err = btrfs_del_root_ref(trans, root->fs_info->tree_root,
|
||||
key.objectid, root->root_key.objectid,
|
||||
parent_ino, &local_index, name, name_len);
|
||||
|
||||
} else if (add_backref) {
|
||||
u64 local_index;
|
||||
int err;
|
||||
|
||||
err = btrfs_del_inode_ref(trans, root, name, name_len,
|
||||
ino, parent_ino, &local_index);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int btrfs_add_nondir(struct btrfs_trans_handle *trans,
|
||||
|
@ -6696,8 +6724,10 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
|
|||
int err;
|
||||
u64 index = 0;
|
||||
|
||||
inode = btrfs_new_inode(trans, new_root, NULL, "..", 2, new_dirid,
|
||||
new_dirid, S_IFDIR | 0700, &index);
|
||||
inode = btrfs_new_inode(trans, new_root, NULL, "..", 2,
|
||||
new_dirid, new_dirid,
|
||||
S_IFDIR | (~current_umask() & S_IRWXUGO),
|
||||
&index);
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
inode->i_op = &btrfs_dir_inode_operations;
|
||||
|
|
|
@ -861,6 +861,7 @@ static int cluster_pages_for_defrag(struct inode *inode,
|
|||
int i_done;
|
||||
struct btrfs_ordered_extent *ordered;
|
||||
struct extent_state *cached_state = NULL;
|
||||
struct extent_io_tree *tree;
|
||||
gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping);
|
||||
|
||||
if (isize == 0)
|
||||
|
@ -871,18 +872,34 @@ static int cluster_pages_for_defrag(struct inode *inode,
|
|||
num_pages << PAGE_CACHE_SHIFT);
|
||||
if (ret)
|
||||
return ret;
|
||||
again:
|
||||
ret = 0;
|
||||
i_done = 0;
|
||||
tree = &BTRFS_I(inode)->io_tree;
|
||||
|
||||
/* step one, lock all the pages */
|
||||
for (i = 0; i < num_pages; i++) {
|
||||
struct page *page;
|
||||
again:
|
||||
page = find_or_create_page(inode->i_mapping,
|
||||
start_index + i, mask);
|
||||
start_index + i, mask);
|
||||
if (!page)
|
||||
break;
|
||||
|
||||
page_start = page_offset(page);
|
||||
page_end = page_start + PAGE_CACHE_SIZE - 1;
|
||||
while (1) {
|
||||
lock_extent(tree, page_start, page_end, GFP_NOFS);
|
||||
ordered = btrfs_lookup_ordered_extent(inode,
|
||||
page_start);
|
||||
unlock_extent(tree, page_start, page_end, GFP_NOFS);
|
||||
if (!ordered)
|
||||
break;
|
||||
|
||||
unlock_page(page);
|
||||
btrfs_start_ordered_extent(inode, ordered, 1);
|
||||
btrfs_put_ordered_extent(ordered);
|
||||
lock_page(page);
|
||||
}
|
||||
|
||||
if (!PageUptodate(page)) {
|
||||
btrfs_readpage(NULL, page);
|
||||
lock_page(page);
|
||||
|
@ -893,15 +910,22 @@ static int cluster_pages_for_defrag(struct inode *inode,
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
isize = i_size_read(inode);
|
||||
file_end = (isize - 1) >> PAGE_CACHE_SHIFT;
|
||||
if (!isize || page->index > file_end ||
|
||||
page->mapping != inode->i_mapping) {
|
||||
if (!isize || page->index > file_end) {
|
||||
/* whoops, we blew past eof, skip this page */
|
||||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
break;
|
||||
}
|
||||
|
||||
if (page->mapping != inode->i_mapping) {
|
||||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
goto again;
|
||||
}
|
||||
|
||||
pages[i] = page;
|
||||
i_done++;
|
||||
}
|
||||
|
@ -924,25 +948,6 @@ static int cluster_pages_for_defrag(struct inode *inode,
|
|||
lock_extent_bits(&BTRFS_I(inode)->io_tree,
|
||||
page_start, page_end - 1, 0, &cached_state,
|
||||
GFP_NOFS);
|
||||
ordered = btrfs_lookup_first_ordered_extent(inode, page_end - 1);
|
||||
if (ordered &&
|
||||
ordered->file_offset + ordered->len > page_start &&
|
||||
ordered->file_offset < page_end) {
|
||||
btrfs_put_ordered_extent(ordered);
|
||||
unlock_extent_cached(&BTRFS_I(inode)->io_tree,
|
||||
page_start, page_end - 1,
|
||||
&cached_state, GFP_NOFS);
|
||||
for (i = 0; i < i_done; i++) {
|
||||
unlock_page(pages[i]);
|
||||
page_cache_release(pages[i]);
|
||||
}
|
||||
btrfs_wait_ordered_range(inode, page_start,
|
||||
page_end - page_start);
|
||||
goto again;
|
||||
}
|
||||
if (ordered)
|
||||
btrfs_put_ordered_extent(ordered);
|
||||
|
||||
clear_extent_bit(&BTRFS_I(inode)->io_tree, page_start,
|
||||
page_end - 1, EXTENT_DIRTY | EXTENT_DELALLOC |
|
||||
EXTENT_DO_ACCOUNTING, 0, 0, &cached_state,
|
||||
|
@ -1327,6 +1332,12 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (name[0] == '.' &&
|
||||
(namelen == 1 || (name[1] == '.' && namelen == 2))) {
|
||||
ret = -EEXIST;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (subvol) {
|
||||
ret = btrfs_mksubvol(&file->f_path, name, namelen,
|
||||
NULL, transid, readonly);
|
||||
|
|
|
@ -1367,7 +1367,8 @@ static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev,
|
|||
}
|
||||
|
||||
static noinline_for_stack int scrub_chunk(struct scrub_dev *sdev,
|
||||
u64 chunk_tree, u64 chunk_objectid, u64 chunk_offset, u64 length)
|
||||
u64 chunk_tree, u64 chunk_objectid, u64 chunk_offset, u64 length,
|
||||
u64 dev_offset)
|
||||
{
|
||||
struct btrfs_mapping_tree *map_tree =
|
||||
&sdev->dev->dev_root->fs_info->mapping_tree;
|
||||
|
@ -1391,7 +1392,8 @@ static noinline_for_stack int scrub_chunk(struct scrub_dev *sdev,
|
|||
goto out;
|
||||
|
||||
for (i = 0; i < map->num_stripes; ++i) {
|
||||
if (map->stripes[i].dev == sdev->dev) {
|
||||
if (map->stripes[i].dev == sdev->dev &&
|
||||
map->stripes[i].physical == dev_offset) {
|
||||
ret = scrub_stripe(sdev, map, i, chunk_offset, length);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
@ -1487,7 +1489,7 @@ int scrub_enumerate_chunks(struct scrub_dev *sdev, u64 start, u64 end)
|
|||
break;
|
||||
}
|
||||
ret = scrub_chunk(sdev, chunk_tree, chunk_objectid,
|
||||
chunk_offset, length);
|
||||
chunk_offset, length, found_key.offset);
|
||||
btrfs_put_block_group(cache);
|
||||
if (ret)
|
||||
break;
|
||||
|
|
|
@ -327,7 +327,8 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
|
|||
|
||||
if (num_bytes) {
|
||||
trace_btrfs_space_reservation(root->fs_info, "transaction",
|
||||
(u64)h, num_bytes, 1);
|
||||
(u64)(unsigned long)h,
|
||||
num_bytes, 1);
|
||||
h->block_rsv = &root->fs_info->trans_block_rsv;
|
||||
h->bytes_reserved = num_bytes;
|
||||
}
|
||||
|
@ -915,7 +916,11 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
|
|||
dentry->d_name.name, dentry->d_name.len,
|
||||
parent_inode, &key,
|
||||
BTRFS_FT_DIR, index);
|
||||
BUG_ON(ret);
|
||||
if (ret) {
|
||||
pending->error = -EEXIST;
|
||||
dput(parent);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
btrfs_i_size_write(parent_inode, parent_inode->i_size +
|
||||
dentry->d_name.len * 2);
|
||||
|
@ -993,12 +998,9 @@ static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans,
|
|||
{
|
||||
struct btrfs_pending_snapshot *pending;
|
||||
struct list_head *head = &trans->transaction->pending_snapshots;
|
||||
int ret;
|
||||
|
||||
list_for_each_entry(pending, head, list) {
|
||||
ret = create_pending_snapshot(trans, fs_info, pending);
|
||||
BUG_ON(ret);
|
||||
}
|
||||
list_for_each_entry(pending, head, list)
|
||||
create_pending_snapshot(trans, fs_info, pending);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -459,12 +459,23 @@ int btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices)
|
|||
{
|
||||
struct btrfs_device *device, *next;
|
||||
|
||||
struct block_device *latest_bdev = NULL;
|
||||
u64 latest_devid = 0;
|
||||
u64 latest_transid = 0;
|
||||
|
||||
mutex_lock(&uuid_mutex);
|
||||
again:
|
||||
/* This is the initialized path, it is safe to release the devices. */
|
||||
list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) {
|
||||
if (device->in_fs_metadata)
|
||||
if (device->in_fs_metadata) {
|
||||
if (!latest_transid ||
|
||||
device->generation > latest_transid) {
|
||||
latest_devid = device->devid;
|
||||
latest_transid = device->generation;
|
||||
latest_bdev = device->bdev;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (device->bdev) {
|
||||
blkdev_put(device->bdev, device->mode);
|
||||
|
@ -487,6 +498,10 @@ int btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices)
|
|||
goto again;
|
||||
}
|
||||
|
||||
fs_devices->latest_bdev = latest_bdev;
|
||||
fs_devices->latest_devid = latest_devid;
|
||||
fs_devices->latest_trans = latest_transid;
|
||||
|
||||
mutex_unlock(&uuid_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1953,7 +1968,7 @@ static int btrfs_relocate_chunk(struct btrfs_root *root,
|
|||
em = lookup_extent_mapping(em_tree, chunk_offset, 1);
|
||||
read_unlock(&em_tree->lock);
|
||||
|
||||
BUG_ON(em->start > chunk_offset ||
|
||||
BUG_ON(!em || em->start > chunk_offset ||
|
||||
em->start + em->len < chunk_offset);
|
||||
map = (struct map_lookup *)em->bdev;
|
||||
|
||||
|
@ -4356,6 +4371,20 @@ int btrfs_read_sys_array(struct btrfs_root *root)
|
|||
return -ENOMEM;
|
||||
btrfs_set_buffer_uptodate(sb);
|
||||
btrfs_set_buffer_lockdep_class(root->root_key.objectid, sb, 0);
|
||||
/*
|
||||
* The sb extent buffer is artifical and just used to read the system array.
|
||||
* btrfs_set_buffer_uptodate() call does not properly mark all it's
|
||||
* pages up-to-date when the page is larger: extent does not cover the
|
||||
* whole page and consequently check_page_uptodate does not find all
|
||||
* the page's extents up-to-date (the hole beyond sb),
|
||||
* write_extent_buffer then triggers a WARN_ON.
|
||||
*
|
||||
* Regular short extents go through mark_extent_buffer_dirty/writeback cycle,
|
||||
* but sb spans only this function. Add an explicit SetPageUptodate call
|
||||
* to silence the warning eg. on PowerPC 64.
|
||||
*/
|
||||
if (PAGE_CACHE_SIZE > BTRFS_SUPER_INFO_SIZE)
|
||||
SetPageUptodate(sb->first_page);
|
||||
|
||||
write_extent_buffer(sb, super_copy, 0, BTRFS_SUPER_INFO_SIZE);
|
||||
array_size = btrfs_super_sys_array_size(super_copy);
|
||||
|
|
Loading…
Reference in a new issue