From 5b6716cee8bb69c5f309ce19e7e47da1f74992d9 Mon Sep 17 00:00:00 2001
From: SamYaple <sam@yaple.net>
Date: Wed, 9 Mar 2016 22:43:27 +0000
Subject: [PATCH] Use fstrim to prep the block device

This cuts the image size down alot, esspecially if there were lots of
small file deletes.

The fstrim utility is in the util-linux package and should be on
most all systems. fstrim also works with XFS, ext4, btrfs, etc
prodiving the kernel is new enough.

A reduction of 25% or more in size is common.

Change-Id: I269b4416be450369616f9b8e030f84c30e329804
---
 bin/disk-image-create           | 11 +++++++++++
 doc/source/developer/design.rst |  7 +++++++
 lib/img-functions               | 11 +++++++++++
 3 files changed, 29 insertions(+)

diff --git a/bin/disk-image-create b/bin/disk-image-create
index 455ebda81..f62889752 100755
--- a/bin/disk-image-create
+++ b/bin/disk-image-create
@@ -264,6 +264,14 @@ for X in ${!IMAGE_TYPES[@]}; do
     esac
 done
 
+# NOTE: fstrim is on most all recent systems. It is provided by the util-linux
+# package.
+if [[ -z "$(which fstrim)" ]]; then
+    echo "fstrim utility is not found. This is provided by util-linux package"
+    echo "Please check your PATH variable is set correctly"
+    exit 1
+fi
+
 # NOTE: Tuning the rootfs uuid works only for ext filesystems.
 # Rely on the below environment variable only for ext filesystems.
 export DIB_IMAGE_ROOT_FS_UUID=$(uuidgen -r)
@@ -387,6 +395,9 @@ for X in ${!IMAGE_TYPES[@]} ; do
   fi
 done
 
+# Prep filesystem by discarding all unused space
+fstrim_image
+
 # Unmount and cleanup the /mnt and /build subdirectories, to save
 # space before converting the image to some other format.
 unmount_image
diff --git a/doc/source/developer/design.rst b/doc/source/developer/design.rst
index e767eadc9..df0cecf1b 100644
--- a/doc/source/developer/design.rst
+++ b/doc/source/developer/design.rst
@@ -12,6 +12,13 @@ and file system) is created and the tree copied into it. The file system
 created is an ext4 filesystem just large enough to hold the file system tree
 and can be resized up to 1PB in size.
 
+To produce the smallest image the utility fstrim is used. When deleting a file
+the space is simply marked as free on the disk, the file is still there until
+it is overwritten. fstrim informs the underlying disk to drop those bytes the
+end result of which is like writting zeros over those sectors. The same effect
+could be achieved by creating a large file full of zeros and removing that
+file, however that method is far more IO intensive.
+
 An element is a particular set of code that alters how the image is built, or
 runs within the chroot to prepare the image. E.g. the local-config element
 copies in the http proxy and ssh keys of the user running the image build
diff --git a/lib/img-functions b/lib/img-functions
index cf817ae89..908123ce9 100644
--- a/lib/img-functions
+++ b/lib/img-functions
@@ -29,6 +29,17 @@ function unmount_image () {
     fi
 }
 
+function fstrim_image () {
+    # A race condition can occur when trying to fstrim immediately after
+    # deleting a file resulting in that free space not being reclaimed.
+    # Calling sync before fstrim is a workaround for this behaviour.
+    # https://lists.gnu.org/archive/html/qemu-devel/2014-03/msg02978.html
+    sync
+
+    # Discard all unused bytes
+    sudo fstrim "${TMP_BUILD_DIR}/mnt"
+}
+
 function trap_cleanup() {
     exitval=$?
     cleanup