1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) STRATO AG 2013. All rights reserved.
6 #include <linux/kthread.h>
7 #include <linux/uuid.h>
8 #include <linux/unaligned.h>
11 #include "transaction.h"
14 #include "accessors.h"
15 #include "uuid-tree.h"
18 static void btrfs_uuid_to_key(const u8
*uuid
, u8 type
, struct btrfs_key
*key
)
21 key
->objectid
= get_unaligned_le64(uuid
);
22 key
->offset
= get_unaligned_le64(uuid
+ sizeof(u64
));
25 /* return -ENOENT for !found, < 0 for errors, or 0 if an item was found */
26 static int btrfs_uuid_tree_lookup(struct btrfs_root
*uuid_root
, const u8
*uuid
,
30 struct btrfs_path
*path
= NULL
;
31 struct extent_buffer
*eb
;
37 if (WARN_ON_ONCE(!uuid_root
)) {
42 path
= btrfs_alloc_path();
48 btrfs_uuid_to_key(uuid
, type
, &key
);
49 ret
= btrfs_search_slot(NULL
, uuid_root
, &key
, path
, 0, 0);
58 slot
= path
->slots
[0];
59 item_size
= btrfs_item_size(eb
, slot
);
60 offset
= btrfs_item_ptr_offset(eb
, slot
);
63 if (!IS_ALIGNED(item_size
, sizeof(u64
))) {
64 btrfs_warn(uuid_root
->fs_info
,
65 "uuid item with illegal size %lu!",
66 (unsigned long)item_size
);
72 read_extent_buffer(eb
, &data
, offset
, sizeof(data
));
73 if (le64_to_cpu(data
) == subid
) {
77 offset
+= sizeof(data
);
78 item_size
-= sizeof(data
);
82 btrfs_free_path(path
);
86 int btrfs_uuid_tree_add(struct btrfs_trans_handle
*trans
, const u8
*uuid
, u8 type
,
89 struct btrfs_fs_info
*fs_info
= trans
->fs_info
;
90 struct btrfs_root
*uuid_root
= fs_info
->uuid_root
;
92 struct btrfs_path
*path
= NULL
;
94 struct extent_buffer
*eb
;
99 ret
= btrfs_uuid_tree_lookup(uuid_root
, uuid
, type
, subid_cpu
);
103 if (WARN_ON_ONCE(!uuid_root
)) {
108 btrfs_uuid_to_key(uuid
, type
, &key
);
110 path
= btrfs_alloc_path();
116 ret
= btrfs_insert_empty_item(trans
, uuid_root
, path
, &key
,
119 /* Add an item for the type for the first time */
121 slot
= path
->slots
[0];
122 offset
= btrfs_item_ptr_offset(eb
, slot
);
123 } else if (ret
== -EEXIST
) {
125 * An item with that type already exists.
126 * Extend the item and store the new subid at the end.
128 btrfs_extend_item(trans
, path
, sizeof(subid_le
));
130 slot
= path
->slots
[0];
131 offset
= btrfs_item_ptr_offset(eb
, slot
);
132 offset
+= btrfs_item_size(eb
, slot
) - sizeof(subid_le
);
135 "insert uuid item failed %d (0x%016llx, 0x%016llx) type %u!",
136 ret
, key
.objectid
, key
.offset
, type
);
141 subid_le
= cpu_to_le64(subid_cpu
);
142 write_extent_buffer(eb
, &subid_le
, offset
, sizeof(subid_le
));
143 btrfs_mark_buffer_dirty(trans
, eb
);
146 btrfs_free_path(path
);
150 int btrfs_uuid_tree_remove(struct btrfs_trans_handle
*trans
, const u8
*uuid
, u8 type
,
153 struct btrfs_fs_info
*fs_info
= trans
->fs_info
;
154 struct btrfs_root
*uuid_root
= fs_info
->uuid_root
;
156 struct btrfs_path
*path
= NULL
;
157 struct btrfs_key key
;
158 struct extent_buffer
*eb
;
160 unsigned long offset
;
162 unsigned long move_dst
;
163 unsigned long move_src
;
164 unsigned long move_len
;
166 if (WARN_ON_ONCE(!uuid_root
)) {
171 btrfs_uuid_to_key(uuid
, type
, &key
);
173 path
= btrfs_alloc_path();
179 ret
= btrfs_search_slot(trans
, uuid_root
, &key
, path
, -1, 1);
181 btrfs_warn(fs_info
, "error %d while searching for uuid item!",
191 slot
= path
->slots
[0];
192 offset
= btrfs_item_ptr_offset(eb
, slot
);
193 item_size
= btrfs_item_size(eb
, slot
);
194 if (!IS_ALIGNED(item_size
, sizeof(u64
))) {
195 btrfs_warn(fs_info
, "uuid item with illegal size %lu!",
196 (unsigned long)item_size
);
203 read_extent_buffer(eb
, &read_subid
, offset
, sizeof(read_subid
));
204 if (le64_to_cpu(read_subid
) == subid
)
206 offset
+= sizeof(read_subid
);
207 item_size
-= sizeof(read_subid
);
215 item_size
= btrfs_item_size(eb
, slot
);
216 if (item_size
== sizeof(subid
)) {
217 ret
= btrfs_del_item(trans
, uuid_root
, path
);
222 move_src
= offset
+ sizeof(subid
);
223 move_len
= item_size
- (move_src
- btrfs_item_ptr_offset(eb
, slot
));
224 memmove_extent_buffer(eb
, move_dst
, move_src
, move_len
);
225 btrfs_truncate_item(trans
, path
, item_size
- sizeof(subid
), 1);
228 btrfs_free_path(path
);
232 static int btrfs_uuid_iter_rem(struct btrfs_root
*uuid_root
, u8
*uuid
, u8 type
,
235 struct btrfs_trans_handle
*trans
;
238 /* 1 - for the uuid item */
239 trans
= btrfs_start_transaction(uuid_root
, 1);
241 ret
= PTR_ERR(trans
);
245 ret
= btrfs_uuid_tree_remove(trans
, uuid
, type
, subid
);
246 btrfs_end_transaction(trans
);
253 * Check if there's an matching subvolume for given UUID
256 * 0 check succeeded, the entry is not outdated
257 * > 0 if the check failed, the caller should remove the entry
258 * < 0 if an error occurred
260 static int btrfs_check_uuid_tree_entry(struct btrfs_fs_info
*fs_info
,
261 const u8
*uuid
, u8 type
, u64 subvolid
)
264 struct btrfs_root
*subvol_root
;
266 if (type
!= BTRFS_UUID_KEY_SUBVOL
&&
267 type
!= BTRFS_UUID_KEY_RECEIVED_SUBVOL
)
270 subvol_root
= btrfs_get_fs_root(fs_info
, subvolid
, true);
271 if (IS_ERR(subvol_root
)) {
272 ret
= PTR_ERR(subvol_root
);
279 case BTRFS_UUID_KEY_SUBVOL
:
280 if (memcmp(uuid
, subvol_root
->root_item
.uuid
, BTRFS_UUID_SIZE
))
283 case BTRFS_UUID_KEY_RECEIVED_SUBVOL
:
284 if (memcmp(uuid
, subvol_root
->root_item
.received_uuid
,
289 btrfs_put_root(subvol_root
);
294 int btrfs_uuid_tree_iterate(struct btrfs_fs_info
*fs_info
)
296 struct btrfs_root
*root
= fs_info
->uuid_root
;
297 struct btrfs_key key
;
298 struct btrfs_path
*path
;
300 struct extent_buffer
*leaf
;
303 unsigned long offset
;
305 path
= btrfs_alloc_path();
316 ret
= btrfs_search_forward(root
, &key
, path
, BTRFS_OLDEST_GENERATION
);
324 if (btrfs_fs_closing(fs_info
)) {
329 leaf
= path
->nodes
[0];
330 slot
= path
->slots
[0];
331 btrfs_item_key_to_cpu(leaf
, &key
, slot
);
333 if (key
.type
!= BTRFS_UUID_KEY_SUBVOL
&&
334 key
.type
!= BTRFS_UUID_KEY_RECEIVED_SUBVOL
)
337 offset
= btrfs_item_ptr_offset(leaf
, slot
);
338 item_size
= btrfs_item_size(leaf
, slot
);
339 if (!IS_ALIGNED(item_size
, sizeof(u64
))) {
341 "uuid item with illegal size %lu!",
342 (unsigned long)item_size
);
346 u8 uuid
[BTRFS_UUID_SIZE
];
350 put_unaligned_le64(key
.objectid
, uuid
);
351 put_unaligned_le64(key
.offset
, uuid
+ sizeof(u64
));
352 read_extent_buffer(leaf
, &subid_le
, offset
,
354 subid_cpu
= le64_to_cpu(subid_le
);
355 ret
= btrfs_check_uuid_tree_entry(fs_info
, uuid
,
356 key
.type
, subid_cpu
);
360 btrfs_release_path(path
);
361 ret
= btrfs_uuid_iter_rem(root
, uuid
, key
.type
,
365 * this might look inefficient, but the
366 * justification is that it is an
367 * exception that check_func returns 1,
368 * and that in the regular case only one
369 * entry per UUID exists.
371 goto again_search_slot
;
373 if (ret
< 0 && ret
!= -ENOENT
)
376 goto again_search_slot
;
378 item_size
-= sizeof(subid_le
);
379 offset
+= sizeof(subid_le
);
383 ret
= btrfs_next_item(root
, path
);
392 btrfs_free_path(path
);
396 int btrfs_uuid_scan_kthread(void *data
)
398 struct btrfs_fs_info
*fs_info
= data
;
399 struct btrfs_root
*root
= fs_info
->tree_root
;
400 struct btrfs_key key
;
401 struct btrfs_path
*path
= NULL
;
403 struct extent_buffer
*eb
;
405 struct btrfs_root_item root_item
;
407 struct btrfs_trans_handle
*trans
= NULL
;
408 bool closing
= false;
410 path
= btrfs_alloc_path();
417 key
.type
= BTRFS_ROOT_ITEM_KEY
;
421 if (btrfs_fs_closing(fs_info
)) {
425 ret
= btrfs_search_forward(root
, &key
, path
,
426 BTRFS_OLDEST_GENERATION
);
433 if (key
.type
!= BTRFS_ROOT_ITEM_KEY
||
434 (key
.objectid
< BTRFS_FIRST_FREE_OBJECTID
&&
435 key
.objectid
!= BTRFS_FS_TREE_OBJECTID
) ||
436 key
.objectid
> BTRFS_LAST_FREE_OBJECTID
)
440 slot
= path
->slots
[0];
441 item_size
= btrfs_item_size(eb
, slot
);
442 if (item_size
< sizeof(root_item
))
445 read_extent_buffer(eb
, &root_item
,
446 btrfs_item_ptr_offset(eb
, slot
),
447 (int)sizeof(root_item
));
448 if (btrfs_root_refs(&root_item
) == 0)
451 if (!btrfs_is_empty_uuid(root_item
.uuid
) ||
452 !btrfs_is_empty_uuid(root_item
.received_uuid
)) {
456 btrfs_release_path(path
);
458 * 1 - subvol uuid item
459 * 1 - received_subvol uuid item
461 trans
= btrfs_start_transaction(fs_info
->uuid_root
, 2);
463 ret
= PTR_ERR(trans
);
471 btrfs_release_path(path
);
472 if (!btrfs_is_empty_uuid(root_item
.uuid
)) {
473 ret
= btrfs_uuid_tree_add(trans
, root_item
.uuid
,
474 BTRFS_UUID_KEY_SUBVOL
,
477 btrfs_warn(fs_info
, "uuid_tree_add failed %d",
483 if (!btrfs_is_empty_uuid(root_item
.received_uuid
)) {
484 ret
= btrfs_uuid_tree_add(trans
,
485 root_item
.received_uuid
,
486 BTRFS_UUID_KEY_RECEIVED_SUBVOL
,
489 btrfs_warn(fs_info
, "uuid_tree_add failed %d",
496 btrfs_release_path(path
);
498 ret
= btrfs_end_transaction(trans
);
504 if (key
.offset
< (u64
)-1) {
506 } else if (key
.type
< BTRFS_ROOT_ITEM_KEY
) {
508 key
.type
= BTRFS_ROOT_ITEM_KEY
;
509 } else if (key
.objectid
< (u64
)-1) {
511 key
.type
= BTRFS_ROOT_ITEM_KEY
;
520 btrfs_free_path(path
);
521 if (trans
&& !IS_ERR(trans
))
522 btrfs_end_transaction(trans
);
524 btrfs_warn(fs_info
, "btrfs_uuid_scan_kthread failed %d", ret
);
526 set_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN
, &fs_info
->flags
);
527 up(&fs_info
->uuid_tree_rescan_sem
);
531 int btrfs_create_uuid_tree(struct btrfs_fs_info
*fs_info
)
533 struct btrfs_trans_handle
*trans
;
534 struct btrfs_root
*tree_root
= fs_info
->tree_root
;
535 struct btrfs_root
*uuid_root
;
536 struct task_struct
*task
;
543 trans
= btrfs_start_transaction(tree_root
, 2);
545 return PTR_ERR(trans
);
547 uuid_root
= btrfs_create_tree(trans
, BTRFS_UUID_TREE_OBJECTID
);
548 if (IS_ERR(uuid_root
)) {
549 ret
= PTR_ERR(uuid_root
);
550 btrfs_abort_transaction(trans
, ret
);
551 btrfs_end_transaction(trans
);
555 fs_info
->uuid_root
= uuid_root
;
557 ret
= btrfs_commit_transaction(trans
);
561 down(&fs_info
->uuid_tree_rescan_sem
);
562 task
= kthread_run(btrfs_uuid_scan_kthread
, fs_info
, "btrfs-uuid");
564 /* fs_info->update_uuid_tree_gen remains 0 in all error case */
565 btrfs_warn(fs_info
, "failed to start uuid_scan task");
566 up(&fs_info
->uuid_tree_rescan_sem
);
567 return PTR_ERR(task
);