xref: /openbmc/linux/fs/btrfs/inode-item.c (revision 3212fa14)
1c1d7c514SDavid Sterba // SPDX-License-Identifier: GPL-2.0
26cbd5570SChris Mason /*
36cbd5570SChris Mason  * Copyright (C) 2007 Oracle.  All rights reserved.
46cbd5570SChris Mason  */
56cbd5570SChris Mason 
61e1d2701SChris Mason #include "ctree.h"
71e1d2701SChris Mason #include "disk-io.h"
8e089f05cSChris Mason #include "transaction.h"
9727011e0SChris Mason #include "print-tree.h"
101e1d2701SChris Mason 
119bb8407fSNikolay Borisov struct btrfs_inode_ref *btrfs_find_name_in_backref(struct extent_buffer *leaf,
129bb8407fSNikolay Borisov 						   int slot, const char *name,
139bb8407fSNikolay Borisov 						   int name_len)
143954401fSChris Mason {
153954401fSChris Mason 	struct btrfs_inode_ref *ref;
163954401fSChris Mason 	unsigned long ptr;
173954401fSChris Mason 	unsigned long name_ptr;
183954401fSChris Mason 	u32 item_size;
193954401fSChris Mason 	u32 cur_offset = 0;
203954401fSChris Mason 	int len;
213954401fSChris Mason 
22*3212fa14SJosef Bacik 	item_size = btrfs_item_size(leaf, slot);
231f250e92SFilipe Manana 	ptr = btrfs_item_ptr_offset(leaf, slot);
243954401fSChris Mason 	while (cur_offset < item_size) {
253954401fSChris Mason 		ref = (struct btrfs_inode_ref *)(ptr + cur_offset);
263954401fSChris Mason 		len = btrfs_inode_ref_name_len(leaf, ref);
273954401fSChris Mason 		name_ptr = (unsigned long)(ref + 1);
283954401fSChris Mason 		cur_offset += len + sizeof(*ref);
293954401fSChris Mason 		if (len != name_len)
303954401fSChris Mason 			continue;
319bb8407fSNikolay Borisov 		if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
329bb8407fSNikolay Borisov 			return ref;
333954401fSChris Mason 	}
349bb8407fSNikolay Borisov 	return NULL;
353954401fSChris Mason }
363954401fSChris Mason 
376ff49c6aSNikolay Borisov struct btrfs_inode_extref *btrfs_find_name_in_ext_backref(
386ff49c6aSNikolay Borisov 		struct extent_buffer *leaf, int slot, u64 ref_objectid,
396ff49c6aSNikolay Borisov 		const char *name, int name_len)
40f186373fSMark Fasheh {
41f186373fSMark Fasheh 	struct btrfs_inode_extref *extref;
42f186373fSMark Fasheh 	unsigned long ptr;
43f186373fSMark Fasheh 	unsigned long name_ptr;
44f186373fSMark Fasheh 	u32 item_size;
45f186373fSMark Fasheh 	u32 cur_offset = 0;
46f186373fSMark Fasheh 	int ref_name_len;
47f186373fSMark Fasheh 
48*3212fa14SJosef Bacik 	item_size = btrfs_item_size(leaf, slot);
491f250e92SFilipe Manana 	ptr = btrfs_item_ptr_offset(leaf, slot);
50f186373fSMark Fasheh 
51f186373fSMark Fasheh 	/*
52f186373fSMark Fasheh 	 * Search all extended backrefs in this item. We're only
53f186373fSMark Fasheh 	 * looking through any collisions so most of the time this is
54f186373fSMark Fasheh 	 * just going to compare against one buffer. If all is well,
55f186373fSMark Fasheh 	 * we'll return success and the inode ref object.
56f186373fSMark Fasheh 	 */
57f186373fSMark Fasheh 	while (cur_offset < item_size) {
58f186373fSMark Fasheh 		extref = (struct btrfs_inode_extref *) (ptr + cur_offset);
59f186373fSMark Fasheh 		name_ptr = (unsigned long)(&extref->name);
60f186373fSMark Fasheh 		ref_name_len = btrfs_inode_extref_name_len(leaf, extref);
61f186373fSMark Fasheh 
62f186373fSMark Fasheh 		if (ref_name_len == name_len &&
63f186373fSMark Fasheh 		    btrfs_inode_extref_parent(leaf, extref) == ref_objectid &&
646ff49c6aSNikolay Borisov 		    (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0))
656ff49c6aSNikolay Borisov 			return extref;
66f186373fSMark Fasheh 
67f186373fSMark Fasheh 		cur_offset += ref_name_len + sizeof(*extref);
68f186373fSMark Fasheh 	}
696ff49c6aSNikolay Borisov 	return NULL;
70f186373fSMark Fasheh }
71f186373fSMark Fasheh 
72f186373fSMark Fasheh /* Returns NULL if no extref found */
73f186373fSMark Fasheh struct btrfs_inode_extref *
74f186373fSMark Fasheh btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans,
75f186373fSMark Fasheh 			  struct btrfs_root *root,
76f186373fSMark Fasheh 			  struct btrfs_path *path,
77f186373fSMark Fasheh 			  const char *name, int name_len,
78f186373fSMark Fasheh 			  u64 inode_objectid, u64 ref_objectid, int ins_len,
79f186373fSMark Fasheh 			  int cow)
80f186373fSMark Fasheh {
81f186373fSMark Fasheh 	int ret;
82f186373fSMark Fasheh 	struct btrfs_key key;
83f186373fSMark Fasheh 
84f186373fSMark Fasheh 	key.objectid = inode_objectid;
85f186373fSMark Fasheh 	key.type = BTRFS_INODE_EXTREF_KEY;
86f186373fSMark Fasheh 	key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
87f186373fSMark Fasheh 
88f186373fSMark Fasheh 	ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
89f186373fSMark Fasheh 	if (ret < 0)
90f186373fSMark Fasheh 		return ERR_PTR(ret);
91f186373fSMark Fasheh 	if (ret > 0)
92f186373fSMark Fasheh 		return NULL;
936ff49c6aSNikolay Borisov 	return btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0],
946ff49c6aSNikolay Borisov 					      ref_objectid, name, name_len);
956ff49c6aSNikolay Borisov 
96f186373fSMark Fasheh }
97f186373fSMark Fasheh 
9848a3b636SEric Sandeen static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,
99f186373fSMark Fasheh 				  struct btrfs_root *root,
100f186373fSMark Fasheh 				  const char *name, int name_len,
10148a3b636SEric Sandeen 				  u64 inode_objectid, u64 ref_objectid,
10248a3b636SEric Sandeen 				  u64 *index)
103f186373fSMark Fasheh {
104f186373fSMark Fasheh 	struct btrfs_path *path;
105f186373fSMark Fasheh 	struct btrfs_key key;
106f186373fSMark Fasheh 	struct btrfs_inode_extref *extref;
107f186373fSMark Fasheh 	struct extent_buffer *leaf;
108f186373fSMark Fasheh 	int ret;
109f186373fSMark Fasheh 	int del_len = name_len + sizeof(*extref);
110f186373fSMark Fasheh 	unsigned long ptr;
111f186373fSMark Fasheh 	unsigned long item_start;
112f186373fSMark Fasheh 	u32 item_size;
113f186373fSMark Fasheh 
114f186373fSMark Fasheh 	key.objectid = inode_objectid;
115962a298fSDavid Sterba 	key.type = BTRFS_INODE_EXTREF_KEY;
116f186373fSMark Fasheh 	key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
117f186373fSMark Fasheh 
118f186373fSMark Fasheh 	path = btrfs_alloc_path();
119f186373fSMark Fasheh 	if (!path)
120f186373fSMark Fasheh 		return -ENOMEM;
121f186373fSMark Fasheh 
122f186373fSMark Fasheh 	ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
123f186373fSMark Fasheh 	if (ret > 0)
124f186373fSMark Fasheh 		ret = -ENOENT;
125f186373fSMark Fasheh 	if (ret < 0)
126f186373fSMark Fasheh 		goto out;
127f186373fSMark Fasheh 
128f186373fSMark Fasheh 	/*
129f186373fSMark Fasheh 	 * Sanity check - did we find the right item for this name?
130f186373fSMark Fasheh 	 * This should always succeed so error here will make the FS
131f186373fSMark Fasheh 	 * readonly.
132f186373fSMark Fasheh 	 */
1336ff49c6aSNikolay Borisov 	extref = btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0],
1346ff49c6aSNikolay Borisov 						ref_objectid, name, name_len);
1356ff49c6aSNikolay Borisov 	if (!extref) {
13634d97007SAnand Jain 		btrfs_handle_fs_error(root->fs_info, -ENOENT, NULL);
137f186373fSMark Fasheh 		ret = -EROFS;
138f186373fSMark Fasheh 		goto out;
139f186373fSMark Fasheh 	}
140f186373fSMark Fasheh 
141f186373fSMark Fasheh 	leaf = path->nodes[0];
142*3212fa14SJosef Bacik 	item_size = btrfs_item_size(leaf, path->slots[0]);
143f186373fSMark Fasheh 	if (index)
144f186373fSMark Fasheh 		*index = btrfs_inode_extref_index(leaf, extref);
145f186373fSMark Fasheh 
146f186373fSMark Fasheh 	if (del_len == item_size) {
147f186373fSMark Fasheh 		/*
148f186373fSMark Fasheh 		 * Common case only one ref in the item, remove the
149f186373fSMark Fasheh 		 * whole item.
150f186373fSMark Fasheh 		 */
151f186373fSMark Fasheh 		ret = btrfs_del_item(trans, root, path);
152f186373fSMark Fasheh 		goto out;
153f186373fSMark Fasheh 	}
154f186373fSMark Fasheh 
155f186373fSMark Fasheh 	ptr = (unsigned long)extref;
156f186373fSMark Fasheh 	item_start = btrfs_item_ptr_offset(leaf, path->slots[0]);
157f186373fSMark Fasheh 
158f186373fSMark Fasheh 	memmove_extent_buffer(leaf, ptr, ptr + del_len,
159f186373fSMark Fasheh 			      item_size - (ptr + del_len - item_start));
160f186373fSMark Fasheh 
16178ac4f9eSDavid Sterba 	btrfs_truncate_item(path, item_size - del_len, 1);
162f186373fSMark Fasheh 
163f186373fSMark Fasheh out:
164f186373fSMark Fasheh 	btrfs_free_path(path);
165f186373fSMark Fasheh 
166f186373fSMark Fasheh 	return ret;
167f186373fSMark Fasheh }
168f186373fSMark Fasheh 
1693954401fSChris Mason int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
1703954401fSChris Mason 			struct btrfs_root *root,
1713954401fSChris Mason 			const char *name, int name_len,
172aec7477bSJosef Bacik 			u64 inode_objectid, u64 ref_objectid, u64 *index)
1733954401fSChris Mason {
1743954401fSChris Mason 	struct btrfs_path *path;
1753954401fSChris Mason 	struct btrfs_key key;
1763954401fSChris Mason 	struct btrfs_inode_ref *ref;
1773954401fSChris Mason 	struct extent_buffer *leaf;
1783954401fSChris Mason 	unsigned long ptr;
1793954401fSChris Mason 	unsigned long item_start;
1803954401fSChris Mason 	u32 item_size;
1813954401fSChris Mason 	u32 sub_item_len;
1823954401fSChris Mason 	int ret;
183f186373fSMark Fasheh 	int search_ext_refs = 0;
1843954401fSChris Mason 	int del_len = name_len + sizeof(*ref);
1853954401fSChris Mason 
1863954401fSChris Mason 	key.objectid = inode_objectid;
1873954401fSChris Mason 	key.offset = ref_objectid;
188962a298fSDavid Sterba 	key.type = BTRFS_INODE_REF_KEY;
1893954401fSChris Mason 
1903954401fSChris Mason 	path = btrfs_alloc_path();
1913954401fSChris Mason 	if (!path)
1923954401fSChris Mason 		return -ENOMEM;
1933954401fSChris Mason 
1943954401fSChris Mason 	ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
1953954401fSChris Mason 	if (ret > 0) {
1963954401fSChris Mason 		ret = -ENOENT;
197f186373fSMark Fasheh 		search_ext_refs = 1;
1983954401fSChris Mason 		goto out;
1993954401fSChris Mason 	} else if (ret < 0) {
2003954401fSChris Mason 		goto out;
2013954401fSChris Mason 	}
2029bb8407fSNikolay Borisov 
2039bb8407fSNikolay Borisov 	ref = btrfs_find_name_in_backref(path->nodes[0], path->slots[0], name,
2049bb8407fSNikolay Borisov 					 name_len);
2059bb8407fSNikolay Borisov 	if (!ref) {
2063954401fSChris Mason 		ret = -ENOENT;
207f186373fSMark Fasheh 		search_ext_refs = 1;
2083954401fSChris Mason 		goto out;
2093954401fSChris Mason 	}
2103954401fSChris Mason 	leaf = path->nodes[0];
211*3212fa14SJosef Bacik 	item_size = btrfs_item_size(leaf, path->slots[0]);
212aec7477bSJosef Bacik 
213aec7477bSJosef Bacik 	if (index)
214aec7477bSJosef Bacik 		*index = btrfs_inode_ref_index(leaf, ref);
215aec7477bSJosef Bacik 
2163954401fSChris Mason 	if (del_len == item_size) {
2173954401fSChris Mason 		ret = btrfs_del_item(trans, root, path);
2183954401fSChris Mason 		goto out;
2193954401fSChris Mason 	}
2203954401fSChris Mason 	ptr = (unsigned long)ref;
2213954401fSChris Mason 	sub_item_len = name_len + sizeof(*ref);
2223954401fSChris Mason 	item_start = btrfs_item_ptr_offset(leaf, path->slots[0]);
2233954401fSChris Mason 	memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
2243954401fSChris Mason 			      item_size - (ptr + sub_item_len - item_start));
22578ac4f9eSDavid Sterba 	btrfs_truncate_item(path, item_size - sub_item_len, 1);
226f186373fSMark Fasheh out:
227f186373fSMark Fasheh 	btrfs_free_path(path);
228f186373fSMark Fasheh 
229f186373fSMark Fasheh 	if (search_ext_refs) {
230f186373fSMark Fasheh 		/*
231f186373fSMark Fasheh 		 * No refs were found, or we could not find the
232f186373fSMark Fasheh 		 * name in our ref array. Find and remove the extended
233f186373fSMark Fasheh 		 * inode ref then.
234f186373fSMark Fasheh 		 */
235f186373fSMark Fasheh 		return btrfs_del_inode_extref(trans, root, name, name_len,
236f186373fSMark Fasheh 					      inode_objectid, ref_objectid, index);
237f186373fSMark Fasheh 	}
238f186373fSMark Fasheh 
239f186373fSMark Fasheh 	return ret;
240f186373fSMark Fasheh }
241f186373fSMark Fasheh 
242f186373fSMark Fasheh /*
243f186373fSMark Fasheh  * btrfs_insert_inode_extref() - Inserts an extended inode ref into a tree.
244f186373fSMark Fasheh  *
245f186373fSMark Fasheh  * The caller must have checked against BTRFS_LINK_MAX already.
246f186373fSMark Fasheh  */
247f186373fSMark Fasheh static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,
248f186373fSMark Fasheh 				     struct btrfs_root *root,
249f186373fSMark Fasheh 				     const char *name, int name_len,
250f186373fSMark Fasheh 				     u64 inode_objectid, u64 ref_objectid, u64 index)
251f186373fSMark Fasheh {
252f186373fSMark Fasheh 	struct btrfs_inode_extref *extref;
253f186373fSMark Fasheh 	int ret;
254f186373fSMark Fasheh 	int ins_len = name_len + sizeof(*extref);
255f186373fSMark Fasheh 	unsigned long ptr;
256f186373fSMark Fasheh 	struct btrfs_path *path;
257f186373fSMark Fasheh 	struct btrfs_key key;
258f186373fSMark Fasheh 	struct extent_buffer *leaf;
259f186373fSMark Fasheh 
260f186373fSMark Fasheh 	key.objectid = inode_objectid;
261f186373fSMark Fasheh 	key.type = BTRFS_INODE_EXTREF_KEY;
262f186373fSMark Fasheh 	key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
263f186373fSMark Fasheh 
264f186373fSMark Fasheh 	path = btrfs_alloc_path();
265f186373fSMark Fasheh 	if (!path)
266f186373fSMark Fasheh 		return -ENOMEM;
267f186373fSMark Fasheh 
268f186373fSMark Fasheh 	ret = btrfs_insert_empty_item(trans, root, path, &key,
269f186373fSMark Fasheh 				      ins_len);
270f186373fSMark Fasheh 	if (ret == -EEXIST) {
2711f250e92SFilipe Manana 		if (btrfs_find_name_in_ext_backref(path->nodes[0],
2721f250e92SFilipe Manana 						   path->slots[0],
2731f250e92SFilipe Manana 						   ref_objectid,
2746ff49c6aSNikolay Borisov 						   name, name_len))
275f186373fSMark Fasheh 			goto out;
276f186373fSMark Fasheh 
277c71dd880SDavid Sterba 		btrfs_extend_item(path, ins_len);
278f186373fSMark Fasheh 		ret = 0;
279f186373fSMark Fasheh 	}
280f186373fSMark Fasheh 	if (ret < 0)
281f186373fSMark Fasheh 		goto out;
282f186373fSMark Fasheh 
283f186373fSMark Fasheh 	leaf = path->nodes[0];
284f186373fSMark Fasheh 	ptr = (unsigned long)btrfs_item_ptr(leaf, path->slots[0], char);
285*3212fa14SJosef Bacik 	ptr += btrfs_item_size(leaf, path->slots[0]) - ins_len;
286f186373fSMark Fasheh 	extref = (struct btrfs_inode_extref *)ptr;
287f186373fSMark Fasheh 
288f186373fSMark Fasheh 	btrfs_set_inode_extref_name_len(path->nodes[0], extref, name_len);
289f186373fSMark Fasheh 	btrfs_set_inode_extref_index(path->nodes[0], extref, index);
290f186373fSMark Fasheh 	btrfs_set_inode_extref_parent(path->nodes[0], extref, ref_objectid);
291f186373fSMark Fasheh 
292f186373fSMark Fasheh 	ptr = (unsigned long)&extref->name;
293f186373fSMark Fasheh 	write_extent_buffer(path->nodes[0], name, ptr, name_len);
294f186373fSMark Fasheh 	btrfs_mark_buffer_dirty(path->nodes[0]);
295f186373fSMark Fasheh 
2963954401fSChris Mason out:
2973954401fSChris Mason 	btrfs_free_path(path);
2983954401fSChris Mason 	return ret;
2993954401fSChris Mason }
3003954401fSChris Mason 
30179787eaaSJeff Mahoney /* Will return 0, -ENOMEM, -EMLINK, or -EEXIST or anything from the CoW path */
3023954401fSChris Mason int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
3033954401fSChris Mason 			   struct btrfs_root *root,
3043954401fSChris Mason 			   const char *name, int name_len,
305aec7477bSJosef Bacik 			   u64 inode_objectid, u64 ref_objectid, u64 index)
3063954401fSChris Mason {
3070b246afaSJeff Mahoney 	struct btrfs_fs_info *fs_info = root->fs_info;
3083954401fSChris Mason 	struct btrfs_path *path;
3093954401fSChris Mason 	struct btrfs_key key;
3103954401fSChris Mason 	struct btrfs_inode_ref *ref;
3113954401fSChris Mason 	unsigned long ptr;
3123954401fSChris Mason 	int ret;
3133954401fSChris Mason 	int ins_len = name_len + sizeof(*ref);
3143954401fSChris Mason 
3153954401fSChris Mason 	key.objectid = inode_objectid;
3163954401fSChris Mason 	key.offset = ref_objectid;
317962a298fSDavid Sterba 	key.type = BTRFS_INODE_REF_KEY;
3183954401fSChris Mason 
3193954401fSChris Mason 	path = btrfs_alloc_path();
3203954401fSChris Mason 	if (!path)
3213954401fSChris Mason 		return -ENOMEM;
3223954401fSChris Mason 
323df8d116fSFilipe Manana 	path->skip_release_on_error = 1;
3243954401fSChris Mason 	ret = btrfs_insert_empty_item(trans, root, path, &key,
3253954401fSChris Mason 				      ins_len);
3263954401fSChris Mason 	if (ret == -EEXIST) {
3273954401fSChris Mason 		u32 old_size;
3289bb8407fSNikolay Borisov 		ref = btrfs_find_name_in_backref(path->nodes[0], path->slots[0],
3299bb8407fSNikolay Borisov 						 name, name_len);
3309bb8407fSNikolay Borisov 		if (ref)
3313954401fSChris Mason 			goto out;
3323954401fSChris Mason 
333*3212fa14SJosef Bacik 		old_size = btrfs_item_size(path->nodes[0], path->slots[0]);
334c71dd880SDavid Sterba 		btrfs_extend_item(path, ins_len);
3353954401fSChris Mason 		ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
3363954401fSChris Mason 				     struct btrfs_inode_ref);
3373954401fSChris Mason 		ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size);
3383954401fSChris Mason 		btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
339aec7477bSJosef Bacik 		btrfs_set_inode_ref_index(path->nodes[0], ref, index);
3403954401fSChris Mason 		ptr = (unsigned long)(ref + 1);
3413954401fSChris Mason 		ret = 0;
3423954401fSChris Mason 	} else if (ret < 0) {
343df8d116fSFilipe Manana 		if (ret == -EOVERFLOW) {
3441f250e92SFilipe Manana 			if (btrfs_find_name_in_backref(path->nodes[0],
3451f250e92SFilipe Manana 						       path->slots[0],
3469bb8407fSNikolay Borisov 						       name, name_len))
347df8d116fSFilipe Manana 				ret = -EEXIST;
348df8d116fSFilipe Manana 			else
349a5719521SYan, Zheng 				ret = -EMLINK;
350df8d116fSFilipe Manana 		}
3513954401fSChris Mason 		goto out;
3523954401fSChris Mason 	} else {
3533954401fSChris Mason 		ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
3543954401fSChris Mason 				     struct btrfs_inode_ref);
3553954401fSChris Mason 		btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
356aec7477bSJosef Bacik 		btrfs_set_inode_ref_index(path->nodes[0], ref, index);
3573954401fSChris Mason 		ptr = (unsigned long)(ref + 1);
3583954401fSChris Mason 	}
3593954401fSChris Mason 	write_extent_buffer(path->nodes[0], name, ptr, name_len);
3603954401fSChris Mason 	btrfs_mark_buffer_dirty(path->nodes[0]);
3613954401fSChris Mason 
3623954401fSChris Mason out:
3633954401fSChris Mason 	btrfs_free_path(path);
364f186373fSMark Fasheh 
365f186373fSMark Fasheh 	if (ret == -EMLINK) {
3660b246afaSJeff Mahoney 		struct btrfs_super_block *disk_super = fs_info->super_copy;
367f186373fSMark Fasheh 		/* We ran out of space in the ref array. Need to
368f186373fSMark Fasheh 		 * add an extended ref. */
369f186373fSMark Fasheh 		if (btrfs_super_incompat_flags(disk_super)
370f186373fSMark Fasheh 		    & BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF)
371f186373fSMark Fasheh 			ret = btrfs_insert_inode_extref(trans, root, name,
372f186373fSMark Fasheh 							name_len,
373f186373fSMark Fasheh 							inode_objectid,
374f186373fSMark Fasheh 							ref_objectid, index);
375f186373fSMark Fasheh 	}
376f186373fSMark Fasheh 
3773954401fSChris Mason 	return ret;
3783954401fSChris Mason }
3793954401fSChris Mason 
3805f39d397SChris Mason int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans,
3815f39d397SChris Mason 			     struct btrfs_root *root,
3825f39d397SChris Mason 			     struct btrfs_path *path, u64 objectid)
3831e1d2701SChris Mason {
3841e1d2701SChris Mason 	struct btrfs_key key;
3851e1d2701SChris Mason 	int ret;
3861e1d2701SChris Mason 	key.objectid = objectid;
387962a298fSDavid Sterba 	key.type = BTRFS_INODE_ITEM_KEY;
3881e1d2701SChris Mason 	key.offset = 0;
3891e1d2701SChris Mason 
3905f39d397SChris Mason 	ret = btrfs_insert_empty_item(trans, root, path, &key,
3915f39d397SChris Mason 				      sizeof(struct btrfs_inode_item));
3921e1d2701SChris Mason 	return ret;
3931e1d2701SChris Mason }
3941e1d2701SChris Mason 
395e089f05cSChris Mason int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
396d6e4a428SChris Mason 		       *root, struct btrfs_path *path,
397d6e4a428SChris Mason 		       struct btrfs_key *location, int mod)
3981e1d2701SChris Mason {
3991e1d2701SChris Mason 	int ins_len = mod < 0 ? -1 : 0;
4001e1d2701SChris Mason 	int cow = mod != 0;
401d6e4a428SChris Mason 	int ret;
402d6e4a428SChris Mason 	int slot;
4035f39d397SChris Mason 	struct extent_buffer *leaf;
404d6e4a428SChris Mason 	struct btrfs_key found_key;
4051e1d2701SChris Mason 
406d6e4a428SChris Mason 	ret = btrfs_search_slot(trans, root, location, path, ins_len, cow);
407962a298fSDavid Sterba 	if (ret > 0 && location->type == BTRFS_ROOT_ITEM_KEY &&
408d6e4a428SChris Mason 	    location->offset == (u64)-1 && path->slots[0] != 0) {
409d6e4a428SChris Mason 		slot = path->slots[0] - 1;
4105f39d397SChris Mason 		leaf = path->nodes[0];
4115f39d397SChris Mason 		btrfs_item_key_to_cpu(leaf, &found_key, slot);
412d6e4a428SChris Mason 		if (found_key.objectid == location->objectid &&
413962a298fSDavid Sterba 		    found_key.type == location->type) {
414d6e4a428SChris Mason 			path->slots[0]--;
415d6e4a428SChris Mason 			return 0;
416d6e4a428SChris Mason 		}
417d6e4a428SChris Mason 	}
418d6e4a428SChris Mason 	return ret;
4191e1d2701SChris Mason }
420