btrfs-progs: check: add option to skip mount checks
authorDavid Sterba <dsterba@suse.cz>
Thu, 31 Aug 2017 16:34:37 +0000 (18:34 +0200)
committerDavid Sterba <dsterba@suse.com>
Fri, 8 Sep 2017 14:15:05 +0000 (16:15 +0200)
Sometimes it's needed to do a check on a mounted filesystem. This should
work fine on a quiescent filesystem or a read-only mount. Changes on the
block device done by kernel might confuse the userspace checker and it
might crash when it reads some stale data.

Repair without mount checks is not supported right now.

Signed-off-by: David Sterba <dsterba@suse.cz>
Documentation/btrfs-check.asciidoc
cmds-check.c

index fa054e4..fbf4884 100644 (file)
@@ -3,7 +3,7 @@ btrfs-check(8)
 
 NAME
 ----
-btrfs-check - check or repair an unmounted btrfs filesystem
+btrfs-check - check or repair a btrfs filesystem
 
 SYNOPSIS
 --------
@@ -13,7 +13,9 @@ DESCRIPTION
 -----------
 
 The filesystem checker is used to verify structural integrity of a filesystem
-and attempt to repair it if requested. The filesystem must be unmounted.
+and attempt to repair it if requested.  It is recommended to unmount the
+filesystem prior to running the check, but it is possible to start checking a
+mounted filesystem (see '--force').
 
 By default, *btrfs check* will not modify the device but you can reaffirm that
 by the option '--readonly'.
@@ -120,6 +122,12 @@ needs to re-read blocks when needed. This may increase run time.
 NOTE: 'lowmem' mode does not work with '--repair' yet, and is still considered
 experimental.
 
+--force::
+allow to work on a mounted filesystem. Note that this should work fine on a
+quiescent or read-only mounted filesystem but may crash if the device is
+changed externally, eg. by the kernel module.  Repair without mount checks is
+not supported right now.
+
 EXIT STATUS
 -----------
 *btrfs check* returns a zero exit status if it succeeds. Non zero is
index a633d04..006edbd 100644 (file)
@@ -12730,6 +12730,7 @@ const char * const cmd_check_usage[] = {
        "",
        "-s|--super <superblock>     use this superblock copy",
        "-b|--backup                 use the first valid backup root copy",
+       "--force                     skip mount checks, repair is not possible",
        "--repair                    try to repair the filesystem",
        "--readonly                  run in read-only mode (default)",
        "--init-csum-tree            create a new CRC tree",
@@ -12761,7 +12762,7 @@ int cmd_check(int argc, char **argv)
        u64 tree_root_bytenr = 0;
        u64 chunk_root_bytenr = 0;
        char uuidbuf[BTRFS_UUID_UNPARSED_SIZE];
-       int ret;
+       int ret = 0;
        int err = 0;
        u64 num;
        int init_csum_tree = 0;
@@ -12770,13 +12771,15 @@ int cmd_check(int argc, char **argv)
        int qgroup_report = 0;
        int qgroups_repaired = 0;
        unsigned ctree_flags = OPEN_CTREE_EXCLUSIVE;
+       int force = 0;
 
        while(1) {
                int c;
                enum { GETOPT_VAL_REPAIR = 257, GETOPT_VAL_INIT_CSUM,
                        GETOPT_VAL_INIT_EXTENT, GETOPT_VAL_CHECK_CSUM,
                        GETOPT_VAL_READONLY, GETOPT_VAL_CHUNK_TREE,
-                       GETOPT_VAL_MODE, GETOPT_VAL_CLEAR_SPACE_CACHE };
+                       GETOPT_VAL_MODE, GETOPT_VAL_CLEAR_SPACE_CACHE,
+                       GETOPT_VAL_FORCE };
                static const struct option long_options[] = {
                        { "super", required_argument, NULL, 's' },
                        { "repair", no_argument, NULL, GETOPT_VAL_REPAIR },
@@ -12798,6 +12801,7 @@ int cmd_check(int argc, char **argv)
                                GETOPT_VAL_MODE },
                        { "clear-space-cache", required_argument, NULL,
                                GETOPT_VAL_CLEAR_SPACE_CACHE},
+                       { "force", no_argument, NULL, GETOPT_VAL_FORCE },
                        { NULL, 0, NULL, 0}
                };
 
@@ -12882,6 +12886,9 @@ int cmd_check(int argc, char **argv)
                                }
                                ctree_flags |= OPEN_CTREE_WRITES;
                                break;
+                       case GETOPT_VAL_FORCE:
+                               force = 1;
+                               break;
                }
        }
 
@@ -12910,15 +12917,36 @@ int cmd_check(int argc, char **argv)
        radix_tree_init();
        cache_tree_init(&root_cache);
 
-       if((ret = check_mounted(argv[optind])) < 0) {
-               error("could not check mount status: %s", strerror(-ret));
-               err |= !!ret;
-               goto err_out;
-       } else if(ret) {
-               error("%s is currently mounted, aborting", argv[optind]);
-               ret = -EBUSY;
-               err |= !!ret;
-               goto err_out;
+       ret = check_mounted(argv[optind]);
+       if (!force) {
+               if (ret < 0) {
+                       error("could not check mount status: %s",
+                                       strerror(-ret));
+                       err |= !!ret;
+                       goto err_out;
+               } else if (ret) {
+                       error(
+"%s is currently mounted, use --force if you really intend to check the filesystem",
+                               argv[optind]);
+                       ret = -EBUSY;
+                       err |= !!ret;
+                       goto err_out;
+               }
+       } else {
+               if (repair) {
+                       error("repair and --force is not yet supported");
+                       ret = 1;
+                       err |= !!ret;
+                       goto err_out;
+               }
+               if (ret < 0) {
+                       warning(
+"cannot check mount status of %s, the filesystem could be mounted, continuing because of --force",
+                               argv[optind]);
+               } else if (ret) {
+                       warning(
+                       "filesystem mounted, continuing because of --force");
+               }
        }
 
        /* only allow partial opening under repair mode */