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 BUG_ON(IS_ERR(trans
));
70 btrfs_set_super_flags(disk_super
, super_flags
);
71 ret
= btrfs_commit_transaction(trans
, root
);
76 static int set_super_incompat_flags(struct btrfs_root
*root
, u64 flags
)
78 struct btrfs_trans_handle
*trans
;
79 struct btrfs_super_block
*disk_super
;
83 disk_super
= root
->fs_info
->super_copy
;
84 super_flags
= btrfs_super_incompat_flags(disk_super
);
86 trans
= btrfs_start_transaction(root
, 1);
87 BUG_ON(IS_ERR(trans
));
88 btrfs_set_super_incompat_flags(disk_super
, super_flags
);
89 ret
= btrfs_commit_transaction(trans
, root
);
94 static int change_header_uuid(struct btrfs_root
*root
, struct extent_buffer
*eb
)
96 struct btrfs_fs_info
*fs_info
= root
->fs_info
;
98 int same_chunk_tree_uuid
= 1;
101 same_fsid
= !memcmp_extent_buffer(eb
, fs_info
->new_fsid
,
102 btrfs_header_fsid(), BTRFS_FSID_SIZE
);
103 same_chunk_tree_uuid
=
104 !memcmp_extent_buffer(eb
, fs_info
->new_chunk_tree_uuid
,
105 btrfs_header_chunk_tree_uuid(eb
),
107 if (same_fsid
&& same_chunk_tree_uuid
)
110 write_extent_buffer(eb
, fs_info
->new_fsid
, btrfs_header_fsid(),
112 if (!same_chunk_tree_uuid
)
113 write_extent_buffer(eb
, fs_info
->new_chunk_tree_uuid
,
114 btrfs_header_chunk_tree_uuid(eb
),
116 ret
= write_tree_block(NULL
, fs_info
, eb
);
121 static int change_extents_uuid(struct btrfs_fs_info
*fs_info
)
123 struct btrfs_root
*root
= fs_info
->extent_root
;
124 struct btrfs_path path
;
125 struct btrfs_key key
= {0, 0, 0};
128 btrfs_init_path(&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(fs_info
, bytenr
, 0);
156 error("failed to read tree block: %llu", bytenr
);
160 ret
= change_header_uuid(root
, eb
);
161 free_extent_buffer(eb
);
163 error("failed to change uuid of tree block: %llu",
168 ret
= btrfs_next_item(root
, &path
);
178 btrfs_release_path(&path
);
182 static int change_device_uuid(struct btrfs_fs_info
*fs_info
, struct extent_buffer
*eb
,
185 struct btrfs_dev_item
*di
;
188 di
= btrfs_item_ptr(eb
, slot
, struct btrfs_dev_item
);
189 if (!memcmp_extent_buffer(eb
, fs_info
->new_fsid
,
190 (unsigned long)btrfs_device_fsid(di
),
194 write_extent_buffer(eb
, fs_info
->new_fsid
,
195 (unsigned long)btrfs_device_fsid(di
),
197 ret
= write_tree_block(NULL
, fs_info
, eb
);
202 static int change_devices_uuid(struct btrfs_fs_info
*fs_info
)
204 struct btrfs_root
*root
= fs_info
->chunk_root
;
205 struct btrfs_path path
;
206 struct btrfs_key key
= {0, 0, 0};
209 btrfs_init_path(&path
);
210 /* No transaction again */
211 ret
= btrfs_search_slot(NULL
, root
, &key
, &path
, 0, 0);
216 btrfs_item_key_to_cpu(path
.nodes
[0], &key
, path
.slots
[0]);
217 if (key
.type
!= BTRFS_DEV_ITEM_KEY
||
218 key
.objectid
!= BTRFS_DEV_ITEMS_OBJECTID
)
220 ret
= change_device_uuid(fs_info
, path
.nodes
[0], path
.slots
[0]);
224 ret
= btrfs_next_item(root
, &path
);
233 btrfs_release_path(&path
);
237 static int change_fsid_prepare(struct btrfs_fs_info
*fs_info
)
239 struct btrfs_root
*tree_root
= fs_info
->tree_root
;
240 u64 flags
= btrfs_super_flags(fs_info
->super_copy
);
243 flags
|= BTRFS_SUPER_FLAG_CHANGING_FSID
;
244 btrfs_set_super_flags(fs_info
->super_copy
, flags
);
246 memcpy(fs_info
->super_copy
->fsid
, fs_info
->new_fsid
, BTRFS_FSID_SIZE
);
247 ret
= write_all_supers(fs_info
);
251 /* also restore new chunk_tree_id into tree_root for restore */
252 write_extent_buffer(tree_root
->node
, fs_info
->new_chunk_tree_uuid
,
253 btrfs_header_chunk_tree_uuid(tree_root
->node
),
255 return write_tree_block(NULL
, fs_info
, tree_root
->node
);
258 static int change_fsid_done(struct btrfs_fs_info
*fs_info
)
260 u64 flags
= btrfs_super_flags(fs_info
->super_copy
);
262 flags
&= ~BTRFS_SUPER_FLAG_CHANGING_FSID
;
263 btrfs_set_super_flags(fs_info
->super_copy
, flags
);
265 return write_all_supers(fs_info
);
269 * Return 0 for no unfinished fsid change.
270 * Return >0 for unfinished fsid change, and restore unfinished fsid/
271 * chunk_tree_id into fsid_ret/chunk_id_ret.
273 static int check_unfinished_fsid_change(struct btrfs_fs_info
*fs_info
,
274 uuid_t fsid_ret
, uuid_t chunk_id_ret
)
276 struct btrfs_root
*tree_root
= fs_info
->tree_root
;
277 u64 flags
= btrfs_super_flags(fs_info
->super_copy
);
279 if (flags
& BTRFS_SUPER_FLAG_CHANGING_FSID
) {
280 memcpy(fsid_ret
, fs_info
->super_copy
->fsid
, BTRFS_FSID_SIZE
);
281 read_extent_buffer(tree_root
->node
, chunk_id_ret
,
282 btrfs_header_chunk_tree_uuid(tree_root
->node
),
290 * Change fsid of a given fs.
292 * If new_fsid_str is not given, use a random generated UUID.
293 * Caller should check new_fsid_str is valid
295 static int change_uuid(struct btrfs_fs_info
*fs_info
, const char *new_fsid_str
)
300 char uuid_buf
[BTRFS_UUID_UNPARSED_SIZE
];
303 if (check_unfinished_fsid_change(fs_info
, new_fsid
, new_chunk_id
)) {
307 uuid_parse(new_fsid_str
, tmp
);
308 if (memcmp(tmp
, new_fsid
, BTRFS_FSID_SIZE
)) {
310 "new fsid %s is not the same with unfinished fsid change",
317 uuid_parse(new_fsid_str
, new_fsid
);
319 uuid_generate(new_fsid
);
321 uuid_generate(new_chunk_id
);
323 fs_info
->new_fsid
= new_fsid
;
324 fs_info
->new_chunk_tree_uuid
= new_chunk_id
;
326 memcpy(old_fsid
, (const char*)fs_info
->fsid
, BTRFS_UUID_SIZE
);
327 uuid_unparse(old_fsid
, uuid_buf
);
328 printf("Current fsid: %s\n", uuid_buf
);
330 uuid_unparse(new_fsid
, uuid_buf
);
331 printf("New fsid: %s\n", uuid_buf
);
332 /* Now we can begin fsid change */
333 printf("Set superblock flag CHANGING_FSID\n");
334 ret
= change_fsid_prepare(fs_info
);
338 /* Change extents first */
339 printf("Change fsid in extents\n");
340 ret
= change_extents_uuid(fs_info
);
342 error("failed to change UUID of metadata: %d", ret
);
347 printf("Change fsid on devices\n");
348 ret
= change_devices_uuid(fs_info
);
350 error("failed to change UUID of devices: %d", ret
);
354 /* Last, change fsid in super */
355 memcpy(fs_info
->fs_devices
->fsid
, fs_info
->new_fsid
,
357 memcpy(fs_info
->super_copy
->fsid
, fs_info
->new_fsid
,
359 ret
= write_all_supers(fs_info
);
363 /* Now fsid change is done */
364 printf("Clear superblock flag CHANGING_FSID\n");
365 ret
= change_fsid_done(fs_info
);
366 fs_info
->new_fsid
= NULL
;
367 fs_info
->new_chunk_tree_uuid
= NULL
;
368 printf("Fsid change finished\n");
373 static void print_usage(void)
375 printf("usage: btrfstune [options] device\n");
376 printf("\t-S value\tpositive value will enable seeding, zero to disable, negative is not allowed\n");
377 printf("\t-r \t\tenable extended inode refs\n");
378 printf("\t-x \t\tenable skinny metadata extent refs\n");
379 printf("\t-n \t\tenable no-holes feature (more efficient sparse file representation)\n");
380 printf("\t-f \t\tforce to do dangerous operation, make sure that you are aware of the dangers\n");
381 printf("\t-u \t\tchange fsid, use a random one\n");
382 printf("\t-U UUID\t\tchange fsid to UUID\n");
385 int main(int argc
, char *argv
[])
387 struct btrfs_root
*root
;
388 unsigned ctree_flags
= OPEN_CTREE_WRITES
;
391 int seeding_flag
= 0;
392 u64 seeding_value
= 0;
394 char *new_fsid_str
= NULL
;
399 static const struct option long_options
[] = {
400 { "help", no_argument
, NULL
, GETOPT_VAL_HELP
},
403 int c
= getopt_long(argc
, argv
, "S:rxfuU:n", long_options
, NULL
);
410 seeding_value
= arg_strtou64(optarg
);
413 super_flags
|= BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF
;
416 super_flags
|= BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA
;
419 super_flags
|= BTRFS_FEATURE_INCOMPAT_NO_HOLES
;
425 ctree_flags
|= OPEN_CTREE_IGNORE_FSID_MISMATCH
;
426 new_fsid_str
= optarg
;
429 ctree_flags
|= OPEN_CTREE_IGNORE_FSID_MISMATCH
;
432 case GETOPT_VAL_HELP
:
435 return c
!= GETOPT_VAL_HELP
;
440 device
= argv
[optind
];
441 if (check_argc_exact(argc
- optind
, 1)) {
446 if (random_fsid
&& new_fsid_str
) {
447 error("random fsid can't be used with specified fsid");
450 if (!super_flags
&& !seeding_flag
&& !(random_fsid
|| new_fsid_str
)) {
451 error("at least one option should be specified");
459 ret
= uuid_parse(new_fsid_str
, tmp
);
461 error("could not parse UUID: %s", new_fsid_str
);
464 if (!test_uuid_unique(new_fsid_str
)) {
465 error("fsid %s is not unique", new_fsid_str
);
470 ret
= check_mounted(device
);
472 error("could not check mount status of %s: %s", device
,
476 error("%s is mounted", device
);
480 root
= open_ctree(device
, 0, ctree_flags
);
483 error("open ctree failed");
488 if (!seeding_value
&& !force
) {
490 "this is dangerous, clearing the seeding flag may cause the derived device not to be mountable!");
491 ret
= ask_user("We are going to clear the seeding flag, are you sure?");
493 fprintf(stderr
, "Clear seeding flag canceled\n");
499 ret
= update_seeding_flag(root
, seeding_value
);
506 ret
= set_super_incompat_flags(root
, super_flags
);
512 if (random_fsid
|| new_fsid_str
) {
515 "it's highly recommended to run 'btrfs check' before this operation");
517 "also canceling running UUID change progress may cause corruption");
518 ret
= ask_user("We are going to change UUID, are your sure?");
520 fprintf(stderr
, "UUID change canceled\n");
525 ret
= change_uuid(root
->fs_info
, new_fsid_str
);
531 if (success
== total
) {
534 root
->fs_info
->readonly
= 1;
536 error("btrfstune failed");
540 btrfs_close_all_devices();