cmd_attr: Add --options=- and --remove-all to unset options

Signed-off-by: Jérôme Poulin <jeromepoulin@gmail.com>
This commit is contained in:
Jérôme Poulin 2025-06-04 23:03:36 -04:00 committed by Kent Overstreet
parent 3321afc8b6
commit 5dd10a17e9
4 changed files with 74 additions and 7 deletions

View File

@ -576,7 +576,10 @@ Offset of existing superblock
.El
.Sh Commands for operating on files in a bcachefs filesystem
.Bl -tag -width Ds
.It Nm Ic set-file-option Oo Ar options Oc Ar devices\ ...
.It Nm Ic set-file-option Oo Ar options Oc Ar [files|folders]\ ...
Set various per-file attributes on files and directories in a bcachefs filesystem.
When applied to directories, attributes are propagated recursively to all files
and subdirectories within.
.Bl -tag -width Ds
.It Fl -data_replicas Ns = Ns Ar number
Number of data replicas
@ -602,7 +605,16 @@ Enable erasure coding (DO NOT USE YET)
.It Fl -nocow
Nocow mode: Writes will be done in place when possible.
.It Fl -remove-all
Remove all file options from the specified files/directories
.El
.Pp
To remove specific options, use
.Ar --option=-
.Pp
Options can be chained together to perform multiple operations in a single command, for example:
.Dl bcachefs set-file-option --remove-all --compression=lz4 .
.Dl bcachefs set-file-option --compression=- --background_compression=zstd:10 --data_replicas=- file.txt
.El
.Sh Commands for debugging
These commands work on offline, unmounted filesystems.

View File

@ -55,18 +55,54 @@ static void propagate_recurse(int dirfd)
closedir(dir);
}
static void do_setattr(char *path, struct bch_opt_strs opts)
static void remove_bcachefs_attr(const char *path, const char *full_attr_name)
{
if (removexattr(path, full_attr_name) != 0) {
// EINVAL in case bcachefs-tools is newer than kernel
if (errno != ENODATA && errno != EINVAL) {
fprintf(stderr, "error removing attribute %s from %s: %m\n",
full_attr_name, path);
}
}
}
static void remove_all_bcachefs_attrs(const char *path)
{
unsigned i;
for (i = 0; i < bch2_opts_nr; i++) {
if (bch2_opt_table[i].flags & OPT_INODE) {
// Only works on empty directory.
if (strcmp(bch2_opt_table[i].attr.name, "casefold") == 0)
continue;
char *full_name = mprintf("bcachefs.%s", bch2_opt_table[i].attr.name);
remove_bcachefs_attr(path, full_name);
free(full_name);
}
}
}
static void do_setattr(char *path, struct bch_opt_strs opts, bool remove_all)
{
unsigned i;
if (remove_all) {
remove_all_bcachefs_attrs(path);
}
for (i = 0; i < bch2_opts_nr; i++) {
if (!opts.by_id[i])
continue;
char *n = mprintf("bcachefs.%s", bch2_opt_table[i].attr.name);
if (setxattr(path, n, opts.by_id[i], strlen(opts.by_id[i]), 0))
die("setxattr error: %m");
if (strcmp(opts.by_id[i], "-") == 0) {
remove_bcachefs_attr(path, n);
} else {
if (setxattr(path, n, opts.by_id[i], strlen(opts.by_id[i]), 0))
die("setxattr error: %m");
}
free(n);
}
@ -90,15 +126,27 @@ static void setattr_usage(void)
"Options:");
bch2_opts_usage(OPT_INODE);
puts(" -h Display this help and exit\n"
puts(" --remove-all Remove all file options\n"
" To remove specific options, use: --option=-\n"
" -h Display this help and exit\n"
"Report bugs to <linux-bcachefs@vger.kernel.org>");
}
int cmd_setattr(int argc, char *argv[])
{
unsigned i;
bool remove_all = false;
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "--remove-all") == 0) {
remove_all = true;
bch_remove_arg_from_argv(&argc, argv, i);
i--;
}
}
struct bch_opt_strs opts =
bch2_cmdline_opts_get(&argc, argv, OPT_INODE);
unsigned i;
for (i = 1; i < argc; i++)
if (argv[i][0] == '-') {
@ -111,7 +159,7 @@ int cmd_setattr(int argc, char *argv[])
die("Please supply one or more files");
for (i = 1; i < argc; i++)
do_setattr(argv[i], opts);
do_setattr(argv[i], opts, remove_all);
bch2_opt_strs_free(&opts);
return 0;

View File

@ -737,6 +737,12 @@ noopt:
return NULL;
}
void bch_remove_arg_from_argv(int *argc, char *argv[], int index)
{
memmove(&argv[index], &argv[index + 1], (*argc - index) * sizeof(char*));
(*argc)--;
}
struct bch_opt_strs bch2_cmdline_opts_get(int *argc, char *argv[],
unsigned opt_types)
{

View File

@ -31,6 +31,7 @@ void bch2_opt_strs_free(struct bch_opt_strs *);
const struct bch_option *bch2_cmdline_opt_parse(int argc, char *argv[],
unsigned opt_types);
void bch_remove_arg_from_argv(int *argc, char *argv[], int index);
struct bch_opt_strs bch2_cmdline_opts_get(int *, char *[], unsigned);
struct bch_opts bch2_parse_opts(struct bch_opt_strs);
void bch2_opts_usage(unsigned);