xref: /openbmc/linux/fs/btrfs/inode-item.c (revision 727011e0)
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"
21e089f05cSChris Mason #include "transaction.h"
22727011e0SChris Mason #include "print-tree.h"
231e1d2701SChris Mason 
24b2950863SChristoph Hellwig static int find_name_in_backref(struct btrfs_path *path, const char *name,
253954401fSChris Mason 			 int name_len, struct btrfs_inode_ref **ref_ret)
263954401fSChris Mason {
273954401fSChris Mason 	struct extent_buffer *leaf;
283954401fSChris Mason 	struct btrfs_inode_ref *ref;
293954401fSChris Mason 	unsigned long ptr;
303954401fSChris Mason 	unsigned long name_ptr;
313954401fSChris Mason 	u32 item_size;
323954401fSChris Mason 	u32 cur_offset = 0;
333954401fSChris Mason 	int len;
343954401fSChris Mason 
353954401fSChris Mason 	leaf = path->nodes[0];
363954401fSChris Mason 	item_size = btrfs_item_size_nr(leaf, path->slots[0]);
373954401fSChris Mason 	ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
383954401fSChris Mason 	while (cur_offset < item_size) {
393954401fSChris Mason 		ref = (struct btrfs_inode_ref *)(ptr + cur_offset);
403954401fSChris Mason 		len = btrfs_inode_ref_name_len(leaf, ref);
413954401fSChris Mason 		name_ptr = (unsigned long)(ref + 1);
423954401fSChris Mason 		cur_offset += len + sizeof(*ref);
433954401fSChris Mason 		if (len != name_len)
443954401fSChris Mason 			continue;
453954401fSChris Mason 		if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) {
463954401fSChris Mason 			*ref_ret = ref;
473954401fSChris Mason 			return 1;
483954401fSChris Mason 		}
493954401fSChris Mason 	}
503954401fSChris Mason 	return 0;
513954401fSChris Mason }
523954401fSChris Mason 
53a22285a6SYan, Zheng struct btrfs_inode_ref *
54a22285a6SYan, Zheng btrfs_lookup_inode_ref(struct btrfs_trans_handle *trans,
55a22285a6SYan, Zheng 			struct btrfs_root *root,
56a22285a6SYan, Zheng 			struct btrfs_path *path,
57a22285a6SYan, Zheng 			const char *name, int name_len,
58a22285a6SYan, Zheng 			u64 inode_objectid, u64 ref_objectid, int mod)
59a22285a6SYan, Zheng {
60a22285a6SYan, Zheng 	struct btrfs_key key;
61a22285a6SYan, Zheng 	struct btrfs_inode_ref *ref;
62a22285a6SYan, Zheng 	int ins_len = mod < 0 ? -1 : 0;
63a22285a6SYan, Zheng 	int cow = mod != 0;
64a22285a6SYan, Zheng 	int ret;
65a22285a6SYan, Zheng 
66a22285a6SYan, Zheng 	key.objectid = inode_objectid;
67a22285a6SYan, Zheng 	key.type = BTRFS_INODE_REF_KEY;
68a22285a6SYan, Zheng 	key.offset = ref_objectid;
69a22285a6SYan, Zheng 
70a22285a6SYan, Zheng 	ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
71a22285a6SYan, Zheng 	if (ret < 0)
72a22285a6SYan, Zheng 		return ERR_PTR(ret);
73a22285a6SYan, Zheng 	if (ret > 0)
74a22285a6SYan, Zheng 		return NULL;
75a22285a6SYan, Zheng 	if (!find_name_in_backref(path, name, name_len, &ref))
76a22285a6SYan, Zheng 		return NULL;
77a22285a6SYan, Zheng 	return ref;
78a22285a6SYan, Zheng }
79a22285a6SYan, Zheng 
803954401fSChris Mason int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
813954401fSChris Mason 			   struct btrfs_root *root,
823954401fSChris Mason 			   const char *name, int name_len,
83aec7477bSJosef Bacik 			   u64 inode_objectid, u64 ref_objectid, u64 *index)
843954401fSChris Mason {
853954401fSChris Mason 	struct btrfs_path *path;
863954401fSChris Mason 	struct btrfs_key key;
873954401fSChris Mason 	struct btrfs_inode_ref *ref;
883954401fSChris Mason 	struct extent_buffer *leaf;
893954401fSChris Mason 	unsigned long ptr;
903954401fSChris Mason 	unsigned long item_start;
913954401fSChris Mason 	u32 item_size;
923954401fSChris Mason 	u32 sub_item_len;
933954401fSChris Mason 	int ret;
943954401fSChris Mason 	int del_len = name_len + sizeof(*ref);
953954401fSChris Mason 
963954401fSChris Mason 	key.objectid = inode_objectid;
973954401fSChris Mason 	key.offset = ref_objectid;
983954401fSChris Mason 	btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY);
993954401fSChris Mason 
1003954401fSChris Mason 	path = btrfs_alloc_path();
1013954401fSChris Mason 	if (!path)
1023954401fSChris Mason 		return -ENOMEM;
1033954401fSChris Mason 
104b9473439SChris Mason 	path->leave_spinning = 1;
105b9473439SChris Mason 
1063954401fSChris Mason 	ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
1073954401fSChris Mason 	if (ret > 0) {
1083954401fSChris Mason 		ret = -ENOENT;
1093954401fSChris Mason 		goto out;
1103954401fSChris Mason 	} else if (ret < 0) {
1113954401fSChris Mason 		goto out;
1123954401fSChris Mason 	}
1133954401fSChris Mason 	if (!find_name_in_backref(path, name, name_len, &ref)) {
1143954401fSChris Mason 		ret = -ENOENT;
1153954401fSChris Mason 		goto out;
1163954401fSChris Mason 	}
1173954401fSChris Mason 	leaf = path->nodes[0];
1183954401fSChris Mason 	item_size = btrfs_item_size_nr(leaf, path->slots[0]);
119aec7477bSJosef Bacik 
120aec7477bSJosef Bacik 	if (index)
121aec7477bSJosef Bacik 		*index = btrfs_inode_ref_index(leaf, ref);
122aec7477bSJosef Bacik 
1233954401fSChris Mason 	if (del_len == item_size) {
1243954401fSChris Mason 		ret = btrfs_del_item(trans, root, path);
1253954401fSChris Mason 		goto out;
1263954401fSChris Mason 	}
1273954401fSChris Mason 	ptr = (unsigned long)ref;
1283954401fSChris Mason 	sub_item_len = name_len + sizeof(*ref);
1293954401fSChris Mason 	item_start = btrfs_item_ptr_offset(leaf, path->slots[0]);
1303954401fSChris Mason 	memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
1313954401fSChris Mason 			      item_size - (ptr + sub_item_len - item_start));
1323954401fSChris Mason 	ret = btrfs_truncate_item(trans, root, path,
1333954401fSChris Mason 				  item_size - sub_item_len, 1);
1343954401fSChris Mason out:
1353954401fSChris Mason 	btrfs_free_path(path);
1363954401fSChris Mason 	return ret;
1373954401fSChris Mason }
1383954401fSChris Mason 
1393954401fSChris Mason int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
1403954401fSChris Mason 			   struct btrfs_root *root,
1413954401fSChris Mason 			   const char *name, int name_len,
142aec7477bSJosef Bacik 			   u64 inode_objectid, u64 ref_objectid, u64 index)
1433954401fSChris Mason {
1443954401fSChris Mason 	struct btrfs_path *path;
1453954401fSChris Mason 	struct btrfs_key key;
1463954401fSChris Mason 	struct btrfs_inode_ref *ref;
1473954401fSChris Mason 	unsigned long ptr;
1483954401fSChris Mason 	int ret;
1493954401fSChris Mason 	int ins_len = name_len + sizeof(*ref);
1503954401fSChris Mason 
1513954401fSChris Mason 	key.objectid = inode_objectid;
1523954401fSChris Mason 	key.offset = ref_objectid;
1533954401fSChris Mason 	btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY);
1543954401fSChris Mason 
1553954401fSChris Mason 	path = btrfs_alloc_path();
1563954401fSChris Mason 	if (!path)
1573954401fSChris Mason 		return -ENOMEM;
1583954401fSChris Mason 
159b9473439SChris Mason 	path->leave_spinning = 1;
1603954401fSChris Mason 	ret = btrfs_insert_empty_item(trans, root, path, &key,
1613954401fSChris Mason 				      ins_len);
1623954401fSChris Mason 	if (ret == -EEXIST) {
1633954401fSChris Mason 		u32 old_size;
1643954401fSChris Mason 
1653954401fSChris Mason 		if (find_name_in_backref(path, name, name_len, &ref))
1663954401fSChris Mason 			goto out;
1673954401fSChris Mason 
1683954401fSChris Mason 		old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]);
1693954401fSChris Mason 		ret = btrfs_extend_item(trans, root, path, ins_len);
1703954401fSChris Mason 		ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
1713954401fSChris Mason 				     struct btrfs_inode_ref);
1723954401fSChris Mason 		ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size);
1733954401fSChris Mason 		btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
174aec7477bSJosef Bacik 		btrfs_set_inode_ref_index(path->nodes[0], ref, index);
1753954401fSChris Mason 		ptr = (unsigned long)(ref + 1);
1763954401fSChris Mason 		ret = 0;
1773954401fSChris Mason 	} else if (ret < 0) {
178a5719521SYan, Zheng 		if (ret == -EOVERFLOW)
179a5719521SYan, Zheng 			ret = -EMLINK;
1803954401fSChris Mason 		goto out;
1813954401fSChris Mason 	} else {
1823954401fSChris Mason 		ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
1833954401fSChris Mason 				     struct btrfs_inode_ref);
1843954401fSChris Mason 		btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
185aec7477bSJosef Bacik 		btrfs_set_inode_ref_index(path->nodes[0], ref, index);
1863954401fSChris Mason 		ptr = (unsigned long)(ref + 1);
1873954401fSChris Mason 	}
1883954401fSChris Mason 	write_extent_buffer(path->nodes[0], name, ptr, name_len);
1893954401fSChris Mason 	btrfs_mark_buffer_dirty(path->nodes[0]);
1903954401fSChris Mason 
1913954401fSChris Mason out:
1923954401fSChris Mason 	btrfs_free_path(path);
1933954401fSChris Mason 	return ret;
1943954401fSChris Mason }
1953954401fSChris Mason 
1965f39d397SChris Mason int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans,
1975f39d397SChris Mason 			     struct btrfs_root *root,
1985f39d397SChris Mason 			     struct btrfs_path *path, u64 objectid)
1991e1d2701SChris Mason {
2001e1d2701SChris Mason 	struct btrfs_key key;
2011e1d2701SChris Mason 	int ret;
2021e1d2701SChris Mason 	key.objectid = objectid;
2031e1d2701SChris Mason 	btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
2041e1d2701SChris Mason 	key.offset = 0;
2051e1d2701SChris Mason 
2065f39d397SChris Mason 	ret = btrfs_insert_empty_item(trans, root, path, &key,
2075f39d397SChris Mason 				      sizeof(struct btrfs_inode_item));
2081e1d2701SChris Mason 	return ret;
2091e1d2701SChris Mason }
2101e1d2701SChris Mason 
211e089f05cSChris Mason int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
212d6e4a428SChris Mason 		       *root, struct btrfs_path *path,
213d6e4a428SChris Mason 		       struct btrfs_key *location, int mod)
2141e1d2701SChris Mason {
2151e1d2701SChris Mason 	int ins_len = mod < 0 ? -1 : 0;
2161e1d2701SChris Mason 	int cow = mod != 0;
217d6e4a428SChris Mason 	int ret;
218d6e4a428SChris Mason 	int slot;
2195f39d397SChris Mason 	struct extent_buffer *leaf;
220d6e4a428SChris Mason 	struct btrfs_key found_key;
2211e1d2701SChris Mason 
222d6e4a428SChris Mason 	ret = btrfs_search_slot(trans, root, location, path, ins_len, cow);
223d6e4a428SChris Mason 	if (ret > 0 && btrfs_key_type(location) == BTRFS_ROOT_ITEM_KEY &&
224d6e4a428SChris Mason 	    location->offset == (u64)-1 && path->slots[0] != 0) {
225d6e4a428SChris Mason 		slot = path->slots[0] - 1;
2265f39d397SChris Mason 		leaf = path->nodes[0];
2275f39d397SChris Mason 		btrfs_item_key_to_cpu(leaf, &found_key, slot);
228d6e4a428SChris Mason 		if (found_key.objectid == location->objectid &&
229d6e4a428SChris Mason 		    btrfs_key_type(&found_key) == btrfs_key_type(location)) {
230d6e4a428SChris Mason 			path->slots[0]--;
231d6e4a428SChris Mason 			return 0;
232d6e4a428SChris Mason 		}
233d6e4a428SChris Mason 	}
234d6e4a428SChris Mason 	return ret;
2351e1d2701SChris Mason }
236