diff options
| -rw-r--r-- | fs/btrfs/tree-log.c | 237 |
1 files changed, 186 insertions, 51 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index a4068be25996..776f3dfdfa86 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -433,8 +433,10 @@ static int overwrite_item(struct btrfs_trans_handle *trans, /* Look for the key in the destination tree. */ ret = btrfs_search_slot(NULL, root, key, path, 0, 0); - if (ret < 0) + if (ret < 0) { + btrfs_abort_transaction(trans, ret); return ret; + } dst_eb = path->nodes[0]; dst_slot = path->slots[0]; @@ -453,6 +455,7 @@ static int overwrite_item(struct btrfs_trans_handle *trans, src_copy = kmalloc(item_size, GFP_NOFS); if (!src_copy) { btrfs_release_path(path); + btrfs_abort_transaction(trans, -ENOMEM); return -ENOMEM; } @@ -537,6 +540,7 @@ insert: else if (found_size < item_size) btrfs_extend_item(trans, path, item_size - found_size); } else if (ret) { + btrfs_abort_transaction(trans, ret); return ret; } dst_ptr = btrfs_item_ptr_offset(dst_eb, dst_slot); @@ -667,6 +671,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, extent_end = ALIGN(start + size, fs_info->sectorsize); } else { + btrfs_abort_transaction(trans, -EUCLEAN); btrfs_err(fs_info, "unexpected extent type=%d root=%llu inode=%llu offset=%llu", found_type, btrfs_root_id(root), key->objectid, key->offset); @@ -674,8 +679,11 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, } inode = btrfs_iget_logging(key->objectid, root); - if (IS_ERR(inode)) - return PTR_ERR(inode); + if (IS_ERR(inode)) { + ret = PTR_ERR(inode); + btrfs_abort_transaction(trans, ret); + return ret; + } /* * first check to see if we already have this extent in the @@ -710,8 +718,10 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, drop_args.end = extent_end; drop_args.drop_cache = true; ret = btrfs_drop_extents(trans, root, inode, &drop_args); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); goto out; + } if (found_type == BTRFS_FILE_EXTENT_REG || found_type == BTRFS_FILE_EXTENT_PREALLOC) { @@ -725,8 +735,10 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, ret = btrfs_insert_empty_item(trans, root, path, key, sizeof(*item)); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); goto out; + } dest_offset = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]); copy_extent_buffer(path->nodes[0], eb, dest_offset, @@ -748,8 +760,10 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, ret = btrfs_qgroup_trace_extent(trans, btrfs_file_extent_disk_bytenr(eb, item), btrfs_file_extent_disk_num_bytes(eb, item)); - if (ret < 0) + if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out; + } if (ins.objectid > 0) { u64 csum_start; @@ -763,6 +777,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, ret = btrfs_lookup_data_extent(fs_info, ins.objectid, ins.offset); if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out; } else if (ret == 0) { struct btrfs_ref ref = { @@ -775,8 +790,10 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, btrfs_init_data_ref(&ref, key->objectid, offset, 0, false); ret = btrfs_inc_extent_ref(trans, &ref); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); goto out; + } } else { /* * insert the extent pointer in the extent @@ -785,8 +802,10 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, ret = btrfs_alloc_logged_file_extent(trans, btrfs_root_id(root), key->objectid, offset, &ins); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); goto out; + } } btrfs_release_path(path); @@ -803,8 +822,10 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, ret = btrfs_lookup_csums_list(root->log_root, csum_start, csum_end - 1, &ordered_sums, false); - if (ret < 0) + if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out; + } ret = 0; /* * Now delete all existing cums in the csum root that @@ -864,14 +885,20 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, list); csum_root = btrfs_csum_root(fs_info, sums->logical); - if (!ret) + if (!ret) { ret = btrfs_del_csums(trans, csum_root, sums->logical, sums->len); - if (!ret) + if (ret) + btrfs_abort_transaction(trans, ret); + } + if (!ret) { ret = btrfs_csum_file_blocks(trans, csum_root, sums); + if (ret) + btrfs_abort_transaction(trans, ret); + } list_del(&sums->list); kfree(sums); } @@ -888,12 +915,16 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, } ret = btrfs_inode_set_file_extent_range(inode, start, extent_end - start); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); goto out; + } update_inode: btrfs_update_inode_bytes(inode, nbytes, drop_args.bytes_found); ret = btrfs_update_inode(trans, inode); + if (ret) + btrfs_abort_transaction(trans, ret); out: iput(&inode->vfs_inode); return ret; @@ -907,15 +938,20 @@ static int unlink_inode_for_log_replay(struct btrfs_trans_handle *trans, int ret; ret = btrfs_unlink_inode(trans, dir, inode, name); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); return ret; + } /* * Whenever we need to check if a name exists or not, we check the * fs/subvolume tree. So after an unlink we must run delayed items, so * that future checks for a name during log replay see that the name * does not exists anymore. */ - return btrfs_run_delayed_items(trans); + ret = btrfs_run_delayed_items(trans); + if (ret) + btrfs_abort_transaction(trans, ret); + return ret; } /* @@ -942,14 +978,17 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans, btrfs_dir_item_key_to_cpu(leaf, di, &location); ret = read_alloc_one_name(leaf, di + 1, btrfs_dir_name_len(leaf, di), &name); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); return ret; + } btrfs_release_path(path); inode = btrfs_iget_logging(location.objectid, root); if (IS_ERR(inode)) { ret = PTR_ERR(inode); + btrfs_abort_transaction(trans, ret); inode = NULL; goto out; } @@ -1080,14 +1119,18 @@ static int unlink_refs_not_in_log(struct btrfs_trans_handle *trans, ret = read_alloc_one_name(leaf, (victim_ref + 1), btrfs_inode_ref_name_len(leaf, victim_ref), &victim_name); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); return ret; + } ret = backref_in_log(log_root, search_key, parent_objectid, &victim_name); if (ret) { kfree(victim_name.name); - if (ret < 0) + if (ret < 0) { + btrfs_abort_transaction(trans, ret); return ret; + } ptr = (unsigned long)(victim_ref + 1) + victim_name.len; continue; } @@ -1133,8 +1176,10 @@ static int unlink_extrefs_not_in_log(struct btrfs_trans_handle *trans, ret = read_alloc_one_name(leaf, &extref->name, victim_name.len, &victim_name); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); return ret; + } search_key->objectid = inode_objectid; search_key->type = BTRFS_INODE_EXTREF_KEY; @@ -1144,8 +1189,10 @@ static int unlink_extrefs_not_in_log(struct btrfs_trans_handle *trans, ret = backref_in_log(log_root, search_key, parent_objectid, &victim_name); if (ret) { kfree(victim_name.name); - if (ret < 0) + if (ret < 0) { + btrfs_abort_transaction(trans, ret); return ret; + } next: cur_offset += victim_name.len + sizeof(*extref); continue; @@ -1154,7 +1201,9 @@ next: victim_parent = btrfs_iget_logging(parent_objectid, root); if (IS_ERR(victim_parent)) { kfree(victim_name.name); - return PTR_ERR(victim_parent); + ret = PTR_ERR(victim_parent); + btrfs_abort_transaction(trans, ret); + return ret; } inc_nlink(&inode->vfs_inode); @@ -1193,6 +1242,7 @@ again: search_key.offset = parent_objectid; ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0); if (ret < 0) { + btrfs_abort_transaction(trans, ret); return ret; } else if (ret == 0) { /* @@ -1230,7 +1280,9 @@ again: di = btrfs_lookup_dir_index_item(trans, root, path, btrfs_ino(dir), ref_index, name, 0); if (IS_ERR(di)) { - return PTR_ERR(di); + ret = PTR_ERR(di); + btrfs_abort_transaction(trans, ret); + return ret; } else if (di) { ret = drop_one_dir_item(trans, path, dir, di); if (ret) @@ -1320,8 +1372,10 @@ again: ret = 0; goto out; } - if (ret < 0) + if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out; + } eb = path->nodes[0]; ref_ptr = btrfs_item_ptr_offset(eb, path->slots[0]); @@ -1333,12 +1387,18 @@ again: if (key->type == BTRFS_INODE_EXTREF_KEY) { ret = extref_get_fields(eb, ref_ptr, &name, NULL, &parent_id); + if (ret) { + btrfs_abort_transaction(trans, ret); + goto out; + } } else { parent_id = key->offset; ret = ref_get_fields(eb, ref_ptr, &name, NULL); + if (ret) { + btrfs_abort_transaction(trans, ret); + goto out; + } } - if (ret) - goto out; if (key->type == BTRFS_INODE_EXTREF_KEY) ret = !!btrfs_find_name_in_ext_backref(log_eb, log_slot, @@ -1354,6 +1414,7 @@ again: if (IS_ERR(dir)) { ret = PTR_ERR(dir); kfree(name.name); + btrfs_abort_transaction(trans, ret); goto out; } ret = unlink_inode_for_log_replay(trans, dir, inode, &name); @@ -1428,6 +1489,8 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, ret = PTR_ERR(dir); if (ret == -ENOENT) ret = 0; + else + btrfs_abort_transaction(trans, ret); dir = NULL; goto out; } @@ -1435,6 +1498,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, inode = btrfs_iget_logging(inode_objectid, root); if (IS_ERR(inode)) { ret = PTR_ERR(inode); + btrfs_abort_transaction(trans, ret); inode = NULL; goto out; } @@ -1443,8 +1507,10 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, if (is_extref_item) { ret = extref_get_fields(eb, ref_ptr, &name, &ref_index, &parent_objectid); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); goto out; + } /* * parent object can change from one array * item to another. @@ -1469,19 +1535,24 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, */ ret = 0; goto next; + } else { + btrfs_abort_transaction(trans, ret); } goto out; } } } else { ret = ref_get_fields(eb, ref_ptr, &name, &ref_index); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); goto out; + } } ret = inode_in_dir(root, path, btrfs_ino(dir), btrfs_ino(inode), ref_index, &name); if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out; } else if (ret == 0) { /* @@ -1502,12 +1573,16 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, /* insert our name */ ret = btrfs_add_link(trans, dir, inode, &name, 0, ref_index); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); goto out; + } ret = btrfs_update_inode(trans, inode); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); goto out; + } } /* Else, ret == 1, we already have a perfect match, we're done. */ @@ -1779,8 +1854,11 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans, struct inode *vfs_inode; inode = btrfs_iget_logging(objectid, root); - if (IS_ERR(inode)) - return PTR_ERR(inode); + if (IS_ERR(inode)) { + ret = PTR_ERR(inode); + btrfs_abort_transaction(trans, ret); + return ret; + } vfs_inode = &inode->vfs_inode; key.objectid = BTRFS_TREE_LOG_FIXUP_OBJECTID; @@ -1798,6 +1876,8 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans, ret = btrfs_update_inode(trans, inode); } else if (ret == -EEXIST) { ret = 0; + } else { + btrfs_abort_transaction(trans, ret); } iput(vfs_inode); @@ -1904,19 +1984,26 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, bool name_added = false; dir = btrfs_iget_logging(key->objectid, root); - if (IS_ERR(dir)) - return PTR_ERR(dir); + if (IS_ERR(dir)) { + ret = PTR_ERR(dir); + btrfs_abort_transaction(trans, ret); + return ret; + } ret = read_alloc_one_name(eb, di + 1, btrfs_dir_name_len(eb, di), &name); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); goto out; + } log_flags = btrfs_dir_flags(eb, di); btrfs_dir_item_key_to_cpu(eb, di, &log_key); ret = btrfs_lookup_inode(trans, root, path, &log_key, 0); btrfs_release_path(path); - if (ret < 0) + if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out; + } exists = (ret == 0); ret = 0; @@ -1924,12 +2011,15 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, &name, 1); if (IS_ERR(dir_dst_di)) { ret = PTR_ERR(dir_dst_di); + btrfs_abort_transaction(trans, ret); goto out; } else if (dir_dst_di) { ret = delete_conflicting_dir_entry(trans, dir, path, dir_dst_di, &log_key, log_flags, exists); - if (ret < 0) + if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out; + } dir_dst_matches = (ret == 1); } @@ -1940,12 +2030,15 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, &name, 1); if (IS_ERR(index_dst_di)) { ret = PTR_ERR(index_dst_di); + btrfs_abort_transaction(trans, ret); goto out; } else if (index_dst_di) { ret = delete_conflicting_dir_entry(trans, dir, path, index_dst_di, &log_key, log_flags, exists); - if (ret < 0) + if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out; + } index_dst_matches = (ret == 1); } @@ -1966,6 +2059,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, search_key.offset = key->objectid; ret = backref_in_log(root->log_root, &search_key, 0, &name); if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out; } else if (ret) { /* The dentry will be added later. */ @@ -1979,6 +2073,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, search_key.offset = btrfs_extref_hash(key->objectid, name.name, name.len); ret = backref_in_log(root->log_root, &search_key, key->objectid, &name); if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out; } else if (ret) { /* The dentry will be added later. */ @@ -1989,8 +2084,10 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, btrfs_release_path(path); ret = insert_one_name(trans, root, key->objectid, key->offset, &name, &log_key); - if (ret && ret != -ENOENT && ret != -EEXIST) + if (ret && ret != -ENOENT && ret != -EEXIST) { + btrfs_abort_transaction(trans, ret); goto out; + } if (!ret) name_added = true; update_size = false; @@ -2000,6 +2097,8 @@ out: if (!ret && update_size) { btrfs_i_size_write(dir, dir->vfs_inode.i_size + name.len * 2); ret = btrfs_update_inode(trans, dir); + if (ret) + btrfs_abort_transaction(trans, ret); } kfree(name.name); iput(&dir->vfs_inode); @@ -2057,8 +2156,10 @@ static noinline int replay_one_dir_item(struct btrfs_trans_handle *trans, struct btrfs_key di_key; fixup_path = btrfs_alloc_path(); - if (!fixup_path) + if (!fixup_path) { + btrfs_abort_transaction(trans, -ENOMEM); return -ENOMEM; + } btrfs_dir_item_key_to_cpu(eb, di, &di_key); ret = link_to_fixup_dir(trans, root, fixup_path, di_key.objectid); @@ -2183,8 +2284,10 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans, slot = path->slots[0]; di = btrfs_item_ptr(eb, slot, struct btrfs_dir_item); ret = read_alloc_one_name(eb, di + 1, btrfs_dir_name_len(eb, di), &name); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); goto out; + } if (log) { struct btrfs_dir_item *log_di; @@ -2194,6 +2297,7 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans, dir_key->offset, &name, 0); if (IS_ERR(log_di)) { ret = PTR_ERR(log_di); + btrfs_abort_transaction(trans, ret); goto out; } else if (log_di) { /* The dentry exists in the log, we have nothing to do. */ @@ -2209,6 +2313,7 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans, if (IS_ERR(inode)) { ret = PTR_ERR(inode); inode = NULL; + btrfs_abort_transaction(trans, ret); goto out; } @@ -2245,16 +2350,20 @@ static int replay_xattr_deletes(struct btrfs_trans_handle *trans, int ret; log_path = btrfs_alloc_path(); - if (!log_path) + if (!log_path) { + btrfs_abort_transaction(trans, -ENOMEM); return -ENOMEM; + } search_key.objectid = ino; search_key.type = BTRFS_XATTR_ITEM_KEY; search_key.offset = 0; again: ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0); - if (ret < 0) + if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out; + } process_leaf: nritems = btrfs_header_nritems(path->nodes[0]); for (i = path->slots[0]; i < nritems; i++) { @@ -2282,6 +2391,7 @@ process_leaf: name = kmalloc(name_len, GFP_NOFS); if (!name) { ret = -ENOMEM; + btrfs_abort_transaction(trans, ret); goto out; } read_extent_buffer(path->nodes[0], name, @@ -2298,13 +2408,16 @@ process_leaf: kfree(name); if (IS_ERR(di)) { ret = PTR_ERR(di); + btrfs_abort_transaction(trans, ret); goto out; } ASSERT(di); ret = btrfs_delete_one_dir_name(trans, root, path, di); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); goto out; + } btrfs_release_path(path); search_key = key; goto again; @@ -2312,6 +2425,7 @@ process_leaf: kfree(name); if (IS_ERR(log_di)) { ret = PTR_ERR(log_di); + btrfs_abort_transaction(trans, ret); goto out; } cur += this_len; @@ -2323,6 +2437,8 @@ process_leaf: ret = 0; else if (ret == 0) goto process_leaf; + else + btrfs_abort_transaction(trans, ret); out: btrfs_free_path(log_path); btrfs_release_path(path); @@ -2357,8 +2473,10 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans, dir_key.objectid = dirid; dir_key.type = BTRFS_DIR_INDEX_KEY; log_path = btrfs_alloc_path(); - if (!log_path) + if (!log_path) { + btrfs_abort_transaction(trans, -ENOMEM); return -ENOMEM; + } dir = btrfs_iget_logging(dirid, root); /* @@ -2370,6 +2488,8 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans, ret = PTR_ERR(dir); if (ret == -ENOENT) ret = 0; + else + btrfs_abort_transaction(trans, ret); return ret; } @@ -2381,10 +2501,12 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans, else { ret = find_dir_range(log, path, dirid, &range_start, &range_end); - if (ret < 0) + if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out; - else if (ret > 0) + } else if (ret > 0) { break; + } } dir_key.offset = range_start; @@ -2392,16 +2514,20 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans, int nritems; ret = btrfs_search_slot(NULL, root, &dir_key, path, 0, 0); - if (ret < 0) + if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out; + } nritems = btrfs_header_nritems(path->nodes[0]); if (path->slots[0] >= nritems) { ret = btrfs_next_leaf(root, path); - if (ret == 1) + if (ret == 1) { break; - else if (ret < 0) + } else if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out; + } } btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]); @@ -2463,8 +2589,10 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, int ret; ret = btrfs_read_extent_buffer(eb, &check); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); return ret; + } level = btrfs_header_level(eb); @@ -2472,8 +2600,10 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, return 0; path = btrfs_alloc_path(); - if (!path) + if (!path) { + btrfs_abort_transaction(trans, -ENOMEM); return -ENOMEM; + } nritems = btrfs_header_nritems(eb); for (i = 0; i < nritems; i++) { @@ -2545,6 +2675,7 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, inode = btrfs_iget_logging(key.objectid, root); if (IS_ERR(inode)) { ret = PTR_ERR(inode); + btrfs_abort_transaction(trans, ret); break; } from = ALIGN(i_size_read(&inode->vfs_inode), @@ -2553,11 +2684,15 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, drop_args.end = (u64)-1; drop_args.drop_cache = true; ret = btrfs_drop_extents(trans, root, inode, &drop_args); - if (!ret) { + if (ret) { + btrfs_abort_transaction(trans, ret); + } else { inode_sub_bytes(&inode->vfs_inode, drop_args.bytes_found); /* Update the inode's nbytes. */ ret = btrfs_update_inode(trans, inode); + if (ret) + btrfs_abort_transaction(trans, ret); } iput(&inode->vfs_inode); if (ret) |
