When you call guestfs_disk_create on a block device with format=raw
then it will try to discard the blocks on the device.
---
configure.ac | 1 +
daemon/blkdiscard.c | 3 +++
generator/actions.ml | 4 ++++
src/create.c | 46 +++++++++++++++++++++++++++++++++++++++-------
4 files changed, 47 insertions(+), 7 deletions(-)
diff --git a/configure.ac b/configure.ac
index 887feea..014332e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -291,6 +291,7 @@ AC_CHECK_HEADERS([\
byteswap.h \
endian.h \
errno.h \
+ linux/fs.h \
linux/raid/md_u.h \
printf.h \
sys/inotify.h \
diff --git a/daemon/blkdiscard.c b/daemon/blkdiscard.c
index 7b63b99..612c97f 100644
--- a/daemon/blkdiscard.c
+++ b/daemon/blkdiscard.c
@@ -25,7 +25,10 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
+
+#ifdef HAVE_LINUX_FS_H
#include <linux/fs.h>
+#endif
#include "daemon.h"
#include "actions.h"
diff --git a/generator/actions.ml b/generator/actions.ml
index 8825493..3f30d8c 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -3084,6 +3084,10 @@ size of the backing file, which is discovered automatically. You
are encouraged to also pass C<backingformat> to describe the format
of C<backingfile>.
+If C<filename> refers to a block device, then the device is
+formatted. The C<size> is ignored since block devices have an
+intrinsic size.
+
The other optional parameters are:
=over 4
diff --git a/src/create.c b/src/create.c
index 40a5cac..0cfe6be 100644
--- a/src/create.c
+++ b/src/create.c
@@ -27,8 +27,13 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
+#include <sys/ioctl.h>
#include <errno.h>
+#ifdef HAVE_LINUX_FS_H
+#include <linux/fs.h>
+#endif
+
#include "guestfs.h"
#include "guestfs-internal.h"
#include "guestfs-internal-actions.h"
@@ -90,6 +95,36 @@ guestfs__disk_create (guestfs_h *g, const char *filename,
}
static int
+disk_create_raw_block (guestfs_h *g, const char *filename)
+{
+ int fd;
+
+ fd = open (filename, O_WRONLY|O_NOCTTY|O_CLOEXEC, 0666);
+ if (fd == -1) {
+ perrorf (g, _("cannot open block device: %s"), filename);
+ return -1;
+ }
+
+ /* Just discard blocks, if possible. However don't try too hard. */
+#if defined(BLKGETSIZE64) && defined(BLKDISCARD)
+ uint64_t size;
+ uint64_t range[2];
+
+ if (ioctl (fd, BLKGETSIZE64, &size) == 0) {
+ range[0] = 0;
+ range[1] = size;
+ if (ioctl (fd, BLKDISCARD, range) == 0)
+ debug (g, "disk_create: %s: BLKDISCARD failed on this device: %m",
+ filename);
+ }
+#endif
+
+ close (fd);
+
+ return 0;
+}
+
+static int
disk_create_raw (guestfs_h *g, const char *filename, int64_t size,
const struct guestfs_disk_create_argv *optargs)
{
@@ -123,18 +158,15 @@ disk_create_raw (guestfs_h *g, const char *filename, int64_t size,
return -1;
}
- /* This version refuses to overwrite block devices or char devices.
- * XXX It would be possible to make it work with block devices.
- */
if (stat (filename, &statbuf) == 0) {
- if (S_ISBLK (statbuf.st_mode)) {
- error (g, _("refusing to overwrite block device '%s'"),
filename);
- return -1;
- }
+ /* Refuse to overwrite char devices. */
if (S_ISCHR (statbuf.st_mode)) {
error (g, _("refusing to overwrite char device '%s'"),
filename);
return -1;
}
+ /* Block devices have to be handled specially. */
+ if (S_ISBLK (statbuf.st_mode))
+ return disk_create_raw_block (g, filename);
}
fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_TRUNC|O_CLOEXEC, 0666);
--
1.8.5.3
Show replies by date