16cbd5570SChris Mason /* 26cbd5570SChris Mason * Copyright (C) 2007 Oracle. All rights reserved. 36cbd5570SChris Mason * 46cbd5570SChris Mason * This program is free software; you can redistribute it and/or 56cbd5570SChris Mason * modify it under the terms of the GNU General Public 66cbd5570SChris Mason * License v2 as published by the Free Software Foundation. 76cbd5570SChris Mason * 86cbd5570SChris Mason * This program is distributed in the hope that it will be useful, 96cbd5570SChris Mason * but WITHOUT ANY WARRANTY; without even the implied warranty of 106cbd5570SChris Mason * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 116cbd5570SChris Mason * General Public License for more details. 126cbd5570SChris Mason * 136cbd5570SChris Mason * You should have received a copy of the GNU General Public 146cbd5570SChris Mason * License along with this program; if not, write to the 156cbd5570SChris Mason * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 166cbd5570SChris Mason * Boston, MA 021110-1307, USA. 176cbd5570SChris Mason */ 186cbd5570SChris Mason 191e1d2701SChris Mason #include "ctree.h" 201e1d2701SChris Mason #include "disk-io.h" 21f186373fSMark Fasheh #include "hash.h" 22e089f05cSChris Mason #include "transaction.h" 23727011e0SChris Mason #include "print-tree.h" 241e1d2701SChris Mason 25b2950863SChristoph Hellwig static int find_name_in_backref(struct btrfs_path *path, const char *name, 263954401fSChris Mason int name_len, struct btrfs_inode_ref **ref_ret) 273954401fSChris Mason { 283954401fSChris Mason struct extent_buffer *leaf; 293954401fSChris Mason struct btrfs_inode_ref *ref; 303954401fSChris Mason unsigned long ptr; 313954401fSChris Mason unsigned long name_ptr; 323954401fSChris Mason u32 item_size; 333954401fSChris Mason u32 cur_offset = 0; 343954401fSChris Mason int len; 353954401fSChris Mason 363954401fSChris Mason leaf = path->nodes[0]; 373954401fSChris Mason item_size = btrfs_item_size_nr(leaf, path->slots[0]); 383954401fSChris Mason ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); 393954401fSChris Mason while (cur_offset < item_size) { 403954401fSChris Mason ref = (struct btrfs_inode_ref *)(ptr + cur_offset); 413954401fSChris Mason len = btrfs_inode_ref_name_len(leaf, ref); 423954401fSChris Mason name_ptr = (unsigned long)(ref + 1); 433954401fSChris Mason cur_offset += len + sizeof(*ref); 443954401fSChris Mason if (len != name_len) 453954401fSChris Mason continue; 463954401fSChris Mason if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) { 473954401fSChris Mason *ref_ret = ref; 483954401fSChris Mason return 1; 493954401fSChris Mason } 503954401fSChris Mason } 513954401fSChris Mason return 0; 523954401fSChris Mason } 533954401fSChris Mason 54f186373fSMark Fasheh int btrfs_find_name_in_ext_backref(struct btrfs_path *path, u64 ref_objectid, 55f186373fSMark Fasheh const char *name, int name_len, 56f186373fSMark Fasheh struct btrfs_inode_extref **extref_ret) 57f186373fSMark Fasheh { 58f186373fSMark Fasheh struct extent_buffer *leaf; 59f186373fSMark Fasheh struct btrfs_inode_extref *extref; 60f186373fSMark Fasheh unsigned long ptr; 61f186373fSMark Fasheh unsigned long name_ptr; 62f186373fSMark Fasheh u32 item_size; 63f186373fSMark Fasheh u32 cur_offset = 0; 64f186373fSMark Fasheh int ref_name_len; 65f186373fSMark Fasheh 66f186373fSMark Fasheh leaf = path->nodes[0]; 67f186373fSMark Fasheh item_size = btrfs_item_size_nr(leaf, path->slots[0]); 68f186373fSMark Fasheh ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); 69f186373fSMark Fasheh 70f186373fSMark Fasheh /* 71f186373fSMark Fasheh * Search all extended backrefs in this item. We're only 72f186373fSMark Fasheh * looking through any collisions so most of the time this is 73f186373fSMark Fasheh * just going to compare against one buffer. If all is well, 74f186373fSMark Fasheh * we'll return success and the inode ref object. 75f186373fSMark Fasheh */ 76f186373fSMark Fasheh while (cur_offset < item_size) { 77f186373fSMark Fasheh extref = (struct btrfs_inode_extref *) (ptr + cur_offset); 78f186373fSMark Fasheh name_ptr = (unsigned long)(&extref->name); 79f186373fSMark Fasheh ref_name_len = btrfs_inode_extref_name_len(leaf, extref); 80f186373fSMark Fasheh 81f186373fSMark Fasheh if (ref_name_len == name_len && 82f186373fSMark Fasheh btrfs_inode_extref_parent(leaf, extref) == ref_objectid && 83f186373fSMark Fasheh (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)) { 84f186373fSMark Fasheh if (extref_ret) 85f186373fSMark Fasheh *extref_ret = extref; 86f186373fSMark Fasheh return 1; 87f186373fSMark Fasheh } 88f186373fSMark Fasheh 89f186373fSMark Fasheh cur_offset += ref_name_len + sizeof(*extref); 90f186373fSMark Fasheh } 91f186373fSMark Fasheh return 0; 92f186373fSMark Fasheh } 93f186373fSMark Fasheh 94f186373fSMark Fasheh static struct btrfs_inode_ref * 95a22285a6SYan, Zheng btrfs_lookup_inode_ref(struct btrfs_trans_handle *trans, 96a22285a6SYan, Zheng struct btrfs_root *root, 97a22285a6SYan, Zheng struct btrfs_path *path, 98a22285a6SYan, Zheng const char *name, int name_len, 99f186373fSMark Fasheh u64 inode_objectid, u64 ref_objectid, int ins_len, 100f186373fSMark Fasheh int cow) 101a22285a6SYan, Zheng { 102f186373fSMark Fasheh int ret; 103a22285a6SYan, Zheng struct btrfs_key key; 104a22285a6SYan, Zheng struct btrfs_inode_ref *ref; 105a22285a6SYan, Zheng 106a22285a6SYan, Zheng key.objectid = inode_objectid; 107a22285a6SYan, Zheng key.type = BTRFS_INODE_REF_KEY; 108a22285a6SYan, Zheng key.offset = ref_objectid; 109a22285a6SYan, Zheng 110a22285a6SYan, Zheng ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); 111a22285a6SYan, Zheng if (ret < 0) 112a22285a6SYan, Zheng return ERR_PTR(ret); 113a22285a6SYan, Zheng if (ret > 0) 114a22285a6SYan, Zheng return NULL; 115a22285a6SYan, Zheng if (!find_name_in_backref(path, name, name_len, &ref)) 116a22285a6SYan, Zheng return NULL; 117a22285a6SYan, Zheng return ref; 118a22285a6SYan, Zheng } 119a22285a6SYan, Zheng 120f186373fSMark Fasheh /* Returns NULL if no extref found */ 121f186373fSMark Fasheh struct btrfs_inode_extref * 122f186373fSMark Fasheh btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans, 123f186373fSMark Fasheh struct btrfs_root *root, 124f186373fSMark Fasheh struct btrfs_path *path, 125f186373fSMark Fasheh const char *name, int name_len, 126f186373fSMark Fasheh u64 inode_objectid, u64 ref_objectid, int ins_len, 127f186373fSMark Fasheh int cow) 128f186373fSMark Fasheh { 129f186373fSMark Fasheh int ret; 130f186373fSMark Fasheh struct btrfs_key key; 131f186373fSMark Fasheh struct btrfs_inode_extref *extref; 132f186373fSMark Fasheh 133f186373fSMark Fasheh key.objectid = inode_objectid; 134f186373fSMark Fasheh key.type = BTRFS_INODE_EXTREF_KEY; 135f186373fSMark Fasheh key.offset = btrfs_extref_hash(ref_objectid, name, name_len); 136f186373fSMark Fasheh 137f186373fSMark Fasheh ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); 138f186373fSMark Fasheh if (ret < 0) 139f186373fSMark Fasheh return ERR_PTR(ret); 140f186373fSMark Fasheh if (ret > 0) 141f186373fSMark Fasheh return NULL; 142f186373fSMark Fasheh if (!btrfs_find_name_in_ext_backref(path, ref_objectid, name, name_len, &extref)) 143f186373fSMark Fasheh return NULL; 144f186373fSMark Fasheh return extref; 145f186373fSMark Fasheh } 146f186373fSMark Fasheh 147f186373fSMark Fasheh int btrfs_get_inode_ref_index(struct btrfs_trans_handle *trans, 148f186373fSMark Fasheh struct btrfs_root *root, 149f186373fSMark Fasheh struct btrfs_path *path, 150f186373fSMark Fasheh const char *name, int name_len, 151f186373fSMark Fasheh u64 inode_objectid, u64 ref_objectid, int mod, 152f186373fSMark Fasheh u64 *ret_index) 153f186373fSMark Fasheh { 154f186373fSMark Fasheh struct btrfs_inode_ref *ref; 155f186373fSMark Fasheh struct btrfs_inode_extref *extref; 156f186373fSMark Fasheh int ins_len = mod < 0 ? -1 : 0; 157f186373fSMark Fasheh int cow = mod != 0; 158f186373fSMark Fasheh 159f186373fSMark Fasheh ref = btrfs_lookup_inode_ref(trans, root, path, name, name_len, 160f186373fSMark Fasheh inode_objectid, ref_objectid, ins_len, 161f186373fSMark Fasheh cow); 162f186373fSMark Fasheh if (IS_ERR(ref)) 163f186373fSMark Fasheh return PTR_ERR(ref); 164f186373fSMark Fasheh 165f186373fSMark Fasheh if (ref != NULL) { 166f186373fSMark Fasheh *ret_index = btrfs_inode_ref_index(path->nodes[0], ref); 167f186373fSMark Fasheh return 0; 168f186373fSMark Fasheh } 169f186373fSMark Fasheh 170f186373fSMark Fasheh btrfs_release_path(path); 171f186373fSMark Fasheh 172f186373fSMark Fasheh extref = btrfs_lookup_inode_extref(trans, root, path, name, 173f186373fSMark Fasheh name_len, inode_objectid, 174f186373fSMark Fasheh ref_objectid, ins_len, cow); 175f186373fSMark Fasheh if (IS_ERR(extref)) 176f186373fSMark Fasheh return PTR_ERR(extref); 177f186373fSMark Fasheh 178f186373fSMark Fasheh if (extref) { 179f186373fSMark Fasheh *ret_index = btrfs_inode_extref_index(path->nodes[0], extref); 180f186373fSMark Fasheh return 0; 181f186373fSMark Fasheh } 182f186373fSMark Fasheh 183f186373fSMark Fasheh return -ENOENT; 184f186373fSMark Fasheh } 185f186373fSMark Fasheh 18648a3b636SEric Sandeen static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans, 187f186373fSMark Fasheh struct btrfs_root *root, 188f186373fSMark Fasheh const char *name, int name_len, 18948a3b636SEric Sandeen u64 inode_objectid, u64 ref_objectid, 19048a3b636SEric Sandeen u64 *index) 191f186373fSMark Fasheh { 192f186373fSMark Fasheh struct btrfs_path *path; 193f186373fSMark Fasheh struct btrfs_key key; 194f186373fSMark Fasheh struct btrfs_inode_extref *extref; 195f186373fSMark Fasheh struct extent_buffer *leaf; 196f186373fSMark Fasheh int ret; 197f186373fSMark Fasheh int del_len = name_len + sizeof(*extref); 198f186373fSMark Fasheh unsigned long ptr; 199f186373fSMark Fasheh unsigned long item_start; 200f186373fSMark Fasheh u32 item_size; 201f186373fSMark Fasheh 202f186373fSMark Fasheh key.objectid = inode_objectid; 203f186373fSMark Fasheh btrfs_set_key_type(&key, BTRFS_INODE_EXTREF_KEY); 204f186373fSMark Fasheh key.offset = btrfs_extref_hash(ref_objectid, name, name_len); 205f186373fSMark Fasheh 206f186373fSMark Fasheh path = btrfs_alloc_path(); 207f186373fSMark Fasheh if (!path) 208f186373fSMark Fasheh return -ENOMEM; 209f186373fSMark Fasheh 210f186373fSMark Fasheh path->leave_spinning = 1; 211f186373fSMark Fasheh 212f186373fSMark Fasheh ret = btrfs_search_slot(trans, root, &key, path, -1, 1); 213f186373fSMark Fasheh if (ret > 0) 214f186373fSMark Fasheh ret = -ENOENT; 215f186373fSMark Fasheh if (ret < 0) 216f186373fSMark Fasheh goto out; 217f186373fSMark Fasheh 218f186373fSMark Fasheh /* 219f186373fSMark Fasheh * Sanity check - did we find the right item for this name? 220f186373fSMark Fasheh * This should always succeed so error here will make the FS 221f186373fSMark Fasheh * readonly. 222f186373fSMark Fasheh */ 223f186373fSMark Fasheh if (!btrfs_find_name_in_ext_backref(path, ref_objectid, 224f186373fSMark Fasheh name, name_len, &extref)) { 225f186373fSMark Fasheh btrfs_std_error(root->fs_info, -ENOENT); 226f186373fSMark Fasheh ret = -EROFS; 227f186373fSMark Fasheh goto out; 228f186373fSMark Fasheh } 229f186373fSMark Fasheh 230f186373fSMark Fasheh leaf = path->nodes[0]; 231f186373fSMark Fasheh item_size = btrfs_item_size_nr(leaf, path->slots[0]); 232f186373fSMark Fasheh if (index) 233f186373fSMark Fasheh *index = btrfs_inode_extref_index(leaf, extref); 234f186373fSMark Fasheh 235f186373fSMark Fasheh if (del_len == item_size) { 236f186373fSMark Fasheh /* 237f186373fSMark Fasheh * Common case only one ref in the item, remove the 238f186373fSMark Fasheh * whole item. 239f186373fSMark Fasheh */ 240f186373fSMark Fasheh ret = btrfs_del_item(trans, root, path); 241f186373fSMark Fasheh goto out; 242f186373fSMark Fasheh } 243f186373fSMark Fasheh 244f186373fSMark Fasheh ptr = (unsigned long)extref; 245f186373fSMark Fasheh item_start = btrfs_item_ptr_offset(leaf, path->slots[0]); 246f186373fSMark Fasheh 247f186373fSMark Fasheh memmove_extent_buffer(leaf, ptr, ptr + del_len, 248f186373fSMark Fasheh item_size - (ptr + del_len - item_start)); 249f186373fSMark Fasheh 250afe5fea7STsutomu Itoh btrfs_truncate_item(root, path, item_size - del_len, 1); 251f186373fSMark Fasheh 252f186373fSMark Fasheh out: 253f186373fSMark Fasheh btrfs_free_path(path); 254f186373fSMark Fasheh 255f186373fSMark Fasheh return ret; 256f186373fSMark Fasheh } 257f186373fSMark Fasheh 2583954401fSChris Mason int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, 2593954401fSChris Mason struct btrfs_root *root, 2603954401fSChris Mason const char *name, int name_len, 261aec7477bSJosef Bacik u64 inode_objectid, u64 ref_objectid, u64 *index) 2623954401fSChris Mason { 2633954401fSChris Mason struct btrfs_path *path; 2643954401fSChris Mason struct btrfs_key key; 2653954401fSChris Mason struct btrfs_inode_ref *ref; 2663954401fSChris Mason struct extent_buffer *leaf; 2673954401fSChris Mason unsigned long ptr; 2683954401fSChris Mason unsigned long item_start; 2693954401fSChris Mason u32 item_size; 2703954401fSChris Mason u32 sub_item_len; 2713954401fSChris Mason int ret; 272f186373fSMark Fasheh int search_ext_refs = 0; 2733954401fSChris Mason int del_len = name_len + sizeof(*ref); 2743954401fSChris Mason 2753954401fSChris Mason key.objectid = inode_objectid; 2763954401fSChris Mason key.offset = ref_objectid; 2773954401fSChris Mason btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY); 2783954401fSChris Mason 2793954401fSChris Mason path = btrfs_alloc_path(); 2803954401fSChris Mason if (!path) 2813954401fSChris Mason return -ENOMEM; 2823954401fSChris Mason 283b9473439SChris Mason path->leave_spinning = 1; 284b9473439SChris Mason 2853954401fSChris Mason ret = btrfs_search_slot(trans, root, &key, path, -1, 1); 2863954401fSChris Mason if (ret > 0) { 2873954401fSChris Mason ret = -ENOENT; 288f186373fSMark Fasheh search_ext_refs = 1; 2893954401fSChris Mason goto out; 2903954401fSChris Mason } else if (ret < 0) { 2913954401fSChris Mason goto out; 2923954401fSChris Mason } 2933954401fSChris Mason if (!find_name_in_backref(path, name, name_len, &ref)) { 2943954401fSChris Mason ret = -ENOENT; 295f186373fSMark Fasheh search_ext_refs = 1; 2963954401fSChris Mason goto out; 2973954401fSChris Mason } 2983954401fSChris Mason leaf = path->nodes[0]; 2993954401fSChris Mason item_size = btrfs_item_size_nr(leaf, path->slots[0]); 300aec7477bSJosef Bacik 301aec7477bSJosef Bacik if (index) 302aec7477bSJosef Bacik *index = btrfs_inode_ref_index(leaf, ref); 303aec7477bSJosef Bacik 3043954401fSChris Mason if (del_len == item_size) { 3053954401fSChris Mason ret = btrfs_del_item(trans, root, path); 3063954401fSChris Mason goto out; 3073954401fSChris Mason } 3083954401fSChris Mason ptr = (unsigned long)ref; 3093954401fSChris Mason sub_item_len = name_len + sizeof(*ref); 3103954401fSChris Mason item_start = btrfs_item_ptr_offset(leaf, path->slots[0]); 3113954401fSChris Mason memmove_extent_buffer(leaf, ptr, ptr + sub_item_len, 3123954401fSChris Mason item_size - (ptr + sub_item_len - item_start)); 313afe5fea7STsutomu Itoh btrfs_truncate_item(root, path, item_size - sub_item_len, 1); 314f186373fSMark Fasheh out: 315f186373fSMark Fasheh btrfs_free_path(path); 316f186373fSMark Fasheh 317f186373fSMark Fasheh if (search_ext_refs) { 318f186373fSMark Fasheh /* 319f186373fSMark Fasheh * No refs were found, or we could not find the 320f186373fSMark Fasheh * name in our ref array. Find and remove the extended 321f186373fSMark Fasheh * inode ref then. 322f186373fSMark Fasheh */ 323f186373fSMark Fasheh return btrfs_del_inode_extref(trans, root, name, name_len, 324f186373fSMark Fasheh inode_objectid, ref_objectid, index); 325f186373fSMark Fasheh } 326f186373fSMark Fasheh 327f186373fSMark Fasheh return ret; 328f186373fSMark Fasheh } 329f186373fSMark Fasheh 330f186373fSMark Fasheh /* 331f186373fSMark Fasheh * btrfs_insert_inode_extref() - Inserts an extended inode ref into a tree. 332f186373fSMark Fasheh * 333f186373fSMark Fasheh * The caller must have checked against BTRFS_LINK_MAX already. 334f186373fSMark Fasheh */ 335f186373fSMark Fasheh static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans, 336f186373fSMark Fasheh struct btrfs_root *root, 337f186373fSMark Fasheh const char *name, int name_len, 338f186373fSMark Fasheh u64 inode_objectid, u64 ref_objectid, u64 index) 339f186373fSMark Fasheh { 340f186373fSMark Fasheh struct btrfs_inode_extref *extref; 341f186373fSMark Fasheh int ret; 342f186373fSMark Fasheh int ins_len = name_len + sizeof(*extref); 343f186373fSMark Fasheh unsigned long ptr; 344f186373fSMark Fasheh struct btrfs_path *path; 345f186373fSMark Fasheh struct btrfs_key key; 346f186373fSMark Fasheh struct extent_buffer *leaf; 347f186373fSMark Fasheh struct btrfs_item *item; 348f186373fSMark Fasheh 349f186373fSMark Fasheh key.objectid = inode_objectid; 350f186373fSMark Fasheh key.type = BTRFS_INODE_EXTREF_KEY; 351f186373fSMark Fasheh key.offset = btrfs_extref_hash(ref_objectid, name, name_len); 352f186373fSMark Fasheh 353f186373fSMark Fasheh path = btrfs_alloc_path(); 354f186373fSMark Fasheh if (!path) 355f186373fSMark Fasheh return -ENOMEM; 356f186373fSMark Fasheh 357f186373fSMark Fasheh path->leave_spinning = 1; 358f186373fSMark Fasheh ret = btrfs_insert_empty_item(trans, root, path, &key, 359f186373fSMark Fasheh ins_len); 360f186373fSMark Fasheh if (ret == -EEXIST) { 361f186373fSMark Fasheh if (btrfs_find_name_in_ext_backref(path, ref_objectid, 362f186373fSMark Fasheh name, name_len, NULL)) 363f186373fSMark Fasheh goto out; 364f186373fSMark Fasheh 3654b90c680STsutomu Itoh btrfs_extend_item(root, path, ins_len); 366f186373fSMark Fasheh ret = 0; 367f186373fSMark Fasheh } 368f186373fSMark Fasheh if (ret < 0) 369f186373fSMark Fasheh goto out; 370f186373fSMark Fasheh 371f186373fSMark Fasheh leaf = path->nodes[0]; 372f186373fSMark Fasheh item = btrfs_item_nr(leaf, path->slots[0]); 373f186373fSMark Fasheh ptr = (unsigned long)btrfs_item_ptr(leaf, path->slots[0], char); 374f186373fSMark Fasheh ptr += btrfs_item_size(leaf, item) - ins_len; 375f186373fSMark Fasheh extref = (struct btrfs_inode_extref *)ptr; 376f186373fSMark Fasheh 377f186373fSMark Fasheh btrfs_set_inode_extref_name_len(path->nodes[0], extref, name_len); 378f186373fSMark Fasheh btrfs_set_inode_extref_index(path->nodes[0], extref, index); 379f186373fSMark Fasheh btrfs_set_inode_extref_parent(path->nodes[0], extref, ref_objectid); 380f186373fSMark Fasheh 381f186373fSMark Fasheh ptr = (unsigned long)&extref->name; 382f186373fSMark Fasheh write_extent_buffer(path->nodes[0], name, ptr, name_len); 383f186373fSMark Fasheh btrfs_mark_buffer_dirty(path->nodes[0]); 384f186373fSMark Fasheh 3853954401fSChris Mason out: 3863954401fSChris Mason btrfs_free_path(path); 3873954401fSChris Mason return ret; 3883954401fSChris Mason } 3893954401fSChris Mason 39079787eaaSJeff Mahoney /* Will return 0, -ENOMEM, -EMLINK, or -EEXIST or anything from the CoW path */ 3913954401fSChris Mason int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, 3923954401fSChris Mason struct btrfs_root *root, 3933954401fSChris Mason const char *name, int name_len, 394aec7477bSJosef Bacik u64 inode_objectid, u64 ref_objectid, u64 index) 3953954401fSChris Mason { 3963954401fSChris Mason struct btrfs_path *path; 3973954401fSChris Mason struct btrfs_key key; 3983954401fSChris Mason struct btrfs_inode_ref *ref; 3993954401fSChris Mason unsigned long ptr; 4003954401fSChris Mason int ret; 4013954401fSChris Mason int ins_len = name_len + sizeof(*ref); 4023954401fSChris Mason 4033954401fSChris Mason key.objectid = inode_objectid; 4043954401fSChris Mason key.offset = ref_objectid; 4053954401fSChris Mason btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY); 4063954401fSChris Mason 4073954401fSChris Mason path = btrfs_alloc_path(); 4083954401fSChris Mason if (!path) 4093954401fSChris Mason return -ENOMEM; 4103954401fSChris Mason 411b9473439SChris Mason path->leave_spinning = 1; 4123954401fSChris Mason ret = btrfs_insert_empty_item(trans, root, path, &key, 4133954401fSChris Mason ins_len); 4143954401fSChris Mason if (ret == -EEXIST) { 4153954401fSChris Mason u32 old_size; 4163954401fSChris Mason 4173954401fSChris Mason if (find_name_in_backref(path, name, name_len, &ref)) 4183954401fSChris Mason goto out; 4193954401fSChris Mason 4203954401fSChris Mason old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]); 4214b90c680STsutomu Itoh btrfs_extend_item(root, path, ins_len); 4223954401fSChris Mason ref = btrfs_item_ptr(path->nodes[0], path->slots[0], 4233954401fSChris Mason struct btrfs_inode_ref); 4243954401fSChris Mason ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size); 4253954401fSChris Mason btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); 426aec7477bSJosef Bacik btrfs_set_inode_ref_index(path->nodes[0], ref, index); 4273954401fSChris Mason ptr = (unsigned long)(ref + 1); 4283954401fSChris Mason ret = 0; 4293954401fSChris Mason } else if (ret < 0) { 430a5719521SYan, Zheng if (ret == -EOVERFLOW) 431a5719521SYan, Zheng ret = -EMLINK; 4323954401fSChris Mason goto out; 4333954401fSChris Mason } else { 4343954401fSChris Mason ref = btrfs_item_ptr(path->nodes[0], path->slots[0], 4353954401fSChris Mason struct btrfs_inode_ref); 4363954401fSChris Mason btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); 437aec7477bSJosef Bacik btrfs_set_inode_ref_index(path->nodes[0], ref, index); 4383954401fSChris Mason ptr = (unsigned long)(ref + 1); 4393954401fSChris Mason } 4403954401fSChris Mason write_extent_buffer(path->nodes[0], name, ptr, name_len); 4413954401fSChris Mason btrfs_mark_buffer_dirty(path->nodes[0]); 4423954401fSChris Mason 4433954401fSChris Mason out: 4443954401fSChris Mason btrfs_free_path(path); 445f186373fSMark Fasheh 446f186373fSMark Fasheh if (ret == -EMLINK) { 447f186373fSMark Fasheh struct btrfs_super_block *disk_super = root->fs_info->super_copy; 448f186373fSMark Fasheh /* We ran out of space in the ref array. Need to 449f186373fSMark Fasheh * add an extended ref. */ 450f186373fSMark Fasheh if (btrfs_super_incompat_flags(disk_super) 451f186373fSMark Fasheh & BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF) 452f186373fSMark Fasheh ret = btrfs_insert_inode_extref(trans, root, name, 453f186373fSMark Fasheh name_len, 454f186373fSMark Fasheh inode_objectid, 455f186373fSMark Fasheh ref_objectid, index); 456f186373fSMark Fasheh } 457f186373fSMark Fasheh 4583954401fSChris Mason return ret; 4593954401fSChris Mason } 4603954401fSChris Mason 4615f39d397SChris Mason int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans, 4625f39d397SChris Mason struct btrfs_root *root, 4635f39d397SChris Mason struct btrfs_path *path, u64 objectid) 4641e1d2701SChris Mason { 4651e1d2701SChris Mason struct btrfs_key key; 4661e1d2701SChris Mason int ret; 4671e1d2701SChris Mason key.objectid = objectid; 4681e1d2701SChris Mason btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY); 4691e1d2701SChris Mason key.offset = 0; 4701e1d2701SChris Mason 4715f39d397SChris Mason ret = btrfs_insert_empty_item(trans, root, path, &key, 4725f39d397SChris Mason sizeof(struct btrfs_inode_item)); 4731e1d2701SChris Mason return ret; 4741e1d2701SChris Mason } 4751e1d2701SChris Mason 476e089f05cSChris Mason int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root 477d6e4a428SChris Mason *root, struct btrfs_path *path, 478d6e4a428SChris Mason struct btrfs_key *location, int mod) 4791e1d2701SChris Mason { 4801e1d2701SChris Mason int ins_len = mod < 0 ? -1 : 0; 4811e1d2701SChris Mason int cow = mod != 0; 482d6e4a428SChris Mason int ret; 483d6e4a428SChris Mason int slot; 4845f39d397SChris Mason struct extent_buffer *leaf; 485d6e4a428SChris Mason struct btrfs_key found_key; 4861e1d2701SChris Mason 487d6e4a428SChris Mason ret = btrfs_search_slot(trans, root, location, path, ins_len, cow); 488d6e4a428SChris Mason if (ret > 0 && btrfs_key_type(location) == BTRFS_ROOT_ITEM_KEY && 489d6e4a428SChris Mason location->offset == (u64)-1 && path->slots[0] != 0) { 490d6e4a428SChris Mason slot = path->slots[0] - 1; 4915f39d397SChris Mason leaf = path->nodes[0]; 4925f39d397SChris Mason btrfs_item_key_to_cpu(leaf, &found_key, slot); 493d6e4a428SChris Mason if (found_key.objectid == location->objectid && 494d6e4a428SChris Mason btrfs_key_type(&found_key) == btrfs_key_type(location)) { 495d6e4a428SChris Mason path->slots[0]--; 496d6e4a428SChris Mason return 0; 497d6e4a428SChris Mason } 498d6e4a428SChris Mason } 499d6e4a428SChris Mason return ret; 5001e1d2701SChris Mason } 501