2 * Copyright (C) 2008 Oracle. All rights reserved.
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.
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.
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.
21 #include <sys/types.h>
26 #include <uuid/uuid.h>
29 #include "kerncompat.h"
32 #include "transaction.h"
39 static int update_seeding_flag(struct btrfs_root
*root
, int set_flag
)
41 struct btrfs_trans_handle
*trans
;
42 struct btrfs_super_block
*disk_super
;
46 disk_super
= root
->fs_info
->super_copy
;
47 super_flags
= btrfs_super_flags(disk_super
);
49 if (super_flags
& BTRFS_SUPER_FLAG_SEEDING
) {
53 fprintf(stderr
, "seeding flag is already set on %s\n", device
);
56 super_flags
|= BTRFS_SUPER_FLAG_SEEDING
;
58 if (!(super_flags
& BTRFS_SUPER_FLAG_SEEDING
)) {
59 fprintf(stderr
, "seeding flag is not set on %s\n",
63 super_flags
&= ~BTRFS_SUPER_FLAG_SEEDING
;
64 fprintf(stderr
, "Warning: Seeding flag cleared.\n");
67 trans
= btrfs_start_transaction(root
, 1);
68 btrfs_set_super_flags(disk_super
, super_flags
);
69 ret
= btrfs_commit_transaction(trans
, root
);
74 static int set_super_incompat_flags(struct btrfs_root
*root
, u64 flags
)
76 struct btrfs_trans_handle
*trans
;
77 struct btrfs_super_block
*disk_super
;
81 disk_super
= root
->fs_info
->super_copy
;
82 super_flags
= btrfs_super_incompat_flags(disk_super
);
84 trans
= btrfs_start_transaction(root
, 1);
85 btrfs_set_super_incompat_flags(disk_super
, super_flags
);
86 ret
= btrfs_commit_transaction(trans
, root
);
91 static int change_header_uuid(struct btrfs_root
*root
, struct extent_buffer
*eb
)
93 struct btrfs_fs_info
*fs_info
= root
->fs_info
;
95 int same_chunk_tree_uuid
= 1;
98 same_fsid
= !memcmp_extent_buffer(eb
, fs_info
->new_fsid
,
99 btrfs_header_fsid(), BTRFS_FSID_SIZE
);
100 same_chunk_tree_uuid
=
101 !memcmp_extent_buffer(eb
, fs_info
->new_chunk_tree_uuid
,
102 btrfs_header_chunk_tree_uuid(eb
),
104 if (same_fsid
&& same_chunk_tree_uuid
)
107 write_extent_buffer(eb
, fs_info
->new_fsid
, btrfs_header_fsid(),
109 if (!same_chunk_tree_uuid
)
110 write_extent_buffer(eb
, fs_info
->new_chunk_tree_uuid
,
111 btrfs_header_chunk_tree_uuid(eb
),
113 ret
= write_tree_block(NULL
, root
, eb
);
118 static int change_extents_uuid(struct btrfs_fs_info
*fs_info
)
120 struct btrfs_root
*root
= fs_info
->extent_root
;
121 struct btrfs_path
*path
;
122 struct btrfs_key key
= {0, 0, 0};
125 path
= btrfs_alloc_path();
130 * Here we don't use transaction as it will takes a lot of reserve
131 * space, and that will make a near-full btrfs unable to change uuid
133 ret
= btrfs_search_slot(NULL
, root
, &key
, path
, 0, 0);
138 struct btrfs_extent_item
*ei
;
139 struct extent_buffer
*eb
;
143 btrfs_item_key_to_cpu(path
->nodes
[0], &key
, path
->slots
[0]);
144 if (key
.type
!= BTRFS_EXTENT_ITEM_KEY
&&
145 key
.type
!= BTRFS_METADATA_ITEM_KEY
)
147 ei
= btrfs_item_ptr(path
->nodes
[0], path
->slots
[0],
148 struct btrfs_extent_item
);
149 flags
= btrfs_extent_flags(path
->nodes
[0], ei
);
150 if (!(flags
& BTRFS_EXTENT_FLAG_TREE_BLOCK
))
153 bytenr
= key
.objectid
;
154 eb
= read_tree_block(root
, bytenr
, root
->nodesize
, 0);
156 fprintf(stderr
, "Failed to read tree block: %llu\n",
161 ret
= change_header_uuid(root
, eb
);
162 free_extent_buffer(eb
);
164 fprintf(stderr
, "Failed to change uuid of tree block: %llu\n",
169 ret
= btrfs_next_item(root
, path
);
179 btrfs_free_path(path
);
183 static int change_device_uuid(struct btrfs_root
*root
, struct extent_buffer
*eb
,
186 struct btrfs_fs_info
*fs_info
= root
->fs_info
;
187 struct btrfs_dev_item
*di
;
190 di
= btrfs_item_ptr(eb
, slot
, struct btrfs_dev_item
);
191 if (!memcmp_extent_buffer(eb
, fs_info
->new_fsid
,
192 (unsigned long)btrfs_device_fsid(di
),
196 write_extent_buffer(eb
, fs_info
->new_fsid
,
197 (unsigned long)btrfs_device_fsid(di
),
199 ret
= write_tree_block(NULL
, root
, eb
);
204 static int change_devices_uuid(struct btrfs_fs_info
*fs_info
)
206 struct btrfs_root
*root
= fs_info
->chunk_root
;
207 struct btrfs_path
*path
;
208 struct btrfs_key key
= {0, 0, 0};
211 path
= btrfs_alloc_path();
214 /* No transaction again */
215 ret
= btrfs_search_slot(NULL
, root
, &key
, path
, 0, 0);
220 btrfs_item_key_to_cpu(path
->nodes
[0], &key
, path
->slots
[0]);
221 if (key
.type
!= BTRFS_DEV_ITEM_KEY
||
222 key
.objectid
!= BTRFS_DEV_ITEMS_OBJECTID
)
224 ret
= change_device_uuid(root
, path
->nodes
[0], path
->slots
[0]);
228 ret
= btrfs_next_item(root
, path
);
237 btrfs_free_path(path
);
241 static int change_fsid_prepare(struct btrfs_fs_info
*fs_info
)
243 struct btrfs_root
*tree_root
= fs_info
->tree_root
;
244 u64 flags
= btrfs_super_flags(fs_info
->super_copy
);
247 flags
|= BTRFS_SUPER_FLAG_CHANGING_FSID
;
248 btrfs_set_super_flags(fs_info
->super_copy
, flags
);
250 memcpy(fs_info
->super_copy
->fsid
, fs_info
->new_fsid
, BTRFS_FSID_SIZE
);
251 ret
= write_all_supers(tree_root
);
255 /* also restore new chunk_tree_id into tree_root for restore */
256 write_extent_buffer(tree_root
->node
, fs_info
->new_chunk_tree_uuid
,
257 btrfs_header_chunk_tree_uuid(tree_root
->node
),
259 return write_tree_block(NULL
, tree_root
, tree_root
->node
);
262 static int change_fsid_done(struct btrfs_fs_info
*fs_info
)
264 u64 flags
= btrfs_super_flags(fs_info
->super_copy
);
266 flags
&= ~BTRFS_SUPER_FLAG_CHANGING_FSID
;
267 btrfs_set_super_flags(fs_info
->super_copy
, flags
);
269 return write_all_supers(fs_info
->tree_root
);
273 * Return 0 for no unfinished fsid change.
274 * Return >0 for unfinished fsid change, and restore unfinished fsid/
275 * chunk_tree_id into fsid_ret/chunk_id_ret.
277 static int check_unfinished_fsid_change(struct btrfs_fs_info
*fs_info
,
278 uuid_t fsid_ret
, uuid_t chunk_id_ret
)
280 struct btrfs_root
*tree_root
= fs_info
->tree_root
;
281 u64 flags
= btrfs_super_flags(fs_info
->super_copy
);
283 if (flags
& BTRFS_SUPER_FLAG_CHANGING_FSID
) {
284 memcpy(fsid_ret
, fs_info
->super_copy
->fsid
, BTRFS_FSID_SIZE
);
285 read_extent_buffer(tree_root
->node
, chunk_id_ret
,
286 btrfs_header_chunk_tree_uuid(tree_root
->node
),
294 * Change fsid of a given fs.
296 * If new_fsid_str is not given, use a random generated UUID.
297 * Caller should check new_fsid_str is valid
299 static int change_uuid(struct btrfs_fs_info
*fs_info
, const char *new_fsid_str
)
304 char uuid_buf
[BTRFS_UUID_UNPARSED_SIZE
];
307 if (check_unfinished_fsid_change(fs_info
, new_fsid
, new_chunk_id
)) {
311 uuid_parse(new_fsid_str
, tmp
);
312 if (memcmp(tmp
, new_fsid
, BTRFS_FSID_SIZE
)) {
314 "ERROR: New fsid %s is not the same with unfinished fsid change\n",
321 uuid_parse(new_fsid_str
, new_fsid
);
323 uuid_generate(new_fsid
);
325 uuid_generate(new_chunk_id
);
327 fs_info
->new_fsid
= new_fsid
;
328 fs_info
->new_chunk_tree_uuid
= new_chunk_id
;
330 memcpy(old_fsid
, (const char*)fs_info
->fsid
, BTRFS_UUID_SIZE
);
331 uuid_unparse(old_fsid
, uuid_buf
);
332 printf("Current fsid: %s\n", uuid_buf
);
334 uuid_unparse(new_fsid
, uuid_buf
);
335 printf("New fsid: %s\n", uuid_buf
);
336 /* Now we can begin fsid change */
337 printf("Set superblock flag CHANGING_FSID\n");
338 ret
= change_fsid_prepare(fs_info
);
342 /* Change extents first */
343 printf("Change fsid in extents\n");
344 ret
= change_extents_uuid(fs_info
);
346 fprintf(stderr
, "Failed to change UUID of metadata\n");
351 printf("Change fsid on devices\n");
352 ret
= change_devices_uuid(fs_info
);
354 fprintf(stderr
, "Failed to change UUID of devices\n");
358 /* Last, change fsid in super */
359 memcpy(fs_info
->fs_devices
->fsid
, fs_info
->new_fsid
,
361 memcpy(fs_info
->super_copy
->fsid
, fs_info
->new_fsid
,
363 ret
= write_all_supers(fs_info
->tree_root
);
367 /* Now fsid change is done */
368 printf("Clear superblock flag CHANGING_FSID\n");
369 ret
= change_fsid_done(fs_info
);
370 fs_info
->new_fsid
= NULL
;
371 fs_info
->new_chunk_tree_uuid
= NULL
;
372 printf("Fsid change finished\n");
377 static void print_usage(void)
379 fprintf(stderr
, "usage: btrfstune [options] device\n");
380 fprintf(stderr
, "\t-S value\tpositive value will enable seeding, zero to disable, negative is not allowed\n");
381 fprintf(stderr
, "\t-r \t\tenable extended inode refs\n");
382 fprintf(stderr
, "\t-x \t\tenable skinny metadata extent refs\n");
383 fprintf(stderr
, "\t-n \t\tenable no-holes feature (more efficient sparse file representation)\n");
384 fprintf(stderr
, "\t-f \t\tforce to do dangerous operation, make sure that you are aware of the dangers\n");
385 fprintf(stderr
, "\t-u \t\tchange fsid, use a random one\n");
386 fprintf(stderr
, "\t-U UUID\t\tchange fsid to UUID\n");
389 int main(int argc
, char *argv
[])
391 struct btrfs_root
*root
;
392 enum btrfs_open_ctree_flags ctree_flags
= OPEN_CTREE_WRITES
;
395 int seeding_flag
= 0;
396 u64 seeding_value
= 0;
398 char *new_fsid_str
= NULL
;
404 static const struct option long_options
[] = {
405 { "help", no_argument
, NULL
, GETOPT_VAL_HELP
},
408 int c
= getopt_long(argc
, argv
, "S:rxfuU:n", long_options
, NULL
);
415 seeding_value
= arg_strtou64(optarg
);
418 super_flags
|= BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF
;
421 super_flags
|= BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA
;
424 super_flags
|= BTRFS_FEATURE_INCOMPAT_NO_HOLES
;
430 ctree_flags
|= OPEN_CTREE_IGNORE_FSID_MISMATCH
;
431 new_fsid_str
= optarg
;
434 ctree_flags
|= OPEN_CTREE_IGNORE_FSID_MISMATCH
;
437 case GETOPT_VAL_HELP
:
440 return c
!= GETOPT_VAL_HELP
;
445 device
= argv
[optind
];
446 if (check_argc_exact(argc
- optind
, 1)) {
451 if (random_fsid
&& new_fsid_str
) {
453 "ERROR: Random fsid can't be used with specified fsid\n");
456 if (!super_flags
&& !seeding_flag
&& !(random_fsid
|| new_fsid_str
)) {
458 "ERROR: At least one option should be assigned.\n");
466 ret
= uuid_parse(new_fsid_str
, tmp
);
469 "ERROR: Could not parse UUID: %s\n",
473 if (!test_uuid_unique(new_fsid_str
)) {
475 "ERROR: Fsid %s is not unique\n",
481 ret
= check_mounted(device
);
483 fprintf(stderr
, "Could not check mount status: %s\n",
487 fprintf(stderr
, "%s is mounted\n", device
);
491 root
= open_ctree(device
, 0, ctree_flags
);
494 fprintf(stderr
, "Open ctree failed\n");
499 if (!seeding_value
&& !force
) {
500 fprintf(stderr
, "Warning: This is dangerous, clearing the seeding flag may cause the derived device not to be mountable!\n");
501 ret
= ask_user("We are going to clear the seeding flag, are you sure?");
503 fprintf(stderr
, "Clear seeding flag canceled\n");
509 ret
= update_seeding_flag(root
, seeding_value
);
516 ret
= set_super_incompat_flags(root
, super_flags
);
522 if (random_fsid
|| new_fsid_str
) {
525 "Warning: It's highly recommended to run 'btrfs check' before this operation\n");
527 "Also canceling running UUID change progress may cause corruption\n");
528 ret
= ask_user("We are going to change UUID, are your sure?");
530 fprintf(stderr
, "UUID change canceled\n");
535 ret
= change_uuid(root
->fs_info
, new_fsid_str
);
541 if (success
== total
) {
544 root
->fs_info
->readonly
= 1;
546 fprintf(stderr
, "btrfstune failed\n");
550 btrfs_close_all_devices();