1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2007 Oracle. All rights reserved.
8 #include "transaction.h"
9 #include "print-tree.h"
11 struct btrfs_inode_ref
*btrfs_find_name_in_backref(struct extent_buffer
*leaf
,
12 int slot
, const char *name
,
15 struct btrfs_inode_ref
*ref
;
17 unsigned long name_ptr
;
22 item_size
= btrfs_item_size_nr(leaf
, slot
);
23 ptr
= btrfs_item_ptr_offset(leaf
, slot
);
24 while (cur_offset
< item_size
) {
25 ref
= (struct btrfs_inode_ref
*)(ptr
+ cur_offset
);
26 len
= btrfs_inode_ref_name_len(leaf
, ref
);
27 name_ptr
= (unsigned long)(ref
+ 1);
28 cur_offset
+= len
+ sizeof(*ref
);
31 if (memcmp_extent_buffer(leaf
, name
, name_ptr
, name_len
) == 0)
37 struct btrfs_inode_extref
*btrfs_find_name_in_ext_backref(
38 struct extent_buffer
*leaf
, int slot
, u64 ref_objectid
,
39 const char *name
, int name_len
)
41 struct btrfs_inode_extref
*extref
;
43 unsigned long name_ptr
;
48 item_size
= btrfs_item_size_nr(leaf
, slot
);
49 ptr
= btrfs_item_ptr_offset(leaf
, slot
);
52 * Search all extended backrefs in this item. We're only
53 * looking through any collisions so most of the time this is
54 * just going to compare against one buffer. If all is well,
55 * we'll return success and the inode ref object.
57 while (cur_offset
< item_size
) {
58 extref
= (struct btrfs_inode_extref
*) (ptr
+ cur_offset
);
59 name_ptr
= (unsigned long)(&extref
->name
);
60 ref_name_len
= btrfs_inode_extref_name_len(leaf
, extref
);
62 if (ref_name_len
== name_len
&&
63 btrfs_inode_extref_parent(leaf
, extref
) == ref_objectid
&&
64 (memcmp_extent_buffer(leaf
, name
, name_ptr
, name_len
) == 0))
67 cur_offset
+= ref_name_len
+ sizeof(*extref
);
72 /* Returns NULL if no extref found */
73 struct btrfs_inode_extref
*
74 btrfs_lookup_inode_extref(struct btrfs_trans_handle
*trans
,
75 struct btrfs_root
*root
,
76 struct btrfs_path
*path
,
77 const char *name
, int name_len
,
78 u64 inode_objectid
, u64 ref_objectid
, int ins_len
,
84 key
.objectid
= inode_objectid
;
85 key
.type
= BTRFS_INODE_EXTREF_KEY
;
86 key
.offset
= btrfs_extref_hash(ref_objectid
, name
, name_len
);
88 ret
= btrfs_search_slot(trans
, root
, &key
, path
, ins_len
, cow
);
93 return btrfs_find_name_in_ext_backref(path
->nodes
[0], path
->slots
[0],
94 ref_objectid
, name
, name_len
);
98 static int btrfs_del_inode_extref(struct btrfs_trans_handle
*trans
,
99 struct btrfs_root
*root
,
100 const char *name
, int name_len
,
101 u64 inode_objectid
, u64 ref_objectid
,
104 struct btrfs_path
*path
;
105 struct btrfs_key key
;
106 struct btrfs_inode_extref
*extref
;
107 struct extent_buffer
*leaf
;
109 int del_len
= name_len
+ sizeof(*extref
);
111 unsigned long item_start
;
114 key
.objectid
= inode_objectid
;
115 key
.type
= BTRFS_INODE_EXTREF_KEY
;
116 key
.offset
= btrfs_extref_hash(ref_objectid
, name
, name_len
);
118 path
= btrfs_alloc_path();
122 ret
= btrfs_search_slot(trans
, root
, &key
, path
, -1, 1);
129 * Sanity check - did we find the right item for this name?
130 * This should always succeed so error here will make the FS
133 extref
= btrfs_find_name_in_ext_backref(path
->nodes
[0], path
->slots
[0],
134 ref_objectid
, name
, name_len
);
136 btrfs_handle_fs_error(root
->fs_info
, -ENOENT
, NULL
);
141 leaf
= path
->nodes
[0];
142 item_size
= btrfs_item_size_nr(leaf
, path
->slots
[0]);
144 *index
= btrfs_inode_extref_index(leaf
, extref
);
146 if (del_len
== item_size
) {
148 * Common case only one ref in the item, remove the
151 ret
= btrfs_del_item(trans
, root
, path
);
155 ptr
= (unsigned long)extref
;
156 item_start
= btrfs_item_ptr_offset(leaf
, path
->slots
[0]);
158 memmove_extent_buffer(leaf
, ptr
, ptr
+ del_len
,
159 item_size
- (ptr
+ del_len
- item_start
));
161 btrfs_truncate_item(path
, item_size
- del_len
, 1);
164 btrfs_free_path(path
);
169 int btrfs_del_inode_ref(struct btrfs_trans_handle
*trans
,
170 struct btrfs_root
*root
,
171 const char *name
, int name_len
,
172 u64 inode_objectid
, u64 ref_objectid
, u64
*index
)
174 struct btrfs_path
*path
;
175 struct btrfs_key key
;
176 struct btrfs_inode_ref
*ref
;
177 struct extent_buffer
*leaf
;
179 unsigned long item_start
;
183 int search_ext_refs
= 0;
184 int del_len
= name_len
+ sizeof(*ref
);
186 key
.objectid
= inode_objectid
;
187 key
.offset
= ref_objectid
;
188 key
.type
= BTRFS_INODE_REF_KEY
;
190 path
= btrfs_alloc_path();
194 ret
= btrfs_search_slot(trans
, root
, &key
, path
, -1, 1);
199 } else if (ret
< 0) {
203 ref
= btrfs_find_name_in_backref(path
->nodes
[0], path
->slots
[0], name
,
210 leaf
= path
->nodes
[0];
211 item_size
= btrfs_item_size_nr(leaf
, path
->slots
[0]);
214 *index
= btrfs_inode_ref_index(leaf
, ref
);
216 if (del_len
== item_size
) {
217 ret
= btrfs_del_item(trans
, root
, path
);
220 ptr
= (unsigned long)ref
;
221 sub_item_len
= name_len
+ sizeof(*ref
);
222 item_start
= btrfs_item_ptr_offset(leaf
, path
->slots
[0]);
223 memmove_extent_buffer(leaf
, ptr
, ptr
+ sub_item_len
,
224 item_size
- (ptr
+ sub_item_len
- item_start
));
225 btrfs_truncate_item(path
, item_size
- sub_item_len
, 1);
227 btrfs_free_path(path
);
229 if (search_ext_refs
) {
231 * No refs were found, or we could not find the
232 * name in our ref array. Find and remove the extended
235 return btrfs_del_inode_extref(trans
, root
, name
, name_len
,
236 inode_objectid
, ref_objectid
, index
);
243 * btrfs_insert_inode_extref() - Inserts an extended inode ref into a tree.
245 * The caller must have checked against BTRFS_LINK_MAX already.
247 static int btrfs_insert_inode_extref(struct btrfs_trans_handle
*trans
,
248 struct btrfs_root
*root
,
249 const char *name
, int name_len
,
250 u64 inode_objectid
, u64 ref_objectid
, u64 index
)
252 struct btrfs_inode_extref
*extref
;
254 int ins_len
= name_len
+ sizeof(*extref
);
256 struct btrfs_path
*path
;
257 struct btrfs_key key
;
258 struct extent_buffer
*leaf
;
259 struct btrfs_item
*item
;
261 key
.objectid
= inode_objectid
;
262 key
.type
= BTRFS_INODE_EXTREF_KEY
;
263 key
.offset
= btrfs_extref_hash(ref_objectid
, name
, name_len
);
265 path
= btrfs_alloc_path();
269 ret
= btrfs_insert_empty_item(trans
, root
, path
, &key
,
271 if (ret
== -EEXIST
) {
272 if (btrfs_find_name_in_ext_backref(path
->nodes
[0],
278 btrfs_extend_item(path
, ins_len
);
284 leaf
= path
->nodes
[0];
285 item
= btrfs_item_nr(path
->slots
[0]);
286 ptr
= (unsigned long)btrfs_item_ptr(leaf
, path
->slots
[0], char);
287 ptr
+= btrfs_item_size(leaf
, item
) - ins_len
;
288 extref
= (struct btrfs_inode_extref
*)ptr
;
290 btrfs_set_inode_extref_name_len(path
->nodes
[0], extref
, name_len
);
291 btrfs_set_inode_extref_index(path
->nodes
[0], extref
, index
);
292 btrfs_set_inode_extref_parent(path
->nodes
[0], extref
, ref_objectid
);
294 ptr
= (unsigned long)&extref
->name
;
295 write_extent_buffer(path
->nodes
[0], name
, ptr
, name_len
);
296 btrfs_mark_buffer_dirty(path
->nodes
[0]);
299 btrfs_free_path(path
);
303 /* Will return 0, -ENOMEM, -EMLINK, or -EEXIST or anything from the CoW path */
304 int btrfs_insert_inode_ref(struct btrfs_trans_handle
*trans
,
305 struct btrfs_root
*root
,
306 const char *name
, int name_len
,
307 u64 inode_objectid
, u64 ref_objectid
, u64 index
)
309 struct btrfs_fs_info
*fs_info
= root
->fs_info
;
310 struct btrfs_path
*path
;
311 struct btrfs_key key
;
312 struct btrfs_inode_ref
*ref
;
315 int ins_len
= name_len
+ sizeof(*ref
);
317 key
.objectid
= inode_objectid
;
318 key
.offset
= ref_objectid
;
319 key
.type
= BTRFS_INODE_REF_KEY
;
321 path
= btrfs_alloc_path();
325 path
->skip_release_on_error
= 1;
326 ret
= btrfs_insert_empty_item(trans
, root
, path
, &key
,
328 if (ret
== -EEXIST
) {
330 ref
= btrfs_find_name_in_backref(path
->nodes
[0], path
->slots
[0],
335 old_size
= btrfs_item_size_nr(path
->nodes
[0], path
->slots
[0]);
336 btrfs_extend_item(path
, ins_len
);
337 ref
= btrfs_item_ptr(path
->nodes
[0], path
->slots
[0],
338 struct btrfs_inode_ref
);
339 ref
= (struct btrfs_inode_ref
*)((unsigned long)ref
+ old_size
);
340 btrfs_set_inode_ref_name_len(path
->nodes
[0], ref
, name_len
);
341 btrfs_set_inode_ref_index(path
->nodes
[0], ref
, index
);
342 ptr
= (unsigned long)(ref
+ 1);
344 } else if (ret
< 0) {
345 if (ret
== -EOVERFLOW
) {
346 if (btrfs_find_name_in_backref(path
->nodes
[0],
355 ref
= btrfs_item_ptr(path
->nodes
[0], path
->slots
[0],
356 struct btrfs_inode_ref
);
357 btrfs_set_inode_ref_name_len(path
->nodes
[0], ref
, name_len
);
358 btrfs_set_inode_ref_index(path
->nodes
[0], ref
, index
);
359 ptr
= (unsigned long)(ref
+ 1);
361 write_extent_buffer(path
->nodes
[0], name
, ptr
, name_len
);
362 btrfs_mark_buffer_dirty(path
->nodes
[0]);
365 btrfs_free_path(path
);
367 if (ret
== -EMLINK
) {
368 struct btrfs_super_block
*disk_super
= fs_info
->super_copy
;
369 /* We ran out of space in the ref array. Need to
370 * add an extended ref. */
371 if (btrfs_super_incompat_flags(disk_super
)
372 & BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF
)
373 ret
= btrfs_insert_inode_extref(trans
, root
, name
,
376 ref_objectid
, index
);
382 int btrfs_insert_empty_inode(struct btrfs_trans_handle
*trans
,
383 struct btrfs_root
*root
,
384 struct btrfs_path
*path
, u64 objectid
)
386 struct btrfs_key key
;
388 key
.objectid
= objectid
;
389 key
.type
= BTRFS_INODE_ITEM_KEY
;
392 ret
= btrfs_insert_empty_item(trans
, root
, path
, &key
,
393 sizeof(struct btrfs_inode_item
));
397 int btrfs_lookup_inode(struct btrfs_trans_handle
*trans
, struct btrfs_root
398 *root
, struct btrfs_path
*path
,
399 struct btrfs_key
*location
, int mod
)
401 int ins_len
= mod
< 0 ? -1 : 0;
405 struct extent_buffer
*leaf
;
406 struct btrfs_key found_key
;
408 ret
= btrfs_search_slot(trans
, root
, location
, path
, ins_len
, cow
);
409 if (ret
> 0 && location
->type
== BTRFS_ROOT_ITEM_KEY
&&
410 location
->offset
== (u64
)-1 && path
->slots
[0] != 0) {
411 slot
= path
->slots
[0] - 1;
412 leaf
= path
->nodes
[0];
413 btrfs_item_key_to_cpu(leaf
, &found_key
, slot
);
414 if (found_key
.objectid
== location
->objectid
&&
415 found_key
.type
== location
->type
) {