xref: /openbmc/linux/fs/btrfs/dir-item.c (revision 94a48aef)
1c1d7c514SDavid Sterba // SPDX-License-Identifier: GPL-2.0
26cbd5570SChris Mason /*
36cbd5570SChris Mason  * Copyright (C) 2007 Oracle.  All rights reserved.
46cbd5570SChris Mason  */
56cbd5570SChris Mason 
69b569ea0SJosef Bacik #include "messages.h"
762e2749eSChris Mason #include "ctree.h"
862e2749eSChris Mason #include "disk-io.h"
9e089f05cSChris Mason #include "transaction.h"
1007e81dc9SJosef Bacik #include "accessors.h"
1162e2749eSChris Mason 
12d352ac68SChris Mason /*
13d352ac68SChris Mason  * insert a name into a directory, doing overflow properly if there is a hash
14d352ac68SChris Mason  * collision.  data_size indicates how big the item inserted should be.  On
15d352ac68SChris Mason  * success a struct btrfs_dir_item pointer is returned, otherwise it is
16d352ac68SChris Mason  * an ERR_PTR.
17d352ac68SChris Mason  *
18d352ac68SChris Mason  * The name is not copied into the dir item, you have to do that yourself.
19d352ac68SChris Mason  */
2035b7e476SChris Mason static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
2135b7e476SChris Mason 						   *trans,
227e38180eSChris Mason 						   struct btrfs_root *root,
237e38180eSChris Mason 						   struct btrfs_path *path,
247e38180eSChris Mason 						   struct btrfs_key *cpu_key,
25e06afa83SChris Mason 						   u32 data_size,
26e06afa83SChris Mason 						   const char *name,
27e06afa83SChris Mason 						   int name_len)
287fcde0e3SChris Mason {
292ff7e61eSJeff Mahoney 	struct btrfs_fs_info *fs_info = root->fs_info;
307fcde0e3SChris Mason 	int ret;
317e38180eSChris Mason 	char *ptr;
325f39d397SChris Mason 	struct extent_buffer *leaf;
337fcde0e3SChris Mason 
347fcde0e3SChris Mason 	ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
357e38180eSChris Mason 	if (ret == -EEXIST) {
36e06afa83SChris Mason 		struct btrfs_dir_item *di;
372ff7e61eSJeff Mahoney 		di = btrfs_match_dir_item_name(fs_info, path, name, name_len);
38e06afa83SChris Mason 		if (di)
39e06afa83SChris Mason 			return ERR_PTR(-EEXIST);
40c71dd880SDavid Sterba 		btrfs_extend_item(path, data_size);
41143bede5SJeff Mahoney 	} else if (ret < 0)
4254aa1f4dSChris Mason 		return ERR_PTR(ret);
437e38180eSChris Mason 	WARN_ON(ret > 0);
445f39d397SChris Mason 	leaf = path->nodes[0];
457e38180eSChris Mason 	ptr = btrfs_item_ptr(leaf, path->slots[0], char);
463212fa14SJosef Bacik 	ASSERT(data_size <= btrfs_item_size(leaf, path->slots[0]));
473212fa14SJosef Bacik 	ptr += btrfs_item_size(leaf, path->slots[0]) - 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);
86*94a48aefSOmar Sandoval 	btrfs_set_dir_flags(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  */
108e43eec81SSweet Tea Dorminy int btrfs_insert_dir_item(struct btrfs_trans_handle *trans,
1096db75318SSweet Tea Dorminy 			  const struct fscrypt_str *name, struct btrfs_inode *dir,
110684572dfSLu Fengqi 			  struct btrfs_key *location, u8 type, u64 index)
11162e2749eSChris Mason {
11262e2749eSChris Mason 	int ret = 0;
113e06afa83SChris Mason 	int ret2 = 0;
114684572dfSLu Fengqi 	struct btrfs_root *root = dir->root;
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;
125e43eec81SSweet Tea Dorminy 	key.offset = btrfs_name_hash(name->name, name->len);
126b9473439SChris Mason 
1275caf2a00SChris Mason 	path = btrfs_alloc_path();
12816cdcec7SMiao Xie 	if (!path)
12916cdcec7SMiao Xie 		return -ENOMEM;
130b9473439SChris Mason 
13116cdcec7SMiao Xie 	btrfs_cpu_key_to_disk(&disk_key, location);
13216cdcec7SMiao Xie 
133e43eec81SSweet Tea Dorminy 	data_size = sizeof(*dir_item) + name->len;
134e06afa83SChris Mason 	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
135e43eec81SSweet Tea Dorminy 					name->name, name->len);
1367e38180eSChris Mason 	if (IS_ERR(dir_item)) {
1377e38180eSChris Mason 		ret = PTR_ERR(dir_item);
138e06afa83SChris Mason 		if (ret == -EEXIST)
139e06afa83SChris Mason 			goto second_insert;
140c2db1073STsutomu Itoh 		goto out_free;
1417e38180eSChris Mason 	}
14262e2749eSChris Mason 
143*94a48aefSOmar Sandoval 	if (IS_ENCRYPTED(&dir->vfs_inode))
144*94a48aefSOmar Sandoval 		type |= BTRFS_FT_ENCRYPTED;
145*94a48aefSOmar Sandoval 
1465f39d397SChris Mason 	leaf = path->nodes[0];
1475f39d397SChris Mason 	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
148*94a48aefSOmar Sandoval 	btrfs_set_dir_flags(leaf, dir_item, type);
1495103e947SJosef Bacik 	btrfs_set_dir_data_len(leaf, dir_item, 0);
150e43eec81SSweet Tea Dorminy 	btrfs_set_dir_name_len(leaf, dir_item, name->len);
151e02119d5SChris Mason 	btrfs_set_dir_transid(leaf, dir_item, trans->transid);
1525f39d397SChris Mason 	name_ptr = (unsigned long)(dir_item + 1);
153c5739bbaSChris Mason 
154e43eec81SSweet Tea Dorminy 	write_extent_buffer(leaf, name->name, name_ptr, name->len);
1555f39d397SChris Mason 	btrfs_mark_buffer_dirty(leaf);
1567e38180eSChris Mason 
157e06afa83SChris Mason second_insert:
1587e38180eSChris Mason 	/* FIXME, use some real flag for selecting the extra index */
1597e38180eSChris Mason 	if (root == root->fs_info->tree_root) {
1607e38180eSChris Mason 		ret = 0;
161c2db1073STsutomu Itoh 		goto out_free;
1627e38180eSChris Mason 	}
163b3b4aa74SDavid Sterba 	btrfs_release_path(path);
1647e38180eSChris Mason 
165e43eec81SSweet Tea Dorminy 	ret2 = btrfs_insert_delayed_dir_index(trans, name->name, name->len, dir,
1664465c8b4SLu Fengqi 					      &disk_key, type, index);
167c2db1073STsutomu Itoh out_free:
1685caf2a00SChris Mason 	btrfs_free_path(path);
169e06afa83SChris Mason 	if (ret)
17062e2749eSChris Mason 		return ret;
171e06afa83SChris Mason 	if (ret2)
172e06afa83SChris Mason 		return ret2;
173e06afa83SChris Mason 	return 0;
17462e2749eSChris Mason }
17562e2749eSChris Mason 
176a7d1c5dcSMarcos Paulo de Souza static struct btrfs_dir_item *btrfs_lookup_match_dir(
177a7d1c5dcSMarcos Paulo de Souza 			struct btrfs_trans_handle *trans,
178a7d1c5dcSMarcos Paulo de Souza 			struct btrfs_root *root, struct btrfs_path *path,
179a7d1c5dcSMarcos Paulo de Souza 			struct btrfs_key *key, const char *name,
180a7d1c5dcSMarcos Paulo de Souza 			int name_len, int mod)
181a7d1c5dcSMarcos Paulo de Souza {
182a7d1c5dcSMarcos Paulo de Souza 	const int ins_len = (mod < 0 ? -1 : 0);
183a7d1c5dcSMarcos Paulo de Souza 	const int cow = (mod != 0);
184a7d1c5dcSMarcos Paulo de Souza 	int ret;
185a7d1c5dcSMarcos Paulo de Souza 
186a7d1c5dcSMarcos Paulo de Souza 	ret = btrfs_search_slot(trans, root, key, path, ins_len, cow);
187a7d1c5dcSMarcos Paulo de Souza 	if (ret < 0)
188a7d1c5dcSMarcos Paulo de Souza 		return ERR_PTR(ret);
189a7d1c5dcSMarcos Paulo de Souza 	if (ret > 0)
190a7d1c5dcSMarcos Paulo de Souza 		return ERR_PTR(-ENOENT);
191a7d1c5dcSMarcos Paulo de Souza 
192a7d1c5dcSMarcos Paulo de Souza 	return btrfs_match_dir_item_name(root->fs_info, path, name, name_len);
193a7d1c5dcSMarcos Paulo de Souza }
194a7d1c5dcSMarcos Paulo de Souza 
195d352ac68SChris Mason /*
1968dcbc261SFilipe Manana  * Lookup for a directory item by name.
1978dcbc261SFilipe Manana  *
1988dcbc261SFilipe Manana  * @trans:	The transaction handle to use. Can be NULL if @mod is 0.
1998dcbc261SFilipe Manana  * @root:	The root of the target tree.
2008dcbc261SFilipe Manana  * @path:	Path to use for the search.
2018dcbc261SFilipe Manana  * @dir:	The inode number (objectid) of the directory.
2028dcbc261SFilipe Manana  * @name:	The name associated to the directory entry we are looking for.
2038dcbc261SFilipe Manana  * @name_len:	The length of the name.
2048dcbc261SFilipe Manana  * @mod:	Used to indicate if the tree search is meant for a read only
2058dcbc261SFilipe Manana  *		lookup, for a modification lookup or for a deletion lookup, so
2068dcbc261SFilipe Manana  *		its value should be 0, 1 or -1, respectively.
2078dcbc261SFilipe Manana  *
2088dcbc261SFilipe Manana  * Returns: NULL if the dir item does not exists, an error pointer if an error
2098dcbc261SFilipe Manana  * happened, or a pointer to a dir item if a dir item exists for the given name.
210d352ac68SChris Mason  */
2117e38180eSChris Mason struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
2127e38180eSChris Mason 					     struct btrfs_root *root,
2137e38180eSChris Mason 					     struct btrfs_path *path, u64 dir,
2146db75318SSweet Tea Dorminy 					     const struct fscrypt_str *name,
2157e38180eSChris Mason 					     int mod)
21662e2749eSChris Mason {
21762e2749eSChris Mason 	struct btrfs_key key;
218a7d1c5dcSMarcos Paulo de Souza 	struct btrfs_dir_item *di;
21962e2749eSChris Mason 
22062e2749eSChris Mason 	key.objectid = dir;
221962a298fSDavid Sterba 	key.type = BTRFS_DIR_ITEM_KEY;
222e43eec81SSweet Tea Dorminy 	key.offset = btrfs_name_hash(name->name, name->len);
2235f39d397SChris Mason 
224e43eec81SSweet Tea Dorminy 	di = btrfs_lookup_match_dir(trans, root, path, &key, name->name,
225e43eec81SSweet Tea Dorminy 				    name->len, mod);
226a7d1c5dcSMarcos Paulo de Souza 	if (IS_ERR(di) && PTR_ERR(di) == -ENOENT)
2277e38180eSChris Mason 		return NULL;
2287fcde0e3SChris Mason 
229a7d1c5dcSMarcos Paulo de Souza 	return di;
23062e2749eSChris Mason }
23162e2749eSChris Mason 
2329c52057cSChris Mason int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
2336db75318SSweet Tea Dorminy 				   const struct fscrypt_str *name)
2349c52057cSChris Mason {
2359c52057cSChris Mason 	int ret;
2369c52057cSChris Mason 	struct btrfs_key key;
2379c52057cSChris Mason 	struct btrfs_dir_item *di;
2389c52057cSChris Mason 	int data_size;
2399c52057cSChris Mason 	struct extent_buffer *leaf;
2409c52057cSChris Mason 	int slot;
2419c52057cSChris Mason 	struct btrfs_path *path;
2429c52057cSChris Mason 
2439c52057cSChris Mason 	path = btrfs_alloc_path();
2449c52057cSChris Mason 	if (!path)
2459c52057cSChris Mason 		return -ENOMEM;
2469c52057cSChris Mason 
2479c52057cSChris Mason 	key.objectid = dir;
248962a298fSDavid Sterba 	key.type = BTRFS_DIR_ITEM_KEY;
249e43eec81SSweet Tea Dorminy 	key.offset = btrfs_name_hash(name->name, name->len);
2509c52057cSChris Mason 
251e43eec81SSweet Tea Dorminy 	di = btrfs_lookup_match_dir(NULL, root, path, &key, name->name,
252e43eec81SSweet Tea Dorminy 				    name->len, 0);
253a7d1c5dcSMarcos Paulo de Souza 	if (IS_ERR(di)) {
254a7d1c5dcSMarcos Paulo de Souza 		ret = PTR_ERR(di);
255a7d1c5dcSMarcos Paulo de Souza 		/* Nothing found, we're safe */
256a7d1c5dcSMarcos Paulo de Souza 		if (ret == -ENOENT) {
2579c52057cSChris Mason 			ret = 0;
2589c52057cSChris Mason 			goto out;
2599c52057cSChris Mason 		}
2609c52057cSChris Mason 
261a7d1c5dcSMarcos Paulo de Souza 		if (ret < 0)
262a7d1c5dcSMarcos Paulo de Souza 			goto out;
263a7d1c5dcSMarcos Paulo de Souza 	}
264a7d1c5dcSMarcos Paulo de Souza 
2659c52057cSChris Mason 	/* we found an item, look for our name in the item */
2669c52057cSChris Mason 	if (di) {
2679c52057cSChris Mason 		/* our exact name was found */
2689c52057cSChris Mason 		ret = -EEXIST;
2699c52057cSChris Mason 		goto out;
2709c52057cSChris Mason 	}
2719c52057cSChris Mason 
272e43eec81SSweet Tea Dorminy 	/* See if there is room in the item to insert this name. */
273e43eec81SSweet Tea Dorminy 	data_size = sizeof(*di) + name->len;
2749c52057cSChris Mason 	leaf = path->nodes[0];
2759c52057cSChris Mason 	slot = path->slots[0];
2763212fa14SJosef Bacik 	if (data_size + btrfs_item_size(leaf, slot) +
277da17066cSJeff Mahoney 	    sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root->fs_info)) {
2789c52057cSChris Mason 		ret = -EOVERFLOW;
2799c52057cSChris Mason 	} else {
2809c52057cSChris Mason 		/* plenty of insertion room */
2819c52057cSChris Mason 		ret = 0;
2829c52057cSChris Mason 	}
2839c52057cSChris Mason out:
2849c52057cSChris Mason 	btrfs_free_path(path);
2859c52057cSChris Mason 	return ret;
2869c52057cSChris Mason }
2879c52057cSChris Mason 
288d352ac68SChris Mason /*
2898dcbc261SFilipe Manana  * Lookup for a directory index item by name and index number.
290d352ac68SChris Mason  *
2918dcbc261SFilipe Manana  * @trans:	The transaction handle to use. Can be NULL if @mod is 0.
2928dcbc261SFilipe Manana  * @root:	The root of the target tree.
2938dcbc261SFilipe Manana  * @path:	Path to use for the search.
2948dcbc261SFilipe Manana  * @dir:	The inode number (objectid) of the directory.
2958dcbc261SFilipe Manana  * @index:	The index number.
2968dcbc261SFilipe Manana  * @name:	The name associated to the directory entry we are looking for.
2978dcbc261SFilipe Manana  * @name_len:	The length of the name.
2988dcbc261SFilipe Manana  * @mod:	Used to indicate if the tree search is meant for a read only
2998dcbc261SFilipe Manana  *		lookup, for a modification lookup or for a deletion lookup, so
3008dcbc261SFilipe Manana  *		its value should be 0, 1 or -1, respectively.
3018dcbc261SFilipe Manana  *
3028dcbc261SFilipe Manana  * Returns: NULL if the dir index item does not exists, an error pointer if an
3038dcbc261SFilipe Manana  * error happened, or a pointer to a dir item if the dir index item exists and
3048dcbc261SFilipe Manana  * matches the criteria (name and index number).
305d352ac68SChris Mason  */
3067e38180eSChris Mason struct btrfs_dir_item *
3077e38180eSChris Mason btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
3087e38180eSChris Mason 			    struct btrfs_root *root,
3097e38180eSChris Mason 			    struct btrfs_path *path, u64 dir,
3106db75318SSweet Tea Dorminy 			    u64 index, const struct fscrypt_str *name, int mod)
3117e38180eSChris Mason {
3128dcbc261SFilipe Manana 	struct btrfs_dir_item *di;
3137e38180eSChris Mason 	struct btrfs_key key;
3147e38180eSChris Mason 
3157e38180eSChris Mason 	key.objectid = dir;
316962a298fSDavid Sterba 	key.type = BTRFS_DIR_INDEX_KEY;
3178dcbc261SFilipe Manana 	key.offset = index;
3187e38180eSChris Mason 
319e43eec81SSweet Tea Dorminy 	di = btrfs_lookup_match_dir(trans, root, path, &key, name->name,
320e43eec81SSweet Tea Dorminy 				    name->len, mod);
3218dcbc261SFilipe Manana 	if (di == ERR_PTR(-ENOENT))
3228dcbc261SFilipe Manana 		return NULL;
3238dcbc261SFilipe Manana 
3248dcbc261SFilipe Manana 	return di;
3257e38180eSChris Mason }
3267e38180eSChris Mason 
3274df27c4dSYan, Zheng struct btrfs_dir_item *
328e43eec81SSweet Tea Dorminy btrfs_search_dir_index_item(struct btrfs_root *root, struct btrfs_path *path,
3296db75318SSweet Tea Dorminy 			    u64 dirid, const struct fscrypt_str *name)
3304df27c4dSYan, Zheng {
3314df27c4dSYan, Zheng 	struct btrfs_dir_item *di;
3324df27c4dSYan, Zheng 	struct btrfs_key key;
3334df27c4dSYan, Zheng 	int ret;
3344df27c4dSYan, Zheng 
3354df27c4dSYan, Zheng 	key.objectid = dirid;
3364df27c4dSYan, Zheng 	key.type = BTRFS_DIR_INDEX_KEY;
3374df27c4dSYan, Zheng 	key.offset = 0;
3384df27c4dSYan, Zheng 
3399dcbe16fSGabriel Niebler 	btrfs_for_each_slot(root, &key, &key, path, ret) {
3404df27c4dSYan, Zheng 		if (key.objectid != dirid || key.type != BTRFS_DIR_INDEX_KEY)
3414df27c4dSYan, Zheng 			break;
3424df27c4dSYan, Zheng 
3432ff7e61eSJeff Mahoney 		di = btrfs_match_dir_item_name(root->fs_info, path,
344e43eec81SSweet Tea Dorminy 					       name->name, name->len);
3454df27c4dSYan, Zheng 		if (di)
3464df27c4dSYan, Zheng 			return di;
3474df27c4dSYan, Zheng 	}
3489dcbe16fSGabriel Niebler 	/* Adjust return code if the key was not found in the next leaf. */
3499dcbe16fSGabriel Niebler 	if (ret > 0)
3509dcbe16fSGabriel Niebler 		ret = 0;
3519dcbe16fSGabriel Niebler 
3529dcbe16fSGabriel Niebler 	return ERR_PTR(ret);
3534df27c4dSYan, Zheng }
3544df27c4dSYan, Zheng 
3555103e947SJosef Bacik struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
3565103e947SJosef Bacik 					  struct btrfs_root *root,
3575103e947SJosef Bacik 					  struct btrfs_path *path, u64 dir,
3585103e947SJosef Bacik 					  const char *name, u16 name_len,
3595103e947SJosef Bacik 					  int mod)
3605103e947SJosef Bacik {
3615103e947SJosef Bacik 	struct btrfs_key key;
362a7d1c5dcSMarcos Paulo de Souza 	struct btrfs_dir_item *di;
3635103e947SJosef Bacik 
3645103e947SJosef Bacik 	key.objectid = dir;
365962a298fSDavid Sterba 	key.type = BTRFS_XATTR_ITEM_KEY;
366df68b8a7SDavid Miller 	key.offset = btrfs_name_hash(name, name_len);
367a7d1c5dcSMarcos Paulo de Souza 
368a7d1c5dcSMarcos Paulo de Souza 	di = btrfs_lookup_match_dir(trans, root, path, &key, name, name_len, mod);
369a7d1c5dcSMarcos Paulo de Souza 	if (IS_ERR(di) && PTR_ERR(di) == -ENOENT)
3705103e947SJosef Bacik 		return NULL;
3715103e947SJosef Bacik 
372a7d1c5dcSMarcos Paulo de Souza 	return di;
3735103e947SJosef Bacik }
3745103e947SJosef Bacik 
375d352ac68SChris Mason /*
376d352ac68SChris Mason  * helper function to look at the directory item pointed to by 'path'
377d352ac68SChris Mason  * this walks through all the entries in a dir item and finds one
378d352ac68SChris Mason  * for a specific name.
379d352ac68SChris Mason  */
3802ff7e61eSJeff Mahoney struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_fs_info *fs_info,
3817f5c1516SChris Mason 						 struct btrfs_path *path,
3827f5c1516SChris Mason 						 const char *name, int name_len)
38362e2749eSChris Mason {
38462e2749eSChris Mason 	struct btrfs_dir_item *dir_item;
3855f39d397SChris Mason 	unsigned long name_ptr;
3867e38180eSChris Mason 	u32 total_len;
3877e38180eSChris Mason 	u32 cur = 0;
3887e38180eSChris Mason 	u32 this_len;
3895f39d397SChris Mason 	struct extent_buffer *leaf;
390a8a2ee0cSChris Mason 
3915f39d397SChris Mason 	leaf = path->nodes[0];
3927e38180eSChris Mason 	dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
39322a94d44SJosef Bacik 
3943212fa14SJosef Bacik 	total_len = btrfs_item_size(leaf, path->slots[0]);
3957e38180eSChris Mason 	while (cur < total_len) {
3965f39d397SChris Mason 		this_len = sizeof(*dir_item) +
3975103e947SJosef Bacik 			btrfs_dir_name_len(leaf, dir_item) +
3985103e947SJosef Bacik 			btrfs_dir_data_len(leaf, dir_item);
3995f39d397SChris Mason 		name_ptr = (unsigned long)(dir_item + 1);
4007e38180eSChris Mason 
4015f39d397SChris Mason 		if (btrfs_dir_name_len(leaf, dir_item) == name_len &&
4025f39d397SChris Mason 		    memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
4037e38180eSChris Mason 			return dir_item;
4047e38180eSChris Mason 
4057e38180eSChris Mason 		cur += this_len;
4067e38180eSChris Mason 		dir_item = (struct btrfs_dir_item *)((char *)dir_item +
4077e38180eSChris Mason 						     this_len);
40862e2749eSChris Mason 	}
4097e38180eSChris Mason 	return NULL;
4107e38180eSChris Mason }
4117e38180eSChris Mason 
412d352ac68SChris Mason /*
413d352ac68SChris Mason  * given a pointer into a directory item, delete it.  This
414d352ac68SChris Mason  * handles items that have more than one entry in them.
415d352ac68SChris Mason  */
4167e38180eSChris Mason int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
4177e38180eSChris Mason 			      struct btrfs_root *root,
4187e38180eSChris Mason 			      struct btrfs_path *path,
4197e38180eSChris Mason 			      struct btrfs_dir_item *di)
4207e38180eSChris Mason {
4217e38180eSChris Mason 
4225f39d397SChris Mason 	struct extent_buffer *leaf;
4237e38180eSChris Mason 	u32 sub_item_len;
4247e38180eSChris Mason 	u32 item_len;
42554aa1f4dSChris Mason 	int ret = 0;
4267e38180eSChris Mason 
4275f39d397SChris Mason 	leaf = path->nodes[0];
4285103e947SJosef Bacik 	sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) +
4295103e947SJosef Bacik 		btrfs_dir_data_len(leaf, di);
4303212fa14SJosef Bacik 	item_len = btrfs_item_size(leaf, path->slots[0]);
4315f39d397SChris Mason 	if (sub_item_len == item_len) {
4327e38180eSChris Mason 		ret = btrfs_del_item(trans, root, path);
4337e38180eSChris Mason 	} else {
4345f39d397SChris Mason 		/* MARKER */
4355f39d397SChris Mason 		unsigned long ptr = (unsigned long)di;
4365f39d397SChris Mason 		unsigned long start;
4375f39d397SChris Mason 
4385f39d397SChris Mason 		start = btrfs_item_ptr_offset(leaf, path->slots[0]);
4395f39d397SChris Mason 		memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
4407e38180eSChris Mason 			item_len - (ptr + sub_item_len - start));
44178ac4f9eSDavid Sterba 		btrfs_truncate_item(path, item_len - sub_item_len, 1);
4427e38180eSChris Mason 	}
443411fc6bcSAndi Kleen 	return ret;
4447e38180eSChris Mason }
445