xref: /openbmc/linux/fs/btrfs/dir-item.c (revision c1d7c514)
1c1d7c514SDavid Sterba // SPDX-License-Identifier: GPL-2.0
26cbd5570SChris Mason /*
36cbd5570SChris Mason  * Copyright (C) 2007 Oracle.  All rights reserved.
46cbd5570SChris Mason  */
56cbd5570SChris Mason 
662e2749eSChris Mason #include "ctree.h"
762e2749eSChris Mason #include "disk-io.h"
8e089f05cSChris Mason #include "transaction.h"
962e2749eSChris Mason 
10d352ac68SChris Mason /*
11d352ac68SChris Mason  * insert a name into a directory, doing overflow properly if there is a hash
12d352ac68SChris Mason  * collision.  data_size indicates how big the item inserted should be.  On
13d352ac68SChris Mason  * success a struct btrfs_dir_item pointer is returned, otherwise it is
14d352ac68SChris Mason  * an ERR_PTR.
15d352ac68SChris Mason  *
16d352ac68SChris Mason  * The name is not copied into the dir item, you have to do that yourself.
17d352ac68SChris Mason  */
1835b7e476SChris Mason static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
1935b7e476SChris Mason 						   *trans,
207e38180eSChris Mason 						   struct btrfs_root *root,
217e38180eSChris Mason 						   struct btrfs_path *path,
227e38180eSChris Mason 						   struct btrfs_key *cpu_key,
23e06afa83SChris Mason 						   u32 data_size,
24e06afa83SChris Mason 						   const char *name,
25e06afa83SChris Mason 						   int name_len)
267fcde0e3SChris Mason {
272ff7e61eSJeff Mahoney 	struct btrfs_fs_info *fs_info = root->fs_info;
287fcde0e3SChris Mason 	int ret;
297e38180eSChris Mason 	char *ptr;
307e38180eSChris Mason 	struct btrfs_item *item;
315f39d397SChris Mason 	struct extent_buffer *leaf;
327fcde0e3SChris Mason 
337fcde0e3SChris Mason 	ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
347e38180eSChris Mason 	if (ret == -EEXIST) {
35e06afa83SChris Mason 		struct btrfs_dir_item *di;
362ff7e61eSJeff Mahoney 		di = btrfs_match_dir_item_name(fs_info, path, name, name_len);
37e06afa83SChris Mason 		if (di)
38e06afa83SChris Mason 			return ERR_PTR(-EEXIST);
392ff7e61eSJeff Mahoney 		btrfs_extend_item(fs_info, path, data_size);
40143bede5SJeff Mahoney 	} else if (ret < 0)
4154aa1f4dSChris Mason 		return ERR_PTR(ret);
427e38180eSChris Mason 	WARN_ON(ret > 0);
435f39d397SChris Mason 	leaf = path->nodes[0];
44dd3cc16bSRoss Kirk 	item = btrfs_item_nr(path->slots[0]);
457e38180eSChris Mason 	ptr = btrfs_item_ptr(leaf, path->slots[0], char);
465f39d397SChris Mason 	BUG_ON(data_size > btrfs_item_size(leaf, item));
475f39d397SChris Mason 	ptr += btrfs_item_size(leaf, item) - data_size;
487e38180eSChris Mason 	return (struct btrfs_dir_item *)ptr;
497fcde0e3SChris Mason }
507fcde0e3SChris Mason 
51d352ac68SChris Mason /*
52d352ac68SChris Mason  * xattrs work a lot like directories, this inserts an xattr item
53d352ac68SChris Mason  * into the tree
54d352ac68SChris Mason  */
555103e947SJosef Bacik int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
56f34f57a3SYan, Zheng 			    struct btrfs_root *root,
57f34f57a3SYan, Zheng 			    struct btrfs_path *path, u64 objectid,
58f34f57a3SYan, Zheng 			    const char *name, u16 name_len,
59f34f57a3SYan, Zheng 			    const void *data, u16 data_len)
605103e947SJosef Bacik {
615103e947SJosef Bacik 	int ret = 0;
625103e947SJosef Bacik 	struct btrfs_dir_item *dir_item;
635103e947SJosef Bacik 	unsigned long name_ptr, data_ptr;
645103e947SJosef Bacik 	struct btrfs_key key, location;
655103e947SJosef Bacik 	struct btrfs_disk_key disk_key;
665103e947SJosef Bacik 	struct extent_buffer *leaf;
675103e947SJosef Bacik 	u32 data_size;
685103e947SJosef Bacik 
69b9d04c60SDavid Sterba 	if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(root->fs_info))
70b9d04c60SDavid Sterba 		return -ENOSPC;
71f34f57a3SYan, Zheng 
72f34f57a3SYan, Zheng 	key.objectid = objectid;
73962a298fSDavid Sterba 	key.type = BTRFS_XATTR_ITEM_KEY;
74df68b8a7SDavid Miller 	key.offset = btrfs_name_hash(name, name_len);
755103e947SJosef Bacik 
765103e947SJosef Bacik 	data_size = sizeof(*dir_item) + name_len + data_len;
775103e947SJosef Bacik 	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
785103e947SJosef Bacik 					name, name_len);
79fa09200bSJosef Bacik 	if (IS_ERR(dir_item))
80fa09200bSJosef Bacik 		return PTR_ERR(dir_item);
815103e947SJosef Bacik 	memset(&location, 0, sizeof(location));
825103e947SJosef Bacik 
835103e947SJosef Bacik 	leaf = path->nodes[0];
845103e947SJosef Bacik 	btrfs_cpu_key_to_disk(&disk_key, &location);
855103e947SJosef Bacik 	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
865103e947SJosef Bacik 	btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR);
875103e947SJosef Bacik 	btrfs_set_dir_name_len(leaf, dir_item, name_len);
88e02119d5SChris Mason 	btrfs_set_dir_transid(leaf, dir_item, trans->transid);
895103e947SJosef Bacik 	btrfs_set_dir_data_len(leaf, dir_item, data_len);
905103e947SJosef Bacik 	name_ptr = (unsigned long)(dir_item + 1);
915103e947SJosef Bacik 	data_ptr = (unsigned long)((char *)name_ptr + name_len);
925103e947SJosef Bacik 
935103e947SJosef Bacik 	write_extent_buffer(leaf, name, name_ptr, name_len);
945103e947SJosef Bacik 	write_extent_buffer(leaf, data, data_ptr, data_len);
955103e947SJosef Bacik 	btrfs_mark_buffer_dirty(path->nodes[0]);
965103e947SJosef Bacik 
975103e947SJosef Bacik 	return ret;
985103e947SJosef Bacik }
995103e947SJosef Bacik 
100d352ac68SChris Mason /*
101d352ac68SChris Mason  * insert a directory item in the tree, doing all the magic for
102d352ac68SChris Mason  * both indexes. 'dir' indicates which objectid to insert it into,
103d352ac68SChris Mason  * 'location' is the key to stuff into the directory item, 'type' is the
104d352ac68SChris Mason  * type of the inode we're pointing to, and 'index' is the sequence number
105d352ac68SChris Mason  * to use for the second index (if one is created).
10679787eaaSJeff Mahoney  * Will return 0 or -ENOMEM
107d352ac68SChris Mason  */
108e089f05cSChris Mason int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
10916cdcec7SMiao Xie 			  *root, const char *name, int name_len,
1108e7611cfSNikolay Borisov 			  struct btrfs_inode *dir, struct btrfs_key *location,
11116cdcec7SMiao Xie 			  u8 type, u64 index)
11262e2749eSChris Mason {
11362e2749eSChris Mason 	int ret = 0;
114e06afa83SChris Mason 	int ret2 = 0;
1155caf2a00SChris Mason 	struct btrfs_path *path;
11662e2749eSChris Mason 	struct btrfs_dir_item *dir_item;
1175f39d397SChris Mason 	struct extent_buffer *leaf;
1185f39d397SChris Mason 	unsigned long name_ptr;
11962e2749eSChris Mason 	struct btrfs_key key;
1205f39d397SChris Mason 	struct btrfs_disk_key disk_key;
12162e2749eSChris Mason 	u32 data_size;
12262e2749eSChris Mason 
1238e7611cfSNikolay Borisov 	key.objectid = btrfs_ino(dir);
124962a298fSDavid Sterba 	key.type = BTRFS_DIR_ITEM_KEY;
125df68b8a7SDavid Miller 	key.offset = btrfs_name_hash(name, name_len);
126b9473439SChris Mason 
1275caf2a00SChris Mason 	path = btrfs_alloc_path();
12816cdcec7SMiao Xie 	if (!path)
12916cdcec7SMiao Xie 		return -ENOMEM;
130b9473439SChris Mason 	path->leave_spinning = 1;
131b9473439SChris Mason 
13216cdcec7SMiao Xie 	btrfs_cpu_key_to_disk(&disk_key, location);
13316cdcec7SMiao Xie 
13462e2749eSChris Mason 	data_size = sizeof(*dir_item) + name_len;
135e06afa83SChris Mason 	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
136e06afa83SChris Mason 					name, name_len);
1377e38180eSChris Mason 	if (IS_ERR(dir_item)) {
1387e38180eSChris Mason 		ret = PTR_ERR(dir_item);
139e06afa83SChris Mason 		if (ret == -EEXIST)
140e06afa83SChris Mason 			goto second_insert;
141c2db1073STsutomu Itoh 		goto out_free;
1427e38180eSChris Mason 	}
14362e2749eSChris Mason 
1445f39d397SChris Mason 	leaf = path->nodes[0];
1455f39d397SChris Mason 	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
1465f39d397SChris Mason 	btrfs_set_dir_type(leaf, dir_item, type);
1475103e947SJosef Bacik 	btrfs_set_dir_data_len(leaf, dir_item, 0);
1485f39d397SChris Mason 	btrfs_set_dir_name_len(leaf, dir_item, name_len);
149e02119d5SChris Mason 	btrfs_set_dir_transid(leaf, dir_item, trans->transid);
1505f39d397SChris Mason 	name_ptr = (unsigned long)(dir_item + 1);
151c5739bbaSChris Mason 
1525f39d397SChris Mason 	write_extent_buffer(leaf, name, name_ptr, name_len);
1535f39d397SChris Mason 	btrfs_mark_buffer_dirty(leaf);
1547e38180eSChris Mason 
155e06afa83SChris Mason second_insert:
1567e38180eSChris Mason 	/* FIXME, use some real flag for selecting the extra index */
1577e38180eSChris Mason 	if (root == root->fs_info->tree_root) {
1587e38180eSChris Mason 		ret = 0;
159c2db1073STsutomu Itoh 		goto out_free;
1607e38180eSChris Mason 	}
161b3b4aa74SDavid Sterba 	btrfs_release_path(path);
1627e38180eSChris Mason 
1632ff7e61eSJeff Mahoney 	ret2 = btrfs_insert_delayed_dir_index(trans, root->fs_info, name,
1648e7611cfSNikolay Borisov 			name_len, dir, &disk_key, type, index);
165c2db1073STsutomu Itoh out_free:
1665caf2a00SChris Mason 	btrfs_free_path(path);
167e06afa83SChris Mason 	if (ret)
16862e2749eSChris Mason 		return ret;
169e06afa83SChris Mason 	if (ret2)
170e06afa83SChris Mason 		return ret2;
171e06afa83SChris Mason 	return 0;
17262e2749eSChris Mason }
17362e2749eSChris Mason 
174d352ac68SChris Mason /*
175d352ac68SChris Mason  * lookup a directory item based on name.  'dir' is the objectid
176d352ac68SChris Mason  * we're searching in, and 'mod' tells us if you plan on deleting the
177d352ac68SChris Mason  * item (use mod < 0) or changing the options (use mod > 0)
178d352ac68SChris Mason  */
1797e38180eSChris Mason struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
1807e38180eSChris Mason 					     struct btrfs_root *root,
1817e38180eSChris Mason 					     struct btrfs_path *path, u64 dir,
1827e38180eSChris Mason 					     const char *name, int name_len,
1837e38180eSChris Mason 					     int mod)
18462e2749eSChris Mason {
1851d4f6404SChris Mason 	int ret;
18662e2749eSChris Mason 	struct btrfs_key key;
1871d4f6404SChris Mason 	int ins_len = mod < 0 ? -1 : 0;
1881d4f6404SChris Mason 	int cow = mod != 0;
18962e2749eSChris Mason 
19062e2749eSChris Mason 	key.objectid = dir;
191962a298fSDavid Sterba 	key.type = BTRFS_DIR_ITEM_KEY;
1925f39d397SChris Mason 
193df68b8a7SDavid Miller 	key.offset = btrfs_name_hash(name, name_len);
1945f39d397SChris Mason 
195e089f05cSChris Mason 	ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
1967fcde0e3SChris Mason 	if (ret < 0)
1977e38180eSChris Mason 		return ERR_PTR(ret);
19885d85a74SLi Zefan 	if (ret > 0)
1997e38180eSChris Mason 		return NULL;
2007fcde0e3SChris Mason 
2012ff7e61eSJeff Mahoney 	return btrfs_match_dir_item_name(root->fs_info, path, name, name_len);
20262e2749eSChris Mason }
20362e2749eSChris Mason 
2049c52057cSChris Mason int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
2059c52057cSChris Mason 				   const char *name, int name_len)
2069c52057cSChris Mason {
2079c52057cSChris Mason 	int ret;
2089c52057cSChris Mason 	struct btrfs_key key;
2099c52057cSChris Mason 	struct btrfs_dir_item *di;
2109c52057cSChris Mason 	int data_size;
2119c52057cSChris Mason 	struct extent_buffer *leaf;
2129c52057cSChris Mason 	int slot;
2139c52057cSChris Mason 	struct btrfs_path *path;
2149c52057cSChris Mason 
2159c52057cSChris Mason 
2169c52057cSChris Mason 	path = btrfs_alloc_path();
2179c52057cSChris Mason 	if (!path)
2189c52057cSChris Mason 		return -ENOMEM;
2199c52057cSChris Mason 
2209c52057cSChris Mason 	key.objectid = dir;
221962a298fSDavid Sterba 	key.type = BTRFS_DIR_ITEM_KEY;
2229c52057cSChris Mason 	key.offset = btrfs_name_hash(name, name_len);
2239c52057cSChris Mason 
2249c52057cSChris Mason 	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
2259c52057cSChris Mason 
2269c52057cSChris Mason 	/* return back any errors */
2279c52057cSChris Mason 	if (ret < 0)
2289c52057cSChris Mason 		goto out;
2299c52057cSChris Mason 
2309c52057cSChris Mason 	/* nothing found, we're safe */
2319c52057cSChris Mason 	if (ret > 0) {
2329c52057cSChris Mason 		ret = 0;
2339c52057cSChris Mason 		goto out;
2349c52057cSChris Mason 	}
2359c52057cSChris Mason 
2369c52057cSChris Mason 	/* we found an item, look for our name in the item */
2372ff7e61eSJeff Mahoney 	di = btrfs_match_dir_item_name(root->fs_info, path, name, name_len);
2389c52057cSChris Mason 	if (di) {
2399c52057cSChris Mason 		/* our exact name was found */
2409c52057cSChris Mason 		ret = -EEXIST;
2419c52057cSChris Mason 		goto out;
2429c52057cSChris Mason 	}
2439c52057cSChris Mason 
2449c52057cSChris Mason 	/*
2459c52057cSChris Mason 	 * see if there is room in the item to insert this
2469c52057cSChris Mason 	 * name
2479c52057cSChris Mason 	 */
248878f2d2cSFilipe David Borba Manana 	data_size = sizeof(*di) + name_len;
2499c52057cSChris Mason 	leaf = path->nodes[0];
2509c52057cSChris Mason 	slot = path->slots[0];
2519c52057cSChris Mason 	if (data_size + btrfs_item_size_nr(leaf, slot) +
252da17066cSJeff Mahoney 	    sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root->fs_info)) {
2539c52057cSChris Mason 		ret = -EOVERFLOW;
2549c52057cSChris Mason 	} else {
2559c52057cSChris Mason 		/* plenty of insertion room */
2569c52057cSChris Mason 		ret = 0;
2579c52057cSChris Mason 	}
2589c52057cSChris Mason out:
2599c52057cSChris Mason 	btrfs_free_path(path);
2609c52057cSChris Mason 	return ret;
2619c52057cSChris Mason }
2629c52057cSChris Mason 
263d352ac68SChris Mason /*
264d352ac68SChris Mason  * lookup a directory item based on index.  'dir' is the objectid
265d352ac68SChris Mason  * we're searching in, and 'mod' tells us if you plan on deleting the
266d352ac68SChris Mason  * item (use mod < 0) or changing the options (use mod > 0)
267d352ac68SChris Mason  *
268d352ac68SChris Mason  * The name is used to make sure the index really points to the name you were
269d352ac68SChris Mason  * looking for.
270d352ac68SChris Mason  */
2717e38180eSChris Mason struct btrfs_dir_item *
2727e38180eSChris Mason btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
2737e38180eSChris Mason 			    struct btrfs_root *root,
2747e38180eSChris Mason 			    struct btrfs_path *path, u64 dir,
2757e38180eSChris Mason 			    u64 objectid, const char *name, int name_len,
2767e38180eSChris Mason 			    int mod)
2777e38180eSChris Mason {
2787e38180eSChris Mason 	int ret;
2797e38180eSChris Mason 	struct btrfs_key key;
2807e38180eSChris Mason 	int ins_len = mod < 0 ? -1 : 0;
2817e38180eSChris Mason 	int cow = mod != 0;
2827e38180eSChris Mason 
2837e38180eSChris Mason 	key.objectid = dir;
284962a298fSDavid Sterba 	key.type = BTRFS_DIR_INDEX_KEY;
2857e38180eSChris Mason 	key.offset = objectid;
2867e38180eSChris Mason 
2877e38180eSChris Mason 	ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
2887e38180eSChris Mason 	if (ret < 0)
2897e38180eSChris Mason 		return ERR_PTR(ret);
2907e38180eSChris Mason 	if (ret > 0)
2917e38180eSChris Mason 		return ERR_PTR(-ENOENT);
2922ff7e61eSJeff Mahoney 	return btrfs_match_dir_item_name(root->fs_info, path, name, name_len);
2937e38180eSChris Mason }
2947e38180eSChris Mason 
2954df27c4dSYan, Zheng struct btrfs_dir_item *
2964df27c4dSYan, Zheng btrfs_search_dir_index_item(struct btrfs_root *root,
2974df27c4dSYan, Zheng 			    struct btrfs_path *path, u64 dirid,
2984df27c4dSYan, Zheng 			    const char *name, int name_len)
2994df27c4dSYan, Zheng {
3004df27c4dSYan, Zheng 	struct extent_buffer *leaf;
3014df27c4dSYan, Zheng 	struct btrfs_dir_item *di;
3024df27c4dSYan, Zheng 	struct btrfs_key key;
3034df27c4dSYan, Zheng 	u32 nritems;
3044df27c4dSYan, Zheng 	int ret;
3054df27c4dSYan, Zheng 
3064df27c4dSYan, Zheng 	key.objectid = dirid;
3074df27c4dSYan, Zheng 	key.type = BTRFS_DIR_INDEX_KEY;
3084df27c4dSYan, Zheng 	key.offset = 0;
3094df27c4dSYan, Zheng 
3104df27c4dSYan, Zheng 	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
3114df27c4dSYan, Zheng 	if (ret < 0)
3124df27c4dSYan, Zheng 		return ERR_PTR(ret);
3134df27c4dSYan, Zheng 
3144df27c4dSYan, Zheng 	leaf = path->nodes[0];
3154df27c4dSYan, Zheng 	nritems = btrfs_header_nritems(leaf);
3164df27c4dSYan, Zheng 
3174df27c4dSYan, Zheng 	while (1) {
3184df27c4dSYan, Zheng 		if (path->slots[0] >= nritems) {
3194df27c4dSYan, Zheng 			ret = btrfs_next_leaf(root, path);
3204df27c4dSYan, Zheng 			if (ret < 0)
3214df27c4dSYan, Zheng 				return ERR_PTR(ret);
3224df27c4dSYan, Zheng 			if (ret > 0)
3234df27c4dSYan, Zheng 				break;
3244df27c4dSYan, Zheng 			leaf = path->nodes[0];
3254df27c4dSYan, Zheng 			nritems = btrfs_header_nritems(leaf);
3264df27c4dSYan, Zheng 			continue;
3274df27c4dSYan, Zheng 		}
3284df27c4dSYan, Zheng 
3294df27c4dSYan, Zheng 		btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
3304df27c4dSYan, Zheng 		if (key.objectid != dirid || key.type != BTRFS_DIR_INDEX_KEY)
3314df27c4dSYan, Zheng 			break;
3324df27c4dSYan, Zheng 
3332ff7e61eSJeff Mahoney 		di = btrfs_match_dir_item_name(root->fs_info, path,
3342ff7e61eSJeff Mahoney 					       name, name_len);
3354df27c4dSYan, Zheng 		if (di)
3364df27c4dSYan, Zheng 			return di;
3374df27c4dSYan, Zheng 
3384df27c4dSYan, Zheng 		path->slots[0]++;
3394df27c4dSYan, Zheng 	}
3404df27c4dSYan, Zheng 	return NULL;
3414df27c4dSYan, Zheng }
3424df27c4dSYan, Zheng 
3435103e947SJosef Bacik struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
3445103e947SJosef Bacik 					  struct btrfs_root *root,
3455103e947SJosef Bacik 					  struct btrfs_path *path, u64 dir,
3465103e947SJosef Bacik 					  const char *name, u16 name_len,
3475103e947SJosef Bacik 					  int mod)
3485103e947SJosef Bacik {
3495103e947SJosef Bacik 	int ret;
3505103e947SJosef Bacik 	struct btrfs_key key;
3515103e947SJosef Bacik 	int ins_len = mod < 0 ? -1 : 0;
3525103e947SJosef Bacik 	int cow = mod != 0;
3535103e947SJosef Bacik 
3545103e947SJosef Bacik 	key.objectid = dir;
355962a298fSDavid Sterba 	key.type = BTRFS_XATTR_ITEM_KEY;
356df68b8a7SDavid Miller 	key.offset = btrfs_name_hash(name, name_len);
3575103e947SJosef Bacik 	ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
3585103e947SJosef Bacik 	if (ret < 0)
3595103e947SJosef Bacik 		return ERR_PTR(ret);
36085d85a74SLi Zefan 	if (ret > 0)
3615103e947SJosef Bacik 		return NULL;
3625103e947SJosef Bacik 
3632ff7e61eSJeff Mahoney 	return btrfs_match_dir_item_name(root->fs_info, path, name, name_len);
3645103e947SJosef Bacik }
3655103e947SJosef Bacik 
366d352ac68SChris Mason /*
367d352ac68SChris Mason  * helper function to look at the directory item pointed to by 'path'
368d352ac68SChris Mason  * this walks through all the entries in a dir item and finds one
369d352ac68SChris Mason  * for a specific name.
370d352ac68SChris Mason  */
3712ff7e61eSJeff Mahoney struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info,
3727f5c1516SChris Mason 						 struct btrfs_path *path,
3737f5c1516SChris Mason 						 const char *name, int name_len)
37462e2749eSChris Mason {
37562e2749eSChris Mason 	struct btrfs_dir_item *dir_item;
3765f39d397SChris Mason 	unsigned long name_ptr;
3777e38180eSChris Mason 	u32 total_len;
3787e38180eSChris Mason 	u32 cur = 0;
3797e38180eSChris Mason 	u32 this_len;
3805f39d397SChris Mason 	struct extent_buffer *leaf;
381a8a2ee0cSChris Mason 
3825f39d397SChris Mason 	leaf = path->nodes[0];
3837e38180eSChris Mason 	dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
38422a94d44SJosef Bacik 
3855f39d397SChris Mason 	total_len = btrfs_item_size_nr(leaf, path->slots[0]);
3867e38180eSChris Mason 	while (cur < total_len) {
3875f39d397SChris Mason 		this_len = sizeof(*dir_item) +
3885103e947SJosef Bacik 			btrfs_dir_name_len(leaf, dir_item) +
3895103e947SJosef Bacik 			btrfs_dir_data_len(leaf, dir_item);
3905f39d397SChris Mason 		name_ptr = (unsigned long)(dir_item + 1);
3917e38180eSChris Mason 
3925f39d397SChris Mason 		if (btrfs_dir_name_len(leaf, dir_item) == name_len &&
3935f39d397SChris Mason 		    memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
3947e38180eSChris Mason 			return dir_item;
3957e38180eSChris Mason 
3967e38180eSChris Mason 		cur += this_len;
3977e38180eSChris Mason 		dir_item = (struct btrfs_dir_item *)((char *)dir_item +
3987e38180eSChris Mason 						     this_len);
39962e2749eSChris Mason 	}
4007e38180eSChris Mason 	return NULL;
4017e38180eSChris Mason }
4027e38180eSChris Mason 
403d352ac68SChris Mason /*
404d352ac68SChris Mason  * given a pointer into a directory item, delete it.  This
405d352ac68SChris Mason  * handles items that have more than one entry in them.
406d352ac68SChris Mason  */
4077e38180eSChris Mason int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
4087e38180eSChris Mason 			      struct btrfs_root *root,
4097e38180eSChris Mason 			      struct btrfs_path *path,
4107e38180eSChris Mason 			      struct btrfs_dir_item *di)
4117e38180eSChris Mason {
4127e38180eSChris Mason 
4135f39d397SChris Mason 	struct extent_buffer *leaf;
4147e38180eSChris Mason 	u32 sub_item_len;
4157e38180eSChris Mason 	u32 item_len;
41654aa1f4dSChris Mason 	int ret = 0;
4177e38180eSChris Mason 
4185f39d397SChris Mason 	leaf = path->nodes[0];
4195103e947SJosef Bacik 	sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) +
4205103e947SJosef Bacik 		btrfs_dir_data_len(leaf, di);
4215f39d397SChris Mason 	item_len = btrfs_item_size_nr(leaf, path->slots[0]);
4225f39d397SChris Mason 	if (sub_item_len == item_len) {
4237e38180eSChris Mason 		ret = btrfs_del_item(trans, root, path);
4247e38180eSChris Mason 	} else {
4255f39d397SChris Mason 		/* MARKER */
4265f39d397SChris Mason 		unsigned long ptr = (unsigned long)di;
4275f39d397SChris Mason 		unsigned long start;
4285f39d397SChris Mason 
4295f39d397SChris Mason 		start = btrfs_item_ptr_offset(leaf, path->slots[0]);
4305f39d397SChris Mason 		memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
4317e38180eSChris Mason 			item_len - (ptr + sub_item_len - start));
4322ff7e61eSJeff Mahoney 		btrfs_truncate_item(root->fs_info, path,
4332ff7e61eSJeff Mahoney 				    item_len - sub_item_len, 1);
4347e38180eSChris Mason 	}
435411fc6bcSAndi Kleen 	return ret;
4367e38180eSChris Mason }
437