Linux Audio

Check our new training course

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