xref: /openbmc/linux/fs/btrfs/dir-item.c (revision fa09200b)
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 
24d352ac68SChris Mason /*
25d352ac68SChris Mason  * insert a name into a directory, doing overflow properly if there is a hash
26d352ac68SChris Mason  * collision.  data_size indicates how big the item inserted should be.  On
27d352ac68SChris Mason  * success a struct btrfs_dir_item pointer is returned, otherwise it is
28d352ac68SChris Mason  * an ERR_PTR.
29d352ac68SChris Mason  *
30d352ac68SChris Mason  * The name is not copied into the dir item, you have to do that yourself.
31d352ac68SChris Mason  */
3235b7e476SChris Mason static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
3335b7e476SChris Mason 						   *trans,
347e38180eSChris Mason 						   struct btrfs_root *root,
357e38180eSChris Mason 						   struct btrfs_path *path,
367e38180eSChris Mason 						   struct btrfs_key *cpu_key,
37e06afa83SChris Mason 						   u32 data_size,
38e06afa83SChris Mason 						   const char *name,
39e06afa83SChris Mason 						   int name_len)
407fcde0e3SChris Mason {
417fcde0e3SChris Mason 	int ret;
427e38180eSChris Mason 	char *ptr;
437e38180eSChris Mason 	struct btrfs_item *item;
445f39d397SChris Mason 	struct extent_buffer *leaf;
457fcde0e3SChris Mason 
467fcde0e3SChris Mason 	ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
477e38180eSChris Mason 	if (ret == -EEXIST) {
48e06afa83SChris Mason 		struct btrfs_dir_item *di;
49e06afa83SChris Mason 		di = btrfs_match_dir_item_name(root, path, name, name_len);
50e06afa83SChris Mason 		if (di)
51e06afa83SChris Mason 			return ERR_PTR(-EEXIST);
527e38180eSChris Mason 		ret = btrfs_extend_item(trans, root, path, data_size);
537fcde0e3SChris Mason 	}
5454aa1f4dSChris Mason 	if (ret < 0)
5554aa1f4dSChris Mason 		return ERR_PTR(ret);
567e38180eSChris Mason 	WARN_ON(ret > 0);
575f39d397SChris Mason 	leaf = path->nodes[0];
585f39d397SChris Mason 	item = btrfs_item_nr(leaf, path->slots[0]);
597e38180eSChris Mason 	ptr = btrfs_item_ptr(leaf, path->slots[0], char);
605f39d397SChris Mason 	BUG_ON(data_size > btrfs_item_size(leaf, item));
615f39d397SChris Mason 	ptr += btrfs_item_size(leaf, item) - data_size;
627e38180eSChris Mason 	return (struct btrfs_dir_item *)ptr;
637fcde0e3SChris Mason }
647fcde0e3SChris Mason 
65d352ac68SChris Mason /*
66d352ac68SChris Mason  * xattrs work a lot like directories, this inserts an xattr item
67d352ac68SChris Mason  * into the tree
68d352ac68SChris Mason  */
695103e947SJosef Bacik int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
70f34f57a3SYan, Zheng 			    struct btrfs_root *root,
71f34f57a3SYan, Zheng 			    struct btrfs_path *path, u64 objectid,
72f34f57a3SYan, Zheng 			    const char *name, u16 name_len,
73f34f57a3SYan, Zheng 			    const void *data, u16 data_len)
745103e947SJosef Bacik {
755103e947SJosef Bacik 	int ret = 0;
765103e947SJosef Bacik 	struct btrfs_dir_item *dir_item;
775103e947SJosef Bacik 	unsigned long name_ptr, data_ptr;
785103e947SJosef Bacik 	struct btrfs_key key, location;
795103e947SJosef Bacik 	struct btrfs_disk_key disk_key;
805103e947SJosef Bacik 	struct extent_buffer *leaf;
815103e947SJosef Bacik 	u32 data_size;
825103e947SJosef Bacik 
83f34f57a3SYan, Zheng 	BUG_ON(name_len + data_len > BTRFS_MAX_XATTR_SIZE(root));
84f34f57a3SYan, Zheng 
85f34f57a3SYan, Zheng 	key.objectid = objectid;
865103e947SJosef Bacik 	btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
87df68b8a7SDavid Miller 	key.offset = btrfs_name_hash(name, name_len);
885103e947SJosef Bacik 
895103e947SJosef Bacik 	data_size = sizeof(*dir_item) + name_len + data_len;
905103e947SJosef Bacik 	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
915103e947SJosef Bacik 					name, name_len);
92fa09200bSJosef Bacik 	if (IS_ERR(dir_item))
93fa09200bSJosef Bacik 		return PTR_ERR(dir_item);
945103e947SJosef Bacik 	memset(&location, 0, sizeof(location));
955103e947SJosef Bacik 
965103e947SJosef Bacik 	leaf = path->nodes[0];
975103e947SJosef Bacik 	btrfs_cpu_key_to_disk(&disk_key, &location);
985103e947SJosef Bacik 	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
995103e947SJosef Bacik 	btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR);
1005103e947SJosef Bacik 	btrfs_set_dir_name_len(leaf, dir_item, name_len);
101e02119d5SChris Mason 	btrfs_set_dir_transid(leaf, dir_item, trans->transid);
1025103e947SJosef Bacik 	btrfs_set_dir_data_len(leaf, dir_item, data_len);
1035103e947SJosef Bacik 	name_ptr = (unsigned long)(dir_item + 1);
1045103e947SJosef Bacik 	data_ptr = (unsigned long)((char *)name_ptr + name_len);
1055103e947SJosef Bacik 
1065103e947SJosef Bacik 	write_extent_buffer(leaf, name, name_ptr, name_len);
1075103e947SJosef Bacik 	write_extent_buffer(leaf, data, data_ptr, data_len);
1085103e947SJosef Bacik 	btrfs_mark_buffer_dirty(path->nodes[0]);
1095103e947SJosef Bacik 
1105103e947SJosef Bacik 	return ret;
1115103e947SJosef Bacik }
1125103e947SJosef Bacik 
113d352ac68SChris Mason /*
114d352ac68SChris Mason  * insert a directory item in the tree, doing all the magic for
115d352ac68SChris Mason  * both indexes. 'dir' indicates which objectid to insert it into,
116d352ac68SChris Mason  * 'location' is the key to stuff into the directory item, 'type' is the
117d352ac68SChris Mason  * type of the inode we're pointing to, and 'index' is the sequence number
118d352ac68SChris Mason  * to use for the second index (if one is created).
119d352ac68SChris Mason  */
120e089f05cSChris Mason int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
12116cdcec7SMiao Xie 			  *root, const char *name, int name_len,
12216cdcec7SMiao Xie 			  struct inode *dir, struct btrfs_key *location,
12316cdcec7SMiao Xie 			  u8 type, u64 index)
12462e2749eSChris Mason {
12562e2749eSChris Mason 	int ret = 0;
126e06afa83SChris Mason 	int ret2 = 0;
1275caf2a00SChris Mason 	struct btrfs_path *path;
12862e2749eSChris Mason 	struct btrfs_dir_item *dir_item;
1295f39d397SChris Mason 	struct extent_buffer *leaf;
1305f39d397SChris Mason 	unsigned long name_ptr;
13162e2749eSChris Mason 	struct btrfs_key key;
1325f39d397SChris Mason 	struct btrfs_disk_key disk_key;
13362e2749eSChris Mason 	u32 data_size;
13462e2749eSChris Mason 
1350d0ca30fSChris Mason 	key.objectid = btrfs_ino(dir);
1361d4f6404SChris Mason 	btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
137df68b8a7SDavid Miller 	key.offset = btrfs_name_hash(name, name_len);
138b9473439SChris Mason 
1395caf2a00SChris Mason 	path = btrfs_alloc_path();
14016cdcec7SMiao Xie 	if (!path)
14116cdcec7SMiao Xie 		return -ENOMEM;
142b9473439SChris Mason 	path->leave_spinning = 1;
143b9473439SChris Mason 
14416cdcec7SMiao Xie 	btrfs_cpu_key_to_disk(&disk_key, location);
14516cdcec7SMiao Xie 
14662e2749eSChris Mason 	data_size = sizeof(*dir_item) + name_len;
147e06afa83SChris Mason 	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
148e06afa83SChris Mason 					name, name_len);
1497e38180eSChris Mason 	if (IS_ERR(dir_item)) {
1507e38180eSChris Mason 		ret = PTR_ERR(dir_item);
151e06afa83SChris Mason 		if (ret == -EEXIST)
152e06afa83SChris Mason 			goto second_insert;
153c2db1073STsutomu Itoh 		goto out_free;
1547e38180eSChris Mason 	}
15562e2749eSChris Mason 
1565f39d397SChris Mason 	leaf = path->nodes[0];
1575f39d397SChris Mason 	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
1585f39d397SChris Mason 	btrfs_set_dir_type(leaf, dir_item, type);
1595103e947SJosef Bacik 	btrfs_set_dir_data_len(leaf, dir_item, 0);
1605f39d397SChris Mason 	btrfs_set_dir_name_len(leaf, dir_item, name_len);
161e02119d5SChris Mason 	btrfs_set_dir_transid(leaf, dir_item, trans->transid);
1625f39d397SChris Mason 	name_ptr = (unsigned long)(dir_item + 1);
163c5739bbaSChris Mason 
1645f39d397SChris Mason 	write_extent_buffer(leaf, name, name_ptr, name_len);
1655f39d397SChris Mason 	btrfs_mark_buffer_dirty(leaf);
1667e38180eSChris Mason 
167e06afa83SChris Mason second_insert:
1687e38180eSChris Mason 	/* FIXME, use some real flag for selecting the extra index */
1697e38180eSChris Mason 	if (root == root->fs_info->tree_root) {
1707e38180eSChris Mason 		ret = 0;
171c2db1073STsutomu Itoh 		goto out_free;
1727e38180eSChris Mason 	}
173b3b4aa74SDavid Sterba 	btrfs_release_path(path);
1747e38180eSChris Mason 
17516cdcec7SMiao Xie 	ret2 = btrfs_insert_delayed_dir_index(trans, root, name, name_len, dir,
17616cdcec7SMiao Xie 					      &disk_key, type, index);
177c2db1073STsutomu Itoh out_free:
1785caf2a00SChris Mason 	btrfs_free_path(path);
179e06afa83SChris Mason 	if (ret)
18062e2749eSChris Mason 		return ret;
181e06afa83SChris Mason 	if (ret2)
182e06afa83SChris Mason 		return ret2;
183e06afa83SChris Mason 	return 0;
18462e2749eSChris Mason }
18562e2749eSChris Mason 
186d352ac68SChris Mason /*
187d352ac68SChris Mason  * lookup a directory item based on name.  'dir' is the objectid
188d352ac68SChris Mason  * we're searching in, and 'mod' tells us if you plan on deleting the
189d352ac68SChris Mason  * item (use mod < 0) or changing the options (use mod > 0)
190d352ac68SChris Mason  */
1917e38180eSChris Mason struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
1927e38180eSChris Mason 					     struct btrfs_root *root,
1937e38180eSChris Mason 					     struct btrfs_path *path, u64 dir,
1947e38180eSChris Mason 					     const char *name, int name_len,
1957e38180eSChris Mason 					     int mod)
19662e2749eSChris Mason {
1971d4f6404SChris Mason 	int ret;
19862e2749eSChris Mason 	struct btrfs_key key;
1991d4f6404SChris Mason 	int ins_len = mod < 0 ? -1 : 0;
2001d4f6404SChris Mason 	int cow = mod != 0;
2015f39d397SChris Mason 	struct btrfs_key found_key;
2025f39d397SChris Mason 	struct extent_buffer *leaf;
20362e2749eSChris Mason 
20462e2749eSChris Mason 	key.objectid = dir;
2051d4f6404SChris Mason 	btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
2065f39d397SChris Mason 
207df68b8a7SDavid Miller 	key.offset = btrfs_name_hash(name, name_len);
2085f39d397SChris Mason 
209e089f05cSChris Mason 	ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
2107fcde0e3SChris Mason 	if (ret < 0)
2117e38180eSChris Mason 		return ERR_PTR(ret);
2127fcde0e3SChris Mason 	if (ret > 0) {
2137fcde0e3SChris Mason 		if (path->slots[0] == 0)
2147e38180eSChris Mason 			return NULL;
2157fcde0e3SChris Mason 		path->slots[0]--;
2167fcde0e3SChris Mason 	}
2177fcde0e3SChris Mason 
2185f39d397SChris Mason 	leaf = path->nodes[0];
2195f39d397SChris Mason 	btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
2205f39d397SChris Mason 
2215f39d397SChris Mason 	if (found_key.objectid != dir ||
2225f39d397SChris Mason 	    btrfs_key_type(&found_key) != BTRFS_DIR_ITEM_KEY ||
2235f39d397SChris Mason 	    found_key.offset != key.offset)
2247e38180eSChris Mason 		return NULL;
2257fcde0e3SChris Mason 
2267e38180eSChris Mason 	return btrfs_match_dir_item_name(root, path, name, name_len);
22762e2749eSChris Mason }
22862e2749eSChris Mason 
229d352ac68SChris Mason /*
230d352ac68SChris Mason  * lookup a directory item based on index.  'dir' is the objectid
231d352ac68SChris Mason  * we're searching in, and 'mod' tells us if you plan on deleting the
232d352ac68SChris Mason  * item (use mod < 0) or changing the options (use mod > 0)
233d352ac68SChris Mason  *
234d352ac68SChris Mason  * The name is used to make sure the index really points to the name you were
235d352ac68SChris Mason  * looking for.
236d352ac68SChris Mason  */
2377e38180eSChris Mason struct btrfs_dir_item *
2387e38180eSChris Mason btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
2397e38180eSChris Mason 			    struct btrfs_root *root,
2407e38180eSChris Mason 			    struct btrfs_path *path, u64 dir,
2417e38180eSChris Mason 			    u64 objectid, const char *name, int name_len,
2427e38180eSChris Mason 			    int mod)
2437e38180eSChris Mason {
2447e38180eSChris Mason 	int ret;
2457e38180eSChris Mason 	struct btrfs_key key;
2467e38180eSChris Mason 	int ins_len = mod < 0 ? -1 : 0;
2477e38180eSChris Mason 	int cow = mod != 0;
2487e38180eSChris Mason 
2497e38180eSChris Mason 	key.objectid = dir;
2507e38180eSChris Mason 	btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
2517e38180eSChris Mason 	key.offset = objectid;
2527e38180eSChris Mason 
2537e38180eSChris Mason 	ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
2547e38180eSChris Mason 	if (ret < 0)
2557e38180eSChris Mason 		return ERR_PTR(ret);
2567e38180eSChris Mason 	if (ret > 0)
2577e38180eSChris Mason 		return ERR_PTR(-ENOENT);
2587e38180eSChris Mason 	return btrfs_match_dir_item_name(root, path, name, name_len);
2597e38180eSChris Mason }
2607e38180eSChris Mason 
2614df27c4dSYan, Zheng struct btrfs_dir_item *
2624df27c4dSYan, Zheng btrfs_search_dir_index_item(struct btrfs_root *root,
2634df27c4dSYan, Zheng 			    struct btrfs_path *path, u64 dirid,
2644df27c4dSYan, Zheng 			    const char *name, int name_len)
2654df27c4dSYan, Zheng {
2664df27c4dSYan, Zheng 	struct extent_buffer *leaf;
2674df27c4dSYan, Zheng 	struct btrfs_dir_item *di;
2684df27c4dSYan, Zheng 	struct btrfs_key key;
2694df27c4dSYan, Zheng 	u32 nritems;
2704df27c4dSYan, Zheng 	int ret;
2714df27c4dSYan, Zheng 
2724df27c4dSYan, Zheng 	key.objectid = dirid;
2734df27c4dSYan, Zheng 	key.type = BTRFS_DIR_INDEX_KEY;
2744df27c4dSYan, Zheng 	key.offset = 0;
2754df27c4dSYan, Zheng 
2764df27c4dSYan, Zheng 	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
2774df27c4dSYan, Zheng 	if (ret < 0)
2784df27c4dSYan, Zheng 		return ERR_PTR(ret);
2794df27c4dSYan, Zheng 
2804df27c4dSYan, Zheng 	leaf = path->nodes[0];
2814df27c4dSYan, Zheng 	nritems = btrfs_header_nritems(leaf);
2824df27c4dSYan, Zheng 
2834df27c4dSYan, Zheng 	while (1) {
2844df27c4dSYan, Zheng 		if (path->slots[0] >= nritems) {
2854df27c4dSYan, Zheng 			ret = btrfs_next_leaf(root, path);
2864df27c4dSYan, Zheng 			if (ret < 0)
2874df27c4dSYan, Zheng 				return ERR_PTR(ret);
2884df27c4dSYan, Zheng 			if (ret > 0)
2894df27c4dSYan, Zheng 				break;
2904df27c4dSYan, Zheng 			leaf = path->nodes[0];
2914df27c4dSYan, Zheng 			nritems = btrfs_header_nritems(leaf);
2924df27c4dSYan, Zheng 			continue;
2934df27c4dSYan, Zheng 		}
2944df27c4dSYan, Zheng 
2954df27c4dSYan, Zheng 		btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
2964df27c4dSYan, Zheng 		if (key.objectid != dirid || key.type != BTRFS_DIR_INDEX_KEY)
2974df27c4dSYan, Zheng 			break;
2984df27c4dSYan, Zheng 
2994df27c4dSYan, Zheng 		di = btrfs_match_dir_item_name(root, path, name, name_len);
3004df27c4dSYan, Zheng 		if (di)
3014df27c4dSYan, Zheng 			return di;
3024df27c4dSYan, Zheng 
3034df27c4dSYan, Zheng 		path->slots[0]++;
3044df27c4dSYan, Zheng 	}
3054df27c4dSYan, Zheng 	return NULL;
3064df27c4dSYan, Zheng }
3074df27c4dSYan, Zheng 
3085103e947SJosef Bacik struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
3095103e947SJosef Bacik 					  struct btrfs_root *root,
3105103e947SJosef Bacik 					  struct btrfs_path *path, u64 dir,
3115103e947SJosef Bacik 					  const char *name, u16 name_len,
3125103e947SJosef Bacik 					  int mod)
3135103e947SJosef Bacik {
3145103e947SJosef Bacik 	int ret;
3155103e947SJosef Bacik 	struct btrfs_key key;
3165103e947SJosef Bacik 	int ins_len = mod < 0 ? -1 : 0;
3175103e947SJosef Bacik 	int cow = mod != 0;
3185103e947SJosef Bacik 	struct btrfs_key found_key;
3195103e947SJosef Bacik 	struct extent_buffer *leaf;
3205103e947SJosef Bacik 
3215103e947SJosef Bacik 	key.objectid = dir;
3225103e947SJosef Bacik 	btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
323df68b8a7SDavid Miller 	key.offset = btrfs_name_hash(name, name_len);
3245103e947SJosef Bacik 	ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
3255103e947SJosef Bacik 	if (ret < 0)
3265103e947SJosef Bacik 		return ERR_PTR(ret);
3275103e947SJosef Bacik 	if (ret > 0) {
3285103e947SJosef Bacik 		if (path->slots[0] == 0)
3295103e947SJosef Bacik 			return NULL;
3305103e947SJosef Bacik 		path->slots[0]--;
3315103e947SJosef Bacik 	}
3325103e947SJosef Bacik 
3335103e947SJosef Bacik 	leaf = path->nodes[0];
3345103e947SJosef Bacik 	btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
3355103e947SJosef Bacik 
3365103e947SJosef Bacik 	if (found_key.objectid != dir ||
3375103e947SJosef Bacik 	    btrfs_key_type(&found_key) != BTRFS_XATTR_ITEM_KEY ||
3385103e947SJosef Bacik 	    found_key.offset != key.offset)
3395103e947SJosef Bacik 		return NULL;
3405103e947SJosef Bacik 
3415103e947SJosef Bacik 	return btrfs_match_dir_item_name(root, path, name, name_len);
3425103e947SJosef Bacik }
3435103e947SJosef Bacik 
344d352ac68SChris Mason /*
345d352ac68SChris Mason  * helper function to look at the directory item pointed to by 'path'
346d352ac68SChris Mason  * this walks through all the entries in a dir item and finds one
347d352ac68SChris Mason  * for a specific name.
348d352ac68SChris Mason  */
3497e38180eSChris Mason struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
3507f5c1516SChris Mason 			      struct btrfs_path *path,
3517f5c1516SChris Mason 			      const char *name, int name_len)
35262e2749eSChris Mason {
35362e2749eSChris Mason 	struct btrfs_dir_item *dir_item;
3545f39d397SChris Mason 	unsigned long name_ptr;
3557e38180eSChris Mason 	u32 total_len;
3567e38180eSChris Mason 	u32 cur = 0;
3577e38180eSChris Mason 	u32 this_len;
3585f39d397SChris Mason 	struct extent_buffer *leaf;
359a8a2ee0cSChris Mason 
3605f39d397SChris Mason 	leaf = path->nodes[0];
3617e38180eSChris Mason 	dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
36222a94d44SJosef Bacik 	if (verify_dir_item(root, leaf, dir_item))
36322a94d44SJosef Bacik 		return NULL;
36422a94d44SJosef Bacik 
3655f39d397SChris Mason 	total_len = btrfs_item_size_nr(leaf, path->slots[0]);
3667e38180eSChris Mason 	while (cur < total_len) {
3675f39d397SChris Mason 		this_len = sizeof(*dir_item) +
3685103e947SJosef Bacik 			btrfs_dir_name_len(leaf, dir_item) +
3695103e947SJosef Bacik 			btrfs_dir_data_len(leaf, dir_item);
3705f39d397SChris Mason 		name_ptr = (unsigned long)(dir_item + 1);
3717e38180eSChris Mason 
3725f39d397SChris Mason 		if (btrfs_dir_name_len(leaf, dir_item) == name_len &&
3735f39d397SChris Mason 		    memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
3747e38180eSChris Mason 			return dir_item;
3757e38180eSChris Mason 
3767e38180eSChris Mason 		cur += this_len;
3777e38180eSChris Mason 		dir_item = (struct btrfs_dir_item *)((char *)dir_item +
3787e38180eSChris Mason 						     this_len);
37962e2749eSChris Mason 	}
3807e38180eSChris Mason 	return NULL;
3817e38180eSChris Mason }
3827e38180eSChris Mason 
383d352ac68SChris Mason /*
384d352ac68SChris Mason  * given a pointer into a directory item, delete it.  This
385d352ac68SChris Mason  * handles items that have more than one entry in them.
386d352ac68SChris Mason  */
3877e38180eSChris Mason int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
3887e38180eSChris Mason 			      struct btrfs_root *root,
3897e38180eSChris Mason 			      struct btrfs_path *path,
3907e38180eSChris Mason 			      struct btrfs_dir_item *di)
3917e38180eSChris Mason {
3927e38180eSChris Mason 
3935f39d397SChris Mason 	struct extent_buffer *leaf;
3947e38180eSChris Mason 	u32 sub_item_len;
3957e38180eSChris Mason 	u32 item_len;
39654aa1f4dSChris Mason 	int ret = 0;
3977e38180eSChris Mason 
3985f39d397SChris Mason 	leaf = path->nodes[0];
3995103e947SJosef Bacik 	sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) +
4005103e947SJosef Bacik 		btrfs_dir_data_len(leaf, di);
4015f39d397SChris Mason 	item_len = btrfs_item_size_nr(leaf, path->slots[0]);
4025f39d397SChris Mason 	if (sub_item_len == item_len) {
4037e38180eSChris Mason 		ret = btrfs_del_item(trans, root, path);
4047e38180eSChris Mason 	} else {
4055f39d397SChris Mason 		/* MARKER */
4065f39d397SChris Mason 		unsigned long ptr = (unsigned long)di;
4075f39d397SChris Mason 		unsigned long start;
4085f39d397SChris Mason 
4095f39d397SChris Mason 		start = btrfs_item_ptr_offset(leaf, path->slots[0]);
4105f39d397SChris Mason 		memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
4117e38180eSChris Mason 			item_len - (ptr + sub_item_len - start));
4127e38180eSChris Mason 		ret = btrfs_truncate_item(trans, root, path,
413179e29e4SChris Mason 					  item_len - sub_item_len, 1);
4147e38180eSChris Mason 	}
415411fc6bcSAndi Kleen 	return ret;
4167e38180eSChris Mason }
41722a94d44SJosef Bacik 
41822a94d44SJosef Bacik int verify_dir_item(struct btrfs_root *root,
41922a94d44SJosef Bacik 		    struct extent_buffer *leaf,
42022a94d44SJosef Bacik 		    struct btrfs_dir_item *dir_item)
42122a94d44SJosef Bacik {
42222a94d44SJosef Bacik 	u16 namelen = BTRFS_NAME_LEN;
42322a94d44SJosef Bacik 	u8 type = btrfs_dir_type(leaf, dir_item);
42422a94d44SJosef Bacik 
42522a94d44SJosef Bacik 	if (type >= BTRFS_FT_MAX) {
42622a94d44SJosef Bacik 		printk(KERN_CRIT "btrfs: invalid dir item type: %d\n",
42722a94d44SJosef Bacik 		       (int)type);
42822a94d44SJosef Bacik 		return 1;
42922a94d44SJosef Bacik 	}
43022a94d44SJosef Bacik 
43122a94d44SJosef Bacik 	if (type == BTRFS_FT_XATTR)
43222a94d44SJosef Bacik 		namelen = XATTR_NAME_MAX;
43322a94d44SJosef Bacik 
43422a94d44SJosef Bacik 	if (btrfs_dir_name_len(leaf, dir_item) > namelen) {
4359694b3fcSSergei Trofimovich 		printk(KERN_CRIT "btrfs: invalid dir item name len: %u\n",
43622a94d44SJosef Bacik 		       (unsigned)btrfs_dir_data_len(leaf, dir_item));
43722a94d44SJosef Bacik 		return 1;
43822a94d44SJosef Bacik 	}
43922a94d44SJosef Bacik 
44022a94d44SJosef Bacik 	/* BTRFS_MAX_XATTR_SIZE is the same for all dir items */
44122a94d44SJosef Bacik 	if (btrfs_dir_data_len(leaf, dir_item) > BTRFS_MAX_XATTR_SIZE(root)) {
44222a94d44SJosef Bacik 		printk(KERN_CRIT "btrfs: invalid dir item data len: %u\n",
44322a94d44SJosef Bacik 		       (unsigned)btrfs_dir_data_len(leaf, dir_item));
44422a94d44SJosef Bacik 		return 1;
44522a94d44SJosef Bacik 	}
44622a94d44SJosef Bacik 
44722a94d44SJosef Bacik 	return 0;
44822a94d44SJosef Bacik }
449