summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2012-03-15 09:43:04 +0000
committerRichard W.M. Jones <rjones@redhat.com>2012-03-15 16:15:44 +0000
commitd9bdb9587b4e1cad0c3e9997ea7d2b2a07aed0ad (patch)
tree0e1745b31d42da17281edf59c8b1dc11480e84fd
parent7934ea2395d2a417fbc20efc22573113f7ae9d7a (diff)
downloadlibguestfs-d9bdb9587b4e1cad0c3e9997ea7d2b2a07aed0ad.tar.gz
libguestfs-d9bdb9587b4e1cad0c3e9997ea7d2b2a07aed0ad.tar.xz
libguestfs-d9bdb9587b4e1cad0c3e9997ea7d2b2a07aed0ad.zip
New API: zero_free_space: zero free space in a filesystem.
Add an API for doing what virt-sparsify was doing: freeing up free space in a filesystem. The current implementation is simple-minded: we create a file, fill it with zeroes until we run out of space, then delete the file. However the description leaves it open to do a better implementation, eg. using sparsification support that is currently being worked on in ext4 and qemu. The implementation also sends progress notifications, which is an advantage over the old 'dd' method.
-rw-r--r--daemon/zero.c104
-rw-r--r--generator/generator_actions.ml14
-rw-r--r--src/MAX_PROC_NR2
3 files changed, 119 insertions, 1 deletions
diff --git a/daemon/zero.c b/daemon/zero.c
index c45088cd..3076a602 100644
--- a/daemon/zero.c
+++ b/daemon/zero.c
@@ -24,6 +24,7 @@
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
+#include <sys/statvfs.h>
#include "daemon.h"
#include "actions.h"
@@ -226,3 +227,106 @@ do_is_zero_device (const char *device)
return 1;
}
+
+static int
+random_name (char *p)
+{
+ int fd;
+ unsigned char c;
+
+ fd = open ("/dev/urandom", O_RDONLY|O_CLOEXEC);
+ if (fd == -1) {
+ reply_with_perror ("/dev/urandom");
+ return -1;
+ }
+
+ while (*p) {
+ if (*p == 'X') {
+ if (read (fd, &c, 1) != 1) {
+ reply_with_perror ("read: /dev/urandom");
+ close (fd);
+ return -1;
+ }
+ *p = "0123456789abcdefghijklmnopqrstuvwxyz"[c % 36];
+ }
+
+ p++;
+ }
+
+ close (fd);
+ return 0;
+}
+
+/* Current implementation is to create a file of all zeroes, then
+ * delete it. The description of this function is left open in order
+ * to allow better implementations in future, including
+ * sparsification.
+ */
+int
+do_zero_free_space (const char *dir)
+{
+ size_t len = strlen (dir);
+ char filename[sysroot_len+len+14]; /* sysroot + dir + "/" + 8.3 + "\0" */
+ int fd;
+ unsigned skip = 0;
+ struct statvfs statbuf;
+ fsblkcnt_t bfree_initial;
+
+ /* Choose a randomly named 8.3 file. Because of the random name,
+ * this won't conflict with existing files, and it should be
+ * compatible with any filesystem type inc. FAT.
+ */
+ snprintf (filename, sysroot_len+len+14, "%s%s/XXXXXXXX.XXX", sysroot, dir);
+ if (random_name (&filename[sysroot_len+len]) == -1)
+ return -1;
+
+ if (verbose)
+ printf ("random filename: %s\n", filename);
+
+ /* Open file and fill with zeroes until we run out of space. */
+ fd = open (filename, O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0600);
+ if (fd == -1) {
+ reply_with_perror ("open: %s", filename);
+ return -1;
+ }
+
+ /* To estimate progress in this operation, we're going to track
+ * free blocks in this filesystem down to zero.
+ */
+ if (fstatvfs (fd, &statbuf) == -1) {
+ reply_with_perror ("fstatvfs");
+ close (fd);
+ return -1;
+ }
+ bfree_initial = statbuf.f_bfree;
+
+ for (;;) {
+ if (write (fd, zero_buf, sizeof zero_buf) == -1) {
+ if (errno == ENOSPC) /* expected error */
+ break;
+ reply_with_perror ("write: %s", filename);
+ close (fd);
+ unlink (filename);
+ return -1;
+ }
+
+ skip++;
+ if ((skip & 256) == 0 && fstatvfs (fd, &statbuf) == 0)
+ notify_progress (bfree_initial - statbuf.f_bfree, bfree_initial);
+ }
+
+ /* Make sure the file is completely written to disk. */
+ close (fd); /* expect this to give an error, don't check it */
+
+ sync_disks ();
+
+ notify_progress (bfree_initial, bfree_initial);
+
+ /* Remove the file. */
+ if (unlink (filename) == -1) {
+ reply_with_perror ("unlink: %s", filename);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml
index 4c6e704b..4b4e5ffe 100644
--- a/generator/generator_actions.ml
+++ b/generator/generator_actions.ml
@@ -6748,6 +6748,20 @@ On NTFS filesystems, labels are limited to 128 unicode characters.
To read the label on a filesystem, call C<guestfs_vfs_label>.");
+ ("zero_free_space", (RErr, [Pathname "directory"], []), 311, [Progress],
+ [InitScratchFS, Always, TestRun (
+ [["zero_free_space"; "/"]])],
+ "zero free space in a filesystem",
+ "\
+Zero the free space in the filesystem mounted on C<directory>.
+The filesystem must be mounted read-write.
+
+The filesystem contents are not affected, but any free space
+in the filesystem is freed.
+
+In future (but not currently) these zeroed blocks will be
+\"sparsified\" - that is, given back to the host.");
+
]
let all_functions = non_daemon_functions @ daemon_functions
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index 54ea97e9..b661fff6 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-310
+311