diff options
| author | Richard W.M. Jones <rjones@redhat.com> | 2012-03-15 09:43:04 +0000 |
|---|---|---|
| committer | Richard W.M. Jones <rjones@redhat.com> | 2012-03-15 16:15:44 +0000 |
| commit | d9bdb9587b4e1cad0c3e9997ea7d2b2a07aed0ad (patch) | |
| tree | 0e1745b31d42da17281edf59c8b1dc11480e84fd | |
| parent | 7934ea2395d2a417fbc20efc22573113f7ae9d7a (diff) | |
| download | libguestfs-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.c | 104 | ||||
| -rw-r--r-- | generator/generator_actions.ml | 14 | ||||
| -rw-r--r-- | src/MAX_PROC_NR | 2 |
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 |
