[Libguestfs] [PATCH] disk-create: Fix this API so it works correctly with block devices (RHBZ#1088262).

Richard W.M. Jones rjones at redhat.com
Wed Apr 16 11:09:55 UTC 2014


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




More information about the Libguestfs mailing list