summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJérôme Poulin <jeromepoulin@gmail.com>2025-06-04 23:03:36 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2025-07-12 22:20:17 -0400
commit5dd10a17e9c06b24818bc19cd78db0a8e4492ef8 (patch)
tree2857caf2e412b08e92269df49a86e6d537fad14c
parent3321afc8b6e43fe71e744f19c7df6c7dc3146271 (diff)
cmd_attr: Add --options=- and --remove-all to unset options
Signed-off-by: Jérôme Poulin <jeromepoulin@gmail.com>
-rw-r--r--bcachefs.814
-rw-r--r--c_src/cmd_attr.c60
-rw-r--r--c_src/libbcachefs.c6
-rw-r--r--c_src/libbcachefs.h1
4 files changed, 74 insertions, 7 deletions
diff --git a/bcachefs.8 b/bcachefs.8
index 37cf0a8f..cf133e3b 100644
--- a/bcachefs.8
+++ b/bcachefs.8
@@ -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.
diff --git a/c_src/cmd_attr.c b/c_src/cmd_attr.c
index 0fc21824..a7f27831 100644
--- a/c_src/cmd_attr.c
+++ b/c_src/cmd_attr.c
@@ -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;
diff --git a/c_src/libbcachefs.c b/c_src/libbcachefs.c
index 81ad8cf1..935b13ce 100644
--- a/c_src/libbcachefs.c
+++ b/c_src/libbcachefs.c
@@ -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)
{
diff --git a/c_src/libbcachefs.h b/c_src/libbcachefs.h
index b1ac1b0a..edb05084 100644
--- a/c_src/libbcachefs.h
+++ b/c_src/libbcachefs.h
@@ -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);