mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/kdave/btrfs-progs.git
synced 2024-11-16 08:44:31 +08:00
btrfs-progs: Add recursive defrag using -r option
Add an option to defrag all files in a directory recursively. Signed-off-by: Frank Holton <fholton@gmail.com> Signed-off-by: David Sterba <dsterba@suse.cz> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
This commit is contained in:
parent
016e698a37
commit
c2c5e53bf7
@ -14,6 +14,7 @@
|
||||
* Boston, MA 021110-1307, USA.
|
||||
*/
|
||||
|
||||
#define _XOPEN_SOURCE 500
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -22,6 +23,8 @@
|
||||
#include <errno.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <ftw.h>
|
||||
|
||||
#include "kerncompat.h"
|
||||
#include "ctree.h"
|
||||
@ -348,6 +351,7 @@ static const char * const cmd_defrag_usage[] = {
|
||||
"Defragment a file or a directory",
|
||||
"",
|
||||
"-v be verbose",
|
||||
"-r defragment files recursively",
|
||||
"-c[zlib,lzo] compress the file while defragmenting",
|
||||
"-f flush data to disk immediately after defragmenting",
|
||||
"-s start defragment only from byte onward",
|
||||
@ -356,6 +360,58 @@ static const char * const cmd_defrag_usage[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static int do_defrag(int fd, int fancy_ioctl,
|
||||
struct btrfs_ioctl_defrag_range_args *range)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!fancy_ioctl)
|
||||
ret = ioctl(fd, BTRFS_IOC_DEFRAG, NULL);
|
||||
else
|
||||
ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, range);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int defrag_global_fancy_ioctl;
|
||||
static struct btrfs_ioctl_defrag_range_args defrag_global_range;
|
||||
static int defrag_global_verbose;
|
||||
static int defrag_global_errors;
|
||||
static int defrag_callback(const char *fpath, const struct stat *sb,
|
||||
int typeflag, struct FTW *ftwbuf)
|
||||
{
|
||||
int ret = 0;
|
||||
int e = 0;
|
||||
int fd = 0;
|
||||
|
||||
if (typeflag == FTW_F) {
|
||||
if (defrag_global_verbose)
|
||||
printf("%s\n", fpath);
|
||||
fd = open(fpath, O_RDWR);
|
||||
e = errno;
|
||||
if (fd < 0)
|
||||
goto error;
|
||||
ret = do_defrag(fd, defrag_global_fancy_ioctl, &defrag_global_range);
|
||||
e = errno;
|
||||
close(fd);
|
||||
if (ret && e == ENOTTY) {
|
||||
fprintf(stderr, "ERROR: defrag range ioctl not "
|
||||
"supported in this kernel, please try "
|
||||
"without any options.\n");
|
||||
defrag_global_errors++;
|
||||
return ENOTTY;
|
||||
}
|
||||
if (ret)
|
||||
goto error;
|
||||
}
|
||||
return 0;
|
||||
|
||||
error:
|
||||
fprintf(stderr, "ERROR: defrag failed on %s - %s\n", fpath, strerror(e));
|
||||
defrag_global_errors++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_defrag(int argc, char **argv)
|
||||
{
|
||||
int fd;
|
||||
@ -364,18 +420,20 @@ static int cmd_defrag(int argc, char **argv)
|
||||
u64 len = (u64)-1;
|
||||
u32 thresh = 0;
|
||||
int i;
|
||||
int errors = 0;
|
||||
int recursive = 0;
|
||||
int ret = 0;
|
||||
int verbose = 0;
|
||||
int fancy_ioctl = 0;
|
||||
struct btrfs_ioctl_defrag_range_args range;
|
||||
int e=0;
|
||||
int e = 0;
|
||||
int compress_type = BTRFS_COMPRESS_NONE;
|
||||
DIR *dirstream = NULL;
|
||||
DIR *dirstream;
|
||||
|
||||
defrag_global_errors = 0;
|
||||
defrag_global_verbose = 0;
|
||||
defrag_global_errors = 0;
|
||||
defrag_global_fancy_ioctl = 0;
|
||||
optind = 1;
|
||||
while(1) {
|
||||
int c = getopt(argc, argv, "vc::fs:l:t:");
|
||||
int c = getopt(argc, argv, "vrc::fs:l:t:");
|
||||
if (c < 0)
|
||||
break;
|
||||
|
||||
@ -384,26 +442,29 @@ static int cmd_defrag(int argc, char **argv)
|
||||
compress_type = BTRFS_COMPRESS_ZLIB;
|
||||
if (optarg)
|
||||
compress_type = parse_compress_type(optarg);
|
||||
fancy_ioctl = 1;
|
||||
defrag_global_fancy_ioctl = 1;
|
||||
break;
|
||||
case 'f':
|
||||
flush = 1;
|
||||
fancy_ioctl = 1;
|
||||
defrag_global_fancy_ioctl = 1;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
defrag_global_verbose = 1;
|
||||
break;
|
||||
case 's':
|
||||
start = parse_size(optarg);
|
||||
fancy_ioctl = 1;
|
||||
defrag_global_fancy_ioctl = 1;
|
||||
break;
|
||||
case 'l':
|
||||
len = parse_size(optarg);
|
||||
fancy_ioctl = 1;
|
||||
defrag_global_fancy_ioctl = 1;
|
||||
break;
|
||||
case 't':
|
||||
thresh = parse_size(optarg);
|
||||
fancy_ioctl = 1;
|
||||
defrag_global_fancy_ioctl = 1;
|
||||
break;
|
||||
case 'r':
|
||||
recursive = 1;
|
||||
break;
|
||||
default:
|
||||
usage(cmd_defrag_usage);
|
||||
@ -413,55 +474,72 @@ static int cmd_defrag(int argc, char **argv)
|
||||
if (check_argc_min(argc - optind, 1))
|
||||
usage(cmd_defrag_usage);
|
||||
|
||||
memset(&range, 0, sizeof(range));
|
||||
range.start = start;
|
||||
range.len = len;
|
||||
range.extent_thresh = thresh;
|
||||
memset(&defrag_global_range, 0, sizeof(range));
|
||||
defrag_global_range.start = start;
|
||||
defrag_global_range.len = len;
|
||||
defrag_global_range.extent_thresh = thresh;
|
||||
if (compress_type) {
|
||||
range.flags |= BTRFS_DEFRAG_RANGE_COMPRESS;
|
||||
range.compress_type = compress_type;
|
||||
defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_COMPRESS;
|
||||
defrag_global_range.compress_type = compress_type;
|
||||
}
|
||||
if (flush)
|
||||
range.flags |= BTRFS_DEFRAG_RANGE_START_IO;
|
||||
defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_START_IO;
|
||||
|
||||
for (i = optind; i < argc; i++) {
|
||||
if (verbose)
|
||||
printf("%s\n", argv[i]);
|
||||
dirstream = NULL;
|
||||
fd = open_file_or_dir(argv[i], &dirstream);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "failed to open %s\n", argv[i]);
|
||||
perror("open:");
|
||||
errors++;
|
||||
fprintf(stderr, "ERROR: failed to open %s - %s\n", argv[i],
|
||||
strerror(errno));
|
||||
defrag_global_errors++;
|
||||
close_file_or_dir(fd, dirstream);
|
||||
continue;
|
||||
}
|
||||
if (!fancy_ioctl) {
|
||||
ret = ioctl(fd, BTRFS_IOC_DEFRAG, NULL);
|
||||
e=errno;
|
||||
} else {
|
||||
ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, &range);
|
||||
if (ret && errno == ENOTTY) {
|
||||
fprintf(stderr, "ERROR: defrag range ioctl not "
|
||||
"supported in this kernel, please try "
|
||||
"without any options.\n");
|
||||
errors++;
|
||||
close(fd);
|
||||
break;
|
||||
if (recursive) {
|
||||
struct stat st;
|
||||
|
||||
fstat(fd, &st);
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
ret = nftw(argv[i], defrag_callback, 10,
|
||||
FTW_MOUNT | FTW_PHYS);
|
||||
if (ret == ENOTTY)
|
||||
exit(1);
|
||||
/* errors are handled in the callback */
|
||||
ret = 0;
|
||||
} else {
|
||||
if (defrag_global_verbose)
|
||||
printf("%s\n", argv[i]);
|
||||
ret = do_defrag(fd, defrag_global_fancy_ioctl,
|
||||
&defrag_global_range);
|
||||
e = errno;
|
||||
}
|
||||
} else {
|
||||
if (defrag_global_verbose)
|
||||
printf("%s\n", argv[i]);
|
||||
ret = do_defrag(fd, defrag_global_fancy_ioctl,
|
||||
&defrag_global_range);
|
||||
e = errno;
|
||||
}
|
||||
close_file_or_dir(fd, dirstream);
|
||||
if (ret && e == ENOTTY) {
|
||||
fprintf(stderr, "ERROR: defrag range ioctl not "
|
||||
"supported in this kernel, please try "
|
||||
"without any options.\n");
|
||||
defrag_global_errors++;
|
||||
break;
|
||||
}
|
||||
if (ret) {
|
||||
fprintf(stderr, "ERROR: defrag failed on %s - %s\n",
|
||||
argv[i], strerror(e));
|
||||
errors++;
|
||||
defrag_global_errors++;
|
||||
}
|
||||
close_file_or_dir(fd, dirstream);
|
||||
}
|
||||
if (verbose)
|
||||
if (defrag_global_verbose)
|
||||
printf("%s\n", BTRFS_BUILD_VERSION);
|
||||
if (errors)
|
||||
fprintf(stderr, "total %d failures\n", errors);
|
||||
if (defrag_global_errors)
|
||||
fprintf(stderr, "total %d failures\n", defrag_global_errors);
|
||||
|
||||
return !!errors;
|
||||
return !!defrag_global_errors;
|
||||
}
|
||||
|
||||
static const char * const cmd_resize_usage[] = {
|
||||
|
Loading…
Reference in New Issue
Block a user