mirror of
https://github.com/koverstreet/bcachefs-tools.git
synced 2025-12-19 00:00:10 +03:00
cmd_image: finish_image()
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
d0e71900a3
commit
c1a25673e9
@ -27,6 +27,7 @@
|
|||||||
#include "libbcachefs/alloc_background.h"
|
#include "libbcachefs/alloc_background.h"
|
||||||
#include "libbcachefs/alloc_foreground.h"
|
#include "libbcachefs/alloc_foreground.h"
|
||||||
#include "libbcachefs/data_update.h"
|
#include "libbcachefs/data_update.h"
|
||||||
|
#include "libbcachefs/disk_accounting.h"
|
||||||
#include "libbcachefs/errcode.h"
|
#include "libbcachefs/errcode.h"
|
||||||
#include "libbcachefs/journal_reclaim.h"
|
#include "libbcachefs/journal_reclaim.h"
|
||||||
#include "libbcachefs/move.h"
|
#include "libbcachefs/move.h"
|
||||||
@ -168,19 +169,207 @@ err:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_dev_usage_all(struct bch_fs *c)
|
static void prt_sectors(struct printbuf *out, u64 v)
|
||||||
|
{
|
||||||
|
prt_tab(out);
|
||||||
|
prt_human_readable_u64(out, v << 9);
|
||||||
|
prt_tab_rjust(out);
|
||||||
|
prt_newline(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_data_type_usage(struct printbuf *out,
|
||||||
|
struct bch_dev *ca,
|
||||||
|
struct bch_dev_usage_full u,
|
||||||
|
unsigned i)
|
||||||
|
{
|
||||||
|
if (u.d[i].buckets) {
|
||||||
|
bch2_prt_data_type(out, i);
|
||||||
|
prt_sectors(out, bucket_to_sector(ca, u.d[i].buckets));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (u.d[i].fragmented) {
|
||||||
|
bch2_prt_data_type(out, i);
|
||||||
|
prt_str(out, " fragmented");
|
||||||
|
prt_sectors(out, u.d[i].fragmented);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_image_usage(struct bch_fs *c, bool keep_alloc, u64 nbuckets)
|
||||||
{
|
{
|
||||||
struct printbuf buf = PRINTBUF;
|
struct printbuf buf = PRINTBUF;
|
||||||
|
printbuf_tabstop_push(&buf, 24);
|
||||||
|
printbuf_tabstop_push(&buf, 16);
|
||||||
|
printbuf_tabstop_push(&buf, 16);
|
||||||
|
printbuf_tabstop_push(&buf, 8);
|
||||||
|
|
||||||
for_each_member_device(c, ca) {
|
struct bch_dev *ca = c->devs[0];
|
||||||
struct bch_dev_usage_full stats = bch2_dev_usage_full_read(ca);
|
struct bch_dev_usage_full dev_stats = bch2_dev_usage_full_read(ca);
|
||||||
bch2_dev_usage_to_text(&buf, ca, &stats);
|
|
||||||
|
print_data_type_usage(&buf, ca, dev_stats, BCH_DATA_sb);
|
||||||
|
print_data_type_usage(&buf, ca, dev_stats, BCH_DATA_journal);
|
||||||
|
print_data_type_usage(&buf, ca, dev_stats, BCH_DATA_btree);
|
||||||
|
|
||||||
|
printbuf_indent_add(&buf, 2);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < BTREE_ID_NR; i++) {
|
||||||
|
if (btree_id_is_alloc(i) && !keep_alloc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
struct disk_accounting_pos a;
|
||||||
|
disk_accounting_key_init(a, btree, i);
|
||||||
|
|
||||||
|
u64 v = 0;
|
||||||
|
bch2_accounting_mem_read(c, disk_accounting_pos_to_bpos(&a), &v, 1);
|
||||||
|
|
||||||
|
if (v) {
|
||||||
|
bch2_btree_id_to_text(&buf, i);
|
||||||
|
prt_sectors(&buf, v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printbuf_indent_sub(&buf, 2);
|
||||||
|
|
||||||
|
struct disk_accounting_pos acc_replicas_key;
|
||||||
|
memset(&acc_replicas_key, 0, sizeof(acc_replicas_key));
|
||||||
|
acc_replicas_key.type = BCH_DISK_ACCOUNTING_replicas;
|
||||||
|
acc_replicas_key.replicas.data_type = BCH_DATA_user;
|
||||||
|
acc_replicas_key.replicas.nr_devs = 0;
|
||||||
|
acc_replicas_key.replicas.nr_required = 1;
|
||||||
|
acc_replicas_key.replicas.nr_required = 1;
|
||||||
|
replicas_entry_add_dev(&acc_replicas_key.replicas, 0);
|
||||||
|
|
||||||
|
u64 v = 0;
|
||||||
|
bch2_accounting_mem_read(c, disk_accounting_pos_to_bpos(&acc_replicas_key), &v, 1);
|
||||||
|
prt_printf(&buf, "user");
|
||||||
|
prt_sectors(&buf, v);
|
||||||
|
|
||||||
|
if (dev_stats.d[BCH_DATA_user].fragmented) {
|
||||||
|
prt_printf(&buf, "user fragmented");
|
||||||
|
prt_sectors(&buf, dev_stats.d[BCH_DATA_user].fragmented);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool compression_header = false;
|
||||||
|
for (unsigned i = 1; i < BCH_COMPRESSION_TYPE_NR; i++) {
|
||||||
|
struct disk_accounting_pos a;
|
||||||
|
disk_accounting_key_init(a, compression, .type = i);
|
||||||
|
struct bpos p = disk_accounting_pos_to_bpos(&a);
|
||||||
|
u64 v[3];
|
||||||
|
bch2_accounting_mem_read(c, p, v, ARRAY_SIZE(v));
|
||||||
|
|
||||||
|
if (!v[0])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!compression_header) {
|
||||||
|
prt_printf(&buf, "compression type\tcompressed\runcompressed\rratio\r\n");
|
||||||
|
printbuf_indent_add(&buf, 2);
|
||||||
|
}
|
||||||
|
compression_header = true;
|
||||||
|
|
||||||
|
u64 sectors_uncompressed = v[1];
|
||||||
|
u64 sectors_compressed = v[2];
|
||||||
|
|
||||||
|
bch2_prt_compression_type(&buf, i);
|
||||||
|
prt_tab(&buf);
|
||||||
|
|
||||||
|
prt_human_readable_u64(&buf, sectors_compressed << 9);
|
||||||
|
prt_tab_rjust(&buf);
|
||||||
|
|
||||||
|
if (i == BCH_COMPRESSION_TYPE_incompressible) {
|
||||||
|
prt_newline(&buf);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
prt_human_readable_u64(&buf, sectors_uncompressed << 9);
|
||||||
|
prt_printf(&buf, "\r%llu%%\r\n",
|
||||||
|
div64_u64(sectors_compressed * 100,
|
||||||
|
sectors_uncompressed));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compression_header)
|
||||||
|
printbuf_indent_sub(&buf, 2);
|
||||||
|
|
||||||
|
prt_printf(&buf, "image size");
|
||||||
|
prt_sectors(&buf, bucket_to_sector(c->devs[0], nbuckets));
|
||||||
|
|
||||||
printf("%s", buf.buf);
|
printf("%s", buf.buf);
|
||||||
printbuf_exit(&buf);
|
printbuf_exit(&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int finish_image(struct bch_fs *c,
|
||||||
|
bool keep_alloc,
|
||||||
|
unsigned verbosity)
|
||||||
|
{
|
||||||
|
if (verbosity > 1)
|
||||||
|
printf("moving %stree to primary device\n",
|
||||||
|
keep_alloc ? "" : "non-alloc ");
|
||||||
|
|
||||||
|
mutex_lock(&c->sb_lock);
|
||||||
|
struct bch_member *m = bch2_members_v2_get_mut(c->disk_sb.sb, 0);
|
||||||
|
SET_BCH_MEMBER_DATA_ALLOWED(m, BCH_MEMBER_DATA_ALLOWED(m)|BIT(BCH_DATA_btree));
|
||||||
|
bch2_write_super(c);
|
||||||
|
mutex_unlock(&c->sb_lock);
|
||||||
|
|
||||||
|
bch2_dev_allocator_set_rw(c, c->devs[0], true);
|
||||||
|
|
||||||
|
int ret = move_btree(c, keep_alloc, 0);
|
||||||
|
bch_err_msg(c, ret, "migrating btree from temporary device");
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
bch2_fs_read_only(c);
|
||||||
|
|
||||||
|
if (0)
|
||||||
|
check_gaps(c);
|
||||||
|
|
||||||
|
u64 nbuckets;
|
||||||
|
ret = get_nbuckets_used(c, &nbuckets);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (verbosity)
|
||||||
|
print_image_usage(c, keep_alloc, nbuckets);
|
||||||
|
|
||||||
|
if (ftruncate(c->devs[0]->disk_sb.bdev->bd_fd, nbuckets * bucket_bytes(c->devs[0]))) {
|
||||||
|
fprintf(stderr, "truncate error: %m\n");
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&c->sb_lock);
|
||||||
|
if (!keep_alloc) {
|
||||||
|
if (verbosity > 1)
|
||||||
|
printf("Stripping alloc info\n");
|
||||||
|
strip_fs_alloc(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
rcu_assign_pointer(c->devs[1], NULL);
|
||||||
|
|
||||||
|
m = bch2_members_v2_get_mut(c->disk_sb.sb, 0);
|
||||||
|
SET_BCH_MEMBER_DATA_ALLOWED(m, BCH_MEMBER_DATA_ALLOWED(m)|BIT(BCH_DATA_journal));
|
||||||
|
|
||||||
|
bch2_members_v2_get_mut(c->disk_sb.sb, 0)->nbuckets = cpu_to_le64(nbuckets);
|
||||||
|
|
||||||
|
for_each_online_member(c, ca, 0) {
|
||||||
|
struct bch_member *m = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx);
|
||||||
|
SET_BCH_MEMBER_RESIZE_ON_MOUNT(m, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
c->disk_sb.sb->features[0] |= cpu_to_le64(BIT_ULL(BCH_FEATURE_small_image));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* sb->nr_devices must be 1 so that it can be mounted without UUID
|
||||||
|
* conflicts
|
||||||
|
*/
|
||||||
|
unsigned u64s = DIV_ROUND_UP(sizeof(struct bch_sb_field_members_v2) +
|
||||||
|
sizeof(struct bch_member), sizeof(u64));
|
||||||
|
bch2_sb_field_resize(&c->disk_sb, members_v2, u64s);
|
||||||
|
c->disk_sb.sb->nr_devices = 1;
|
||||||
|
SET_BCH_SB_MULTI_DEVICE(c->disk_sb.sb, false);
|
||||||
|
|
||||||
|
bch2_write_super(c);
|
||||||
|
mutex_unlock(&c->sb_lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build an image file:
|
* Build an image file:
|
||||||
*
|
*
|
||||||
@ -195,9 +384,9 @@ static void print_dev_usage_all(struct bch_fs *c)
|
|||||||
* metadata device is dropped.
|
* metadata device is dropped.
|
||||||
*/
|
*/
|
||||||
static void image_create(struct bch_opt_strs fs_opt_strs,
|
static void image_create(struct bch_opt_strs fs_opt_strs,
|
||||||
struct bch_opts fs_opts,
|
struct bch_opts fs_opts,
|
||||||
struct format_opts format_opts,
|
struct format_opts format_opts,
|
||||||
struct dev_opts dev_opts,
|
struct dev_opts dev_opts,
|
||||||
const char *src_path,
|
const char *src_path,
|
||||||
bool keep_alloc,
|
bool keep_alloc,
|
||||||
unsigned verbosity)
|
unsigned verbosity)
|
||||||
@ -273,79 +462,11 @@ static void image_create(struct bch_opt_strs fs_opt_strs,
|
|||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
struct copy_fs_state s = {};
|
struct copy_fs_state s = {};
|
||||||
ret = copy_fs(c, &s, src_fd, src_path);
|
ret = copy_fs(c, &s, src_fd, src_path) ?:
|
||||||
|
finish_image(c, keep_alloc, verbosity);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (verbosity > 1)
|
|
||||||
printf("moving non-alloc btree to primary device\n");
|
|
||||||
|
|
||||||
mutex_lock(&c->sb_lock);
|
|
||||||
struct bch_member *m = bch2_members_v2_get_mut(c->disk_sb.sb, 0);
|
|
||||||
SET_BCH_MEMBER_DATA_ALLOWED(m, BCH_MEMBER_DATA_ALLOWED(m)|BIT(BCH_DATA_btree));
|
|
||||||
bch2_write_super(c);
|
|
||||||
mutex_unlock(&c->sb_lock);
|
|
||||||
|
|
||||||
bch2_dev_allocator_set_rw(c, c->devs[0], true);
|
|
||||||
|
|
||||||
ret = move_btree(c, keep_alloc, 0);
|
|
||||||
if (ret) {
|
|
||||||
fprintf(stderr, "error migrating btree from temporary device: %s\n",
|
|
||||||
bch2_err_str(ret));
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
bch2_fs_read_only(c);
|
|
||||||
|
|
||||||
if (verbosity > 1)
|
|
||||||
print_dev_usage_all(c);
|
|
||||||
|
|
||||||
if (0)
|
|
||||||
check_gaps(c);
|
|
||||||
|
|
||||||
u64 nbuckets;
|
|
||||||
ret = get_nbuckets_used(c, &nbuckets);
|
|
||||||
if (ret)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
if (ftruncate(c->devs[0]->disk_sb.bdev->bd_fd, nbuckets * bucket_bytes(c->devs[0]))) {
|
|
||||||
fprintf(stderr, "truncate error: %m\n");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock(&c->sb_lock);
|
|
||||||
if (!keep_alloc) {
|
|
||||||
printf("Stripping alloc info\n");
|
|
||||||
strip_fs_alloc(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
rcu_assign_pointer(c->devs[1], NULL);
|
|
||||||
|
|
||||||
m = bch2_members_v2_get_mut(c->disk_sb.sb, 0);
|
|
||||||
SET_BCH_MEMBER_DATA_ALLOWED(m, BCH_MEMBER_DATA_ALLOWED(m)|BIT(BCH_DATA_journal));
|
|
||||||
|
|
||||||
bch2_members_v2_get_mut(c->disk_sb.sb, 0)->nbuckets = cpu_to_le64(nbuckets);
|
|
||||||
|
|
||||||
for_each_online_member(c, ca, 0) {
|
|
||||||
struct bch_member *m = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx);
|
|
||||||
SET_BCH_MEMBER_RESIZE_ON_MOUNT(m, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
c->disk_sb.sb->features[0] |= cpu_to_le64(BIT_ULL(BCH_FEATURE_small_image));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* sb->nr_devices must be 1 so that it can be mounted without UUID
|
|
||||||
* conflicts
|
|
||||||
*/
|
|
||||||
unsigned u64s = DIV_ROUND_UP(sizeof(struct bch_sb_field_members_v2) +
|
|
||||||
sizeof(struct bch_member), sizeof(u64));
|
|
||||||
bch2_sb_field_resize(&c->disk_sb, members_v2, u64s);
|
|
||||||
c->disk_sb.sb->nr_devices = 1;
|
|
||||||
SET_BCH_SB_MULTI_DEVICE(c->disk_sb.sb, false);
|
|
||||||
|
|
||||||
bch2_write_super(c);
|
|
||||||
mutex_unlock(&c->sb_lock);
|
|
||||||
|
|
||||||
bch2_fs_stop(c);
|
bch2_fs_stop(c);
|
||||||
darray_exit(&device_paths);
|
darray_exit(&device_paths);
|
||||||
xclose(src_fd);
|
xclose(src_fd);
|
||||||
@ -481,7 +602,8 @@ static int cmd_image_create(int argc, char *argv[])
|
|||||||
|
|
||||||
dev_opts.path = argv[0];
|
dev_opts.path = argv[0];
|
||||||
|
|
||||||
image_create(fs_opt_strs, fs_opts, opts, dev_opts, opts.source, keep_alloc, verbosity);
|
image_create(fs_opt_strs, fs_opts, opts, dev_opts, opts.source,
|
||||||
|
keep_alloc, verbosity);
|
||||||
bch2_opt_strs_free(&fs_opt_strs);
|
bch2_opt_strs_free(&fs_opt_strs);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user