xref: /openbmc/linux/fs/btrfs/dir-item.c (revision 5f39d397)
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 
1962e2749eSChris Mason #include "ctree.h"
2062e2749eSChris Mason #include "disk-io.h"
2162e2749eSChris Mason #include "hash.h"
22e089f05cSChris Mason #include "transaction.h"
2362e2749eSChris Mason 
2435b7e476SChris Mason static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
2535b7e476SChris Mason 						   *trans,
267e38180eSChris Mason 						   struct btrfs_root *root,
277e38180eSChris Mason 						   struct btrfs_path *path,
287e38180eSChris Mason 						   struct btrfs_key *cpu_key,
29e06afa83SChris Mason 						   u32 data_size,
30e06afa83SChris Mason 						   const char *name,
31e06afa83SChris Mason 						   int name_len)
327fcde0e3SChris Mason {
337fcde0e3SChris Mason 	int ret;
347e38180eSChris Mason 	char *ptr;
357e38180eSChris Mason 	struct btrfs_item *item;
365f39d397SChris Mason 	struct extent_buffer *leaf;
377fcde0e3SChris Mason 
387fcde0e3SChris Mason 	ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
397e38180eSChris Mason 	if (ret == -EEXIST) {
40e06afa83SChris Mason 		struct btrfs_dir_item *di;
41e06afa83SChris Mason 		di = btrfs_match_dir_item_name(root, path, name, name_len);
42e06afa83SChris Mason 		if (di)
43e06afa83SChris Mason 			return ERR_PTR(-EEXIST);
447e38180eSChris Mason 		ret = btrfs_extend_item(trans, root, path, data_size);
457e38180eSChris Mason 		WARN_ON(ret > 0);
467e38180eSChris Mason 		if (ret)
477e38180eSChris Mason 			return ERR_PTR(ret);
487fcde0e3SChris Mason 	}
4954aa1f4dSChris Mason 	if (ret < 0)
5054aa1f4dSChris Mason 		return ERR_PTR(ret);
517e38180eSChris Mason 	WARN_ON(ret > 0);
525f39d397SChris Mason 	leaf = path->nodes[0];
535f39d397SChris Mason 	item = btrfs_item_nr(leaf, path->slots[0]);
547e38180eSChris Mason 	ptr = btrfs_item_ptr(leaf, path->slots[0], char);
555f39d397SChris Mason 	BUG_ON(data_size > btrfs_item_size(leaf, item));
565f39d397SChris Mason 	ptr += btrfs_item_size(leaf, item) - data_size;
577e38180eSChris Mason 	return (struct btrfs_dir_item *)ptr;
587fcde0e3SChris Mason }
597fcde0e3SChris Mason 
60e089f05cSChris Mason int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
61d6e4a428SChris Mason 			  *root, const char *name, int name_len, u64 dir,
62d6e4a428SChris Mason 			  struct btrfs_key *location, u8 type)
6362e2749eSChris Mason {
6462e2749eSChris Mason 	int ret = 0;
65e06afa83SChris Mason 	int ret2 = 0;
665caf2a00SChris Mason 	struct btrfs_path *path;
6762e2749eSChris Mason 	struct btrfs_dir_item *dir_item;
685f39d397SChris Mason 	struct extent_buffer *leaf;
695f39d397SChris Mason 	unsigned long name_ptr;
7062e2749eSChris Mason 	struct btrfs_key key;
715f39d397SChris Mason 	struct btrfs_disk_key disk_key;
7262e2749eSChris Mason 	u32 data_size;
7362e2749eSChris Mason 
7462e2749eSChris Mason 	key.objectid = dir;
751d4f6404SChris Mason 	btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
7662e2749eSChris Mason 	ret = btrfs_name_hash(name, name_len, &key.offset);
7762e2749eSChris Mason 	BUG_ON(ret);
785caf2a00SChris Mason 	path = btrfs_alloc_path();
7962e2749eSChris Mason 	data_size = sizeof(*dir_item) + name_len;
80e06afa83SChris Mason 	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
81e06afa83SChris Mason 					name, name_len);
827e38180eSChris Mason 	if (IS_ERR(dir_item)) {
837e38180eSChris Mason 		ret = PTR_ERR(dir_item);
84e06afa83SChris Mason 		if (ret == -EEXIST)
85e06afa83SChris Mason 			goto second_insert;
8662e2749eSChris Mason 		goto out;
877e38180eSChris Mason 	}
8862e2749eSChris Mason 
895f39d397SChris Mason 	leaf = path->nodes[0];
905f39d397SChris Mason 	btrfs_cpu_key_to_disk(&disk_key, location);
915f39d397SChris Mason 	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
925f39d397SChris Mason 	btrfs_set_dir_type(leaf, dir_item, type);
935f39d397SChris Mason 	btrfs_set_dir_flags(leaf, dir_item, 0);
945f39d397SChris Mason 	btrfs_set_dir_name_len(leaf, dir_item, name_len);
955f39d397SChris Mason 	name_ptr = (unsigned long)(dir_item + 1);
96c5739bbaSChris Mason 
975f39d397SChris Mason 	write_extent_buffer(leaf, name, name_ptr, name_len);
985f39d397SChris Mason 	btrfs_mark_buffer_dirty(leaf);
997e38180eSChris Mason 
100e06afa83SChris Mason second_insert:
1017e38180eSChris Mason 	/* FIXME, use some real flag for selecting the extra index */
1027e38180eSChris Mason 	if (root == root->fs_info->tree_root) {
1037e38180eSChris Mason 		ret = 0;
1047e38180eSChris Mason 		goto out;
1057e38180eSChris Mason 	}
1065caf2a00SChris Mason 	btrfs_release_path(root, path);
1077e38180eSChris Mason 
1087e38180eSChris Mason 	btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
1097e38180eSChris Mason 	key.offset = location->objectid;
110e06afa83SChris Mason 	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
111e06afa83SChris Mason 					name, name_len);
1127e38180eSChris Mason 	if (IS_ERR(dir_item)) {
113e06afa83SChris Mason 		ret2 = PTR_ERR(dir_item);
1147e38180eSChris Mason 		goto out;
1157e38180eSChris Mason 	}
1165f39d397SChris Mason 	leaf = path->nodes[0];
1175f39d397SChris Mason 	btrfs_cpu_key_to_disk(&disk_key, location);
1185f39d397SChris Mason 	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
1195f39d397SChris Mason 	btrfs_set_dir_type(leaf, dir_item, type);
1205f39d397SChris Mason 	btrfs_set_dir_flags(leaf, dir_item, 0);
1215f39d397SChris Mason 	btrfs_set_dir_name_len(leaf, dir_item, name_len);
1225f39d397SChris Mason 	name_ptr = (unsigned long)(dir_item + 1);
1235f39d397SChris Mason 	write_extent_buffer(leaf, name, name_ptr, name_len);
1245f39d397SChris Mason 	btrfs_mark_buffer_dirty(leaf);
1257e38180eSChris Mason out:
1265caf2a00SChris Mason 	btrfs_free_path(path);
127e06afa83SChris Mason 	if (ret)
12862e2749eSChris Mason 		return ret;
129e06afa83SChris Mason 	if (ret2)
130e06afa83SChris Mason 		return ret2;
131e06afa83SChris Mason 	return 0;
13262e2749eSChris Mason }
13362e2749eSChris Mason 
1347e38180eSChris Mason struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
1357e38180eSChris Mason 					     struct btrfs_root *root,
1367e38180eSChris Mason 					     struct btrfs_path *path, u64 dir,
1377e38180eSChris Mason 					     const char *name, int name_len,
1387e38180eSChris Mason 					     int mod)
13962e2749eSChris Mason {
1401d4f6404SChris Mason 	int ret;
14162e2749eSChris Mason 	struct btrfs_key key;
1421d4f6404SChris Mason 	int ins_len = mod < 0 ? -1 : 0;
1431d4f6404SChris Mason 	int cow = mod != 0;
1445f39d397SChris Mason 	struct btrfs_key found_key;
1455f39d397SChris Mason 	struct extent_buffer *leaf;
14662e2749eSChris Mason 
14762e2749eSChris Mason 	key.objectid = dir;
1481d4f6404SChris Mason 	btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
1495f39d397SChris Mason 
15062e2749eSChris Mason 	ret = btrfs_name_hash(name, name_len, &key.offset);
15162e2749eSChris Mason 	BUG_ON(ret);
1525f39d397SChris Mason 
153e089f05cSChris Mason 	ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
1547fcde0e3SChris Mason 	if (ret < 0)
1557e38180eSChris Mason 		return ERR_PTR(ret);
1567fcde0e3SChris Mason 	if (ret > 0) {
1577fcde0e3SChris Mason 		if (path->slots[0] == 0)
1587e38180eSChris Mason 			return NULL;
1597fcde0e3SChris Mason 		path->slots[0]--;
1607fcde0e3SChris Mason 	}
1617fcde0e3SChris Mason 
1625f39d397SChris Mason 	leaf = path->nodes[0];
1635f39d397SChris Mason 	btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
1645f39d397SChris Mason 
1655f39d397SChris Mason 	if (found_key.objectid != dir ||
1665f39d397SChris Mason 	    btrfs_key_type(&found_key) != BTRFS_DIR_ITEM_KEY ||
1675f39d397SChris Mason 	    found_key.offset != key.offset)
1687e38180eSChris Mason 		return NULL;
1697fcde0e3SChris Mason 
1707e38180eSChris Mason 	return btrfs_match_dir_item_name(root, path, name, name_len);
17162e2749eSChris Mason }
17262e2749eSChris Mason 
1737e38180eSChris Mason struct btrfs_dir_item *
1747e38180eSChris Mason btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
1757e38180eSChris Mason 			    struct btrfs_root *root,
1767e38180eSChris Mason 			    struct btrfs_path *path, u64 dir,
1777e38180eSChris Mason 			    u64 objectid, const char *name, int name_len,
1787e38180eSChris Mason 			    int mod)
1797e38180eSChris Mason {
1807e38180eSChris Mason 	int ret;
1817e38180eSChris Mason 	struct btrfs_key key;
1827e38180eSChris Mason 	int ins_len = mod < 0 ? -1 : 0;
1837e38180eSChris Mason 	int cow = mod != 0;
1847e38180eSChris Mason 
1857e38180eSChris Mason 	key.objectid = dir;
1867e38180eSChris Mason 	btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
1877e38180eSChris Mason 	key.offset = objectid;
1887e38180eSChris Mason 
1897e38180eSChris Mason 	ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
1907e38180eSChris Mason 	if (ret < 0)
1917e38180eSChris Mason 		return ERR_PTR(ret);
1927e38180eSChris Mason 	if (ret > 0)
1937e38180eSChris Mason 		return ERR_PTR(-ENOENT);
1947e38180eSChris Mason 	return btrfs_match_dir_item_name(root, path, name, name_len);
1957e38180eSChris Mason }
1967e38180eSChris Mason 
1977e38180eSChris Mason struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
1987f5c1516SChris Mason 			      struct btrfs_path *path,
1997f5c1516SChris Mason 			      const char *name, int name_len)
20062e2749eSChris Mason {
20162e2749eSChris Mason 	struct btrfs_dir_item *dir_item;
2025f39d397SChris Mason 	unsigned long name_ptr;
2037e38180eSChris Mason 	u32 total_len;
2047e38180eSChris Mason 	u32 cur = 0;
2057e38180eSChris Mason 	u32 this_len;
2065f39d397SChris Mason 	struct extent_buffer *leaf;
207a8a2ee0cSChris Mason 
2085f39d397SChris Mason 	leaf = path->nodes[0];
2097e38180eSChris Mason 	dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
2105f39d397SChris Mason 	total_len = btrfs_item_size_nr(leaf, path->slots[0]);
2117e38180eSChris Mason 	while(cur < total_len) {
2125f39d397SChris Mason 		this_len = sizeof(*dir_item) +
2135f39d397SChris Mason 			btrfs_dir_name_len(leaf, dir_item);
2145f39d397SChris Mason 		name_ptr = (unsigned long)(dir_item + 1);
2157e38180eSChris Mason 
2165f39d397SChris Mason 		if (btrfs_dir_name_len(leaf, dir_item) == name_len &&
2175f39d397SChris Mason 		    memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
2187e38180eSChris Mason 			return dir_item;
2197e38180eSChris Mason 
2207e38180eSChris Mason 		cur += this_len;
2217e38180eSChris Mason 		dir_item = (struct btrfs_dir_item *)((char *)dir_item +
2227e38180eSChris Mason 						     this_len);
22362e2749eSChris Mason 	}
2247e38180eSChris Mason 	return NULL;
2257e38180eSChris Mason }
2267e38180eSChris Mason 
2277e38180eSChris Mason int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
2287e38180eSChris Mason 			      struct btrfs_root *root,
2297e38180eSChris Mason 			      struct btrfs_path *path,
2307e38180eSChris Mason 			      struct btrfs_dir_item *di)
2317e38180eSChris Mason {
2327e38180eSChris Mason 
2335f39d397SChris Mason 	struct extent_buffer *leaf;
2347e38180eSChris Mason 	u32 sub_item_len;
2357e38180eSChris Mason 	u32 item_len;
23654aa1f4dSChris Mason 	int ret = 0;
2377e38180eSChris Mason 
2385f39d397SChris Mason 	leaf = path->nodes[0];
2395f39d397SChris Mason 	sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di);
2405f39d397SChris Mason 	item_len = btrfs_item_size_nr(leaf, path->slots[0]);
2415f39d397SChris Mason 	if (sub_item_len == item_len) {
2427e38180eSChris Mason 		ret = btrfs_del_item(trans, root, path);
2437e38180eSChris Mason 	} else {
2445f39d397SChris Mason 		/* MARKER */
2455f39d397SChris Mason 		unsigned long ptr = (unsigned long)di;
2465f39d397SChris Mason 		unsigned long start;
2475f39d397SChris Mason 
2485f39d397SChris Mason 		start = btrfs_item_ptr_offset(leaf, path->slots[0]);
2495f39d397SChris Mason 		memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
2507e38180eSChris Mason 			item_len - (ptr + sub_item_len - start));
2517e38180eSChris Mason 		ret = btrfs_truncate_item(trans, root, path,
2527e38180eSChris Mason 					  item_len - sub_item_len);
2537e38180eSChris Mason 	}
2547e38180eSChris Mason 	return 0;
2557e38180eSChris Mason }
2567e38180eSChris Mason 
257