diff options
author | Jérôme Poulin <jeromepoulin@gmail.com> | 2025-06-04 23:03:36 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2025-07-12 22:20:17 -0400 |
commit | 5dd10a17e9c06b24818bc19cd78db0a8e4492ef8 (patch) | |
tree | 2857caf2e412b08e92269df49a86e6d537fad14c | |
parent | 3321afc8b6e43fe71e744f19c7df6c7dc3146271 (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.8 | 14 | ||||
-rw-r--r-- | c_src/cmd_attr.c | 60 | ||||
-rw-r--r-- | c_src/libbcachefs.c | 6 | ||||
-rw-r--r-- | c_src/libbcachefs.h | 1 |
4 files changed, 74 insertions, 7 deletions
@@ -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); |