btrfs-progs: defrag: open files RO on new enough kernels

Defragging an executable conflicts both way with it being run, resulting in
ETXTBSY.  This either makes defrag fail or prevents the program from being
executed.

Kernels 4.19-rc1 and later allow defragging files you could have possibly
opened rw, even if the passed descriptor is ro (commit 616d374efa23
"btrfs: allow defrag on a file opened read-only that has rw
permissions").

Signed-off-by: Adam Borowski <kilobyte@angband.pl>
Signed-off-by: David Sterba <dsterba@suse.com>
master
Adam Borowski 2019-02-25 19:16:44 +01:00 committed by David Sterba
parent 3da12f3d5f
commit 5ebf288875
1 changed files with 12 additions and 2 deletions

View File

@ -26,6 +26,7 @@
#include <ftw.h>
#include <mntent.h>
#include <linux/limits.h>
#include <linux/version.h>
#include <getopt.h>
#include <btrfsutil.h>
@ -39,12 +40,14 @@
#include "list_sort.h"
#include "disk-io.h"
#include "help.h"
#include "fsfeatures.h"
/*
* for btrfs fi show, we maintain a hash of fsids we've already printed.
* This way we don't print dups if a given FS is mounted more than once.
*/
static struct seen_fsid *seen_fsid_hash[SEEN_FSID_HASH_SIZE] = {NULL,};
static mode_t defrag_open_mode = O_RDONLY;
static const char * const filesystem_cmd_group_usage[] = {
"btrfs filesystem [<group>] <command> [<args>]",
@ -880,7 +883,7 @@ static int defrag_callback(const char *fpath, const struct stat *sb,
if ((typeflag == FTW_F) && S_ISREG(sb->st_mode)) {
if (defrag_global_verbose)
printf("%s\n", fpath);
fd = open(fpath, O_RDWR);
fd = open(fpath, defrag_open_mode);
if (fd < 0) {
goto error;
}
@ -917,6 +920,13 @@ static int cmd_filesystem_defrag(int argc, char **argv)
int compress_type = BTRFS_COMPRESS_NONE;
DIR *dirstream;
/*
* Kernel 4.19+ supports defragmention of files open read-only,
* otherwise it's an ETXTBSY error
*/
if (get_running_kernel_version() < KERNEL_VERSION(4,19,0))
defrag_open_mode = O_RDWR;
/*
* Kernel has a different default (256K) that is supposed to be safe,
* but it does not defragment very well. The 32M will likely lead to
@ -1017,7 +1027,7 @@ static int cmd_filesystem_defrag(int argc, char **argv)
int defrag_err = 0;
dirstream = NULL;
fd = open_file_or_dir(argv[i], &dirstream);
fd = open_file_or_dir3(argv[i], &dirstream, defrag_open_mode);
if (fd < 0) {
error("cannot open %s: %m", argv[i]);
ret = -errno;