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"
40 static int update_seeding_flag(struct btrfs_root
*root
, int set_flag
)
42 struct btrfs_trans_handle
*trans
;
43 struct btrfs_super_block
*disk_super
;
47 disk_super
= root
->fs_info
->super_copy
;
48 super_flags
= btrfs_super_flags(disk_super
);
50 if (super_flags
& BTRFS_SUPER_FLAG_SEEDING
) {
54 warning("seeding flag is already set on %s",
58 super_flags
|= BTRFS_SUPER_FLAG_SEEDING
;
60 if (!(super_flags
& BTRFS_SUPER_FLAG_SEEDING
)) {
61 warning("seeding flag is not set on %s", device
);
64 super_flags
&= ~BTRFS_SUPER_FLAG_SEEDING
;
65 warning("seeding flag cleared on %s", device
);
68 trans
= btrfs_start_transaction(root
, 1);
69 btrfs_set_super_flags(disk_super
, super_flags
);
70 ret
= btrfs_commit_transaction(trans
, root
);
75 static int set_super_incompat_flags(struct btrfs_root
*root
, u64 flags
)
77 struct btrfs_trans_handle
*trans
;
78 struct btrfs_super_block
*disk_super
;
82 disk_super
= root
->fs_info
->super_copy
;
83 super_flags
= btrfs_super_incompat_flags(disk_super
);
85 trans
= btrfs_start_transaction(root
, 1);
86 btrfs_set_super_incompat_flags(disk_super
, super_flags
);
87 ret
= btrfs_commit_transaction(trans
, root
);
92 static int change_header_uuid(struct btrfs_root
*root
, struct extent_buffer
*eb
)
94 struct btrfs_fs_info
*fs_info
= root
->fs_info
;
96 int same_chunk_tree_uuid
= 1;
99 same_fsid
= !memcmp_extent_buffer(eb
, fs_info
->new_fsid
,
100 btrfs_header_fsid(), BTRFS_FSID_SIZE
);
101 same_chunk_tree_uuid
=
102 !memcmp_extent_buffer(eb
, fs_info
->new_chunk_tree_uuid
,
103 btrfs_header_chunk_tree_uuid(eb
),
105 if (same_fsid
&& same_chunk_tree_uuid
)
108 write_extent_buffer(eb
, fs_info
->new_fsid
, btrfs_header_fsid(),
110 if (!same_chunk_tree_uuid
)
111 write_extent_buffer(eb
, fs_info
->new_chunk_tree_uuid
,
112 btrfs_header_chunk_tree_uuid(eb
),
114 ret
= write_tree_block(NULL
, root
, eb
);
119 static int change_extents_uuid(struct btrfs_fs_info
*fs_info
)
121 struct btrfs_root
*root
= fs_info
->extent_root
;
122 struct btrfs_path path
;
123 struct btrfs_key key
= {0, 0, 0};
126 btrfs_init_path(&path
);
128 * Here we don't use transaction as it will takes a lot of reserve
129 * space, and that will make a near-full btrfs unable to change uuid
131 ret
= btrfs_search_slot(NULL
, root
, &key
, &path
, 0, 0);
136 struct btrfs_extent_item
*ei
;
137 struct extent_buffer
*eb
;
141 btrfs_item_key_to_cpu(path
.nodes
[0], &key
, path
.slots
[0]);
142 if (key
.type
!= BTRFS_EXTENT_ITEM_KEY
&&
143 key
.type
!= BTRFS_METADATA_ITEM_KEY
)
145 ei
= btrfs_item_ptr(path
.nodes
[0], path
.slots
[0],
146 struct btrfs_extent_item
);
147 flags
= btrfs_extent_flags(path
.nodes
[0], ei
);
148 if (!(flags
& BTRFS_EXTENT_FLAG_TREE_BLOCK
))
151 bytenr
= key
.objectid
;
152 eb
= read_tree_block(root
, bytenr
, root
->nodesize
, 0);
154 error("failed to read tree block: %llu", bytenr
);
158 ret
= change_header_uuid(root
, eb
);
159 free_extent_buffer(eb
);
161 error("failed to change uuid of tree block: %llu",
166 ret
= btrfs_next_item(root
, &path
);
176 btrfs_release_path(&path
);
180 static int change_device_uuid(struct btrfs_root
*root
, struct extent_buffer
*eb
,
183 struct btrfs_fs_info
*fs_info
= root
->fs_info
;
184 struct btrfs_dev_item
*di
;
187 di
= btrfs_item_ptr(eb
, slot
, struct btrfs_dev_item
);
188 if (!memcmp_extent_buffer(eb
, fs_info
->new_fsid
,
189 (unsigned long)btrfs_device_fsid(di
),
193 write_extent_buffer(eb
, fs_info
->new_fsid
,
194 (unsigned long)btrfs_device_fsid(di
),
196 ret
= write_tree_block(NULL
, root
, eb
);
201 static int change_devices_uuid(struct btrfs_fs_info
*fs_info
)
203 struct btrfs_root
*root
= fs_info
->chunk_root
;
204 struct btrfs_path path
;
205 struct btrfs_key key
= {0, 0, 0};
208 btrfs_init_path(&path
);
209 /* No transaction again */
210 ret
= btrfs_search_slot(NULL
, root
, &key
, &path
, 0, 0);
215 btrfs_item_key_to_cpu(path
.nodes
[0], &key
, path
.slots
[0]);
216 if (key
.type
!= BTRFS_DEV_ITEM_KEY
||
217 key
.objectid
!= BTRFS_DEV_ITEMS_OBJECTID
)
219 ret
= change_device_uuid(root
, path
.nodes
[0], path
.slots
[0]);
223 ret
= btrfs_next_item(root
, &path
);
232 btrfs_release_path(&path
);
236 static int change_fsid_prepare(struct btrfs_fs_info
*fs_info
)
238 struct btrfs_root
*tree_root
= fs_info
->tree_root
;
239 u64 flags
= btrfs_super_flags(fs_info
->super_copy
);
242 flags
|= BTRFS_SUPER_FLAG_CHANGING_FSID
;
243 btrfs_set_super_flags(fs_info
->super_copy
, flags
);
245 memcpy(fs_info
->super_copy
->fsid
, fs_info
->new_fsid
, BTRFS_FSID_SIZE
);
246 ret
= write_all_supers(tree_root
);
250 /* also restore new chunk_tree_id into tree_root for restore */
251 write_extent_buffer(tree_root
->node
, fs_info
->new_chunk_tree_uuid
,
252 btrfs_header_chunk_tree_uuid(tree_root
->node
),
254 return write_tree_block(NULL
, tree_root
, tree_root
->node
);
257 static int change_fsid_done(struct btrfs_fs_info
*fs_info
)
259 u64 flags
= btrfs_super_flags(fs_info
->super_copy
);
261 flags
&= ~BTRFS_SUPER_FLAG_CHANGING_FSID
;
262 btrfs_set_super_flags(fs_info
->super_copy
, flags
);
264 return write_all_supers(fs_info
->tree_root
);
268 * Return 0 for no unfinished fsid change.
269 * Return >0 for unfinished fsid change, and restore unfinished fsid/
270 * chunk_tree_id into fsid_ret/chunk_id_ret.
272 static int check_unfinished_fsid_change(struct btrfs_fs_info
*fs_info
,
273 uuid_t fsid_ret
, uuid_t chunk_id_ret
)
275 struct btrfs_root
*tree_root
= fs_info
->tree_root
;
276 u64 flags
= btrfs_super_flags(fs_info
->super_copy
);
278 if (flags
& BTRFS_SUPER_FLAG_CHANGING_FSID
) {
279 memcpy(fsid_ret
, fs_info
->super_copy
->fsid
, BTRFS_FSID_SIZE
);
280 read_extent_buffer(tree_root
->node
, chunk_id_ret
,
281 btrfs_header_chunk_tree_uuid(tree_root
->node
),
289 * Change fsid of a given fs.
291 * If new_fsid_str is not given, use a random generated UUID.
292 * Caller should check new_fsid_str is valid
294 static int change_uuid(struct btrfs_fs_info
*fs_info
, const char *new_fsid_str
)
299 char uuid_buf
[BTRFS_UUID_UNPARSED_SIZE
];
302 if (check_unfinished_fsid_change(fs_info
, new_fsid
, new_chunk_id
)) {
306 uuid_parse(new_fsid_str
, tmp
);
307 if (memcmp(tmp
, new_fsid
, BTRFS_FSID_SIZE
)) {
309 "new fsid %s is not the same with unfinished fsid change",
316 uuid_parse(new_fsid_str
, new_fsid
);
318 uuid_generate(new_fsid
);
320 uuid_generate(new_chunk_id
);
322 fs_info
->new_fsid
= new_fsid
;
323 fs_info
->new_chunk_tree_uuid
= new_chunk_id
;
325 memcpy(old_fsid
, (const char*)fs_info
->fsid
, BTRFS_UUID_SIZE
);
326 uuid_unparse(old_fsid
, uuid_buf
);
327 printf("Current fsid: %s\n", uuid_buf
);
329 uuid_unparse(new_fsid
, uuid_buf
);
330 printf("New fsid: %s\n", uuid_buf
);
331 /* Now we can begin fsid change */
332 printf("Set superblock flag CHANGING_FSID\n");
333 ret
= change_fsid_prepare(fs_info
);
337 /* Change extents first */
338 printf("Change fsid in extents\n");
339 ret
= change_extents_uuid(fs_info
);
341 error("failed to change UUID of metadata: %d", ret
);
346 printf("Change fsid on devices\n");
347 ret
= change_devices_uuid(fs_info
);
349 error("failed to change UUID of devices: %d", ret
);
353 /* Last, change fsid in super */
354 memcpy(fs_info
->fs_devices
->fsid
, fs_info
->new_fsid
,
356 memcpy(fs_info
->super_copy
->fsid
, fs_info
->new_fsid
,
358 ret
= write_all_supers(fs_info
->tree_root
);
362 /* Now fsid change is done */
363 printf("Clear superblock flag CHANGING_FSID\n");
364 ret
= change_fsid_done(fs_info
);
365 fs_info
->new_fsid
= NULL
;
366 fs_info
->new_chunk_tree_uuid
= NULL
;
367 printf("Fsid change finished\n");
372 static void print_usage(void)
374 printf("usage: btrfstune [options] device\n");
375 printf("\t-S value\tpositive value will enable seeding, zero to disable, negative is not allowed\n");
376 printf("\t-r \t\tenable extended inode refs\n");
377 printf("\t-x \t\tenable skinny metadata extent refs\n");
378 printf("\t-n \t\tenable no-holes feature (more efficient sparse file representation)\n");
379 printf("\t-f \t\tforce to do dangerous operation, make sure that you are aware of the dangers\n");
380 printf("\t-u \t\tchange fsid, use a random one\n");
381 printf("\t-U UUID\t\tchange fsid to UUID\n");
384 int main(int argc
, char *argv
[])
386 struct btrfs_root
*root
;
387 unsigned ctree_flags
= OPEN_CTREE_WRITES
;
390 int seeding_flag
= 0;
391 u64 seeding_value
= 0;
393 char *new_fsid_str
= NULL
;
398 static const struct option long_options
[] = {
399 { "help", no_argument
, NULL
, GETOPT_VAL_HELP
},
402 int c
= getopt_long(argc
, argv
, "S:rxfuU:n", long_options
, NULL
);
409 seeding_value
= arg_strtou64(optarg
);
412 super_flags
|= BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF
;
415 super_flags
|= BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA
;
418 super_flags
|= BTRFS_FEATURE_INCOMPAT_NO_HOLES
;
424 ctree_flags
|= OPEN_CTREE_IGNORE_FSID_MISMATCH
;
425 new_fsid_str
= optarg
;
428 ctree_flags
|= OPEN_CTREE_IGNORE_FSID_MISMATCH
;
431 case GETOPT_VAL_HELP
:
434 return c
!= GETOPT_VAL_HELP
;
439 device
= argv
[optind
];
440 if (check_argc_exact(argc
- optind
, 1)) {
445 if (random_fsid
&& new_fsid_str
) {
446 error("random fsid can't be used with specified fsid");
449 if (!super_flags
&& !seeding_flag
&& !(random_fsid
|| new_fsid_str
)) {
450 error("at least one option should be specified");
458 ret
= uuid_parse(new_fsid_str
, tmp
);
460 error("could not parse UUID: %s", new_fsid_str
);
463 if (!test_uuid_unique(new_fsid_str
)) {
464 error("fsid %s is not unique", new_fsid_str
);
469 ret
= check_mounted(device
);
471 error("could not check mount status of %s: %s", device
,
475 error("%s is mounted", device
);
479 root
= open_ctree(device
, 0, ctree_flags
);
482 error("open ctree failed");
487 if (!seeding_value
&& !force
) {
489 "this is dangerous, clearing the seeding flag may cause the derived device not to be mountable!");
490 ret
= ask_user("We are going to clear the seeding flag, are you sure?");
492 fprintf(stderr
, "Clear seeding flag canceled\n");
498 ret
= update_seeding_flag(root
, seeding_value
);
505 ret
= set_super_incompat_flags(root
, super_flags
);
511 if (random_fsid
|| new_fsid_str
) {
514 "it's highly recommended to run 'btrfs check' before this operation");
516 "also canceling running UUID change progress may cause corruption");
517 ret
= ask_user("We are going to change UUID, are your sure?");
519 fprintf(stderr
, "UUID change canceled\n");
524 ret
= change_uuid(root
->fs_info
, new_fsid_str
);
530 if (success
== total
) {
533 root
->fs_info
->readonly
= 1;
535 error("btrfstune failed");
539 btrfs_close_all_devices();