1c1d7c514SDavid Sterba // SPDX-License-Identifier: GPL-2.0 26cbd5570SChris Mason /* 36cbd5570SChris Mason * Copyright (C) 2007 Oracle. All rights reserved. 46cbd5570SChris Mason */ 56cbd5570SChris Mason 61e1d2701SChris Mason #include "ctree.h" 71e1d2701SChris Mason #include "disk-io.h" 8e089f05cSChris Mason #include "transaction.h" 9727011e0SChris Mason #include "print-tree.h" 101e1d2701SChris Mason 119bb8407fSNikolay Borisov struct btrfs_inode_ref *btrfs_find_name_in_backref(struct extent_buffer *leaf, 129bb8407fSNikolay Borisov int slot, const char *name, 139bb8407fSNikolay Borisov int name_len) 143954401fSChris Mason { 153954401fSChris Mason struct btrfs_inode_ref *ref; 163954401fSChris Mason unsigned long ptr; 173954401fSChris Mason unsigned long name_ptr; 183954401fSChris Mason u32 item_size; 193954401fSChris Mason u32 cur_offset = 0; 203954401fSChris Mason int len; 213954401fSChris Mason 22*3212fa14SJosef Bacik item_size = btrfs_item_size(leaf, slot); 231f250e92SFilipe Manana ptr = btrfs_item_ptr_offset(leaf, slot); 243954401fSChris Mason while (cur_offset < item_size) { 253954401fSChris Mason ref = (struct btrfs_inode_ref *)(ptr + cur_offset); 263954401fSChris Mason len = btrfs_inode_ref_name_len(leaf, ref); 273954401fSChris Mason name_ptr = (unsigned long)(ref + 1); 283954401fSChris Mason cur_offset += len + sizeof(*ref); 293954401fSChris Mason if (len != name_len) 303954401fSChris Mason continue; 319bb8407fSNikolay Borisov if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) 329bb8407fSNikolay Borisov return ref; 333954401fSChris Mason } 349bb8407fSNikolay Borisov return NULL; 353954401fSChris Mason } 363954401fSChris Mason 376ff49c6aSNikolay Borisov struct btrfs_inode_extref *btrfs_find_name_in_ext_backref( 386ff49c6aSNikolay Borisov struct extent_buffer *leaf, int slot, u64 ref_objectid, 396ff49c6aSNikolay Borisov const char *name, int name_len) 40f186373fSMark Fasheh { 41f186373fSMark Fasheh struct btrfs_inode_extref *extref; 42f186373fSMark Fasheh unsigned long ptr; 43f186373fSMark Fasheh unsigned long name_ptr; 44f186373fSMark Fasheh u32 item_size; 45f186373fSMark Fasheh u32 cur_offset = 0; 46f186373fSMark Fasheh int ref_name_len; 47f186373fSMark Fasheh 48*3212fa14SJosef Bacik item_size = btrfs_item_size(leaf, slot); 491f250e92SFilipe Manana ptr = btrfs_item_ptr_offset(leaf, slot); 50f186373fSMark Fasheh 51f186373fSMark Fasheh /* 52f186373fSMark Fasheh * Search all extended backrefs in this item. We're only 53f186373fSMark Fasheh * looking through any collisions so most of the time this is 54f186373fSMark Fasheh * just going to compare against one buffer. If all is well, 55f186373fSMark Fasheh * we'll return success and the inode ref object. 56f186373fSMark Fasheh */ 57f186373fSMark Fasheh while (cur_offset < item_size) { 58f186373fSMark Fasheh extref = (struct btrfs_inode_extref *) (ptr + cur_offset); 59f186373fSMark Fasheh name_ptr = (unsigned long)(&extref->name); 60f186373fSMark Fasheh ref_name_len = btrfs_inode_extref_name_len(leaf, extref); 61f186373fSMark Fasheh 62f186373fSMark Fasheh if (ref_name_len == name_len && 63f186373fSMark Fasheh btrfs_inode_extref_parent(leaf, extref) == ref_objectid && 646ff49c6aSNikolay Borisov (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)) 656ff49c6aSNikolay Borisov return extref; 66f186373fSMark Fasheh 67f186373fSMark Fasheh cur_offset += ref_name_len + sizeof(*extref); 68f186373fSMark Fasheh } 696ff49c6aSNikolay Borisov return NULL; 70f186373fSMark Fasheh } 71f186373fSMark Fasheh 72f186373fSMark Fasheh /* Returns NULL if no extref found */ 73f186373fSMark Fasheh struct btrfs_inode_extref * 74f186373fSMark Fasheh btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans, 75f186373fSMark Fasheh struct btrfs_root *root, 76f186373fSMark Fasheh struct btrfs_path *path, 77f186373fSMark Fasheh const char *name, int name_len, 78f186373fSMark Fasheh u64 inode_objectid, u64 ref_objectid, int ins_len, 79f186373fSMark Fasheh int cow) 80f186373fSMark Fasheh { 81f186373fSMark Fasheh int ret; 82f186373fSMark Fasheh struct btrfs_key key; 83f186373fSMark Fasheh 84f186373fSMark Fasheh key.objectid = inode_objectid; 85f186373fSMark Fasheh key.type = BTRFS_INODE_EXTREF_KEY; 86f186373fSMark Fasheh key.offset = btrfs_extref_hash(ref_objectid, name, name_len); 87f186373fSMark Fasheh 88f186373fSMark Fasheh ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); 89f186373fSMark Fasheh if (ret < 0) 90f186373fSMark Fasheh return ERR_PTR(ret); 91f186373fSMark Fasheh if (ret > 0) 92f186373fSMark Fasheh return NULL; 936ff49c6aSNikolay Borisov return btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0], 946ff49c6aSNikolay Borisov ref_objectid, name, name_len); 956ff49c6aSNikolay Borisov 96f186373fSMark Fasheh } 97f186373fSMark Fasheh 9848a3b636SEric Sandeen static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans, 99f186373fSMark Fasheh struct btrfs_root *root, 100f186373fSMark Fasheh const char *name, int name_len, 10148a3b636SEric Sandeen u64 inode_objectid, u64 ref_objectid, 10248a3b636SEric Sandeen u64 *index) 103f186373fSMark Fasheh { 104f186373fSMark Fasheh struct btrfs_path *path; 105f186373fSMark Fasheh struct btrfs_key key; 106f186373fSMark Fasheh struct btrfs_inode_extref *extref; 107f186373fSMark Fasheh struct extent_buffer *leaf; 108f186373fSMark Fasheh int ret; 109f186373fSMark Fasheh int del_len = name_len + sizeof(*extref); 110f186373fSMark Fasheh unsigned long ptr; 111f186373fSMark Fasheh unsigned long item_start; 112f186373fSMark Fasheh u32 item_size; 113f186373fSMark Fasheh 114f186373fSMark Fasheh key.objectid = inode_objectid; 115962a298fSDavid Sterba key.type = BTRFS_INODE_EXTREF_KEY; 116f186373fSMark Fasheh key.offset = btrfs_extref_hash(ref_objectid, name, name_len); 117f186373fSMark Fasheh 118f186373fSMark Fasheh path = btrfs_alloc_path(); 119f186373fSMark Fasheh if (!path) 120f186373fSMark Fasheh return -ENOMEM; 121f186373fSMark Fasheh 122f186373fSMark Fasheh ret = btrfs_search_slot(trans, root, &key, path, -1, 1); 123f186373fSMark Fasheh if (ret > 0) 124f186373fSMark Fasheh ret = -ENOENT; 125f186373fSMark Fasheh if (ret < 0) 126f186373fSMark Fasheh goto out; 127f186373fSMark Fasheh 128f186373fSMark Fasheh /* 129f186373fSMark Fasheh * Sanity check - did we find the right item for this name? 130f186373fSMark Fasheh * This should always succeed so error here will make the FS 131f186373fSMark Fasheh * readonly. 132f186373fSMark Fasheh */ 1336ff49c6aSNikolay Borisov extref = btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0], 1346ff49c6aSNikolay Borisov ref_objectid, name, name_len); 1356ff49c6aSNikolay Borisov if (!extref) { 13634d97007SAnand Jain btrfs_handle_fs_error(root->fs_info, -ENOENT, NULL); 137f186373fSMark Fasheh ret = -EROFS; 138f186373fSMark Fasheh goto out; 139f186373fSMark Fasheh } 140f186373fSMark Fasheh 141f186373fSMark Fasheh leaf = path->nodes[0]; 142*3212fa14SJosef Bacik item_size = btrfs_item_size(leaf, path->slots[0]); 143f186373fSMark Fasheh if (index) 144f186373fSMark Fasheh *index = btrfs_inode_extref_index(leaf, extref); 145f186373fSMark Fasheh 146f186373fSMark Fasheh if (del_len == item_size) { 147f186373fSMark Fasheh /* 148f186373fSMark Fasheh * Common case only one ref in the item, remove the 149f186373fSMark Fasheh * whole item. 150f186373fSMark Fasheh */ 151f186373fSMark Fasheh ret = btrfs_del_item(trans, root, path); 152f186373fSMark Fasheh goto out; 153f186373fSMark Fasheh } 154f186373fSMark Fasheh 155f186373fSMark Fasheh ptr = (unsigned long)extref; 156f186373fSMark Fasheh item_start = btrfs_item_ptr_offset(leaf, path->slots[0]); 157f186373fSMark Fasheh 158f186373fSMark Fasheh memmove_extent_buffer(leaf, ptr, ptr + del_len, 159f186373fSMark Fasheh item_size - (ptr + del_len - item_start)); 160f186373fSMark Fasheh 16178ac4f9eSDavid Sterba btrfs_truncate_item(path, item_size - del_len, 1); 162f186373fSMark Fasheh 163f186373fSMark Fasheh out: 164f186373fSMark Fasheh btrfs_free_path(path); 165f186373fSMark Fasheh 166f186373fSMark Fasheh return ret; 167f186373fSMark Fasheh } 168f186373fSMark Fasheh 1693954401fSChris Mason int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, 1703954401fSChris Mason struct btrfs_root *root, 1713954401fSChris Mason const char *name, int name_len, 172aec7477bSJosef Bacik u64 inode_objectid, u64 ref_objectid, u64 *index) 1733954401fSChris Mason { 1743954401fSChris Mason struct btrfs_path *path; 1753954401fSChris Mason struct btrfs_key key; 1763954401fSChris Mason struct btrfs_inode_ref *ref; 1773954401fSChris Mason struct extent_buffer *leaf; 1783954401fSChris Mason unsigned long ptr; 1793954401fSChris Mason unsigned long item_start; 1803954401fSChris Mason u32 item_size; 1813954401fSChris Mason u32 sub_item_len; 1823954401fSChris Mason int ret; 183f186373fSMark Fasheh int search_ext_refs = 0; 1843954401fSChris Mason int del_len = name_len + sizeof(*ref); 1853954401fSChris Mason 1863954401fSChris Mason key.objectid = inode_objectid; 1873954401fSChris Mason key.offset = ref_objectid; 188962a298fSDavid Sterba key.type = BTRFS_INODE_REF_KEY; 1893954401fSChris Mason 1903954401fSChris Mason path = btrfs_alloc_path(); 1913954401fSChris Mason if (!path) 1923954401fSChris Mason return -ENOMEM; 1933954401fSChris Mason 1943954401fSChris Mason ret = btrfs_search_slot(trans, root, &key, path, -1, 1); 1953954401fSChris Mason if (ret > 0) { 1963954401fSChris Mason ret = -ENOENT; 197f186373fSMark Fasheh search_ext_refs = 1; 1983954401fSChris Mason goto out; 1993954401fSChris Mason } else if (ret < 0) { 2003954401fSChris Mason goto out; 2013954401fSChris Mason } 2029bb8407fSNikolay Borisov 2039bb8407fSNikolay Borisov ref = btrfs_find_name_in_backref(path->nodes[0], path->slots[0], name, 2049bb8407fSNikolay Borisov name_len); 2059bb8407fSNikolay Borisov if (!ref) { 2063954401fSChris Mason ret = -ENOENT; 207f186373fSMark Fasheh search_ext_refs = 1; 2083954401fSChris Mason goto out; 2093954401fSChris Mason } 2103954401fSChris Mason leaf = path->nodes[0]; 211*3212fa14SJosef Bacik item_size = btrfs_item_size(leaf, path->slots[0]); 212aec7477bSJosef Bacik 213aec7477bSJosef Bacik if (index) 214aec7477bSJosef Bacik *index = btrfs_inode_ref_index(leaf, ref); 215aec7477bSJosef Bacik 2163954401fSChris Mason if (del_len == item_size) { 2173954401fSChris Mason ret = btrfs_del_item(trans, root, path); 2183954401fSChris Mason goto out; 2193954401fSChris Mason } 2203954401fSChris Mason ptr = (unsigned long)ref; 2213954401fSChris Mason sub_item_len = name_len + sizeof(*ref); 2223954401fSChris Mason item_start = btrfs_item_ptr_offset(leaf, path->slots[0]); 2233954401fSChris Mason memmove_extent_buffer(leaf, ptr, ptr + sub_item_len, 2243954401fSChris Mason item_size - (ptr + sub_item_len - item_start)); 22578ac4f9eSDavid Sterba btrfs_truncate_item(path, item_size - sub_item_len, 1); 226f186373fSMark Fasheh out: 227f186373fSMark Fasheh btrfs_free_path(path); 228f186373fSMark Fasheh 229f186373fSMark Fasheh if (search_ext_refs) { 230f186373fSMark Fasheh /* 231f186373fSMark Fasheh * No refs were found, or we could not find the 232f186373fSMark Fasheh * name in our ref array. Find and remove the extended 233f186373fSMark Fasheh * inode ref then. 234f186373fSMark Fasheh */ 235f186373fSMark Fasheh return btrfs_del_inode_extref(trans, root, name, name_len, 236f186373fSMark Fasheh inode_objectid, ref_objectid, index); 237f186373fSMark Fasheh } 238f186373fSMark Fasheh 239f186373fSMark Fasheh return ret; 240f186373fSMark Fasheh } 241f186373fSMark Fasheh 242f186373fSMark Fasheh /* 243f186373fSMark Fasheh * btrfs_insert_inode_extref() - Inserts an extended inode ref into a tree. 244f186373fSMark Fasheh * 245f186373fSMark Fasheh * The caller must have checked against BTRFS_LINK_MAX already. 246f186373fSMark Fasheh */ 247f186373fSMark Fasheh static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans, 248f186373fSMark Fasheh struct btrfs_root *root, 249f186373fSMark Fasheh const char *name, int name_len, 250f186373fSMark Fasheh u64 inode_objectid, u64 ref_objectid, u64 index) 251f186373fSMark Fasheh { 252f186373fSMark Fasheh struct btrfs_inode_extref *extref; 253f186373fSMark Fasheh int ret; 254f186373fSMark Fasheh int ins_len = name_len + sizeof(*extref); 255f186373fSMark Fasheh unsigned long ptr; 256f186373fSMark Fasheh struct btrfs_path *path; 257f186373fSMark Fasheh struct btrfs_key key; 258f186373fSMark Fasheh struct extent_buffer *leaf; 259f186373fSMark Fasheh 260f186373fSMark Fasheh key.objectid = inode_objectid; 261f186373fSMark Fasheh key.type = BTRFS_INODE_EXTREF_KEY; 262f186373fSMark Fasheh key.offset = btrfs_extref_hash(ref_objectid, name, name_len); 263f186373fSMark Fasheh 264f186373fSMark Fasheh path = btrfs_alloc_path(); 265f186373fSMark Fasheh if (!path) 266f186373fSMark Fasheh return -ENOMEM; 267f186373fSMark Fasheh 268f186373fSMark Fasheh ret = btrfs_insert_empty_item(trans, root, path, &key, 269f186373fSMark Fasheh ins_len); 270f186373fSMark Fasheh if (ret == -EEXIST) { 2711f250e92SFilipe Manana if (btrfs_find_name_in_ext_backref(path->nodes[0], 2721f250e92SFilipe Manana path->slots[0], 2731f250e92SFilipe Manana ref_objectid, 2746ff49c6aSNikolay Borisov name, name_len)) 275f186373fSMark Fasheh goto out; 276f186373fSMark Fasheh 277c71dd880SDavid Sterba btrfs_extend_item(path, ins_len); 278f186373fSMark Fasheh ret = 0; 279f186373fSMark Fasheh } 280f186373fSMark Fasheh if (ret < 0) 281f186373fSMark Fasheh goto out; 282f186373fSMark Fasheh 283f186373fSMark Fasheh leaf = path->nodes[0]; 284f186373fSMark Fasheh ptr = (unsigned long)btrfs_item_ptr(leaf, path->slots[0], char); 285*3212fa14SJosef Bacik ptr += btrfs_item_size(leaf, path->slots[0]) - ins_len; 286f186373fSMark Fasheh extref = (struct btrfs_inode_extref *)ptr; 287f186373fSMark Fasheh 288f186373fSMark Fasheh btrfs_set_inode_extref_name_len(path->nodes[0], extref, name_len); 289f186373fSMark Fasheh btrfs_set_inode_extref_index(path->nodes[0], extref, index); 290f186373fSMark Fasheh btrfs_set_inode_extref_parent(path->nodes[0], extref, ref_objectid); 291f186373fSMark Fasheh 292f186373fSMark Fasheh ptr = (unsigned long)&extref->name; 293f186373fSMark Fasheh write_extent_buffer(path->nodes[0], name, ptr, name_len); 294f186373fSMark Fasheh btrfs_mark_buffer_dirty(path->nodes[0]); 295f186373fSMark Fasheh 2963954401fSChris Mason out: 2973954401fSChris Mason btrfs_free_path(path); 2983954401fSChris Mason return ret; 2993954401fSChris Mason } 3003954401fSChris Mason 30179787eaaSJeff Mahoney /* Will return 0, -ENOMEM, -EMLINK, or -EEXIST or anything from the CoW path */ 3023954401fSChris Mason int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, 3033954401fSChris Mason struct btrfs_root *root, 3043954401fSChris Mason const char *name, int name_len, 305aec7477bSJosef Bacik u64 inode_objectid, u64 ref_objectid, u64 index) 3063954401fSChris Mason { 3070b246afaSJeff Mahoney struct btrfs_fs_info *fs_info = root->fs_info; 3083954401fSChris Mason struct btrfs_path *path; 3093954401fSChris Mason struct btrfs_key key; 3103954401fSChris Mason struct btrfs_inode_ref *ref; 3113954401fSChris Mason unsigned long ptr; 3123954401fSChris Mason int ret; 3133954401fSChris Mason int ins_len = name_len + sizeof(*ref); 3143954401fSChris Mason 3153954401fSChris Mason key.objectid = inode_objectid; 3163954401fSChris Mason key.offset = ref_objectid; 317962a298fSDavid Sterba key.type = BTRFS_INODE_REF_KEY; 3183954401fSChris Mason 3193954401fSChris Mason path = btrfs_alloc_path(); 3203954401fSChris Mason if (!path) 3213954401fSChris Mason return -ENOMEM; 3223954401fSChris Mason 323df8d116fSFilipe Manana path->skip_release_on_error = 1; 3243954401fSChris Mason ret = btrfs_insert_empty_item(trans, root, path, &key, 3253954401fSChris Mason ins_len); 3263954401fSChris Mason if (ret == -EEXIST) { 3273954401fSChris Mason u32 old_size; 3289bb8407fSNikolay Borisov ref = btrfs_find_name_in_backref(path->nodes[0], path->slots[0], 3299bb8407fSNikolay Borisov name, name_len); 3309bb8407fSNikolay Borisov if (ref) 3313954401fSChris Mason goto out; 3323954401fSChris Mason 333*3212fa14SJosef Bacik old_size = btrfs_item_size(path->nodes[0], path->slots[0]); 334c71dd880SDavid Sterba btrfs_extend_item(path, ins_len); 3353954401fSChris Mason ref = btrfs_item_ptr(path->nodes[0], path->slots[0], 3363954401fSChris Mason struct btrfs_inode_ref); 3373954401fSChris Mason ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size); 3383954401fSChris Mason btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); 339aec7477bSJosef Bacik btrfs_set_inode_ref_index(path->nodes[0], ref, index); 3403954401fSChris Mason ptr = (unsigned long)(ref + 1); 3413954401fSChris Mason ret = 0; 3423954401fSChris Mason } else if (ret < 0) { 343df8d116fSFilipe Manana if (ret == -EOVERFLOW) { 3441f250e92SFilipe Manana if (btrfs_find_name_in_backref(path->nodes[0], 3451f250e92SFilipe Manana path->slots[0], 3469bb8407fSNikolay Borisov name, name_len)) 347df8d116fSFilipe Manana ret = -EEXIST; 348df8d116fSFilipe Manana else 349a5719521SYan, Zheng ret = -EMLINK; 350df8d116fSFilipe Manana } 3513954401fSChris Mason goto out; 3523954401fSChris Mason } else { 3533954401fSChris Mason ref = btrfs_item_ptr(path->nodes[0], path->slots[0], 3543954401fSChris Mason struct btrfs_inode_ref); 3553954401fSChris Mason btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); 356aec7477bSJosef Bacik btrfs_set_inode_ref_index(path->nodes[0], ref, index); 3573954401fSChris Mason ptr = (unsigned long)(ref + 1); 3583954401fSChris Mason } 3593954401fSChris Mason write_extent_buffer(path->nodes[0], name, ptr, name_len); 3603954401fSChris Mason btrfs_mark_buffer_dirty(path->nodes[0]); 3613954401fSChris Mason 3623954401fSChris Mason out: 3633954401fSChris Mason btrfs_free_path(path); 364f186373fSMark Fasheh 365f186373fSMark Fasheh if (ret == -EMLINK) { 3660b246afaSJeff Mahoney struct btrfs_super_block *disk_super = fs_info->super_copy; 367f186373fSMark Fasheh /* We ran out of space in the ref array. Need to 368f186373fSMark Fasheh * add an extended ref. */ 369f186373fSMark Fasheh if (btrfs_super_incompat_flags(disk_super) 370f186373fSMark Fasheh & BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF) 371f186373fSMark Fasheh ret = btrfs_insert_inode_extref(trans, root, name, 372f186373fSMark Fasheh name_len, 373f186373fSMark Fasheh inode_objectid, 374f186373fSMark Fasheh ref_objectid, index); 375f186373fSMark Fasheh } 376f186373fSMark Fasheh 3773954401fSChris Mason return ret; 3783954401fSChris Mason } 3793954401fSChris Mason 3805f39d397SChris Mason int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans, 3815f39d397SChris Mason struct btrfs_root *root, 3825f39d397SChris Mason struct btrfs_path *path, u64 objectid) 3831e1d2701SChris Mason { 3841e1d2701SChris Mason struct btrfs_key key; 3851e1d2701SChris Mason int ret; 3861e1d2701SChris Mason key.objectid = objectid; 387962a298fSDavid Sterba key.type = BTRFS_INODE_ITEM_KEY; 3881e1d2701SChris Mason key.offset = 0; 3891e1d2701SChris Mason 3905f39d397SChris Mason ret = btrfs_insert_empty_item(trans, root, path, &key, 3915f39d397SChris Mason sizeof(struct btrfs_inode_item)); 3921e1d2701SChris Mason return ret; 3931e1d2701SChris Mason } 3941e1d2701SChris Mason 395e089f05cSChris Mason int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root 396d6e4a428SChris Mason *root, struct btrfs_path *path, 397d6e4a428SChris Mason struct btrfs_key *location, int mod) 3981e1d2701SChris Mason { 3991e1d2701SChris Mason int ins_len = mod < 0 ? -1 : 0; 4001e1d2701SChris Mason int cow = mod != 0; 401d6e4a428SChris Mason int ret; 402d6e4a428SChris Mason int slot; 4035f39d397SChris Mason struct extent_buffer *leaf; 404d6e4a428SChris Mason struct btrfs_key found_key; 4051e1d2701SChris Mason 406d6e4a428SChris Mason ret = btrfs_search_slot(trans, root, location, path, ins_len, cow); 407962a298fSDavid Sterba if (ret > 0 && location->type == BTRFS_ROOT_ITEM_KEY && 408d6e4a428SChris Mason location->offset == (u64)-1 && path->slots[0] != 0) { 409d6e4a428SChris Mason slot = path->slots[0] - 1; 4105f39d397SChris Mason leaf = path->nodes[0]; 4115f39d397SChris Mason btrfs_item_key_to_cpu(leaf, &found_key, slot); 412d6e4a428SChris Mason if (found_key.objectid == location->objectid && 413962a298fSDavid Sterba found_key.type == location->type) { 414d6e4a428SChris Mason path->slots[0]--; 415d6e4a428SChris Mason return 0; 416d6e4a428SChris Mason } 417d6e4a428SChris Mason } 418d6e4a428SChris Mason return ret; 4191e1d2701SChris Mason } 420