xref: /openbmc/linux/fs/btrfs/inode-item.c (revision aec7477b)
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"
221e1d2701SChris Mason 
233954401fSChris Mason int find_name_in_backref(struct btrfs_path *path, const char * name,
243954401fSChris Mason 			 int name_len, struct btrfs_inode_ref **ref_ret)
253954401fSChris Mason {
263954401fSChris Mason 	struct extent_buffer *leaf;
273954401fSChris Mason 	struct btrfs_inode_ref *ref;
283954401fSChris Mason 	unsigned long ptr;
293954401fSChris Mason 	unsigned long name_ptr;
303954401fSChris Mason 	u32 item_size;
313954401fSChris Mason 	u32 cur_offset = 0;
323954401fSChris Mason 	int len;
333954401fSChris Mason 
343954401fSChris Mason 	leaf = path->nodes[0];
353954401fSChris Mason 	item_size = btrfs_item_size_nr(leaf, path->slots[0]);
363954401fSChris Mason 	ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
373954401fSChris Mason 	while (cur_offset < item_size) {
383954401fSChris Mason 		ref = (struct btrfs_inode_ref *)(ptr + cur_offset);
393954401fSChris Mason 		len = btrfs_inode_ref_name_len(leaf, ref);
403954401fSChris Mason 		name_ptr = (unsigned long)(ref + 1);
413954401fSChris Mason 		cur_offset += len + sizeof(*ref);
423954401fSChris Mason 		if (len != name_len)
433954401fSChris Mason 			continue;
443954401fSChris Mason 		if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) {
453954401fSChris Mason 			*ref_ret = ref;
463954401fSChris Mason 			return 1;
473954401fSChris Mason 		}
483954401fSChris Mason 	}
493954401fSChris Mason 	return 0;
503954401fSChris Mason }
513954401fSChris Mason 
523954401fSChris Mason int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
533954401fSChris Mason 			   struct btrfs_root *root,
543954401fSChris Mason 			   const char *name, int name_len,
55aec7477bSJosef Bacik 			   u64 inode_objectid, u64 ref_objectid, u64 *index)
563954401fSChris Mason {
573954401fSChris Mason 	struct btrfs_path *path;
583954401fSChris Mason 	struct btrfs_key key;
593954401fSChris Mason 	struct btrfs_inode_ref *ref;
603954401fSChris Mason 	struct extent_buffer *leaf;
613954401fSChris Mason 	unsigned long ptr;
623954401fSChris Mason 	unsigned long item_start;
633954401fSChris Mason 	u32 item_size;
643954401fSChris Mason 	u32 sub_item_len;
653954401fSChris Mason 	int ret;
663954401fSChris Mason 	int del_len = name_len + sizeof(*ref);
673954401fSChris Mason 
683954401fSChris Mason 	key.objectid = inode_objectid;
693954401fSChris Mason 	key.offset = ref_objectid;
703954401fSChris Mason 	btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY);
713954401fSChris Mason 
723954401fSChris Mason 	path = btrfs_alloc_path();
733954401fSChris Mason 	if (!path)
743954401fSChris Mason 		return -ENOMEM;
753954401fSChris Mason 
763954401fSChris Mason 	ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
773954401fSChris Mason 	if (ret > 0) {
783954401fSChris Mason 		ret = -ENOENT;
793954401fSChris Mason 		goto out;
803954401fSChris Mason 	} else if (ret < 0) {
813954401fSChris Mason 		goto out;
823954401fSChris Mason 	}
833954401fSChris Mason 	if (!find_name_in_backref(path, name, name_len, &ref)) {
843954401fSChris Mason 		ret = -ENOENT;
853954401fSChris Mason 		goto out;
863954401fSChris Mason 	}
873954401fSChris Mason 	leaf = path->nodes[0];
883954401fSChris Mason 	item_size = btrfs_item_size_nr(leaf, path->slots[0]);
89aec7477bSJosef Bacik 
90aec7477bSJosef Bacik 	if (index)
91aec7477bSJosef Bacik 		*index = btrfs_inode_ref_index(leaf, ref);
92aec7477bSJosef Bacik 
933954401fSChris Mason 	if (del_len == item_size) {
943954401fSChris Mason 		ret = btrfs_del_item(trans, root, path);
953954401fSChris Mason 		goto out;
963954401fSChris Mason 	}
973954401fSChris Mason 	ptr = (unsigned long)ref;
983954401fSChris Mason 	sub_item_len = name_len + sizeof(*ref);
993954401fSChris Mason 	item_start = btrfs_item_ptr_offset(leaf, path->slots[0]);
1003954401fSChris Mason 	memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
1013954401fSChris Mason 			      item_size - (ptr + sub_item_len - item_start));
1023954401fSChris Mason 	ret = btrfs_truncate_item(trans, root, path,
1033954401fSChris Mason 				  item_size - sub_item_len, 1);
1043954401fSChris Mason 	BUG_ON(ret);
1053954401fSChris Mason out:
1063954401fSChris Mason 	btrfs_free_path(path);
1073954401fSChris Mason 	return ret;
1083954401fSChris Mason }
1093954401fSChris Mason 
1103954401fSChris Mason int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
1113954401fSChris Mason 			   struct btrfs_root *root,
1123954401fSChris Mason 			   const char *name, int name_len,
113aec7477bSJosef Bacik 			   u64 inode_objectid, u64 ref_objectid, u64 index)
1143954401fSChris Mason {
1153954401fSChris Mason 	struct btrfs_path *path;
1163954401fSChris Mason 	struct btrfs_key key;
1173954401fSChris Mason 	struct btrfs_inode_ref *ref;
1183954401fSChris Mason 	unsigned long ptr;
1193954401fSChris Mason 	int ret;
1203954401fSChris Mason 	int ins_len = name_len + sizeof(*ref);
1213954401fSChris Mason 
1223954401fSChris Mason 	key.objectid = inode_objectid;
1233954401fSChris Mason 	key.offset = ref_objectid;
1243954401fSChris Mason 	btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY);
1253954401fSChris Mason 
1263954401fSChris Mason 	path = btrfs_alloc_path();
1273954401fSChris Mason 	if (!path)
1283954401fSChris Mason 		return -ENOMEM;
1293954401fSChris Mason 
1303954401fSChris Mason 	ret = btrfs_insert_empty_item(trans, root, path, &key,
1313954401fSChris Mason 				      ins_len);
1323954401fSChris Mason 	if (ret == -EEXIST) {
1333954401fSChris Mason 		u32 old_size;
1343954401fSChris Mason 
1353954401fSChris Mason 		if (find_name_in_backref(path, name, name_len, &ref))
1363954401fSChris Mason 			goto out;
1373954401fSChris Mason 
1383954401fSChris Mason 		old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]);
1393954401fSChris Mason 		ret = btrfs_extend_item(trans, root, path, ins_len);
1403954401fSChris Mason 		BUG_ON(ret);
1413954401fSChris Mason 		ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
1423954401fSChris Mason 				     struct btrfs_inode_ref);
1433954401fSChris Mason 		ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size);
1443954401fSChris Mason 		btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
145aec7477bSJosef Bacik 		btrfs_set_inode_ref_index(path->nodes[0], ref, index);
1463954401fSChris Mason 		ptr = (unsigned long)(ref + 1);
1473954401fSChris Mason 		ret = 0;
1483954401fSChris Mason 	} else if (ret < 0) {
1493954401fSChris Mason 		goto out;
1503954401fSChris Mason 	} else {
1513954401fSChris Mason 		ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
1523954401fSChris Mason 				     struct btrfs_inode_ref);
1533954401fSChris Mason 		btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
154aec7477bSJosef Bacik 		btrfs_set_inode_ref_index(path->nodes[0], ref, index);
1553954401fSChris Mason 		ptr = (unsigned long)(ref + 1);
1563954401fSChris Mason 	}
1573954401fSChris Mason 	write_extent_buffer(path->nodes[0], name, ptr, name_len);
1583954401fSChris Mason 	btrfs_mark_buffer_dirty(path->nodes[0]);
1593954401fSChris Mason 
1603954401fSChris Mason out:
1613954401fSChris Mason 	btrfs_free_path(path);
1623954401fSChris Mason 	return ret;
1633954401fSChris Mason }
1643954401fSChris Mason 
1655f39d397SChris Mason int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans,
1665f39d397SChris Mason 			     struct btrfs_root *root,
1675f39d397SChris Mason 			     struct btrfs_path *path, u64 objectid)
1681e1d2701SChris Mason {
1691e1d2701SChris Mason 	struct btrfs_key key;
1701e1d2701SChris Mason 	int ret;
1711e1d2701SChris Mason 	key.objectid = objectid;
1721e1d2701SChris Mason 	btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
1731e1d2701SChris Mason 	key.offset = 0;
1741e1d2701SChris Mason 
1755f39d397SChris Mason 	ret = btrfs_insert_empty_item(trans, root, path, &key,
1765f39d397SChris Mason 				      sizeof(struct btrfs_inode_item));
1771b05da2eSChris Mason 	if (ret == 0 && objectid > root->highest_inode)
1781b05da2eSChris Mason 		root->highest_inode = objectid;
1791e1d2701SChris Mason 	return ret;
1801e1d2701SChris Mason }
1811e1d2701SChris Mason 
182e089f05cSChris Mason int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
183d6e4a428SChris Mason 		       *root, struct btrfs_path *path,
184d6e4a428SChris Mason 		       struct btrfs_key *location, int mod)
1851e1d2701SChris Mason {
1861e1d2701SChris Mason 	int ins_len = mod < 0 ? -1 : 0;
1871e1d2701SChris Mason 	int cow = mod != 0;
188d6e4a428SChris Mason 	int ret;
189d6e4a428SChris Mason 	int slot;
1905f39d397SChris Mason 	struct extent_buffer *leaf;
191d6e4a428SChris Mason 	struct btrfs_key found_key;
1921e1d2701SChris Mason 
193d6e4a428SChris Mason 	ret = btrfs_search_slot(trans, root, location, path, ins_len, cow);
194d6e4a428SChris Mason 	if (ret > 0 && btrfs_key_type(location) == BTRFS_ROOT_ITEM_KEY &&
195d6e4a428SChris Mason 	    location->offset == (u64)-1 && path->slots[0] != 0) {
196d6e4a428SChris Mason 		slot = path->slots[0] - 1;
1975f39d397SChris Mason 		leaf = path->nodes[0];
1985f39d397SChris Mason 		btrfs_item_key_to_cpu(leaf, &found_key, slot);
199d6e4a428SChris Mason 		if (found_key.objectid == location->objectid &&
200d6e4a428SChris Mason 		    btrfs_key_type(&found_key) == btrfs_key_type(location)) {
201d6e4a428SChris Mason 			path->slots[0]--;
202d6e4a428SChris Mason 			return 0;
203d6e4a428SChris Mason 		}
204d6e4a428SChris Mason 	}
205d6e4a428SChris Mason 	return ret;
2061e1d2701SChris Mason }
207