[libvirt] [PATCH 8/9] Simplified version of volume zeroing based on feedback from the list.
Daniel P. Berrange
berrange at redhat.com
Thu Mar 4 10:22:12 UTC 2010
On Tue, Mar 02, 2010 at 05:13:33PM -0500, David Allan wrote:
> @@ -1518,6 +1521,220 @@ cleanup:
> return ret;
> +
> +static int
> +storageZeroExtent(virStorageVolDefPtr vol,
> + struct stat *st,
> + int fd,
> + size_t extent_start,
> + size_t extent_length,
> + char *writebuf,
> + size_t *bytes_zeroed)
> +{
> + int ret = -1, written;
> + size_t remaining, write_size;
> + char errbuf[64];
> +
> + VIR_DEBUG("extent logical start: %zu len: %zu ",
> + extent_start, extent_length);
> +
> + if ((ret = lseek(fd, extent_start, SEEK_SET)) < 0) {
> + virReportSystemError(ret, "Failed to seek to position %zu in volume "
> + "with path '%s': '%s'",
> + extent_start, vol->target.path,
> + virStrerror(errno, errbuf, sizeof(errbuf)));
> + goto out;
> + }
> +
> + remaining = extent_length;
> + while (remaining > 0) {
> +
> + write_size = (st->st_blksize < remaining) ? st->st_blksize : remaining;
> + written = safewrite(fd, writebuf, write_size);
This is a little fragile, because its making storageZeroExtent() assume that the
passed in 'writebuf' is st->st_blksize. I think it'd be better if a 'writebuflen'
were passed in from the caller
> + if (written < 0) {
> + virReportSystemError(written,
> + _("Failed to write to storage volume with "
> + "path '%s': '%s' "
> + "(attempted to write %d bytes)"),
> + vol->target.path,
> + virStrerror(errno, errbuf, sizeof(errbuf)),
> + write_size);
> + goto out;
> + }
> +
> + *bytes_zeroed += written;
> + remaining -= written;
> + }
> +
> + VIR_DEBUG("Wrote %zu bytes to volume with path '%s'",
> + *bytes_zeroed, vol->target.path);
> +
> + ret = 0;
> +
> +out:
> + return ret;
> +}
> +
> +
> +static int
> +storageVolumeZeroOutInternal(virStorageVolDefPtr def)
> +{
> + int ret = -1, fd = -1;
> + char errbuf[64];
> + struct stat st;
> + char *writebuf;
> + size_t bytes_zeroed = 0;
> +
> + VIR_DEBUG("Zeroing out volume with path '%s'", def->target.path);
> +
> + fd = open(def->target.path, O_RDWR);
> + if (fd == -1) {
> + VIR_ERROR("Failed to open storage volume with path '%s': '%s'",
> + def->target.path,
> + virStrerror(errno, errbuf, sizeof(errbuf)));
> + goto out;
> + }
> +
> + memset(&st, 0, sizeof(st));
That's redundant I believe - at least no other fstat calls ever memset
their buffer ahead of time.
> +
> + if (fstat(fd, &st) == -1) {
> + VIR_ERROR("Failed to stat storage volume with path '%s': '%s'",
> + def->target.path,
> + virStrerror(errno, errbuf, sizeof(errbuf)));
> + goto out;
> + }
> +
> + if (S_ISREG(st.st_mode) && st.st_blocks < (st.st_size / DEV_BSIZE)) {
> + ret = storageVolumeZeroSparseFile(def, &st, fd);
> + } else {
> +
> + if (VIR_ALLOC_N(writebuf, st.st_blksize) != 0) {
> + virReportOOMError();
> + goto out;
> + }
> +
> + ret = storageZeroExtent(def,
> + &st,
> + fd,
> + 0,
> + def->allocation,
> + writebuf,
> + &bytes_zeroed);
Add st.st_blksize as a param here
> + }
> +
> +out:
> + VIR_FREE(writebuf);
> +
> + if (fd != -1) {
> + close(fd);
> + }
> +
> + return ret;
> +}
> +
> +
> +static int
> +storageVolumeZeroOut(virStorageVolPtr obj,
> + unsigned int flags ATTRIBUTE_UNUSED)
> +{
> + virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
> + virStoragePoolObjPtr pool;
> + virStorageVolDefPtr vol = NULL;
> + int ret = -1;
As Eric suggested, this would be a good time to do an explicit 'flags == 0'
check, so that callers can detect whether a flag is supported or not.
> +
> + storageDriverLock(driver);
> + pool = virStoragePoolObjFindByName(&driver->pools, obj->pool);
> + storageDriverUnlock(driver);
> +
> + if (!pool) {
> + virStorageReportError(VIR_ERR_INVALID_STORAGE_POOL,
> + "%s", _("no storage pool with matching uuid"));
> + goto out;
> + }
> +
> + if (!virStoragePoolObjIsActive(pool)) {
> + virStorageReportError(VIR_ERR_INTERNAL_ERROR,
> + "%s", _("storage pool is not active"));
> + goto out;
> + }
> +
> + vol = virStorageVolDefFindByName(pool, obj->name);
> +
> + if (vol == NULL) {
> + virStorageReportError(VIR_ERR_NO_STORAGE_VOL,
> + _("no storage vol with matching name '%s'"),
> + obj->name);
> + goto out;
> + }
> +
> + if (vol->building) {
> + virStorageReportError(VIR_ERR_INTERNAL_ERROR,
> + _("volume '%s' is still being allocated."),
> + vol->name);
> + goto out;
> + }
> +
> + if (storageVolumeZeroOutInternal(vol) == -1) {
> + goto out;
> + }
> +
> + ret = 0;
> +
> +out:
> + if (pool) {
> + virStoragePoolObjUnlock(pool);
> + }
> +
> + return ret;
> +
> +}
> +
> static int
> storageVolumeDelete(virStorageVolPtr obj,
> unsigned int flags) {
> @@ -1775,6 +1992,7 @@ static virStorageDriver storageDriver = {
> .volCreateXML = storageVolumeCreateXML,
> .volCreateXMLFrom = storageVolumeCreateXMLFrom,
> .volDelete = storageVolumeDelete,
> + .volZeroOut = storageVolumeZeroOut,
> .volGetInfo = storageVolumeGetInfo,
> .volGetXMLDesc = storageVolumeGetXMLDesc,
> .volGetPath = storageVolumeGetPath,
> --
Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
More information about the libvir-list
mailing list