Line data Source code
1 : /*
2 : * Copyright (C) 2007 Oracle. All rights reserved.
3 : *
4 : * This program is free software; you can redistribute it and/or
5 : * modify it under the terms of the GNU General Public
6 : * License v2 as published by the Free Software Foundation.
7 : *
8 : * This program is distributed in the hope that it will be useful,
9 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 : * General Public License for more details.
12 : *
13 : * You should have received a copy of the GNU General Public
14 : * License along with this program; if not, write to the
15 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 : * Boston, MA 021110-1307, USA.
17 : */
18 :
19 : #include "ctree.h"
20 : #include "disk-io.h"
21 : #include "hash.h"
22 : #include "transaction.h"
23 :
24 : static struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
25 : struct btrfs_path *path,
26 : const char *name, int name_len);
27 :
28 : /*
29 : * insert a name into a directory, doing overflow properly if there is a hash
30 : * collision. data_size indicates how big the item inserted should be. On
31 : * success a struct btrfs_dir_item pointer is returned, otherwise it is
32 : * an ERR_PTR.
33 : *
34 : * The name is not copied into the dir item, you have to do that yourself.
35 : */
36 26875 : static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
37 : *trans,
38 : struct btrfs_root *root,
39 40 : struct btrfs_path *path,
40 : struct btrfs_key *cpu_key,
41 : u32 data_size,
42 : const char *name,
43 : int name_len)
44 : {
45 : int ret;
46 : char *ptr;
47 : struct btrfs_item *item;
48 : struct extent_buffer *leaf;
49 :
50 : ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
51 26875 : if (ret == -EEXIST) {
52 : struct btrfs_dir_item *di;
53 40 : di = btrfs_match_dir_item_name(root, path, name, name_len);
54 40 : if (di)
55 : return ERR_PTR(-EEXIST);
56 0 : btrfs_extend_item(root, path, data_size);
57 26835 : } else if (ret < 0)
58 0 : return ERR_PTR(ret);
59 26835 : WARN_ON(ret > 0);
60 26835 : leaf = path->nodes[0];
61 26835 : item = btrfs_item_nr(path->slots[0]);
62 26834 : ptr = btrfs_item_ptr(leaf, path->slots[0], char);
63 26834 : BUG_ON(data_size > btrfs_item_size(leaf, item));
64 26834 : ptr += btrfs_item_size(leaf, item) - data_size;
65 26834 : return (struct btrfs_dir_item *)ptr;
66 : }
67 :
68 : /*
69 : * xattrs work a lot like directories, this inserts an xattr item
70 : * into the tree
71 : */
72 374 : int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
73 : struct btrfs_root *root,
74 : struct btrfs_path *path, u64 objectid,
75 : const char *name, u16 name_len,
76 : const void *data, u16 data_len)
77 : {
78 : int ret = 0;
79 : struct btrfs_dir_item *dir_item;
80 : unsigned long name_ptr, data_ptr;
81 : struct btrfs_key key, location;
82 : struct btrfs_disk_key disk_key;
83 : struct extent_buffer *leaf;
84 : u32 data_size;
85 :
86 374 : BUG_ON(name_len + data_len > BTRFS_MAX_XATTR_SIZE(root));
87 :
88 374 : key.objectid = objectid;
89 : btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
90 374 : key.offset = btrfs_name_hash(name, name_len);
91 :
92 374 : data_size = sizeof(*dir_item) + name_len + data_len;
93 374 : dir_item = insert_with_overflow(trans, root, path, &key, data_size,
94 : name, name_len);
95 374 : if (IS_ERR(dir_item))
96 40 : return PTR_ERR(dir_item);
97 334 : memset(&location, 0, sizeof(location));
98 :
99 334 : leaf = path->nodes[0];
100 : btrfs_cpu_key_to_disk(&disk_key, &location);
101 : btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
102 : btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR);
103 : btrfs_set_dir_name_len(leaf, dir_item, name_len);
104 334 : btrfs_set_dir_transid(leaf, dir_item, trans->transid);
105 : btrfs_set_dir_data_len(leaf, dir_item, data_len);
106 334 : name_ptr = (unsigned long)(dir_item + 1);
107 334 : data_ptr = (unsigned long)((char *)name_ptr + name_len);
108 :
109 334 : write_extent_buffer(leaf, name, name_ptr, name_len);
110 334 : write_extent_buffer(leaf, data, data_ptr, data_len);
111 334 : btrfs_mark_buffer_dirty(path->nodes[0]);
112 :
113 334 : return ret;
114 : }
115 :
116 : /*
117 : * insert a directory item in the tree, doing all the magic for
118 : * both indexes. 'dir' indicates which objectid to insert it into,
119 : * 'location' is the key to stuff into the directory item, 'type' is the
120 : * type of the inode we're pointing to, and 'index' is the sequence number
121 : * to use for the second index (if one is created).
122 : * Will return 0 or -ENOMEM
123 : */
124 26501 : int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
125 : *root, const char *name, int name_len,
126 : struct inode *dir, struct btrfs_key *location,
127 : u8 type, u64 index)
128 : {
129 : int ret = 0;
130 : int ret2 = 0;
131 : struct btrfs_path *path;
132 : struct btrfs_dir_item *dir_item;
133 : struct extent_buffer *leaf;
134 : unsigned long name_ptr;
135 : struct btrfs_key key;
136 : struct btrfs_disk_key disk_key;
137 : u32 data_size;
138 :
139 26501 : key.objectid = btrfs_ino(dir);
140 : btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
141 26501 : key.offset = btrfs_name_hash(name, name_len);
142 :
143 26501 : path = btrfs_alloc_path();
144 26501 : if (!path)
145 : return -ENOMEM;
146 26501 : path->leave_spinning = 1;
147 :
148 : btrfs_cpu_key_to_disk(&disk_key, location);
149 :
150 26501 : data_size = sizeof(*dir_item) + name_len;
151 26501 : dir_item = insert_with_overflow(trans, root, path, &key, data_size,
152 : name, name_len);
153 26500 : if (IS_ERR(dir_item)) {
154 0 : ret = PTR_ERR(dir_item);
155 0 : if (ret == -EEXIST)
156 : goto second_insert;
157 : goto out_free;
158 : }
159 :
160 26500 : leaf = path->nodes[0];
161 : btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
162 : btrfs_set_dir_type(leaf, dir_item, type);
163 : btrfs_set_dir_data_len(leaf, dir_item, 0);
164 26500 : btrfs_set_dir_name_len(leaf, dir_item, name_len);
165 26500 : btrfs_set_dir_transid(leaf, dir_item, trans->transid);
166 26500 : name_ptr = (unsigned long)(dir_item + 1);
167 :
168 26500 : write_extent_buffer(leaf, name, name_ptr, name_len);
169 26500 : btrfs_mark_buffer_dirty(leaf);
170 :
171 : second_insert:
172 : /* FIXME, use some real flag for selecting the extra index */
173 26501 : if (root == root->fs_info->tree_root) {
174 : ret = 0;
175 : goto out_free;
176 : }
177 26501 : btrfs_release_path(path);
178 :
179 26501 : ret2 = btrfs_insert_delayed_dir_index(trans, root, name, name_len, dir,
180 : &disk_key, type, index);
181 : out_free:
182 26501 : btrfs_free_path(path);
183 26501 : if (ret)
184 : return ret;
185 26501 : if (ret2)
186 0 : return ret2;
187 : return 0;
188 : }
189 :
190 : /*
191 : * lookup a directory item based on name. 'dir' is the objectid
192 : * we're searching in, and 'mod' tells us if you plan on deleting the
193 : * item (use mod < 0) or changing the options (use mod > 0)
194 : */
195 54663 : struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
196 : struct btrfs_root *root,
197 25069 : struct btrfs_path *path, u64 dir,
198 : const char *name, int name_len,
199 : int mod)
200 : {
201 : int ret;
202 : struct btrfs_key key;
203 54663 : int ins_len = mod < 0 ? -1 : 0;
204 54663 : int cow = mod != 0;
205 :
206 54663 : key.objectid = dir;
207 : btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
208 :
209 54663 : key.offset = btrfs_name_hash(name, name_len);
210 :
211 54663 : ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
212 54660 : if (ret < 0)
213 0 : return ERR_PTR(ret);
214 54660 : if (ret > 0)
215 : return NULL;
216 :
217 25069 : return btrfs_match_dir_item_name(root, path, name, name_len);
218 : }
219 :
220 2507 : int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
221 : const char *name, int name_len)
222 : {
223 : int ret;
224 : struct btrfs_key key;
225 : struct btrfs_dir_item *di;
226 : int data_size;
227 : struct extent_buffer *leaf;
228 : int slot;
229 12 : struct btrfs_path *path;
230 :
231 :
232 2507 : path = btrfs_alloc_path();
233 2507 : if (!path)
234 : return -ENOMEM;
235 :
236 2507 : key.objectid = dir;
237 : btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
238 2507 : key.offset = btrfs_name_hash(name, name_len);
239 :
240 2507 : ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
241 :
242 : /* return back any errors */
243 2507 : if (ret < 0)
244 : goto out;
245 :
246 : /* nothing found, we're safe */
247 2507 : if (ret > 0) {
248 : ret = 0;
249 : goto out;
250 : }
251 :
252 : /* we found an item, look for our name in the item */
253 12 : di = btrfs_match_dir_item_name(root, path, name, name_len);
254 12 : if (di) {
255 : /* our exact name was found */
256 : ret = -EEXIST;
257 : goto out;
258 : }
259 :
260 : /*
261 : * see if there is room in the item to insert this
262 : * name
263 : */
264 0 : data_size = sizeof(*di) + name_len;
265 0 : leaf = path->nodes[0];
266 0 : slot = path->slots[0];
267 0 : if (data_size + btrfs_item_size_nr(leaf, slot) +
268 0 : sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root)) {
269 : ret = -EOVERFLOW;
270 : } else {
271 : /* plenty of insertion room */
272 : ret = 0;
273 : }
274 : out:
275 2507 : btrfs_free_path(path);
276 2507 : return ret;
277 : }
278 :
279 : /*
280 : * lookup a directory item based on index. 'dir' is the objectid
281 : * we're searching in, and 'mod' tells us if you plan on deleting the
282 : * item (use mod < 0) or changing the options (use mod > 0)
283 : *
284 : * The name is used to make sure the index really points to the name you were
285 : * looking for.
286 : */
287 : struct btrfs_dir_item *
288 151 : btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
289 : struct btrfs_root *root,
290 0 : struct btrfs_path *path, u64 dir,
291 : u64 objectid, const char *name, int name_len,
292 : int mod)
293 : {
294 : int ret;
295 : struct btrfs_key key;
296 151 : int ins_len = mod < 0 ? -1 : 0;
297 151 : int cow = mod != 0;
298 :
299 151 : key.objectid = dir;
300 : btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
301 151 : key.offset = objectid;
302 :
303 151 : ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
304 151 : if (ret < 0)
305 0 : return ERR_PTR(ret);
306 151 : if (ret > 0)
307 : return ERR_PTR(-ENOENT);
308 0 : return btrfs_match_dir_item_name(root, path, name, name_len);
309 : }
310 :
311 : struct btrfs_dir_item *
312 0 : btrfs_search_dir_index_item(struct btrfs_root *root,
313 0 : struct btrfs_path *path, u64 dirid,
314 : const char *name, int name_len)
315 : {
316 0 : struct extent_buffer *leaf;
317 : struct btrfs_dir_item *di;
318 : struct btrfs_key key;
319 : u32 nritems;
320 : int ret;
321 :
322 0 : key.objectid = dirid;
323 0 : key.type = BTRFS_DIR_INDEX_KEY;
324 0 : key.offset = 0;
325 :
326 0 : ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
327 0 : if (ret < 0)
328 0 : return ERR_PTR(ret);
329 :
330 0 : leaf = path->nodes[0];
331 : nritems = btrfs_header_nritems(leaf);
332 :
333 : while (1) {
334 0 : if (path->slots[0] >= nritems) {
335 0 : ret = btrfs_next_leaf(root, path);
336 0 : if (ret < 0)
337 0 : return ERR_PTR(ret);
338 0 : if (ret > 0)
339 : break;
340 0 : leaf = path->nodes[0];
341 : nritems = btrfs_header_nritems(leaf);
342 0 : continue;
343 : }
344 :
345 0 : btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
346 0 : if (key.objectid != dirid || key.type != BTRFS_DIR_INDEX_KEY)
347 : break;
348 :
349 0 : di = btrfs_match_dir_item_name(root, path, name, name_len);
350 0 : if (di)
351 : return di;
352 :
353 0 : path->slots[0]++;
354 : }
355 : return NULL;
356 : }
357 :
358 106943 : struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
359 : struct btrfs_root *root,
360 155 : struct btrfs_path *path, u64 dir,
361 : const char *name, u16 name_len,
362 : int mod)
363 : {
364 : int ret;
365 : struct btrfs_key key;
366 106943 : int ins_len = mod < 0 ? -1 : 0;
367 106943 : int cow = mod != 0;
368 :
369 106943 : key.objectid = dir;
370 : btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
371 106943 : key.offset = btrfs_name_hash(name, name_len);
372 106943 : ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
373 106942 : if (ret < 0)
374 0 : return ERR_PTR(ret);
375 106942 : if (ret > 0)
376 : return NULL;
377 :
378 310 : return btrfs_match_dir_item_name(root, path, name, name_len);
379 : }
380 :
381 : /*
382 : * helper function to look at the directory item pointed to by 'path'
383 : * this walks through all the entries in a dir item and finds one
384 : * for a specific name.
385 : */
386 25276 : static struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
387 : struct btrfs_path *path,
388 : const char *name, int name_len)
389 : {
390 : struct btrfs_dir_item *dir_item;
391 : unsigned long name_ptr;
392 : u32 total_len;
393 : u32 cur = 0;
394 : u32 this_len;
395 : struct extent_buffer *leaf;
396 :
397 25276 : leaf = path->nodes[0];
398 50552 : dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
399 25276 : if (verify_dir_item(root, leaf, dir_item))
400 : return NULL;
401 :
402 25276 : total_len = btrfs_item_size_nr(leaf, path->slots[0]);
403 25276 : while (cur < total_len) {
404 50552 : this_len = sizeof(*dir_item) +
405 : btrfs_dir_name_len(leaf, dir_item) +
406 : btrfs_dir_data_len(leaf, dir_item);
407 25276 : name_ptr = (unsigned long)(dir_item + 1);
408 :
409 50552 : if (btrfs_dir_name_len(leaf, dir_item) == name_len &&
410 25276 : memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
411 : return dir_item;
412 :
413 0 : cur += this_len;
414 0 : dir_item = (struct btrfs_dir_item *)((char *)dir_item +
415 : this_len);
416 : }
417 : return NULL;
418 : }
419 :
420 : /*
421 : * given a pointer into a directory item, delete it. This
422 : * handles items that have more than one entry in them.
423 : */
424 12363 : int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
425 : struct btrfs_root *root,
426 : struct btrfs_path *path,
427 : struct btrfs_dir_item *di)
428 : {
429 :
430 : struct extent_buffer *leaf;
431 : u32 sub_item_len;
432 : u32 item_len;
433 : int ret = 0;
434 :
435 12363 : leaf = path->nodes[0];
436 24726 : sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) +
437 : btrfs_dir_data_len(leaf, di);
438 12363 : item_len = btrfs_item_size_nr(leaf, path->slots[0]);
439 12363 : if (sub_item_len == item_len) {
440 : ret = btrfs_del_item(trans, root, path);
441 : } else {
442 : /* MARKER */
443 0 : unsigned long ptr = (unsigned long)di;
444 : unsigned long start;
445 :
446 0 : start = btrfs_item_ptr_offset(leaf, path->slots[0]);
447 0 : memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
448 0 : item_len - (ptr + sub_item_len - start));
449 0 : btrfs_truncate_item(root, path, item_len - sub_item_len, 1);
450 : }
451 12363 : return ret;
452 : }
453 :
454 171906 : int verify_dir_item(struct btrfs_root *root,
455 : struct extent_buffer *leaf,
456 : struct btrfs_dir_item *dir_item)
457 : {
458 : u16 namelen = BTRFS_NAME_LEN;
459 : u8 type = btrfs_dir_type(leaf, dir_item);
460 :
461 171906 : if (type >= BTRFS_FT_MAX) {
462 0 : btrfs_crit(root->fs_info, "invalid dir item type: %d",
463 : (int)type);
464 0 : return 1;
465 : }
466 :
467 : if (type == BTRFS_FT_XATTR)
468 : namelen = XATTR_NAME_MAX;
469 :
470 171906 : if (btrfs_dir_name_len(leaf, dir_item) > namelen) {
471 0 : btrfs_crit(root->fs_info, "invalid dir item name len: %u",
472 : (unsigned)btrfs_dir_data_len(leaf, dir_item));
473 0 : return 1;
474 : }
475 :
476 : /* BTRFS_MAX_XATTR_SIZE is the same for all dir items */
477 515718 : if ((btrfs_dir_data_len(leaf, dir_item) +
478 171906 : btrfs_dir_name_len(leaf, dir_item)) > BTRFS_MAX_XATTR_SIZE(root)) {
479 0 : btrfs_crit(root->fs_info, "invalid dir item name + data len: %u + %u",
480 : (unsigned)btrfs_dir_name_len(leaf, dir_item),
481 : (unsigned)btrfs_dir_data_len(leaf, dir_item));
482 0 : return 1;
483 : }
484 :
485 : return 0;
486 : }
|