diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r-- | fs/btrfs/tree-log.c | 362 |
1 files changed, 96 insertions, 266 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 39d83da03e03..79f057c0619a 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -26,6 +26,7 @@ #include "locking.h" #include "print-tree.h" #include "backref.h" +#include "compat.h" #include "tree-log.h" #include "hash.h" @@ -570,7 +571,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, if (btrfs_file_extent_disk_bytenr(eb, item) == 0) nbytes = 0; } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { - size = btrfs_file_extent_inline_len(eb, slot, item); + size = btrfs_file_extent_inline_len(eb, item); nbytes = btrfs_file_extent_ram_bytes(eb, item); extent_end = ALIGN(start + size, root->sectorsize); } else { @@ -935,7 +936,7 @@ again: parent_objectid, victim_name, victim_name_len)) { - inc_nlink(inode); + btrfs_inc_nlink(inode); btrfs_release_path(path); ret = btrfs_unlink_inode(trans, root, dir, @@ -1005,7 +1006,7 @@ again: victim_parent = read_one_inode(root, parent_objectid); if (victim_parent) { - inc_nlink(inode); + btrfs_inc_nlink(inode); btrfs_release_path(path); ret = btrfs_unlink_inode(trans, root, @@ -1112,11 +1113,11 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, struct extent_buffer *eb, int slot, struct btrfs_key *key) { - struct inode *dir = NULL; - struct inode *inode = NULL; + struct inode *dir; + struct inode *inode; unsigned long ref_ptr; unsigned long ref_end; - char *name = NULL; + char *name; int namelen; int ret; int search_done = 0; @@ -1149,15 +1150,13 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, * care of the rest */ dir = read_one_inode(root, parent_objectid); - if (!dir) { - ret = -ENOENT; - goto out; - } + if (!dir) + return -ENOENT; inode = read_one_inode(root, inode_objectid); if (!inode) { - ret = -EIO; - goto out; + iput(dir); + return -EIO; } while (ref_ptr < ref_end) { @@ -1170,16 +1169,14 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, */ if (!dir) dir = read_one_inode(root, parent_objectid); - if (!dir) { - ret = -ENOENT; - goto out; - } + if (!dir) + return -ENOENT; } else { ret = ref_get_fields(eb, ref_ptr, &namelen, &name, &ref_index); } if (ret) - goto out; + return ret; /* if we already have a perfect match, we're done */ if (!inode_in_dir(root, path, btrfs_ino(dir), btrfs_ino(inode), @@ -1199,11 +1196,12 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, parent_objectid, ref_index, name, namelen, &search_done); - if (ret) { - if (ret == 1) - ret = 0; + if (ret == 1) { + ret = 0; goto out; } + if (ret) + goto out; } /* insert our name */ @@ -1217,7 +1215,6 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, ref_ptr = (unsigned long)(ref_ptr + ref_struct_size) + namelen; kfree(name); - name = NULL; if (log_ref_ver) { iput(dir); dir = NULL; @@ -1228,7 +1225,6 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, ret = overwrite_item(trans, root, path, eb, slot, key); out: btrfs_release_path(path); - kfree(name); iput(dir); iput(inode); return ret; @@ -1238,8 +1234,7 @@ static int insert_orphan_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 offset) { int ret; - ret = btrfs_find_item(root, NULL, BTRFS_ORPHAN_OBJECTID, - offset, BTRFS_ORPHAN_ITEM_KEY, NULL); + ret = btrfs_find_orphan_item(root, offset); if (ret > 0) ret = btrfs_insert_orphan_item(trans, root, offset); return ret; @@ -1312,7 +1307,6 @@ static int count_inode_refs(struct btrfs_root *root, break; path->slots[0]--; } -process_slot: btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); if (key.objectid != ino || @@ -1333,10 +1327,6 @@ process_slot: if (key.offset == 0) break; - if (path->slots[0] > 0) { - path->slots[0]--; - goto process_slot; - } key.offset--; btrfs_release_path(path); } @@ -1490,7 +1480,7 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans, if (!inode->i_nlink) set_nlink(inode, 1); else - inc_nlink(inode); + btrfs_inc_nlink(inode); ret = btrfs_update_inode(trans, root, inode); } else if (ret == -EEXIST) { ret = 0; @@ -1833,7 +1823,7 @@ again: dir_key->offset, name, name_len, 0); } - if (!log_di || (IS_ERR(log_di) && PTR_ERR(log_di) == -ENOENT)) { + if (IS_ERR_OR_NULL(log_di)) { btrfs_dir_item_key_to_cpu(eb, di, &location); btrfs_release_path(path); btrfs_release_path(log_path); @@ -1851,7 +1841,7 @@ again: goto out; } - inc_nlink(inode); + btrfs_inc_nlink(inode); ret = btrfs_unlink_inode(trans, root, dir, inode, name, name_len); if (!ret) @@ -1870,9 +1860,6 @@ again: goto again; ret = 0; goto out; - } else if (IS_ERR(log_di)) { - kfree(name); - return PTR_ERR(log_di); } btrfs_release_path(log_path); kfree(name); @@ -2131,7 +2118,8 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans, WARN_ON(*level >= BTRFS_MAX_LEVEL); cur = path->nodes[*level]; - WARN_ON(btrfs_header_level(cur) != *level); + if (btrfs_header_level(cur) != *level) + WARN_ON(1); if (path->slots[*level] >= btrfs_header_nritems(cur)) @@ -2163,13 +2151,11 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans, return ret; } - if (trans) { - btrfs_tree_lock(next); - btrfs_set_lock_blocking(next); - clean_tree_block(trans, root, next); - btrfs_wait_tree_block_writeback(next); - btrfs_tree_unlock(next); - } + btrfs_tree_lock(next); + btrfs_set_lock_blocking(next); + clean_tree_block(trans, root, next); + btrfs_wait_tree_block_writeback(next); + btrfs_tree_unlock(next); WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID); @@ -2241,13 +2227,11 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans, next = path->nodes[*level]; - if (trans) { - btrfs_tree_lock(next); - btrfs_set_lock_blocking(next); - clean_tree_block(trans, root, next); - btrfs_wait_tree_block_writeback(next); - btrfs_tree_unlock(next); - } + btrfs_tree_lock(next); + btrfs_set_lock_blocking(next); + clean_tree_block(trans, root, next); + btrfs_wait_tree_block_writeback(next); + btrfs_tree_unlock(next); WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID); ret = btrfs_free_and_pin_reserved_extent(root, @@ -2317,13 +2301,11 @@ static int walk_log_tree(struct btrfs_trans_handle *trans, next = path->nodes[orig_level]; - if (trans) { - btrfs_tree_lock(next); - btrfs_set_lock_blocking(next); - clean_tree_block(trans, log, next); - btrfs_wait_tree_block_writeback(next); - btrfs_tree_unlock(next); - } + btrfs_tree_lock(next); + btrfs_set_lock_blocking(next); + clean_tree_block(trans, log, next); + btrfs_wait_tree_block_writeback(next); + btrfs_tree_unlock(next); WARN_ON(log->root_key.objectid != BTRFS_TREE_LOG_OBJECTID); @@ -2589,7 +2571,9 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, * the running transaction open, so a full commit can't hop * in and cause problems either. */ + btrfs_scrub_pause_super(root); ret = write_ctree_super(trans, root->fs_info->tree_root, 1); + btrfs_scrub_continue_super(root); if (ret) { btrfs_abort_transaction(trans, root, ret); goto out_wake_log_root; @@ -2624,10 +2608,13 @@ static void free_log_tree(struct btrfs_trans_handle *trans, .process_func = process_one_buffer }; - ret = walk_log_tree(trans, log, &wc); - /* I don't think this can happen but just in case */ - if (ret) - btrfs_abort_transaction(trans, log, ret); + if (trans) { + ret = walk_log_tree(trans, log, &wc); + + /* I don't think this can happen but just in case */ + if (ret) + btrfs_abort_transaction(trans, log, ret); + } while (1) { ret = find_first_extent_bit(&log->dirty_log_pages, @@ -2880,6 +2867,7 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, u64 min_offset, u64 *last_offset_ret) { struct btrfs_key min_key; + struct btrfs_key max_key; struct btrfs_root *log = root->log_root; struct extent_buffer *src; int err = 0; @@ -2891,6 +2879,9 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, u64 ino = btrfs_ino(inode); log = root->log_root; + max_key.objectid = ino; + max_key.offset = (u64)-1; + max_key.type = key_type; min_key.objectid = ino; min_key.type = key_type; @@ -2898,7 +2889,8 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, path->keep_locks = 1; - ret = btrfs_search_forward(root, &min_key, path, trans->transid); + ret = btrfs_search_forward(root, &min_key, &max_key, + path, trans->transid); /* * we didn't find anything from this transaction, see if there @@ -2951,8 +2943,10 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, /* find the first key from this transaction again */ ret = btrfs_search_slot(NULL, root, &min_key, path, 0, 0); - if (WARN_ON(ret != 0)) + if (ret != 0) { + WARN_ON(1); goto done; + } /* * we have a block from this transaction, log every item in it @@ -3178,10 +3172,11 @@ static int log_inode_item(struct btrfs_trans_handle *trans, struct inode *inode) { struct btrfs_inode_item *inode_item; + struct btrfs_key key; int ret; - ret = btrfs_insert_empty_item(trans, log, path, - &BTRFS_I(inode)->location, + memcpy(&key, &BTRFS_I(inode)->location, sizeof(key)); + ret = btrfs_insert_empty_item(trans, log, path, &key, sizeof(*inode_item)); if (ret && ret != -EEXIST) return ret; @@ -3195,7 +3190,7 @@ static int log_inode_item(struct btrfs_trans_handle *trans, static noinline int copy_items(struct btrfs_trans_handle *trans, struct inode *inode, struct btrfs_path *dst_path, - struct btrfs_path *src_path, u64 *last_extent, + struct extent_buffer *src, int start_slot, int nr, int inode_only) { unsigned long src_offset; @@ -3203,8 +3198,6 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, struct btrfs_root *log = BTRFS_I(inode)->root->log_root; struct btrfs_file_extent_item *extent; struct btrfs_inode_item *inode_item; - struct extent_buffer *src = src_path->nodes[0]; - struct btrfs_key first_key, last_key, key; int ret; struct btrfs_key *ins_keys; u32 *ins_sizes; @@ -3212,9 +3205,6 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, int i; struct list_head ordered_sums; int skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; - bool has_extents = false; - bool need_find_last_extent = (*last_extent == 0); - bool done = false; INIT_LIST_HEAD(&ordered_sums); @@ -3223,8 +3213,6 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, if (!ins_data) return -ENOMEM; - first_key.objectid = (u64)-1; - ins_sizes = (u32 *)ins_data; ins_keys = (struct btrfs_key *)(ins_data + nr * sizeof(u32)); @@ -3245,9 +3233,6 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, src_offset = btrfs_item_ptr_offset(src, start_slot + i); - if ((i == (nr - 1))) - last_key = ins_keys[i]; - if (ins_keys[i].type == BTRFS_INODE_ITEM_KEY) { inode_item = btrfs_item_ptr(dst_path->nodes[0], dst_path->slots[0], @@ -3259,21 +3244,6 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, src_offset, ins_sizes[i]); } - /* - * We set need_find_last_extent here in case we know we were - * processing other items and then walk into the first extent in - * the inode. If we don't hit an extent then nothing changes, - * we'll do the last search the next time around. - */ - if (ins_keys[i].type == BTRFS_EXTENT_DATA_KEY) { - has_extents = true; - if (need_find_last_extent && - first_key.objectid == (u64)-1) - first_key = ins_keys[i]; - } else { - need_find_last_extent = false; - } - /* take a reference on file data extents so that truncates * or deletes of this inode don't have to relog the inode * again @@ -3338,128 +3308,6 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, list_del(&sums->list); kfree(sums); } - - if (!has_extents) - return ret; - - /* - * Because we use btrfs_search_forward we could skip leaves that were - * not modified and then assume *last_extent is valid when it really - * isn't. So back up to the previous leaf and read the end of the last - * extent before we go and fill in holes. - */ - if (need_find_last_extent) { - u64 len; - - ret = btrfs_prev_leaf(BTRFS_I(inode)->root, src_path); - if (ret < 0) - return ret; - if (ret) - goto fill_holes; - if (src_path->slots[0]) - src_path->slots[0]--; - src = src_path->nodes[0]; - btrfs_item_key_to_cpu(src, &key, src_path->slots[0]); - if (key.objectid != btrfs_ino(inode) || - key.type != BTRFS_EXTENT_DATA_KEY) - goto fill_holes; - extent = btrfs_item_ptr(src, src_path->slots[0], - struct btrfs_file_extent_item); - if (btrfs_file_extent_type(src, extent) == - BTRFS_FILE_EXTENT_INLINE) { - len = btrfs_file_extent_inline_len(src, - src_path->slots[0], - extent); - *last_extent = ALIGN(key.offset + len, - log->sectorsize); - } else { - len = btrfs_file_extent_num_bytes(src, extent); - *last_extent = key.offset + len; - } - } -fill_holes: - /* So we did prev_leaf, now we need to move to the next leaf, but a few - * things could have happened - * - * 1) A merge could have happened, so we could currently be on a leaf - * that holds what we were copying in the first place. - * 2) A split could have happened, and now not all of the items we want - * are on the same leaf. - * - * So we need to adjust how we search for holes, we need to drop the - * path and re-search for the first extent key we found, and then walk - * forward until we hit the last one we copied. - */ - if (need_find_last_extent) { - /* btrfs_prev_leaf could return 1 without releasing the path */ - btrfs_release_path(src_path); - ret = btrfs_search_slot(NULL, BTRFS_I(inode)->root, &first_key, - src_path, 0, 0); - if (ret < 0) - return ret; - ASSERT(ret == 0); - src = src_path->nodes[0]; - i = src_path->slots[0]; - } else { - i = start_slot; - } - - /* - * Ok so here we need to go through and fill in any holes we may have - * to make sure that holes are punched for those areas in case they had - * extents previously. - */ - while (!done) { - u64 offset, len; - u64 extent_end; - - if (i >= btrfs_header_nritems(src_path->nodes[0])) { - ret = btrfs_next_leaf(BTRFS_I(inode)->root, src_path); - if (ret < 0) - return ret; - ASSERT(ret == 0); - src = src_path->nodes[0]; - i = 0; - } - - btrfs_item_key_to_cpu(src, &key, i); - if (!btrfs_comp_cpu_keys(&key, &last_key)) - done = true; - if (key.objectid != btrfs_ino(inode) || - key.type != BTRFS_EXTENT_DATA_KEY) { - i++; - continue; - } - extent = btrfs_item_ptr(src, i, struct btrfs_file_extent_item); - if (btrfs_file_extent_type(src, extent) == - BTRFS_FILE_EXTENT_INLINE) { - len = btrfs_file_extent_inline_len(src, i, extent); - extent_end = ALIGN(key.offset + len, log->sectorsize); - } else { - len = btrfs_file_extent_num_bytes(src, extent); - extent_end = key.offset + len; - } - i++; - - if (*last_extent == key.offset) { - *last_extent = extent_end; - continue; - } - offset = *last_extent; - len = key.offset - *last_extent; - ret = btrfs_insert_file_extent(trans, log, btrfs_ino(inode), - offset, 0, 0, len, 0, len, 0, - 0, 0); - if (ret) - break; - *last_extent = offset + len; - } - /* - * Need to let the callers know we dropped the path so they should - * re-search. - */ - if (!ret && need_find_last_extent) - ret = 1; return ret; } @@ -3497,27 +3345,21 @@ static int log_one_extent(struct btrfs_trans_handle *trans, int ret; int index = log->log_transid % 2; bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; - int extent_inserted = 0; - - INIT_LIST_HEAD(&ordered_sums); - btrfs_init_map_token(&token); ret = __btrfs_drop_extents(trans, log, inode, path, em->start, - em->start + em->len, NULL, 0, 1, - sizeof(*fi), &extent_inserted); + em->start + em->len, NULL, 0); if (ret) return ret; - if (!extent_inserted) { - key.objectid = btrfs_ino(inode); - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = em->start; + INIT_LIST_HEAD(&ordered_sums); + btrfs_init_map_token(&token); + key.objectid = btrfs_ino(inode); + key.type = BTRFS_EXTENT_DATA_KEY; + key.offset = em->start; - ret = btrfs_insert_empty_item(trans, log, path, &key, - sizeof(*fi)); - if (ret) - return ret; - } + ret = btrfs_insert_empty_item(trans, log, path, &key, sizeof(*fi)); + if (ret) + return ret; leaf = path->nodes[0]; fi = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item); @@ -3533,7 +3375,7 @@ static int log_one_extent(struct btrfs_trans_handle *trans, btrfs_set_token_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG, &token); - if (em->block_start == EXTENT_MAP_HOLE) + if (em->block_start == 0) skip_csum = true; } @@ -3575,6 +3417,11 @@ static int log_one_extent(struct btrfs_trans_handle *trans, if (skip_csum) return 0; + if (em->compress_type) { + csum_offset = 0; + csum_len = block_len; + } + /* * First check and see if our csums are on our outstanding ordered * extents. @@ -3639,11 +3486,7 @@ again: * start over after this. */ - if (ordered->csum_bytes_left) { - btrfs_start_ordered_extent(inode, ordered, 0); - wait_event(ordered->wait, - ordered->csum_bytes_left == 0); - } + wait_event(ordered->wait, ordered->csum_bytes_left == 0); list_for_each_entry(sum, &ordered->list, list) { ret = btrfs_csum_file_blocks(trans, log, sum); @@ -3662,13 +3505,8 @@ unlocked: if (!mod_len || ret) return ret; - if (em->compress_type) { - csum_offset = 0; - csum_len = block_len; - } else { - csum_offset = mod_start - em->start; - csum_len = mod_len; - } + csum_offset = mod_start - em->start; + csum_len = mod_len; /* block start is already adjusted for the file extent offset. */ ret = btrfs_lookup_csums_range(log->fs_info->csum_root, @@ -3788,7 +3626,6 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, struct btrfs_key max_key; struct btrfs_root *log = root->log_root; struct extent_buffer *src = NULL; - u64 last_extent = 0; int err = 0; int ret; int nritems; @@ -3856,8 +3693,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, ret = btrfs_truncate_inode_items(trans, log, inode, 0, 0); } else if (test_and_clear_bit(BTRFS_INODE_COPY_EVERYTHING, - &BTRFS_I(inode)->runtime_flags) || - inode_only == LOG_INODE_EXISTS) { + &BTRFS_I(inode)->runtime_flags)) { if (inode_only == LOG_INODE_ALL) fast_search = true; max_key.type = BTRFS_XATTR_ITEM_KEY; @@ -3883,7 +3719,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, while (1) { ins_nr = 0; - ret = btrfs_search_forward(root, &min_key, + ret = btrfs_search_forward(root, &min_key, &max_key, path, trans->transid); if (ret != 0) break; @@ -3904,15 +3740,11 @@ again: goto next_slot; } - ret = copy_items(trans, inode, dst_path, path, &last_extent, - ins_start_slot, ins_nr, inode_only); - if (ret < 0) { + ret = copy_items(trans, inode, dst_path, src, ins_start_slot, + ins_nr, inode_only); + if (ret) { err = ret; goto out_unlock; - } if (ret) { - ins_nr = 0; - btrfs_release_path(path); - continue; } ins_nr = 1; ins_start_slot = path->slots[0]; @@ -3926,35 +3758,33 @@ next_slot: goto again; } if (ins_nr) { - ret = copy_items(trans, inode, dst_path, path, - &last_extent, ins_start_slot, + ret = copy_items(trans, inode, dst_path, src, + ins_start_slot, ins_nr, inode_only); - if (ret < 0) { + if (ret) { err = ret; goto out_unlock; } - ret = 0; ins_nr = 0; } btrfs_release_path(path); - if (min_key.offset < (u64)-1) { + if (min_key.offset < (u64)-1) min_key.offset++; - } else if (min_key.type < max_key.type) { + else if (min_key.type < (u8)-1) min_key.type++; - min_key.offset = 0; - } else { + else if (min_key.objectid < (u64)-1) + min_key.objectid++; + else break; - } } if (ins_nr) { - ret = copy_items(trans, inode, dst_path, path, &last_extent, - ins_start_slot, ins_nr, inode_only); - if (ret < 0) { + ret = copy_items(trans, inode, dst_path, src, ins_start_slot, + ins_nr, inode_only); + if (ret) { err = ret; goto out_unlock; } - ret = 0; ins_nr = 0; } @@ -3967,7 +3797,7 @@ log_extents: err = ret; goto out_unlock; } - } else if (inode_only == LOG_INODE_ALL) { + } else { struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree; struct extent_map *em, *n; |