1 /* 2 * Copyright (C) 2007 Oracle. All rights reserved. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public 6 * License v2 as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public 14 * License along with this program; if not, write to the 15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 16 * Boston, MA 021110-1307, USA. 17 */ 18 19 #include "ctree.h" 20 #include "disk-io.h" 21 #include "transaction.h" 22 #include "print-tree.h" 23 24 static int find_name_in_backref(struct btrfs_path *path, const char *name, 25 int name_len, struct btrfs_inode_ref **ref_ret) 26 { 27 struct extent_buffer *leaf; 28 struct btrfs_inode_ref *ref; 29 unsigned long ptr; 30 unsigned long name_ptr; 31 u32 item_size; 32 u32 cur_offset = 0; 33 int len; 34 35 leaf = path->nodes[0]; 36 item_size = btrfs_item_size_nr(leaf, path->slots[0]); 37 ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); 38 while (cur_offset < item_size) { 39 ref = (struct btrfs_inode_ref *)(ptr + cur_offset); 40 len = btrfs_inode_ref_name_len(leaf, ref); 41 name_ptr = (unsigned long)(ref + 1); 42 cur_offset += len + sizeof(*ref); 43 if (len != name_len) 44 continue; 45 if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) { 46 *ref_ret = ref; 47 return 1; 48 } 49 } 50 return 0; 51 } 52 53 struct btrfs_inode_ref * 54 btrfs_lookup_inode_ref(struct btrfs_trans_handle *trans, 55 struct btrfs_root *root, 56 struct btrfs_path *path, 57 const char *name, int name_len, 58 u64 inode_objectid, u64 ref_objectid, int mod) 59 { 60 struct btrfs_key key; 61 struct btrfs_inode_ref *ref; 62 int ins_len = mod < 0 ? -1 : 0; 63 int cow = mod != 0; 64 int ret; 65 66 key.objectid = inode_objectid; 67 key.type = BTRFS_INODE_REF_KEY; 68 key.offset = ref_objectid; 69 70 ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); 71 if (ret < 0) 72 return ERR_PTR(ret); 73 if (ret > 0) 74 return NULL; 75 if (!find_name_in_backref(path, name, name_len, &ref)) 76 return NULL; 77 return ref; 78 } 79 80 int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, 81 struct btrfs_root *root, 82 const char *name, int name_len, 83 u64 inode_objectid, u64 ref_objectid, u64 *index) 84 { 85 struct btrfs_path *path; 86 struct btrfs_key key; 87 struct btrfs_inode_ref *ref; 88 struct extent_buffer *leaf; 89 unsigned long ptr; 90 unsigned long item_start; 91 u32 item_size; 92 u32 sub_item_len; 93 int ret; 94 int del_len = name_len + sizeof(*ref); 95 96 key.objectid = inode_objectid; 97 key.offset = ref_objectid; 98 btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY); 99 100 path = btrfs_alloc_path(); 101 if (!path) 102 return -ENOMEM; 103 104 path->leave_spinning = 1; 105 106 ret = btrfs_search_slot(trans, root, &key, path, -1, 1); 107 if (ret > 0) { 108 ret = -ENOENT; 109 goto out; 110 } else if (ret < 0) { 111 goto out; 112 } 113 if (!find_name_in_backref(path, name, name_len, &ref)) { 114 ret = -ENOENT; 115 goto out; 116 } 117 leaf = path->nodes[0]; 118 item_size = btrfs_item_size_nr(leaf, path->slots[0]); 119 120 if (index) 121 *index = btrfs_inode_ref_index(leaf, ref); 122 123 if (del_len == item_size) { 124 ret = btrfs_del_item(trans, root, path); 125 goto out; 126 } 127 ptr = (unsigned long)ref; 128 sub_item_len = name_len + sizeof(*ref); 129 item_start = btrfs_item_ptr_offset(leaf, path->slots[0]); 130 memmove_extent_buffer(leaf, ptr, ptr + sub_item_len, 131 item_size - (ptr + sub_item_len - item_start)); 132 btrfs_truncate_item(trans, root, path, 133 item_size - sub_item_len, 1); 134 out: 135 btrfs_free_path(path); 136 return ret; 137 } 138 139 /* Will return 0, -ENOMEM, -EMLINK, or -EEXIST or anything from the CoW path */ 140 int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, 141 struct btrfs_root *root, 142 const char *name, int name_len, 143 u64 inode_objectid, u64 ref_objectid, u64 index) 144 { 145 struct btrfs_path *path; 146 struct btrfs_key key; 147 struct btrfs_inode_ref *ref; 148 unsigned long ptr; 149 int ret; 150 int ins_len = name_len + sizeof(*ref); 151 152 key.objectid = inode_objectid; 153 key.offset = ref_objectid; 154 btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY); 155 156 path = btrfs_alloc_path(); 157 if (!path) 158 return -ENOMEM; 159 160 path->leave_spinning = 1; 161 ret = btrfs_insert_empty_item(trans, root, path, &key, 162 ins_len); 163 if (ret == -EEXIST) { 164 u32 old_size; 165 166 if (find_name_in_backref(path, name, name_len, &ref)) 167 goto out; 168 169 old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]); 170 btrfs_extend_item(trans, root, path, ins_len); 171 ref = btrfs_item_ptr(path->nodes[0], path->slots[0], 172 struct btrfs_inode_ref); 173 ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size); 174 btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); 175 btrfs_set_inode_ref_index(path->nodes[0], ref, index); 176 ptr = (unsigned long)(ref + 1); 177 ret = 0; 178 } else if (ret < 0) { 179 if (ret == -EOVERFLOW) 180 ret = -EMLINK; 181 goto out; 182 } else { 183 ref = btrfs_item_ptr(path->nodes[0], path->slots[0], 184 struct btrfs_inode_ref); 185 btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); 186 btrfs_set_inode_ref_index(path->nodes[0], ref, index); 187 ptr = (unsigned long)(ref + 1); 188 } 189 write_extent_buffer(path->nodes[0], name, ptr, name_len); 190 btrfs_mark_buffer_dirty(path->nodes[0]); 191 192 out: 193 btrfs_free_path(path); 194 return ret; 195 } 196 197 int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans, 198 struct btrfs_root *root, 199 struct btrfs_path *path, u64 objectid) 200 { 201 struct btrfs_key key; 202 int ret; 203 key.objectid = objectid; 204 btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY); 205 key.offset = 0; 206 207 ret = btrfs_insert_empty_item(trans, root, path, &key, 208 sizeof(struct btrfs_inode_item)); 209 return ret; 210 } 211 212 int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root 213 *root, struct btrfs_path *path, 214 struct btrfs_key *location, int mod) 215 { 216 int ins_len = mod < 0 ? -1 : 0; 217 int cow = mod != 0; 218 int ret; 219 int slot; 220 struct extent_buffer *leaf; 221 struct btrfs_key found_key; 222 223 ret = btrfs_search_slot(trans, root, location, path, ins_len, cow); 224 if (ret > 0 && btrfs_key_type(location) == BTRFS_ROOT_ITEM_KEY && 225 location->offset == (u64)-1 && path->slots[0] != 0) { 226 slot = path->slots[0] - 1; 227 leaf = path->nodes[0]; 228 btrfs_item_key_to_cpu(leaf, &found_key, slot); 229 if (found_key.objectid == location->objectid && 230 btrfs_key_type(&found_key) == btrfs_key_type(location)) { 231 path->slots[0]--; 232 return 0; 233 } 234 } 235 return ret; 236 } 237