Skip to content

Commit

Permalink
btrfs-progs: defrag: open files RO on new enough kernels
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
kilobyte authored and kdave committed Mar 5, 2019
1 parent 3da12f3 commit 5ebf288
Showing 1 changed file with 12 additions and 2 deletions.
14 changes: 12 additions & 2 deletions cmds-filesystem.c
Expand Up @@ -26,6 +26,7 @@
#include <ftw.h>
#include <mntent.h>
#include <linux/limits.h>
#include <linux/version.h>
#include <getopt.h>

#include <btrfsutil.h>
Expand All @@ -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>]",
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 5ebf288

Please sign in to comment.