The next patch will move the storage volume wiping code into the
individual backends. This patch splits out the common code to wipe a
local volume into a separate backend helper so that the next patch is
simpler.
---
src/storage/storage_backend.c | 203 ++++++++++++++++++++++++++++++++++++++++++
src/storage/storage_backend.h | 6 ++
src/storage/storage_driver.c | 199 +----------------------------------------
3 files changed, 210 insertions(+), 198 deletions(-)
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c
index 7b17ca4..8e62403 100644
--- a/src/storage/storage_backend.c
+++ b/src/storage/storage_backend.c
@@ -1700,6 +1700,209 @@ virStorageBackendVolDownloadLocal(virConnectPtr conn
ATTRIBUTE_UNUSED,
return virFDStreamOpenFile(stream, vol->target.path, offset, len, O_RDONLY);
}
+
+/* If the volume we're wiping is already a sparse file, we simply
+ * truncate and extend it to its original size, filling it with
+ * zeroes. This behavior is guaranteed by POSIX:
+ *
+ *
http://www.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html
+ *
+ * If fildes refers to a regular file, the ftruncate() function shall
+ * cause the size of the file to be truncated to length. If the size
+ * of the file previously exceeded length, the extra data shall no
+ * longer be available to reads on the file. If the file previously
+ * was smaller than this size, ftruncate() shall increase the size of
+ * the file. If the file size is increased, the extended area shall
+ * appear as if it were zero-filled.
+ */
+static int
+virStorageBackendVolZeroSparseFileLocal(virStorageVolDefPtr vol,
+ off_t size,
+ int fd)
+{
+ int ret = -1;
+
+ ret = ftruncate(fd, 0);
+ if (ret == -1) {
+ virReportSystemError(errno,
+ _("Failed to truncate volume with "
+ "path '%s' to 0 bytes"),
+ vol->target.path);
+ return ret;
+ }
+
+ ret = ftruncate(fd, size);
+ if (ret == -1) {
+ virReportSystemError(errno,
+ _("Failed to truncate volume with "
+ "path '%s' to %ju bytes"),
+ vol->target.path, (uintmax_t)size);
+ }
+
+ return ret;
+}
+
+
+static int
+virStorageBackendWipeExtentLocal(virStorageVolDefPtr vol,
+ int fd,
+ off_t extent_start,
+ off_t extent_length,
+ char *writebuf,
+ size_t writebuf_length,
+ size_t *bytes_wiped)
+{
+ int ret = -1, written = 0;
+ off_t remaining = 0;
+ size_t write_size = 0;
+
+ VIR_DEBUG("extent logical start: %ju len: %ju",
+ (uintmax_t)extent_start, (uintmax_t)extent_length);
+
+ if ((ret = lseek(fd, extent_start, SEEK_SET)) < 0) {
+ virReportSystemError(errno,
+ _("Failed to seek to position %ju in volume "
+ "with path '%s'"),
+ (uintmax_t)extent_start, vol->target.path);
+ goto cleanup;
+ }
+
+ remaining = extent_length;
+ while (remaining > 0) {
+
+ write_size = (writebuf_length < remaining) ? writebuf_length : remaining;
+ written = safewrite(fd, writebuf, write_size);
+ if (written < 0) {
+ virReportSystemError(errno,
+ _("Failed to write %zu bytes to "
+ "storage volume with path '%s'"),
+ write_size, vol->target.path);
+
+ goto cleanup;
+ }
+
+ *bytes_wiped += written;
+ remaining -= written;
+ }
+
+ if (fdatasync(fd) < 0) {
+ ret = -errno;
+ virReportSystemError(errno,
+ _("cannot sync data to volume with path
'%s'"),
+ vol->target.path);
+ goto cleanup;
+ }
+
+ VIR_DEBUG("Wrote %zu bytes to volume with path '%s'",
+ *bytes_wiped, vol->target.path);
+
+ ret = 0;
+
+ cleanup:
+ return ret;
+}
+
+
+int
+virStorageBackendVolWipeLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
+ virStorageVolDefPtr vol,
+ unsigned int algorithm,
+ unsigned int flags)
+{
+ int ret = -1, fd = -1;
+ struct stat st;
+ char *writebuf = NULL;
+ size_t bytes_wiped = 0;
+ virCommandPtr cmd = NULL;
+
+ virCheckFlags(0, -1);
+
+ VIR_DEBUG("Wiping volume with path '%s' and algorithm %u",
+ vol->target.path, algorithm);
+
+ fd = open(vol->target.path, O_RDWR);
+ if (fd == -1) {
+ virReportSystemError(errno,
+ _("Failed to open storage volume with path
'%s'"),
+ vol->target.path);
+ goto cleanup;
+ }
+
+ if (fstat(fd, &st) == -1) {
+ virReportSystemError(errno,
+ _("Failed to stat storage volume with path
'%s'"),
+ vol->target.path);
+ goto cleanup;
+ }
+
+ if (algorithm != VIR_STORAGE_VOL_WIPE_ALG_ZERO) {
+ const char *alg_char ATTRIBUTE_UNUSED = NULL;
+ switch (algorithm) {
+ case VIR_STORAGE_VOL_WIPE_ALG_NNSA:
+ alg_char = "nnsa";
+ break;
+ case VIR_STORAGE_VOL_WIPE_ALG_DOD:
+ alg_char = "dod";
+ break;
+ case VIR_STORAGE_VOL_WIPE_ALG_BSI:
+ alg_char = "bsi";
+ break;
+ case VIR_STORAGE_VOL_WIPE_ALG_GUTMANN:
+ alg_char = "gutmann";
+ break;
+ case VIR_STORAGE_VOL_WIPE_ALG_SCHNEIER:
+ alg_char = "schneier";
+ break;
+ case VIR_STORAGE_VOL_WIPE_ALG_PFITZNER7:
+ alg_char = "pfitzner7";
+ break;
+ case VIR_STORAGE_VOL_WIPE_ALG_PFITZNER33:
+ alg_char = "pfitzner33";
+ break;
+ case VIR_STORAGE_VOL_WIPE_ALG_RANDOM:
+ alg_char = "random";
+ break;
+ default:
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("unsupported algorithm %d"),
+ algorithm);
+ }
+ cmd = virCommandNew(SCRUB);
+ virCommandAddArgList(cmd, "-f", "-p", alg_char,
+ vol->target.path, NULL);
+
+ if (virCommandRun(cmd, NULL) < 0)
+ goto cleanup;
+
+ ret = 0;
+ goto cleanup;
+ } else {
+ if (S_ISREG(st.st_mode) && st.st_blocks < (st.st_size / DEV_BSIZE)) {
+ ret = virStorageBackendVolZeroSparseFileLocal(vol, st.st_size, fd);
+ } else {
+
+ if (VIR_ALLOC_N(writebuf, st.st_blksize) < 0)
+ goto cleanup;
+
+ ret = virStorageBackendWipeExtentLocal(vol,
+ fd,
+ 0,
+ vol->target.allocation,
+ writebuf,
+ st.st_blksize,
+ &bytes_wiped);
+ }
+ }
+
+ cleanup:
+ virCommandFree(cmd);
+ VIR_FREE(writebuf);
+ VIR_FORCE_CLOSE(fd);
+ return ret;
+}
+
+
#ifdef GLUSTER_CLI
int
virStorageBackendFindGlusterPoolSources(const char *host,
diff --git a/src/storage/storage_backend.h b/src/storage/storage_backend.h
index 4d7d4b0..5e251d7 100644
--- a/src/storage/storage_backend.h
+++ b/src/storage/storage_backend.h
@@ -120,6 +120,12 @@ int virStorageBackendVolDownloadLocal(virConnectPtr conn,
unsigned long long len,
unsigned int flags);
+int virStorageBackendVolWipeLocal(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ virStorageVolDefPtr vol,
+ unsigned int algorithm,
+ unsigned int flags);
+
typedef struct _virStorageBackend virStorageBackend;
typedef virStorageBackend *virStorageBackendPtr;
diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c
index 5407dfb..97571e8 100644
--- a/src/storage/storage_driver.c
+++ b/src/storage/storage_driver.c
@@ -2094,202 +2094,6 @@ storageVolResize(virStorageVolPtr obj,
return ret;
}
-/* If the volume we're wiping is already a sparse file, we simply
- * truncate and extend it to its original size, filling it with
- * zeroes. This behavior is guaranteed by POSIX:
- *
- *
http://www.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html
- *
- * If fildes refers to a regular file, the ftruncate() function shall
- * cause the size of the file to be truncated to length. If the size
- * of the file previously exceeded length, the extra data shall no
- * longer be available to reads on the file. If the file previously
- * was smaller than this size, ftruncate() shall increase the size of
- * the file. If the file size is increased, the extended area shall
- * appear as if it were zero-filled.
- */
-static int
-storageVolZeroSparseFile(virStorageVolDefPtr vol,
- off_t size,
- int fd)
-{
- int ret = -1;
-
- ret = ftruncate(fd, 0);
- if (ret == -1) {
- virReportSystemError(errno,
- _("Failed to truncate volume with "
- "path '%s' to 0 bytes"),
- vol->target.path);
- return ret;
- }
-
- ret = ftruncate(fd, size);
- if (ret == -1) {
- virReportSystemError(errno,
- _("Failed to truncate volume with "
- "path '%s' to %ju bytes"),
- vol->target.path, (uintmax_t)size);
- }
-
- return ret;
-}
-
-
-static int
-storageWipeExtent(virStorageVolDefPtr vol,
- int fd,
- off_t extent_start,
- off_t extent_length,
- char *writebuf,
- size_t writebuf_length,
- size_t *bytes_wiped)
-{
- int ret = -1, written = 0;
- off_t remaining = 0;
- size_t write_size = 0;
-
- VIR_DEBUG("extent logical start: %ju len: %ju",
- (uintmax_t)extent_start, (uintmax_t)extent_length);
-
- if ((ret = lseek(fd, extent_start, SEEK_SET)) < 0) {
- virReportSystemError(errno,
- _("Failed to seek to position %ju in volume "
- "with path '%s'"),
- (uintmax_t)extent_start, vol->target.path);
- goto cleanup;
- }
-
- remaining = extent_length;
- while (remaining > 0) {
-
- write_size = (writebuf_length < remaining) ? writebuf_length : remaining;
- written = safewrite(fd, writebuf, write_size);
- if (written < 0) {
- virReportSystemError(errno,
- _("Failed to write %zu bytes to "
- "storage volume with path '%s'"),
- write_size, vol->target.path);
-
- goto cleanup;
- }
-
- *bytes_wiped += written;
- remaining -= written;
- }
-
- if (fdatasync(fd) < 0) {
- ret = -errno;
- virReportSystemError(errno,
- _("cannot sync data to volume with path
'%s'"),
- vol->target.path);
- goto cleanup;
- }
-
- VIR_DEBUG("Wrote %zu bytes to volume with path '%s'",
- *bytes_wiped, vol->target.path);
-
- ret = 0;
-
- cleanup:
- return ret;
-}
-
-
-static int
-storageVolWipeInternal(virStorageVolDefPtr def,
- unsigned int algorithm)
-{
- int ret = -1, fd = -1;
- struct stat st;
- char *writebuf = NULL;
- size_t bytes_wiped = 0;
- virCommandPtr cmd = NULL;
-
- VIR_DEBUG("Wiping volume with path '%s' and algorithm %u",
- def->target.path, algorithm);
-
- fd = open(def->target.path, O_RDWR);
- if (fd == -1) {
- virReportSystemError(errno,
- _("Failed to open storage volume with path
'%s'"),
- def->target.path);
- goto cleanup;
- }
-
- if (fstat(fd, &st) == -1) {
- virReportSystemError(errno,
- _("Failed to stat storage volume with path
'%s'"),
- def->target.path);
- goto cleanup;
- }
-
- if (algorithm != VIR_STORAGE_VOL_WIPE_ALG_ZERO) {
- const char *alg_char ATTRIBUTE_UNUSED = NULL;
- switch (algorithm) {
- case VIR_STORAGE_VOL_WIPE_ALG_NNSA:
- alg_char = "nnsa";
- break;
- case VIR_STORAGE_VOL_WIPE_ALG_DOD:
- alg_char = "dod";
- break;
- case VIR_STORAGE_VOL_WIPE_ALG_BSI:
- alg_char = "bsi";
- break;
- case VIR_STORAGE_VOL_WIPE_ALG_GUTMANN:
- alg_char = "gutmann";
- break;
- case VIR_STORAGE_VOL_WIPE_ALG_SCHNEIER:
- alg_char = "schneier";
- break;
- case VIR_STORAGE_VOL_WIPE_ALG_PFITZNER7:
- alg_char = "pfitzner7";
- break;
- case VIR_STORAGE_VOL_WIPE_ALG_PFITZNER33:
- alg_char = "pfitzner33";
- break;
- case VIR_STORAGE_VOL_WIPE_ALG_RANDOM:
- alg_char = "random";
- break;
- default:
- virReportError(VIR_ERR_INVALID_ARG,
- _("unsupported algorithm %d"),
- algorithm);
- }
- cmd = virCommandNew(SCRUB);
- virCommandAddArgList(cmd, "-f", "-p", alg_char,
- def->target.path, NULL);
-
- if (virCommandRun(cmd, NULL) < 0)
- goto cleanup;
-
- ret = 0;
- goto cleanup;
- } else {
- if (S_ISREG(st.st_mode) && st.st_blocks < (st.st_size / DEV_BSIZE)) {
- ret = storageVolZeroSparseFile(def, st.st_size, fd);
- } else {
-
- if (VIR_ALLOC_N(writebuf, st.st_blksize) < 0)
- goto cleanup;
-
- ret = storageWipeExtent(def,
- fd,
- 0,
- def->target.allocation,
- writebuf,
- st.st_blksize,
- &bytes_wiped);
- }
- }
-
- cleanup:
- virCommandFree(cmd);
- VIR_FREE(writebuf);
- VIR_FORCE_CLOSE(fd);
- return ret;
-}
-
static int
storageVolWipePattern(virStorageVolPtr obj,
@@ -2330,9 +2134,8 @@ storageVolWipePattern(virStorageVolPtr obj,
goto cleanup;
}
- if (storageVolWipeInternal(vol, algorithm) == -1) {
+ if (virStorageBackendVolWipeLocal(obj->conn, pool, vol, algorithm, flags) < 0)
goto cleanup;
- }
ret = 0;
--
2.0.0