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" 221e1d2701SChris Mason 233954401fSChris Mason int find_name_in_backref(struct btrfs_path *path, const char * name, 243954401fSChris Mason int name_len, struct btrfs_inode_ref **ref_ret) 253954401fSChris Mason { 263954401fSChris Mason struct extent_buffer *leaf; 273954401fSChris Mason struct btrfs_inode_ref *ref; 283954401fSChris Mason unsigned long ptr; 293954401fSChris Mason unsigned long name_ptr; 303954401fSChris Mason u32 item_size; 313954401fSChris Mason u32 cur_offset = 0; 323954401fSChris Mason int len; 333954401fSChris Mason 343954401fSChris Mason leaf = path->nodes[0]; 353954401fSChris Mason item_size = btrfs_item_size_nr(leaf, path->slots[0]); 363954401fSChris Mason ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); 373954401fSChris Mason while (cur_offset < item_size) { 383954401fSChris Mason ref = (struct btrfs_inode_ref *)(ptr + cur_offset); 393954401fSChris Mason len = btrfs_inode_ref_name_len(leaf, ref); 403954401fSChris Mason name_ptr = (unsigned long)(ref + 1); 413954401fSChris Mason cur_offset += len + sizeof(*ref); 423954401fSChris Mason if (len != name_len) 433954401fSChris Mason continue; 443954401fSChris Mason if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) { 453954401fSChris Mason *ref_ret = ref; 463954401fSChris Mason return 1; 473954401fSChris Mason } 483954401fSChris Mason } 493954401fSChris Mason return 0; 503954401fSChris Mason } 513954401fSChris Mason 523954401fSChris Mason int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, 533954401fSChris Mason struct btrfs_root *root, 543954401fSChris Mason const char *name, int name_len, 55aec7477bSJosef Bacik u64 inode_objectid, u64 ref_objectid, u64 *index) 563954401fSChris Mason { 573954401fSChris Mason struct btrfs_path *path; 583954401fSChris Mason struct btrfs_key key; 593954401fSChris Mason struct btrfs_inode_ref *ref; 603954401fSChris Mason struct extent_buffer *leaf; 613954401fSChris Mason unsigned long ptr; 623954401fSChris Mason unsigned long item_start; 633954401fSChris Mason u32 item_size; 643954401fSChris Mason u32 sub_item_len; 653954401fSChris Mason int ret; 663954401fSChris Mason int del_len = name_len + sizeof(*ref); 673954401fSChris Mason 683954401fSChris Mason key.objectid = inode_objectid; 693954401fSChris Mason key.offset = ref_objectid; 703954401fSChris Mason btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY); 713954401fSChris Mason 723954401fSChris Mason path = btrfs_alloc_path(); 733954401fSChris Mason if (!path) 743954401fSChris Mason return -ENOMEM; 753954401fSChris Mason 763954401fSChris Mason ret = btrfs_search_slot(trans, root, &key, path, -1, 1); 773954401fSChris Mason if (ret > 0) { 783954401fSChris Mason ret = -ENOENT; 793954401fSChris Mason goto out; 803954401fSChris Mason } else if (ret < 0) { 813954401fSChris Mason goto out; 823954401fSChris Mason } 833954401fSChris Mason if (!find_name_in_backref(path, name, name_len, &ref)) { 843954401fSChris Mason ret = -ENOENT; 853954401fSChris Mason goto out; 863954401fSChris Mason } 873954401fSChris Mason leaf = path->nodes[0]; 883954401fSChris Mason item_size = btrfs_item_size_nr(leaf, path->slots[0]); 89aec7477bSJosef Bacik 90aec7477bSJosef Bacik if (index) 91aec7477bSJosef Bacik *index = btrfs_inode_ref_index(leaf, ref); 92aec7477bSJosef Bacik 933954401fSChris Mason if (del_len == item_size) { 943954401fSChris Mason ret = btrfs_del_item(trans, root, path); 953954401fSChris Mason goto out; 963954401fSChris Mason } 973954401fSChris Mason ptr = (unsigned long)ref; 983954401fSChris Mason sub_item_len = name_len + sizeof(*ref); 993954401fSChris Mason item_start = btrfs_item_ptr_offset(leaf, path->slots[0]); 1003954401fSChris Mason memmove_extent_buffer(leaf, ptr, ptr + sub_item_len, 1013954401fSChris Mason item_size - (ptr + sub_item_len - item_start)); 1023954401fSChris Mason ret = btrfs_truncate_item(trans, root, path, 1033954401fSChris Mason item_size - sub_item_len, 1); 1043954401fSChris Mason BUG_ON(ret); 1053954401fSChris Mason out: 1063954401fSChris Mason btrfs_free_path(path); 1073954401fSChris Mason return ret; 1083954401fSChris Mason } 1093954401fSChris Mason 1103954401fSChris Mason int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, 1113954401fSChris Mason struct btrfs_root *root, 1123954401fSChris Mason const char *name, int name_len, 113aec7477bSJosef Bacik u64 inode_objectid, u64 ref_objectid, u64 index) 1143954401fSChris Mason { 1153954401fSChris Mason struct btrfs_path *path; 1163954401fSChris Mason struct btrfs_key key; 1173954401fSChris Mason struct btrfs_inode_ref *ref; 1183954401fSChris Mason unsigned long ptr; 1193954401fSChris Mason int ret; 1203954401fSChris Mason int ins_len = name_len + sizeof(*ref); 1213954401fSChris Mason 1223954401fSChris Mason key.objectid = inode_objectid; 1233954401fSChris Mason key.offset = ref_objectid; 1243954401fSChris Mason btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY); 1253954401fSChris Mason 1263954401fSChris Mason path = btrfs_alloc_path(); 1273954401fSChris Mason if (!path) 1283954401fSChris Mason return -ENOMEM; 1293954401fSChris Mason 1303954401fSChris Mason ret = btrfs_insert_empty_item(trans, root, path, &key, 1313954401fSChris Mason ins_len); 1323954401fSChris Mason if (ret == -EEXIST) { 1333954401fSChris Mason u32 old_size; 1343954401fSChris Mason 1353954401fSChris Mason if (find_name_in_backref(path, name, name_len, &ref)) 1363954401fSChris Mason goto out; 1373954401fSChris Mason 1383954401fSChris Mason old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]); 1393954401fSChris Mason ret = btrfs_extend_item(trans, root, path, ins_len); 1403954401fSChris Mason BUG_ON(ret); 1413954401fSChris Mason ref = btrfs_item_ptr(path->nodes[0], path->slots[0], 1423954401fSChris Mason struct btrfs_inode_ref); 1433954401fSChris Mason ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size); 1443954401fSChris Mason btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); 145aec7477bSJosef Bacik btrfs_set_inode_ref_index(path->nodes[0], ref, index); 1463954401fSChris Mason ptr = (unsigned long)(ref + 1); 1473954401fSChris Mason ret = 0; 1483954401fSChris Mason } else if (ret < 0) { 1493954401fSChris Mason goto out; 1503954401fSChris Mason } else { 1513954401fSChris Mason ref = btrfs_item_ptr(path->nodes[0], path->slots[0], 1523954401fSChris Mason struct btrfs_inode_ref); 1533954401fSChris Mason btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); 154aec7477bSJosef Bacik btrfs_set_inode_ref_index(path->nodes[0], ref, index); 1553954401fSChris Mason ptr = (unsigned long)(ref + 1); 1563954401fSChris Mason } 1573954401fSChris Mason write_extent_buffer(path->nodes[0], name, ptr, name_len); 1583954401fSChris Mason btrfs_mark_buffer_dirty(path->nodes[0]); 1593954401fSChris Mason 1603954401fSChris Mason out: 1613954401fSChris Mason btrfs_free_path(path); 1623954401fSChris Mason return ret; 1633954401fSChris Mason } 1643954401fSChris Mason 1655f39d397SChris Mason int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans, 1665f39d397SChris Mason struct btrfs_root *root, 1675f39d397SChris Mason struct btrfs_path *path, u64 objectid) 1681e1d2701SChris Mason { 1691e1d2701SChris Mason struct btrfs_key key; 1701e1d2701SChris Mason int ret; 1711e1d2701SChris Mason key.objectid = objectid; 1721e1d2701SChris Mason btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY); 1731e1d2701SChris Mason key.offset = 0; 1741e1d2701SChris Mason 1755f39d397SChris Mason ret = btrfs_insert_empty_item(trans, root, path, &key, 1765f39d397SChris Mason sizeof(struct btrfs_inode_item)); 1771b05da2eSChris Mason if (ret == 0 && objectid > root->highest_inode) 1781b05da2eSChris Mason root->highest_inode = objectid; 1791e1d2701SChris Mason return ret; 1801e1d2701SChris Mason } 1811e1d2701SChris Mason 182e089f05cSChris Mason int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root 183d6e4a428SChris Mason *root, struct btrfs_path *path, 184d6e4a428SChris Mason struct btrfs_key *location, int mod) 1851e1d2701SChris Mason { 1861e1d2701SChris Mason int ins_len = mod < 0 ? -1 : 0; 1871e1d2701SChris Mason int cow = mod != 0; 188d6e4a428SChris Mason int ret; 189d6e4a428SChris Mason int slot; 1905f39d397SChris Mason struct extent_buffer *leaf; 191d6e4a428SChris Mason struct btrfs_key found_key; 1921e1d2701SChris Mason 193d6e4a428SChris Mason ret = btrfs_search_slot(trans, root, location, path, ins_len, cow); 194d6e4a428SChris Mason if (ret > 0 && btrfs_key_type(location) == BTRFS_ROOT_ITEM_KEY && 195d6e4a428SChris Mason location->offset == (u64)-1 && path->slots[0] != 0) { 196d6e4a428SChris Mason slot = path->slots[0] - 1; 1975f39d397SChris Mason leaf = path->nodes[0]; 1985f39d397SChris Mason btrfs_item_key_to_cpu(leaf, &found_key, slot); 199d6e4a428SChris Mason if (found_key.objectid == location->objectid && 200d6e4a428SChris Mason btrfs_key_type(&found_key) == btrfs_key_type(location)) { 201d6e4a428SChris Mason path->slots[0]--; 202d6e4a428SChris Mason return 0; 203d6e4a428SChris Mason } 204d6e4a428SChris Mason } 205d6e4a428SChris Mason return ret; 2061e1d2701SChris Mason } 207