xref: /OK3568_Linux_fs/kernel/fs/btrfs/inode-item.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2007 Oracle.  All rights reserved.
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include "ctree.h"
7*4882a593Smuzhiyun #include "disk-io.h"
8*4882a593Smuzhiyun #include "transaction.h"
9*4882a593Smuzhiyun #include "print-tree.h"
10*4882a593Smuzhiyun 
btrfs_find_name_in_backref(struct extent_buffer * leaf,int slot,const char * name,int name_len)11*4882a593Smuzhiyun struct btrfs_inode_ref *btrfs_find_name_in_backref(struct extent_buffer *leaf,
12*4882a593Smuzhiyun 						   int slot, const char *name,
13*4882a593Smuzhiyun 						   int name_len)
14*4882a593Smuzhiyun {
15*4882a593Smuzhiyun 	struct btrfs_inode_ref *ref;
16*4882a593Smuzhiyun 	unsigned long ptr;
17*4882a593Smuzhiyun 	unsigned long name_ptr;
18*4882a593Smuzhiyun 	u32 item_size;
19*4882a593Smuzhiyun 	u32 cur_offset = 0;
20*4882a593Smuzhiyun 	int len;
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun 	item_size = btrfs_item_size_nr(leaf, slot);
23*4882a593Smuzhiyun 	ptr = btrfs_item_ptr_offset(leaf, slot);
24*4882a593Smuzhiyun 	while (cur_offset < item_size) {
25*4882a593Smuzhiyun 		ref = (struct btrfs_inode_ref *)(ptr + cur_offset);
26*4882a593Smuzhiyun 		len = btrfs_inode_ref_name_len(leaf, ref);
27*4882a593Smuzhiyun 		name_ptr = (unsigned long)(ref + 1);
28*4882a593Smuzhiyun 		cur_offset += len + sizeof(*ref);
29*4882a593Smuzhiyun 		if (len != name_len)
30*4882a593Smuzhiyun 			continue;
31*4882a593Smuzhiyun 		if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
32*4882a593Smuzhiyun 			return ref;
33*4882a593Smuzhiyun 	}
34*4882a593Smuzhiyun 	return NULL;
35*4882a593Smuzhiyun }
36*4882a593Smuzhiyun 
btrfs_find_name_in_ext_backref(struct extent_buffer * leaf,int slot,u64 ref_objectid,const char * name,int name_len)37*4882a593Smuzhiyun struct btrfs_inode_extref *btrfs_find_name_in_ext_backref(
38*4882a593Smuzhiyun 		struct extent_buffer *leaf, int slot, u64 ref_objectid,
39*4882a593Smuzhiyun 		const char *name, int name_len)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun 	struct btrfs_inode_extref *extref;
42*4882a593Smuzhiyun 	unsigned long ptr;
43*4882a593Smuzhiyun 	unsigned long name_ptr;
44*4882a593Smuzhiyun 	u32 item_size;
45*4882a593Smuzhiyun 	u32 cur_offset = 0;
46*4882a593Smuzhiyun 	int ref_name_len;
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	item_size = btrfs_item_size_nr(leaf, slot);
49*4882a593Smuzhiyun 	ptr = btrfs_item_ptr_offset(leaf, slot);
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	/*
52*4882a593Smuzhiyun 	 * Search all extended backrefs in this item. We're only
53*4882a593Smuzhiyun 	 * looking through any collisions so most of the time this is
54*4882a593Smuzhiyun 	 * just going to compare against one buffer. If all is well,
55*4882a593Smuzhiyun 	 * we'll return success and the inode ref object.
56*4882a593Smuzhiyun 	 */
57*4882a593Smuzhiyun 	while (cur_offset < item_size) {
58*4882a593Smuzhiyun 		extref = (struct btrfs_inode_extref *) (ptr + cur_offset);
59*4882a593Smuzhiyun 		name_ptr = (unsigned long)(&extref->name);
60*4882a593Smuzhiyun 		ref_name_len = btrfs_inode_extref_name_len(leaf, extref);
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 		if (ref_name_len == name_len &&
63*4882a593Smuzhiyun 		    btrfs_inode_extref_parent(leaf, extref) == ref_objectid &&
64*4882a593Smuzhiyun 		    (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0))
65*4882a593Smuzhiyun 			return extref;
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 		cur_offset += ref_name_len + sizeof(*extref);
68*4882a593Smuzhiyun 	}
69*4882a593Smuzhiyun 	return NULL;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun /* Returns NULL if no extref found */
73*4882a593Smuzhiyun struct btrfs_inode_extref *
btrfs_lookup_inode_extref(struct btrfs_trans_handle * trans,struct btrfs_root * root,struct btrfs_path * path,const char * name,int name_len,u64 inode_objectid,u64 ref_objectid,int ins_len,int cow)74*4882a593Smuzhiyun btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans,
75*4882a593Smuzhiyun 			  struct btrfs_root *root,
76*4882a593Smuzhiyun 			  struct btrfs_path *path,
77*4882a593Smuzhiyun 			  const char *name, int name_len,
78*4882a593Smuzhiyun 			  u64 inode_objectid, u64 ref_objectid, int ins_len,
79*4882a593Smuzhiyun 			  int cow)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun 	int ret;
82*4882a593Smuzhiyun 	struct btrfs_key key;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	key.objectid = inode_objectid;
85*4882a593Smuzhiyun 	key.type = BTRFS_INODE_EXTREF_KEY;
86*4882a593Smuzhiyun 	key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
89*4882a593Smuzhiyun 	if (ret < 0)
90*4882a593Smuzhiyun 		return ERR_PTR(ret);
91*4882a593Smuzhiyun 	if (ret > 0)
92*4882a593Smuzhiyun 		return NULL;
93*4882a593Smuzhiyun 	return btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0],
94*4882a593Smuzhiyun 					      ref_objectid, name, name_len);
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun 
btrfs_del_inode_extref(struct btrfs_trans_handle * trans,struct btrfs_root * root,const char * name,int name_len,u64 inode_objectid,u64 ref_objectid,u64 * index)98*4882a593Smuzhiyun static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,
99*4882a593Smuzhiyun 				  struct btrfs_root *root,
100*4882a593Smuzhiyun 				  const char *name, int name_len,
101*4882a593Smuzhiyun 				  u64 inode_objectid, u64 ref_objectid,
102*4882a593Smuzhiyun 				  u64 *index)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun 	struct btrfs_path *path;
105*4882a593Smuzhiyun 	struct btrfs_key key;
106*4882a593Smuzhiyun 	struct btrfs_inode_extref *extref;
107*4882a593Smuzhiyun 	struct extent_buffer *leaf;
108*4882a593Smuzhiyun 	int ret;
109*4882a593Smuzhiyun 	int del_len = name_len + sizeof(*extref);
110*4882a593Smuzhiyun 	unsigned long ptr;
111*4882a593Smuzhiyun 	unsigned long item_start;
112*4882a593Smuzhiyun 	u32 item_size;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	key.objectid = inode_objectid;
115*4882a593Smuzhiyun 	key.type = BTRFS_INODE_EXTREF_KEY;
116*4882a593Smuzhiyun 	key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	path = btrfs_alloc_path();
119*4882a593Smuzhiyun 	if (!path)
120*4882a593Smuzhiyun 		return -ENOMEM;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	path->leave_spinning = 1;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
125*4882a593Smuzhiyun 	if (ret > 0)
126*4882a593Smuzhiyun 		ret = -ENOENT;
127*4882a593Smuzhiyun 	if (ret < 0)
128*4882a593Smuzhiyun 		goto out;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	/*
131*4882a593Smuzhiyun 	 * Sanity check - did we find the right item for this name?
132*4882a593Smuzhiyun 	 * This should always succeed so error here will make the FS
133*4882a593Smuzhiyun 	 * readonly.
134*4882a593Smuzhiyun 	 */
135*4882a593Smuzhiyun 	extref = btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0],
136*4882a593Smuzhiyun 						ref_objectid, name, name_len);
137*4882a593Smuzhiyun 	if (!extref) {
138*4882a593Smuzhiyun 		btrfs_handle_fs_error(root->fs_info, -ENOENT, NULL);
139*4882a593Smuzhiyun 		ret = -EROFS;
140*4882a593Smuzhiyun 		goto out;
141*4882a593Smuzhiyun 	}
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	leaf = path->nodes[0];
144*4882a593Smuzhiyun 	item_size = btrfs_item_size_nr(leaf, path->slots[0]);
145*4882a593Smuzhiyun 	if (index)
146*4882a593Smuzhiyun 		*index = btrfs_inode_extref_index(leaf, extref);
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	if (del_len == item_size) {
149*4882a593Smuzhiyun 		/*
150*4882a593Smuzhiyun 		 * Common case only one ref in the item, remove the
151*4882a593Smuzhiyun 		 * whole item.
152*4882a593Smuzhiyun 		 */
153*4882a593Smuzhiyun 		ret = btrfs_del_item(trans, root, path);
154*4882a593Smuzhiyun 		goto out;
155*4882a593Smuzhiyun 	}
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	ptr = (unsigned long)extref;
158*4882a593Smuzhiyun 	item_start = btrfs_item_ptr_offset(leaf, path->slots[0]);
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	memmove_extent_buffer(leaf, ptr, ptr + del_len,
161*4882a593Smuzhiyun 			      item_size - (ptr + del_len - item_start));
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	btrfs_truncate_item(path, item_size - del_len, 1);
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun out:
166*4882a593Smuzhiyun 	btrfs_free_path(path);
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	return ret;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun 
btrfs_del_inode_ref(struct btrfs_trans_handle * trans,struct btrfs_root * root,const char * name,int name_len,u64 inode_objectid,u64 ref_objectid,u64 * index)171*4882a593Smuzhiyun int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
172*4882a593Smuzhiyun 			struct btrfs_root *root,
173*4882a593Smuzhiyun 			const char *name, int name_len,
174*4882a593Smuzhiyun 			u64 inode_objectid, u64 ref_objectid, u64 *index)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun 	struct btrfs_path *path;
177*4882a593Smuzhiyun 	struct btrfs_key key;
178*4882a593Smuzhiyun 	struct btrfs_inode_ref *ref;
179*4882a593Smuzhiyun 	struct extent_buffer *leaf;
180*4882a593Smuzhiyun 	unsigned long ptr;
181*4882a593Smuzhiyun 	unsigned long item_start;
182*4882a593Smuzhiyun 	u32 item_size;
183*4882a593Smuzhiyun 	u32 sub_item_len;
184*4882a593Smuzhiyun 	int ret;
185*4882a593Smuzhiyun 	int search_ext_refs = 0;
186*4882a593Smuzhiyun 	int del_len = name_len + sizeof(*ref);
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	key.objectid = inode_objectid;
189*4882a593Smuzhiyun 	key.offset = ref_objectid;
190*4882a593Smuzhiyun 	key.type = BTRFS_INODE_REF_KEY;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	path = btrfs_alloc_path();
193*4882a593Smuzhiyun 	if (!path)
194*4882a593Smuzhiyun 		return -ENOMEM;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	path->leave_spinning = 1;
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
199*4882a593Smuzhiyun 	if (ret > 0) {
200*4882a593Smuzhiyun 		ret = -ENOENT;
201*4882a593Smuzhiyun 		search_ext_refs = 1;
202*4882a593Smuzhiyun 		goto out;
203*4882a593Smuzhiyun 	} else if (ret < 0) {
204*4882a593Smuzhiyun 		goto out;
205*4882a593Smuzhiyun 	}
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	ref = btrfs_find_name_in_backref(path->nodes[0], path->slots[0], name,
208*4882a593Smuzhiyun 					 name_len);
209*4882a593Smuzhiyun 	if (!ref) {
210*4882a593Smuzhiyun 		ret = -ENOENT;
211*4882a593Smuzhiyun 		search_ext_refs = 1;
212*4882a593Smuzhiyun 		goto out;
213*4882a593Smuzhiyun 	}
214*4882a593Smuzhiyun 	leaf = path->nodes[0];
215*4882a593Smuzhiyun 	item_size = btrfs_item_size_nr(leaf, path->slots[0]);
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	if (index)
218*4882a593Smuzhiyun 		*index = btrfs_inode_ref_index(leaf, ref);
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	if (del_len == item_size) {
221*4882a593Smuzhiyun 		ret = btrfs_del_item(trans, root, path);
222*4882a593Smuzhiyun 		goto out;
223*4882a593Smuzhiyun 	}
224*4882a593Smuzhiyun 	ptr = (unsigned long)ref;
225*4882a593Smuzhiyun 	sub_item_len = name_len + sizeof(*ref);
226*4882a593Smuzhiyun 	item_start = btrfs_item_ptr_offset(leaf, path->slots[0]);
227*4882a593Smuzhiyun 	memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
228*4882a593Smuzhiyun 			      item_size - (ptr + sub_item_len - item_start));
229*4882a593Smuzhiyun 	btrfs_truncate_item(path, item_size - sub_item_len, 1);
230*4882a593Smuzhiyun out:
231*4882a593Smuzhiyun 	btrfs_free_path(path);
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	if (search_ext_refs) {
234*4882a593Smuzhiyun 		/*
235*4882a593Smuzhiyun 		 * No refs were found, or we could not find the
236*4882a593Smuzhiyun 		 * name in our ref array. Find and remove the extended
237*4882a593Smuzhiyun 		 * inode ref then.
238*4882a593Smuzhiyun 		 */
239*4882a593Smuzhiyun 		return btrfs_del_inode_extref(trans, root, name, name_len,
240*4882a593Smuzhiyun 					      inode_objectid, ref_objectid, index);
241*4882a593Smuzhiyun 	}
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	return ret;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun /*
247*4882a593Smuzhiyun  * btrfs_insert_inode_extref() - Inserts an extended inode ref into a tree.
248*4882a593Smuzhiyun  *
249*4882a593Smuzhiyun  * The caller must have checked against BTRFS_LINK_MAX already.
250*4882a593Smuzhiyun  */
btrfs_insert_inode_extref(struct btrfs_trans_handle * trans,struct btrfs_root * root,const char * name,int name_len,u64 inode_objectid,u64 ref_objectid,u64 index)251*4882a593Smuzhiyun static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,
252*4882a593Smuzhiyun 				     struct btrfs_root *root,
253*4882a593Smuzhiyun 				     const char *name, int name_len,
254*4882a593Smuzhiyun 				     u64 inode_objectid, u64 ref_objectid, u64 index)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun 	struct btrfs_inode_extref *extref;
257*4882a593Smuzhiyun 	int ret;
258*4882a593Smuzhiyun 	int ins_len = name_len + sizeof(*extref);
259*4882a593Smuzhiyun 	unsigned long ptr;
260*4882a593Smuzhiyun 	struct btrfs_path *path;
261*4882a593Smuzhiyun 	struct btrfs_key key;
262*4882a593Smuzhiyun 	struct extent_buffer *leaf;
263*4882a593Smuzhiyun 	struct btrfs_item *item;
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	key.objectid = inode_objectid;
266*4882a593Smuzhiyun 	key.type = BTRFS_INODE_EXTREF_KEY;
267*4882a593Smuzhiyun 	key.offset = btrfs_extref_hash(ref_objectid, name, name_len);
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	path = btrfs_alloc_path();
270*4882a593Smuzhiyun 	if (!path)
271*4882a593Smuzhiyun 		return -ENOMEM;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	path->leave_spinning = 1;
274*4882a593Smuzhiyun 	ret = btrfs_insert_empty_item(trans, root, path, &key,
275*4882a593Smuzhiyun 				      ins_len);
276*4882a593Smuzhiyun 	if (ret == -EEXIST) {
277*4882a593Smuzhiyun 		if (btrfs_find_name_in_ext_backref(path->nodes[0],
278*4882a593Smuzhiyun 						   path->slots[0],
279*4882a593Smuzhiyun 						   ref_objectid,
280*4882a593Smuzhiyun 						   name, name_len))
281*4882a593Smuzhiyun 			goto out;
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 		btrfs_extend_item(path, ins_len);
284*4882a593Smuzhiyun 		ret = 0;
285*4882a593Smuzhiyun 	}
286*4882a593Smuzhiyun 	if (ret < 0)
287*4882a593Smuzhiyun 		goto out;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	leaf = path->nodes[0];
290*4882a593Smuzhiyun 	item = btrfs_item_nr(path->slots[0]);
291*4882a593Smuzhiyun 	ptr = (unsigned long)btrfs_item_ptr(leaf, path->slots[0], char);
292*4882a593Smuzhiyun 	ptr += btrfs_item_size(leaf, item) - ins_len;
293*4882a593Smuzhiyun 	extref = (struct btrfs_inode_extref *)ptr;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	btrfs_set_inode_extref_name_len(path->nodes[0], extref, name_len);
296*4882a593Smuzhiyun 	btrfs_set_inode_extref_index(path->nodes[0], extref, index);
297*4882a593Smuzhiyun 	btrfs_set_inode_extref_parent(path->nodes[0], extref, ref_objectid);
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	ptr = (unsigned long)&extref->name;
300*4882a593Smuzhiyun 	write_extent_buffer(path->nodes[0], name, ptr, name_len);
301*4882a593Smuzhiyun 	btrfs_mark_buffer_dirty(path->nodes[0]);
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun out:
304*4882a593Smuzhiyun 	btrfs_free_path(path);
305*4882a593Smuzhiyun 	return ret;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun /* Will return 0, -ENOMEM, -EMLINK, or -EEXIST or anything from the CoW path */
btrfs_insert_inode_ref(struct btrfs_trans_handle * trans,struct btrfs_root * root,const char * name,int name_len,u64 inode_objectid,u64 ref_objectid,u64 index)309*4882a593Smuzhiyun int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
310*4882a593Smuzhiyun 			   struct btrfs_root *root,
311*4882a593Smuzhiyun 			   const char *name, int name_len,
312*4882a593Smuzhiyun 			   u64 inode_objectid, u64 ref_objectid, u64 index)
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun 	struct btrfs_fs_info *fs_info = root->fs_info;
315*4882a593Smuzhiyun 	struct btrfs_path *path;
316*4882a593Smuzhiyun 	struct btrfs_key key;
317*4882a593Smuzhiyun 	struct btrfs_inode_ref *ref;
318*4882a593Smuzhiyun 	unsigned long ptr;
319*4882a593Smuzhiyun 	int ret;
320*4882a593Smuzhiyun 	int ins_len = name_len + sizeof(*ref);
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	key.objectid = inode_objectid;
323*4882a593Smuzhiyun 	key.offset = ref_objectid;
324*4882a593Smuzhiyun 	key.type = BTRFS_INODE_REF_KEY;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	path = btrfs_alloc_path();
327*4882a593Smuzhiyun 	if (!path)
328*4882a593Smuzhiyun 		return -ENOMEM;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	path->leave_spinning = 1;
331*4882a593Smuzhiyun 	path->skip_release_on_error = 1;
332*4882a593Smuzhiyun 	ret = btrfs_insert_empty_item(trans, root, path, &key,
333*4882a593Smuzhiyun 				      ins_len);
334*4882a593Smuzhiyun 	if (ret == -EEXIST) {
335*4882a593Smuzhiyun 		u32 old_size;
336*4882a593Smuzhiyun 		ref = btrfs_find_name_in_backref(path->nodes[0], path->slots[0],
337*4882a593Smuzhiyun 						 name, name_len);
338*4882a593Smuzhiyun 		if (ref)
339*4882a593Smuzhiyun 			goto out;
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 		old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]);
342*4882a593Smuzhiyun 		btrfs_extend_item(path, ins_len);
343*4882a593Smuzhiyun 		ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
344*4882a593Smuzhiyun 				     struct btrfs_inode_ref);
345*4882a593Smuzhiyun 		ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size);
346*4882a593Smuzhiyun 		btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
347*4882a593Smuzhiyun 		btrfs_set_inode_ref_index(path->nodes[0], ref, index);
348*4882a593Smuzhiyun 		ptr = (unsigned long)(ref + 1);
349*4882a593Smuzhiyun 		ret = 0;
350*4882a593Smuzhiyun 	} else if (ret < 0) {
351*4882a593Smuzhiyun 		if (ret == -EOVERFLOW) {
352*4882a593Smuzhiyun 			if (btrfs_find_name_in_backref(path->nodes[0],
353*4882a593Smuzhiyun 						       path->slots[0],
354*4882a593Smuzhiyun 						       name, name_len))
355*4882a593Smuzhiyun 				ret = -EEXIST;
356*4882a593Smuzhiyun 			else
357*4882a593Smuzhiyun 				ret = -EMLINK;
358*4882a593Smuzhiyun 		}
359*4882a593Smuzhiyun 		goto out;
360*4882a593Smuzhiyun 	} else {
361*4882a593Smuzhiyun 		ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
362*4882a593Smuzhiyun 				     struct btrfs_inode_ref);
363*4882a593Smuzhiyun 		btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
364*4882a593Smuzhiyun 		btrfs_set_inode_ref_index(path->nodes[0], ref, index);
365*4882a593Smuzhiyun 		ptr = (unsigned long)(ref + 1);
366*4882a593Smuzhiyun 	}
367*4882a593Smuzhiyun 	write_extent_buffer(path->nodes[0], name, ptr, name_len);
368*4882a593Smuzhiyun 	btrfs_mark_buffer_dirty(path->nodes[0]);
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun out:
371*4882a593Smuzhiyun 	btrfs_free_path(path);
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	if (ret == -EMLINK) {
374*4882a593Smuzhiyun 		struct btrfs_super_block *disk_super = fs_info->super_copy;
375*4882a593Smuzhiyun 		/* We ran out of space in the ref array. Need to
376*4882a593Smuzhiyun 		 * add an extended ref. */
377*4882a593Smuzhiyun 		if (btrfs_super_incompat_flags(disk_super)
378*4882a593Smuzhiyun 		    & BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF)
379*4882a593Smuzhiyun 			ret = btrfs_insert_inode_extref(trans, root, name,
380*4882a593Smuzhiyun 							name_len,
381*4882a593Smuzhiyun 							inode_objectid,
382*4882a593Smuzhiyun 							ref_objectid, index);
383*4882a593Smuzhiyun 	}
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	return ret;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun 
btrfs_insert_empty_inode(struct btrfs_trans_handle * trans,struct btrfs_root * root,struct btrfs_path * path,u64 objectid)388*4882a593Smuzhiyun int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans,
389*4882a593Smuzhiyun 			     struct btrfs_root *root,
390*4882a593Smuzhiyun 			     struct btrfs_path *path, u64 objectid)
391*4882a593Smuzhiyun {
392*4882a593Smuzhiyun 	struct btrfs_key key;
393*4882a593Smuzhiyun 	int ret;
394*4882a593Smuzhiyun 	key.objectid = objectid;
395*4882a593Smuzhiyun 	key.type = BTRFS_INODE_ITEM_KEY;
396*4882a593Smuzhiyun 	key.offset = 0;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	ret = btrfs_insert_empty_item(trans, root, path, &key,
399*4882a593Smuzhiyun 				      sizeof(struct btrfs_inode_item));
400*4882a593Smuzhiyun 	return ret;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun 
btrfs_lookup_inode(struct btrfs_trans_handle * trans,struct btrfs_root * root,struct btrfs_path * path,struct btrfs_key * location,int mod)403*4882a593Smuzhiyun int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
404*4882a593Smuzhiyun 		       *root, struct btrfs_path *path,
405*4882a593Smuzhiyun 		       struct btrfs_key *location, int mod)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun 	int ins_len = mod < 0 ? -1 : 0;
408*4882a593Smuzhiyun 	int cow = mod != 0;
409*4882a593Smuzhiyun 	int ret;
410*4882a593Smuzhiyun 	int slot;
411*4882a593Smuzhiyun 	struct extent_buffer *leaf;
412*4882a593Smuzhiyun 	struct btrfs_key found_key;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	ret = btrfs_search_slot(trans, root, location, path, ins_len, cow);
415*4882a593Smuzhiyun 	if (ret > 0 && location->type == BTRFS_ROOT_ITEM_KEY &&
416*4882a593Smuzhiyun 	    location->offset == (u64)-1 && path->slots[0] != 0) {
417*4882a593Smuzhiyun 		slot = path->slots[0] - 1;
418*4882a593Smuzhiyun 		leaf = path->nodes[0];
419*4882a593Smuzhiyun 		btrfs_item_key_to_cpu(leaf, &found_key, slot);
420*4882a593Smuzhiyun 		if (found_key.objectid == location->objectid &&
421*4882a593Smuzhiyun 		    found_key.type == location->type) {
422*4882a593Smuzhiyun 			path->slots[0]--;
423*4882a593Smuzhiyun 			return 0;
424*4882a593Smuzhiyun 		}
425*4882a593Smuzhiyun 	}
426*4882a593Smuzhiyun 	return ret;
427*4882a593Smuzhiyun }
428