Make --shrink a separate option for --rootdir, and make it default to
off.
So this will cause less confusion.

Signed-off-by: Qu Wenruo <w...@suse.com>
---
 Documentation/mkfs.btrfs.asciidoc | 11 +++++++++++
 mkfs/main.c                       | 27 +++++++++++++++++++++------
 mkfs/rootdir.c                    | 21 ++++++++++++++++++++-
 mkfs/rootdir.h                    |  3 ++-
 4 files changed, 54 insertions(+), 8 deletions(-)

diff --git a/Documentation/mkfs.btrfs.asciidoc 
b/Documentation/mkfs.btrfs.asciidoc
index d53d9e265fb7..5ddbedbcea97 100644
--- a/Documentation/mkfs.btrfs.asciidoc
+++ b/Documentation/mkfs.btrfs.asciidoc
@@ -106,6 +106,17 @@ Please see the mount option 'discard' for that in 
`btrfs`(5).
 *-r|--rootdir <rootdir>*::
 Populate the toplevel subvolume with files from 'rootdir'.  This does not
 require root permissions and does not mount the filesystem.
++
+NOTE: This option may enlarge the image or file to ensure it's large enough to
+contain the files from 'rootdir'.
+
+*--shrink*:
+Shrink the filesystem to its minimal size, only works with *-r|--rootdir*
+option.
++
+NOTE: If the destination is regular file, this option will also reduce the
+file size. Or it will only reduce the filesystem available space.
+Extra space will not be usable unless resized using 'btrfs filesystem resize'.
 
 *-O|--features <feature1>[,<feature2>...]*::
 A list of filesystem features turned on at mkfs time. Not all features are
diff --git a/mkfs/main.c b/mkfs/main.c
index 6aefb50a8033..1d72702414bc 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -731,9 +731,11 @@ int main(int argc, char **argv)
        int ssd = 0;
        int force_overwrite = 0;
        char *source_dir = NULL;
-       int source_dir_set = 0;
+       bool source_dir_set = false;
+       bool shrink_rootdir = false;
        u64 source_dir_size = 0;
        u64 min_dev_size;
+       u64 shrink_size;
        int dev_cnt = 0;
        int saved_optind;
        char fs_uuid[BTRFS_UUID_UNPARSED_SIZE] = { 0 };
@@ -743,6 +745,7 @@ int main(int argc, char **argv)
 
        while(1) {
                int c;
+               enum { GETOPT_VAL_SHRINK = 257 };
                static const struct option long_options[] = {
                        { "alloc-start", required_argument, NULL, 'A'},
                        { "byte-count", required_argument, NULL, 'b' },
@@ -760,6 +763,7 @@ int main(int argc, char **argv)
                        { "features", required_argument, NULL, 'O' },
                        { "uuid", required_argument, NULL, 'U' },
                        { "quiet", 0, NULL, 'q' },
+                       { "shrink", no_argument, NULL, GETOPT_VAL_SHRINK },
                        { "help", no_argument, NULL, GETOPT_VAL_HELP },
                        { NULL, 0, NULL, 0}
                };
@@ -827,7 +831,7 @@ int main(int argc, char **argv)
                                goto success;
                        case 'r':
                                source_dir = optarg;
-                               source_dir_set = 1;
+                               source_dir_set = true;
                                break;
                        case 'U':
                                strncpy(fs_uuid, optarg,
@@ -839,6 +843,10 @@ int main(int argc, char **argv)
                        case 'q':
                                verbose = 0;
                                break;
+                       case GETOPT_VAL_SHRINK:
+                               shrink_rootdir = true;
+                               break;
+                               break;
                        case GETOPT_VAL_HELP:
                        default:
                                print_usage(c != GETOPT_VAL_HELP);
@@ -861,6 +869,10 @@ int main(int argc, char **argv)
                error("the option -r is limited to a single device");
                goto error;
        }
+       if (shrink_rootdir && !source_dir_set) {
+               error("the option --shrink can only be paired with -r");
+               goto error;
+       }
 
        if (*fs_uuid) {
                uuid_t dummy_uuid;
@@ -1186,10 +1198,13 @@ raid_groups:
                        error("error wihle filling filesystem: %d", ret);
                        goto out;
                }
-               ret = btrfs_mkfs_shrink_fs(fs_info, NULL);
-               if (ret < 0) {
-                       error("error while shrinking filesystem: %d", ret);
-                       goto out;
+               if (shrink_rootdir) {
+                       ret = btrfs_mkfs_shrink_fs(fs_info, &shrink_size,
+                                                  shrink_rootdir);
+                       if (ret < 0) {
+                               error("error while shrinking filesystem: %d", 
ret);
+                               goto out;
+                       }
                }
        }
 
diff --git a/mkfs/rootdir.c b/mkfs/rootdir.c
index 9593bbc25b39..aa42d186a43f 100644
--- a/mkfs/rootdir.c
+++ b/mkfs/rootdir.c
@@ -898,11 +898,13 @@ err:
        return ret;
 }
 
-int btrfs_mkfs_shrink_fs(struct btrfs_fs_info *fs_info, u64 *new_size_ret)
+int btrfs_mkfs_shrink_fs(struct btrfs_fs_info *fs_info, u64 *new_size_ret,
+                        bool shrink_file_size)
 {
        u64 new_size;
        struct btrfs_device *device;
        struct list_head *cur;
+       struct stat64 file_stat;
        int nr_devs = 0;
        int ret;
 
@@ -930,5 +932,22 @@ int btrfs_mkfs_shrink_fs(struct btrfs_fs_info *fs_info, 
u64 *new_size_ret)
                return ret;
        if (new_size_ret)
                *new_size_ret = new_size;
+
+       if (shrink_file_size) {
+               ret = fstat64(device->fd, &file_stat);
+               if (ret < 0) {
+                       error("failed to stat devid %llu: %s", device->devid,
+                               strerror(errno));
+                       return ret;
+               }
+               if (!S_ISREG(file_stat.st_mode))
+                       return ret;
+               ret = ftruncate64(device->fd, new_size);
+               if (ret < 0) {
+                       error("failed to truncate device file of devid %llu: 
%s",
+                               device->devid, strerror(errno));
+                       return ret;
+               }
+       }
        return ret;
 }
diff --git a/mkfs/rootdir.h b/mkfs/rootdir.h
index e5b739ede48a..78bc9c90f7c5 100644
--- a/mkfs/rootdir.h
+++ b/mkfs/rootdir.h
@@ -29,5 +29,6 @@ int btrfs_mkfs_fill_dir(const char *source_dir, struct 
btrfs_root *root,
                        bool verbose);
 u64 btrfs_mkfs_size_dir(const char *dir_name, u32 sectorsize, u64 min_dev_size,
                        u64 meta_profile, u64 data_profile);
-int btrfs_mkfs_shrink_fs(struct btrfs_fs_info *fs_info, u64 *new_size_ret);
+int btrfs_mkfs_shrink_fs(struct btrfs_fs_info *fs_info, u64 *new_size_ret,
+                        bool shrink_file_size);
 #endif
-- 
2.14.2

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to