Skip to content

Commit 93f2636

Browse files
committed
btrfs-progs: fi defrag: add new option to process the range in steps
Add a convenience option to processing the range in smaller steps than the whole file, where a flush is done after each steps. This could be potentially used to measure progress with 'btrfs -vv fi defrag'. Issue: #616 Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 5fce099 commit 93f2636

File tree

2 files changed

+67
-4
lines changed

2 files changed

+67
-4
lines changed

Documentation/btrfs-filesystem.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ defragment [options] <file>|<dir> [<file>|<dir>...]
139139
depending on the state of the free space and fragmentation or other internal
140140
logic. Reasonable values are from tens to hundreds of megabytes.
141141

142+
--step SIZE
143+
Perform defragmention in the range in SIZE steps and flush (*-f*) after each one.
144+
The range is default (the whole file) or given by *-s* and *-l*, split into
145+
the steps or done in one go if the step is larger. Minimum range size is 256KiB.
146+
142147
-v
143148
(deprecated) alias for global *-v* option
144149

cmds/filesystem.c

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "kernel-lib/list.h"
3737
#include "kernel-lib/sizes.h"
3838
#include "kernel-lib/list_sort.h"
39+
#include "kernel-lib/overflow.h"
3940
#include "kernel-shared/ctree.h"
4041
#include "kernel-shared/compression.h"
4142
#include "kernel-shared/volumes.h"
@@ -903,6 +904,7 @@ static const char * const cmd_filesystem_defrag_usage[] = {
903904
OPTLINE("-s start", "defragment only from byte onward"),
904905
OPTLINE("-l len", "defragment only up to len bytes"),
905906
OPTLINE("-t size", "target extent size hint (default: 32M)"),
907+
OPTLINE("--step SIZE", "process the range in given steps, flush after each one"),
906908
OPTLINE("-v", "deprecated, alias for global -v option"),
907909
HELPINFO_INSERT_GLOBALS,
908910
HELPINFO_INSERT_VERBOSE,
@@ -916,6 +918,48 @@ static const char * const cmd_filesystem_defrag_usage[] = {
916918

917919
static struct btrfs_ioctl_defrag_range_args defrag_global_range;
918920
static int defrag_global_errors;
921+
static u64 defrag_global_step;
922+
923+
static int defrag_range_in_steps(int fd, const struct stat *st) {
924+
int ret = 0;
925+
u64 end;
926+
struct btrfs_ioctl_defrag_range_args range;
927+
928+
if (defrag_global_step == 0)
929+
return ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, &defrag_global_range);
930+
931+
/*
932+
* If start is set but length is not within or beyond the u64 range,
933+
* assume it's the rest of the range.
934+
*/
935+
if (check_add_overflow(defrag_global_range.start, defrag_global_range.len, &end))
936+
end = (u64)-1;
937+
938+
range = defrag_global_range;
939+
range.flags |= BTRFS_DEFRAG_RANGE_START_IO;
940+
while (range.start < end) {
941+
u64 start;
942+
943+
range.len = defrag_global_step;
944+
pr_verbose(LOG_VERBOSE, "defrag range step: start=%llu len=%llu step=%llu\n",
945+
range.start, range.len, defrag_global_step);
946+
ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, &range);
947+
if (ret < 0)
948+
return ret;
949+
if (check_add_overflow(range.start, defrag_global_step, &start))
950+
break;
951+
range.start = start;
952+
/*
953+
* Avoid -EINVAL when starting the next ioctl, this can still
954+
* happen if the file size changes since the time of stat().
955+
*/
956+
if (start >= (u64)st->st_size)
957+
break;
958+
}
959+
960+
return ret;
961+
}
962+
919963
static int defrag_callback(const char *fpath, const struct stat *sb,
920964
int typeflag, struct FTW *ftwbuf)
921965
{
@@ -928,7 +972,7 @@ static int defrag_callback(const char *fpath, const struct stat *sb,
928972
if (fd < 0) {
929973
goto error;
930974
}
931-
ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, &defrag_global_range);
975+
ret = defrag_range_in_steps(fd, sb);
932976
close(fd);
933977
if (ret && errno == ENOTTY) {
934978
error(
@@ -994,7 +1038,14 @@ static int cmd_filesystem_defrag(const struct cmd_struct *cmd,
9941038
defrag_global_errors = 0;
9951039
optind = 0;
9961040
while(1) {
997-
int c = getopt(argc, argv, "vrc::fs:l:t:");
1041+
enum { GETOPT_VAL_STEP = GETOPT_VAL_FIRST };
1042+
static const struct option long_options[] = {
1043+
{ "step", required_argument, NULL, GETOPT_VAL_STEP },
1044+
{ NULL, 0, NULL, 0 }
1045+
};
1046+
int c;
1047+
1048+
c = getopt_long(argc, argv, "vrc::fs:l:t:", long_options, NULL);
9981049
if (c < 0)
9991050
break;
10001051

@@ -1031,6 +1082,14 @@ static int cmd_filesystem_defrag(const struct cmd_struct *cmd,
10311082
case 'r':
10321083
recursive = true;
10331084
break;
1085+
case GETOPT_VAL_STEP:
1086+
defrag_global_step = parse_size_from_string(optarg);
1087+
if (defrag_global_step < SZ_256K) {
1088+
warning("step %llu too small, adjusting to 256KiB\n",
1089+
defrag_global_step);
1090+
defrag_global_step = SZ_256K;
1091+
}
1092+
break;
10341093
default:
10351094
usage_unknown_option(cmd, argv);
10361095
}
@@ -1112,8 +1171,7 @@ static int cmd_filesystem_defrag(const struct cmd_struct *cmd,
11121171
ret = 0;
11131172
} else {
11141173
pr_verbose(LOG_INFO, "%s\n", argv[i]);
1115-
ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE,
1116-
&defrag_global_range);
1174+
ret = defrag_range_in_steps(fd, &st);
11171175
defrag_err = errno;
11181176
if (ret && defrag_err == ENOTTY) {
11191177
error(

0 commit comments

Comments
 (0)