lxd/storage_lvm_utils.go
func (s *storageLvm) copyContainerLv(target container, source container, readonly bool, refresh bool) error {
	exists, err := storageLVExists(getLvmDevPath(target.Project(), s.getOnDiskPoolName(),
		storagePoolVolumeAPIEndpointContainers, containerNameToLVName(target.Name())))
	if err != nil {
		return err
	}

	// Only create container/snapshot if it doesn't already exist
	if !exists {
		err := s.ContainerCreate(target)
		if err != nil {
			return err
		}
	}

	targetName := target.Name()
	targetStart, err := target.StorageStart()
	if err != nil {
		return err
	}
	if targetStart {
		defer target.StorageStop()
	}

	sourceName := source.Name()
	sourceStart, err := source.StorageStart()
	if err != nil {
		return err
	}
	if sourceStart {
		defer source.StorageStop()
	}

	sourcePool, err := source.StoragePool()
	if err != nil {
		return err
	}
	sourceContainerMntPoint := getContainerMountPoint(source.Project(), sourcePool, sourceName)
	if source.IsSnapshot() {
		sourceContainerMntPoint = getSnapshotMountPoint(source.Project(), sourcePool, sourceName)
	}

	targetContainerMntPoint := getContainerMountPoint(target.Project(), s.pool.Name, targetName)
	if target.IsSnapshot() {
		targetContainerMntPoint = getSnapshotMountPoint(source.Project(), s.pool.Name, targetName)
	}

	if source.IsRunning() {
		err = source.Freeze()
		if err != nil {
			return err
		}
		defer source.Unfreeze()
	}

	bwlimit := s.pool.Config["rsync.bwlimit"]
	output, err := rsyncLocalCopy(sourceContainerMntPoint, targetContainerMntPoint, bwlimit)
	if err != nil {
		return fmt.Errorf("failed to rsync container: %s: %s", string(output), err)
	}

	if readonly {
		targetLvmName := containerNameToLVName(targetName)
		poolName := s.getOnDiskPoolName()
		output, err := shared.TryRunCommand("lvchange", "-pr", fmt.Sprintf("%s/%s_%s", poolName, storagePoolVolumeAPIEndpointContainers, targetLvmName))
		if err != nil {
			logger.Errorf("Failed to make LVM snapshot \"%s\" read-write: %s", targetName, output)
			return err
		}
	}

	return nil
}
func (s *storageLvm) copyContainerLv(target container, source container, readonly bool, refresh bool) error {
	exists, err := storageLVExists(getLvmDevPath(target.Project(), s.getOnDiskPoolName(),
		storagePoolVolumeAPIEndpointContainers, containerNameToLVName(target.Name())))
	if err != nil {
		return err
	}

	// Only create container/snapshot if it doesn't already exist
	if !exists {
		err := s.ContainerCreate(target)
		if err != nil {
			return err
		}
	}

	targetName := target.Name()
	targetStart, err := target.StorageStart()
	if err != nil {
		return err
	}
	if targetStart {
		defer target.StorageStop()
	}

	sourceName := source.Name()
	sourceStart, err := source.StorageStart()
	if err != nil {
		return err
	}
	if sourceStart {
		defer source.StorageStop()
	}

	sourcePool, err := source.StoragePool()
	if err != nil {
		return err
	}
	sourceContainerMntPoint := getContainerMountPoint(source.Project(), sourcePool, sourceName)
	if source.IsSnapshot() {
		sourceContainerMntPoint = getSnapshotMountPoint(source.Project(), sourcePool, sourceName)
	}

	targetContainerMntPoint := getContainerMountPoint(target.Project(), s.pool.Name, targetName)
	if target.IsSnapshot() {
		targetContainerMntPoint = getSnapshotMountPoint(source.Project(), s.pool.Name, targetName)
	}

	if source.IsRunning() {
		err = source.Freeze()
		if err != nil {
			return err
		}
		defer source.Unfreeze()
	}

	bwlimit := s.pool.Config["rsync.bwlimit"]
	output, err := rsyncLocalCopy(sourceContainerMntPoint, targetContainerMntPoint, bwlimit)
	if err != nil {
		return fmt.Errorf("failed to rsync container: %s: %s", string(output), err)
	}

	if readonly {
		targetLvmName := containerNameToLVName(targetName)
		poolName := s.getOnDiskPoolName()
		output, err := shared.TryRunCommand("lvchange", "-pr", fmt.Sprintf("%s/%s_%s", poolName, storagePoolVolumeAPIEndpointContainers, targetLvmName))
		if err != nil {
			logger.Errorf("Failed to make LVM snapshot \"%s\" read-write: %s", targetName, output)
			return err
		}
	}

	return nil
}
// Copy a container on a storage pool that does not use a thinpool.