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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list