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 warning("seeding flag is already set on %s",
57 super_flags
|= BTRFS_SUPER_FLAG_SEEDING
;
59 if (!(super_flags
& BTRFS_SUPER_FLAG_SEEDING
)) {
60 warning("seeding flag is not set on %s", device
);
63 super_flags
&= ~BTRFS_SUPER_FLAG_SEEDING
;
64 warning("seeding flag cleared on %s", device
);
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 btrfs_init_path(&path
);
127 * Here we don't use transaction as it will takes a lot of reserve
128 * space, and that will make a near-full btrfs unable to change uuid
130 ret
= btrfs_search_slot(NULL
, root
, &key
, &path
, 0, 0);
135 struct btrfs_extent_item
*ei
;
136 struct extent_buffer
*eb
;
140 btrfs_item_key_to_cpu(path
.nodes
[0], &key
, path
.slots
[0]);
141 if (key
.type
!= BTRFS_EXTENT_ITEM_KEY
&&
142 key
.type
!= BTRFS_METADATA_ITEM_KEY
)
144 ei
= btrfs_item_ptr(path
.nodes
[0], path
.slots
[0],
145 struct btrfs_extent_item
);
146 flags
= btrfs_extent_flags(path
.nodes
[0], ei
);
147 if (!(flags
& BTRFS_EXTENT_FLAG_TREE_BLOCK
))
150 bytenr
= key
.objectid
;
151 eb
= read_tree_block(root
, bytenr
, root
->nodesize
, 0);
153 error("failed to read tree block: %llu", bytenr
);
157 ret
= change_header_uuid(root
, eb
);
158 free_extent_buffer(eb
);
160 error("failed to change uuid of tree block: %llu",
165 ret
= btrfs_next_item(root
, &path
);
175 btrfs_release_path(&path
);
179 static int change_device_uuid(struct btrfs_root
*root
, struct extent_buffer
*eb
,
182 struct btrfs_fs_info
*fs_info
= root
->fs_info
;
183 struct btrfs_dev_item
*di
;
186 di
= btrfs_item_ptr(eb
, slot
, struct btrfs_dev_item
);
187 if (!memcmp_extent_buffer(eb
, fs_info
->new_fsid
,
188 (unsigned long)btrfs_device_fsid(di
),
192 write_extent_buffer(eb
, fs_info
->new_fsid
,
193 (unsigned long)btrfs_device_fsid(di
),
195 ret
= write_tree_block(NULL
, root
, eb
);
200 static int change_devices_uuid(struct btrfs_fs_info
*fs_info
)
202 struct btrfs_root
*root
= fs_info
->chunk_root
;
203 struct btrfs_path path
;
204 struct btrfs_key key
= {0, 0, 0};
207 btrfs_init_path(&path
);
208 /* No transaction again */
209 ret
= btrfs_search_slot(NULL
, root
, &key
, &path
, 0, 0);
214 btrfs_item_key_to_cpu(path
.nodes
[0], &key
, path
.slots
[0]);
215 if (key
.type
!= BTRFS_DEV_ITEM_KEY
||
216 key
.objectid
!= BTRFS_DEV_ITEMS_OBJECTID
)
218 ret
= change_device_uuid(root
, path
.nodes
[0], path
.slots
[0]);
222 ret
= btrfs_next_item(root
, &path
);
231 btrfs_release_path(&path
);
235 static int change_fsid_prepare(struct btrfs_fs_info
*fs_info
)
237 struct btrfs_root
*tree_root
= fs_info
->tree_root
;
238 u64 flags
= btrfs_super_flags(fs_info
->super_copy
);
241 flags
|= BTRFS_SUPER_FLAG_CHANGING_FSID
;
242 btrfs_set_super_flags(fs_info
->super_copy
, flags
);
244 memcpy(fs_info
->super_copy
->fsid
, fs_info
->new_fsid
, BTRFS_FSID_SIZE
);
245 ret
= write_all_supers(tree_root
);
249 /* also restore new chunk_tree_id into tree_root for restore */
250 write_extent_buffer(tree_root
->node
, fs_info
->new_chunk_tree_uuid
,
251 btrfs_header_chunk_tree_uuid(tree_root
->node
),
253 return write_tree_block(NULL
, tree_root
, tree_root
->node
);
256 static int change_fsid_done(struct btrfs_fs_info
*fs_info
)
258 u64 flags
= btrfs_super_flags(fs_info
->super_copy
);
260 flags
&= ~BTRFS_SUPER_FLAG_CHANGING_FSID
;
261 btrfs_set_super_flags(fs_info
->super_copy
, flags
);
263 return write_all_supers(fs_info
->tree_root
);
267 * Return 0 for no unfinished fsid change.
268 * Return >0 for unfinished fsid change, and restore unfinished fsid/
269 * chunk_tree_id into fsid_ret/chunk_id_ret.
271 static int check_unfinished_fsid_change(struct btrfs_fs_info
*fs_info
,
272 uuid_t fsid_ret
, uuid_t chunk_id_ret
)
274 struct btrfs_root
*tree_root
= fs_info
->tree_root
;
275 u64 flags
= btrfs_super_flags(fs_info
->super_copy
);
277 if (flags
& BTRFS_SUPER_FLAG_CHANGING_FSID
) {
278 memcpy(fsid_ret
, fs_info
->super_copy
->fsid
, BTRFS_FSID_SIZE
);
279 read_extent_buffer(tree_root
->node
, chunk_id_ret
,
280 btrfs_header_chunk_tree_uuid(tree_root
->node
),
288 * Change fsid of a given fs.
290 * If new_fsid_str is not given, use a random generated UUID.
291 * Caller should check new_fsid_str is valid
293 static int change_uuid(struct btrfs_fs_info
*fs_info
, const char *new_fsid_str
)
298 char uuid_buf
[BTRFS_UUID_UNPARSED_SIZE
];
301 if (check_unfinished_fsid_change(fs_info
, new_fsid
, new_chunk_id
)) {
305 uuid_parse(new_fsid_str
, tmp
);
306 if (memcmp(tmp
, new_fsid
, BTRFS_FSID_SIZE
)) {
308 "new fsid %s is not the same with unfinished fsid change",
315 uuid_parse(new_fsid_str
, new_fsid
);
317 uuid_generate(new_fsid
);
319 uuid_generate(new_chunk_id
);
321 fs_info
->new_fsid
= new_fsid
;
322 fs_info
->new_chunk_tree_uuid
= new_chunk_id
;
324 memcpy(old_fsid
, (const char*)fs_info
->fsid
, BTRFS_UUID_SIZE
);
325 uuid_unparse(old_fsid
, uuid_buf
);
326 printf("Current fsid: %s\n", uuid_buf
);
328 uuid_unparse(new_fsid
, uuid_buf
);
329 printf("New fsid: %s\n", uuid_buf
);
330 /* Now we can begin fsid change */
331 printf("Set superblock flag CHANGING_FSID\n");
332 ret
= change_fsid_prepare(fs_info
);
336 /* Change extents first */
337 printf("Change fsid in extents\n");
338 ret
= change_extents_uuid(fs_info
);
340 error("failed to change UUID of metadata: %d", ret
);
345 printf("Change fsid on devices\n");
346 ret
= change_devices_uuid(fs_info
);
348 error("failed to change UUID of devices: %d", ret
);
352 /* Last, change fsid in super */
353 memcpy(fs_info
->fs_devices
->fsid
, fs_info
->new_fsid
,
355 memcpy(fs_info
->super_copy
->fsid
, fs_info
->new_fsid
,
357 ret
= write_all_supers(fs_info
->tree_root
);
361 /* Now fsid change is done */
362 printf("Clear superblock flag CHANGING_FSID\n");
363 ret
= change_fsid_done(fs_info
);
364 fs_info
->new_fsid
= NULL
;
365 fs_info
->new_chunk_tree_uuid
= NULL
;
366 printf("Fsid change finished\n");
371 static void print_usage(void)
373 printf("usage: btrfstune [options] device\n");
374 printf("\t-S value\tpositive value will enable seeding, zero to disable, negative is not allowed\n");
375 printf("\t-r \t\tenable extended inode refs\n");
376 printf("\t-x \t\tenable skinny metadata extent refs\n");
377 printf("\t-n \t\tenable no-holes feature (more efficient sparse file representation)\n");
378 printf("\t-f \t\tforce to do dangerous operation, make sure that you are aware of the dangers\n");
379 printf("\t-u \t\tchange fsid, use a random one\n");
380 printf("\t-U UUID\t\tchange fsid to UUID\n");
383 int main(int argc
, char *argv
[])
385 struct btrfs_root
*root
;
386 unsigned ctree_flags
= OPEN_CTREE_WRITES
;
389 int seeding_flag
= 0;
390 u64 seeding_value
= 0;
392 char *new_fsid_str
= NULL
;
397 static const struct option long_options
[] = {
398 { "help", no_argument
, NULL
, GETOPT_VAL_HELP
},
401 int c
= getopt_long(argc
, argv
, "S:rxfuU:n", long_options
, NULL
);
408 seeding_value
= arg_strtou64(optarg
);
411 super_flags
|= BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF
;
414 super_flags
|= BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA
;
417 super_flags
|= BTRFS_FEATURE_INCOMPAT_NO_HOLES
;
423 ctree_flags
|= OPEN_CTREE_IGNORE_FSID_MISMATCH
;
424 new_fsid_str
= optarg
;
427 ctree_flags
|= OPEN_CTREE_IGNORE_FSID_MISMATCH
;
430 case GETOPT_VAL_HELP
:
433 return c
!= GETOPT_VAL_HELP
;
438 device
= argv
[optind
];
439 if (check_argc_exact(argc
- optind
, 1)) {
444 if (random_fsid
&& new_fsid_str
) {
445 error("random fsid can't be used with specified fsid");
448 if (!super_flags
&& !seeding_flag
&& !(random_fsid
|| new_fsid_str
)) {
449 error("at least one option should be specified");
457 ret
= uuid_parse(new_fsid_str
, tmp
);
459 error("could not parse UUID: %s", new_fsid_str
);
462 if (!test_uuid_unique(new_fsid_str
)) {
463 error("fsid %s is not unique", new_fsid_str
);
468 ret
= check_mounted(device
);
470 error("could not check mount status of %s: %s", device
,
474 error("%s is mounted", device
);
478 root
= open_ctree(device
, 0, ctree_flags
);
481 error("open ctree failed");
486 if (!seeding_value
&& !force
) {
488 "this is dangerous, clearing the seeding flag may cause the derived device not to be mountable!");
489 ret
= ask_user("We are going to clear the seeding flag, are you sure?");
491 fprintf(stderr
, "Clear seeding flag canceled\n");
497 ret
= update_seeding_flag(root
, seeding_value
);
504 ret
= set_super_incompat_flags(root
, super_flags
);
510 if (random_fsid
|| new_fsid_str
) {
513 "it's highly recommended to run 'btrfs check' before this operation");
515 "also canceling running UUID change progress may cause corruption");
516 ret
= ask_user("We are going to change UUID, are your sure?");
518 fprintf(stderr
, "UUID change canceled\n");
523 ret
= change_uuid(root
->fs_info
, new_fsid_str
);
529 if (success
== total
) {
532 root
->fs_info
->readonly
= 1;
534 error("btrfstune failed");
538 btrfs_close_all_devices();