18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2007 Oracle. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include "ctree.h" 78c2ecf20Sopenharmony_ci#include "disk-io.h" 88c2ecf20Sopenharmony_ci#include "transaction.h" 98c2ecf20Sopenharmony_ci#include "print-tree.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_cistruct btrfs_inode_ref *btrfs_find_name_in_backref(struct extent_buffer *leaf, 128c2ecf20Sopenharmony_ci int slot, const char *name, 138c2ecf20Sopenharmony_ci int name_len) 148c2ecf20Sopenharmony_ci{ 158c2ecf20Sopenharmony_ci struct btrfs_inode_ref *ref; 168c2ecf20Sopenharmony_ci unsigned long ptr; 178c2ecf20Sopenharmony_ci unsigned long name_ptr; 188c2ecf20Sopenharmony_ci u32 item_size; 198c2ecf20Sopenharmony_ci u32 cur_offset = 0; 208c2ecf20Sopenharmony_ci int len; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci item_size = btrfs_item_size_nr(leaf, slot); 238c2ecf20Sopenharmony_ci ptr = btrfs_item_ptr_offset(leaf, slot); 248c2ecf20Sopenharmony_ci while (cur_offset < item_size) { 258c2ecf20Sopenharmony_ci ref = (struct btrfs_inode_ref *)(ptr + cur_offset); 268c2ecf20Sopenharmony_ci len = btrfs_inode_ref_name_len(leaf, ref); 278c2ecf20Sopenharmony_ci name_ptr = (unsigned long)(ref + 1); 288c2ecf20Sopenharmony_ci cur_offset += len + sizeof(*ref); 298c2ecf20Sopenharmony_ci if (len != name_len) 308c2ecf20Sopenharmony_ci continue; 318c2ecf20Sopenharmony_ci if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) 328c2ecf20Sopenharmony_ci return ref; 338c2ecf20Sopenharmony_ci } 348c2ecf20Sopenharmony_ci return NULL; 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistruct btrfs_inode_extref *btrfs_find_name_in_ext_backref( 388c2ecf20Sopenharmony_ci struct extent_buffer *leaf, int slot, u64 ref_objectid, 398c2ecf20Sopenharmony_ci const char *name, int name_len) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct btrfs_inode_extref *extref; 428c2ecf20Sopenharmony_ci unsigned long ptr; 438c2ecf20Sopenharmony_ci unsigned long name_ptr; 448c2ecf20Sopenharmony_ci u32 item_size; 458c2ecf20Sopenharmony_ci u32 cur_offset = 0; 468c2ecf20Sopenharmony_ci int ref_name_len; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci item_size = btrfs_item_size_nr(leaf, slot); 498c2ecf20Sopenharmony_ci ptr = btrfs_item_ptr_offset(leaf, slot); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci /* 528c2ecf20Sopenharmony_ci * Search all extended backrefs in this item. We're only 538c2ecf20Sopenharmony_ci * looking through any collisions so most of the time this is 548c2ecf20Sopenharmony_ci * just going to compare against one buffer. If all is well, 558c2ecf20Sopenharmony_ci * we'll return success and the inode ref object. 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_ci while (cur_offset < item_size) { 588c2ecf20Sopenharmony_ci extref = (struct btrfs_inode_extref *) (ptr + cur_offset); 598c2ecf20Sopenharmony_ci name_ptr = (unsigned long)(&extref->name); 608c2ecf20Sopenharmony_ci ref_name_len = btrfs_inode_extref_name_len(leaf, extref); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (ref_name_len == name_len && 638c2ecf20Sopenharmony_ci btrfs_inode_extref_parent(leaf, extref) == ref_objectid && 648c2ecf20Sopenharmony_ci (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)) 658c2ecf20Sopenharmony_ci return extref; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci cur_offset += ref_name_len + sizeof(*extref); 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci return NULL; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* Returns NULL if no extref found */ 738c2ecf20Sopenharmony_cistruct btrfs_inode_extref * 748c2ecf20Sopenharmony_cibtrfs_lookup_inode_extref(struct btrfs_trans_handle *trans, 758c2ecf20Sopenharmony_ci struct btrfs_root *root, 768c2ecf20Sopenharmony_ci struct btrfs_path *path, 778c2ecf20Sopenharmony_ci const char *name, int name_len, 788c2ecf20Sopenharmony_ci u64 inode_objectid, u64 ref_objectid, int ins_len, 798c2ecf20Sopenharmony_ci int cow) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci int ret; 828c2ecf20Sopenharmony_ci struct btrfs_key key; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci key.objectid = inode_objectid; 858c2ecf20Sopenharmony_ci key.type = BTRFS_INODE_EXTREF_KEY; 868c2ecf20Sopenharmony_ci key.offset = btrfs_extref_hash(ref_objectid, name, name_len); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); 898c2ecf20Sopenharmony_ci if (ret < 0) 908c2ecf20Sopenharmony_ci return ERR_PTR(ret); 918c2ecf20Sopenharmony_ci if (ret > 0) 928c2ecf20Sopenharmony_ci return NULL; 938c2ecf20Sopenharmony_ci return btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0], 948c2ecf20Sopenharmony_ci ref_objectid, name, name_len); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic int btrfs_del_inode_extref(struct btrfs_trans_handle *trans, 998c2ecf20Sopenharmony_ci struct btrfs_root *root, 1008c2ecf20Sopenharmony_ci const char *name, int name_len, 1018c2ecf20Sopenharmony_ci u64 inode_objectid, u64 ref_objectid, 1028c2ecf20Sopenharmony_ci u64 *index) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci struct btrfs_path *path; 1058c2ecf20Sopenharmony_ci struct btrfs_key key; 1068c2ecf20Sopenharmony_ci struct btrfs_inode_extref *extref; 1078c2ecf20Sopenharmony_ci struct extent_buffer *leaf; 1088c2ecf20Sopenharmony_ci int ret; 1098c2ecf20Sopenharmony_ci int del_len = name_len + sizeof(*extref); 1108c2ecf20Sopenharmony_ci unsigned long ptr; 1118c2ecf20Sopenharmony_ci unsigned long item_start; 1128c2ecf20Sopenharmony_ci u32 item_size; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci key.objectid = inode_objectid; 1158c2ecf20Sopenharmony_ci key.type = BTRFS_INODE_EXTREF_KEY; 1168c2ecf20Sopenharmony_ci key.offset = btrfs_extref_hash(ref_objectid, name, name_len); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 1198c2ecf20Sopenharmony_ci if (!path) 1208c2ecf20Sopenharmony_ci return -ENOMEM; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci path->leave_spinning = 1; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci ret = btrfs_search_slot(trans, root, &key, path, -1, 1); 1258c2ecf20Sopenharmony_ci if (ret > 0) 1268c2ecf20Sopenharmony_ci ret = -ENOENT; 1278c2ecf20Sopenharmony_ci if (ret < 0) 1288c2ecf20Sopenharmony_ci goto out; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* 1318c2ecf20Sopenharmony_ci * Sanity check - did we find the right item for this name? 1328c2ecf20Sopenharmony_ci * This should always succeed so error here will make the FS 1338c2ecf20Sopenharmony_ci * readonly. 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ci extref = btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0], 1368c2ecf20Sopenharmony_ci ref_objectid, name, name_len); 1378c2ecf20Sopenharmony_ci if (!extref) { 1388c2ecf20Sopenharmony_ci btrfs_handle_fs_error(root->fs_info, -ENOENT, NULL); 1398c2ecf20Sopenharmony_ci ret = -EROFS; 1408c2ecf20Sopenharmony_ci goto out; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci leaf = path->nodes[0]; 1448c2ecf20Sopenharmony_ci item_size = btrfs_item_size_nr(leaf, path->slots[0]); 1458c2ecf20Sopenharmony_ci if (index) 1468c2ecf20Sopenharmony_ci *index = btrfs_inode_extref_index(leaf, extref); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (del_len == item_size) { 1498c2ecf20Sopenharmony_ci /* 1508c2ecf20Sopenharmony_ci * Common case only one ref in the item, remove the 1518c2ecf20Sopenharmony_ci * whole item. 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_ci ret = btrfs_del_item(trans, root, path); 1548c2ecf20Sopenharmony_ci goto out; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci ptr = (unsigned long)extref; 1588c2ecf20Sopenharmony_ci item_start = btrfs_item_ptr_offset(leaf, path->slots[0]); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci memmove_extent_buffer(leaf, ptr, ptr + del_len, 1618c2ecf20Sopenharmony_ci item_size - (ptr + del_len - item_start)); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci btrfs_truncate_item(path, item_size - del_len, 1); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ciout: 1668c2ecf20Sopenharmony_ci btrfs_free_path(path); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci return ret; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ciint btrfs_del_inode_ref(struct btrfs_trans_handle *trans, 1728c2ecf20Sopenharmony_ci struct btrfs_root *root, 1738c2ecf20Sopenharmony_ci const char *name, int name_len, 1748c2ecf20Sopenharmony_ci u64 inode_objectid, u64 ref_objectid, u64 *index) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci struct btrfs_path *path; 1778c2ecf20Sopenharmony_ci struct btrfs_key key; 1788c2ecf20Sopenharmony_ci struct btrfs_inode_ref *ref; 1798c2ecf20Sopenharmony_ci struct extent_buffer *leaf; 1808c2ecf20Sopenharmony_ci unsigned long ptr; 1818c2ecf20Sopenharmony_ci unsigned long item_start; 1828c2ecf20Sopenharmony_ci u32 item_size; 1838c2ecf20Sopenharmony_ci u32 sub_item_len; 1848c2ecf20Sopenharmony_ci int ret; 1858c2ecf20Sopenharmony_ci int search_ext_refs = 0; 1868c2ecf20Sopenharmony_ci int del_len = name_len + sizeof(*ref); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci key.objectid = inode_objectid; 1898c2ecf20Sopenharmony_ci key.offset = ref_objectid; 1908c2ecf20Sopenharmony_ci key.type = BTRFS_INODE_REF_KEY; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 1938c2ecf20Sopenharmony_ci if (!path) 1948c2ecf20Sopenharmony_ci return -ENOMEM; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci path->leave_spinning = 1; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci ret = btrfs_search_slot(trans, root, &key, path, -1, 1); 1998c2ecf20Sopenharmony_ci if (ret > 0) { 2008c2ecf20Sopenharmony_ci ret = -ENOENT; 2018c2ecf20Sopenharmony_ci search_ext_refs = 1; 2028c2ecf20Sopenharmony_ci goto out; 2038c2ecf20Sopenharmony_ci } else if (ret < 0) { 2048c2ecf20Sopenharmony_ci goto out; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci ref = btrfs_find_name_in_backref(path->nodes[0], path->slots[0], name, 2088c2ecf20Sopenharmony_ci name_len); 2098c2ecf20Sopenharmony_ci if (!ref) { 2108c2ecf20Sopenharmony_ci ret = -ENOENT; 2118c2ecf20Sopenharmony_ci search_ext_refs = 1; 2128c2ecf20Sopenharmony_ci goto out; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci leaf = path->nodes[0]; 2158c2ecf20Sopenharmony_ci item_size = btrfs_item_size_nr(leaf, path->slots[0]); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (index) 2188c2ecf20Sopenharmony_ci *index = btrfs_inode_ref_index(leaf, ref); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (del_len == item_size) { 2218c2ecf20Sopenharmony_ci ret = btrfs_del_item(trans, root, path); 2228c2ecf20Sopenharmony_ci goto out; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci ptr = (unsigned long)ref; 2258c2ecf20Sopenharmony_ci sub_item_len = name_len + sizeof(*ref); 2268c2ecf20Sopenharmony_ci item_start = btrfs_item_ptr_offset(leaf, path->slots[0]); 2278c2ecf20Sopenharmony_ci memmove_extent_buffer(leaf, ptr, ptr + sub_item_len, 2288c2ecf20Sopenharmony_ci item_size - (ptr + sub_item_len - item_start)); 2298c2ecf20Sopenharmony_ci btrfs_truncate_item(path, item_size - sub_item_len, 1); 2308c2ecf20Sopenharmony_ciout: 2318c2ecf20Sopenharmony_ci btrfs_free_path(path); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if (search_ext_refs) { 2348c2ecf20Sopenharmony_ci /* 2358c2ecf20Sopenharmony_ci * No refs were found, or we could not find the 2368c2ecf20Sopenharmony_ci * name in our ref array. Find and remove the extended 2378c2ecf20Sopenharmony_ci * inode ref then. 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_ci return btrfs_del_inode_extref(trans, root, name, name_len, 2408c2ecf20Sopenharmony_ci inode_objectid, ref_objectid, index); 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci return ret; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci/* 2478c2ecf20Sopenharmony_ci * btrfs_insert_inode_extref() - Inserts an extended inode ref into a tree. 2488c2ecf20Sopenharmony_ci * 2498c2ecf20Sopenharmony_ci * The caller must have checked against BTRFS_LINK_MAX already. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_cistatic int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans, 2528c2ecf20Sopenharmony_ci struct btrfs_root *root, 2538c2ecf20Sopenharmony_ci const char *name, int name_len, 2548c2ecf20Sopenharmony_ci u64 inode_objectid, u64 ref_objectid, u64 index) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct btrfs_inode_extref *extref; 2578c2ecf20Sopenharmony_ci int ret; 2588c2ecf20Sopenharmony_ci int ins_len = name_len + sizeof(*extref); 2598c2ecf20Sopenharmony_ci unsigned long ptr; 2608c2ecf20Sopenharmony_ci struct btrfs_path *path; 2618c2ecf20Sopenharmony_ci struct btrfs_key key; 2628c2ecf20Sopenharmony_ci struct extent_buffer *leaf; 2638c2ecf20Sopenharmony_ci struct btrfs_item *item; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci key.objectid = inode_objectid; 2668c2ecf20Sopenharmony_ci key.type = BTRFS_INODE_EXTREF_KEY; 2678c2ecf20Sopenharmony_ci key.offset = btrfs_extref_hash(ref_objectid, name, name_len); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 2708c2ecf20Sopenharmony_ci if (!path) 2718c2ecf20Sopenharmony_ci return -ENOMEM; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci path->leave_spinning = 1; 2748c2ecf20Sopenharmony_ci ret = btrfs_insert_empty_item(trans, root, path, &key, 2758c2ecf20Sopenharmony_ci ins_len); 2768c2ecf20Sopenharmony_ci if (ret == -EEXIST) { 2778c2ecf20Sopenharmony_ci if (btrfs_find_name_in_ext_backref(path->nodes[0], 2788c2ecf20Sopenharmony_ci path->slots[0], 2798c2ecf20Sopenharmony_ci ref_objectid, 2808c2ecf20Sopenharmony_ci name, name_len)) 2818c2ecf20Sopenharmony_ci goto out; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci btrfs_extend_item(path, ins_len); 2848c2ecf20Sopenharmony_ci ret = 0; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci if (ret < 0) 2878c2ecf20Sopenharmony_ci goto out; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci leaf = path->nodes[0]; 2908c2ecf20Sopenharmony_ci item = btrfs_item_nr(path->slots[0]); 2918c2ecf20Sopenharmony_ci ptr = (unsigned long)btrfs_item_ptr(leaf, path->slots[0], char); 2928c2ecf20Sopenharmony_ci ptr += btrfs_item_size(leaf, item) - ins_len; 2938c2ecf20Sopenharmony_ci extref = (struct btrfs_inode_extref *)ptr; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci btrfs_set_inode_extref_name_len(path->nodes[0], extref, name_len); 2968c2ecf20Sopenharmony_ci btrfs_set_inode_extref_index(path->nodes[0], extref, index); 2978c2ecf20Sopenharmony_ci btrfs_set_inode_extref_parent(path->nodes[0], extref, ref_objectid); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci ptr = (unsigned long)&extref->name; 3008c2ecf20Sopenharmony_ci write_extent_buffer(path->nodes[0], name, ptr, name_len); 3018c2ecf20Sopenharmony_ci btrfs_mark_buffer_dirty(path->nodes[0]); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ciout: 3048c2ecf20Sopenharmony_ci btrfs_free_path(path); 3058c2ecf20Sopenharmony_ci return ret; 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci/* Will return 0, -ENOMEM, -EMLINK, or -EEXIST or anything from the CoW path */ 3098c2ecf20Sopenharmony_ciint btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, 3108c2ecf20Sopenharmony_ci struct btrfs_root *root, 3118c2ecf20Sopenharmony_ci const char *name, int name_len, 3128c2ecf20Sopenharmony_ci u64 inode_objectid, u64 ref_objectid, u64 index) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = root->fs_info; 3158c2ecf20Sopenharmony_ci struct btrfs_path *path; 3168c2ecf20Sopenharmony_ci struct btrfs_key key; 3178c2ecf20Sopenharmony_ci struct btrfs_inode_ref *ref; 3188c2ecf20Sopenharmony_ci unsigned long ptr; 3198c2ecf20Sopenharmony_ci int ret; 3208c2ecf20Sopenharmony_ci int ins_len = name_len + sizeof(*ref); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci key.objectid = inode_objectid; 3238c2ecf20Sopenharmony_ci key.offset = ref_objectid; 3248c2ecf20Sopenharmony_ci key.type = BTRFS_INODE_REF_KEY; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 3278c2ecf20Sopenharmony_ci if (!path) 3288c2ecf20Sopenharmony_ci return -ENOMEM; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci path->leave_spinning = 1; 3318c2ecf20Sopenharmony_ci path->skip_release_on_error = 1; 3328c2ecf20Sopenharmony_ci ret = btrfs_insert_empty_item(trans, root, path, &key, 3338c2ecf20Sopenharmony_ci ins_len); 3348c2ecf20Sopenharmony_ci if (ret == -EEXIST) { 3358c2ecf20Sopenharmony_ci u32 old_size; 3368c2ecf20Sopenharmony_ci ref = btrfs_find_name_in_backref(path->nodes[0], path->slots[0], 3378c2ecf20Sopenharmony_ci name, name_len); 3388c2ecf20Sopenharmony_ci if (ref) 3398c2ecf20Sopenharmony_ci goto out; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]); 3428c2ecf20Sopenharmony_ci btrfs_extend_item(path, ins_len); 3438c2ecf20Sopenharmony_ci ref = btrfs_item_ptr(path->nodes[0], path->slots[0], 3448c2ecf20Sopenharmony_ci struct btrfs_inode_ref); 3458c2ecf20Sopenharmony_ci ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size); 3468c2ecf20Sopenharmony_ci btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); 3478c2ecf20Sopenharmony_ci btrfs_set_inode_ref_index(path->nodes[0], ref, index); 3488c2ecf20Sopenharmony_ci ptr = (unsigned long)(ref + 1); 3498c2ecf20Sopenharmony_ci ret = 0; 3508c2ecf20Sopenharmony_ci } else if (ret < 0) { 3518c2ecf20Sopenharmony_ci if (ret == -EOVERFLOW) { 3528c2ecf20Sopenharmony_ci if (btrfs_find_name_in_backref(path->nodes[0], 3538c2ecf20Sopenharmony_ci path->slots[0], 3548c2ecf20Sopenharmony_ci name, name_len)) 3558c2ecf20Sopenharmony_ci ret = -EEXIST; 3568c2ecf20Sopenharmony_ci else 3578c2ecf20Sopenharmony_ci ret = -EMLINK; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci goto out; 3608c2ecf20Sopenharmony_ci } else { 3618c2ecf20Sopenharmony_ci ref = btrfs_item_ptr(path->nodes[0], path->slots[0], 3628c2ecf20Sopenharmony_ci struct btrfs_inode_ref); 3638c2ecf20Sopenharmony_ci btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); 3648c2ecf20Sopenharmony_ci btrfs_set_inode_ref_index(path->nodes[0], ref, index); 3658c2ecf20Sopenharmony_ci ptr = (unsigned long)(ref + 1); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci write_extent_buffer(path->nodes[0], name, ptr, name_len); 3688c2ecf20Sopenharmony_ci btrfs_mark_buffer_dirty(path->nodes[0]); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ciout: 3718c2ecf20Sopenharmony_ci btrfs_free_path(path); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (ret == -EMLINK) { 3748c2ecf20Sopenharmony_ci struct btrfs_super_block *disk_super = fs_info->super_copy; 3758c2ecf20Sopenharmony_ci /* We ran out of space in the ref array. Need to 3768c2ecf20Sopenharmony_ci * add an extended ref. */ 3778c2ecf20Sopenharmony_ci if (btrfs_super_incompat_flags(disk_super) 3788c2ecf20Sopenharmony_ci & BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF) 3798c2ecf20Sopenharmony_ci ret = btrfs_insert_inode_extref(trans, root, name, 3808c2ecf20Sopenharmony_ci name_len, 3818c2ecf20Sopenharmony_ci inode_objectid, 3828c2ecf20Sopenharmony_ci ref_objectid, index); 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci return ret; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ciint btrfs_insert_empty_inode(struct btrfs_trans_handle *trans, 3898c2ecf20Sopenharmony_ci struct btrfs_root *root, 3908c2ecf20Sopenharmony_ci struct btrfs_path *path, u64 objectid) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci struct btrfs_key key; 3938c2ecf20Sopenharmony_ci int ret; 3948c2ecf20Sopenharmony_ci key.objectid = objectid; 3958c2ecf20Sopenharmony_ci key.type = BTRFS_INODE_ITEM_KEY; 3968c2ecf20Sopenharmony_ci key.offset = 0; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci ret = btrfs_insert_empty_item(trans, root, path, &key, 3998c2ecf20Sopenharmony_ci sizeof(struct btrfs_inode_item)); 4008c2ecf20Sopenharmony_ci return ret; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ciint btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root 4048c2ecf20Sopenharmony_ci *root, struct btrfs_path *path, 4058c2ecf20Sopenharmony_ci struct btrfs_key *location, int mod) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci int ins_len = mod < 0 ? -1 : 0; 4088c2ecf20Sopenharmony_ci int cow = mod != 0; 4098c2ecf20Sopenharmony_ci int ret; 4108c2ecf20Sopenharmony_ci int slot; 4118c2ecf20Sopenharmony_ci struct extent_buffer *leaf; 4128c2ecf20Sopenharmony_ci struct btrfs_key found_key; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci ret = btrfs_search_slot(trans, root, location, path, ins_len, cow); 4158c2ecf20Sopenharmony_ci if (ret > 0 && location->type == BTRFS_ROOT_ITEM_KEY && 4168c2ecf20Sopenharmony_ci location->offset == (u64)-1 && path->slots[0] != 0) { 4178c2ecf20Sopenharmony_ci slot = path->slots[0] - 1; 4188c2ecf20Sopenharmony_ci leaf = path->nodes[0]; 4198c2ecf20Sopenharmony_ci btrfs_item_key_to_cpu(leaf, &found_key, slot); 4208c2ecf20Sopenharmony_ci if (found_key.objectid == location->objectid && 4218c2ecf20Sopenharmony_ci found_key.type == location->type) { 4228c2ecf20Sopenharmony_ci path->slots[0]--; 4238c2ecf20Sopenharmony_ci return 0; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci return ret; 4278c2ecf20Sopenharmony_ci} 428