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 path
->leave_spinning
= 1;
124 ret
= btrfs_search_slot(trans
, root
, &key
, path
, -1, 1);
131 * Sanity check - did we find the right item for this name?
132 * This should always succeed so error here will make the FS
135 extref
= btrfs_find_name_in_ext_backref(path
->nodes
[0], path
->slots
[0],
136 ref_objectid
, name
, name_len
);
138 btrfs_handle_fs_error(root
->fs_info
, -ENOENT
, NULL
);
143 leaf
= path
->nodes
[0];
144 item_size
= btrfs_item_size_nr(leaf
, path
->slots
[0]);
146 *index
= btrfs_inode_extref_index(leaf
, extref
);
148 if (del_len
== item_size
) {
150 * Common case only one ref in the item, remove the
153 ret
= btrfs_del_item(trans
, root
, path
);
157 ptr
= (unsigned long)extref
;
158 item_start
= btrfs_item_ptr_offset(leaf
, path
->slots
[0]);
160 memmove_extent_buffer(leaf
, ptr
, ptr
+ del_len
,
161 item_size
- (ptr
+ del_len
- item_start
));
163 btrfs_truncate_item(path
, item_size
- del_len
, 1);
166 btrfs_free_path(path
);
171 int btrfs_del_inode_ref(struct btrfs_trans_handle
*trans
,
172 struct btrfs_root
*root
,
173 const char *name
, int name_len
,
174 u64 inode_objectid
, u64 ref_objectid
, u64
*index
)
176 struct btrfs_path
*path
;
177 struct btrfs_key key
;
178 struct btrfs_inode_ref
*ref
;
179 struct extent_buffer
*leaf
;
181 unsigned long item_start
;
185 int search_ext_refs
= 0;
186 int del_len
= name_len
+ sizeof(*ref
);
188 key
.objectid
= inode_objectid
;
189 key
.offset
= ref_objectid
;
190 key
.type
= BTRFS_INODE_REF_KEY
;
192 path
= btrfs_alloc_path();
196 path
->leave_spinning
= 1;
198 ret
= btrfs_search_slot(trans
, root
, &key
, path
, -1, 1);
203 } else if (ret
< 0) {
207 ref
= btrfs_find_name_in_backref(path
->nodes
[0], path
->slots
[0], name
,
214 leaf
= path
->nodes
[0];
215 item_size
= btrfs_item_size_nr(leaf
, path
->slots
[0]);
218 *index
= btrfs_inode_ref_index(leaf
, ref
);
220 if (del_len
== item_size
) {
221 ret
= btrfs_del_item(trans
, root
, path
);
224 ptr
= (unsigned long)ref
;
225 sub_item_len
= name_len
+ sizeof(*ref
);
226 item_start
= btrfs_item_ptr_offset(leaf
, path
->slots
[0]);
227 memmove_extent_buffer(leaf
, ptr
, ptr
+ sub_item_len
,
228 item_size
- (ptr
+ sub_item_len
- item_start
));
229 btrfs_truncate_item(path
, item_size
- sub_item_len
, 1);
231 btrfs_free_path(path
);
233 if (search_ext_refs
) {
235 * No refs were found, or we could not find the
236 * name in our ref array. Find and remove the extended
239 return btrfs_del_inode_extref(trans
, root
, name
, name_len
,
240 inode_objectid
, ref_objectid
, index
);
247 * btrfs_insert_inode_extref() - Inserts an extended inode ref into a tree.
249 * The caller must have checked against BTRFS_LINK_MAX already.
251 static int btrfs_insert_inode_extref(struct btrfs_trans_handle
*trans
,
252 struct btrfs_root
*root
,
253 const char *name
, int name_len
,
254 u64 inode_objectid
, u64 ref_objectid
, u64 index
)
256 struct btrfs_inode_extref
*extref
;
258 int ins_len
= name_len
+ sizeof(*extref
);
260 struct btrfs_path
*path
;
261 struct btrfs_key key
;
262 struct extent_buffer
*leaf
;
263 struct btrfs_item
*item
;
265 key
.objectid
= inode_objectid
;
266 key
.type
= BTRFS_INODE_EXTREF_KEY
;
267 key
.offset
= btrfs_extref_hash(ref_objectid
, name
, name_len
);
269 path
= btrfs_alloc_path();
273 path
->leave_spinning
= 1;
274 ret
= btrfs_insert_empty_item(trans
, root
, path
, &key
,
276 if (ret
== -EEXIST
) {
277 if (btrfs_find_name_in_ext_backref(path
->nodes
[0],
283 btrfs_extend_item(path
, ins_len
);
289 leaf
= path
->nodes
[0];
290 item
= btrfs_item_nr(path
->slots
[0]);
291 ptr
= (unsigned long)btrfs_item_ptr(leaf
, path
->slots
[0], char);
292 ptr
+= btrfs_item_size(leaf
, item
) - ins_len
;
293 extref
= (struct btrfs_inode_extref
*)ptr
;
295 btrfs_set_inode_extref_name_len(path
->nodes
[0], extref
, name_len
);
296 btrfs_set_inode_extref_index(path
->nodes
[0], extref
, index
);
297 btrfs_set_inode_extref_parent(path
->nodes
[0], extref
, ref_objectid
);
299 ptr
= (unsigned long)&extref
->name
;
300 write_extent_buffer(path
->nodes
[0], name
, ptr
, name_len
);
301 btrfs_mark_buffer_dirty(path
->nodes
[0]);
304 btrfs_free_path(path
);
308 /* Will return 0, -ENOMEM, -EMLINK, or -EEXIST or anything from the CoW path */
309 int btrfs_insert_inode_ref(struct btrfs_trans_handle
*trans
,
310 struct btrfs_root
*root
,
311 const char *name
, int name_len
,
312 u64 inode_objectid
, u64 ref_objectid
, u64 index
)
314 struct btrfs_fs_info
*fs_info
= root
->fs_info
;
315 struct btrfs_path
*path
;
316 struct btrfs_key key
;
317 struct btrfs_inode_ref
*ref
;
320 int ins_len
= name_len
+ sizeof(*ref
);
322 key
.objectid
= inode_objectid
;
323 key
.offset
= ref_objectid
;
324 key
.type
= BTRFS_INODE_REF_KEY
;
326 path
= btrfs_alloc_path();
330 path
->leave_spinning
= 1;
331 path
->skip_release_on_error
= 1;
332 ret
= btrfs_insert_empty_item(trans
, root
, path
, &key
,
334 if (ret
== -EEXIST
) {
336 ref
= btrfs_find_name_in_backref(path
->nodes
[0], path
->slots
[0],
341 old_size
= btrfs_item_size_nr(path
->nodes
[0], path
->slots
[0]);
342 btrfs_extend_item(path
, ins_len
);
343 ref
= btrfs_item_ptr(path
->nodes
[0], path
->slots
[0],
344 struct btrfs_inode_ref
);
345 ref
= (struct btrfs_inode_ref
*)((unsigned long)ref
+ old_size
);
346 btrfs_set_inode_ref_name_len(path
->nodes
[0], ref
, name_len
);
347 btrfs_set_inode_ref_index(path
->nodes
[0], ref
, index
);
348 ptr
= (unsigned long)(ref
+ 1);
350 } else if (ret
< 0) {
351 if (ret
== -EOVERFLOW
) {
352 if (btrfs_find_name_in_backref(path
->nodes
[0],
361 ref
= btrfs_item_ptr(path
->nodes
[0], path
->slots
[0],
362 struct btrfs_inode_ref
);
363 btrfs_set_inode_ref_name_len(path
->nodes
[0], ref
, name_len
);
364 btrfs_set_inode_ref_index(path
->nodes
[0], ref
, index
);
365 ptr
= (unsigned long)(ref
+ 1);
367 write_extent_buffer(path
->nodes
[0], name
, ptr
, name_len
);
368 btrfs_mark_buffer_dirty(path
->nodes
[0]);
371 btrfs_free_path(path
);
373 if (ret
== -EMLINK
) {
374 struct btrfs_super_block
*disk_super
= fs_info
->super_copy
;
375 /* We ran out of space in the ref array. Need to
376 * add an extended ref. */
377 if (btrfs_super_incompat_flags(disk_super
)
378 & BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF
)
379 ret
= btrfs_insert_inode_extref(trans
, root
, name
,
382 ref_objectid
, index
);
388 int btrfs_insert_empty_inode(struct btrfs_trans_handle
*trans
,
389 struct btrfs_root
*root
,
390 struct btrfs_path
*path
, u64 objectid
)
392 struct btrfs_key key
;
394 key
.objectid
= objectid
;
395 key
.type
= BTRFS_INODE_ITEM_KEY
;
398 ret
= btrfs_insert_empty_item(trans
, root
, path
, &key
,
399 sizeof(struct btrfs_inode_item
));
403 int btrfs_lookup_inode(struct btrfs_trans_handle
*trans
, struct btrfs_root
404 *root
, struct btrfs_path
*path
,
405 struct btrfs_key
*location
, int mod
)
407 int ins_len
= mod
< 0 ? -1 : 0;
411 struct extent_buffer
*leaf
;
412 struct btrfs_key found_key
;
414 ret
= btrfs_search_slot(trans
, root
, location
, path
, ins_len
, cow
);
415 if (ret
> 0 && location
->type
== BTRFS_ROOT_ITEM_KEY
&&
416 location
->offset
== (u64
)-1 && path
->slots
[0] != 0) {
417 slot
= path
->slots
[0] - 1;
418 leaf
= path
->nodes
[0];
419 btrfs_item_key_to_cpu(leaf
, &found_key
, slot
);
420 if (found_key
.objectid
== location
->objectid
&&
421 found_key
.type
== location
->type
) {