Loading fs/btrfs/ctree.c +82 −24 Original line number Diff line number Diff line Loading @@ -73,6 +73,7 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root { struct buffer_head *cow; struct btrfs_node *cow_node; int ret; if (btrfs_header_generation(btrfs_buffer_header(buf)) == trans->transid) { Loading @@ -80,6 +81,8 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root return 0; } cow = btrfs_alloc_free_block(trans, root, buf->b_blocknr); if (IS_ERR(cow)) return PTR_ERR(cow); cow_node = btrfs_buffer_node(cow); if (buf->b_size != root->blocksize || cow->b_size != root->blocksize) WARN_ON(1); Loading @@ -87,7 +90,9 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root btrfs_set_header_blocknr(&cow_node->header, bh_blocknr(cow)); btrfs_set_header_generation(&cow_node->header, trans->transid); btrfs_set_header_owner(&cow_node->header, root->root_key.objectid); btrfs_inc_ref(trans, root, buf); ret = btrfs_inc_ref(trans, root, buf); if (ret) return ret; if (buf == root->node) { root->node = cow; get_bh(cow); Loading Loading @@ -320,6 +325,7 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root int wret; int pslot; int orig_slot = path->slots[level]; int err_on_enospc = 0; u64 orig_ptr; if (level == 0) Loading Loading @@ -363,29 +369,43 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root BTRFS_NODEPTRS_PER_BLOCK(root) / 4) return 0; if (btrfs_header_nritems(&mid->header) < 2) err_on_enospc = 1; left_buf = read_node_slot(root, parent_buf, pslot - 1); right_buf = read_node_slot(root, parent_buf, pslot + 1); /* first, try to make some room in the middle buffer */ if (left_buf) { btrfs_cow_block(trans, root, left_buf, parent_buf, pslot - 1, &left_buf); wret = btrfs_cow_block(trans, root, left_buf, parent_buf, pslot - 1, &left_buf); if (wret) { ret = wret; goto enospc; } left = btrfs_buffer_node(left_buf); orig_slot += btrfs_header_nritems(&left->header); wret = push_node_left(trans, root, left_buf, mid_buf); if (wret < 0) ret = wret; if (btrfs_header_nritems(&mid->header) < 2) err_on_enospc = 1; } /* * then try to empty the right most buffer into the middle */ if (right_buf) { btrfs_cow_block(trans, root, right_buf, parent_buf, pslot + 1, &right_buf); wret = btrfs_cow_block(trans, root, right_buf, parent_buf, pslot + 1, &right_buf); if (wret) { ret = wret; goto enospc; } right = btrfs_buffer_node(right_buf); wret = push_node_left(trans, root, mid_buf, right_buf); if (wret < 0) if (wret < 0 && wret != -ENOSPC) ret = wret; if (btrfs_header_nritems(&right->header) == 0) { u64 blocknr = bh_blocknr(right_buf); Loading Loading @@ -421,8 +441,10 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root */ BUG_ON(!left_buf); wret = balance_node_right(trans, root, mid_buf, left_buf); if (wret < 0) if (wret < 0) { ret = wret; goto enospc; } BUG_ON(wret == 1); } if (btrfs_header_nritems(&mid->header) == 0) { Loading Loading @@ -467,7 +489,7 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root btrfs_node_blockptr(btrfs_buffer_node(path->nodes[level]), path->slots[level])) BUG(); enospc: if (right_buf) btrfs_block_release(root, right_buf); if (left_buf) Loading Loading @@ -519,10 +541,15 @@ static int push_nodes_for_insert(struct btrfs_trans_handle *trans, if (left_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) { wret = 1; } else { btrfs_cow_block(trans, root, left_buf, parent_buf, ret = btrfs_cow_block(trans, root, left_buf, parent_buf, pslot - 1, &left_buf); if (ret) wret = 1; else { left = btrfs_buffer_node(left_buf); wret = push_node_left(trans, root, left_buf, mid_buf); wret = push_node_left(trans, root, left_buf, mid_buf); } } if (wret < 0) ret = wret; Loading Loading @@ -561,12 +588,17 @@ static int push_nodes_for_insert(struct btrfs_trans_handle *trans, if (right_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) { wret = 1; } else { btrfs_cow_block(trans, root, right_buf, parent_buf, pslot + 1, &right_buf); ret = btrfs_cow_block(trans, root, right_buf, parent_buf, pslot + 1, &right_buf); if (ret) wret = 1; else { right = btrfs_buffer_node(right_buf); wret = balance_node_right(trans, root, right_buf, mid_buf); } } if (wret < 0) ret = wret; if (wret == 0) { Loading Loading @@ -631,6 +663,10 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root p->nodes[level + 1], p->slots[level + 1], &cow_buf); if (wret) { btrfs_block_release(root, cow_buf); return wret; } b = cow_buf; c = btrfs_buffer_node(b); } Loading Loading @@ -737,6 +773,7 @@ static int push_node_left(struct btrfs_trans_handle *trans, struct btrfs_root src_nritems = btrfs_header_nritems(&src->header); dst_nritems = btrfs_header_nritems(&dst->header); push_items = BTRFS_NODEPTRS_PER_BLOCK(root) - dst_nritems; if (push_items <= 0) { return 1; } Loading Loading @@ -827,6 +864,8 @@ static int insert_new_root(struct btrfs_trans_handle *trans, struct btrfs_root BUG_ON(path->nodes[level-1] != root->node); t = btrfs_alloc_free_block(trans, root, root->node->b_blocknr); if (IS_ERR(t)) return PTR_ERR(t); c = btrfs_buffer_node(t); memset(c, 0, root->blocksize); btrfs_set_header_nritems(&c->header, 1); Loading Loading @@ -929,10 +968,15 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root btrfs_header_nritems(&c->header) < BTRFS_NODEPTRS_PER_BLOCK(root) - 1) return 0; if (ret < 0) return ret; } c_nritems = btrfs_header_nritems(&c->header); split_buffer = btrfs_alloc_free_block(trans, root, t->b_blocknr); if (IS_ERR(split_buffer)) return PTR_ERR(split_buffer); split = btrfs_buffer_node(split_buffer); btrfs_set_header_flags(&split->header, btrfs_header_flags(&c->header)); btrfs_set_header_level(&split->header, btrfs_header_level(&c->header)); Loading Loading @@ -1022,6 +1066,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root struct btrfs_item *item; u32 left_nritems; u32 right_nritems; int ret; slot = path->slots[1]; if (!path->nodes[1]) { Loading @@ -1041,7 +1086,12 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root return 1; } /* cow and double check */ btrfs_cow_block(trans, root, right_buf, upper, slot + 1, &right_buf); ret = btrfs_cow_block(trans, root, right_buf, upper, slot + 1, &right_buf); if (ret) { btrfs_block_release(root, right_buf); return 1; } right = btrfs_buffer_leaf(right_buf); free_space = btrfs_leaf_free_space(root, right); if (free_space < data_size + sizeof(struct btrfs_item)) { Loading Loading @@ -1162,7 +1212,11 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root } /* cow and double check */ btrfs_cow_block(trans, root, t, path->nodes[1], slot - 1, &t); ret = btrfs_cow_block(trans, root, t, path->nodes[1], slot - 1, &t); if (ret) { /* we hit -ENOSPC, but it isn't fatal here */ return 1; } left = btrfs_buffer_leaf(t); free_space = btrfs_leaf_free_space(root, left); if (free_space < data_size + sizeof(struct btrfs_item)) { Loading Loading @@ -1309,8 +1363,11 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root slot = path->slots[0]; nritems = btrfs_header_nritems(&l->header); mid = (nritems + 1)/ 2; right_buffer = btrfs_alloc_free_block(trans, root, l_buf->b_blocknr); BUG_ON(!right_buffer); if (IS_ERR(right_buffer)) return PTR_ERR(right_buffer); right = btrfs_buffer_leaf(right_buffer); memset(&right->header, 0, sizeof(right->header)); btrfs_set_header_blocknr(&right->header, bh_blocknr(right_buffer)); Loading Loading @@ -1407,7 +1464,9 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root if (!double_split) return ret; right_buffer = btrfs_alloc_free_block(trans, root, l_buf->b_blocknr); BUG_ON(!right_buffer); if (IS_ERR(right_buffer)) return PTR_ERR(right_buffer); right = btrfs_buffer_leaf(right_buffer); memset(&right->header, 0, sizeof(right->header)); btrfs_set_header_blocknr(&right->header, bh_blocknr(right_buffer)); Loading Loading @@ -1655,7 +1714,6 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root ptr, data, data_size); btrfs_mark_buffer_dirty(path->nodes[0]); } btrfs_release_path(root, path); btrfs_free_path(path); return ret; } Loading Loading @@ -1775,12 +1833,12 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, slot = path->slots[1]; get_bh(leaf_buf); wret = push_leaf_left(trans, root, path, 1); if (wret < 0) if (wret < 0 && wret != -ENOSPC) ret = wret; if (path->nodes[0] == leaf_buf && btrfs_header_nritems(&leaf->header)) { wret = push_leaf_right(trans, root, path, 1); if (wret < 0) if (wret < 0 && wret != -ENOSPC) ret = wret; } if (btrfs_header_nritems(&leaf->header) == 0) { Loading fs/btrfs/ctree.h +0 −3 Original line number Diff line number Diff line Loading @@ -1126,9 +1126,6 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, u64 offset, char *data, size_t len); int btrfs_csum_verify_file_block(struct btrfs_root *root, u64 objectid, u64 offset, char *data, size_t len); struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, Loading fs/btrfs/dir-item.c +3 −3 Original line number Diff line number Diff line Loading @@ -47,6 +47,8 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle if (ret) return ERR_PTR(ret); } if (ret < 0) return ERR_PTR(ret); WARN_ON(ret > 0); leaf = btrfs_buffer_leaf(path->nodes[0]); item = leaf->items + path->slots[0]; Loading Loading @@ -225,14 +227,13 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, struct btrfs_leaf *leaf; u32 sub_item_len; u32 item_len; int ret; int ret = 0; leaf = btrfs_buffer_leaf(path->nodes[0]); sub_item_len = sizeof(*di) + btrfs_dir_name_len(di); item_len = btrfs_item_size(leaf->items + path->slots[0]); if (sub_item_len == btrfs_item_size(leaf->items + path->slots[0])) { ret = btrfs_del_item(trans, root, path); BUG_ON(ret); } else { char *ptr = (char *)di; char *start = btrfs_item_ptr(leaf, path->slots[0], char); Loading @@ -240,7 +241,6 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, item_len - (ptr + sub_item_len - start)); ret = btrfs_truncate_item(trans, root, path, item_len - sub_item_len); BUG_ON(ret); } return 0; } Loading fs/btrfs/disk-io.c +1 −1 Original line number Diff line number Diff line Loading @@ -580,7 +580,7 @@ int close_ctree(struct btrfs_root *root) btrfs_transaction_flush_work(root); mutex_lock(&fs_info->fs_mutex); trans = btrfs_start_transaction(root, 1); btrfs_commit_transaction(trans, root); ret = btrfs_commit_transaction(trans, root); /* run commit again to drop the original snapshot */ trans = btrfs_start_transaction(root, 1); btrfs_commit_transaction(trans, root); Loading fs/btrfs/extent-tree.c +115 −26 Original line number Diff line number Diff line Loading @@ -100,6 +100,8 @@ static int cache_block_group(struct btrfs_root *root, if (slot >= btrfs_header_nritems(&leaf->header)) { reada_extent_leaves(root, path, limit); ret = btrfs_next_leaf(root, path); if (ret < 0) goto err; if (ret == 0) { continue; } else { Loading Loading @@ -148,6 +150,7 @@ static int cache_block_group(struct btrfs_root *root, } block_group->cached = 1; err: btrfs_free_path(path); return 0; } Loading Loading @@ -201,7 +204,9 @@ static u64 find_search_start(struct btrfs_root *root, last = max(last, cache->last_prealloc); } again: cache_block_group(root, cache); ret = cache_block_group(root, cache); if (ret) goto out; while(1) { ret = find_first_radix_bit(&root->fs_info->extent_map_radix, gang, last, ARRAY_SIZE(gang)); Loading Loading @@ -398,16 +403,23 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, struct btrfs_key ins; u32 refs; find_free_extent(trans, root->fs_info->extent_root, 0, 0, (u64)-1, 0, &ins, 0); path = btrfs_alloc_path(); BUG_ON(!path); if (!path) return -ENOMEM; ret = find_free_extent(trans, root->fs_info->extent_root, 0, 0, (u64)-1, 0, &ins, 0); if (ret) { btrfs_free_path(path); return ret; } key.objectid = blocknr; key.flags = 0; btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); key.offset = num_blocks; ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path, 0, 1); if (ret < 0) return ret; if (ret != 0) { BUG(); } Loading Loading @@ -442,12 +454,14 @@ static int lookup_extent_ref(struct btrfs_trans_handle *trans, btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path, 0, 0); if (ret < 0) goto out; if (ret != 0) BUG(); l = btrfs_buffer_leaf(path->nodes[0]); item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item); *refs = btrfs_extent_refs(item); btrfs_release_path(root->fs_info->extent_root, path); out: btrfs_free_path(path); return 0; } Loading @@ -469,6 +483,8 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, int i; int leaf; int ret; int faili; int err; if (!root->ref_cows) return 0; Loading @@ -491,14 +507,45 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, continue; ret = btrfs_inc_extent_ref(trans, root, disk_blocknr, btrfs_file_extent_disk_num_blocks(fi)); BUG_ON(ret); if (ret) { faili = i; goto fail; } } else { blocknr = btrfs_node_blockptr(buf_node, i); ret = btrfs_inc_extent_ref(trans, root, blocknr, 1); BUG_ON(ret); if (ret) { faili = i; goto fail; } } } return 0; fail: for (i =0; i < faili; i++) { if (leaf) { u64 disk_blocknr; key = &buf_leaf->items[i].key; if (btrfs_disk_key_type(key) != BTRFS_EXTENT_DATA_KEY) continue; fi = btrfs_item_ptr(buf_leaf, i, struct btrfs_file_extent_item); if (btrfs_file_extent_type(fi) == BTRFS_FILE_EXTENT_INLINE) continue; disk_blocknr = btrfs_file_extent_disk_blocknr(fi); if (disk_blocknr == 0) continue; err = btrfs_free_extent(trans, root, disk_blocknr, btrfs_file_extent_disk_num_blocks(fi), 0); BUG_ON(err); } else { blocknr = btrfs_node_blockptr(buf_node, i); err = btrfs_free_extent(trans, root, blocknr, 1, 0); BUG_ON(err); } } return ret; } static int write_one_cache_group(struct btrfs_trans_handle *trans, Loading @@ -512,15 +559,20 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans, struct btrfs_block_group_item *bi; struct btrfs_key ins; find_free_extent(trans, extent_root, 0, 0, (u64)-1, 0, &ins, 0); ret = find_free_extent(trans, extent_root, 0, 0, (u64)-1, 0, &ins, 0); /* FIXME, set bit to recalc cache groups on next mount */ if (ret) return ret; ret = btrfs_search_slot(trans, extent_root, &cache->key, path, 0, 1); if (ret < 0) goto fail; BUG_ON(ret); bi = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], struct btrfs_block_group_item); memcpy(bi, &cache->item, sizeof(*bi)); mark_buffer_dirty(path->nodes[0]); btrfs_release_path(extent_root, path); fail: finish_current_insert(trans, extent_root); pending_ret = del_pending_extents(trans, extent_root); if (ret) Loading @@ -543,6 +595,7 @@ static int write_dirty_block_radix(struct btrfs_trans_handle *trans, int werr = 0; int i; struct btrfs_path *path; unsigned long off = 0; path = btrfs_alloc_path(); if (!path) Loading @@ -550,18 +603,28 @@ static int write_dirty_block_radix(struct btrfs_trans_handle *trans, while(1) { ret = radix_tree_gang_lookup_tag(radix, (void **)cache, 0, ARRAY_SIZE(cache), off, ARRAY_SIZE(cache), BTRFS_BLOCK_GROUP_DIRTY); if (!ret) break; for (i = 0; i < ret; i++) { radix_tree_tag_clear(radix, cache[i]->key.objectid + cache[i]->key.offset - 1, BTRFS_BLOCK_GROUP_DIRTY); err = write_one_cache_group(trans, root, path, cache[i]); if (err) /* * if we fail to write the cache group, we want * to keep it marked dirty in hopes that a later * write will work */ if (err) { werr = err; off = cache[i]->key.objectid + cache[i]->key.offset; continue; } radix_tree_tag_clear(radix, cache[i]->key.objectid + cache[i]->key.offset - 1, BTRFS_BLOCK_GROUP_DIRTY); } } btrfs_free_path(path); Loading Loading @@ -801,14 +864,20 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); key.offset = num_blocks; find_free_extent(trans, root, 0, 0, (u64)-1, 0, &ins, 0); path = btrfs_alloc_path(); BUG_ON(!path); if (!path) return -ENOMEM; ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1); ret = find_free_extent(trans, root, 0, 0, (u64)-1, 0, &ins, 0); if (ret) { BUG(); btrfs_free_path(path); return ret; } ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1); if (ret < 0) return ret; BUG_ON(ret); ei = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], struct btrfs_extent_item); BUG_ON(ei->refs == 0); Loading @@ -827,8 +896,9 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root btrfs_set_super_blocks_used(info->disk_super, super_blocks_used - num_blocks); ret = btrfs_del_item(trans, extent_root, path); if (ret) BUG(); if (ret) { return ret; } ret = update_block_group(trans, root, blocknr, num_blocks, 0, mark_free, 0); BUG_ON(ret); Loading Loading @@ -1075,7 +1145,6 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root path->slots[0]++; cond_resched(); } // FIXME -ENOSPC check_pending: /* we have to make sure we didn't find an extent that has already * been allocated by the map tree or the original allocation Loading Loading @@ -1246,6 +1315,14 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, ret = find_free_extent(trans, root, num_blocks, search_start, search_end, hint_block, ins, data); if (ret) { if (search_start == 0) return ret; search_end = search_start - 1; search_start = 0; hint_block = search_start; ret = find_free_extent(trans, root, num_blocks, search_start, search_end, hint_block, ins, data); if (ret) return ret; } Loading @@ -1271,6 +1348,15 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, search_end, hint_block, &prealloc_key, 0); if (ret) { if (search_start == 0) return ret; search_end = search_start - 1; search_start = 0; hint_block = search_start; ret = find_free_extent(trans, root, 0, search_start, search_end, hint_block, &prealloc_key, 0); if (ret) return ret; } } Loading Loading @@ -1309,11 +1395,14 @@ struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, ret = btrfs_alloc_extent(trans, root, root->root_key.objectid, 1, hint, (unsigned long)-1, &ins, 0); if (ret) { BUG(); return NULL; BUG_ON(ret > 0); return ERR_PTR(ret); } BUG_ON(ret); buf = btrfs_find_create_tree_block(root, ins.objectid); if (!buf) { btrfs_free_extent(trans, root, ins.objectid, 1, 0); return ERR_PTR(-ENOMEM); } set_buffer_uptodate(buf); set_buffer_checked(buf); set_radix_bit(&trans->transaction->dirty_pages, buf->b_page->index); Loading Loading
fs/btrfs/ctree.c +82 −24 Original line number Diff line number Diff line Loading @@ -73,6 +73,7 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root { struct buffer_head *cow; struct btrfs_node *cow_node; int ret; if (btrfs_header_generation(btrfs_buffer_header(buf)) == trans->transid) { Loading @@ -80,6 +81,8 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root return 0; } cow = btrfs_alloc_free_block(trans, root, buf->b_blocknr); if (IS_ERR(cow)) return PTR_ERR(cow); cow_node = btrfs_buffer_node(cow); if (buf->b_size != root->blocksize || cow->b_size != root->blocksize) WARN_ON(1); Loading @@ -87,7 +90,9 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root btrfs_set_header_blocknr(&cow_node->header, bh_blocknr(cow)); btrfs_set_header_generation(&cow_node->header, trans->transid); btrfs_set_header_owner(&cow_node->header, root->root_key.objectid); btrfs_inc_ref(trans, root, buf); ret = btrfs_inc_ref(trans, root, buf); if (ret) return ret; if (buf == root->node) { root->node = cow; get_bh(cow); Loading Loading @@ -320,6 +325,7 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root int wret; int pslot; int orig_slot = path->slots[level]; int err_on_enospc = 0; u64 orig_ptr; if (level == 0) Loading Loading @@ -363,29 +369,43 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root BTRFS_NODEPTRS_PER_BLOCK(root) / 4) return 0; if (btrfs_header_nritems(&mid->header) < 2) err_on_enospc = 1; left_buf = read_node_slot(root, parent_buf, pslot - 1); right_buf = read_node_slot(root, parent_buf, pslot + 1); /* first, try to make some room in the middle buffer */ if (left_buf) { btrfs_cow_block(trans, root, left_buf, parent_buf, pslot - 1, &left_buf); wret = btrfs_cow_block(trans, root, left_buf, parent_buf, pslot - 1, &left_buf); if (wret) { ret = wret; goto enospc; } left = btrfs_buffer_node(left_buf); orig_slot += btrfs_header_nritems(&left->header); wret = push_node_left(trans, root, left_buf, mid_buf); if (wret < 0) ret = wret; if (btrfs_header_nritems(&mid->header) < 2) err_on_enospc = 1; } /* * then try to empty the right most buffer into the middle */ if (right_buf) { btrfs_cow_block(trans, root, right_buf, parent_buf, pslot + 1, &right_buf); wret = btrfs_cow_block(trans, root, right_buf, parent_buf, pslot + 1, &right_buf); if (wret) { ret = wret; goto enospc; } right = btrfs_buffer_node(right_buf); wret = push_node_left(trans, root, mid_buf, right_buf); if (wret < 0) if (wret < 0 && wret != -ENOSPC) ret = wret; if (btrfs_header_nritems(&right->header) == 0) { u64 blocknr = bh_blocknr(right_buf); Loading Loading @@ -421,8 +441,10 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root */ BUG_ON(!left_buf); wret = balance_node_right(trans, root, mid_buf, left_buf); if (wret < 0) if (wret < 0) { ret = wret; goto enospc; } BUG_ON(wret == 1); } if (btrfs_header_nritems(&mid->header) == 0) { Loading Loading @@ -467,7 +489,7 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root btrfs_node_blockptr(btrfs_buffer_node(path->nodes[level]), path->slots[level])) BUG(); enospc: if (right_buf) btrfs_block_release(root, right_buf); if (left_buf) Loading Loading @@ -519,10 +541,15 @@ static int push_nodes_for_insert(struct btrfs_trans_handle *trans, if (left_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) { wret = 1; } else { btrfs_cow_block(trans, root, left_buf, parent_buf, ret = btrfs_cow_block(trans, root, left_buf, parent_buf, pslot - 1, &left_buf); if (ret) wret = 1; else { left = btrfs_buffer_node(left_buf); wret = push_node_left(trans, root, left_buf, mid_buf); wret = push_node_left(trans, root, left_buf, mid_buf); } } if (wret < 0) ret = wret; Loading Loading @@ -561,12 +588,17 @@ static int push_nodes_for_insert(struct btrfs_trans_handle *trans, if (right_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) { wret = 1; } else { btrfs_cow_block(trans, root, right_buf, parent_buf, pslot + 1, &right_buf); ret = btrfs_cow_block(trans, root, right_buf, parent_buf, pslot + 1, &right_buf); if (ret) wret = 1; else { right = btrfs_buffer_node(right_buf); wret = balance_node_right(trans, root, right_buf, mid_buf); } } if (wret < 0) ret = wret; if (wret == 0) { Loading Loading @@ -631,6 +663,10 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root p->nodes[level + 1], p->slots[level + 1], &cow_buf); if (wret) { btrfs_block_release(root, cow_buf); return wret; } b = cow_buf; c = btrfs_buffer_node(b); } Loading Loading @@ -737,6 +773,7 @@ static int push_node_left(struct btrfs_trans_handle *trans, struct btrfs_root src_nritems = btrfs_header_nritems(&src->header); dst_nritems = btrfs_header_nritems(&dst->header); push_items = BTRFS_NODEPTRS_PER_BLOCK(root) - dst_nritems; if (push_items <= 0) { return 1; } Loading Loading @@ -827,6 +864,8 @@ static int insert_new_root(struct btrfs_trans_handle *trans, struct btrfs_root BUG_ON(path->nodes[level-1] != root->node); t = btrfs_alloc_free_block(trans, root, root->node->b_blocknr); if (IS_ERR(t)) return PTR_ERR(t); c = btrfs_buffer_node(t); memset(c, 0, root->blocksize); btrfs_set_header_nritems(&c->header, 1); Loading Loading @@ -929,10 +968,15 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root btrfs_header_nritems(&c->header) < BTRFS_NODEPTRS_PER_BLOCK(root) - 1) return 0; if (ret < 0) return ret; } c_nritems = btrfs_header_nritems(&c->header); split_buffer = btrfs_alloc_free_block(trans, root, t->b_blocknr); if (IS_ERR(split_buffer)) return PTR_ERR(split_buffer); split = btrfs_buffer_node(split_buffer); btrfs_set_header_flags(&split->header, btrfs_header_flags(&c->header)); btrfs_set_header_level(&split->header, btrfs_header_level(&c->header)); Loading Loading @@ -1022,6 +1066,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root struct btrfs_item *item; u32 left_nritems; u32 right_nritems; int ret; slot = path->slots[1]; if (!path->nodes[1]) { Loading @@ -1041,7 +1086,12 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root return 1; } /* cow and double check */ btrfs_cow_block(trans, root, right_buf, upper, slot + 1, &right_buf); ret = btrfs_cow_block(trans, root, right_buf, upper, slot + 1, &right_buf); if (ret) { btrfs_block_release(root, right_buf); return 1; } right = btrfs_buffer_leaf(right_buf); free_space = btrfs_leaf_free_space(root, right); if (free_space < data_size + sizeof(struct btrfs_item)) { Loading Loading @@ -1162,7 +1212,11 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root } /* cow and double check */ btrfs_cow_block(trans, root, t, path->nodes[1], slot - 1, &t); ret = btrfs_cow_block(trans, root, t, path->nodes[1], slot - 1, &t); if (ret) { /* we hit -ENOSPC, but it isn't fatal here */ return 1; } left = btrfs_buffer_leaf(t); free_space = btrfs_leaf_free_space(root, left); if (free_space < data_size + sizeof(struct btrfs_item)) { Loading Loading @@ -1309,8 +1363,11 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root slot = path->slots[0]; nritems = btrfs_header_nritems(&l->header); mid = (nritems + 1)/ 2; right_buffer = btrfs_alloc_free_block(trans, root, l_buf->b_blocknr); BUG_ON(!right_buffer); if (IS_ERR(right_buffer)) return PTR_ERR(right_buffer); right = btrfs_buffer_leaf(right_buffer); memset(&right->header, 0, sizeof(right->header)); btrfs_set_header_blocknr(&right->header, bh_blocknr(right_buffer)); Loading Loading @@ -1407,7 +1464,9 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root if (!double_split) return ret; right_buffer = btrfs_alloc_free_block(trans, root, l_buf->b_blocknr); BUG_ON(!right_buffer); if (IS_ERR(right_buffer)) return PTR_ERR(right_buffer); right = btrfs_buffer_leaf(right_buffer); memset(&right->header, 0, sizeof(right->header)); btrfs_set_header_blocknr(&right->header, bh_blocknr(right_buffer)); Loading Loading @@ -1655,7 +1714,6 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root ptr, data, data_size); btrfs_mark_buffer_dirty(path->nodes[0]); } btrfs_release_path(root, path); btrfs_free_path(path); return ret; } Loading Loading @@ -1775,12 +1833,12 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, slot = path->slots[1]; get_bh(leaf_buf); wret = push_leaf_left(trans, root, path, 1); if (wret < 0) if (wret < 0 && wret != -ENOSPC) ret = wret; if (path->nodes[0] == leaf_buf && btrfs_header_nritems(&leaf->header)) { wret = push_leaf_right(trans, root, path, 1); if (wret < 0) if (wret < 0 && wret != -ENOSPC) ret = wret; } if (btrfs_header_nritems(&leaf->header) == 0) { Loading
fs/btrfs/ctree.h +0 −3 Original line number Diff line number Diff line Loading @@ -1126,9 +1126,6 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, u64 offset, char *data, size_t len); int btrfs_csum_verify_file_block(struct btrfs_root *root, u64 objectid, u64 offset, char *data, size_t len); struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, Loading
fs/btrfs/dir-item.c +3 −3 Original line number Diff line number Diff line Loading @@ -47,6 +47,8 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle if (ret) return ERR_PTR(ret); } if (ret < 0) return ERR_PTR(ret); WARN_ON(ret > 0); leaf = btrfs_buffer_leaf(path->nodes[0]); item = leaf->items + path->slots[0]; Loading Loading @@ -225,14 +227,13 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, struct btrfs_leaf *leaf; u32 sub_item_len; u32 item_len; int ret; int ret = 0; leaf = btrfs_buffer_leaf(path->nodes[0]); sub_item_len = sizeof(*di) + btrfs_dir_name_len(di); item_len = btrfs_item_size(leaf->items + path->slots[0]); if (sub_item_len == btrfs_item_size(leaf->items + path->slots[0])) { ret = btrfs_del_item(trans, root, path); BUG_ON(ret); } else { char *ptr = (char *)di; char *start = btrfs_item_ptr(leaf, path->slots[0], char); Loading @@ -240,7 +241,6 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, item_len - (ptr + sub_item_len - start)); ret = btrfs_truncate_item(trans, root, path, item_len - sub_item_len); BUG_ON(ret); } return 0; } Loading
fs/btrfs/disk-io.c +1 −1 Original line number Diff line number Diff line Loading @@ -580,7 +580,7 @@ int close_ctree(struct btrfs_root *root) btrfs_transaction_flush_work(root); mutex_lock(&fs_info->fs_mutex); trans = btrfs_start_transaction(root, 1); btrfs_commit_transaction(trans, root); ret = btrfs_commit_transaction(trans, root); /* run commit again to drop the original snapshot */ trans = btrfs_start_transaction(root, 1); btrfs_commit_transaction(trans, root); Loading
fs/btrfs/extent-tree.c +115 −26 Original line number Diff line number Diff line Loading @@ -100,6 +100,8 @@ static int cache_block_group(struct btrfs_root *root, if (slot >= btrfs_header_nritems(&leaf->header)) { reada_extent_leaves(root, path, limit); ret = btrfs_next_leaf(root, path); if (ret < 0) goto err; if (ret == 0) { continue; } else { Loading Loading @@ -148,6 +150,7 @@ static int cache_block_group(struct btrfs_root *root, } block_group->cached = 1; err: btrfs_free_path(path); return 0; } Loading Loading @@ -201,7 +204,9 @@ static u64 find_search_start(struct btrfs_root *root, last = max(last, cache->last_prealloc); } again: cache_block_group(root, cache); ret = cache_block_group(root, cache); if (ret) goto out; while(1) { ret = find_first_radix_bit(&root->fs_info->extent_map_radix, gang, last, ARRAY_SIZE(gang)); Loading Loading @@ -398,16 +403,23 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, struct btrfs_key ins; u32 refs; find_free_extent(trans, root->fs_info->extent_root, 0, 0, (u64)-1, 0, &ins, 0); path = btrfs_alloc_path(); BUG_ON(!path); if (!path) return -ENOMEM; ret = find_free_extent(trans, root->fs_info->extent_root, 0, 0, (u64)-1, 0, &ins, 0); if (ret) { btrfs_free_path(path); return ret; } key.objectid = blocknr; key.flags = 0; btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); key.offset = num_blocks; ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path, 0, 1); if (ret < 0) return ret; if (ret != 0) { BUG(); } Loading Loading @@ -442,12 +454,14 @@ static int lookup_extent_ref(struct btrfs_trans_handle *trans, btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path, 0, 0); if (ret < 0) goto out; if (ret != 0) BUG(); l = btrfs_buffer_leaf(path->nodes[0]); item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item); *refs = btrfs_extent_refs(item); btrfs_release_path(root->fs_info->extent_root, path); out: btrfs_free_path(path); return 0; } Loading @@ -469,6 +483,8 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, int i; int leaf; int ret; int faili; int err; if (!root->ref_cows) return 0; Loading @@ -491,14 +507,45 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, continue; ret = btrfs_inc_extent_ref(trans, root, disk_blocknr, btrfs_file_extent_disk_num_blocks(fi)); BUG_ON(ret); if (ret) { faili = i; goto fail; } } else { blocknr = btrfs_node_blockptr(buf_node, i); ret = btrfs_inc_extent_ref(trans, root, blocknr, 1); BUG_ON(ret); if (ret) { faili = i; goto fail; } } } return 0; fail: for (i =0; i < faili; i++) { if (leaf) { u64 disk_blocknr; key = &buf_leaf->items[i].key; if (btrfs_disk_key_type(key) != BTRFS_EXTENT_DATA_KEY) continue; fi = btrfs_item_ptr(buf_leaf, i, struct btrfs_file_extent_item); if (btrfs_file_extent_type(fi) == BTRFS_FILE_EXTENT_INLINE) continue; disk_blocknr = btrfs_file_extent_disk_blocknr(fi); if (disk_blocknr == 0) continue; err = btrfs_free_extent(trans, root, disk_blocknr, btrfs_file_extent_disk_num_blocks(fi), 0); BUG_ON(err); } else { blocknr = btrfs_node_blockptr(buf_node, i); err = btrfs_free_extent(trans, root, blocknr, 1, 0); BUG_ON(err); } } return ret; } static int write_one_cache_group(struct btrfs_trans_handle *trans, Loading @@ -512,15 +559,20 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans, struct btrfs_block_group_item *bi; struct btrfs_key ins; find_free_extent(trans, extent_root, 0, 0, (u64)-1, 0, &ins, 0); ret = find_free_extent(trans, extent_root, 0, 0, (u64)-1, 0, &ins, 0); /* FIXME, set bit to recalc cache groups on next mount */ if (ret) return ret; ret = btrfs_search_slot(trans, extent_root, &cache->key, path, 0, 1); if (ret < 0) goto fail; BUG_ON(ret); bi = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], struct btrfs_block_group_item); memcpy(bi, &cache->item, sizeof(*bi)); mark_buffer_dirty(path->nodes[0]); btrfs_release_path(extent_root, path); fail: finish_current_insert(trans, extent_root); pending_ret = del_pending_extents(trans, extent_root); if (ret) Loading @@ -543,6 +595,7 @@ static int write_dirty_block_radix(struct btrfs_trans_handle *trans, int werr = 0; int i; struct btrfs_path *path; unsigned long off = 0; path = btrfs_alloc_path(); if (!path) Loading @@ -550,18 +603,28 @@ static int write_dirty_block_radix(struct btrfs_trans_handle *trans, while(1) { ret = radix_tree_gang_lookup_tag(radix, (void **)cache, 0, ARRAY_SIZE(cache), off, ARRAY_SIZE(cache), BTRFS_BLOCK_GROUP_DIRTY); if (!ret) break; for (i = 0; i < ret; i++) { radix_tree_tag_clear(radix, cache[i]->key.objectid + cache[i]->key.offset - 1, BTRFS_BLOCK_GROUP_DIRTY); err = write_one_cache_group(trans, root, path, cache[i]); if (err) /* * if we fail to write the cache group, we want * to keep it marked dirty in hopes that a later * write will work */ if (err) { werr = err; off = cache[i]->key.objectid + cache[i]->key.offset; continue; } radix_tree_tag_clear(radix, cache[i]->key.objectid + cache[i]->key.offset - 1, BTRFS_BLOCK_GROUP_DIRTY); } } btrfs_free_path(path); Loading Loading @@ -801,14 +864,20 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); key.offset = num_blocks; find_free_extent(trans, root, 0, 0, (u64)-1, 0, &ins, 0); path = btrfs_alloc_path(); BUG_ON(!path); if (!path) return -ENOMEM; ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1); ret = find_free_extent(trans, root, 0, 0, (u64)-1, 0, &ins, 0); if (ret) { BUG(); btrfs_free_path(path); return ret; } ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1); if (ret < 0) return ret; BUG_ON(ret); ei = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], struct btrfs_extent_item); BUG_ON(ei->refs == 0); Loading @@ -827,8 +896,9 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root btrfs_set_super_blocks_used(info->disk_super, super_blocks_used - num_blocks); ret = btrfs_del_item(trans, extent_root, path); if (ret) BUG(); if (ret) { return ret; } ret = update_block_group(trans, root, blocknr, num_blocks, 0, mark_free, 0); BUG_ON(ret); Loading Loading @@ -1075,7 +1145,6 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root path->slots[0]++; cond_resched(); } // FIXME -ENOSPC check_pending: /* we have to make sure we didn't find an extent that has already * been allocated by the map tree or the original allocation Loading Loading @@ -1246,6 +1315,14 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, ret = find_free_extent(trans, root, num_blocks, search_start, search_end, hint_block, ins, data); if (ret) { if (search_start == 0) return ret; search_end = search_start - 1; search_start = 0; hint_block = search_start; ret = find_free_extent(trans, root, num_blocks, search_start, search_end, hint_block, ins, data); if (ret) return ret; } Loading @@ -1271,6 +1348,15 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, search_end, hint_block, &prealloc_key, 0); if (ret) { if (search_start == 0) return ret; search_end = search_start - 1; search_start = 0; hint_block = search_start; ret = find_free_extent(trans, root, 0, search_start, search_end, hint_block, &prealloc_key, 0); if (ret) return ret; } } Loading Loading @@ -1309,11 +1395,14 @@ struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, ret = btrfs_alloc_extent(trans, root, root->root_key.objectid, 1, hint, (unsigned long)-1, &ins, 0); if (ret) { BUG(); return NULL; BUG_ON(ret > 0); return ERR_PTR(ret); } BUG_ON(ret); buf = btrfs_find_create_tree_block(root, ins.objectid); if (!buf) { btrfs_free_extent(trans, root, ins.objectid, 1, 0); return ERR_PTR(-ENOMEM); } set_buffer_uptodate(buf); set_buffer_checked(buf); set_radix_bit(&trans->transaction->dirty_pages, buf->b_page->index); Loading