btrfs: replace many BUG_ONs with proper error handling
btrfs currently handles most errors with BUG_ON. This patch is a work-in- progress but aims to handle most errors other than internal logic errors and ENOMEM more gracefully. This iteration prevents most crashes but can run into lockups with the page lock on occasion when the timing "works out." Signed-off-by: Jeff Mahoney <jeffm@suse.com>
This commit is contained in:
Родитель
49b25e0540
Коммит
79787eaab4
|
@ -391,16 +391,16 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
|
||||||
*/
|
*/
|
||||||
atomic_inc(&cb->pending_bios);
|
atomic_inc(&cb->pending_bios);
|
||||||
ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
|
ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
|
|
||||||
if (!skip_sum) {
|
if (!skip_sum) {
|
||||||
ret = btrfs_csum_one_bio(root, inode, bio,
|
ret = btrfs_csum_one_bio(root, inode, bio,
|
||||||
start, 1);
|
start, 1);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = btrfs_map_bio(root, WRITE, bio, 0, 1);
|
ret = btrfs_map_bio(root, WRITE, bio, 0, 1);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
|
|
||||||
bio_put(bio);
|
bio_put(bio);
|
||||||
|
|
||||||
|
@ -420,15 +420,15 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
|
||||||
bio_get(bio);
|
bio_get(bio);
|
||||||
|
|
||||||
ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
|
ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
|
|
||||||
if (!skip_sum) {
|
if (!skip_sum) {
|
||||||
ret = btrfs_csum_one_bio(root, inode, bio, start, 1);
|
ret = btrfs_csum_one_bio(root, inode, bio, start, 1);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = btrfs_map_bio(root, WRITE, bio, 0, 1);
|
ret = btrfs_map_bio(root, WRITE, bio, 0, 1);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
|
|
||||||
bio_put(bio);
|
bio_put(bio);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -661,7 +661,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
|
||||||
bio_get(comp_bio);
|
bio_get(comp_bio);
|
||||||
|
|
||||||
ret = btrfs_bio_wq_end_io(root->fs_info, comp_bio, 0);
|
ret = btrfs_bio_wq_end_io(root->fs_info, comp_bio, 0);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* inc the count before we submit the bio so
|
* inc the count before we submit the bio so
|
||||||
|
@ -674,14 +674,14 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
|
||||||
if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
|
if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
|
||||||
ret = btrfs_lookup_bio_sums(root, inode,
|
ret = btrfs_lookup_bio_sums(root, inode,
|
||||||
comp_bio, sums);
|
comp_bio, sums);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
sums += (comp_bio->bi_size + root->sectorsize - 1) /
|
sums += (comp_bio->bi_size + root->sectorsize - 1) /
|
||||||
root->sectorsize;
|
root->sectorsize;
|
||||||
|
|
||||||
ret = btrfs_map_bio(root, READ, comp_bio,
|
ret = btrfs_map_bio(root, READ, comp_bio,
|
||||||
mirror_num, 0);
|
mirror_num, 0);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
|
|
||||||
bio_put(comp_bio);
|
bio_put(comp_bio);
|
||||||
|
|
||||||
|
@ -697,15 +697,15 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
|
||||||
bio_get(comp_bio);
|
bio_get(comp_bio);
|
||||||
|
|
||||||
ret = btrfs_bio_wq_end_io(root->fs_info, comp_bio, 0);
|
ret = btrfs_bio_wq_end_io(root->fs_info, comp_bio, 0);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
|
|
||||||
if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
|
if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
|
||||||
ret = btrfs_lookup_bio_sums(root, inode, comp_bio, sums);
|
ret = btrfs_lookup_bio_sums(root, inode, comp_bio, sums);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0);
|
ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
|
|
||||||
bio_put(comp_bio);
|
bio_put(comp_bio);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -356,14 +356,14 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
|
||||||
root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) &&
|
root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) &&
|
||||||
!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) {
|
!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) {
|
||||||
ret = btrfs_inc_ref(trans, root, buf, 1, 1);
|
ret = btrfs_inc_ref(trans, root, buf, 1, 1);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
|
|
||||||
if (root->root_key.objectid ==
|
if (root->root_key.objectid ==
|
||||||
BTRFS_TREE_RELOC_OBJECTID) {
|
BTRFS_TREE_RELOC_OBJECTID) {
|
||||||
ret = btrfs_dec_ref(trans, root, buf, 0, 1);
|
ret = btrfs_dec_ref(trans, root, buf, 0, 1);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
ret = btrfs_inc_ref(trans, root, cow, 1, 1);
|
ret = btrfs_inc_ref(trans, root, cow, 1, 1);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
new_flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF;
|
new_flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF;
|
||||||
} else {
|
} else {
|
||||||
|
@ -373,7 +373,7 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
|
||||||
ret = btrfs_inc_ref(trans, root, cow, 1, 1);
|
ret = btrfs_inc_ref(trans, root, cow, 1, 1);
|
||||||
else
|
else
|
||||||
ret = btrfs_inc_ref(trans, root, cow, 0, 1);
|
ret = btrfs_inc_ref(trans, root, cow, 0, 1);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
if (new_flags != 0) {
|
if (new_flags != 0) {
|
||||||
ret = btrfs_set_disk_extent_flags(trans, root,
|
ret = btrfs_set_disk_extent_flags(trans, root,
|
||||||
|
@ -390,9 +390,9 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
|
||||||
ret = btrfs_inc_ref(trans, root, cow, 1, 1);
|
ret = btrfs_inc_ref(trans, root, cow, 1, 1);
|
||||||
else
|
else
|
||||||
ret = btrfs_inc_ref(trans, root, cow, 0, 1);
|
ret = btrfs_inc_ref(trans, root, cow, 0, 1);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
ret = btrfs_dec_ref(trans, root, buf, 1, 1);
|
ret = btrfs_dec_ref(trans, root, buf, 1, 1);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
clean_tree_block(trans, root, buf);
|
clean_tree_block(trans, root, buf);
|
||||||
*last_ref = 1;
|
*last_ref = 1;
|
||||||
|
@ -475,7 +475,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
ret = update_ref_for_cow(trans, root, buf, cow, &last_ref);
|
ret = update_ref_for_cow(trans, root, buf, cow, &last_ref);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
btrfs_std_error(root->fs_info, ret);
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2713,7 +2713,8 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||||
path->nodes[1], slot - 1, &left);
|
path->nodes[1], slot - 1, &left);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
/* we hit -ENOSPC, but it isn't fatal here */
|
/* we hit -ENOSPC, but it isn't fatal here */
|
||||||
ret = 1;
|
if (ret == -ENOSPC)
|
||||||
|
ret = 1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4017,7 +4018,7 @@ find_next_key:
|
||||||
}
|
}
|
||||||
btrfs_set_path_blocking(path);
|
btrfs_set_path_blocking(path);
|
||||||
cur = read_node_slot(root, cur, slot);
|
cur = read_node_slot(root, cur, slot);
|
||||||
BUG_ON(!cur);
|
BUG_ON(!cur); /* -ENOMEM */
|
||||||
|
|
||||||
btrfs_tree_read_lock(cur);
|
btrfs_tree_read_lock(cur);
|
||||||
|
|
||||||
|
|
|
@ -115,6 +115,7 @@ static struct btrfs_delayed_node *btrfs_get_delayed_node(struct inode *inode)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Will return either the node or PTR_ERR(-ENOMEM) */
|
||||||
static struct btrfs_delayed_node *btrfs_get_or_create_delayed_node(
|
static struct btrfs_delayed_node *btrfs_get_or_create_delayed_node(
|
||||||
struct inode *inode)
|
struct inode *inode)
|
||||||
{
|
{
|
||||||
|
@ -1106,16 +1107,25 @@ static int btrfs_update_delayed_inode(struct btrfs_trans_handle *trans,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called when committing the transaction. */
|
/*
|
||||||
|
* Called when committing the transaction.
|
||||||
|
* Returns 0 on success.
|
||||||
|
* Returns < 0 on error and returns with an aborted transaction with any
|
||||||
|
* outstanding delayed items cleaned up.
|
||||||
|
*/
|
||||||
int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
|
int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root)
|
struct btrfs_root *root)
|
||||||
{
|
{
|
||||||
|
struct btrfs_root *curr_root = root;
|
||||||
struct btrfs_delayed_root *delayed_root;
|
struct btrfs_delayed_root *delayed_root;
|
||||||
struct btrfs_delayed_node *curr_node, *prev_node;
|
struct btrfs_delayed_node *curr_node, *prev_node;
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
struct btrfs_block_rsv *block_rsv;
|
struct btrfs_block_rsv *block_rsv;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
if (trans->aborted)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
path = btrfs_alloc_path();
|
path = btrfs_alloc_path();
|
||||||
if (!path)
|
if (!path)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -1128,17 +1138,18 @@ int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
curr_node = btrfs_first_delayed_node(delayed_root);
|
curr_node = btrfs_first_delayed_node(delayed_root);
|
||||||
while (curr_node) {
|
while (curr_node) {
|
||||||
root = curr_node->root;
|
curr_root = curr_node->root;
|
||||||
ret = btrfs_insert_delayed_items(trans, path, root,
|
ret = btrfs_insert_delayed_items(trans, path, curr_root,
|
||||||
curr_node);
|
curr_node);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = btrfs_delete_delayed_items(trans, path, root,
|
ret = btrfs_delete_delayed_items(trans, path,
|
||||||
curr_node);
|
curr_root, curr_node);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = btrfs_update_delayed_inode(trans, root, path,
|
ret = btrfs_update_delayed_inode(trans, curr_root,
|
||||||
curr_node);
|
path, curr_node);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
btrfs_release_delayed_node(curr_node);
|
btrfs_release_delayed_node(curr_node);
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1149,6 +1160,7 @@ int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
trans->block_rsv = block_rsv;
|
trans->block_rsv = block_rsv;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1369,6 +1381,7 @@ void btrfs_balance_delayed_items(struct btrfs_root *root)
|
||||||
btrfs_wq_run_delayed_node(delayed_root, root, 0);
|
btrfs_wq_run_delayed_node(delayed_root, root, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Will return 0 or -ENOMEM */
|
||||||
int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
|
int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root, const char *name,
|
struct btrfs_root *root, const char *name,
|
||||||
int name_len, struct inode *dir,
|
int name_len, struct inode *dir,
|
||||||
|
|
|
@ -115,6 +115,7 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
|
||||||
* 'location' is the key to stuff into the directory item, 'type' is the
|
* 'location' is the key to stuff into the directory item, 'type' is the
|
||||||
* type of the inode we're pointing to, and 'index' is the sequence number
|
* type of the inode we're pointing to, and 'index' is the sequence number
|
||||||
* to use for the second index (if one is created).
|
* to use for the second index (if one is created).
|
||||||
|
* Will return 0 or -ENOMEM
|
||||||
*/
|
*/
|
||||||
int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
|
int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||||
*root, const char *name, int name_len,
|
*root, const char *name, int name_len,
|
||||||
|
|
|
@ -98,6 +98,7 @@ struct async_submit_bio {
|
||||||
*/
|
*/
|
||||||
u64 bio_offset;
|
u64 bio_offset;
|
||||||
struct btrfs_work work;
|
struct btrfs_work work;
|
||||||
|
int error;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -405,7 +406,7 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
|
||||||
u64 found_start;
|
u64 found_start;
|
||||||
unsigned long len;
|
unsigned long len;
|
||||||
struct extent_buffer *eb;
|
struct extent_buffer *eb;
|
||||||
int ret;
|
int ret = -EIO;
|
||||||
|
|
||||||
tree = &BTRFS_I(page->mapping->host)->io_tree;
|
tree = &BTRFS_I(page->mapping->host)->io_tree;
|
||||||
|
|
||||||
|
@ -423,13 +424,20 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
|
||||||
eb = alloc_extent_buffer(tree, start, len, page);
|
eb = alloc_extent_buffer(tree, start, len, page);
|
||||||
if (eb == NULL) {
|
if (eb == NULL) {
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
|
ret = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
ret = btree_read_extent_buffer_pages(root, eb, start + PAGE_CACHE_SIZE,
|
ret = btree_read_extent_buffer_pages(root, eb, start + PAGE_CACHE_SIZE,
|
||||||
btrfs_header_generation(eb));
|
btrfs_header_generation(eb));
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_printk(root->fs_info, KERN_WARNING
|
||||||
|
"Failed to checksum dirty buffer @ %llu[%lu]\n",
|
||||||
|
start, len);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
WARN_ON(!btrfs_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN));
|
WARN_ON(!btrfs_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN));
|
||||||
|
|
||||||
|
ret = -EIO;
|
||||||
found_start = btrfs_header_bytenr(eb);
|
found_start = btrfs_header_bytenr(eb);
|
||||||
if (found_start != start) {
|
if (found_start != start) {
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
|
@ -444,10 +452,11 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
csum_tree_block(root, eb, 0);
|
csum_tree_block(root, eb, 0);
|
||||||
|
ret = 0;
|
||||||
err:
|
err:
|
||||||
free_extent_buffer(eb);
|
free_extent_buffer(eb);
|
||||||
out:
|
out:
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int check_tree_block_fsid(struct btrfs_root *root,
|
static int check_tree_block_fsid(struct btrfs_root *root,
|
||||||
|
@ -718,11 +727,14 @@ unsigned long btrfs_async_submit_limit(struct btrfs_fs_info *info)
|
||||||
static void run_one_async_start(struct btrfs_work *work)
|
static void run_one_async_start(struct btrfs_work *work)
|
||||||
{
|
{
|
||||||
struct async_submit_bio *async;
|
struct async_submit_bio *async;
|
||||||
|
int ret;
|
||||||
|
|
||||||
async = container_of(work, struct async_submit_bio, work);
|
async = container_of(work, struct async_submit_bio, work);
|
||||||
async->submit_bio_start(async->inode, async->rw, async->bio,
|
ret = async->submit_bio_start(async->inode, async->rw, async->bio,
|
||||||
async->mirror_num, async->bio_flags,
|
async->mirror_num, async->bio_flags,
|
||||||
async->bio_offset);
|
async->bio_offset);
|
||||||
|
if (ret)
|
||||||
|
async->error = ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void run_one_async_done(struct btrfs_work *work)
|
static void run_one_async_done(struct btrfs_work *work)
|
||||||
|
@ -743,6 +755,12 @@ static void run_one_async_done(struct btrfs_work *work)
|
||||||
waitqueue_active(&fs_info->async_submit_wait))
|
waitqueue_active(&fs_info->async_submit_wait))
|
||||||
wake_up(&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->submit_bio_done(async->inode, async->rw, async->bio,
|
||||||
async->mirror_num, async->bio_flags,
|
async->mirror_num, async->bio_flags,
|
||||||
async->bio_offset);
|
async->bio_offset);
|
||||||
|
@ -784,6 +802,8 @@ int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode,
|
||||||
async->bio_flags = bio_flags;
|
async->bio_flags = bio_flags;
|
||||||
async->bio_offset = bio_offset;
|
async->bio_offset = bio_offset;
|
||||||
|
|
||||||
|
async->error = 0;
|
||||||
|
|
||||||
atomic_inc(&fs_info->nr_async_submits);
|
atomic_inc(&fs_info->nr_async_submits);
|
||||||
|
|
||||||
if (rw & REQ_SYNC)
|
if (rw & REQ_SYNC)
|
||||||
|
@ -805,15 +825,18 @@ static int btree_csum_one_bio(struct bio *bio)
|
||||||
struct bio_vec *bvec = bio->bi_io_vec;
|
struct bio_vec *bvec = bio->bi_io_vec;
|
||||||
int bio_index = 0;
|
int bio_index = 0;
|
||||||
struct btrfs_root *root;
|
struct btrfs_root *root;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
WARN_ON(bio->bi_vcnt <= 0);
|
WARN_ON(bio->bi_vcnt <= 0);
|
||||||
while (bio_index < bio->bi_vcnt) {
|
while (bio_index < bio->bi_vcnt) {
|
||||||
root = BTRFS_I(bvec->bv_page->mapping->host)->root;
|
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++;
|
bio_index++;
|
||||||
bvec++;
|
bvec++;
|
||||||
}
|
}
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __btree_submit_bio_start(struct inode *inode, int rw,
|
static int __btree_submit_bio_start(struct inode *inode, int rw,
|
||||||
|
@ -825,8 +848,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
|
* when we're called for a write, we're already in the async
|
||||||
* submission context. Just jump into btrfs_map_bio
|
* submission context. Just jump into btrfs_map_bio
|
||||||
*/
|
*/
|
||||||
btree_csum_one_bio(bio);
|
return btree_csum_one_bio(bio);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio,
|
static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio,
|
||||||
|
@ -1381,7 +1403,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),
|
root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
|
||||||
blocksize, generation);
|
blocksize, generation);
|
||||||
root->commit_root = btrfs_root_node(root);
|
root->commit_root = btrfs_root_node(root);
|
||||||
BUG_ON(!root->node);
|
BUG_ON(!root->node); /* -ENOMEM */
|
||||||
out:
|
out:
|
||||||
if (location->objectid != BTRFS_TREE_LOG_OBJECTID) {
|
if (location->objectid != BTRFS_TREE_LOG_OBJECTID) {
|
||||||
root->ref_cows = 1;
|
root->ref_cows = 1;
|
||||||
|
@ -1618,7 +1640,6 @@ static int transaction_kthread(void *arg)
|
||||||
u64 transid;
|
u64 transid;
|
||||||
unsigned long now;
|
unsigned long now;
|
||||||
unsigned long delay;
|
unsigned long delay;
|
||||||
int ret;
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
delay = HZ * 30;
|
delay = HZ * 30;
|
||||||
|
@ -1642,11 +1663,12 @@ static int transaction_kthread(void *arg)
|
||||||
transid = cur->transid;
|
transid = cur->transid;
|
||||||
spin_unlock(&root->fs_info->trans_lock);
|
spin_unlock(&root->fs_info->trans_lock);
|
||||||
|
|
||||||
|
/* If the file system is aborted, this will always fail. */
|
||||||
trans = btrfs_join_transaction(root);
|
trans = btrfs_join_transaction(root);
|
||||||
BUG_ON(IS_ERR(trans));
|
if (IS_ERR(trans))
|
||||||
|
goto sleep;
|
||||||
if (transid == trans->transid) {
|
if (transid == trans->transid) {
|
||||||
ret = btrfs_commit_transaction(trans, root);
|
btrfs_commit_transaction(trans, root);
|
||||||
BUG_ON(ret);
|
|
||||||
} else {
|
} else {
|
||||||
btrfs_end_transaction(trans, root);
|
btrfs_end_transaction(trans, root);
|
||||||
}
|
}
|
||||||
|
@ -2289,7 +2311,7 @@ int open_ctree(struct super_block *sb,
|
||||||
chunk_root->node = read_tree_block(chunk_root,
|
chunk_root->node = read_tree_block(chunk_root,
|
||||||
btrfs_super_chunk_root(disk_super),
|
btrfs_super_chunk_root(disk_super),
|
||||||
blocksize, generation);
|
blocksize, generation);
|
||||||
BUG_ON(!chunk_root->node);
|
BUG_ON(!chunk_root->node); /* -ENOMEM */
|
||||||
if (!test_bit(EXTENT_BUFFER_UPTODATE, &chunk_root->node->bflags)) {
|
if (!test_bit(EXTENT_BUFFER_UPTODATE, &chunk_root->node->bflags)) {
|
||||||
printk(KERN_WARNING "btrfs: failed to read chunk root on %s\n",
|
printk(KERN_WARNING "btrfs: failed to read chunk root on %s\n",
|
||||||
sb->s_id);
|
sb->s_id);
|
||||||
|
@ -2429,21 +2451,31 @@ retry_root_backup:
|
||||||
log_tree_root->node = read_tree_block(tree_root, bytenr,
|
log_tree_root->node = read_tree_block(tree_root, bytenr,
|
||||||
blocksize,
|
blocksize,
|
||||||
generation + 1);
|
generation + 1);
|
||||||
|
/* returns with log_tree_root freed on success */
|
||||||
ret = btrfs_recover_log_trees(log_tree_root);
|
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) {
|
if (sb->s_flags & MS_RDONLY) {
|
||||||
ret = btrfs_commit_super(tree_root);
|
ret = btrfs_commit_super(tree_root);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
goto fail_trans_kthread;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = btrfs_find_orphan_roots(tree_root);
|
ret = btrfs_find_orphan_roots(tree_root);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
goto fail_trans_kthread;
|
||||||
|
|
||||||
if (!(sb->s_flags & MS_RDONLY)) {
|
if (!(sb->s_flags & MS_RDONLY)) {
|
||||||
ret = btrfs_cleanup_fs_roots(fs_info);
|
ret = btrfs_cleanup_fs_roots(fs_info);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
}
|
||||||
|
|
||||||
ret = btrfs_recover_relocation(tree_root);
|
ret = btrfs_recover_relocation(tree_root);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -2863,6 +2895,8 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors)
|
||||||
if (total_errors > max_errors) {
|
if (total_errors > max_errors) {
|
||||||
printk(KERN_ERR "btrfs: %d errors while writing supers\n",
|
printk(KERN_ERR "btrfs: %d errors while writing supers\n",
|
||||||
total_errors);
|
total_errors);
|
||||||
|
|
||||||
|
/* This shouldn't happen. FUA is masked off if unsupported */
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2879,9 +2913,9 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors)
|
||||||
}
|
}
|
||||||
mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
|
mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
|
||||||
if (total_errors > max_errors) {
|
if (total_errors > max_errors) {
|
||||||
printk(KERN_ERR "btrfs: %d errors while writing supers\n",
|
btrfs_error(root->fs_info, -EIO,
|
||||||
total_errors);
|
"%d errors while writing supers", total_errors);
|
||||||
BUG();
|
return -EIO;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -3014,14 +3048,21 @@ int btrfs_commit_super(struct btrfs_root *root)
|
||||||
if (IS_ERR(trans))
|
if (IS_ERR(trans))
|
||||||
return PTR_ERR(trans);
|
return PTR_ERR(trans);
|
||||||
ret = btrfs_commit_transaction(trans, root);
|
ret = btrfs_commit_transaction(trans, root);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
return ret;
|
||||||
/* run commit again to drop the original snapshot */
|
/* run commit again to drop the original snapshot */
|
||||||
trans = btrfs_join_transaction(root);
|
trans = btrfs_join_transaction(root);
|
||||||
if (IS_ERR(trans))
|
if (IS_ERR(trans))
|
||||||
return PTR_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);
|
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);
|
ret = write_ctree_super(NULL, root, 0);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -3366,8 +3407,8 @@ static void btrfs_destroy_ordered_extents(struct btrfs_root *root)
|
||||||
spin_unlock(&root->fs_info->ordered_extent_lock);
|
spin_unlock(&root->fs_info->ordered_extent_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
|
int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
|
||||||
struct btrfs_root *root)
|
struct btrfs_root *root)
|
||||||
{
|
{
|
||||||
struct rb_node *node;
|
struct rb_node *node;
|
||||||
struct btrfs_delayed_ref_root *delayed_refs;
|
struct btrfs_delayed_ref_root *delayed_refs;
|
||||||
|
@ -3376,6 +3417,7 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
|
||||||
|
|
||||||
delayed_refs = &trans->delayed_refs;
|
delayed_refs = &trans->delayed_refs;
|
||||||
|
|
||||||
|
again:
|
||||||
spin_lock(&delayed_refs->lock);
|
spin_lock(&delayed_refs->lock);
|
||||||
if (delayed_refs->num_entries == 0) {
|
if (delayed_refs->num_entries == 0) {
|
||||||
spin_unlock(&delayed_refs->lock);
|
spin_unlock(&delayed_refs->lock);
|
||||||
|
@ -3397,6 +3439,7 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
|
||||||
struct btrfs_delayed_ref_head *head;
|
struct btrfs_delayed_ref_head *head;
|
||||||
|
|
||||||
head = btrfs_delayed_node_to_head(ref);
|
head = btrfs_delayed_node_to_head(ref);
|
||||||
|
spin_unlock(&delayed_refs->lock);
|
||||||
mutex_lock(&head->mutex);
|
mutex_lock(&head->mutex);
|
||||||
kfree(head->extent_op);
|
kfree(head->extent_op);
|
||||||
delayed_refs->num_heads--;
|
delayed_refs->num_heads--;
|
||||||
|
@ -3404,8 +3447,9 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
|
||||||
delayed_refs->num_heads_ready--;
|
delayed_refs->num_heads_ready--;
|
||||||
list_del_init(&head->cluster);
|
list_del_init(&head->cluster);
|
||||||
mutex_unlock(&head->mutex);
|
mutex_unlock(&head->mutex);
|
||||||
|
btrfs_put_delayed_ref(ref);
|
||||||
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock(&delayed_refs->lock);
|
spin_unlock(&delayed_refs->lock);
|
||||||
btrfs_put_delayed_ref(ref);
|
btrfs_put_delayed_ref(ref);
|
||||||
|
|
||||||
|
@ -3649,6 +3693,17 @@ int btrfs_cleanup_transaction(struct btrfs_root *root)
|
||||||
return 0;
|
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 = {
|
static struct extent_io_ops btree_extent_io_ops = {
|
||||||
.write_cache_pages_lock_hook = btree_lock_page_hook,
|
.write_cache_pages_lock_hook = btree_lock_page_hook,
|
||||||
.readpage_end_io_hook = btree_readpage_end_io_hook,
|
.readpage_end_io_hook = btree_readpage_end_io_hook,
|
||||||
|
@ -3656,4 +3711,5 @@ static struct extent_io_ops btree_extent_io_ops = {
|
||||||
.submit_bio_hook = btree_submit_bio_hook,
|
.submit_bio_hook = btree_submit_bio_hook,
|
||||||
/* note we're sharing with inode.c for the merge bio hook */
|
/* note we're sharing with inode.c for the merge bio hook */
|
||||||
.merge_bio_hook = btrfs_merge_bio_hook,
|
.merge_bio_hook = btrfs_merge_bio_hook,
|
||||||
|
.writepage_io_failed_hook = btree_writepage_io_failed_hook,
|
||||||
};
|
};
|
||||||
|
|
|
@ -193,7 +193,7 @@ static struct dentry *btrfs_get_parent(struct dentry *child)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
BUG_ON(ret == 0);
|
BUG_ON(ret == 0); /* Key with offset of -1 found */
|
||||||
if (path->slots[0] == 0) {
|
if (path->slots[0] == 0) {
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
|
@ -245,7 +245,7 @@ static int exclude_super_stripes(struct btrfs_root *root,
|
||||||
cache->bytes_super += stripe_len;
|
cache->bytes_super += stripe_len;
|
||||||
ret = add_excluded_extent(root, cache->key.objectid,
|
ret = add_excluded_extent(root, cache->key.objectid,
|
||||||
stripe_len);
|
stripe_len);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
|
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
|
||||||
|
@ -253,13 +253,13 @@ static int exclude_super_stripes(struct btrfs_root *root,
|
||||||
ret = btrfs_rmap_block(&root->fs_info->mapping_tree,
|
ret = btrfs_rmap_block(&root->fs_info->mapping_tree,
|
||||||
cache->key.objectid, bytenr,
|
cache->key.objectid, bytenr,
|
||||||
0, &logical, &nr, &stripe_len);
|
0, &logical, &nr, &stripe_len);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
|
|
||||||
while (nr--) {
|
while (nr--) {
|
||||||
cache->bytes_super += stripe_len;
|
cache->bytes_super += stripe_len;
|
||||||
ret = add_excluded_extent(root, logical[nr],
|
ret = add_excluded_extent(root, logical[nr],
|
||||||
stripe_len);
|
stripe_len);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree(logical);
|
kfree(logical);
|
||||||
|
@ -321,7 +321,7 @@ static u64 add_new_free_space(struct btrfs_block_group_cache *block_group,
|
||||||
total_added += size;
|
total_added += size;
|
||||||
ret = btrfs_add_free_space(block_group, start,
|
ret = btrfs_add_free_space(block_group, start,
|
||||||
size);
|
size);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM or logic error */
|
||||||
start = extent_end + 1;
|
start = extent_end + 1;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
@ -332,7 +332,7 @@ static u64 add_new_free_space(struct btrfs_block_group_cache *block_group,
|
||||||
size = end - start;
|
size = end - start;
|
||||||
total_added += size;
|
total_added += size;
|
||||||
ret = btrfs_add_free_space(block_group, start, size);
|
ret = btrfs_add_free_space(block_group, start, size);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM or logic error */
|
||||||
}
|
}
|
||||||
|
|
||||||
return total_added;
|
return total_added;
|
||||||
|
@ -474,7 +474,8 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
caching_ctl = kzalloc(sizeof(*caching_ctl), GFP_NOFS);
|
caching_ctl = kzalloc(sizeof(*caching_ctl), GFP_NOFS);
|
||||||
BUG_ON(!caching_ctl);
|
if (!caching_ctl)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&caching_ctl->list);
|
INIT_LIST_HEAD(&caching_ctl->list);
|
||||||
mutex_init(&caching_ctl->mutex);
|
mutex_init(&caching_ctl->mutex);
|
||||||
|
@ -982,7 +983,7 @@ static int convert_extent_item_v0(struct btrfs_trans_handle *trans,
|
||||||
ret = btrfs_next_leaf(root, path);
|
ret = btrfs_next_leaf(root, path);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
BUG_ON(ret > 0);
|
BUG_ON(ret > 0); /* Corruption */
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
}
|
}
|
||||||
btrfs_item_key_to_cpu(leaf, &found_key,
|
btrfs_item_key_to_cpu(leaf, &found_key,
|
||||||
|
@ -1008,7 +1009,7 @@ static int convert_extent_item_v0(struct btrfs_trans_handle *trans,
|
||||||
new_size + extra_size, 1);
|
new_size + extra_size, 1);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* Corruption */
|
||||||
|
|
||||||
btrfs_extend_item(trans, root, path, new_size);
|
btrfs_extend_item(trans, root, path, new_size);
|
||||||
|
|
||||||
|
@ -1478,7 +1479,11 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
|
||||||
err = ret;
|
err = ret;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
BUG_ON(ret);
|
if (ret && !insert) {
|
||||||
|
err = -ENOENT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
BUG_ON(ret); /* Corruption */
|
||||||
|
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
item_size = btrfs_item_size_nr(leaf, path->slots[0]);
|
item_size = btrfs_item_size_nr(leaf, path->slots[0]);
|
||||||
|
@ -1831,6 +1836,7 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
|
||||||
/* Tell the block device(s) that the sectors can be discarded */
|
/* Tell the block device(s) that the sectors can be discarded */
|
||||||
ret = btrfs_map_block(&root->fs_info->mapping_tree, REQ_DISCARD,
|
ret = btrfs_map_block(&root->fs_info->mapping_tree, REQ_DISCARD,
|
||||||
bytenr, &num_bytes, &bbio, 0);
|
bytenr, &num_bytes, &bbio, 0);
|
||||||
|
/* Error condition is -ENOMEM */
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
struct btrfs_bio_stripe *stripe = bbio->stripes;
|
struct btrfs_bio_stripe *stripe = bbio->stripes;
|
||||||
int i;
|
int i;
|
||||||
|
@ -1846,7 +1852,7 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
|
||||||
if (!ret)
|
if (!ret)
|
||||||
discarded_bytes += stripe->length;
|
discarded_bytes += stripe->length;
|
||||||
else if (ret != -EOPNOTSUPP)
|
else if (ret != -EOPNOTSUPP)
|
||||||
break;
|
break; /* Logic errors or -ENOMEM, or -EIO but I don't know how that could happen JDM */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Just in case we get back EOPNOTSUPP for some reason,
|
* Just in case we get back EOPNOTSUPP for some reason,
|
||||||
|
@ -1865,6 +1871,7 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Can return -ENOMEM */
|
||||||
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
|
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
u64 bytenr, u64 num_bytes, u64 parent,
|
u64 bytenr, u64 num_bytes, u64 parent,
|
||||||
|
@ -1940,7 +1947,8 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
|
||||||
ret = insert_extent_backref(trans, root->fs_info->extent_root,
|
ret = insert_extent_backref(trans, root->fs_info->extent_root,
|
||||||
path, bytenr, parent, root_objectid,
|
path, bytenr, parent, root_objectid,
|
||||||
owner, offset, refs_to_add);
|
owner, offset, refs_to_add);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
out:
|
out:
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
return err;
|
return err;
|
||||||
|
@ -2027,6 +2035,9 @@ static int run_delayed_extent_op(struct btrfs_trans_handle *trans,
|
||||||
int ret;
|
int ret;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
|
if (trans->aborted)
|
||||||
|
return 0;
|
||||||
|
|
||||||
path = btrfs_alloc_path();
|
path = btrfs_alloc_path();
|
||||||
if (!path)
|
if (!path)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -2124,7 +2135,11 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_delayed_extent_op *extent_op,
|
struct btrfs_delayed_extent_op *extent_op,
|
||||||
int insert_reserved)
|
int insert_reserved)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret = 0;
|
||||||
|
|
||||||
|
if (trans->aborted)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (btrfs_delayed_ref_is_head(node)) {
|
if (btrfs_delayed_ref_is_head(node)) {
|
||||||
struct btrfs_delayed_ref_head *head;
|
struct btrfs_delayed_ref_head *head;
|
||||||
/*
|
/*
|
||||||
|
@ -2142,11 +2157,10 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans,
|
||||||
ret = btrfs_del_csums(trans, root,
|
ret = btrfs_del_csums(trans, root,
|
||||||
node->bytenr,
|
node->bytenr,
|
||||||
node->num_bytes);
|
node->num_bytes);
|
||||||
BUG_ON(ret);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&head->mutex);
|
mutex_unlock(&head->mutex);
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->type == BTRFS_TREE_BLOCK_REF_KEY ||
|
if (node->type == BTRFS_TREE_BLOCK_REF_KEY ||
|
||||||
|
@ -2193,6 +2207,10 @@ again:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns 0 on success or if called with an already aborted transaction.
|
||||||
|
* Returns -ENOMEM or -EIO on failure and will abort the transaction.
|
||||||
|
*/
|
||||||
static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
|
static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
struct list_head *cluster)
|
struct list_head *cluster)
|
||||||
|
@ -2281,9 +2299,13 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
ret = run_delayed_extent_op(trans, root,
|
ret = run_delayed_extent_op(trans, root,
|
||||||
ref, extent_op);
|
ref, extent_op);
|
||||||
BUG_ON(ret);
|
|
||||||
kfree(extent_op);
|
kfree(extent_op);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
printk(KERN_DEBUG "btrfs: run_delayed_extent_op returned %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2304,11 +2326,16 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
ret = run_one_delayed_ref(trans, root, ref, extent_op,
|
ret = run_one_delayed_ref(trans, root, ref, extent_op,
|
||||||
must_insert_reserved);
|
must_insert_reserved);
|
||||||
BUG_ON(ret);
|
|
||||||
|
|
||||||
btrfs_put_delayed_ref(ref);
|
btrfs_put_delayed_ref(ref);
|
||||||
kfree(extent_op);
|
kfree(extent_op);
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
printk(KERN_DEBUG "btrfs: run_one_delayed_ref returned %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
next:
|
next:
|
||||||
do_chunk_alloc(trans, root->fs_info->extent_root,
|
do_chunk_alloc(trans, root->fs_info->extent_root,
|
||||||
2 * 1024 * 1024,
|
2 * 1024 * 1024,
|
||||||
|
@ -2343,6 +2370,9 @@ static void wait_for_more_refs(struct btrfs_delayed_ref_root *delayed_refs,
|
||||||
* 0, which means to process everything in the tree at the start
|
* 0, which means to process everything in the tree at the start
|
||||||
* of the run (but not newly added entries), or it can be some target
|
* of the run (but not newly added entries), or it can be some target
|
||||||
* number you'd like to process.
|
* number you'd like to process.
|
||||||
|
*
|
||||||
|
* Returns 0 on success or if called with an aborted transaction
|
||||||
|
* Returns <0 on error and aborts the transaction
|
||||||
*/
|
*/
|
||||||
int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
|
int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root, unsigned long count)
|
struct btrfs_root *root, unsigned long count)
|
||||||
|
@ -2358,6 +2388,10 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
|
||||||
unsigned long num_refs = 0;
|
unsigned long num_refs = 0;
|
||||||
int consider_waiting;
|
int consider_waiting;
|
||||||
|
|
||||||
|
/* We'll clean this up in btrfs_cleanup_transaction */
|
||||||
|
if (trans->aborted)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (root == root->fs_info->extent_root)
|
if (root == root->fs_info->extent_root)
|
||||||
root = root->fs_info->tree_root;
|
root = root->fs_info->tree_root;
|
||||||
|
|
||||||
|
@ -2415,7 +2449,11 @@ again:
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = run_clustered_refs(trans, root, &cluster);
|
ret = run_clustered_refs(trans, root, &cluster);
|
||||||
BUG_ON(ret < 0);
|
if (ret < 0) {
|
||||||
|
spin_unlock(&delayed_refs->lock);
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
count -= min_t(unsigned long, ret, count);
|
count -= min_t(unsigned long, ret, count);
|
||||||
|
|
||||||
|
@ -2580,7 +2618,7 @@ static noinline int check_committed_ref(struct btrfs_trans_handle *trans,
|
||||||
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
|
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
BUG_ON(ret == 0);
|
BUG_ON(ret == 0); /* Corruption */
|
||||||
|
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
if (path->slots[0] == 0)
|
if (path->slots[0] == 0)
|
||||||
|
@ -2734,7 +2772,6 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
fail:
|
fail:
|
||||||
BUG();
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2763,7 +2800,7 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans,
|
||||||
ret = btrfs_search_slot(trans, extent_root, &cache->key, path, 0, 1);
|
ret = btrfs_search_slot(trans, extent_root, &cache->key, path, 0, 1);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* Corruption */
|
||||||
|
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
bi = btrfs_item_ptr_offset(leaf, path->slots[0]);
|
bi = btrfs_item_ptr_offset(leaf, path->slots[0]);
|
||||||
|
@ -2771,8 +2808,10 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans,
|
||||||
btrfs_mark_buffer_dirty(leaf);
|
btrfs_mark_buffer_dirty(leaf);
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
fail:
|
fail:
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2945,7 +2984,8 @@ again:
|
||||||
if (last == 0) {
|
if (last == 0) {
|
||||||
err = btrfs_run_delayed_refs(trans, root,
|
err = btrfs_run_delayed_refs(trans, root,
|
||||||
(unsigned long)-1);
|
(unsigned long)-1);
|
||||||
BUG_ON(err);
|
if (err) /* File system offline */
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
cache = btrfs_lookup_first_block_group(root->fs_info, last);
|
cache = btrfs_lookup_first_block_group(root->fs_info, last);
|
||||||
|
@ -2972,7 +3012,9 @@ again:
|
||||||
last = cache->key.objectid + cache->key.offset;
|
last = cache->key.objectid + cache->key.offset;
|
||||||
|
|
||||||
err = write_one_cache_group(trans, root, path, cache);
|
err = write_one_cache_group(trans, root, path, cache);
|
||||||
BUG_ON(err);
|
if (err) /* File system offline */
|
||||||
|
goto out;
|
||||||
|
|
||||||
btrfs_put_block_group(cache);
|
btrfs_put_block_group(cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2985,7 +3027,8 @@ again:
|
||||||
if (last == 0) {
|
if (last == 0) {
|
||||||
err = btrfs_run_delayed_refs(trans, root,
|
err = btrfs_run_delayed_refs(trans, root,
|
||||||
(unsigned long)-1);
|
(unsigned long)-1);
|
||||||
BUG_ON(err);
|
if (err) /* File system offline */
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
cache = btrfs_lookup_first_block_group(root->fs_info, last);
|
cache = btrfs_lookup_first_block_group(root->fs_info, last);
|
||||||
|
@ -3010,20 +3053,21 @@ again:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_write_out_cache(root, trans, cache, path);
|
err = btrfs_write_out_cache(root, trans, cache, path);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we didn't have an error then the cache state is still
|
* If we didn't have an error then the cache state is still
|
||||||
* NEED_WRITE, so we can set it to WRITTEN.
|
* NEED_WRITE, so we can set it to WRITTEN.
|
||||||
*/
|
*/
|
||||||
if (cache->disk_cache_state == BTRFS_DC_NEED_WRITE)
|
if (!err && cache->disk_cache_state == BTRFS_DC_NEED_WRITE)
|
||||||
cache->disk_cache_state = BTRFS_DC_WRITTEN;
|
cache->disk_cache_state = BTRFS_DC_WRITTEN;
|
||||||
last = cache->key.objectid + cache->key.offset;
|
last = cache->key.objectid + cache->key.offset;
|
||||||
btrfs_put_block_group(cache);
|
btrfs_put_block_group(cache);
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
|
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
return 0;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr)
|
int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr)
|
||||||
|
@ -3407,9 +3451,9 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
|
||||||
if (!space_info) {
|
if (!space_info) {
|
||||||
ret = update_space_info(extent_root->fs_info, flags,
|
ret = update_space_info(extent_root->fs_info, flags,
|
||||||
0, 0, &space_info);
|
0, 0, &space_info);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
BUG_ON(!space_info);
|
BUG_ON(!space_info); /* Logic error */
|
||||||
|
|
||||||
again:
|
again:
|
||||||
spin_lock(&space_info->lock);
|
spin_lock(&space_info->lock);
|
||||||
|
@ -3674,8 +3718,10 @@ again:
|
||||||
ret = wait_event_interruptible(space_info->wait,
|
ret = wait_event_interruptible(space_info->wait,
|
||||||
!space_info->flush);
|
!space_info->flush);
|
||||||
/* Must have been interrupted, return */
|
/* Must have been interrupted, return */
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
printk(KERN_DEBUG "btrfs: %s returning -EINTR\n", __func__);
|
||||||
return -EINTR;
|
return -EINTR;
|
||||||
|
}
|
||||||
|
|
||||||
spin_lock(&space_info->lock);
|
spin_lock(&space_info->lock);
|
||||||
}
|
}
|
||||||
|
@ -3832,8 +3878,9 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct btrfs_block_rsv *get_block_rsv(struct btrfs_trans_handle *trans,
|
static struct btrfs_block_rsv *get_block_rsv(
|
||||||
struct btrfs_root *root)
|
const struct btrfs_trans_handle *trans,
|
||||||
|
const struct btrfs_root *root)
|
||||||
{
|
{
|
||||||
struct btrfs_block_rsv *block_rsv = NULL;
|
struct btrfs_block_rsv *block_rsv = NULL;
|
||||||
|
|
||||||
|
@ -4200,6 +4247,7 @@ void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
|
||||||
trans->bytes_reserved = 0;
|
trans->bytes_reserved = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Can only return 0 or -ENOSPC */
|
||||||
int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
|
int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
|
||||||
struct inode *inode)
|
struct inode *inode)
|
||||||
{
|
{
|
||||||
|
@ -4536,7 +4584,7 @@ static int update_block_group(struct btrfs_trans_handle *trans,
|
||||||
while (total) {
|
while (total) {
|
||||||
cache = btrfs_lookup_block_group(info, bytenr);
|
cache = btrfs_lookup_block_group(info, bytenr);
|
||||||
if (!cache)
|
if (!cache)
|
||||||
return -1;
|
return -ENOENT;
|
||||||
if (cache->flags & (BTRFS_BLOCK_GROUP_DUP |
|
if (cache->flags & (BTRFS_BLOCK_GROUP_DUP |
|
||||||
BTRFS_BLOCK_GROUP_RAID1 |
|
BTRFS_BLOCK_GROUP_RAID1 |
|
||||||
BTRFS_BLOCK_GROUP_RAID10))
|
BTRFS_BLOCK_GROUP_RAID10))
|
||||||
|
@ -4639,7 +4687,7 @@ int btrfs_pin_extent(struct btrfs_root *root,
|
||||||
struct btrfs_block_group_cache *cache;
|
struct btrfs_block_group_cache *cache;
|
||||||
|
|
||||||
cache = btrfs_lookup_block_group(root->fs_info, bytenr);
|
cache = btrfs_lookup_block_group(root->fs_info, bytenr);
|
||||||
BUG_ON(!cache);
|
BUG_ON(!cache); /* Logic error */
|
||||||
|
|
||||||
pin_down_extent(root, cache, bytenr, num_bytes, reserved);
|
pin_down_extent(root, cache, bytenr, num_bytes, reserved);
|
||||||
|
|
||||||
|
@ -4657,7 +4705,7 @@ int btrfs_pin_extent_for_log_replay(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_block_group_cache *cache;
|
struct btrfs_block_group_cache *cache;
|
||||||
|
|
||||||
cache = btrfs_lookup_block_group(root->fs_info, bytenr);
|
cache = btrfs_lookup_block_group(root->fs_info, bytenr);
|
||||||
BUG_ON(!cache);
|
BUG_ON(!cache); /* Logic error */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* pull in the free space cache (if any) so that our pin
|
* pull in the free space cache (if any) so that our pin
|
||||||
|
@ -4702,6 +4750,7 @@ static int btrfs_update_reserved_bytes(struct btrfs_block_group_cache *cache,
|
||||||
{
|
{
|
||||||
struct btrfs_space_info *space_info = cache->space_info;
|
struct btrfs_space_info *space_info = cache->space_info;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
spin_lock(&space_info->lock);
|
spin_lock(&space_info->lock);
|
||||||
spin_lock(&cache->lock);
|
spin_lock(&cache->lock);
|
||||||
if (reserve != RESERVE_FREE) {
|
if (reserve != RESERVE_FREE) {
|
||||||
|
@ -4774,7 +4823,7 @@ static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end)
|
||||||
if (cache)
|
if (cache)
|
||||||
btrfs_put_block_group(cache);
|
btrfs_put_block_group(cache);
|
||||||
cache = btrfs_lookup_block_group(fs_info, start);
|
cache = btrfs_lookup_block_group(fs_info, start);
|
||||||
BUG_ON(!cache);
|
BUG_ON(!cache); /* Logic error */
|
||||||
}
|
}
|
||||||
|
|
||||||
len = cache->key.objectid + cache->key.offset - start;
|
len = cache->key.objectid + cache->key.offset - start;
|
||||||
|
@ -4811,6 +4860,9 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
|
||||||
u64 end;
|
u64 end;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (trans->aborted)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (fs_info->pinned_extents == &fs_info->freed_extents[0])
|
if (fs_info->pinned_extents == &fs_info->freed_extents[0])
|
||||||
unpin = &fs_info->freed_extents[1];
|
unpin = &fs_info->freed_extents[1];
|
||||||
else
|
else
|
||||||
|
@ -4896,7 +4948,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
||||||
ret = remove_extent_backref(trans, extent_root, path,
|
ret = remove_extent_backref(trans, extent_root, path,
|
||||||
NULL, refs_to_drop,
|
NULL, refs_to_drop,
|
||||||
is_data);
|
is_data);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
goto abort;
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
path->leave_spinning = 1;
|
path->leave_spinning = 1;
|
||||||
|
|
||||||
|
@ -4914,10 +4967,11 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
||||||
btrfs_print_leaf(extent_root,
|
btrfs_print_leaf(extent_root,
|
||||||
path->nodes[0]);
|
path->nodes[0]);
|
||||||
}
|
}
|
||||||
BUG_ON(ret);
|
if (ret < 0)
|
||||||
|
goto abort;
|
||||||
extent_slot = path->slots[0];
|
extent_slot = path->slots[0];
|
||||||
}
|
}
|
||||||
} else {
|
} else if (ret == -ENOENT) {
|
||||||
btrfs_print_leaf(extent_root, path->nodes[0]);
|
btrfs_print_leaf(extent_root, path->nodes[0]);
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
printk(KERN_ERR "btrfs unable to find ref byte nr %llu "
|
printk(KERN_ERR "btrfs unable to find ref byte nr %llu "
|
||||||
|
@ -4927,6 +4981,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
||||||
(unsigned long long)root_objectid,
|
(unsigned long long)root_objectid,
|
||||||
(unsigned long long)owner_objectid,
|
(unsigned long long)owner_objectid,
|
||||||
(unsigned long long)owner_offset);
|
(unsigned long long)owner_offset);
|
||||||
|
} else {
|
||||||
|
goto abort;
|
||||||
}
|
}
|
||||||
|
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
|
@ -4936,7 +4992,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
||||||
BUG_ON(found_extent || extent_slot != path->slots[0]);
|
BUG_ON(found_extent || extent_slot != path->slots[0]);
|
||||||
ret = convert_extent_item_v0(trans, extent_root, path,
|
ret = convert_extent_item_v0(trans, extent_root, path,
|
||||||
owner_objectid, 0);
|
owner_objectid, 0);
|
||||||
BUG_ON(ret < 0);
|
if (ret < 0)
|
||||||
|
goto abort;
|
||||||
|
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
path->leave_spinning = 1;
|
path->leave_spinning = 1;
|
||||||
|
@ -4953,7 +5010,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
||||||
(unsigned long long)bytenr);
|
(unsigned long long)bytenr);
|
||||||
btrfs_print_leaf(extent_root, path->nodes[0]);
|
btrfs_print_leaf(extent_root, path->nodes[0]);
|
||||||
}
|
}
|
||||||
BUG_ON(ret);
|
if (ret < 0)
|
||||||
|
goto abort;
|
||||||
extent_slot = path->slots[0];
|
extent_slot = path->slots[0];
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
item_size = btrfs_item_size_nr(leaf, extent_slot);
|
item_size = btrfs_item_size_nr(leaf, extent_slot);
|
||||||
|
@ -4990,7 +5048,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
||||||
ret = remove_extent_backref(trans, extent_root, path,
|
ret = remove_extent_backref(trans, extent_root, path,
|
||||||
iref, refs_to_drop,
|
iref, refs_to_drop,
|
||||||
is_data);
|
is_data);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
goto abort;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (found_extent) {
|
if (found_extent) {
|
||||||
|
@ -5007,12 +5066,14 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
ret = btrfs_del_items(trans, extent_root, path, path->slots[0],
|
ret = btrfs_del_items(trans, extent_root, path, path->slots[0],
|
||||||
num_to_del);
|
num_to_del);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
goto abort;
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
|
|
||||||
if (is_data) {
|
if (is_data) {
|
||||||
ret = btrfs_del_csums(trans, root, bytenr, num_bytes);
|
ret = btrfs_del_csums(trans, root, bytenr, num_bytes);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
goto abort;
|
||||||
} else {
|
} else {
|
||||||
invalidate_mapping_pages(info->btree_inode->i_mapping,
|
invalidate_mapping_pages(info->btree_inode->i_mapping,
|
||||||
bytenr >> PAGE_CACHE_SHIFT,
|
bytenr >> PAGE_CACHE_SHIFT,
|
||||||
|
@ -5020,10 +5081,16 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = update_block_group(trans, root, bytenr, num_bytes, 0);
|
ret = update_block_group(trans, root, bytenr, num_bytes, 0);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
goto abort;
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
abort:
|
||||||
|
btrfs_abort_transaction(trans, extent_root, ret);
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -5119,7 +5186,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
|
||||||
parent, root->root_key.objectid,
|
parent, root->root_key.objectid,
|
||||||
btrfs_header_level(buf),
|
btrfs_header_level(buf),
|
||||||
BTRFS_DROP_DELAYED_REF, NULL, for_cow);
|
BTRFS_DROP_DELAYED_REF, NULL, for_cow);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!last_ref)
|
if (!last_ref)
|
||||||
|
@ -5153,6 +5220,7 @@ out:
|
||||||
btrfs_put_block_group(cache);
|
btrfs_put_block_group(cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Can return -ENOMEM */
|
||||||
int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||||
u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid,
|
u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid,
|
||||||
u64 owner, u64 offset, int for_cow)
|
u64 owner, u64 offset, int for_cow)
|
||||||
|
@ -5174,14 +5242,12 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||||
num_bytes,
|
num_bytes,
|
||||||
parent, root_objectid, (int)owner,
|
parent, root_objectid, (int)owner,
|
||||||
BTRFS_DROP_DELAYED_REF, NULL, for_cow);
|
BTRFS_DROP_DELAYED_REF, NULL, for_cow);
|
||||||
BUG_ON(ret);
|
|
||||||
} else {
|
} else {
|
||||||
ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr,
|
ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr,
|
||||||
num_bytes,
|
num_bytes,
|
||||||
parent, root_objectid, owner,
|
parent, root_objectid, owner,
|
||||||
offset, BTRFS_DROP_DELAYED_REF,
|
offset, BTRFS_DROP_DELAYED_REF,
|
||||||
NULL, for_cow);
|
NULL, for_cow);
|
||||||
BUG_ON(ret);
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -5418,6 +5484,7 @@ have_block_group:
|
||||||
found_uncached_bg = true;
|
found_uncached_bg = true;
|
||||||
ret = cache_block_group(block_group, trans,
|
ret = cache_block_group(block_group, trans,
|
||||||
orig_root, 1);
|
orig_root, 1);
|
||||||
|
BUG_ON(ret < 0); /* -ENOMEM */
|
||||||
if (block_group->cached == BTRFS_CACHE_FINISHED)
|
if (block_group->cached == BTRFS_CACHE_FINISHED)
|
||||||
goto alloc;
|
goto alloc;
|
||||||
|
|
||||||
|
@ -5439,7 +5506,7 @@ have_block_group:
|
||||||
if (loop > LOOP_FIND_IDEAL) {
|
if (loop > LOOP_FIND_IDEAL) {
|
||||||
ret = cache_block_group(block_group, trans,
|
ret = cache_block_group(block_group, trans,
|
||||||
orig_root, 0);
|
orig_root, 0);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -5712,6 +5779,11 @@ loop:
|
||||||
ret = do_chunk_alloc(trans, root, num_bytes +
|
ret = do_chunk_alloc(trans, root, num_bytes +
|
||||||
2 * 1024 * 1024, data,
|
2 * 1024 * 1024, data,
|
||||||
CHUNK_ALLOC_LIMITED);
|
CHUNK_ALLOC_LIMITED);
|
||||||
|
if (ret < 0) {
|
||||||
|
btrfs_abort_transaction(trans,
|
||||||
|
root, ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
allowed_chunk_alloc = 0;
|
allowed_chunk_alloc = 0;
|
||||||
if (ret == 1)
|
if (ret == 1)
|
||||||
done_chunk_alloc = 1;
|
done_chunk_alloc = 1;
|
||||||
|
@ -5740,6 +5812,7 @@ loop:
|
||||||
} else if (ins->objectid) {
|
} else if (ins->objectid) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -5806,10 +5879,15 @@ again:
|
||||||
* the only place that sets empty_size is btrfs_realloc_node, which
|
* the only place that sets empty_size is btrfs_realloc_node, which
|
||||||
* is not called recursively on allocations
|
* is not called recursively on allocations
|
||||||
*/
|
*/
|
||||||
if (empty_size || root->ref_cows)
|
if (empty_size || root->ref_cows) {
|
||||||
ret = do_chunk_alloc(trans, root->fs_info->extent_root,
|
ret = do_chunk_alloc(trans, root->fs_info->extent_root,
|
||||||
num_bytes + 2 * 1024 * 1024, data,
|
num_bytes + 2 * 1024 * 1024, data,
|
||||||
CHUNK_ALLOC_NO_FORCE);
|
CHUNK_ALLOC_NO_FORCE);
|
||||||
|
if (ret < 0 && ret != -ENOSPC) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
WARN_ON(num_bytes < root->sectorsize);
|
WARN_ON(num_bytes < root->sectorsize);
|
||||||
ret = find_free_extent(trans, root, num_bytes, empty_size,
|
ret = find_free_extent(trans, root, num_bytes, empty_size,
|
||||||
|
@ -5821,8 +5899,12 @@ again:
|
||||||
num_bytes = num_bytes >> 1;
|
num_bytes = num_bytes >> 1;
|
||||||
num_bytes = num_bytes & ~(root->sectorsize - 1);
|
num_bytes = num_bytes & ~(root->sectorsize - 1);
|
||||||
num_bytes = max(num_bytes, min_alloc_size);
|
num_bytes = max(num_bytes, min_alloc_size);
|
||||||
do_chunk_alloc(trans, root->fs_info->extent_root,
|
ret = do_chunk_alloc(trans, root->fs_info->extent_root,
|
||||||
num_bytes, data, CHUNK_ALLOC_FORCE);
|
num_bytes, data, CHUNK_ALLOC_FORCE);
|
||||||
|
if (ret < 0 && ret != -ENOSPC) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
if (num_bytes == min_alloc_size)
|
if (num_bytes == min_alloc_size)
|
||||||
final_tried = true;
|
final_tried = true;
|
||||||
goto again;
|
goto again;
|
||||||
|
@ -5913,7 +5995,10 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
|
||||||
path->leave_spinning = 1;
|
path->leave_spinning = 1;
|
||||||
ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path,
|
ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path,
|
||||||
ins, size);
|
ins, size);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_free_path(path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
extent_item = btrfs_item_ptr(leaf, path->slots[0],
|
extent_item = btrfs_item_ptr(leaf, path->slots[0],
|
||||||
|
@ -5943,7 +6028,7 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
|
|
||||||
ret = update_block_group(trans, root, ins->objectid, ins->offset, 1);
|
ret = update_block_group(trans, root, ins->objectid, ins->offset, 1);
|
||||||
if (ret) {
|
if (ret) { /* -ENOENT, logic error */
|
||||||
printk(KERN_ERR "btrfs update block group failed for %llu "
|
printk(KERN_ERR "btrfs update block group failed for %llu "
|
||||||
"%llu\n", (unsigned long long)ins->objectid,
|
"%llu\n", (unsigned long long)ins->objectid,
|
||||||
(unsigned long long)ins->offset);
|
(unsigned long long)ins->offset);
|
||||||
|
@ -5974,7 +6059,10 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
|
||||||
path->leave_spinning = 1;
|
path->leave_spinning = 1;
|
||||||
ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path,
|
ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path,
|
||||||
ins, size);
|
ins, size);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_free_path(path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
extent_item = btrfs_item_ptr(leaf, path->slots[0],
|
extent_item = btrfs_item_ptr(leaf, path->slots[0],
|
||||||
|
@ -6004,7 +6092,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
|
|
||||||
ret = update_block_group(trans, root, ins->objectid, ins->offset, 1);
|
ret = update_block_group(trans, root, ins->objectid, ins->offset, 1);
|
||||||
if (ret) {
|
if (ret) { /* -ENOENT, logic error */
|
||||||
printk(KERN_ERR "btrfs update block group failed for %llu "
|
printk(KERN_ERR "btrfs update block group failed for %llu "
|
||||||
"%llu\n", (unsigned long long)ins->objectid,
|
"%llu\n", (unsigned long long)ins->objectid,
|
||||||
(unsigned long long)ins->offset);
|
(unsigned long long)ins->offset);
|
||||||
|
@ -6052,28 +6140,28 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
|
||||||
if (!caching_ctl) {
|
if (!caching_ctl) {
|
||||||
BUG_ON(!block_group_cache_done(block_group));
|
BUG_ON(!block_group_cache_done(block_group));
|
||||||
ret = btrfs_remove_free_space(block_group, start, num_bytes);
|
ret = btrfs_remove_free_space(block_group, start, num_bytes);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
} else {
|
} else {
|
||||||
mutex_lock(&caching_ctl->mutex);
|
mutex_lock(&caching_ctl->mutex);
|
||||||
|
|
||||||
if (start >= caching_ctl->progress) {
|
if (start >= caching_ctl->progress) {
|
||||||
ret = add_excluded_extent(root, start, num_bytes);
|
ret = add_excluded_extent(root, start, num_bytes);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
} else if (start + num_bytes <= caching_ctl->progress) {
|
} else if (start + num_bytes <= caching_ctl->progress) {
|
||||||
ret = btrfs_remove_free_space(block_group,
|
ret = btrfs_remove_free_space(block_group,
|
||||||
start, num_bytes);
|
start, num_bytes);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
} else {
|
} else {
|
||||||
num_bytes = caching_ctl->progress - start;
|
num_bytes = caching_ctl->progress - start;
|
||||||
ret = btrfs_remove_free_space(block_group,
|
ret = btrfs_remove_free_space(block_group,
|
||||||
start, num_bytes);
|
start, num_bytes);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
|
|
||||||
start = caching_ctl->progress;
|
start = caching_ctl->progress;
|
||||||
num_bytes = ins->objectid + ins->offset -
|
num_bytes = ins->objectid + ins->offset -
|
||||||
caching_ctl->progress;
|
caching_ctl->progress;
|
||||||
ret = add_excluded_extent(root, start, num_bytes);
|
ret = add_excluded_extent(root, start, num_bytes);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&caching_ctl->mutex);
|
mutex_unlock(&caching_ctl->mutex);
|
||||||
|
@ -6082,7 +6170,7 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
ret = btrfs_update_reserved_bytes(block_group, ins->offset,
|
ret = btrfs_update_reserved_bytes(block_group, ins->offset,
|
||||||
RESERVE_ALLOC_NO_ACCOUNT);
|
RESERVE_ALLOC_NO_ACCOUNT);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* logic error */
|
||||||
btrfs_put_block_group(block_group);
|
btrfs_put_block_group(block_group);
|
||||||
ret = alloc_reserved_file_extent(trans, root, 0, root_objectid,
|
ret = alloc_reserved_file_extent(trans, root, 0, root_objectid,
|
||||||
0, owner, offset, ins, 1);
|
0, owner, offset, ins, 1);
|
||||||
|
@ -6218,7 +6306,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
buf = btrfs_init_new_buffer(trans, root, ins.objectid,
|
buf = btrfs_init_new_buffer(trans, root, ins.objectid,
|
||||||
blocksize, level);
|
blocksize, level);
|
||||||
BUG_ON(IS_ERR(buf));
|
BUG_ON(IS_ERR(buf)); /* -ENOMEM */
|
||||||
|
|
||||||
if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) {
|
if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) {
|
||||||
if (parent == 0)
|
if (parent == 0)
|
||||||
|
@ -6230,7 +6318,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
||||||
if (root_objectid != BTRFS_TREE_LOG_OBJECTID) {
|
if (root_objectid != BTRFS_TREE_LOG_OBJECTID) {
|
||||||
struct btrfs_delayed_extent_op *extent_op;
|
struct btrfs_delayed_extent_op *extent_op;
|
||||||
extent_op = kmalloc(sizeof(*extent_op), GFP_NOFS);
|
extent_op = kmalloc(sizeof(*extent_op), GFP_NOFS);
|
||||||
BUG_ON(!extent_op);
|
BUG_ON(!extent_op); /* -ENOMEM */
|
||||||
if (key)
|
if (key)
|
||||||
memcpy(&extent_op->key, key, sizeof(extent_op->key));
|
memcpy(&extent_op->key, key, sizeof(extent_op->key));
|
||||||
else
|
else
|
||||||
|
@ -6245,7 +6333,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
||||||
ins.offset, parent, root_objectid,
|
ins.offset, parent, root_objectid,
|
||||||
level, BTRFS_ADD_DELAYED_EXTENT,
|
level, BTRFS_ADD_DELAYED_EXTENT,
|
||||||
extent_op, for_cow);
|
extent_op, for_cow);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
@ -6315,7 +6403,9 @@ static noinline void reada_walk_down(struct btrfs_trans_handle *trans,
|
||||||
/* We don't lock the tree block, it's OK to be racy here */
|
/* We don't lock the tree block, it's OK to be racy here */
|
||||||
ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize,
|
ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize,
|
||||||
&refs, &flags);
|
&refs, &flags);
|
||||||
BUG_ON(ret);
|
/* We don't care about errors in readahead. */
|
||||||
|
if (ret < 0)
|
||||||
|
continue;
|
||||||
BUG_ON(refs == 0);
|
BUG_ON(refs == 0);
|
||||||
|
|
||||||
if (wc->stage == DROP_REFERENCE) {
|
if (wc->stage == DROP_REFERENCE) {
|
||||||
|
@ -6382,7 +6472,9 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
|
||||||
eb->start, eb->len,
|
eb->start, eb->len,
|
||||||
&wc->refs[level],
|
&wc->refs[level],
|
||||||
&wc->flags[level]);
|
&wc->flags[level]);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret == -ENOMEM);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
BUG_ON(wc->refs[level] == 0);
|
BUG_ON(wc->refs[level] == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6401,12 +6493,12 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
|
||||||
if (!(wc->flags[level] & flag)) {
|
if (!(wc->flags[level] & flag)) {
|
||||||
BUG_ON(!path->locks[level]);
|
BUG_ON(!path->locks[level]);
|
||||||
ret = btrfs_inc_ref(trans, root, eb, 1, wc->for_reloc);
|
ret = btrfs_inc_ref(trans, root, eb, 1, wc->for_reloc);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
ret = btrfs_dec_ref(trans, root, eb, 0, wc->for_reloc);
|
ret = btrfs_dec_ref(trans, root, eb, 0, wc->for_reloc);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
ret = btrfs_set_disk_extent_flags(trans, root, eb->start,
|
ret = btrfs_set_disk_extent_flags(trans, root, eb->start,
|
||||||
eb->len, flag, 0);
|
eb->len, flag, 0);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
wc->flags[level] |= flag;
|
wc->flags[level] |= flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6478,7 +6570,11 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
|
||||||
ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize,
|
ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize,
|
||||||
&wc->refs[level - 1],
|
&wc->refs[level - 1],
|
||||||
&wc->flags[level - 1]);
|
&wc->flags[level - 1]);
|
||||||
BUG_ON(ret);
|
if (ret < 0) {
|
||||||
|
btrfs_tree_unlock(next);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
BUG_ON(wc->refs[level - 1] == 0);
|
BUG_ON(wc->refs[level - 1] == 0);
|
||||||
*lookup_info = 0;
|
*lookup_info = 0;
|
||||||
|
|
||||||
|
@ -6547,7 +6643,7 @@ skip:
|
||||||
|
|
||||||
ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent,
|
ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent,
|
||||||
root->root_key.objectid, level - 1, 0, 0);
|
root->root_key.objectid, level - 1, 0, 0);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
btrfs_tree_unlock(next);
|
btrfs_tree_unlock(next);
|
||||||
free_extent_buffer(next);
|
free_extent_buffer(next);
|
||||||
|
@ -6605,7 +6701,10 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
|
||||||
eb->start, eb->len,
|
eb->start, eb->len,
|
||||||
&wc->refs[level],
|
&wc->refs[level],
|
||||||
&wc->flags[level]);
|
&wc->flags[level]);
|
||||||
BUG_ON(ret);
|
if (ret < 0) {
|
||||||
|
btrfs_tree_unlock_rw(eb, path->locks[level]);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
BUG_ON(wc->refs[level] == 0);
|
BUG_ON(wc->refs[level] == 0);
|
||||||
if (wc->refs[level] == 1) {
|
if (wc->refs[level] == 1) {
|
||||||
btrfs_tree_unlock_rw(eb, path->locks[level]);
|
btrfs_tree_unlock_rw(eb, path->locks[level]);
|
||||||
|
@ -6625,7 +6724,7 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
|
||||||
else
|
else
|
||||||
ret = btrfs_dec_ref(trans, root, eb, 0,
|
ret = btrfs_dec_ref(trans, root, eb, 0,
|
||||||
wc->for_reloc);
|
wc->for_reloc);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
/* make block locked assertion in clean_tree_block happy */
|
/* make block locked assertion in clean_tree_block happy */
|
||||||
if (!path->locks[level] &&
|
if (!path->locks[level] &&
|
||||||
|
@ -6762,7 +6861,10 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
|
||||||
}
|
}
|
||||||
|
|
||||||
trans = btrfs_start_transaction(tree_root, 0);
|
trans = btrfs_start_transaction(tree_root, 0);
|
||||||
BUG_ON(IS_ERR(trans));
|
if (IS_ERR(trans)) {
|
||||||
|
err = PTR_ERR(trans);
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
if (block_rsv)
|
if (block_rsv)
|
||||||
trans->block_rsv = block_rsv;
|
trans->block_rsv = block_rsv;
|
||||||
|
@ -6787,7 +6889,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
|
||||||
path->lowest_level = 0;
|
path->lowest_level = 0;
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
err = ret;
|
err = ret;
|
||||||
goto out_free;
|
goto out_end_trans;
|
||||||
}
|
}
|
||||||
WARN_ON(ret > 0);
|
WARN_ON(ret > 0);
|
||||||
|
|
||||||
|
@ -6807,7 +6909,10 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
|
||||||
path->nodes[level]->len,
|
path->nodes[level]->len,
|
||||||
&wc->refs[level],
|
&wc->refs[level],
|
||||||
&wc->flags[level]);
|
&wc->flags[level]);
|
||||||
BUG_ON(ret);
|
if (ret < 0) {
|
||||||
|
err = ret;
|
||||||
|
goto out_end_trans;
|
||||||
|
}
|
||||||
BUG_ON(wc->refs[level] == 0);
|
BUG_ON(wc->refs[level] == 0);
|
||||||
|
|
||||||
if (level == root_item->drop_level)
|
if (level == root_item->drop_level)
|
||||||
|
@ -6858,26 +6963,40 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
|
||||||
ret = btrfs_update_root(trans, tree_root,
|
ret = btrfs_update_root(trans, tree_root,
|
||||||
&root->root_key,
|
&root->root_key,
|
||||||
root_item);
|
root_item);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, tree_root, ret);
|
||||||
|
err = ret;
|
||||||
|
goto out_end_trans;
|
||||||
|
}
|
||||||
|
|
||||||
btrfs_end_transaction_throttle(trans, tree_root);
|
btrfs_end_transaction_throttle(trans, tree_root);
|
||||||
trans = btrfs_start_transaction(tree_root, 0);
|
trans = btrfs_start_transaction(tree_root, 0);
|
||||||
BUG_ON(IS_ERR(trans));
|
if (IS_ERR(trans)) {
|
||||||
|
err = PTR_ERR(trans);
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
if (block_rsv)
|
if (block_rsv)
|
||||||
trans->block_rsv = block_rsv;
|
trans->block_rsv = block_rsv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
BUG_ON(err);
|
if (err)
|
||||||
|
goto out_end_trans;
|
||||||
|
|
||||||
ret = btrfs_del_root(trans, tree_root, &root->root_key);
|
ret = btrfs_del_root(trans, tree_root, &root->root_key);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, tree_root, ret);
|
||||||
|
goto out_end_trans;
|
||||||
|
}
|
||||||
|
|
||||||
if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) {
|
if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) {
|
||||||
ret = btrfs_find_last_root(tree_root, root->root_key.objectid,
|
ret = btrfs_find_last_root(tree_root, root->root_key.objectid,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
BUG_ON(ret < 0);
|
if (ret < 0) {
|
||||||
if (ret > 0) {
|
btrfs_abort_transaction(trans, tree_root, ret);
|
||||||
|
err = ret;
|
||||||
|
goto out_end_trans;
|
||||||
|
} else if (ret > 0) {
|
||||||
/* if we fail to delete the orphan item this time
|
/* if we fail to delete the orphan item this time
|
||||||
* around, it'll get picked up the next time.
|
* around, it'll get picked up the next time.
|
||||||
*
|
*
|
||||||
|
@ -6895,8 +7014,9 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
|
||||||
free_extent_buffer(root->commit_root);
|
free_extent_buffer(root->commit_root);
|
||||||
kfree(root);
|
kfree(root);
|
||||||
}
|
}
|
||||||
out_free:
|
out_end_trans:
|
||||||
btrfs_end_transaction_throttle(trans, tree_root);
|
btrfs_end_transaction_throttle(trans, tree_root);
|
||||||
|
out_free:
|
||||||
kfree(wc);
|
kfree(wc);
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
out:
|
out:
|
||||||
|
@ -7099,12 +7219,16 @@ int btrfs_set_block_group_ro(struct btrfs_root *root,
|
||||||
BUG_ON(cache->ro);
|
BUG_ON(cache->ro);
|
||||||
|
|
||||||
trans = btrfs_join_transaction(root);
|
trans = btrfs_join_transaction(root);
|
||||||
BUG_ON(IS_ERR(trans));
|
if (IS_ERR(trans))
|
||||||
|
return PTR_ERR(trans);
|
||||||
|
|
||||||
alloc_flags = update_block_group_flags(root, cache->flags);
|
alloc_flags = update_block_group_flags(root, cache->flags);
|
||||||
if (alloc_flags != cache->flags)
|
if (alloc_flags != cache->flags) {
|
||||||
do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags,
|
ret = do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags,
|
||||||
CHUNK_ALLOC_FORCE);
|
CHUNK_ALLOC_FORCE);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ret = set_block_group_ro(cache, 0);
|
ret = set_block_group_ro(cache, 0);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
|
@ -7567,7 +7691,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
|
||||||
ret = update_space_info(info, cache->flags, found_key.offset,
|
ret = update_space_info(info, cache->flags, found_key.offset,
|
||||||
btrfs_block_group_used(&cache->item),
|
btrfs_block_group_used(&cache->item),
|
||||||
&space_info);
|
&space_info);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
cache->space_info = space_info;
|
cache->space_info = space_info;
|
||||||
spin_lock(&cache->space_info->lock);
|
spin_lock(&cache->space_info->lock);
|
||||||
cache->space_info->bytes_readonly += cache->bytes_super;
|
cache->space_info->bytes_readonly += cache->bytes_super;
|
||||||
|
@ -7576,7 +7700,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
|
||||||
__link_block_group(space_info, cache);
|
__link_block_group(space_info, cache);
|
||||||
|
|
||||||
ret = btrfs_add_block_group_cache(root->fs_info, cache);
|
ret = btrfs_add_block_group_cache(root->fs_info, cache);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* Logic error */
|
||||||
|
|
||||||
set_avail_alloc_bits(root->fs_info, cache->flags);
|
set_avail_alloc_bits(root->fs_info, cache->flags);
|
||||||
if (btrfs_chunk_readonly(root, cache->key.objectid))
|
if (btrfs_chunk_readonly(root, cache->key.objectid))
|
||||||
|
@ -7658,7 +7782,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
ret = update_space_info(root->fs_info, cache->flags, size, bytes_used,
|
ret = update_space_info(root->fs_info, cache->flags, size, bytes_used,
|
||||||
&cache->space_info);
|
&cache->space_info);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
update_global_block_rsv(root->fs_info);
|
update_global_block_rsv(root->fs_info);
|
||||||
|
|
||||||
spin_lock(&cache->space_info->lock);
|
spin_lock(&cache->space_info->lock);
|
||||||
|
@ -7668,11 +7792,14 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
|
||||||
__link_block_group(cache->space_info, cache);
|
__link_block_group(cache->space_info, cache);
|
||||||
|
|
||||||
ret = btrfs_add_block_group_cache(root->fs_info, cache);
|
ret = btrfs_add_block_group_cache(root->fs_info, cache);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* Logic error */
|
||||||
|
|
||||||
ret = btrfs_insert_item(trans, extent_root, &cache->key, &cache->item,
|
ret = btrfs_insert_item(trans, extent_root, &cache->key, &cache->item,
|
||||||
sizeof(cache->item));
|
sizeof(cache->item));
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, extent_root, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
set_avail_alloc_bits(extent_root->fs_info, type);
|
set_avail_alloc_bits(extent_root->fs_info, type);
|
||||||
|
|
||||||
|
@ -7753,7 +7880,10 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
|
||||||
inode = lookup_free_space_inode(tree_root, block_group, path);
|
inode = lookup_free_space_inode(tree_root, block_group, path);
|
||||||
if (!IS_ERR(inode)) {
|
if (!IS_ERR(inode)) {
|
||||||
ret = btrfs_orphan_add(trans, inode);
|
ret = btrfs_orphan_add(trans, inode);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_add_delayed_iput(inode);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
clear_nlink(inode);
|
clear_nlink(inode);
|
||||||
/* One for the block groups ref */
|
/* One for the block groups ref */
|
||||||
spin_lock(&block_group->lock);
|
spin_lock(&block_group->lock);
|
||||||
|
|
|
@ -1244,7 +1244,7 @@ static int set_range_writeback(struct extent_io_tree *tree, u64 start, u64 end)
|
||||||
|
|
||||||
while (index <= end_index) {
|
while (index <= end_index) {
|
||||||
page = find_get_page(tree->mapping, index);
|
page = find_get_page(tree->mapping, index);
|
||||||
BUG_ON(!page);
|
BUG_ON(!page); /* Pages should be in the extent_io_tree */
|
||||||
set_page_writeback(page);
|
set_page_writeback(page);
|
||||||
page_cache_release(page);
|
page_cache_release(page);
|
||||||
index++;
|
index++;
|
||||||
|
@ -1523,7 +1523,7 @@ again:
|
||||||
goto out_failed;
|
goto out_failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* Only valid values are 0 and -EAGAIN */
|
||||||
|
|
||||||
/* step three, lock the state bits for the whole range */
|
/* step three, lock the state bits for the whole range */
|
||||||
lock_extent_bits(tree, delalloc_start, delalloc_end, 0, &cached_state);
|
lock_extent_bits(tree, delalloc_start, delalloc_end, 0, &cached_state);
|
||||||
|
@ -2200,7 +2200,6 @@ int end_extent_writepage(struct page *page, int err, u64 start, u64 end)
|
||||||
/* Writeback already completed */
|
/* Writeback already completed */
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
return 1;
|
return 1;
|
||||||
BUG_ON(ret < 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!uptodate) {
|
if (!uptodate) {
|
||||||
|
@ -2353,7 +2352,6 @@ error_handled:
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
goto error_handled;
|
goto error_handled;
|
||||||
}
|
}
|
||||||
BUG_ON(ret < 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uptodate) {
|
if (uptodate) {
|
||||||
|
@ -2405,6 +2403,10 @@ btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
|
||||||
return bio;
|
return bio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since writes are async, they will only return -ENOMEM.
|
||||||
|
* Reads can return the full range of I/O error conditions.
|
||||||
|
*/
|
||||||
static int __must_check submit_one_bio(int rw, struct bio *bio,
|
static int __must_check submit_one_bio(int rw, struct bio *bio,
|
||||||
int mirror_num, unsigned long bio_flags)
|
int mirror_num, unsigned long bio_flags)
|
||||||
{
|
{
|
||||||
|
@ -2477,7 +2479,8 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree,
|
||||||
bio_add_page(bio, page, page_size, offset) < page_size) {
|
bio_add_page(bio, page, page_size, offset) < page_size) {
|
||||||
ret = submit_one_bio(rw, bio, mirror_num,
|
ret = submit_one_bio(rw, bio, mirror_num,
|
||||||
prev_bio_flags);
|
prev_bio_flags);
|
||||||
BUG_ON(ret < 0);
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
bio = NULL;
|
bio = NULL;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2498,10 +2501,8 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree,
|
||||||
|
|
||||||
if (bio_ret)
|
if (bio_ret)
|
||||||
*bio_ret = bio;
|
*bio_ret = bio;
|
||||||
else {
|
else
|
||||||
ret = submit_one_bio(rw, bio, mirror_num, bio_flags);
|
ret = submit_one_bio(rw, bio, mirror_num, bio_flags);
|
||||||
BUG_ON(ret < 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -2525,6 +2526,7 @@ static void set_page_extent_head(struct page *page, unsigned long len)
|
||||||
* basic readpage implementation. Locked extent state structs are inserted
|
* basic readpage implementation. Locked extent state structs are inserted
|
||||||
* into the tree that are removed when the IO is done (by the end_io
|
* into the tree that are removed when the IO is done (by the end_io
|
||||||
* handlers)
|
* handlers)
|
||||||
|
* XXX JDM: This needs looking at to ensure proper page locking
|
||||||
*/
|
*/
|
||||||
static int __extent_read_full_page(struct extent_io_tree *tree,
|
static int __extent_read_full_page(struct extent_io_tree *tree,
|
||||||
struct page *page,
|
struct page *page,
|
||||||
|
@ -2687,6 +2689,7 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
|
||||||
end_bio_extent_readpage, mirror_num,
|
end_bio_extent_readpage, mirror_num,
|
||||||
*bio_flags,
|
*bio_flags,
|
||||||
this_bio_flag);
|
this_bio_flag);
|
||||||
|
BUG_ON(ret == -ENOMEM);
|
||||||
nr++;
|
nr++;
|
||||||
*bio_flags = this_bio_flag;
|
*bio_flags = this_bio_flag;
|
||||||
}
|
}
|
||||||
|
@ -2713,10 +2716,8 @@ int extent_read_full_page(struct extent_io_tree *tree, struct page *page,
|
||||||
|
|
||||||
ret = __extent_read_full_page(tree, page, get_extent, &bio, mirror_num,
|
ret = __extent_read_full_page(tree, page, get_extent, &bio, mirror_num,
|
||||||
&bio_flags);
|
&bio_flags);
|
||||||
if (bio) {
|
if (bio)
|
||||||
ret = submit_one_bio(READ, bio, mirror_num, bio_flags);
|
ret = submit_one_bio(READ, bio, mirror_num, bio_flags);
|
||||||
BUG_ON(ret < 0);
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2830,7 +2831,11 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
|
||||||
delalloc_end,
|
delalloc_end,
|
||||||
&page_started,
|
&page_started,
|
||||||
&nr_written);
|
&nr_written);
|
||||||
BUG_ON(ret);
|
/* File system has been set read-only */
|
||||||
|
if (ret) {
|
||||||
|
SetPageError(page);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* delalloc_end is already one less than the total
|
* delalloc_end is already one less than the total
|
||||||
* length, so we don't subtract one from
|
* length, so we don't subtract one from
|
||||||
|
@ -3141,7 +3146,7 @@ static void flush_epd_write_bio(struct extent_page_data *epd)
|
||||||
rw = WRITE_SYNC;
|
rw = WRITE_SYNC;
|
||||||
|
|
||||||
ret = submit_one_bio(rw, epd->bio, 0, 0);
|
ret = submit_one_bio(rw, epd->bio, 0, 0);
|
||||||
BUG_ON(ret < 0);
|
BUG_ON(ret < 0); /* -ENOMEM */
|
||||||
epd->bio = NULL;
|
epd->bio = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3257,10 +3262,8 @@ int extent_readpages(struct extent_io_tree *tree,
|
||||||
page_cache_release(page);
|
page_cache_release(page);
|
||||||
}
|
}
|
||||||
BUG_ON(!list_empty(pages));
|
BUG_ON(!list_empty(pages));
|
||||||
if (bio) {
|
if (bio)
|
||||||
int ret = submit_one_bio(READ, bio, 0, bio_flags);
|
return submit_one_bio(READ, bio, 0, bio_flags);
|
||||||
BUG_ON(ret < 0);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4090,7 +4093,8 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
|
||||||
|
|
||||||
if (bio) {
|
if (bio) {
|
||||||
err = submit_one_bio(READ, bio, mirror_num, bio_flags);
|
err = submit_one_bio(READ, bio, mirror_num, bio_flags);
|
||||||
BUG_ON(err < 0);
|
if (err)
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret || wait != WAIT_COMPLETE)
|
if (ret || wait != WAIT_COMPLETE)
|
||||||
|
|
|
@ -59,7 +59,7 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
|
||||||
sizeof(*item));
|
sizeof(*item));
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* Can't happen */
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
item = btrfs_item_ptr(leaf, path->slots[0],
|
item = btrfs_item_ptr(leaf, path->slots[0],
|
||||||
struct btrfs_file_extent_item);
|
struct btrfs_file_extent_item);
|
||||||
|
@ -431,7 +431,7 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
|
||||||
offset = page_offset(bvec->bv_page) + bvec->bv_offset;
|
offset = page_offset(bvec->bv_page) + bvec->bv_offset;
|
||||||
|
|
||||||
ordered = btrfs_lookup_ordered_extent(inode, offset);
|
ordered = btrfs_lookup_ordered_extent(inode, offset);
|
||||||
BUG_ON(!ordered);
|
BUG_ON(!ordered); /* Logic error */
|
||||||
sums->bytenr = ordered->start;
|
sums->bytenr = ordered->start;
|
||||||
|
|
||||||
while (bio_index < bio->bi_vcnt) {
|
while (bio_index < bio->bi_vcnt) {
|
||||||
|
@ -450,11 +450,11 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
|
||||||
|
|
||||||
sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left),
|
sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left),
|
||||||
GFP_NOFS);
|
GFP_NOFS);
|
||||||
BUG_ON(!sums);
|
BUG_ON(!sums); /* -ENOMEM */
|
||||||
sector_sum = sums->sums;
|
sector_sum = sums->sums;
|
||||||
sums->len = bytes_left;
|
sums->len = bytes_left;
|
||||||
ordered = btrfs_lookup_ordered_extent(inode, offset);
|
ordered = btrfs_lookup_ordered_extent(inode, offset);
|
||||||
BUG_ON(!ordered);
|
BUG_ON(!ordered); /* Logic error */
|
||||||
sums->bytenr = ordered->start;
|
sums->bytenr = ordered->start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -643,7 +643,10 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
|
||||||
* item changed size or key
|
* item changed size or key
|
||||||
*/
|
*/
|
||||||
ret = btrfs_split_item(trans, root, path, &key, offset);
|
ret = btrfs_split_item(trans, root, path, &key, offset);
|
||||||
BUG_ON(ret && ret != -EAGAIN);
|
if (ret && ret != -EAGAIN) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
key.offset = end_byte - 1;
|
key.offset = end_byte - 1;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -452,7 +452,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
|
||||||
split = alloc_extent_map();
|
split = alloc_extent_map();
|
||||||
if (!split2)
|
if (!split2)
|
||||||
split2 = alloc_extent_map();
|
split2 = alloc_extent_map();
|
||||||
BUG_ON(!split || !split2);
|
BUG_ON(!split || !split2); /* -ENOMEM */
|
||||||
|
|
||||||
write_lock(&em_tree->lock);
|
write_lock(&em_tree->lock);
|
||||||
em = lookup_extent_mapping(em_tree, start, len);
|
em = lookup_extent_mapping(em_tree, start, len);
|
||||||
|
@ -494,7 +494,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
|
||||||
split->flags = flags;
|
split->flags = flags;
|
||||||
split->compress_type = em->compress_type;
|
split->compress_type = em->compress_type;
|
||||||
ret = add_extent_mapping(em_tree, split);
|
ret = add_extent_mapping(em_tree, split);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* Logic error */
|
||||||
free_extent_map(split);
|
free_extent_map(split);
|
||||||
split = split2;
|
split = split2;
|
||||||
split2 = NULL;
|
split2 = NULL;
|
||||||
|
@ -520,7 +520,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = add_extent_mapping(em_tree, split);
|
ret = add_extent_mapping(em_tree, split);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* Logic error */
|
||||||
free_extent_map(split);
|
free_extent_map(split);
|
||||||
split = NULL;
|
split = NULL;
|
||||||
}
|
}
|
||||||
|
@ -679,7 +679,7 @@ next_slot:
|
||||||
root->root_key.objectid,
|
root->root_key.objectid,
|
||||||
new_key.objectid,
|
new_key.objectid,
|
||||||
start - extent_offset, 0);
|
start - extent_offset, 0);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
*hint_byte = disk_bytenr;
|
*hint_byte = disk_bytenr;
|
||||||
}
|
}
|
||||||
key.offset = start;
|
key.offset = start;
|
||||||
|
@ -754,7 +754,7 @@ next_slot:
|
||||||
root->root_key.objectid,
|
root->root_key.objectid,
|
||||||
key.objectid, key.offset -
|
key.objectid, key.offset -
|
||||||
extent_offset, 0);
|
extent_offset, 0);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
inode_sub_bytes(inode,
|
inode_sub_bytes(inode,
|
||||||
extent_end - key.offset);
|
extent_end - key.offset);
|
||||||
*hint_byte = disk_bytenr;
|
*hint_byte = disk_bytenr;
|
||||||
|
@ -770,7 +770,10 @@ next_slot:
|
||||||
|
|
||||||
ret = btrfs_del_items(trans, root, path, del_slot,
|
ret = btrfs_del_items(trans, root, path, del_slot,
|
||||||
del_nr);
|
del_nr);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
del_nr = 0;
|
del_nr = 0;
|
||||||
del_slot = 0;
|
del_slot = 0;
|
||||||
|
@ -782,11 +785,13 @@ next_slot:
|
||||||
BUG_ON(1);
|
BUG_ON(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (del_nr > 0) {
|
if (!ret && del_nr > 0) {
|
||||||
ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
|
ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -944,7 +949,10 @@ again:
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
BUG_ON(ret < 0);
|
if (ret < 0) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
fi = btrfs_item_ptr(leaf, path->slots[0] - 1,
|
fi = btrfs_item_ptr(leaf, path->slots[0] - 1,
|
||||||
|
@ -963,7 +971,7 @@ again:
|
||||||
ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0,
|
ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0,
|
||||||
root->root_key.objectid,
|
root->root_key.objectid,
|
||||||
ino, orig_offset, 0);
|
ino, orig_offset, 0);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
|
|
||||||
if (split == start) {
|
if (split == start) {
|
||||||
key.offset = start;
|
key.offset = start;
|
||||||
|
@ -990,7 +998,7 @@ again:
|
||||||
ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
|
ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
|
||||||
0, root->root_key.objectid,
|
0, root->root_key.objectid,
|
||||||
ino, orig_offset, 0);
|
ino, orig_offset, 0);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
other_start = 0;
|
other_start = 0;
|
||||||
other_end = start;
|
other_end = start;
|
||||||
|
@ -1007,7 +1015,7 @@ again:
|
||||||
ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
|
ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
|
||||||
0, root->root_key.objectid,
|
0, root->root_key.objectid,
|
||||||
ino, orig_offset, 0);
|
ino, orig_offset, 0);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
if (del_nr == 0) {
|
if (del_nr == 0) {
|
||||||
fi = btrfs_item_ptr(leaf, path->slots[0],
|
fi = btrfs_item_ptr(leaf, path->slots[0],
|
||||||
|
@ -1025,7 +1033,10 @@ again:
|
||||||
btrfs_mark_buffer_dirty(leaf);
|
btrfs_mark_buffer_dirty(leaf);
|
||||||
|
|
||||||
ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
|
ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
|
||||||
BUG_ON(ret);
|
if (ret < 0) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
|
@ -1666,7 +1677,13 @@ static long btrfs_fallocate(struct file *file, int mode,
|
||||||
|
|
||||||
em = btrfs_get_extent(inode, NULL, 0, cur_offset,
|
em = btrfs_get_extent(inode, NULL, 0, cur_offset,
|
||||||
alloc_end - cur_offset, 0);
|
alloc_end - cur_offset, 0);
|
||||||
BUG_ON(IS_ERR_OR_NULL(em));
|
if (IS_ERR_OR_NULL(em)) {
|
||||||
|
if (!em)
|
||||||
|
ret = -ENOMEM;
|
||||||
|
else
|
||||||
|
ret = PTR_ERR(em);
|
||||||
|
break;
|
||||||
|
}
|
||||||
last_byte = min(extent_map_end(em), alloc_end);
|
last_byte = min(extent_map_end(em), alloc_end);
|
||||||
actual_end = min_t(u64, extent_map_end(em), offset + len);
|
actual_end = min_t(u64, extent_map_end(em), offset + len);
|
||||||
last_byte = (last_byte + mask) & ~mask;
|
last_byte = (last_byte + mask) & ~mask;
|
||||||
|
|
|
@ -230,11 +230,13 @@ int btrfs_truncate_free_space_cache(struct btrfs_root *root,
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
trans->block_rsv = rsv;
|
trans->block_rsv = rsv;
|
||||||
WARN_ON(1);
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = btrfs_update_inode(trans, root, inode);
|
ret = btrfs_update_inode(trans, root, inode);
|
||||||
|
if (ret)
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
trans->block_rsv = rsv;
|
trans->block_rsv = rsv;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1948,14 +1950,14 @@ again:
|
||||||
*/
|
*/
|
||||||
ret = btrfs_add_free_space(block_group, old_start,
|
ret = btrfs_add_free_space(block_group, old_start,
|
||||||
offset - old_start);
|
offset - old_start);
|
||||||
WARN_ON(ret);
|
WARN_ON(ret); /* -ENOMEM */
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = remove_from_bitmap(ctl, info, &offset, &bytes);
|
ret = remove_from_bitmap(ctl, info, &offset, &bytes);
|
||||||
if (ret == -EAGAIN)
|
if (ret == -EAGAIN)
|
||||||
goto again;
|
goto again;
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* logic error */
|
||||||
out_lock:
|
out_lock:
|
||||||
spin_unlock(&ctl->tree_lock);
|
spin_unlock(&ctl->tree_lock);
|
||||||
out:
|
out:
|
||||||
|
@ -2346,7 +2348,7 @@ again:
|
||||||
rb_erase(&entry->offset_index, &ctl->free_space_offset);
|
rb_erase(&entry->offset_index, &ctl->free_space_offset);
|
||||||
ret = tree_insert_offset(&cluster->root, entry->offset,
|
ret = tree_insert_offset(&cluster->root, entry->offset,
|
||||||
&entry->offset_index, 1);
|
&entry->offset_index, 1);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -EEXIST; Logic error */
|
||||||
|
|
||||||
trace_btrfs_setup_cluster(block_group, cluster,
|
trace_btrfs_setup_cluster(block_group, cluster,
|
||||||
total_found * block_group->sectorsize, 1);
|
total_found * block_group->sectorsize, 1);
|
||||||
|
@ -2439,7 +2441,7 @@ setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group,
|
||||||
ret = tree_insert_offset(&cluster->root, entry->offset,
|
ret = tree_insert_offset(&cluster->root, entry->offset,
|
||||||
&entry->offset_index, 0);
|
&entry->offset_index, 0);
|
||||||
total_size += entry->bytes;
|
total_size += entry->bytes;
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -EEXIST; Logic error */
|
||||||
} while (node && entry != last);
|
} while (node && entry != last);
|
||||||
|
|
||||||
cluster->max_size = max_extent;
|
cluster->max_size = max_extent;
|
||||||
|
@ -2830,6 +2832,7 @@ u64 btrfs_find_ino_for_alloc(struct btrfs_root *fs_root)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = search_bitmap(ctl, entry, &offset, &count);
|
ret = search_bitmap(ctl, entry, &offset, &count);
|
||||||
|
/* Logic error; Should be empty if it can't find anything */
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
|
||||||
ino = offset;
|
ino = offset;
|
||||||
|
|
|
@ -135,6 +135,7 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Will return 0, -ENOMEM, -EMLINK, or -EEXIST or anything from the CoW path */
|
||||||
int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
|
int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
const char *name, int name_len,
|
const char *name, int name_len,
|
||||||
|
|
|
@ -178,7 +178,7 @@ static void start_caching(struct btrfs_root *root)
|
||||||
|
|
||||||
tsk = kthread_run(caching_kthread, root, "btrfs-ino-cache-%llu\n",
|
tsk = kthread_run(caching_kthread, root, "btrfs-ino-cache-%llu\n",
|
||||||
root->root_key.objectid);
|
root->root_key.objectid);
|
||||||
BUG_ON(IS_ERR(tsk));
|
BUG_ON(IS_ERR(tsk)); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_find_free_ino(struct btrfs_root *root, u64 *objectid)
|
int btrfs_find_free_ino(struct btrfs_root *root, u64 *objectid)
|
||||||
|
@ -271,7 +271,7 @@ void btrfs_unpin_free_ino(struct btrfs_root *root)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
info = rb_entry(n, struct btrfs_free_space, offset_index);
|
info = rb_entry(n, struct btrfs_free_space, offset_index);
|
||||||
BUG_ON(info->bitmap);
|
BUG_ON(info->bitmap); /* Logic error */
|
||||||
|
|
||||||
if (info->offset > root->cache_progress)
|
if (info->offset > root->cache_progress)
|
||||||
goto free;
|
goto free;
|
||||||
|
@ -443,13 +443,13 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
|
||||||
trans->bytes_reserved, 1);
|
trans->bytes_reserved, 1);
|
||||||
again:
|
again:
|
||||||
inode = lookup_free_ino_inode(root, path);
|
inode = lookup_free_ino_inode(root, path);
|
||||||
if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) {
|
if (IS_ERR(inode) && (PTR_ERR(inode) != -ENOENT || retry)) {
|
||||||
ret = PTR_ERR(inode);
|
ret = PTR_ERR(inode);
|
||||||
goto out_release;
|
goto out_release;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_ERR(inode)) {
|
if (IS_ERR(inode)) {
|
||||||
BUG_ON(retry);
|
BUG_ON(retry); /* Logic error */
|
||||||
retry = true;
|
retry = true;
|
||||||
|
|
||||||
ret = create_free_ino_inode(root, trans, path);
|
ret = create_free_ino_inode(root, trans, path);
|
||||||
|
@ -460,12 +460,17 @@ again:
|
||||||
|
|
||||||
BTRFS_I(inode)->generation = 0;
|
BTRFS_I(inode)->generation = 0;
|
||||||
ret = btrfs_update_inode(trans, root, inode);
|
ret = btrfs_update_inode(trans, root, inode);
|
||||||
WARN_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto out_put;
|
||||||
|
}
|
||||||
|
|
||||||
if (i_size_read(inode) > 0) {
|
if (i_size_read(inode) > 0) {
|
||||||
ret = btrfs_truncate_free_space_cache(root, trans, path, inode);
|
ret = btrfs_truncate_free_space_cache(root, trans, path, inode);
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
goto out_put;
|
goto out_put;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock(&root->cache_lock);
|
spin_lock(&root->cache_lock);
|
||||||
|
@ -532,7 +537,7 @@ static int btrfs_find_highest_objectid(struct btrfs_root *root, u64 *objectid)
|
||||||
ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
|
ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
BUG_ON(ret == 0);
|
BUG_ON(ret == 0); /* Corruption */
|
||||||
if (path->slots[0] > 0) {
|
if (path->slots[0] > 0) {
|
||||||
slot = path->slots[0] - 1;
|
slot = path->slots[0] - 1;
|
||||||
l = path->nodes[0];
|
l = path->nodes[0];
|
||||||
|
|
378
fs/btrfs/inode.c
378
fs/btrfs/inode.c
|
@ -150,7 +150,6 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans,
|
||||||
inode_add_bytes(inode, size);
|
inode_add_bytes(inode, size);
|
||||||
ret = btrfs_insert_empty_item(trans, root, path, &key,
|
ret = btrfs_insert_empty_item(trans, root, path, &key,
|
||||||
datasize);
|
datasize);
|
||||||
BUG_ON(ret);
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
err = ret;
|
err = ret;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -206,9 +205,9 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans,
|
||||||
* could end up racing with unlink.
|
* could end up racing with unlink.
|
||||||
*/
|
*/
|
||||||
BTRFS_I(inode)->disk_i_size = inode->i_size;
|
BTRFS_I(inode)->disk_i_size = inode->i_size;
|
||||||
btrfs_update_inode(trans, root, inode);
|
ret = btrfs_update_inode(trans, root, inode);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
fail:
|
fail:
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
return err;
|
return err;
|
||||||
|
@ -250,14 +249,18 @@ static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
ret = btrfs_drop_extents(trans, inode, start, aligned_end,
|
ret = btrfs_drop_extents(trans, inode, start, aligned_end,
|
||||||
&hint_byte, 1);
|
&hint_byte, 1);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (isize > actual_end)
|
if (isize > actual_end)
|
||||||
inline_len = min_t(u64, isize, actual_end);
|
inline_len = min_t(u64, isize, actual_end);
|
||||||
ret = insert_inline_extent(trans, root, inode, start,
|
ret = insert_inline_extent(trans, root, inode, start,
|
||||||
inline_len, compressed_size,
|
inline_len, compressed_size,
|
||||||
compress_type, compressed_pages);
|
compress_type, compressed_pages);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
btrfs_delalloc_release_metadata(inode, end + 1 - start);
|
btrfs_delalloc_release_metadata(inode, end + 1 - start);
|
||||||
btrfs_drop_extent_cache(inode, start, aligned_end - 1, 0);
|
btrfs_drop_extent_cache(inode, start, aligned_end - 1, 0);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -293,7 +296,7 @@ static noinline int add_async_extent(struct async_cow *cow,
|
||||||
struct async_extent *async_extent;
|
struct async_extent *async_extent;
|
||||||
|
|
||||||
async_extent = kmalloc(sizeof(*async_extent), GFP_NOFS);
|
async_extent = kmalloc(sizeof(*async_extent), GFP_NOFS);
|
||||||
BUG_ON(!async_extent);
|
BUG_ON(!async_extent); /* -ENOMEM */
|
||||||
async_extent->start = start;
|
async_extent->start = start;
|
||||||
async_extent->ram_size = ram_size;
|
async_extent->ram_size = ram_size;
|
||||||
async_extent->compressed_size = compressed_size;
|
async_extent->compressed_size = compressed_size;
|
||||||
|
@ -433,7 +436,11 @@ again:
|
||||||
cont:
|
cont:
|
||||||
if (start == 0) {
|
if (start == 0) {
|
||||||
trans = btrfs_join_transaction(root);
|
trans = btrfs_join_transaction(root);
|
||||||
BUG_ON(IS_ERR(trans));
|
if (IS_ERR(trans)) {
|
||||||
|
ret = PTR_ERR(trans);
|
||||||
|
trans = NULL;
|
||||||
|
goto cleanup_and_out;
|
||||||
|
}
|
||||||
trans->block_rsv = &root->fs_info->delalloc_block_rsv;
|
trans->block_rsv = &root->fs_info->delalloc_block_rsv;
|
||||||
|
|
||||||
/* lets try to make an inline extent */
|
/* lets try to make an inline extent */
|
||||||
|
@ -450,11 +457,11 @@ cont:
|
||||||
total_compressed,
|
total_compressed,
|
||||||
compress_type, pages);
|
compress_type, pages);
|
||||||
}
|
}
|
||||||
if (ret == 0) {
|
if (ret <= 0) {
|
||||||
/*
|
/*
|
||||||
* inline extent creation worked, we don't need
|
* inline extent creation worked or returned error,
|
||||||
* to create any more async work items. Unlock
|
* we don't need to create any more async work items.
|
||||||
* and free up our temp pages.
|
* Unlock and free up our temp pages.
|
||||||
*/
|
*/
|
||||||
extent_clear_unlock_delalloc(inode,
|
extent_clear_unlock_delalloc(inode,
|
||||||
&BTRFS_I(inode)->io_tree,
|
&BTRFS_I(inode)->io_tree,
|
||||||
|
@ -547,7 +554,7 @@ cleanup_and_bail_uncompressed:
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return 0;
|
return ret;
|
||||||
|
|
||||||
free_pages_out:
|
free_pages_out:
|
||||||
for (i = 0; i < nr_pages_ret; i++) {
|
for (i = 0; i < nr_pages_ret; i++) {
|
||||||
|
@ -557,6 +564,20 @@ free_pages_out:
|
||||||
kfree(pages);
|
kfree(pages);
|
||||||
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
cleanup_and_out:
|
||||||
|
extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree,
|
||||||
|
start, end, NULL,
|
||||||
|
EXTENT_CLEAR_UNLOCK_PAGE |
|
||||||
|
EXTENT_CLEAR_DIRTY |
|
||||||
|
EXTENT_CLEAR_DELALLOC |
|
||||||
|
EXTENT_SET_WRITEBACK |
|
||||||
|
EXTENT_END_WRITEBACK);
|
||||||
|
if (!trans || IS_ERR(trans))
|
||||||
|
btrfs_error(root->fs_info, ret, "Failed to join transaction");
|
||||||
|
else
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto free_pages_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -606,6 +627,8 @@ retry:
|
||||||
async_extent->ram_size - 1,
|
async_extent->ram_size - 1,
|
||||||
&page_started, &nr_written, 0);
|
&page_started, &nr_written, 0);
|
||||||
|
|
||||||
|
/* JDM XXX */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if page_started, cow_file_range inserted an
|
* if page_started, cow_file_range inserted an
|
||||||
* inline extent and took care of all the unlocking
|
* inline extent and took care of all the unlocking
|
||||||
|
@ -628,14 +651,19 @@ retry:
|
||||||
async_extent->start + async_extent->ram_size - 1);
|
async_extent->start + async_extent->ram_size - 1);
|
||||||
|
|
||||||
trans = btrfs_join_transaction(root);
|
trans = btrfs_join_transaction(root);
|
||||||
BUG_ON(IS_ERR(trans));
|
if (IS_ERR(trans)) {
|
||||||
trans->block_rsv = &root->fs_info->delalloc_block_rsv;
|
ret = PTR_ERR(trans);
|
||||||
ret = btrfs_reserve_extent(trans, root,
|
} else {
|
||||||
|
trans->block_rsv = &root->fs_info->delalloc_block_rsv;
|
||||||
|
ret = btrfs_reserve_extent(trans, root,
|
||||||
async_extent->compressed_size,
|
async_extent->compressed_size,
|
||||||
async_extent->compressed_size,
|
async_extent->compressed_size,
|
||||||
0, alloc_hint,
|
0, alloc_hint,
|
||||||
(u64)-1, &ins, 1);
|
(u64)-1, &ins, 1);
|
||||||
btrfs_end_transaction(trans, root);
|
if (ret)
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
btrfs_end_transaction(trans, root);
|
||||||
|
}
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
int i;
|
int i;
|
||||||
|
@ -649,7 +677,9 @@ retry:
|
||||||
unlock_extent(io_tree, async_extent->start,
|
unlock_extent(io_tree, async_extent->start,
|
||||||
async_extent->start +
|
async_extent->start +
|
||||||
async_extent->ram_size - 1);
|
async_extent->ram_size - 1);
|
||||||
goto retry;
|
if (ret == -ENOSPC)
|
||||||
|
goto retry;
|
||||||
|
goto out_free; /* JDM: Requeue? */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -661,7 +691,7 @@ retry:
|
||||||
async_extent->ram_size - 1, 0);
|
async_extent->ram_size - 1, 0);
|
||||||
|
|
||||||
em = alloc_extent_map();
|
em = alloc_extent_map();
|
||||||
BUG_ON(!em);
|
BUG_ON(!em); /* -ENOMEM */
|
||||||
em->start = async_extent->start;
|
em->start = async_extent->start;
|
||||||
em->len = async_extent->ram_size;
|
em->len = async_extent->ram_size;
|
||||||
em->orig_start = em->start;
|
em->orig_start = em->start;
|
||||||
|
@ -693,7 +723,7 @@ retry:
|
||||||
ins.offset,
|
ins.offset,
|
||||||
BTRFS_ORDERED_COMPRESSED,
|
BTRFS_ORDERED_COMPRESSED,
|
||||||
async_extent->compress_type);
|
async_extent->compress_type);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* clear dirty, set writeback and unlock the pages.
|
* clear dirty, set writeback and unlock the pages.
|
||||||
|
@ -715,13 +745,17 @@ retry:
|
||||||
ins.offset, async_extent->pages,
|
ins.offset, async_extent->pages,
|
||||||
async_extent->nr_pages);
|
async_extent->nr_pages);
|
||||||
|
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
alloc_hint = ins.objectid + ins.offset;
|
alloc_hint = ins.objectid + ins.offset;
|
||||||
kfree(async_extent);
|
kfree(async_extent);
|
||||||
cond_resched();
|
cond_resched();
|
||||||
}
|
}
|
||||||
|
ret = 0;
|
||||||
return 0;
|
out:
|
||||||
|
return ret;
|
||||||
|
out_free:
|
||||||
|
kfree(async_extent);
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u64 get_extent_allocation_hint(struct inode *inode, u64 start,
|
static u64 get_extent_allocation_hint(struct inode *inode, u64 start,
|
||||||
|
@ -790,7 +824,18 @@ static noinline int cow_file_range(struct inode *inode,
|
||||||
|
|
||||||
BUG_ON(btrfs_is_free_space_inode(root, inode));
|
BUG_ON(btrfs_is_free_space_inode(root, inode));
|
||||||
trans = btrfs_join_transaction(root);
|
trans = btrfs_join_transaction(root);
|
||||||
BUG_ON(IS_ERR(trans));
|
if (IS_ERR(trans)) {
|
||||||
|
extent_clear_unlock_delalloc(inode,
|
||||||
|
&BTRFS_I(inode)->io_tree,
|
||||||
|
start, end, NULL,
|
||||||
|
EXTENT_CLEAR_UNLOCK_PAGE |
|
||||||
|
EXTENT_CLEAR_UNLOCK |
|
||||||
|
EXTENT_CLEAR_DELALLOC |
|
||||||
|
EXTENT_CLEAR_DIRTY |
|
||||||
|
EXTENT_SET_WRITEBACK |
|
||||||
|
EXTENT_END_WRITEBACK);
|
||||||
|
return PTR_ERR(trans);
|
||||||
|
}
|
||||||
trans->block_rsv = &root->fs_info->delalloc_block_rsv;
|
trans->block_rsv = &root->fs_info->delalloc_block_rsv;
|
||||||
|
|
||||||
num_bytes = (end - start + blocksize) & ~(blocksize - 1);
|
num_bytes = (end - start + blocksize) & ~(blocksize - 1);
|
||||||
|
@ -820,8 +865,10 @@ static noinline int cow_file_range(struct inode *inode,
|
||||||
*nr_written = *nr_written +
|
*nr_written = *nr_written +
|
||||||
(end - start + PAGE_CACHE_SIZE) / PAGE_CACHE_SIZE;
|
(end - start + PAGE_CACHE_SIZE) / PAGE_CACHE_SIZE;
|
||||||
*page_started = 1;
|
*page_started = 1;
|
||||||
ret = 0;
|
|
||||||
goto out;
|
goto out;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -838,10 +885,13 @@ static noinline int cow_file_range(struct inode *inode,
|
||||||
ret = btrfs_reserve_extent(trans, root, cur_alloc_size,
|
ret = btrfs_reserve_extent(trans, root, cur_alloc_size,
|
||||||
root->sectorsize, 0, alloc_hint,
|
root->sectorsize, 0, alloc_hint,
|
||||||
(u64)-1, &ins, 1);
|
(u64)-1, &ins, 1);
|
||||||
BUG_ON(ret);
|
if (ret < 0) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
em = alloc_extent_map();
|
em = alloc_extent_map();
|
||||||
BUG_ON(!em);
|
BUG_ON(!em); /* -ENOMEM */
|
||||||
em->start = start;
|
em->start = start;
|
||||||
em->orig_start = em->start;
|
em->orig_start = em->start;
|
||||||
ram_size = ins.offset;
|
ram_size = ins.offset;
|
||||||
|
@ -867,13 +917,16 @@ static noinline int cow_file_range(struct inode *inode,
|
||||||
cur_alloc_size = ins.offset;
|
cur_alloc_size = ins.offset;
|
||||||
ret = btrfs_add_ordered_extent(inode, start, ins.objectid,
|
ret = btrfs_add_ordered_extent(inode, start, ins.objectid,
|
||||||
ram_size, cur_alloc_size, 0);
|
ram_size, cur_alloc_size, 0);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
|
|
||||||
if (root->root_key.objectid ==
|
if (root->root_key.objectid ==
|
||||||
BTRFS_DATA_RELOC_TREE_OBJECTID) {
|
BTRFS_DATA_RELOC_TREE_OBJECTID) {
|
||||||
ret = btrfs_reloc_clone_csums(inode, start,
|
ret = btrfs_reloc_clone_csums(inode, start,
|
||||||
cur_alloc_size);
|
cur_alloc_size);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (disk_num_bytes < cur_alloc_size)
|
if (disk_num_bytes < cur_alloc_size)
|
||||||
|
@ -898,11 +951,23 @@ static noinline int cow_file_range(struct inode *inode,
|
||||||
alloc_hint = ins.objectid + ins.offset;
|
alloc_hint = ins.objectid + ins.offset;
|
||||||
start += cur_alloc_size;
|
start += cur_alloc_size;
|
||||||
}
|
}
|
||||||
out:
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
out:
|
||||||
btrfs_end_transaction(trans, root);
|
btrfs_end_transaction(trans, root);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
out_unlock:
|
||||||
|
extent_clear_unlock_delalloc(inode,
|
||||||
|
&BTRFS_I(inode)->io_tree,
|
||||||
|
start, end, NULL,
|
||||||
|
EXTENT_CLEAR_UNLOCK_PAGE |
|
||||||
|
EXTENT_CLEAR_UNLOCK |
|
||||||
|
EXTENT_CLEAR_DELALLOC |
|
||||||
|
EXTENT_CLEAR_DIRTY |
|
||||||
|
EXTENT_SET_WRITEBACK |
|
||||||
|
EXTENT_END_WRITEBACK);
|
||||||
|
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -968,7 +1033,7 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page,
|
||||||
1, 0, NULL, GFP_NOFS);
|
1, 0, NULL, GFP_NOFS);
|
||||||
while (start < end) {
|
while (start < end) {
|
||||||
async_cow = kmalloc(sizeof(*async_cow), GFP_NOFS);
|
async_cow = kmalloc(sizeof(*async_cow), GFP_NOFS);
|
||||||
BUG_ON(!async_cow);
|
BUG_ON(!async_cow); /* -ENOMEM */
|
||||||
async_cow->inode = inode;
|
async_cow->inode = inode;
|
||||||
async_cow->root = root;
|
async_cow->root = root;
|
||||||
async_cow->locked_page = locked_page;
|
async_cow->locked_page = locked_page;
|
||||||
|
@ -1059,7 +1124,7 @@ static noinline int run_delalloc_nocow(struct inode *inode,
|
||||||
u64 disk_bytenr;
|
u64 disk_bytenr;
|
||||||
u64 num_bytes;
|
u64 num_bytes;
|
||||||
int extent_type;
|
int extent_type;
|
||||||
int ret;
|
int ret, err;
|
||||||
int type;
|
int type;
|
||||||
int nocow;
|
int nocow;
|
||||||
int check_prev = 1;
|
int check_prev = 1;
|
||||||
|
@ -1077,7 +1142,11 @@ static noinline int run_delalloc_nocow(struct inode *inode,
|
||||||
else
|
else
|
||||||
trans = btrfs_join_transaction(root);
|
trans = btrfs_join_transaction(root);
|
||||||
|
|
||||||
BUG_ON(IS_ERR(trans));
|
if (IS_ERR(trans)) {
|
||||||
|
btrfs_free_path(path);
|
||||||
|
return PTR_ERR(trans);
|
||||||
|
}
|
||||||
|
|
||||||
trans->block_rsv = &root->fs_info->delalloc_block_rsv;
|
trans->block_rsv = &root->fs_info->delalloc_block_rsv;
|
||||||
|
|
||||||
cow_start = (u64)-1;
|
cow_start = (u64)-1;
|
||||||
|
@ -1085,7 +1154,10 @@ static noinline int run_delalloc_nocow(struct inode *inode,
|
||||||
while (1) {
|
while (1) {
|
||||||
ret = btrfs_lookup_file_extent(trans, root, path, ino,
|
ret = btrfs_lookup_file_extent(trans, root, path, ino,
|
||||||
cur_offset, 0);
|
cur_offset, 0);
|
||||||
BUG_ON(ret < 0);
|
if (ret < 0) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
if (ret > 0 && path->slots[0] > 0 && check_prev) {
|
if (ret > 0 && path->slots[0] > 0 && check_prev) {
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
btrfs_item_key_to_cpu(leaf, &found_key,
|
btrfs_item_key_to_cpu(leaf, &found_key,
|
||||||
|
@ -1099,8 +1171,10 @@ next_slot:
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
|
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
|
||||||
ret = btrfs_next_leaf(root, path);
|
ret = btrfs_next_leaf(root, path);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
BUG_ON(1);
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
break;
|
break;
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
|
@ -1188,7 +1262,10 @@ out_check:
|
||||||
ret = cow_file_range(inode, locked_page, cow_start,
|
ret = cow_file_range(inode, locked_page, cow_start,
|
||||||
found_key.offset - 1, page_started,
|
found_key.offset - 1, page_started,
|
||||||
nr_written, 1);
|
nr_written, 1);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
cow_start = (u64)-1;
|
cow_start = (u64)-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1197,7 +1274,7 @@ out_check:
|
||||||
struct extent_map_tree *em_tree;
|
struct extent_map_tree *em_tree;
|
||||||
em_tree = &BTRFS_I(inode)->extent_tree;
|
em_tree = &BTRFS_I(inode)->extent_tree;
|
||||||
em = alloc_extent_map();
|
em = alloc_extent_map();
|
||||||
BUG_ON(!em);
|
BUG_ON(!em); /* -ENOMEM */
|
||||||
em->start = cur_offset;
|
em->start = cur_offset;
|
||||||
em->orig_start = em->start;
|
em->orig_start = em->start;
|
||||||
em->len = num_bytes;
|
em->len = num_bytes;
|
||||||
|
@ -1223,13 +1300,16 @@ out_check:
|
||||||
|
|
||||||
ret = btrfs_add_ordered_extent(inode, cur_offset, disk_bytenr,
|
ret = btrfs_add_ordered_extent(inode, cur_offset, disk_bytenr,
|
||||||
num_bytes, num_bytes, type);
|
num_bytes, num_bytes, type);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
|
|
||||||
if (root->root_key.objectid ==
|
if (root->root_key.objectid ==
|
||||||
BTRFS_DATA_RELOC_TREE_OBJECTID) {
|
BTRFS_DATA_RELOC_TREE_OBJECTID) {
|
||||||
ret = btrfs_reloc_clone_csums(inode, cur_offset,
|
ret = btrfs_reloc_clone_csums(inode, cur_offset,
|
||||||
num_bytes);
|
num_bytes);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree,
|
extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree,
|
||||||
|
@ -1248,18 +1328,23 @@ out_check:
|
||||||
if (cow_start != (u64)-1) {
|
if (cow_start != (u64)-1) {
|
||||||
ret = cow_file_range(inode, locked_page, cow_start, end,
|
ret = cow_file_range(inode, locked_page, cow_start, end,
|
||||||
page_started, nr_written, 1);
|
page_started, nr_written, 1);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error:
|
||||||
if (nolock) {
|
if (nolock) {
|
||||||
ret = btrfs_end_transaction_nolock(trans, root);
|
err = btrfs_end_transaction_nolock(trans, root);
|
||||||
BUG_ON(ret);
|
|
||||||
} else {
|
} else {
|
||||||
ret = btrfs_end_transaction(trans, root);
|
err = btrfs_end_transaction(trans, root);
|
||||||
BUG_ON(ret);
|
|
||||||
}
|
}
|
||||||
|
if (!ret)
|
||||||
|
ret = err;
|
||||||
|
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1448,7 +1533,7 @@ static int __btrfs_submit_bio_start(struct inode *inode, int rw,
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
ret = btrfs_csum_one_bio(root, inode, bio, 0, 0);
|
ret = btrfs_csum_one_bio(root, inode, bio, 0, 0);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1677,13 +1762,15 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
|
||||||
*/
|
*/
|
||||||
ret = btrfs_drop_extents(trans, inode, file_pos, file_pos + num_bytes,
|
ret = btrfs_drop_extents(trans, inode, file_pos, file_pos + num_bytes,
|
||||||
&hint, 0);
|
&hint, 0);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
ins.objectid = btrfs_ino(inode);
|
ins.objectid = btrfs_ino(inode);
|
||||||
ins.offset = file_pos;
|
ins.offset = file_pos;
|
||||||
ins.type = BTRFS_EXTENT_DATA_KEY;
|
ins.type = BTRFS_EXTENT_DATA_KEY;
|
||||||
ret = btrfs_insert_empty_item(trans, root, path, &ins, sizeof(*fi));
|
ret = btrfs_insert_empty_item(trans, root, path, &ins, sizeof(*fi));
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
goto out;
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
fi = btrfs_item_ptr(leaf, path->slots[0],
|
fi = btrfs_item_ptr(leaf, path->slots[0],
|
||||||
struct btrfs_file_extent_item);
|
struct btrfs_file_extent_item);
|
||||||
|
@ -1711,10 +1798,10 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
|
||||||
ret = btrfs_alloc_reserved_file_extent(trans, root,
|
ret = btrfs_alloc_reserved_file_extent(trans, root,
|
||||||
root->root_key.objectid,
|
root->root_key.objectid,
|
||||||
btrfs_ino(inode), file_pos, &ins);
|
btrfs_ino(inode), file_pos, &ins);
|
||||||
BUG_ON(ret);
|
out:
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1742,22 +1829,24 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
|
||||||
end - start + 1);
|
end - start + 1);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
return 0;
|
return 0;
|
||||||
BUG_ON(!ordered_extent);
|
BUG_ON(!ordered_extent); /* Logic error */
|
||||||
|
|
||||||
nolock = btrfs_is_free_space_inode(root, inode);
|
nolock = btrfs_is_free_space_inode(root, inode);
|
||||||
|
|
||||||
if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) {
|
if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) {
|
||||||
BUG_ON(!list_empty(&ordered_extent->list));
|
BUG_ON(!list_empty(&ordered_extent->list)); /* Logic error */
|
||||||
ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
|
ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
if (nolock)
|
if (nolock)
|
||||||
trans = btrfs_join_transaction_nolock(root);
|
trans = btrfs_join_transaction_nolock(root);
|
||||||
else
|
else
|
||||||
trans = btrfs_join_transaction(root);
|
trans = btrfs_join_transaction(root);
|
||||||
BUG_ON(IS_ERR(trans));
|
if (IS_ERR(trans))
|
||||||
|
return PTR_ERR(trans);
|
||||||
trans->block_rsv = &root->fs_info->delalloc_block_rsv;
|
trans->block_rsv = &root->fs_info->delalloc_block_rsv;
|
||||||
ret = btrfs_update_inode_fallback(trans, root, inode);
|
ret = btrfs_update_inode_fallback(trans, root, inode);
|
||||||
BUG_ON(ret);
|
if (ret) /* -ENOMEM or corruption */
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
}
|
}
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -1770,7 +1859,11 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
|
||||||
trans = btrfs_join_transaction_nolock(root);
|
trans = btrfs_join_transaction_nolock(root);
|
||||||
else
|
else
|
||||||
trans = btrfs_join_transaction(root);
|
trans = btrfs_join_transaction(root);
|
||||||
BUG_ON(IS_ERR(trans));
|
if (IS_ERR(trans)) {
|
||||||
|
ret = PTR_ERR(trans);
|
||||||
|
trans = NULL;
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
trans->block_rsv = &root->fs_info->delalloc_block_rsv;
|
trans->block_rsv = &root->fs_info->delalloc_block_rsv;
|
||||||
|
|
||||||
if (test_bit(BTRFS_ORDERED_COMPRESSED, &ordered_extent->flags))
|
if (test_bit(BTRFS_ORDERED_COMPRESSED, &ordered_extent->flags))
|
||||||
|
@ -1781,7 +1874,6 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
|
||||||
ordered_extent->file_offset,
|
ordered_extent->file_offset,
|
||||||
ordered_extent->file_offset +
|
ordered_extent->file_offset +
|
||||||
ordered_extent->len);
|
ordered_extent->len);
|
||||||
BUG_ON(ret);
|
|
||||||
} else {
|
} else {
|
||||||
BUG_ON(root == root->fs_info->tree_root);
|
BUG_ON(root == root->fs_info->tree_root);
|
||||||
ret = insert_reserved_file_extent(trans, inode,
|
ret = insert_reserved_file_extent(trans, inode,
|
||||||
|
@ -1795,11 +1887,14 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
|
||||||
unpin_extent_cache(&BTRFS_I(inode)->extent_tree,
|
unpin_extent_cache(&BTRFS_I(inode)->extent_tree,
|
||||||
ordered_extent->file_offset,
|
ordered_extent->file_offset,
|
||||||
ordered_extent->len);
|
ordered_extent->len);
|
||||||
BUG_ON(ret);
|
|
||||||
}
|
}
|
||||||
unlock_extent_cached(io_tree, ordered_extent->file_offset,
|
unlock_extent_cached(io_tree, ordered_extent->file_offset,
|
||||||
ordered_extent->file_offset +
|
ordered_extent->file_offset +
|
||||||
ordered_extent->len - 1, &cached_state, GFP_NOFS);
|
ordered_extent->len - 1, &cached_state, GFP_NOFS);
|
||||||
|
if (ret < 0) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
add_pending_csums(trans, inode, ordered_extent->file_offset,
|
add_pending_csums(trans, inode, ordered_extent->file_offset,
|
||||||
&ordered_extent->list);
|
&ordered_extent->list);
|
||||||
|
@ -1807,7 +1902,10 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
|
||||||
ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
|
ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
|
||||||
if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) {
|
if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) {
|
||||||
ret = btrfs_update_inode_fallback(trans, root, inode);
|
ret = btrfs_update_inode_fallback(trans, root, inode);
|
||||||
BUG_ON(ret);
|
if (ret) { /* -ENOMEM or corruption */
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ret = 0;
|
ret = 0;
|
||||||
out:
|
out:
|
||||||
|
@ -1826,6 +1924,11 @@ out:
|
||||||
btrfs_put_ordered_extent(ordered_extent);
|
btrfs_put_ordered_extent(ordered_extent);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
out_unlock:
|
||||||
|
unlock_extent_cached(io_tree, ordered_extent->file_offset,
|
||||||
|
ordered_extent->file_offset +
|
||||||
|
ordered_extent->len - 1, &cached_state, GFP_NOFS);
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end,
|
static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end,
|
||||||
|
@ -1907,6 +2010,8 @@ struct delayed_iput {
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* JDM: If this is fs-wide, why can't we add a pointer to
|
||||||
|
* btrfs_inode instead and avoid the allocation? */
|
||||||
void btrfs_add_delayed_iput(struct inode *inode)
|
void btrfs_add_delayed_iput(struct inode *inode)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info;
|
struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info;
|
||||||
|
@ -2053,20 +2158,27 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode)
|
||||||
/* grab metadata reservation from transaction handle */
|
/* grab metadata reservation from transaction handle */
|
||||||
if (reserve) {
|
if (reserve) {
|
||||||
ret = btrfs_orphan_reserve_metadata(trans, inode);
|
ret = btrfs_orphan_reserve_metadata(trans, inode);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOSPC in reservation; Logic error? JDM */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* insert an orphan item to track this unlinked/truncated file */
|
/* insert an orphan item to track this unlinked/truncated file */
|
||||||
if (insert >= 1) {
|
if (insert >= 1) {
|
||||||
ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode));
|
ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode));
|
||||||
BUG_ON(ret && ret != -EEXIST);
|
if (ret && ret != -EEXIST) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* insert an orphan item to track subvolume contains orphan files */
|
/* insert an orphan item to track subvolume contains orphan files */
|
||||||
if (insert >= 2) {
|
if (insert >= 2) {
|
||||||
ret = btrfs_insert_orphan_item(trans, root->fs_info->tree_root,
|
ret = btrfs_insert_orphan_item(trans, root->fs_info->tree_root,
|
||||||
root->root_key.objectid);
|
root->root_key.objectid);
|
||||||
BUG_ON(ret);
|
if (ret && ret != -EEXIST) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2096,7 +2208,7 @@ int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode)
|
||||||
|
|
||||||
if (trans && delete_item) {
|
if (trans && delete_item) {
|
||||||
ret = btrfs_del_orphan_item(trans, root, btrfs_ino(inode));
|
ret = btrfs_del_orphan_item(trans, root, btrfs_ino(inode));
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM or corruption (JDM: Recheck) */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (release_rsv)
|
if (release_rsv)
|
||||||
|
@ -2230,7 +2342,7 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
|
||||||
}
|
}
|
||||||
ret = btrfs_del_orphan_item(trans, root,
|
ret = btrfs_del_orphan_item(trans, root,
|
||||||
found_key.objectid);
|
found_key.objectid);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM or corruption (JDM: Recheck) */
|
||||||
btrfs_end_transaction(trans, root);
|
btrfs_end_transaction(trans, root);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -2612,16 +2724,22 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans,
|
||||||
printk(KERN_INFO "btrfs failed to delete reference to %.*s, "
|
printk(KERN_INFO "btrfs failed to delete reference to %.*s, "
|
||||||
"inode %llu parent %llu\n", name_len, name,
|
"inode %llu parent %llu\n", name_len, name,
|
||||||
(unsigned long long)ino, (unsigned long long)dir_ino);
|
(unsigned long long)ino, (unsigned long long)dir_ino);
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = btrfs_delete_delayed_dir_index(trans, root, dir, index);
|
ret = btrfs_delete_delayed_dir_index(trans, root, dir, index);
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
goto err;
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
ret = btrfs_del_inode_ref_in_log(trans, root, name, name_len,
|
ret = btrfs_del_inode_ref_in_log(trans, root, name, name_len,
|
||||||
inode, dir_ino);
|
inode, dir_ino);
|
||||||
BUG_ON(ret != 0 && ret != -ENOENT);
|
if (ret != 0 && ret != -ENOENT) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
ret = btrfs_del_dir_entries_in_log(trans, root, name, name_len,
|
ret = btrfs_del_dir_entries_in_log(trans, root, name, name_len,
|
||||||
dir, index);
|
dir, index);
|
||||||
|
@ -2779,7 +2897,7 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir,
|
||||||
err = ret;
|
err = ret;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
BUG_ON(ret == 0);
|
BUG_ON(ret == 0); /* Corruption */
|
||||||
if (check_path_shared(root, path))
|
if (check_path_shared(root, path))
|
||||||
goto out;
|
goto out;
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
|
@ -2812,7 +2930,7 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir,
|
||||||
err = PTR_ERR(ref);
|
err = PTR_ERR(ref);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
BUG_ON(!ref);
|
BUG_ON(!ref); /* Logic error */
|
||||||
if (check_path_shared(root, path))
|
if (check_path_shared(root, path))
|
||||||
goto out;
|
goto out;
|
||||||
index = btrfs_inode_ref_index(path->nodes[0], ref);
|
index = btrfs_inode_ref_index(path->nodes[0], ref);
|
||||||
|
@ -2919,23 +3037,42 @@ int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
di = btrfs_lookup_dir_item(trans, root, path, dir_ino,
|
di = btrfs_lookup_dir_item(trans, root, path, dir_ino,
|
||||||
name, name_len, -1);
|
name, name_len, -1);
|
||||||
BUG_ON(IS_ERR_OR_NULL(di));
|
if (IS_ERR_OR_NULL(di)) {
|
||||||
|
if (!di)
|
||||||
|
ret = -ENOENT;
|
||||||
|
else
|
||||||
|
ret = PTR_ERR(di);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
btrfs_dir_item_key_to_cpu(leaf, di, &key);
|
btrfs_dir_item_key_to_cpu(leaf, di, &key);
|
||||||
WARN_ON(key.type != BTRFS_ROOT_ITEM_KEY || key.objectid != objectid);
|
WARN_ON(key.type != BTRFS_ROOT_ITEM_KEY || key.objectid != objectid);
|
||||||
ret = btrfs_delete_one_dir_name(trans, root, path, di);
|
ret = btrfs_delete_one_dir_name(trans, root, path, di);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
|
|
||||||
ret = btrfs_del_root_ref(trans, root->fs_info->tree_root,
|
ret = btrfs_del_root_ref(trans, root->fs_info->tree_root,
|
||||||
objectid, root->root_key.objectid,
|
objectid, root->root_key.objectid,
|
||||||
dir_ino, &index, name, name_len);
|
dir_ino, &index, name, name_len);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
BUG_ON(ret != -ENOENT);
|
if (ret != -ENOENT) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
di = btrfs_search_dir_index_item(root, path, dir_ino,
|
di = btrfs_search_dir_index_item(root, path, dir_ino,
|
||||||
name, name_len);
|
name, name_len);
|
||||||
BUG_ON(IS_ERR_OR_NULL(di));
|
if (IS_ERR_OR_NULL(di)) {
|
||||||
|
if (!di)
|
||||||
|
ret = -ENOENT;
|
||||||
|
else
|
||||||
|
ret = PTR_ERR(di);
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
|
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
|
||||||
|
@ -2945,15 +3082,19 @@ int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
|
|
||||||
ret = btrfs_delete_delayed_dir_index(trans, root, dir, index);
|
ret = btrfs_delete_delayed_dir_index(trans, root, dir, index);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
btrfs_i_size_write(dir, dir->i_size - name_len * 2);
|
btrfs_i_size_write(dir, dir->i_size - name_len * 2);
|
||||||
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
|
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
|
||||||
ret = btrfs_update_inode(trans, root, dir);
|
ret = btrfs_update_inode(trans, root, dir);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
out:
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
|
static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||||
|
@ -3212,7 +3353,11 @@ delete:
|
||||||
ret = btrfs_del_items(trans, root, path,
|
ret = btrfs_del_items(trans, root, path,
|
||||||
pending_del_slot,
|
pending_del_slot,
|
||||||
pending_del_nr);
|
pending_del_nr);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans,
|
||||||
|
root, ret);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
pending_del_nr = 0;
|
pending_del_nr = 0;
|
||||||
}
|
}
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
|
@ -3225,8 +3370,10 @@ out:
|
||||||
if (pending_del_nr) {
|
if (pending_del_nr) {
|
||||||
ret = btrfs_del_items(trans, root, path, pending_del_slot,
|
ret = btrfs_del_items(trans, root, path, pending_del_slot,
|
||||||
pending_del_nr);
|
pending_del_nr);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
}
|
}
|
||||||
|
error:
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -3373,7 +3520,10 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
|
||||||
while (1) {
|
while (1) {
|
||||||
em = btrfs_get_extent(inode, NULL, 0, cur_offset,
|
em = btrfs_get_extent(inode, NULL, 0, cur_offset,
|
||||||
block_end - cur_offset, 0);
|
block_end - cur_offset, 0);
|
||||||
BUG_ON(IS_ERR_OR_NULL(em));
|
if (IS_ERR(em)) {
|
||||||
|
err = PTR_ERR(em);
|
||||||
|
break;
|
||||||
|
}
|
||||||
last_byte = min(extent_map_end(em), block_end);
|
last_byte = min(extent_map_end(em), block_end);
|
||||||
last_byte = (last_byte + mask) & ~mask;
|
last_byte = (last_byte + mask) & ~mask;
|
||||||
if (!test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) {
|
if (!test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) {
|
||||||
|
@ -3390,7 +3540,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
|
||||||
cur_offset + hole_size,
|
cur_offset + hole_size,
|
||||||
&hint_byte, 1);
|
&hint_byte, 1);
|
||||||
if (err) {
|
if (err) {
|
||||||
btrfs_update_inode(trans, root, inode);
|
btrfs_abort_transaction(trans, root, err);
|
||||||
btrfs_end_transaction(trans, root);
|
btrfs_end_transaction(trans, root);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3400,7 +3550,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
|
||||||
0, hole_size, 0, hole_size,
|
0, hole_size, 0, hole_size,
|
||||||
0, 0, 0);
|
0, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
btrfs_update_inode(trans, root, inode);
|
btrfs_abort_transaction(trans, root, err);
|
||||||
btrfs_end_transaction(trans, root);
|
btrfs_end_transaction(trans, root);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4581,18 +4731,26 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
|
||||||
parent_ino, index);
|
parent_ino, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == 0) {
|
/* Nothing to clean up yet */
|
||||||
ret = btrfs_insert_dir_item(trans, root, name, name_len,
|
if (ret)
|
||||||
parent_inode, &key,
|
return ret;
|
||||||
btrfs_inode_type(inode), index);
|
|
||||||
if (ret)
|
|
||||||
goto fail_dir_item;
|
|
||||||
|
|
||||||
btrfs_i_size_write(parent_inode, parent_inode->i_size +
|
ret = btrfs_insert_dir_item(trans, root, name, name_len,
|
||||||
name_len * 2);
|
parent_inode, &key,
|
||||||
parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME;
|
btrfs_inode_type(inode), index);
|
||||||
ret = btrfs_update_inode(trans, root, parent_inode);
|
if (ret == -EEXIST)
|
||||||
|
goto fail_dir_item;
|
||||||
|
else if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
btrfs_i_size_write(parent_inode, parent_inode->i_size +
|
||||||
|
name_len * 2);
|
||||||
|
parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME;
|
||||||
|
ret = btrfs_update_inode(trans, root, parent_inode);
|
||||||
|
if (ret)
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
fail_dir_item:
|
fail_dir_item:
|
||||||
|
@ -4806,7 +4964,8 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
|
||||||
} else {
|
} else {
|
||||||
struct dentry *parent = dentry->d_parent;
|
struct dentry *parent = dentry->d_parent;
|
||||||
err = btrfs_update_inode(trans, root, inode);
|
err = btrfs_update_inode(trans, root, inode);
|
||||||
BUG_ON(err);
|
if (err)
|
||||||
|
goto fail;
|
||||||
d_instantiate(dentry, inode);
|
d_instantiate(dentry, inode);
|
||||||
btrfs_log_new_name(trans, inode, NULL, parent);
|
btrfs_log_new_name(trans, inode, NULL, parent);
|
||||||
}
|
}
|
||||||
|
@ -5137,7 +5296,7 @@ again:
|
||||||
ret = uncompress_inline(path, inode, page,
|
ret = uncompress_inline(path, inode, page,
|
||||||
pg_offset,
|
pg_offset,
|
||||||
extent_offset, item);
|
extent_offset, item);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
} else {
|
} else {
|
||||||
map = kmap(page);
|
map = kmap(page);
|
||||||
read_extent_buffer(leaf, map + pg_offset, ptr,
|
read_extent_buffer(leaf, map + pg_offset, ptr,
|
||||||
|
@ -5252,6 +5411,7 @@ out:
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
BUG_ON(!em); /* Error is always set */
|
||||||
return em;
|
return em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5868,7 +6028,7 @@ static int __btrfs_submit_bio_start_direct_io(struct inode *inode, int rw,
|
||||||
int ret;
|
int ret;
|
||||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
ret = btrfs_csum_one_bio(root, inode, bio, offset, 1);
|
ret = btrfs_csum_one_bio(root, inode, bio, offset, 1);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7068,7 +7228,10 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = btrfs_update_inode(trans, root, old_inode);
|
ret = btrfs_update_inode(trans, root, old_inode);
|
||||||
}
|
}
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto out_fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (new_inode) {
|
if (new_inode) {
|
||||||
new_inode->i_ctime = CURRENT_TIME;
|
new_inode->i_ctime = CURRENT_TIME;
|
||||||
|
@ -7086,11 +7249,14 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||||
new_dentry->d_name.name,
|
new_dentry->d_name.name,
|
||||||
new_dentry->d_name.len);
|
new_dentry->d_name.len);
|
||||||
}
|
}
|
||||||
BUG_ON(ret);
|
if (!ret && new_inode->i_nlink == 0) {
|
||||||
if (new_inode->i_nlink == 0) {
|
|
||||||
ret = btrfs_orphan_add(trans, new_dentry->d_inode);
|
ret = btrfs_orphan_add(trans, new_dentry->d_inode);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
}
|
}
|
||||||
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto out_fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fixup_inode_flags(new_dir, old_inode);
|
fixup_inode_flags(new_dir, old_inode);
|
||||||
|
@ -7098,7 +7264,10 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||||
ret = btrfs_add_link(trans, new_dir, old_inode,
|
ret = btrfs_add_link(trans, new_dir, old_inode,
|
||||||
new_dentry->d_name.name,
|
new_dentry->d_name.name,
|
||||||
new_dentry->d_name.len, 0, index);
|
new_dentry->d_name.len, 0, index);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto out_fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (old_ino != BTRFS_FIRST_FREE_OBJECTID) {
|
if (old_ino != BTRFS_FIRST_FREE_OBJECTID) {
|
||||||
struct dentry *parent = new_dentry->d_parent;
|
struct dentry *parent = new_dentry->d_parent;
|
||||||
|
@ -7323,7 +7492,12 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
|
||||||
ins.offset, ins.offset,
|
ins.offset, ins.offset,
|
||||||
ins.offset, 0, 0, 0,
|
ins.offset, 0, 0, 0,
|
||||||
BTRFS_FILE_EXTENT_PREALLOC);
|
BTRFS_FILE_EXTENT_PREALLOC);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
if (own_trans)
|
||||||
|
btrfs_end_transaction(trans, root);
|
||||||
|
break;
|
||||||
|
}
|
||||||
btrfs_drop_extent_cache(inode, cur_offset,
|
btrfs_drop_extent_cache(inode, cur_offset,
|
||||||
cur_offset + ins.offset -1, 0);
|
cur_offset + ins.offset -1, 0);
|
||||||
|
|
||||||
|
@ -7345,7 +7519,13 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = btrfs_update_inode(trans, root, inode);
|
ret = btrfs_update_inode(trans, root, inode);
|
||||||
BUG_ON(ret);
|
|
||||||
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
if (own_trans)
|
||||||
|
btrfs_end_transaction(trans, root);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (own_trans)
|
if (own_trans)
|
||||||
btrfs_end_transaction(trans, root);
|
btrfs_end_transaction(trans, root);
|
||||||
|
|
|
@ -425,13 +425,18 @@ static noinline int create_subvol(struct btrfs_root *root,
|
||||||
|
|
||||||
key.offset = (u64)-1;
|
key.offset = (u64)-1;
|
||||||
new_root = btrfs_read_fs_root_no_name(root->fs_info, &key);
|
new_root = btrfs_read_fs_root_no_name(root->fs_info, &key);
|
||||||
BUG_ON(IS_ERR(new_root));
|
if (IS_ERR(new_root)) {
|
||||||
|
btrfs_abort_transaction(trans, root, PTR_ERR(new_root));
|
||||||
|
ret = PTR_ERR(new_root);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
btrfs_record_root_in_trans(trans, new_root);
|
btrfs_record_root_in_trans(trans, new_root);
|
||||||
|
|
||||||
ret = btrfs_create_subvol_root(trans, new_root, new_dirid);
|
ret = btrfs_create_subvol_root(trans, new_root, new_dirid);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
/* We potentially lose an unused inode item here */
|
/* We potentially lose an unused inode item here */
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,13 +444,18 @@ static noinline int create_subvol(struct btrfs_root *root,
|
||||||
* insert the directory item
|
* insert the directory item
|
||||||
*/
|
*/
|
||||||
ret = btrfs_set_inode_index(dir, &index);
|
ret = btrfs_set_inode_index(dir, &index);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
ret = btrfs_insert_dir_item(trans, root,
|
ret = btrfs_insert_dir_item(trans, root,
|
||||||
name, namelen, dir, &key,
|
name, namelen, dir, &key,
|
||||||
BTRFS_FT_DIR, index);
|
BTRFS_FT_DIR, index);
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
btrfs_i_size_write(dir, dir->i_size + namelen * 2);
|
btrfs_i_size_write(dir, dir->i_size + namelen * 2);
|
||||||
ret = btrfs_update_inode(trans, root, dir);
|
ret = btrfs_update_inode(trans, root, dir);
|
||||||
|
@ -1970,7 +1980,11 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
|
||||||
dest->root_key.objectid,
|
dest->root_key.objectid,
|
||||||
dentry->d_name.name,
|
dentry->d_name.name,
|
||||||
dentry->d_name.len);
|
dentry->d_name.len);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
err = ret;
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
goto out_end_trans;
|
||||||
|
}
|
||||||
|
|
||||||
btrfs_record_root_in_trans(trans, dest);
|
btrfs_record_root_in_trans(trans, dest);
|
||||||
|
|
||||||
|
@ -1983,11 +1997,16 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
|
||||||
ret = btrfs_insert_orphan_item(trans,
|
ret = btrfs_insert_orphan_item(trans,
|
||||||
root->fs_info->tree_root,
|
root->fs_info->tree_root,
|
||||||
dest->root_key.objectid);
|
dest->root_key.objectid);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
err = ret;
|
||||||
|
goto out_end_trans;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
out_end_trans:
|
||||||
ret = btrfs_end_transaction(trans, root);
|
ret = btrfs_end_transaction(trans, root);
|
||||||
BUG_ON(ret);
|
if (ret && !err)
|
||||||
|
err = ret;
|
||||||
inode->i_flags |= S_DEAD;
|
inode->i_flags |= S_DEAD;
|
||||||
out_up_write:
|
out_up_write:
|
||||||
up_write(&root->fs_info->subvol_sem);
|
up_write(&root->fs_info->subvol_sem);
|
||||||
|
@ -2451,11 +2470,21 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
|
||||||
new_key.offset,
|
new_key.offset,
|
||||||
new_key.offset + datal,
|
new_key.offset + datal,
|
||||||
&hint_byte, 1);
|
&hint_byte, 1);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root,
|
||||||
|
ret);
|
||||||
|
btrfs_end_transaction(trans, root);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ret = btrfs_insert_empty_item(trans, root, path,
|
ret = btrfs_insert_empty_item(trans, root, path,
|
||||||
&new_key, size);
|
&new_key, size);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root,
|
||||||
|
ret);
|
||||||
|
btrfs_end_transaction(trans, root);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
slot = path->slots[0];
|
slot = path->slots[0];
|
||||||
|
@ -2482,7 +2511,15 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
|
||||||
btrfs_ino(inode),
|
btrfs_ino(inode),
|
||||||
new_key.offset - datao,
|
new_key.offset - datao,
|
||||||
0);
|
0);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans,
|
||||||
|
root,
|
||||||
|
ret);
|
||||||
|
btrfs_end_transaction(trans,
|
||||||
|
root);
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (type == BTRFS_FILE_EXTENT_INLINE) {
|
} else if (type == BTRFS_FILE_EXTENT_INLINE) {
|
||||||
u64 skip = 0;
|
u64 skip = 0;
|
||||||
|
@ -2507,11 +2544,21 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
|
||||||
new_key.offset,
|
new_key.offset,
|
||||||
new_key.offset + datal,
|
new_key.offset + datal,
|
||||||
&hint_byte, 1);
|
&hint_byte, 1);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root,
|
||||||
|
ret);
|
||||||
|
btrfs_end_transaction(trans, root);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ret = btrfs_insert_empty_item(trans, root, path,
|
ret = btrfs_insert_empty_item(trans, root, path,
|
||||||
&new_key, size);
|
&new_key, size);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root,
|
||||||
|
ret);
|
||||||
|
btrfs_end_transaction(trans, root);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (skip) {
|
if (skip) {
|
||||||
u32 start =
|
u32 start =
|
||||||
|
@ -2545,8 +2592,12 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
|
||||||
btrfs_i_size_write(inode, endoff);
|
btrfs_i_size_write(inode, endoff);
|
||||||
|
|
||||||
ret = btrfs_update_inode(trans, root, inode);
|
ret = btrfs_update_inode(trans, root, inode);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
btrfs_end_transaction(trans, root);
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
btrfs_end_transaction(trans, root);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ret = btrfs_end_transaction(trans, root);
|
||||||
}
|
}
|
||||||
next:
|
next:
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
|
|
|
@ -58,7 +58,7 @@ int btrfs_del_orphan_item(struct btrfs_trans_handle *trans,
|
||||||
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
|
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
if (ret) {
|
if (ret) { /* JDM: Really? */
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4102,10 +4102,11 @@ out:
|
||||||
static noinline_for_stack int mark_garbage_root(struct btrfs_root *root)
|
static noinline_for_stack int mark_garbage_root(struct btrfs_root *root)
|
||||||
{
|
{
|
||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans;
|
||||||
int ret;
|
int ret, err;
|
||||||
|
|
||||||
trans = btrfs_start_transaction(root->fs_info->tree_root, 0);
|
trans = btrfs_start_transaction(root->fs_info->tree_root, 0);
|
||||||
BUG_ON(IS_ERR(trans));
|
if (IS_ERR(trans))
|
||||||
|
return PTR_ERR(trans);
|
||||||
|
|
||||||
memset(&root->root_item.drop_progress, 0,
|
memset(&root->root_item.drop_progress, 0,
|
||||||
sizeof(root->root_item.drop_progress));
|
sizeof(root->root_item.drop_progress));
|
||||||
|
@ -4113,11 +4114,11 @@ static noinline_for_stack int mark_garbage_root(struct btrfs_root *root)
|
||||||
btrfs_set_root_refs(&root->root_item, 0);
|
btrfs_set_root_refs(&root->root_item, 0);
|
||||||
ret = btrfs_update_root(trans, root->fs_info->tree_root,
|
ret = btrfs_update_root(trans, root->fs_info->tree_root,
|
||||||
&root->root_key, &root->root_item);
|
&root->root_key, &root->root_item);
|
||||||
BUG_ON(ret);
|
|
||||||
|
|
||||||
ret = btrfs_end_transaction(trans, root->fs_info->tree_root);
|
err = btrfs_end_transaction(trans, root->fs_info->tree_root);
|
||||||
BUG_ON(ret);
|
if (err)
|
||||||
return 0;
|
return err;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -4185,7 +4186,11 @@ int btrfs_recover_relocation(struct btrfs_root *root)
|
||||||
err = ret;
|
err = ret;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
mark_garbage_root(reloc_root);
|
ret = mark_garbage_root(reloc_root);
|
||||||
|
if (ret < 0) {
|
||||||
|
err = ret;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4231,14 +4236,19 @@ int btrfs_recover_relocation(struct btrfs_root *root)
|
||||||
|
|
||||||
fs_root = read_fs_root(root->fs_info,
|
fs_root = read_fs_root(root->fs_info,
|
||||||
reloc_root->root_key.offset);
|
reloc_root->root_key.offset);
|
||||||
BUG_ON(IS_ERR(fs_root));
|
if (IS_ERR(fs_root)) {
|
||||||
|
err = PTR_ERR(fs_root);
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
err = __add_reloc_root(reloc_root);
|
err = __add_reloc_root(reloc_root);
|
||||||
BUG_ON(err < 0);
|
BUG_ON(err < 0); /* -ENOMEM or logic error */
|
||||||
fs_root->reloc_root = reloc_root;
|
fs_root->reloc_root = reloc_root;
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_commit_transaction(trans, rc->extent_root);
|
err = btrfs_commit_transaction(trans, rc->extent_root);
|
||||||
|
if (err)
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
merge_reloc_roots(rc);
|
merge_reloc_roots(rc);
|
||||||
|
|
||||||
|
@ -4248,7 +4258,7 @@ int btrfs_recover_relocation(struct btrfs_root *root)
|
||||||
if (IS_ERR(trans))
|
if (IS_ERR(trans))
|
||||||
err = PTR_ERR(trans);
|
err = PTR_ERR(trans);
|
||||||
else
|
else
|
||||||
btrfs_commit_transaction(trans, rc->extent_root);
|
err = btrfs_commit_transaction(trans, rc->extent_root);
|
||||||
out_free:
|
out_free:
|
||||||
kfree(rc);
|
kfree(rc);
|
||||||
out:
|
out:
|
||||||
|
@ -4297,6 +4307,8 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len)
|
||||||
disk_bytenr = file_pos + BTRFS_I(inode)->index_cnt;
|
disk_bytenr = file_pos + BTRFS_I(inode)->index_cnt;
|
||||||
ret = btrfs_lookup_csums_range(root->fs_info->csum_root, disk_bytenr,
|
ret = btrfs_lookup_csums_range(root->fs_info->csum_root, disk_bytenr,
|
||||||
disk_bytenr + len - 1, &list, 0);
|
disk_bytenr + len - 1, &list, 0);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
while (!list_empty(&list)) {
|
while (!list_empty(&list)) {
|
||||||
sums = list_entry(list.next, struct btrfs_ordered_sum, list);
|
sums = list_entry(list.next, struct btrfs_ordered_sum, list);
|
||||||
|
@ -4314,6 +4326,7 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len)
|
||||||
|
|
||||||
btrfs_add_ordered_sum(inode, ordered, sums);
|
btrfs_add_ordered_sum(inode, ordered, sums);
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
btrfs_put_ordered_extent(ordered);
|
btrfs_put_ordered_extent(ordered);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,8 +97,10 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ret = btrfs_search_slot(trans, root, key, path, 0, 1);
|
ret = btrfs_search_slot(trans, root, key, path, 0, 1);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
btrfs_print_leaf(root, path->nodes[0]);
|
btrfs_print_leaf(root, path->nodes[0]);
|
||||||
|
@ -383,6 +385,8 @@ int btrfs_find_root_ref(struct btrfs_root *tree_root,
|
||||||
*
|
*
|
||||||
* For a back ref the root_id is the id of the subvol or snapshot and
|
* For a back ref the root_id is the id of the subvol or snapshot and
|
||||||
* ref_id is the id of the tree referencing it.
|
* ref_id is the id of the tree referencing it.
|
||||||
|
*
|
||||||
|
* Will return 0, -ENOMEM, or anything from the CoW path
|
||||||
*/
|
*/
|
||||||
int btrfs_add_root_ref(struct btrfs_trans_handle *trans,
|
int btrfs_add_root_ref(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *tree_root,
|
struct btrfs_root *tree_root,
|
||||||
|
@ -406,7 +410,11 @@ int btrfs_add_root_ref(struct btrfs_trans_handle *trans,
|
||||||
again:
|
again:
|
||||||
ret = btrfs_insert_empty_item(trans, tree_root, path, &key,
|
ret = btrfs_insert_empty_item(trans, tree_root, path, &key,
|
||||||
sizeof(*ref) + name_len);
|
sizeof(*ref) + name_len);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, tree_root, ret);
|
||||||
|
btrfs_free_path(path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref);
|
ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref);
|
||||||
|
|
|
@ -1505,6 +1505,9 @@ static noinline_for_stack int scrub_supers(struct scrub_dev *sdev)
|
||||||
struct btrfs_device *device = sdev->dev;
|
struct btrfs_device *device = sdev->dev;
|
||||||
struct btrfs_root *root = device->dev_root;
|
struct btrfs_root *root = device->dev_root;
|
||||||
|
|
||||||
|
if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
gen = root->fs_info->last_trans_committed;
|
gen = root->fs_info->last_trans_committed;
|
||||||
|
|
||||||
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
|
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
|
||||||
|
|
|
@ -216,7 +216,7 @@ void __btrfs_abort_transaction(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root, const char *function,
|
struct btrfs_root *root, const char *function,
|
||||||
unsigned int line, int errno)
|
unsigned int line, int errno)
|
||||||
{
|
{
|
||||||
WARN_ON_ONCE(1);
|
WARN_ONCE(1, KERN_DEBUG "btrfs: Transaction aborted");
|
||||||
trans->aborted = errno;
|
trans->aborted = errno;
|
||||||
/* Nothing used. The other threads that have joined this
|
/* Nothing used. The other threads that have joined this
|
||||||
* transaction may be able to continue. */
|
* transaction may be able to continue. */
|
||||||
|
|
|
@ -949,18 +949,19 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
|
||||||
dentry->d_name.name, dentry->d_name.len,
|
dentry->d_name.name, dentry->d_name.len,
|
||||||
parent_inode, &key,
|
parent_inode, &key,
|
||||||
BTRFS_FT_DIR, index);
|
BTRFS_FT_DIR, index);
|
||||||
if (ret) {
|
if (ret == -EEXIST) {
|
||||||
pending->error = -EEXIST;
|
pending->error = -EEXIST;
|
||||||
dput(parent);
|
dput(parent);
|
||||||
goto fail;
|
goto fail;
|
||||||
} else if (ret)
|
} else if (ret) {
|
||||||
goto abort_trans;
|
goto abort_trans_dput;
|
||||||
|
}
|
||||||
|
|
||||||
btrfs_i_size_write(parent_inode, parent_inode->i_size +
|
btrfs_i_size_write(parent_inode, parent_inode->i_size +
|
||||||
dentry->d_name.len * 2);
|
dentry->d_name.len * 2);
|
||||||
ret = btrfs_update_inode(trans, parent_root, parent_inode);
|
ret = btrfs_update_inode(trans, parent_root, parent_inode);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto abort_trans;
|
goto abort_trans_dput;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* pull in the delayed directory update
|
* pull in the delayed directory update
|
||||||
|
@ -969,8 +970,10 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
|
||||||
* snapshot
|
* snapshot
|
||||||
*/
|
*/
|
||||||
ret = btrfs_run_delayed_items(trans, root);
|
ret = btrfs_run_delayed_items(trans, root);
|
||||||
if (ret) /* Transaction aborted */
|
if (ret) { /* Transaction aborted */
|
||||||
|
dput(parent);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
record_root_in_trans(trans, root);
|
record_root_in_trans(trans, root);
|
||||||
btrfs_set_root_last_snapshot(&root->root_item, trans->transid);
|
btrfs_set_root_last_snapshot(&root->root_item, trans->transid);
|
||||||
|
@ -986,17 +989,20 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
old = btrfs_lock_root_node(root);
|
old = btrfs_lock_root_node(root);
|
||||||
ret = btrfs_cow_block(trans, root, old, NULL, 0, &old);
|
ret = btrfs_cow_block(trans, root, old, NULL, 0, &old);
|
||||||
if (ret)
|
if (ret) {
|
||||||
goto abort_trans;
|
btrfs_tree_unlock(old);
|
||||||
|
free_extent_buffer(old);
|
||||||
|
goto abort_trans_dput;
|
||||||
|
}
|
||||||
|
|
||||||
btrfs_set_lock_blocking(old);
|
btrfs_set_lock_blocking(old);
|
||||||
|
|
||||||
ret = btrfs_copy_root(trans, root, old, &tmp, objectid);
|
ret = btrfs_copy_root(trans, root, old, &tmp, objectid);
|
||||||
if (ret)
|
/* clean up in any case */
|
||||||
goto abort_trans;
|
|
||||||
|
|
||||||
btrfs_tree_unlock(old);
|
btrfs_tree_unlock(old);
|
||||||
free_extent_buffer(old);
|
free_extent_buffer(old);
|
||||||
|
if (ret)
|
||||||
|
goto abort_trans_dput;
|
||||||
|
|
||||||
/* see comments in should_cow_block() */
|
/* see comments in should_cow_block() */
|
||||||
root->force_cow = 1;
|
root->force_cow = 1;
|
||||||
|
@ -1009,7 +1015,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
|
||||||
btrfs_tree_unlock(tmp);
|
btrfs_tree_unlock(tmp);
|
||||||
free_extent_buffer(tmp);
|
free_extent_buffer(tmp);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto abort_trans;
|
goto abort_trans_dput;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* insert root back/forward references
|
* insert root back/forward references
|
||||||
|
@ -1018,14 +1024,16 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
|
||||||
parent_root->root_key.objectid,
|
parent_root->root_key.objectid,
|
||||||
btrfs_ino(parent_inode), index,
|
btrfs_ino(parent_inode), index,
|
||||||
dentry->d_name.name, dentry->d_name.len);
|
dentry->d_name.name, dentry->d_name.len);
|
||||||
|
dput(parent);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto fail;
|
goto fail;
|
||||||
dput(parent);
|
|
||||||
|
|
||||||
key.offset = (u64)-1;
|
key.offset = (u64)-1;
|
||||||
pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key);
|
pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key);
|
||||||
if (IS_ERR(pending->snap))
|
if (IS_ERR(pending->snap)) {
|
||||||
|
ret = PTR_ERR(pending->snap);
|
||||||
goto abort_trans;
|
goto abort_trans;
|
||||||
|
}
|
||||||
|
|
||||||
ret = btrfs_reloc_post_snapshot(trans, pending);
|
ret = btrfs_reloc_post_snapshot(trans, pending);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -1037,6 +1045,8 @@ fail:
|
||||||
btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1);
|
btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
abort_trans_dput:
|
||||||
|
dput(parent);
|
||||||
abort_trans:
|
abort_trans:
|
||||||
btrfs_abort_transaction(trans, root, ret);
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
|
@ -1761,7 +1761,7 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
|
||||||
BTRFS_TREE_LOG_OBJECTID);
|
BTRFS_TREE_LOG_OBJECTID);
|
||||||
ret = btrfs_free_and_pin_reserved_extent(root,
|
ret = btrfs_free_and_pin_reserved_extent(root,
|
||||||
bytenr, blocksize);
|
bytenr, blocksize);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM or logic errors */
|
||||||
}
|
}
|
||||||
free_extent_buffer(next);
|
free_extent_buffer(next);
|
||||||
continue;
|
continue;
|
||||||
|
@ -1869,20 +1869,26 @@ static int walk_log_tree(struct btrfs_trans_handle *trans,
|
||||||
wret = walk_down_log_tree(trans, log, path, &level, wc);
|
wret = walk_down_log_tree(trans, log, path, &level, wc);
|
||||||
if (wret > 0)
|
if (wret > 0)
|
||||||
break;
|
break;
|
||||||
if (wret < 0)
|
if (wret < 0) {
|
||||||
ret = wret;
|
ret = wret;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
wret = walk_up_log_tree(trans, log, path, &level, wc);
|
wret = walk_up_log_tree(trans, log, path, &level, wc);
|
||||||
if (wret > 0)
|
if (wret > 0)
|
||||||
break;
|
break;
|
||||||
if (wret < 0)
|
if (wret < 0) {
|
||||||
ret = wret;
|
ret = wret;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* was the root node processed? if not, catch it here */
|
/* was the root node processed? if not, catch it here */
|
||||||
if (path->nodes[orig_level]) {
|
if (path->nodes[orig_level]) {
|
||||||
wc->process_func(log, path->nodes[orig_level], wc,
|
ret = wc->process_func(log, path->nodes[orig_level], wc,
|
||||||
btrfs_header_generation(path->nodes[orig_level]));
|
btrfs_header_generation(path->nodes[orig_level]));
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
if (wc->free) {
|
if (wc->free) {
|
||||||
struct extent_buffer *next;
|
struct extent_buffer *next;
|
||||||
|
|
||||||
|
@ -1898,10 +1904,11 @@ static int walk_log_tree(struct btrfs_trans_handle *trans,
|
||||||
BTRFS_TREE_LOG_OBJECTID);
|
BTRFS_TREE_LOG_OBJECTID);
|
||||||
ret = btrfs_free_and_pin_reserved_extent(log, next->start,
|
ret = btrfs_free_and_pin_reserved_extent(log, next->start,
|
||||||
next->len);
|
next->len);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM or logic errors */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
for (i = 0; i <= orig_level; i++) {
|
for (i = 0; i <= orig_level; i++) {
|
||||||
if (path->nodes[i]) {
|
if (path->nodes[i]) {
|
||||||
free_extent_buffer(path->nodes[i]);
|
free_extent_buffer(path->nodes[i]);
|
||||||
|
@ -2043,7 +2050,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
|
||||||
* wait for them until later.
|
* wait for them until later.
|
||||||
*/
|
*/
|
||||||
ret = btrfs_write_marked_extents(log, &log->dirty_log_pages, mark);
|
ret = btrfs_write_marked_extents(log, &log->dirty_log_pages, mark);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
mutex_unlock(&root->log_mutex);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
btrfs_set_root_node(&log->root_item, log->node);
|
btrfs_set_root_node(&log->root_item, log->node);
|
||||||
|
|
||||||
|
@ -2074,7 +2085,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
BUG_ON(ret != -ENOSPC);
|
if (ret != -ENOSPC) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
mutex_unlock(&log_root_tree->log_mutex);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
root->fs_info->last_trans_log_full_commit = trans->transid;
|
root->fs_info->last_trans_log_full_commit = trans->transid;
|
||||||
btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
|
btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
|
||||||
mutex_unlock(&log_root_tree->log_mutex);
|
mutex_unlock(&log_root_tree->log_mutex);
|
||||||
|
@ -2114,7 +2129,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
|
||||||
ret = btrfs_write_and_wait_marked_extents(log_root_tree,
|
ret = btrfs_write_and_wait_marked_extents(log_root_tree,
|
||||||
&log_root_tree->dirty_log_pages,
|
&log_root_tree->dirty_log_pages,
|
||||||
EXTENT_DIRTY | EXTENT_NEW);
|
EXTENT_DIRTY | EXTENT_NEW);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
mutex_unlock(&log_root_tree->log_mutex);
|
||||||
|
goto out_wake_log_root;
|
||||||
|
}
|
||||||
btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
|
btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
|
||||||
|
|
||||||
btrfs_set_super_log_root(root->fs_info->super_for_commit,
|
btrfs_set_super_log_root(root->fs_info->super_for_commit,
|
||||||
|
@ -2323,7 +2342,9 @@ out_unlock:
|
||||||
if (ret == -ENOSPC) {
|
if (ret == -ENOSPC) {
|
||||||
root->fs_info->last_trans_log_full_commit = trans->transid;
|
root->fs_info->last_trans_log_full_commit = trans->transid;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
} else if (ret < 0)
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
|
||||||
btrfs_end_log_trans(root);
|
btrfs_end_log_trans(root);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -2354,7 +2375,8 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
|
||||||
if (ret == -ENOSPC) {
|
if (ret == -ENOSPC) {
|
||||||
root->fs_info->last_trans_log_full_commit = trans->transid;
|
root->fs_info->last_trans_log_full_commit = trans->transid;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
} else if (ret < 0 && ret != -ENOENT)
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
btrfs_end_log_trans(root);
|
btrfs_end_log_trans(root);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -3166,13 +3188,20 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
|
||||||
fs_info->log_root_recovering = 1;
|
fs_info->log_root_recovering = 1;
|
||||||
|
|
||||||
trans = btrfs_start_transaction(fs_info->tree_root, 0);
|
trans = btrfs_start_transaction(fs_info->tree_root, 0);
|
||||||
BUG_ON(IS_ERR(trans));
|
if (IS_ERR(trans)) {
|
||||||
|
ret = PTR_ERR(trans);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
wc.trans = trans;
|
wc.trans = trans;
|
||||||
wc.pin = 1;
|
wc.pin = 1;
|
||||||
|
|
||||||
ret = walk_log_tree(trans, log_root_tree, &wc);
|
ret = walk_log_tree(trans, log_root_tree, &wc);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_error(fs_info, ret, "Failed to pin buffers while "
|
||||||
|
"recovering log root tree.");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
again:
|
again:
|
||||||
key.objectid = BTRFS_TREE_LOG_OBJECTID;
|
key.objectid = BTRFS_TREE_LOG_OBJECTID;
|
||||||
|
@ -3181,8 +3210,12 @@ again:
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ret = btrfs_search_slot(NULL, log_root_tree, &key, path, 0, 0);
|
ret = btrfs_search_slot(NULL, log_root_tree, &key, path, 0, 0);
|
||||||
if (ret < 0)
|
|
||||||
break;
|
if (ret < 0) {
|
||||||
|
btrfs_error(fs_info, ret,
|
||||||
|
"Couldn't find tree log root.");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
if (path->slots[0] == 0)
|
if (path->slots[0] == 0)
|
||||||
break;
|
break;
|
||||||
|
@ -3196,14 +3229,24 @@ again:
|
||||||
|
|
||||||
log = btrfs_read_fs_root_no_radix(log_root_tree,
|
log = btrfs_read_fs_root_no_radix(log_root_tree,
|
||||||
&found_key);
|
&found_key);
|
||||||
BUG_ON(IS_ERR(log));
|
if (IS_ERR(log)) {
|
||||||
|
ret = PTR_ERR(log);
|
||||||
|
btrfs_error(fs_info, ret,
|
||||||
|
"Couldn't read tree log root.");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
tmp_key.objectid = found_key.offset;
|
tmp_key.objectid = found_key.offset;
|
||||||
tmp_key.type = BTRFS_ROOT_ITEM_KEY;
|
tmp_key.type = BTRFS_ROOT_ITEM_KEY;
|
||||||
tmp_key.offset = (u64)-1;
|
tmp_key.offset = (u64)-1;
|
||||||
|
|
||||||
wc.replay_dest = btrfs_read_fs_root_no_name(fs_info, &tmp_key);
|
wc.replay_dest = btrfs_read_fs_root_no_name(fs_info, &tmp_key);
|
||||||
BUG_ON(IS_ERR_OR_NULL(wc.replay_dest));
|
if (IS_ERR(wc.replay_dest)) {
|
||||||
|
ret = PTR_ERR(wc.replay_dest);
|
||||||
|
btrfs_error(fs_info, ret, "Couldn't read target root "
|
||||||
|
"for tree log recovery.");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
wc.replay_dest->log_root = log;
|
wc.replay_dest->log_root = log;
|
||||||
btrfs_record_root_in_trans(trans, wc.replay_dest);
|
btrfs_record_root_in_trans(trans, wc.replay_dest);
|
||||||
|
@ -3251,6 +3294,10 @@ again:
|
||||||
|
|
||||||
kfree(log_root_tree);
|
kfree(log_root_tree);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
btrfs_free_path(path);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -549,10 +549,10 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
|
||||||
fs_devices->num_can_discard--;
|
fs_devices->num_can_discard--;
|
||||||
|
|
||||||
new_device = kmalloc(sizeof(*new_device), GFP_NOFS);
|
new_device = kmalloc(sizeof(*new_device), GFP_NOFS);
|
||||||
BUG_ON(!new_device);
|
BUG_ON(!new_device); /* -ENOMEM */
|
||||||
memcpy(new_device, device, sizeof(*new_device));
|
memcpy(new_device, device, sizeof(*new_device));
|
||||||
new_device->name = kstrdup(device->name, GFP_NOFS);
|
new_device->name = kstrdup(device->name, GFP_NOFS);
|
||||||
BUG_ON(device->name && !new_device->name);
|
BUG_ON(device->name && !new_device->name); /* -ENOMEM */
|
||||||
new_device->bdev = NULL;
|
new_device->bdev = NULL;
|
||||||
new_device->writeable = 0;
|
new_device->writeable = 0;
|
||||||
new_device->in_fs_metadata = 0;
|
new_device->in_fs_metadata = 0;
|
||||||
|
@ -1036,8 +1036,10 @@ again:
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
extent = btrfs_item_ptr(leaf, path->slots[0],
|
extent = btrfs_item_ptr(leaf, path->slots[0],
|
||||||
struct btrfs_dev_extent);
|
struct btrfs_dev_extent);
|
||||||
|
} else {
|
||||||
|
btrfs_error(root->fs_info, ret, "Slot search failed");
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
BUG_ON(ret);
|
|
||||||
|
|
||||||
if (device->bytes_used > 0) {
|
if (device->bytes_used > 0) {
|
||||||
u64 len = btrfs_dev_extent_length(leaf, extent);
|
u64 len = btrfs_dev_extent_length(leaf, extent);
|
||||||
|
@ -1047,7 +1049,10 @@ again:
|
||||||
spin_unlock(&root->fs_info->free_chunk_lock);
|
spin_unlock(&root->fs_info->free_chunk_lock);
|
||||||
}
|
}
|
||||||
ret = btrfs_del_item(trans, root, path);
|
ret = btrfs_del_item(trans, root, path);
|
||||||
|
if (ret) {
|
||||||
|
btrfs_error(root->fs_info, ret,
|
||||||
|
"Failed to remove dev extent item");
|
||||||
|
}
|
||||||
out:
|
out:
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1117,7 +1122,7 @@ static noinline int find_next_chunk(struct btrfs_root *root,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
BUG_ON(ret == 0);
|
BUG_ON(ret == 0); /* Corruption */
|
||||||
|
|
||||||
ret = btrfs_previous_item(root, path, 0, BTRFS_CHUNK_ITEM_KEY);
|
ret = btrfs_previous_item(root, path, 0, BTRFS_CHUNK_ITEM_KEY);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -1161,7 +1166,7 @@ static noinline int find_next_devid(struct btrfs_root *root, u64 *objectid)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
BUG_ON(ret == 0);
|
BUG_ON(ret == 0); /* Corruption */
|
||||||
|
|
||||||
ret = btrfs_previous_item(root, path, BTRFS_DEV_ITEMS_OBJECTID,
|
ret = btrfs_previous_item(root, path, BTRFS_DEV_ITEMS_OBJECTID,
|
||||||
BTRFS_DEV_ITEM_KEY);
|
BTRFS_DEV_ITEM_KEY);
|
||||||
|
@ -1595,7 +1600,7 @@ next_slot:
|
||||||
(unsigned long)btrfs_device_fsid(dev_item),
|
(unsigned long)btrfs_device_fsid(dev_item),
|
||||||
BTRFS_UUID_SIZE);
|
BTRFS_UUID_SIZE);
|
||||||
device = btrfs_find_device(root, devid, dev_uuid, fs_uuid);
|
device = btrfs_find_device(root, devid, dev_uuid, fs_uuid);
|
||||||
BUG_ON(!device);
|
BUG_ON(!device); /* Logic error */
|
||||||
|
|
||||||
if (device->fs_devices->seeding) {
|
if (device->fs_devices->seeding) {
|
||||||
btrfs_set_device_generation(leaf, dev_item,
|
btrfs_set_device_generation(leaf, dev_item,
|
||||||
|
@ -1705,7 +1710,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
|
||||||
if (seeding_dev) {
|
if (seeding_dev) {
|
||||||
sb->s_flags &= ~MS_RDONLY;
|
sb->s_flags &= ~MS_RDONLY;
|
||||||
ret = btrfs_prepare_sprout(root);
|
ret = btrfs_prepare_sprout(root);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
|
|
||||||
device->fs_devices = root->fs_info->fs_devices;
|
device->fs_devices = root->fs_info->fs_devices;
|
||||||
|
@ -1743,11 +1748,15 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
|
||||||
|
|
||||||
if (seeding_dev) {
|
if (seeding_dev) {
|
||||||
ret = init_first_rw_device(trans, root, device);
|
ret = init_first_rw_device(trans, root, device);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
goto error_trans;
|
||||||
ret = btrfs_finish_sprout(trans, root);
|
ret = btrfs_finish_sprout(trans, root);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
goto error_trans;
|
||||||
} else {
|
} else {
|
||||||
ret = btrfs_add_device(trans, root, device);
|
ret = btrfs_add_device(trans, root, device);
|
||||||
|
if (ret)
|
||||||
|
goto error_trans;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1757,17 +1766,31 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
|
||||||
btrfs_clear_space_info_full(root->fs_info);
|
btrfs_clear_space_info_full(root->fs_info);
|
||||||
|
|
||||||
unlock_chunks(root);
|
unlock_chunks(root);
|
||||||
btrfs_commit_transaction(trans, root);
|
ret = btrfs_commit_transaction(trans, root);
|
||||||
|
|
||||||
if (seeding_dev) {
|
if (seeding_dev) {
|
||||||
mutex_unlock(&uuid_mutex);
|
mutex_unlock(&uuid_mutex);
|
||||||
up_write(&sb->s_umount);
|
up_write(&sb->s_umount);
|
||||||
|
|
||||||
|
if (ret) /* transaction commit */
|
||||||
|
return ret;
|
||||||
|
|
||||||
ret = btrfs_relocate_sys_chunks(root);
|
ret = btrfs_relocate_sys_chunks(root);
|
||||||
BUG_ON(ret);
|
if (ret < 0)
|
||||||
|
btrfs_error(root->fs_info, ret,
|
||||||
|
"Failed to relocate sys chunks after "
|
||||||
|
"device initialization. This can be fixed "
|
||||||
|
"using the \"btrfs balance\" command.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
error_trans:
|
||||||
|
unlock_chunks(root);
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
btrfs_end_transaction(trans, root);
|
||||||
|
kfree(device->name);
|
||||||
|
kfree(device);
|
||||||
error:
|
error:
|
||||||
blkdev_put(bdev, FMODE_EXCL);
|
blkdev_put(bdev, FMODE_EXCL);
|
||||||
if (seeding_dev) {
|
if (seeding_dev) {
|
||||||
|
@ -1875,10 +1898,20 @@ static int btrfs_free_chunk(struct btrfs_trans_handle *trans,
|
||||||
key.type = BTRFS_CHUNK_ITEM_KEY;
|
key.type = BTRFS_CHUNK_ITEM_KEY;
|
||||||
|
|
||||||
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
|
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
|
||||||
BUG_ON(ret);
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
else if (ret > 0) { /* Logic error or corruption */
|
||||||
|
btrfs_error(root->fs_info, -ENOENT,
|
||||||
|
"Failed lookup while freeing chunk.");
|
||||||
|
ret = -ENOENT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ret = btrfs_del_item(trans, root, path);
|
ret = btrfs_del_item(trans, root, path);
|
||||||
|
if (ret < 0)
|
||||||
|
btrfs_error(root->fs_info, ret,
|
||||||
|
"Failed to delete chunk item.");
|
||||||
|
out:
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -2040,7 +2073,7 @@ again:
|
||||||
ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0);
|
ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
BUG_ON(ret == 0);
|
BUG_ON(ret == 0); /* Corruption */
|
||||||
|
|
||||||
ret = btrfs_previous_item(chunk_root, path, key.objectid,
|
ret = btrfs_previous_item(chunk_root, path, key.objectid,
|
||||||
key.type);
|
key.type);
|
||||||
|
@ -3334,7 +3367,8 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
|
||||||
ret = btrfs_make_block_group(trans, extent_root, 0, type,
|
ret = btrfs_make_block_group(trans, extent_root, 0, type,
|
||||||
BTRFS_FIRST_CHUNK_TREE_OBJECTID,
|
BTRFS_FIRST_CHUNK_TREE_OBJECTID,
|
||||||
start, num_bytes);
|
start, num_bytes);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
goto error;
|
||||||
|
|
||||||
for (i = 0; i < map->num_stripes; ++i) {
|
for (i = 0; i < map->num_stripes; ++i) {
|
||||||
struct btrfs_device *device;
|
struct btrfs_device *device;
|
||||||
|
@ -3347,7 +3381,10 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
|
||||||
info->chunk_root->root_key.objectid,
|
info->chunk_root->root_key.objectid,
|
||||||
BTRFS_FIRST_CHUNK_TREE_OBJECTID,
|
BTRFS_FIRST_CHUNK_TREE_OBJECTID,
|
||||||
start, dev_offset, stripe_size);
|
start, dev_offset, stripe_size);
|
||||||
BUG_ON(ret);
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, extent_root, ret);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree(devices_info);
|
kfree(devices_info);
|
||||||
|
@ -3465,7 +3502,8 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
ret = __finish_chunk_alloc(trans, extent_root, map, chunk_offset,
|
ret = __finish_chunk_alloc(trans, extent_root, map, chunk_offset,
|
||||||
chunk_size, stripe_size);
|
chunk_size, stripe_size);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
return ret;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3497,7 +3535,8 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
ret = __btrfs_alloc_chunk(trans, extent_root, &map, &chunk_size,
|
ret = __btrfs_alloc_chunk(trans, extent_root, &map, &chunk_size,
|
||||||
&stripe_size, chunk_offset, alloc_profile);
|
&stripe_size, chunk_offset, alloc_profile);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
sys_chunk_offset = chunk_offset + chunk_size;
|
sys_chunk_offset = chunk_offset + chunk_size;
|
||||||
|
|
||||||
|
@ -3508,10 +3547,12 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans,
|
||||||
ret = __btrfs_alloc_chunk(trans, extent_root, &sys_map,
|
ret = __btrfs_alloc_chunk(trans, extent_root, &sys_map,
|
||||||
&sys_chunk_size, &sys_stripe_size,
|
&sys_chunk_size, &sys_stripe_size,
|
||||||
sys_chunk_offset, alloc_profile);
|
sys_chunk_offset, alloc_profile);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
goto abort;
|
||||||
|
|
||||||
ret = btrfs_add_device(trans, fs_info->chunk_root, device);
|
ret = btrfs_add_device(trans, fs_info->chunk_root, device);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
goto abort;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Modifying chunk tree needs allocating new blocks from both
|
* Modifying chunk tree needs allocating new blocks from both
|
||||||
|
@ -3521,13 +3562,20 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans,
|
||||||
*/
|
*/
|
||||||
ret = __finish_chunk_alloc(trans, extent_root, map, chunk_offset,
|
ret = __finish_chunk_alloc(trans, extent_root, map, chunk_offset,
|
||||||
chunk_size, stripe_size);
|
chunk_size, stripe_size);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
goto abort;
|
||||||
|
|
||||||
ret = __finish_chunk_alloc(trans, extent_root, sys_map,
|
ret = __finish_chunk_alloc(trans, extent_root, sys_map,
|
||||||
sys_chunk_offset, sys_chunk_size,
|
sys_chunk_offset, sys_chunk_size,
|
||||||
sys_stripe_size);
|
sys_stripe_size);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
goto abort;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
abort:
|
||||||
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset)
|
int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset)
|
||||||
|
@ -3878,7 +3926,7 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
|
||||||
do_div(length, map->num_stripes);
|
do_div(length, map->num_stripes);
|
||||||
|
|
||||||
buf = kzalloc(sizeof(u64) * map->num_stripes, GFP_NOFS);
|
buf = kzalloc(sizeof(u64) * map->num_stripes, GFP_NOFS);
|
||||||
BUG_ON(!buf);
|
BUG_ON(!buf); /* -ENOMEM */
|
||||||
|
|
||||||
for (i = 0; i < map->num_stripes; i++) {
|
for (i = 0; i < map->num_stripes; i++) {
|
||||||
if (devid && map->stripes[i].dev->devid != devid)
|
if (devid && map->stripes[i].dev->devid != devid)
|
||||||
|
@ -4039,7 +4087,8 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
|
||||||
|
|
||||||
ret = btrfs_map_block(map_tree, rw, logical, &map_length, &bbio,
|
ret = btrfs_map_block(map_tree, rw, logical, &map_length, &bbio,
|
||||||
mirror_num);
|
mirror_num);
|
||||||
BUG_ON(ret);
|
if (ret) /* -ENOMEM */
|
||||||
|
return ret;
|
||||||
|
|
||||||
total_devs = bbio->num_stripes;
|
total_devs = bbio->num_stripes;
|
||||||
if (map_length < length) {
|
if (map_length < length) {
|
||||||
|
@ -4058,7 +4107,7 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
|
||||||
while (dev_nr < total_devs) {
|
while (dev_nr < total_devs) {
|
||||||
if (dev_nr < total_devs - 1) {
|
if (dev_nr < total_devs - 1) {
|
||||||
bio = bio_clone(first_bio, GFP_NOFS);
|
bio = bio_clone(first_bio, GFP_NOFS);
|
||||||
BUG_ON(!bio);
|
BUG_ON(!bio); /* -ENOMEM */
|
||||||
} else {
|
} else {
|
||||||
bio = first_bio;
|
bio = first_bio;
|
||||||
}
|
}
|
||||||
|
@ -4212,7 +4261,7 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
|
||||||
write_lock(&map_tree->map_tree.lock);
|
write_lock(&map_tree->map_tree.lock);
|
||||||
ret = add_extent_mapping(&map_tree->map_tree, em);
|
ret = add_extent_mapping(&map_tree->map_tree, em);
|
||||||
write_unlock(&map_tree->map_tree.lock);
|
write_unlock(&map_tree->map_tree.lock);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret); /* Tree corruption */
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче