diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2025-04-03 14:25:05 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2025-06-20 17:16:33 -0400 |
commit | f2d9a55b1b83bce71416b3dca7cf013154c04251 (patch) | |
tree | abd56d3806146548825ef56bdfb858c24e7caed7 | |
parent | 3f66d905c037e3fe31f7ca41a0c0039674b18696 (diff) |
cmd_strip_alloc
Add a command for stripping allocation info for a filesystem.
This is primarily to test codepaths used by the new image creation tool.
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r-- | c_src/bcachefs.c | 1 | ||||
-rw-r--r-- | c_src/cmd_strip_alloc.c | 142 | ||||
-rw-r--r-- | c_src/cmd_strip_alloc.h | 7 | ||||
-rw-r--r-- | c_src/cmds.h | 1 | ||||
-rw-r--r-- | src/bcachefs.rs | 1 |
5 files changed, 152 insertions, 0 deletions
diff --git a/c_src/bcachefs.c b/c_src/bcachefs.c index 9864680b..46c524c4 100644 --- a/c_src/bcachefs.c +++ b/c_src/bcachefs.c @@ -36,6 +36,7 @@ void bcachefs_usage(void) " recover-super Attempt to recover overwritten superblock from backups\n" " set-fs-option Set a filesystem option\n" " reset-counters Reset all counters on an unmounted device\n" + " strip-alloc Strip alloc info on a filesystem to be used read-only\n" "\n" "Mount:\n" " mount Mount a filesystem\n" diff --git a/c_src/cmd_strip_alloc.c b/c_src/cmd_strip_alloc.c new file mode 100644 index 00000000..c313b665 --- /dev/null +++ b/c_src/cmd_strip_alloc.c @@ -0,0 +1,142 @@ +/* + * Authors: Kent Overstreet <kent.overstreet@linux.dev> + * + * GPLv2 + */ + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include <uuid/uuid.h> + +#include "cmds.h" +#include "cmd_strip_alloc.h" +#include "libbcachefs/errcode.h" +#include "libbcachefs/opts.h" +#include "libbcachefs/journal.h" +#include "libbcachefs/sb-clean.h" +#include "libbcachefs/super-io.h" +#include "libbcachefs/util.h" + +#include "libbcachefs/darray.h" + +void strip_fs_alloc(struct bch_fs *c) +{ + struct bch_sb_field_clean *clean = bch2_sb_field_get(c->disk_sb.sb, clean); + struct jset_entry *entry = clean->start; + + unsigned u64s = clean->field.u64s; + while (entry != vstruct_end(&clean->field)) { + if (entry->type == BCH_JSET_ENTRY_btree_root && + btree_id_is_alloc(entry->btree_id)) { + clean->field.u64s -= jset_u64s(entry->u64s); + memmove(entry, + vstruct_next(entry), + vstruct_end(&clean->field) - (void *) vstruct_next(entry)); + } else { + entry = vstruct_next(entry); + } + } + + swap(u64s, clean->field.u64s); + bch2_sb_field_resize(&c->disk_sb, clean, u64s); + + bch2_sb_field_resize(&c->disk_sb, replicas_v0, 0); + bch2_sb_field_resize(&c->disk_sb, replicas, 0); + + for_each_online_member(c, ca, 0) { + bch2_sb_field_resize(&c->disk_sb, journal, 0); + bch2_sb_field_resize(&c->disk_sb, journal_v2, 0); + } + + for_each_member_device(c, ca) { + struct bch_member *m = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx); + SET_BCH_MEMBER_FREESPACE_INITIALIZED(m, false); + } + + c->disk_sb.sb->features[0] |= cpu_to_le64(BIT_ULL(BCH_FEATURE_no_alloc_info)); +} + +static void strip_alloc_usage(void) +{ + puts("bcachefs strip-alloc - remove alloc info and journal from a filesystem\n" + "Removes metadata unneeded for running in read-only mode\n" + "Alloc info and journal will be recreated on first RW mount\n" + "Usage: bcachefs strip_alloc [OPTION]... <devices>\n" + "\n" + "Options:\n" + " -h, --help Display this help and exit\n" + "Report bugs to <linux-bcachefs@vger.kernel.org>"); +} + +int cmd_strip_alloc(int argc, char *argv[]) +{ + static const struct option longopts[] = { + { "help", no_argument, NULL, 'h' }, + { NULL } + }; + int opt; + + while ((opt = getopt_long(argc, argv, "h", longopts, NULL)) != -1) + switch (opt) { + case 'h': + strip_alloc_usage(); + exit(16); + } + args_shift(optind); + + if (!argc) { + fprintf(stderr, "Please supply device(s)\n"); + exit(8); + } + + darray_const_str devs = get_or_split_cmdline_devs(argc, argv); + + struct bch_opts opts = bch2_opts_empty(); + opt_set(opts, nostart, true); +reopen: + struct bch_fs *c = bch2_fs_open(&devs, &opts); + int ret = PTR_ERR_OR_ZERO(c); + if (ret) + die("Error opening filesystem: %s", bch2_err_str(ret)); + + if (!c->sb.clean) { + printf("Filesystem not clean, running recovery"); + ret = bch2_fs_start(c); + if (ret) { + fprintf(stderr, "Error starting filesystem: %s\n", bch2_err_str(ret)); + goto err_stop; + } + bch2_fs_stop(c); + goto reopen; + } + + u64 capacity = 0; + for_each_member_device(c, ca) + capacity += ca->mi.nbuckets * (ca->mi.bucket_size << 9); + + if (capacity > 1ULL << 40) { + fprintf(stderr, "capacity too large for alloc info reconstruction, exiting\n"); + goto err_stop; + } + + printf("Stripping alloc info from %s\n", argv[0]); + + mutex_lock(&c->sb_lock); + strip_fs_alloc(c); + bch2_write_super(c); + mutex_unlock(&c->sb_lock); +err_stop: + bch2_fs_stop(c); + return ret; +} diff --git a/c_src/cmd_strip_alloc.h b/c_src/cmd_strip_alloc.h new file mode 100644 index 00000000..8b5a2f8f --- /dev/null +++ b/c_src/cmd_strip_alloc.h @@ -0,0 +1,7 @@ +#ifndef _TOOLS_CMD_STRIP_ALLOC_H +#define _TOOLS_CMD_STRIP_ALLOC_H + +void strip_fs_alloc(struct bch_fs *); + +#endif /* _TOOLS_CMD_STRIP_ALLOC_H */ + diff --git a/c_src/cmds.h b/c_src/cmds.h index 19961a59..13451ef1 100644 --- a/c_src/cmds.h +++ b/c_src/cmds.h @@ -13,6 +13,7 @@ int cmd_format(int argc, char *argv[]); int cmd_show_super(int argc, char *argv[]); int cmd_recover_super(int argc, char *argv[]); int cmd_reset_counters(int argc, char *argv[]); +int cmd_strip_alloc(int argc, char *argv[]); int cmd_set_option(int argc, char *argv[]); int fs_usage(void); diff --git a/src/bcachefs.rs b/src/bcachefs.rs index 548add0a..d318c8af 100644 --- a/src/bcachefs.rs +++ b/src/bcachefs.rs @@ -61,6 +61,7 @@ fn handle_c_command(mut argv: Vec<String>, symlink_cmd: Option<&str>) -> i32 { "set-file-option" => c::cmd_setattr(argc, argv), "show-super" => c::cmd_show_super(argc, argv), "recover-super" => c::cmd_recover_super(argc, argv), + "strip-alloc" => c::cmd_strip_alloc(argc, argv), "unlock" => c::cmd_unlock(argc, argv), "version" => c::cmd_version(argc, argv), |