xref: /openbmc/linux/fs/btrfs/inode-item.c (revision 34d97007)
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"
21f186373fSMark Fasheh #include "hash.h"
22e089f05cSChris Mason #include "transaction.h"
23727011e0SChris Mason #include "print-tree.h"
241e1d2701SChris Mason 
25b2950863SChristoph Hellwig static int find_name_in_backref(struct btrfs_path *path, const char *name,
263954401fSChris Mason 			 int name_len, struct btrfs_inode_ref **ref_ret)
273954401fSChris Mason {
283954401fSChris Mason 	struct extent_buffer *leaf;
293954401fSChris Mason 	struct btrfs_inode_ref *ref;
303954401fSChris Mason 	unsigned long ptr;
313954401fSChris Mason 	unsigned long name_ptr;
323954401fSChris Mason 	u32 item_size;
333954401fSChris Mason 	u32 cur_offset = 0;
343954401fSChris Mason 	int len;
353954401fSChris Mason 
363954401fSChris Mason 	leaf = path->nodes[0];
373954401fSChris Mason 	item_size = btrfs_item_size_nr(leaf, path->slots[0]);
383954401fSChris Mason 	ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
393954401fSChris Mason 	while (cur_offset < item_size) {
403954401fSChris Mason 		ref = (struct btrfs_inode_ref *)(ptr + cur_offset);
413954401fSChris Mason 		len = btrfs_inode_ref_name_len(leaf, ref);
423954401fSChris Mason 		name_ptr = (unsigned long)(ref + 1);
433954401fSChris Mason 		cur_offset += len + sizeof(*ref);
443954401fSChris Mason 		if (len != name_len)
453954401fSChris Mason 			continue;
463954401fSChris Mason 		if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) {
473954401fSChris Mason 			*ref_ret = ref;
483954401fSChris Mason 			return 1;
493954401fSChris Mason 		}
503954401fSChris Mason 	}
513954401fSChris Mason 	return 0;
523954401fSChris Mason }
533954401fSChris Mason 
54f186373fSMark Fasheh int btrfs_find_name_in_ext_backref(struct btrfs_path *path, u64 ref_objectid,
55f186373fSMark Fasheh 				   const char *name, int name_len,
56f186373fSMark Fasheh 				   struct btrfs_inode_extref **extref_ret)
57f186373fSMark Fasheh {
58f186373fSMark Fasheh 	struct extent_buffer *leaf;
59f186373fSMark Fasheh 	struct btrfs_inode_extref *extref;
60f186373fSMark Fasheh 	unsigned long ptr;
61f186373fSMark Fasheh 	unsigned long name_ptr;
62f186373fSMark Fasheh 	u32 item_size;
63f186373fSMark Fasheh 	u32 cur_offset = 0;
64f186373fSMark Fasheh 	int ref_name_len;
65f186373fSMark Fasheh 
66f186373fSMark Fasheh 	leaf = path->nodes[0];
67f186373fSMark Fasheh 	item_size = btrfs_item_size_nr(leaf, path->slots[0]);
68f186373fSMark Fasheh 	ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
69f186373fSMark Fasheh 
70f186373fSMark Fasheh 	/*
71f186373fSMark Fasheh 	 * Search all extended backrefs in this item. We're only
72f186373fSMark Fasheh 	 * looking through any collisions so most of the time this is
73f186373fSMark Fasheh 	 * just going to compare against one buffer. If all is well,
74f186373fSMark Fasheh 	 * we'll return success and the inode ref object.
75f186373fSMark Fasheh 	 */
76f186373fSMark Fasheh 	while (cur_offset < item_size) {
77f186373fSMark Fasheh 		extref = (struct btrfs_inode_extref *) (ptr + cur_offset);
78f186373fSMark Fasheh 		name_ptr = (unsigned long)(&extref->name);
79f186373fSMark Fasheh 		ref_name_len = btrfs_inode_extref_name_len(leaf, extref);
80f186373fSMark Fasheh 
81f186373fSMark Fasheh 		if (ref_name_len == name_len &&
82f186373fSMark Fasheh 		    btrfs_inode_extref_parent(leaf, extref) == ref_objectid &&
83f186373fSMark Fasheh 		    (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)) {
84f186373fSMark Fasheh 			if (extref_ret)
85f186373fSMark Fasheh 				*extref_ret = extref;
86f186373fSMark Fasheh 			return 1;
87f186373fSMark Fasheh 		}
88f186373fSMark Fasheh 
89f186373fSMark Fasheh 		cur_offset += ref_name_len + sizeof(*extref);
90f186373fSMark Fasheh 	}
91f186373fSMark Fasheh 	return 0;
92f186373fSMark Fasheh }
93f186373fSMark Fasheh 
94f186373fSMark Fasheh /* Returns NULL if no extref found */
95f186373fSMark Fasheh struct btrfs_inode_extref *
96f186373fSMark Fasheh btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans,
97f186373fSMark Fasheh 			  struct btrfs_root *root,
98f186373fSMark Fasheh 			  struct btrfs_path *path,
99f186373fSMark Fasheh 			  const char *name, int name_len,
100f186373fSMark Fasheh 			  u64 inode_objectid, u64 ref_objectid, int ins_len,
101f186373fSMark Fasheh 			  int cow)
102f186373fSMark Fasheh {
103f186373fSMark Fasheh 	int ret;
104f186373fSMark Fasheh 	struct btrfs_key key;
105f186373fSMark Fasheh 	struct btrfs_inode_extref *extref;
106f186373fSMark Fasheh 
107f186373fSMark Fasheh 	key.objectid = inode_objectid;
108f186373fSMark Fasheh 	key.type = BTRFS_INODE_EXTREF_KEY;
109f186373fSMark Fasheh 	key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
110f186373fSMark Fasheh 
111f186373fSMark Fasheh 	ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
112f186373fSMark Fasheh 	if (ret < 0)
113f186373fSMark Fasheh 		return ERR_PTR(ret);
114f186373fSMark Fasheh 	if (ret > 0)
115f186373fSMark Fasheh 		return NULL;
116f186373fSMark Fasheh 	if (!btrfs_find_name_in_ext_backref(path, ref_objectid, name, name_len, &extref))
117f186373fSMark Fasheh 		return NULL;
118f186373fSMark Fasheh 	return extref;
119f186373fSMark Fasheh }
120f186373fSMark Fasheh 
12148a3b636SEric Sandeen static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,
122f186373fSMark Fasheh 				  struct btrfs_root *root,
123f186373fSMark Fasheh 				  const char *name, int name_len,
12448a3b636SEric Sandeen 				  u64 inode_objectid, u64 ref_objectid,
12548a3b636SEric Sandeen 				  u64 *index)
126f186373fSMark Fasheh {
127f186373fSMark Fasheh 	struct btrfs_path *path;
128f186373fSMark Fasheh 	struct btrfs_key key;
129f186373fSMark Fasheh 	struct btrfs_inode_extref *extref;
130f186373fSMark Fasheh 	struct extent_buffer *leaf;
131f186373fSMark Fasheh 	int ret;
132f186373fSMark Fasheh 	int del_len = name_len + sizeof(*extref);
133f186373fSMark Fasheh 	unsigned long ptr;
134f186373fSMark Fasheh 	unsigned long item_start;
135f186373fSMark Fasheh 	u32 item_size;
136f186373fSMark Fasheh 
137f186373fSMark Fasheh 	key.objectid = inode_objectid;
138962a298fSDavid Sterba 	key.type = BTRFS_INODE_EXTREF_KEY;
139f186373fSMark Fasheh 	key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
140f186373fSMark Fasheh 
141f186373fSMark Fasheh 	path = btrfs_alloc_path();
142f186373fSMark Fasheh 	if (!path)
143f186373fSMark Fasheh 		return -ENOMEM;
144f186373fSMark Fasheh 
145f186373fSMark Fasheh 	path->leave_spinning = 1;
146f186373fSMark Fasheh 
147f186373fSMark Fasheh 	ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
148f186373fSMark Fasheh 	if (ret > 0)
149f186373fSMark Fasheh 		ret = -ENOENT;
150f186373fSMark Fasheh 	if (ret < 0)
151f186373fSMark Fasheh 		goto out;
152f186373fSMark Fasheh 
153f186373fSMark Fasheh 	/*
154f186373fSMark Fasheh 	 * Sanity check - did we find the right item for this name?
155f186373fSMark Fasheh 	 * This should always succeed so error here will make the FS
156f186373fSMark Fasheh 	 * readonly.
157f186373fSMark Fasheh 	 */
158f186373fSMark Fasheh 	if (!btrfs_find_name_in_ext_backref(path, ref_objectid,
159f186373fSMark Fasheh 					    name, name_len, &extref)) {
16034d97007SAnand Jain 		btrfs_handle_fs_error(root->fs_info, -ENOENT, NULL);
161f186373fSMark Fasheh 		ret = -EROFS;
162f186373fSMark Fasheh 		goto out;
163f186373fSMark Fasheh 	}
164f186373fSMark Fasheh 
165f186373fSMark Fasheh 	leaf = path->nodes[0];
166f186373fSMark Fasheh 	item_size = btrfs_item_size_nr(leaf, path->slots[0]);
167f186373fSMark Fasheh 	if (index)
168f186373fSMark Fasheh 		*index = btrfs_inode_extref_index(leaf, extref);
169f186373fSMark Fasheh 
170f186373fSMark Fasheh 	if (del_len == item_size) {
171f186373fSMark Fasheh 		/*
172f186373fSMark Fasheh 		 * Common case only one ref in the item, remove the
173f186373fSMark Fasheh 		 * whole item.
174f186373fSMark Fasheh 		 */
175f186373fSMark Fasheh 		ret = btrfs_del_item(trans, root, path);
176f186373fSMark Fasheh 		goto out;
177f186373fSMark Fasheh 	}
178f186373fSMark Fasheh 
179f186373fSMark Fasheh 	ptr = (unsigned long)extref;
180f186373fSMark Fasheh 	item_start = btrfs_item_ptr_offset(leaf, path->slots[0]);
181f186373fSMark Fasheh 
182f186373fSMark Fasheh 	memmove_extent_buffer(leaf, ptr, ptr + del_len,
183f186373fSMark Fasheh 			      item_size - (ptr + del_len - item_start));
184f186373fSMark Fasheh 
185afe5fea7STsutomu Itoh 	btrfs_truncate_item(root, path, item_size - del_len, 1);
186f186373fSMark Fasheh 
187f186373fSMark Fasheh out:
188f186373fSMark Fasheh 	btrfs_free_path(path);
189f186373fSMark Fasheh 
190f186373fSMark Fasheh 	return ret;
191f186373fSMark Fasheh }
192f186373fSMark Fasheh 
1933954401fSChris Mason int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
1943954401fSChris Mason 			struct btrfs_root *root,
1953954401fSChris Mason 			const char *name, int name_len,
196aec7477bSJosef Bacik 			u64 inode_objectid, u64 ref_objectid, u64 *index)
1973954401fSChris Mason {
1983954401fSChris Mason 	struct btrfs_path *path;
1993954401fSChris Mason 	struct btrfs_key key;
2003954401fSChris Mason 	struct btrfs_inode_ref *ref;
2013954401fSChris Mason 	struct extent_buffer *leaf;
2023954401fSChris Mason 	unsigned long ptr;
2033954401fSChris Mason 	unsigned long item_start;
2043954401fSChris Mason 	u32 item_size;
2053954401fSChris Mason 	u32 sub_item_len;
2063954401fSChris Mason 	int ret;
207f186373fSMark Fasheh 	int search_ext_refs = 0;
2083954401fSChris Mason 	int del_len = name_len + sizeof(*ref);
2093954401fSChris Mason 
2103954401fSChris Mason 	key.objectid = inode_objectid;
2113954401fSChris Mason 	key.offset = ref_objectid;
212962a298fSDavid Sterba 	key.type = BTRFS_INODE_REF_KEY;
2133954401fSChris Mason 
2143954401fSChris Mason 	path = btrfs_alloc_path();
2153954401fSChris Mason 	if (!path)
2163954401fSChris Mason 		return -ENOMEM;
2173954401fSChris Mason 
218b9473439SChris Mason 	path->leave_spinning = 1;
219b9473439SChris Mason 
2203954401fSChris Mason 	ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
2213954401fSChris Mason 	if (ret > 0) {
2223954401fSChris Mason 		ret = -ENOENT;
223f186373fSMark Fasheh 		search_ext_refs = 1;
2243954401fSChris Mason 		goto out;
2253954401fSChris Mason 	} else if (ret < 0) {
2263954401fSChris Mason 		goto out;
2273954401fSChris Mason 	}
2283954401fSChris Mason 	if (!find_name_in_backref(path, name, name_len, &ref)) {
2293954401fSChris Mason 		ret = -ENOENT;
230f186373fSMark Fasheh 		search_ext_refs = 1;
2313954401fSChris Mason 		goto out;
2323954401fSChris Mason 	}
2333954401fSChris Mason 	leaf = path->nodes[0];
2343954401fSChris Mason 	item_size = btrfs_item_size_nr(leaf, path->slots[0]);
235aec7477bSJosef Bacik 
236aec7477bSJosef Bacik 	if (index)
237aec7477bSJosef Bacik 		*index = btrfs_inode_ref_index(leaf, ref);
238aec7477bSJosef Bacik 
2393954401fSChris Mason 	if (del_len == item_size) {
2403954401fSChris Mason 		ret = btrfs_del_item(trans, root, path);
2413954401fSChris Mason 		goto out;
2423954401fSChris Mason 	}
2433954401fSChris Mason 	ptr = (unsigned long)ref;
2443954401fSChris Mason 	sub_item_len = name_len + sizeof(*ref);
2453954401fSChris Mason 	item_start = btrfs_item_ptr_offset(leaf, path->slots[0]);
2463954401fSChris Mason 	memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
2473954401fSChris Mason 			      item_size - (ptr + sub_item_len - item_start));
248afe5fea7STsutomu Itoh 	btrfs_truncate_item(root, path, item_size - sub_item_len, 1);
249f186373fSMark Fasheh out:
250f186373fSMark Fasheh 	btrfs_free_path(path);
251f186373fSMark Fasheh 
252f186373fSMark Fasheh 	if (search_ext_refs) {
253f186373fSMark Fasheh 		/*
254f186373fSMark Fasheh 		 * No refs were found, or we could not find the
255f186373fSMark Fasheh 		 * name in our ref array. Find and remove the extended
256f186373fSMark Fasheh 		 * inode ref then.
257f186373fSMark Fasheh 		 */
258f186373fSMark Fasheh 		return btrfs_del_inode_extref(trans, root, name, name_len,
259f186373fSMark Fasheh 					      inode_objectid, ref_objectid, index);
260f186373fSMark Fasheh 	}
261f186373fSMark Fasheh 
262f186373fSMark Fasheh 	return ret;
263f186373fSMark Fasheh }
264f186373fSMark Fasheh 
265f186373fSMark Fasheh /*
266f186373fSMark Fasheh  * btrfs_insert_inode_extref() - Inserts an extended inode ref into a tree.
267f186373fSMark Fasheh  *
268f186373fSMark Fasheh  * The caller must have checked against BTRFS_LINK_MAX already.
269f186373fSMark Fasheh  */
270f186373fSMark Fasheh static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,
271f186373fSMark Fasheh 				     struct btrfs_root *root,
272f186373fSMark Fasheh 				     const char *name, int name_len,
273f186373fSMark Fasheh 				     u64 inode_objectid, u64 ref_objectid, u64 index)
274f186373fSMark Fasheh {
275f186373fSMark Fasheh 	struct btrfs_inode_extref *extref;
276f186373fSMark Fasheh 	int ret;
277f186373fSMark Fasheh 	int ins_len = name_len + sizeof(*extref);
278f186373fSMark Fasheh 	unsigned long ptr;
279f186373fSMark Fasheh 	struct btrfs_path *path;
280f186373fSMark Fasheh 	struct btrfs_key key;
281f186373fSMark Fasheh 	struct extent_buffer *leaf;
282f186373fSMark Fasheh 	struct btrfs_item *item;
283f186373fSMark Fasheh 
284f186373fSMark Fasheh 	key.objectid = inode_objectid;
285f186373fSMark Fasheh 	key.type = BTRFS_INODE_EXTREF_KEY;
286f186373fSMark Fasheh 	key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
287f186373fSMark Fasheh 
288f186373fSMark Fasheh 	path = btrfs_alloc_path();
289f186373fSMark Fasheh 	if (!path)
290f186373fSMark Fasheh 		return -ENOMEM;
291f186373fSMark Fasheh 
292f186373fSMark Fasheh 	path->leave_spinning = 1;
293f186373fSMark Fasheh 	ret = btrfs_insert_empty_item(trans, root, path, &key,
294f186373fSMark Fasheh 				      ins_len);
295f186373fSMark Fasheh 	if (ret == -EEXIST) {
296f186373fSMark Fasheh 		if (btrfs_find_name_in_ext_backref(path, ref_objectid,
297f186373fSMark Fasheh 						   name, name_len, NULL))
298f186373fSMark Fasheh 			goto out;
299f186373fSMark Fasheh 
3004b90c680STsutomu Itoh 		btrfs_extend_item(root, path, ins_len);
301f186373fSMark Fasheh 		ret = 0;
302f186373fSMark Fasheh 	}
303f186373fSMark Fasheh 	if (ret < 0)
304f186373fSMark Fasheh 		goto out;
305f186373fSMark Fasheh 
306f186373fSMark Fasheh 	leaf = path->nodes[0];
307dd3cc16bSRoss Kirk 	item = btrfs_item_nr(path->slots[0]);
308f186373fSMark Fasheh 	ptr = (unsigned long)btrfs_item_ptr(leaf, path->slots[0], char);
309f186373fSMark Fasheh 	ptr += btrfs_item_size(leaf, item) - ins_len;
310f186373fSMark Fasheh 	extref = (struct btrfs_inode_extref *)ptr;
311f186373fSMark Fasheh 
312f186373fSMark Fasheh 	btrfs_set_inode_extref_name_len(path->nodes[0], extref, name_len);
313f186373fSMark Fasheh 	btrfs_set_inode_extref_index(path->nodes[0], extref, index);
314f186373fSMark Fasheh 	btrfs_set_inode_extref_parent(path->nodes[0], extref, ref_objectid);
315f186373fSMark Fasheh 
316f186373fSMark Fasheh 	ptr = (unsigned long)&extref->name;
317f186373fSMark Fasheh 	write_extent_buffer(path->nodes[0], name, ptr, name_len);
318f186373fSMark Fasheh 	btrfs_mark_buffer_dirty(path->nodes[0]);
319f186373fSMark Fasheh 
3203954401fSChris Mason out:
3213954401fSChris Mason 	btrfs_free_path(path);
3223954401fSChris Mason 	return ret;
3233954401fSChris Mason }
3243954401fSChris Mason 
32579787eaaSJeff Mahoney /* Will return 0, -ENOMEM, -EMLINK, or -EEXIST or anything from the CoW path */
3263954401fSChris Mason int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
3273954401fSChris Mason 			   struct btrfs_root *root,
3283954401fSChris Mason 			   const char *name, int name_len,
329aec7477bSJosef Bacik 			   u64 inode_objectid, u64 ref_objectid, u64 index)
3303954401fSChris Mason {
3313954401fSChris Mason 	struct btrfs_path *path;
3323954401fSChris Mason 	struct btrfs_key key;
3333954401fSChris Mason 	struct btrfs_inode_ref *ref;
3343954401fSChris Mason 	unsigned long ptr;
3353954401fSChris Mason 	int ret;
3363954401fSChris Mason 	int ins_len = name_len + sizeof(*ref);
3373954401fSChris Mason 
3383954401fSChris Mason 	key.objectid = inode_objectid;
3393954401fSChris Mason 	key.offset = ref_objectid;
340962a298fSDavid Sterba 	key.type = BTRFS_INODE_REF_KEY;
3413954401fSChris Mason 
3423954401fSChris Mason 	path = btrfs_alloc_path();
3433954401fSChris Mason 	if (!path)
3443954401fSChris Mason 		return -ENOMEM;
3453954401fSChris Mason 
346b9473439SChris Mason 	path->leave_spinning = 1;
347df8d116fSFilipe Manana 	path->skip_release_on_error = 1;
3483954401fSChris Mason 	ret = btrfs_insert_empty_item(trans, root, path, &key,
3493954401fSChris Mason 				      ins_len);
3503954401fSChris Mason 	if (ret == -EEXIST) {
3513954401fSChris Mason 		u32 old_size;
3523954401fSChris Mason 
3533954401fSChris Mason 		if (find_name_in_backref(path, name, name_len, &ref))
3543954401fSChris Mason 			goto out;
3553954401fSChris Mason 
3563954401fSChris Mason 		old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]);
3574b90c680STsutomu Itoh 		btrfs_extend_item(root, path, ins_len);
3583954401fSChris Mason 		ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
3593954401fSChris Mason 				     struct btrfs_inode_ref);
3603954401fSChris Mason 		ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size);
3613954401fSChris Mason 		btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
362aec7477bSJosef Bacik 		btrfs_set_inode_ref_index(path->nodes[0], ref, index);
3633954401fSChris Mason 		ptr = (unsigned long)(ref + 1);
3643954401fSChris Mason 		ret = 0;
3653954401fSChris Mason 	} else if (ret < 0) {
366df8d116fSFilipe Manana 		if (ret == -EOVERFLOW) {
367df8d116fSFilipe Manana 			if (find_name_in_backref(path, name, name_len, &ref))
368df8d116fSFilipe Manana 				ret = -EEXIST;
369df8d116fSFilipe Manana 			else
370a5719521SYan, Zheng 				ret = -EMLINK;
371df8d116fSFilipe Manana 		}
3723954401fSChris Mason 		goto out;
3733954401fSChris Mason 	} else {
3743954401fSChris Mason 		ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
3753954401fSChris Mason 				     struct btrfs_inode_ref);
3763954401fSChris Mason 		btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
377aec7477bSJosef Bacik 		btrfs_set_inode_ref_index(path->nodes[0], ref, index);
3783954401fSChris Mason 		ptr = (unsigned long)(ref + 1);
3793954401fSChris Mason 	}
3803954401fSChris Mason 	write_extent_buffer(path->nodes[0], name, ptr, name_len);
3813954401fSChris Mason 	btrfs_mark_buffer_dirty(path->nodes[0]);
3823954401fSChris Mason 
3833954401fSChris Mason out:
3843954401fSChris Mason 	btrfs_free_path(path);
385f186373fSMark Fasheh 
386f186373fSMark Fasheh 	if (ret == -EMLINK) {
387f186373fSMark Fasheh 		struct btrfs_super_block *disk_super = root->fs_info->super_copy;
388f186373fSMark Fasheh 		/* We ran out of space in the ref array. Need to
389f186373fSMark Fasheh 		 * add an extended ref. */
390f186373fSMark Fasheh 		if (btrfs_super_incompat_flags(disk_super)
391f186373fSMark Fasheh 		    & BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF)
392f186373fSMark Fasheh 			ret = btrfs_insert_inode_extref(trans, root, name,
393f186373fSMark Fasheh 							name_len,
394f186373fSMark Fasheh 							inode_objectid,
395f186373fSMark Fasheh 							ref_objectid, index);
396f186373fSMark Fasheh 	}
397f186373fSMark Fasheh 
3983954401fSChris Mason 	return ret;
3993954401fSChris Mason }
4003954401fSChris Mason 
4015f39d397SChris Mason int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans,
4025f39d397SChris Mason 			     struct btrfs_root *root,
4035f39d397SChris Mason 			     struct btrfs_path *path, u64 objectid)
4041e1d2701SChris Mason {
4051e1d2701SChris Mason 	struct btrfs_key key;
4061e1d2701SChris Mason 	int ret;
4071e1d2701SChris Mason 	key.objectid = objectid;
408962a298fSDavid Sterba 	key.type = BTRFS_INODE_ITEM_KEY;
4091e1d2701SChris Mason 	key.offset = 0;
4101e1d2701SChris Mason 
4115f39d397SChris Mason 	ret = btrfs_insert_empty_item(trans, root, path, &key,
4125f39d397SChris Mason 				      sizeof(struct btrfs_inode_item));
4131e1d2701SChris Mason 	return ret;
4141e1d2701SChris Mason }
4151e1d2701SChris Mason 
416e089f05cSChris Mason int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
417d6e4a428SChris Mason 		       *root, struct btrfs_path *path,
418d6e4a428SChris Mason 		       struct btrfs_key *location, int mod)
4191e1d2701SChris Mason {
4201e1d2701SChris Mason 	int ins_len = mod < 0 ? -1 : 0;
4211e1d2701SChris Mason 	int cow = mod != 0;
422d6e4a428SChris Mason 	int ret;
423d6e4a428SChris Mason 	int slot;
4245f39d397SChris Mason 	struct extent_buffer *leaf;
425d6e4a428SChris Mason 	struct btrfs_key found_key;
4261e1d2701SChris Mason 
427d6e4a428SChris Mason 	ret = btrfs_search_slot(trans, root, location, path, ins_len, cow);
428962a298fSDavid Sterba 	if (ret > 0 && location->type == BTRFS_ROOT_ITEM_KEY &&
429d6e4a428SChris Mason 	    location->offset == (u64)-1 && path->slots[0] != 0) {
430d6e4a428SChris Mason 		slot = path->slots[0] - 1;
4315f39d397SChris Mason 		leaf = path->nodes[0];
4325f39d397SChris Mason 		btrfs_item_key_to_cpu(leaf, &found_key, slot);
433d6e4a428SChris Mason 		if (found_key.objectid == location->objectid &&
434962a298fSDavid Sterba 		    found_key.type == location->type) {
435d6e4a428SChris Mason 			path->slots[0]--;
436d6e4a428SChris Mason 			return 0;
437d6e4a428SChris Mason 		}
438d6e4a428SChris Mason 	}
439d6e4a428SChris Mason 	return ret;
4401e1d2701SChris Mason }
441