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>
This commit is contained in:
Kent Overstreet 2025-04-03 14:25:05 -04:00
parent 3f66d905c0
commit f2d9a55b1b
5 changed files with 152 additions and 0 deletions

View File

@ -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"

142
c_src/cmd_strip_alloc.c Normal file
View File

@ -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;
}

7
c_src/cmd_strip_alloc.h Normal file
View File

@ -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 */

View File

@ -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);

View File

@ -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),