xref: /openbmc/linux/fs/btrfs/dir-item.c (revision c5739bba5260a59cebd20a51a55080592c8d3b07)
1 #include <linux/module.h>
2 #include "ctree.h"
3 #include "disk-io.h"
4 #include "hash.h"
5 #include "transaction.h"
6 
7 int insert_with_overflow(struct btrfs_trans_handle *trans, struct btrfs_root
8 			    *root, struct btrfs_path *path, struct btrfs_key
9 			    *cpu_key, u32 data_size)
10 {
11 	int overflow;
12 	int ret;
13 
14 	ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
15 	overflow = btrfs_key_overflow(cpu_key);
16 
17 	while(ret == -EEXIST && overflow < BTRFS_KEY_OVERFLOW_MAX) {
18 		overflow++;
19 		btrfs_set_key_overflow(cpu_key, overflow);
20 		btrfs_release_path(root, path);
21 		ret = btrfs_insert_empty_item(trans, root, path, cpu_key,
22 					      data_size);
23 	}
24 	return ret;
25 }
26 
27 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
28 			  *root, const char *name, int name_len, u64 dir,
29 			  struct btrfs_key *location, u8 type)
30 {
31 	int ret = 0;
32 	struct btrfs_path *path;
33 	struct btrfs_dir_item *dir_item;
34 	char *name_ptr;
35 	struct btrfs_key key;
36 	u32 data_size;
37 
38 	key.objectid = dir;
39 	key.flags = 0;
40 	btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
41 	ret = btrfs_name_hash(name, name_len, &key.offset);
42 	BUG_ON(ret);
43 	path = btrfs_alloc_path();
44 	btrfs_init_path(path);
45 	data_size = sizeof(*dir_item) + name_len;
46 	ret = insert_with_overflow(trans, root, path, &key, data_size);
47 	if (ret)
48 		goto out;
49 
50 	dir_item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]),
51 				  path->slots[0],
52 				  struct btrfs_dir_item);
53 	btrfs_cpu_key_to_disk(&dir_item->location, location);
54 	btrfs_set_dir_type(dir_item, type);
55 	btrfs_set_dir_flags(dir_item, 0);
56 	btrfs_set_dir_name_len(dir_item, name_len);
57 	name_ptr = (char *)(dir_item + 1);
58 
59 	btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len);
60 	btrfs_mark_buffer_dirty(path->nodes[0]);
61 
62 	/* FIXME, use some real flag for selecting the extra index */
63 	if (root == root->fs_info->tree_root)
64 		goto out;
65 
66 	btrfs_release_path(root, path);
67 
68 	btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
69 	key.offset = location->objectid;
70 	ret = insert_with_overflow(trans, root, path, &key, data_size);
71 	// FIXME clear the dirindex bit
72 	if (ret)
73 		goto out;
74 
75 	dir_item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]),
76 				  path->slots[0],
77 				  struct btrfs_dir_item);
78 	btrfs_cpu_key_to_disk(&dir_item->location, location);
79 	btrfs_set_dir_type(dir_item, type);
80 	btrfs_set_dir_flags(dir_item, 0);
81 	btrfs_set_dir_name_len(dir_item, name_len);
82 	name_ptr = (char *)(dir_item + 1);
83 	btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len);
84 	btrfs_mark_buffer_dirty(path->nodes[0]);
85 out:
86 	btrfs_release_path(root, path);
87 	btrfs_free_path(path);
88 	return ret;
89 }
90 
91 int btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
92 			  *root, struct btrfs_path *path, u64 dir,
93 			  const char *name, int name_len, int mod)
94 {
95 	int ret;
96 	struct btrfs_key key;
97 	int ins_len = mod < 0 ? -1 : 0;
98 	int cow = mod != 0;
99 	struct btrfs_disk_key *found_key;
100 	struct btrfs_leaf *leaf;
101 	u32 overflow;
102 
103 	key.objectid = dir;
104 	key.flags = 0;
105 	btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
106 	btrfs_set_key_overflow(&key, BTRFS_KEY_OVERFLOW_MAX - 1);
107 	ret = btrfs_name_hash(name, name_len, &key.offset);
108 	BUG_ON(ret);
109 	while(1) {
110 		ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
111 		if (ret < 0)
112 			return ret;
113 		if (ret > 0) {
114 			if (path->slots[0] == 0)
115 				return 1;
116 			path->slots[0]--;
117 		}
118 		leaf = btrfs_buffer_leaf(path->nodes[0]);
119 		found_key = &leaf->items[path->slots[0]].key;
120 
121 		if (btrfs_disk_key_objectid(found_key) != dir ||
122 		    btrfs_disk_key_type(found_key) != BTRFS_DIR_ITEM_KEY ||
123 		    btrfs_disk_key_offset(found_key) != key.offset)
124 			return 1;
125 
126 		if (btrfs_match_dir_item_name(root, path, name, name_len))
127 			return 0;
128 
129 		overflow = btrfs_disk_key_overflow(found_key);
130 		if (overflow == 0)
131 			return 1;
132 		btrfs_set_key_overflow(&key, overflow - 1);
133 		btrfs_release_path(root, path);
134 	}
135 	return 1;
136 }
137 
138 int btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
139 				struct btrfs_root *root,
140 				struct btrfs_path *path, u64 dir,
141 				u64 objectid, int mod)
142 {
143 	int ret;
144 	struct btrfs_key key;
145 	int ins_len = mod < 0 ? -1 : 0;
146 	int cow = mod != 0;
147 	struct btrfs_disk_key *found_key;
148 	struct btrfs_leaf *leaf;
149 
150 	key.objectid = dir;
151 	key.flags = 0;
152 	btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
153 	btrfs_set_key_overflow(&key, BTRFS_KEY_OVERFLOW_MAX - 1);
154 	key.offset = objectid;
155 	ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
156 	if (ret < 0)
157 		return ret;
158 	if (ret > 0) {
159 		if (path->slots[0] == 0)
160 			return 1;
161 		path->slots[0]--;
162 	}
163 	leaf = btrfs_buffer_leaf(path->nodes[0]);
164 	found_key = &leaf->items[path->slots[0]].key;
165 
166 	if (btrfs_disk_key_objectid(found_key) != dir ||
167 	    btrfs_disk_key_type(found_key) != BTRFS_DIR_INDEX_KEY)
168 		return 1;
169 	if (btrfs_disk_key_offset(found_key) == objectid)
170 		return 0;
171 	return 1;
172 }
173 
174 int btrfs_match_dir_item_name(struct btrfs_root *root,
175 			      struct btrfs_path *path,
176 			      const char *name, int name_len)
177 {
178 	struct btrfs_dir_item *dir_item;
179 	char *name_ptr;
180 
181 	dir_item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]),
182 				  path->slots[0],
183 				  struct btrfs_dir_item);
184 	if (btrfs_dir_name_len(dir_item) != name_len)
185 		return 0;
186 	name_ptr = (char *)(dir_item + 1);
187 	if (memcmp(name_ptr, name, name_len))
188 		return 0;
189 	return 1;
190 }
191