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" 21e089f05cSChris Mason #include "transaction.h" 22727011e0SChris Mason #include "print-tree.h" 231e1d2701SChris Mason 24b2950863SChristoph Hellwig static int find_name_in_backref(struct btrfs_path *path, const char *name, 253954401fSChris Mason int name_len, struct btrfs_inode_ref **ref_ret) 263954401fSChris Mason { 273954401fSChris Mason struct extent_buffer *leaf; 283954401fSChris Mason struct btrfs_inode_ref *ref; 293954401fSChris Mason unsigned long ptr; 303954401fSChris Mason unsigned long name_ptr; 313954401fSChris Mason u32 item_size; 323954401fSChris Mason u32 cur_offset = 0; 333954401fSChris Mason int len; 343954401fSChris Mason 353954401fSChris Mason leaf = path->nodes[0]; 363954401fSChris Mason item_size = btrfs_item_size_nr(leaf, path->slots[0]); 373954401fSChris Mason ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); 383954401fSChris Mason while (cur_offset < item_size) { 393954401fSChris Mason ref = (struct btrfs_inode_ref *)(ptr + cur_offset); 403954401fSChris Mason len = btrfs_inode_ref_name_len(leaf, ref); 413954401fSChris Mason name_ptr = (unsigned long)(ref + 1); 423954401fSChris Mason cur_offset += len + sizeof(*ref); 433954401fSChris Mason if (len != name_len) 443954401fSChris Mason continue; 453954401fSChris Mason if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) { 463954401fSChris Mason *ref_ret = ref; 473954401fSChris Mason return 1; 483954401fSChris Mason } 493954401fSChris Mason } 503954401fSChris Mason return 0; 513954401fSChris Mason } 523954401fSChris Mason 53a22285a6SYan, Zheng struct btrfs_inode_ref * 54a22285a6SYan, Zheng btrfs_lookup_inode_ref(struct btrfs_trans_handle *trans, 55a22285a6SYan, Zheng struct btrfs_root *root, 56a22285a6SYan, Zheng struct btrfs_path *path, 57a22285a6SYan, Zheng const char *name, int name_len, 58a22285a6SYan, Zheng u64 inode_objectid, u64 ref_objectid, int mod) 59a22285a6SYan, Zheng { 60a22285a6SYan, Zheng struct btrfs_key key; 61a22285a6SYan, Zheng struct btrfs_inode_ref *ref; 62a22285a6SYan, Zheng int ins_len = mod < 0 ? -1 : 0; 63a22285a6SYan, Zheng int cow = mod != 0; 64a22285a6SYan, Zheng int ret; 65a22285a6SYan, Zheng 66a22285a6SYan, Zheng key.objectid = inode_objectid; 67a22285a6SYan, Zheng key.type = BTRFS_INODE_REF_KEY; 68a22285a6SYan, Zheng key.offset = ref_objectid; 69a22285a6SYan, Zheng 70a22285a6SYan, Zheng ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); 71a22285a6SYan, Zheng if (ret < 0) 72a22285a6SYan, Zheng return ERR_PTR(ret); 73a22285a6SYan, Zheng if (ret > 0) 74a22285a6SYan, Zheng return NULL; 75a22285a6SYan, Zheng if (!find_name_in_backref(path, name, name_len, &ref)) 76a22285a6SYan, Zheng return NULL; 77a22285a6SYan, Zheng return ref; 78a22285a6SYan, Zheng } 79a22285a6SYan, Zheng 803954401fSChris Mason int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, 813954401fSChris Mason struct btrfs_root *root, 823954401fSChris Mason const char *name, int name_len, 83aec7477bSJosef Bacik u64 inode_objectid, u64 ref_objectid, u64 *index) 843954401fSChris Mason { 853954401fSChris Mason struct btrfs_path *path; 863954401fSChris Mason struct btrfs_key key; 873954401fSChris Mason struct btrfs_inode_ref *ref; 883954401fSChris Mason struct extent_buffer *leaf; 893954401fSChris Mason unsigned long ptr; 903954401fSChris Mason unsigned long item_start; 913954401fSChris Mason u32 item_size; 923954401fSChris Mason u32 sub_item_len; 933954401fSChris Mason int ret; 943954401fSChris Mason int del_len = name_len + sizeof(*ref); 953954401fSChris Mason 963954401fSChris Mason key.objectid = inode_objectid; 973954401fSChris Mason key.offset = ref_objectid; 983954401fSChris Mason btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY); 993954401fSChris Mason 1003954401fSChris Mason path = btrfs_alloc_path(); 1013954401fSChris Mason if (!path) 1023954401fSChris Mason return -ENOMEM; 1033954401fSChris Mason 104b9473439SChris Mason path->leave_spinning = 1; 105b9473439SChris Mason 1063954401fSChris Mason ret = btrfs_search_slot(trans, root, &key, path, -1, 1); 1073954401fSChris Mason if (ret > 0) { 1083954401fSChris Mason ret = -ENOENT; 1093954401fSChris Mason goto out; 1103954401fSChris Mason } else if (ret < 0) { 1113954401fSChris Mason goto out; 1123954401fSChris Mason } 1133954401fSChris Mason if (!find_name_in_backref(path, name, name_len, &ref)) { 1143954401fSChris Mason ret = -ENOENT; 1153954401fSChris Mason goto out; 1163954401fSChris Mason } 1173954401fSChris Mason leaf = path->nodes[0]; 1183954401fSChris Mason item_size = btrfs_item_size_nr(leaf, path->slots[0]); 119aec7477bSJosef Bacik 120aec7477bSJosef Bacik if (index) 121aec7477bSJosef Bacik *index = btrfs_inode_ref_index(leaf, ref); 122aec7477bSJosef Bacik 1233954401fSChris Mason if (del_len == item_size) { 1243954401fSChris Mason ret = btrfs_del_item(trans, root, path); 1253954401fSChris Mason goto out; 1263954401fSChris Mason } 1273954401fSChris Mason ptr = (unsigned long)ref; 1283954401fSChris Mason sub_item_len = name_len + sizeof(*ref); 1293954401fSChris Mason item_start = btrfs_item_ptr_offset(leaf, path->slots[0]); 1303954401fSChris Mason memmove_extent_buffer(leaf, ptr, ptr + sub_item_len, 1313954401fSChris Mason item_size - (ptr + sub_item_len - item_start)); 1323954401fSChris Mason ret = btrfs_truncate_item(trans, root, path, 1333954401fSChris Mason item_size - sub_item_len, 1); 1343954401fSChris Mason out: 1353954401fSChris Mason btrfs_free_path(path); 1363954401fSChris Mason return ret; 1373954401fSChris Mason } 1383954401fSChris Mason 1393954401fSChris Mason int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, 1403954401fSChris Mason struct btrfs_root *root, 1413954401fSChris Mason const char *name, int name_len, 142aec7477bSJosef Bacik u64 inode_objectid, u64 ref_objectid, u64 index) 1433954401fSChris Mason { 1443954401fSChris Mason struct btrfs_path *path; 1453954401fSChris Mason struct btrfs_key key; 1463954401fSChris Mason struct btrfs_inode_ref *ref; 1473954401fSChris Mason unsigned long ptr; 1483954401fSChris Mason int ret; 1493954401fSChris Mason int ins_len = name_len + sizeof(*ref); 1503954401fSChris Mason 1513954401fSChris Mason key.objectid = inode_objectid; 1523954401fSChris Mason key.offset = ref_objectid; 1533954401fSChris Mason btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY); 1543954401fSChris Mason 1553954401fSChris Mason path = btrfs_alloc_path(); 1563954401fSChris Mason if (!path) 1573954401fSChris Mason return -ENOMEM; 1583954401fSChris Mason 159b9473439SChris Mason path->leave_spinning = 1; 1603954401fSChris Mason ret = btrfs_insert_empty_item(trans, root, path, &key, 1613954401fSChris Mason ins_len); 1623954401fSChris Mason if (ret == -EEXIST) { 1633954401fSChris Mason u32 old_size; 1643954401fSChris Mason 1653954401fSChris Mason if (find_name_in_backref(path, name, name_len, &ref)) 1663954401fSChris Mason goto out; 1673954401fSChris Mason 1683954401fSChris Mason old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]); 1693954401fSChris Mason ret = btrfs_extend_item(trans, root, path, ins_len); 1703954401fSChris Mason ref = btrfs_item_ptr(path->nodes[0], path->slots[0], 1713954401fSChris Mason struct btrfs_inode_ref); 1723954401fSChris Mason ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size); 1733954401fSChris Mason btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); 174aec7477bSJosef Bacik btrfs_set_inode_ref_index(path->nodes[0], ref, index); 1753954401fSChris Mason ptr = (unsigned long)(ref + 1); 1763954401fSChris Mason ret = 0; 1773954401fSChris Mason } else if (ret < 0) { 178a5719521SYan, Zheng if (ret == -EOVERFLOW) 179a5719521SYan, Zheng ret = -EMLINK; 1803954401fSChris Mason goto out; 1813954401fSChris Mason } else { 1823954401fSChris Mason ref = btrfs_item_ptr(path->nodes[0], path->slots[0], 1833954401fSChris Mason struct btrfs_inode_ref); 1843954401fSChris Mason btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); 185aec7477bSJosef Bacik btrfs_set_inode_ref_index(path->nodes[0], ref, index); 1863954401fSChris Mason ptr = (unsigned long)(ref + 1); 1873954401fSChris Mason } 1883954401fSChris Mason write_extent_buffer(path->nodes[0], name, ptr, name_len); 1893954401fSChris Mason btrfs_mark_buffer_dirty(path->nodes[0]); 1903954401fSChris Mason 1913954401fSChris Mason out: 1923954401fSChris Mason btrfs_free_path(path); 1933954401fSChris Mason return ret; 1943954401fSChris Mason } 1953954401fSChris Mason 1965f39d397SChris Mason int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans, 1975f39d397SChris Mason struct btrfs_root *root, 1985f39d397SChris Mason struct btrfs_path *path, u64 objectid) 1991e1d2701SChris Mason { 2001e1d2701SChris Mason struct btrfs_key key; 2011e1d2701SChris Mason int ret; 2021e1d2701SChris Mason key.objectid = objectid; 2031e1d2701SChris Mason btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY); 2041e1d2701SChris Mason key.offset = 0; 2051e1d2701SChris Mason 2065f39d397SChris Mason ret = btrfs_insert_empty_item(trans, root, path, &key, 2075f39d397SChris Mason sizeof(struct btrfs_inode_item)); 2081e1d2701SChris Mason return ret; 2091e1d2701SChris Mason } 2101e1d2701SChris Mason 211e089f05cSChris Mason int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root 212d6e4a428SChris Mason *root, struct btrfs_path *path, 213d6e4a428SChris Mason struct btrfs_key *location, int mod) 2141e1d2701SChris Mason { 2151e1d2701SChris Mason int ins_len = mod < 0 ? -1 : 0; 2161e1d2701SChris Mason int cow = mod != 0; 217d6e4a428SChris Mason int ret; 218d6e4a428SChris Mason int slot; 2195f39d397SChris Mason struct extent_buffer *leaf; 220d6e4a428SChris Mason struct btrfs_key found_key; 2211e1d2701SChris Mason 222d6e4a428SChris Mason ret = btrfs_search_slot(trans, root, location, path, ins_len, cow); 223d6e4a428SChris Mason if (ret > 0 && btrfs_key_type(location) == BTRFS_ROOT_ITEM_KEY && 224d6e4a428SChris Mason location->offset == (u64)-1 && path->slots[0] != 0) { 225d6e4a428SChris Mason slot = path->slots[0] - 1; 2265f39d397SChris Mason leaf = path->nodes[0]; 2275f39d397SChris Mason btrfs_item_key_to_cpu(leaf, &found_key, slot); 228d6e4a428SChris Mason if (found_key.objectid == location->objectid && 229d6e4a428SChris Mason btrfs_key_type(&found_key) == btrfs_key_type(location)) { 230d6e4a428SChris Mason path->slots[0]--; 231d6e4a428SChris Mason return 0; 232d6e4a428SChris Mason } 233d6e4a428SChris Mason } 234d6e4a428SChris Mason return ret; 2351e1d2701SChris Mason } 236