@@ -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
@@ -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;
+ }
}
}
@@ -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;
}
@@ -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
Make --shrink a separate option for --rootdir, and make it default to off. So this will cause less confusion. Signed-off-by: Qu Wenruo <wqu@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(-)