Merge branch 'error-handling' into for-linus
Conflicts: fs/btrfs/ctree.c fs/btrfs/disk-io.c fs/btrfs/extent-tree.c fs/btrfs/extent_io.c fs/btrfs/extent_io.h fs/btrfs/inode.c fs/btrfs/scrub.c Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
@@ -48,20 +48,19 @@
|
||||
static struct extent_io_ops btree_extent_io_ops;
|
||||
static void end_workqueue_fn(struct btrfs_work *work);
|
||||
static void free_fs_root(struct btrfs_root *root);
|
||||
static void btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
|
||||
static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
|
||||
int read_only);
|
||||
static int btrfs_destroy_ordered_operations(struct btrfs_root *root);
|
||||
static int btrfs_destroy_ordered_extents(struct btrfs_root *root);
|
||||
static void btrfs_destroy_ordered_operations(struct btrfs_root *root);
|
||||
static void btrfs_destroy_ordered_extents(struct btrfs_root *root);
|
||||
static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
|
||||
struct btrfs_root *root);
|
||||
static int btrfs_destroy_pending_snapshots(struct btrfs_transaction *t);
|
||||
static int btrfs_destroy_delalloc_inodes(struct btrfs_root *root);
|
||||
static void btrfs_destroy_pending_snapshots(struct btrfs_transaction *t);
|
||||
static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root);
|
||||
static int btrfs_destroy_marked_extents(struct btrfs_root *root,
|
||||
struct extent_io_tree *dirty_pages,
|
||||
int mark);
|
||||
static int btrfs_destroy_pinned_extent(struct btrfs_root *root,
|
||||
struct extent_io_tree *pinned_extents);
|
||||
static int btrfs_cleanup_transaction(struct btrfs_root *root);
|
||||
|
||||
/*
|
||||
* end_io_wq structs are used to do processing in task context when an IO is
|
||||
@@ -99,6 +98,7 @@ struct async_submit_bio {
|
||||
*/
|
||||
u64 bio_offset;
|
||||
struct btrfs_work work;
|
||||
int error;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -332,7 +332,7 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
|
||||
return 0;
|
||||
|
||||
lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1,
|
||||
0, &cached_state, GFP_NOFS);
|
||||
0, &cached_state);
|
||||
if (extent_buffer_uptodate(eb) &&
|
||||
btrfs_header_generation(eb) == parent_transid) {
|
||||
ret = 0;
|
||||
@@ -425,7 +425,6 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
|
||||
eb = (struct extent_buffer *)page->private;
|
||||
if (page != eb->pages[0])
|
||||
return 0;
|
||||
|
||||
found_start = btrfs_header_bytenr(eb);
|
||||
if (found_start != start) {
|
||||
WARN_ON(1);
|
||||
@@ -727,11 +726,14 @@ unsigned long btrfs_async_submit_limit(struct btrfs_fs_info *info)
|
||||
static void run_one_async_start(struct btrfs_work *work)
|
||||
{
|
||||
struct async_submit_bio *async;
|
||||
int ret;
|
||||
|
||||
async = container_of(work, struct async_submit_bio, work);
|
||||
async->submit_bio_start(async->inode, async->rw, async->bio,
|
||||
async->mirror_num, async->bio_flags,
|
||||
async->bio_offset);
|
||||
ret = async->submit_bio_start(async->inode, async->rw, async->bio,
|
||||
async->mirror_num, async->bio_flags,
|
||||
async->bio_offset);
|
||||
if (ret)
|
||||
async->error = ret;
|
||||
}
|
||||
|
||||
static void run_one_async_done(struct btrfs_work *work)
|
||||
@@ -752,6 +754,12 @@ static void run_one_async_done(struct btrfs_work *work)
|
||||
waitqueue_active(&fs_info->async_submit_wait))
|
||||
wake_up(&fs_info->async_submit_wait);
|
||||
|
||||
/* If an error occured we just want to clean up the bio and move on */
|
||||
if (async->error) {
|
||||
bio_endio(async->bio, async->error);
|
||||
return;
|
||||
}
|
||||
|
||||
async->submit_bio_done(async->inode, async->rw, async->bio,
|
||||
async->mirror_num, async->bio_flags,
|
||||
async->bio_offset);
|
||||
@@ -793,6 +801,8 @@ int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode,
|
||||
async->bio_flags = bio_flags;
|
||||
async->bio_offset = bio_offset;
|
||||
|
||||
async->error = 0;
|
||||
|
||||
atomic_inc(&fs_info->nr_async_submits);
|
||||
|
||||
if (rw & REQ_SYNC)
|
||||
@@ -814,15 +824,18 @@ static int btree_csum_one_bio(struct bio *bio)
|
||||
struct bio_vec *bvec = bio->bi_io_vec;
|
||||
int bio_index = 0;
|
||||
struct btrfs_root *root;
|
||||
int ret = 0;
|
||||
|
||||
WARN_ON(bio->bi_vcnt <= 0);
|
||||
while (bio_index < bio->bi_vcnt) {
|
||||
root = BTRFS_I(bvec->bv_page->mapping->host)->root;
|
||||
csum_dirty_buffer(root, bvec->bv_page);
|
||||
ret = csum_dirty_buffer(root, bvec->bv_page);
|
||||
if (ret)
|
||||
break;
|
||||
bio_index++;
|
||||
bvec++;
|
||||
}
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __btree_submit_bio_start(struct inode *inode, int rw,
|
||||
@@ -834,8 +847,7 @@ static int __btree_submit_bio_start(struct inode *inode, int rw,
|
||||
* when we're called for a write, we're already in the async
|
||||
* submission context. Just jump into btrfs_map_bio
|
||||
*/
|
||||
btree_csum_one_bio(bio);
|
||||
return 0;
|
||||
return btree_csum_one_bio(bio);
|
||||
}
|
||||
|
||||
static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio,
|
||||
@@ -863,7 +875,8 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
|
||||
*/
|
||||
ret = btrfs_bio_wq_end_io(BTRFS_I(inode)->root->fs_info,
|
||||
bio, 1);
|
||||
BUG_ON(ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
|
||||
mirror_num, 0);
|
||||
}
|
||||
@@ -1080,8 +1093,8 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
|
||||
|
||||
}
|
||||
|
||||
int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct extent_buffer *buf)
|
||||
void clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct extent_buffer *buf)
|
||||
{
|
||||
if (btrfs_header_generation(buf) ==
|
||||
root->fs_info->running_transaction->transid) {
|
||||
@@ -1091,8 +1104,14 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
spin_lock(&root->fs_info->delalloc_lock);
|
||||
if (root->fs_info->dirty_metadata_bytes >= buf->len)
|
||||
root->fs_info->dirty_metadata_bytes -= buf->len;
|
||||
else
|
||||
WARN_ON(1);
|
||||
else {
|
||||
spin_unlock(&root->fs_info->delalloc_lock);
|
||||
btrfs_panic(root->fs_info, -EOVERFLOW,
|
||||
"Can't clear %lu bytes from "
|
||||
" dirty_mdatadata_bytes (%lu)",
|
||||
buf->len,
|
||||
root->fs_info->dirty_metadata_bytes);
|
||||
}
|
||||
spin_unlock(&root->fs_info->delalloc_lock);
|
||||
}
|
||||
|
||||
@@ -1100,13 +1119,12 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
btrfs_set_lock_blocking(buf);
|
||||
clear_extent_buffer_dirty(buf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
|
||||
u32 stripesize, struct btrfs_root *root,
|
||||
struct btrfs_fs_info *fs_info,
|
||||
u64 objectid)
|
||||
static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
|
||||
u32 stripesize, struct btrfs_root *root,
|
||||
struct btrfs_fs_info *fs_info,
|
||||
u64 objectid)
|
||||
{
|
||||
root->node = NULL;
|
||||
root->commit_root = NULL;
|
||||
@@ -1158,13 +1176,12 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
|
||||
root->defrag_running = 0;
|
||||
root->root_key.objectid = objectid;
|
||||
root->anon_dev = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_and_setup_root(struct btrfs_root *tree_root,
|
||||
struct btrfs_fs_info *fs_info,
|
||||
u64 objectid,
|
||||
struct btrfs_root *root)
|
||||
static int __must_check find_and_setup_root(struct btrfs_root *tree_root,
|
||||
struct btrfs_fs_info *fs_info,
|
||||
u64 objectid,
|
||||
struct btrfs_root *root)
|
||||
{
|
||||
int ret;
|
||||
u32 blocksize;
|
||||
@@ -1177,7 +1194,8 @@ static int find_and_setup_root(struct btrfs_root *tree_root,
|
||||
&root->root_item, &root->root_key);
|
||||
if (ret > 0)
|
||||
return -ENOENT;
|
||||
BUG_ON(ret);
|
||||
else if (ret < 0)
|
||||
return ret;
|
||||
|
||||
generation = btrfs_root_generation(&root->root_item);
|
||||
blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item));
|
||||
@@ -1346,7 +1364,7 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
|
||||
root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
|
||||
blocksize, generation);
|
||||
root->commit_root = btrfs_root_node(root);
|
||||
BUG_ON(!root->node);
|
||||
BUG_ON(!root->node); /* -ENOMEM */
|
||||
out:
|
||||
if (location->objectid != BTRFS_TREE_LOG_OBJECTID) {
|
||||
root->ref_cows = 1;
|
||||
@@ -1537,9 +1555,10 @@ static int transaction_kthread(void *arg)
|
||||
u64 transid;
|
||||
unsigned long now;
|
||||
unsigned long delay;
|
||||
int ret;
|
||||
bool cannot_commit;
|
||||
|
||||
do {
|
||||
cannot_commit = false;
|
||||
delay = HZ * 30;
|
||||
vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE);
|
||||
mutex_lock(&root->fs_info->transaction_kthread_mutex);
|
||||
@@ -1561,11 +1580,14 @@ static int transaction_kthread(void *arg)
|
||||
transid = cur->transid;
|
||||
spin_unlock(&root->fs_info->trans_lock);
|
||||
|
||||
/* If the file system is aborted, this will always fail. */
|
||||
trans = btrfs_join_transaction(root);
|
||||
BUG_ON(IS_ERR(trans));
|
||||
if (IS_ERR(trans)) {
|
||||
cannot_commit = true;
|
||||
goto sleep;
|
||||
}
|
||||
if (transid == trans->transid) {
|
||||
ret = btrfs_commit_transaction(trans, root);
|
||||
BUG_ON(ret);
|
||||
btrfs_commit_transaction(trans, root);
|
||||
} else {
|
||||
btrfs_end_transaction(trans, root);
|
||||
}
|
||||
@@ -1576,7 +1598,8 @@ sleep:
|
||||
if (!try_to_freeze()) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (!kthread_should_stop() &&
|
||||
!btrfs_transaction_blocked(root->fs_info))
|
||||
(!btrfs_transaction_blocked(root->fs_info) ||
|
||||
cannot_commit))
|
||||
schedule_timeout(delay);
|
||||
__set_current_state(TASK_RUNNING);
|
||||
}
|
||||
@@ -2028,7 +2051,12 @@ int open_ctree(struct super_block *sb,
|
||||
/* check FS state, whether FS is broken. */
|
||||
fs_info->fs_state |= btrfs_super_flags(disk_super);
|
||||
|
||||
btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY);
|
||||
ret = btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "btrfs: superblock contains fatal errors\n");
|
||||
err = ret;
|
||||
goto fail_alloc;
|
||||
}
|
||||
|
||||
/*
|
||||
* run through our array of backup supers and setup
|
||||
@@ -2218,6 +2246,14 @@ int open_ctree(struct super_block *sb,
|
||||
goto fail_sb_buffer;
|
||||
}
|
||||
|
||||
if ((features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) &&
|
||||
(leafsize != nodesize || sectorsize != nodesize)) {
|
||||
printk(KERN_WARNING "btrfs: unequal leaf/node/sector sizes "
|
||||
"are not allowed for mixed block groups 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);
|
||||
@@ -2237,7 +2273,7 @@ int open_ctree(struct super_block *sb,
|
||||
chunk_root->node = read_tree_block(chunk_root,
|
||||
btrfs_super_chunk_root(disk_super),
|
||||
blocksize, generation);
|
||||
BUG_ON(!chunk_root->node);
|
||||
BUG_ON(!chunk_root->node); /* -ENOMEM */
|
||||
if (!test_bit(EXTENT_BUFFER_UPTODATE, &chunk_root->node->bflags)) {
|
||||
printk(KERN_WARNING "btrfs: failed to read chunk root on %s\n",
|
||||
sb->s_id);
|
||||
@@ -2377,21 +2413,31 @@ retry_root_backup:
|
||||
log_tree_root->node = read_tree_block(tree_root, bytenr,
|
||||
blocksize,
|
||||
generation + 1);
|
||||
/* returns with log_tree_root freed on success */
|
||||
ret = btrfs_recover_log_trees(log_tree_root);
|
||||
BUG_ON(ret);
|
||||
if (ret) {
|
||||
btrfs_error(tree_root->fs_info, ret,
|
||||
"Failed to recover log tree");
|
||||
free_extent_buffer(log_tree_root->node);
|
||||
kfree(log_tree_root);
|
||||
goto fail_trans_kthread;
|
||||
}
|
||||
|
||||
if (sb->s_flags & MS_RDONLY) {
|
||||
ret = btrfs_commit_super(tree_root);
|
||||
BUG_ON(ret);
|
||||
ret = btrfs_commit_super(tree_root);
|
||||
if (ret)
|
||||
goto fail_trans_kthread;
|
||||
}
|
||||
}
|
||||
|
||||
ret = btrfs_find_orphan_roots(tree_root);
|
||||
BUG_ON(ret);
|
||||
if (ret)
|
||||
goto fail_trans_kthread;
|
||||
|
||||
if (!(sb->s_flags & MS_RDONLY)) {
|
||||
ret = btrfs_cleanup_fs_roots(fs_info);
|
||||
BUG_ON(ret);
|
||||
if (ret) {
|
||||
}
|
||||
|
||||
ret = btrfs_recover_relocation(tree_root);
|
||||
if (ret < 0) {
|
||||
@@ -2811,6 +2857,8 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors)
|
||||
if (total_errors > max_errors) {
|
||||
printk(KERN_ERR "btrfs: %d errors while writing supers\n",
|
||||
total_errors);
|
||||
|
||||
/* This shouldn't happen. FUA is masked off if unsupported */
|
||||
BUG();
|
||||
}
|
||||
|
||||
@@ -2827,9 +2875,9 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors)
|
||||
}
|
||||
mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
|
||||
if (total_errors > max_errors) {
|
||||
printk(KERN_ERR "btrfs: %d errors while writing supers\n",
|
||||
total_errors);
|
||||
BUG();
|
||||
btrfs_error(root->fs_info, -EIO,
|
||||
"%d errors while writing supers", total_errors);
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -2843,7 +2891,20 @@ int write_ctree_super(struct btrfs_trans_handle *trans,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
|
||||
/* Kill all outstanding I/O */
|
||||
void btrfs_abort_devices(struct btrfs_root *root)
|
||||
{
|
||||
struct list_head *head;
|
||||
struct btrfs_device *dev;
|
||||
mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
|
||||
head = &root->fs_info->fs_devices->devices;
|
||||
list_for_each_entry_rcu(dev, head, dev_list) {
|
||||
blk_abort_queue(dev->bdev->bd_disk->queue);
|
||||
}
|
||||
mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
|
||||
}
|
||||
|
||||
void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
|
||||
{
|
||||
spin_lock(&fs_info->fs_roots_radix_lock);
|
||||
radix_tree_delete(&fs_info->fs_roots_radix,
|
||||
@@ -2856,7 +2917,6 @@ int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
|
||||
__btrfs_remove_free_space_cache(root->free_ino_pinned);
|
||||
__btrfs_remove_free_space_cache(root->free_ino_ctl);
|
||||
free_fs_root(root);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_fs_root(struct btrfs_root *root)
|
||||
@@ -2873,7 +2933,7 @@ static void free_fs_root(struct btrfs_root *root)
|
||||
kfree(root);
|
||||
}
|
||||
|
||||
static int del_fs_roots(struct btrfs_fs_info *fs_info)
|
||||
static void del_fs_roots(struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
int ret;
|
||||
struct btrfs_root *gang[8];
|
||||
@@ -2902,7 +2962,6 @@ static int del_fs_roots(struct btrfs_fs_info *fs_info)
|
||||
for (i = 0; i < ret; i++)
|
||||
btrfs_free_fs_root(fs_info, gang[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info)
|
||||
@@ -2951,14 +3010,21 @@ int btrfs_commit_super(struct btrfs_root *root)
|
||||
if (IS_ERR(trans))
|
||||
return PTR_ERR(trans);
|
||||
ret = btrfs_commit_transaction(trans, root);
|
||||
BUG_ON(ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* run commit again to drop the original snapshot */
|
||||
trans = btrfs_join_transaction(root);
|
||||
if (IS_ERR(trans))
|
||||
return PTR_ERR(trans);
|
||||
btrfs_commit_transaction(trans, root);
|
||||
ret = btrfs_commit_transaction(trans, root);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = btrfs_write_and_wait_transaction(NULL, root);
|
||||
BUG_ON(ret);
|
||||
if (ret) {
|
||||
btrfs_error(root->fs_info, ret,
|
||||
"Failed to sync btree inode to disk.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = write_ctree_super(NULL, root, 0);
|
||||
return ret;
|
||||
@@ -3209,15 +3275,23 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
|
||||
static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
|
||||
int read_only)
|
||||
{
|
||||
if (read_only)
|
||||
return;
|
||||
if (btrfs_super_csum_type(fs_info->super_copy) >= ARRAY_SIZE(btrfs_csum_sizes)) {
|
||||
printk(KERN_ERR "btrfs: unsupported checksum algorithm\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)
|
||||
if (read_only)
|
||||
return 0;
|
||||
|
||||
if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
|
||||
printk(KERN_WARNING "warning: mount fs with errors, "
|
||||
"running btrfsck is recommended\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_error_commit_super(struct btrfs_root *root)
|
||||
@@ -3239,7 +3313,7 @@ int btrfs_error_commit_super(struct btrfs_root *root)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int btrfs_destroy_ordered_operations(struct btrfs_root *root)
|
||||
static void btrfs_destroy_ordered_operations(struct btrfs_root *root)
|
||||
{
|
||||
struct btrfs_inode *btrfs_inode;
|
||||
struct list_head splice;
|
||||
@@ -3261,11 +3335,9 @@ static int btrfs_destroy_ordered_operations(struct btrfs_root *root)
|
||||
|
||||
spin_unlock(&root->fs_info->ordered_extent_lock);
|
||||
mutex_unlock(&root->fs_info->ordered_operations_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btrfs_destroy_ordered_extents(struct btrfs_root *root)
|
||||
static void btrfs_destroy_ordered_extents(struct btrfs_root *root)
|
||||
{
|
||||
struct list_head splice;
|
||||
struct btrfs_ordered_extent *ordered;
|
||||
@@ -3297,12 +3369,10 @@ static int btrfs_destroy_ordered_extents(struct btrfs_root *root)
|
||||
}
|
||||
|
||||
spin_unlock(&root->fs_info->ordered_extent_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
|
||||
struct btrfs_root *root)
|
||||
int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
|
||||
struct btrfs_root *root)
|
||||
{
|
||||
struct rb_node *node;
|
||||
struct btrfs_delayed_ref_root *delayed_refs;
|
||||
@@ -3311,6 +3381,7 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
|
||||
|
||||
delayed_refs = &trans->delayed_refs;
|
||||
|
||||
again:
|
||||
spin_lock(&delayed_refs->lock);
|
||||
if (delayed_refs->num_entries == 0) {
|
||||
spin_unlock(&delayed_refs->lock);
|
||||
@@ -3332,6 +3403,7 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
|
||||
struct btrfs_delayed_ref_head *head;
|
||||
|
||||
head = btrfs_delayed_node_to_head(ref);
|
||||
spin_unlock(&delayed_refs->lock);
|
||||
mutex_lock(&head->mutex);
|
||||
kfree(head->extent_op);
|
||||
delayed_refs->num_heads--;
|
||||
@@ -3339,8 +3411,9 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
|
||||
delayed_refs->num_heads_ready--;
|
||||
list_del_init(&head->cluster);
|
||||
mutex_unlock(&head->mutex);
|
||||
btrfs_put_delayed_ref(ref);
|
||||
goto again;
|
||||
}
|
||||
|
||||
spin_unlock(&delayed_refs->lock);
|
||||
btrfs_put_delayed_ref(ref);
|
||||
|
||||
@@ -3353,7 +3426,7 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int btrfs_destroy_pending_snapshots(struct btrfs_transaction *t)
|
||||
static void btrfs_destroy_pending_snapshots(struct btrfs_transaction *t)
|
||||
{
|
||||
struct btrfs_pending_snapshot *snapshot;
|
||||
struct list_head splice;
|
||||
@@ -3371,11 +3444,9 @@ static int btrfs_destroy_pending_snapshots(struct btrfs_transaction *t)
|
||||
|
||||
kfree(snapshot);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btrfs_destroy_delalloc_inodes(struct btrfs_root *root)
|
||||
static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root)
|
||||
{
|
||||
struct btrfs_inode *btrfs_inode;
|
||||
struct list_head splice;
|
||||
@@ -3395,8 +3466,6 @@ static int btrfs_destroy_delalloc_inodes(struct btrfs_root *root)
|
||||
}
|
||||
|
||||
spin_unlock(&root->fs_info->delalloc_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btrfs_destroy_marked_extents(struct btrfs_root *root,
|
||||
@@ -3487,13 +3556,43 @@ static int btrfs_destroy_pinned_extent(struct btrfs_root *root,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btrfs_cleanup_transaction(struct btrfs_root *root)
|
||||
void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
|
||||
struct btrfs_root *root)
|
||||
{
|
||||
btrfs_destroy_delayed_refs(cur_trans, root);
|
||||
btrfs_block_rsv_release(root, &root->fs_info->trans_block_rsv,
|
||||
cur_trans->dirty_pages.dirty_bytes);
|
||||
|
||||
/* FIXME: cleanup wait for commit */
|
||||
cur_trans->in_commit = 1;
|
||||
cur_trans->blocked = 1;
|
||||
if (waitqueue_active(&root->fs_info->transaction_blocked_wait))
|
||||
wake_up(&root->fs_info->transaction_blocked_wait);
|
||||
|
||||
cur_trans->blocked = 0;
|
||||
if (waitqueue_active(&root->fs_info->transaction_wait))
|
||||
wake_up(&root->fs_info->transaction_wait);
|
||||
|
||||
cur_trans->commit_done = 1;
|
||||
if (waitqueue_active(&cur_trans->commit_wait))
|
||||
wake_up(&cur_trans->commit_wait);
|
||||
|
||||
btrfs_destroy_pending_snapshots(cur_trans);
|
||||
|
||||
btrfs_destroy_marked_extents(root, &cur_trans->dirty_pages,
|
||||
EXTENT_DIRTY);
|
||||
|
||||
/*
|
||||
memset(cur_trans, 0, sizeof(*cur_trans));
|
||||
kmem_cache_free(btrfs_transaction_cachep, cur_trans);
|
||||
*/
|
||||
}
|
||||
|
||||
int btrfs_cleanup_transaction(struct btrfs_root *root)
|
||||
{
|
||||
struct btrfs_transaction *t;
|
||||
LIST_HEAD(list);
|
||||
|
||||
WARN_ON(1);
|
||||
|
||||
mutex_lock(&root->fs_info->transaction_kthread_mutex);
|
||||
|
||||
spin_lock(&root->fs_info->trans_lock);
|
||||
@@ -3558,6 +3657,17 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btree_writepage_io_failed_hook(struct bio *bio, struct page *page,
|
||||
u64 start, u64 end,
|
||||
struct extent_state *state)
|
||||
{
|
||||
struct super_block *sb = page->mapping->host->i_sb;
|
||||
struct btrfs_fs_info *fs_info = btrfs_sb(sb);
|
||||
btrfs_error(fs_info, -EIO,
|
||||
"Error occured while writing out btree at %llu", start);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static struct extent_io_ops btree_extent_io_ops = {
|
||||
.write_cache_pages_lock_hook = btree_lock_page_hook,
|
||||
.readpage_end_io_hook = btree_readpage_end_io_hook,
|
||||
@@ -3565,4 +3675,5 @@ static struct extent_io_ops btree_extent_io_ops = {
|
||||
.submit_bio_hook = btree_submit_bio_hook,
|
||||
/* note we're sharing with inode.c for the merge bio hook */
|
||||
.merge_bio_hook = btrfs_merge_bio_hook,
|
||||
.writepage_io_failed_hook = btree_writepage_io_failed_hook,
|
||||
};
|
||||
|
Reference in New Issue
Block a user