From 1c9c5f7fb3f6a2182d230d469b22b3b1329f24d8 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Thu, 19 Oct 2017 17:13:55 +0800 Subject: [PATCH] btrfs-progs: mkfs: Separate shrink from rootdir Make --shrink a separate option for --rootdir, and change the default to off. The shrinking behaviour is not a commonly used feature but can be useful for creating minimal pre-filled images, in one step, without requiring to mount. Signed-off-by: Qu Wenruo [ update changelog and error messages ] Signed-off-by: David Sterba --- 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 f69c529..153bb87 100644 --- a/Documentation/mkfs.btrfs.asciidoc +++ b/Documentation/mkfs.btrfs.asciidoc @@ -101,6 +101,17 @@ Please see the mount option 'discard' for that in `btrfs`(5). *-r|--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 [,...]*:: 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 e9136b1..16254ee 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,9 @@ int main(int argc, char **argv) case 'q': verbose = 0; break; + case GETOPT_VAL_SHRINK: + shrink_rootdir = true; + break; case GETOPT_VAL_HELP: default: print_usage(c != GETOPT_VAL_HELP); @@ -861,6 +868,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 must be used with --rootdir"); + goto error; + } if (*fs_uuid) { uuid_t dummy_uuid; @@ -1189,10 +1200,14 @@ 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 0dc022b..9be4bcb 100644 --- a/mkfs/rootdir.c +++ b/mkfs/rootdir.c @@ -899,11 +899,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; @@ -931,5 +933,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 3618b89..d0fc2eb 100644 --- a/mkfs/rootdir.h +++ b/mkfs/rootdir.h @@ -32,6 +32,7 @@ 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.7.4