diff --git a/configure.ac b/configure.ac index 887feead2..014332ea6 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 7b63b99ff..612c97f5b 100644 --- a/daemon/blkdiscard.c +++ b/daemon/blkdiscard.c @@ -25,7 +25,10 @@ #include #include #include + +#ifdef HAVE_LINUX_FS_H #include +#endif #include "daemon.h" #include "actions.h" diff --git a/generator/actions.ml b/generator/actions.ml index 88254934c..3f30d8cff 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 to describe the format of C. +If C refers to a block device, then the device is +formatted. The C 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 40a5cacf6..0cfe6bec8 100644 --- a/src/create.c +++ b/src/create.c @@ -27,8 +27,13 @@ #include #include #include +#include #include +#ifdef HAVE_LINUX_FS_H +#include +#endif + #include "guestfs.h" #include "guestfs-internal.h" #include "guestfs-internal-actions.h" @@ -89,6 +94,36 @@ guestfs__disk_create (guestfs_h *g, const char *filename, return 0; } +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);