func (devices *DeviceSet) createRegisterDevice(hash string) (*DevInfo, error) { deviceId, err := devices.getNextFreeDeviceId() if err != nil { return nil, err } if err := devices.openTransaction(hash, deviceId); err != nil { log.Debugf("Error opening transaction hash = %s deviceId = %d", hash, deviceId) devices.markDeviceIdFree(deviceId) return nil, err } for { if err := devicemapper.CreateDevice(devices.getPoolDevName(), deviceId); err != nil { if devicemapper.DeviceIdExists(err) { // Device Id already exists. This should not // happen. Now we have a mechianism to find // a free device Id. So something is not right. // Give a warning and continue. log.Errorf("Warning: Device Id %d exists in pool but it is supposed to be unused", deviceId) deviceId, err = devices.getNextFreeDeviceId() if err != nil { return nil, err } // Save new device id into transaction devices.refreshTransaction(deviceId) continue } log.Debugf("Error creating device: %s", err) devices.markDeviceIdFree(deviceId) return nil, err } break } log.Debugf("Registering device (id %v) with FS size %v", deviceId, devices.baseFsSize) info, err := devices.registerDevice(deviceId, hash, devices.baseFsSize, devices.OpenTransactionId) if err != nil { _ = devicemapper.DeleteDevice(devices.getPoolDevName(), deviceId) devices.markDeviceIdFree(deviceId) return nil, err } if err := devices.closeTransaction(); err != nil { devices.unregisterDevice(deviceId, hash) devicemapper.DeleteDevice(devices.getPoolDevName(), deviceId) devices.markDeviceIdFree(deviceId) return nil, err } return info, nil }
func (devices *DeviceSet) AddDevice(hash, baseHash string) error { baseInfo, err := devices.lookupDevice(baseHash) if err != nil { return err } baseInfo.lock.Lock() defer baseInfo.lock.Unlock() devices.Lock() defer devices.Unlock() if info, _ := devices.lookupDevice(hash); info != nil { return fmt.Errorf("device %s already exists", hash) } deviceId := devices.NextDeviceId if err := devicemapper.CreateSnapDevice(devices.getPoolDevName(), &deviceId, baseInfo.Name(), baseInfo.DeviceId); err != nil { log.Debugf("Error creating snap device: %s", err) return err } // Ids are 24bit, so wrap around devices.NextDeviceId = (deviceId + 1) & 0xffffff if _, err := devices.registerDevice(deviceId, hash, baseInfo.Size); err != nil { devicemapper.DeleteDevice(devices.getPoolDevName(), deviceId) log.Debugf("Error registering device: %s", err) return err } return nil }
func (d *Driver) DeleteSnapshot(id, volumeID string) error { snapshot, volume, err := d.getSnapshotAndVolume(id, volumeID) if err != nil { return err } log.WithFields(logrus.Fields{ LOG_FIELD_REASON: LOG_REASON_START, LOG_FIELD_EVENT: LOG_EVENT_REMOVE, LOG_FIELD_OBJECT: LOG_OBJECT_SNAPSHOT, LOG_FIELD_SNAPSHOT: id, LOG_FIELD_VOLUME: volumeID, }).Debugf("Deleting snapshot for volume") err = devicemapper.DeleteDevice(d.ThinpoolDevice, snapshot.DevID) if err != nil { return err } log.Debug("Deleted snapshot device") delete(volume.Snapshots, id) if err = util.ObjectSave(volume); err != nil { return err } return nil }
func (d *Driver) DeleteVolume(id string) error { var err error volume := d.loadVolume(id) if volume == nil { return generateError(logrus.Fields{ LOG_FIELD_VOLUME: id, }, "cannot find volume") } if len(volume.Snapshots) != 0 { for snapshotUUID := range volume.Snapshots { if err = d.DeleteSnapshot(snapshotUUID, volume.UUID); err != nil { return generateError(logrus.Fields{ LOG_FIELD_VOLUME: volume.UUID, LOG_FIELD_SNAPSHOT: snapshotUUID, }, "cannot remove an snapshot of volume, as part of deletion of volume") } } } if err = devicemapper.RemoveDevice(id); err != nil { return err } log.WithFields(logrus.Fields{ LOG_FIELD_REASON: LOG_REASON_START, LOG_FIELD_EVENT: LOG_EVENT_REMOVE, LOG_FIELD_OBJECT: LOG_OBJECT_VOLUME, LOG_FIELD_VOLUME: id, DM_LOG_FIELD_VOLUME_DEVID: volume.DevID, }).Debugf("Deleting device") err = devicemapper.DeleteDevice(d.ThinpoolDevice, volume.DevID) if err != nil { return err } if volume.Base != "" { image := d.loadImage(volume.Base) if image == nil { return generateError(logrus.Fields{ LOG_FIELD_IMAGE: volume.Base, }, "Cannot find volume's base image") } if _, exists := image.VolumeRef[volume.UUID]; !exists { return generateError(logrus.Fields{ LOG_FIELD_IMAGE: volume.Base, LOG_FIELD_VOLUME: volume.UUID, }, "Volume's base image doesn't refer volumev") } delete(image.VolumeRef, volume.UUID) } if err := d.deleteVolume(id); err != nil { return err } return nil }
func (devices *DeviceSet) setupBaseImage() error { oldInfo, _ := devices.lookupDevice("") if oldInfo != nil && oldInfo.Initialized { return nil } if oldInfo != nil && !oldInfo.Initialized { log.Debugf("Removing uninitialized base image") if err := devices.deleteDevice(oldInfo); err != nil { return err } } log.Debugf("Initializing base device-manager snapshot") id := devices.NextDeviceId // Create initial device if err := devicemapper.CreateDevice(devices.getPoolDevName(), &id); err != nil { return err } // Ids are 24bit, so wrap around devices.NextDeviceId = (id + 1) & 0xffffff log.Debugf("Registering base device (id %v) with FS size %v", id, devices.baseFsSize) info, err := devices.registerDevice(id, "", devices.baseFsSize) if err != nil { _ = devicemapper.DeleteDevice(devices.getPoolDevName(), id) return err } log.Debugf("Creating filesystem on base device-manager snapshot") if err = devices.activateDeviceIfNeeded(info); err != nil { return err } if err := devices.createFilesystem(info); err != nil { return err } info.Initialized = true if err = devices.saveMetadata(info); err != nil { info.Initialized = false return err } return nil }
func (d *Driver) DeleteVolume(req Request) error { var err error d.mutex.Lock() defer d.mutex.Unlock() id := req.Name volume := d.blankVolume(id) if err := util.ObjectLoad(volume); err != nil { return err } if volume.MountPoint != "" { return fmt.Errorf("Cannot delete volume %s, it hasn't been umounted", id) } if len(volume.Snapshots) != 0 { for snapshotID := range volume.Snapshots { if err = d.deleteSnapshot(snapshotID, volume.Name); err != nil { return generateError(logrus.Fields{ LOG_FIELD_VOLUME: volume.Name, LOG_FIELD_SNAPSHOT: snapshotID, }, "cannot remove an snapshot of volume, as part of deletion of volume") } } } if err = d.removeDevice(id); err != nil { return err } log.WithFields(logrus.Fields{ LOG_FIELD_REASON: LOG_REASON_START, LOG_FIELD_EVENT: LOG_EVENT_REMOVE, LOG_FIELD_OBJECT: LOG_OBJECT_VOLUME, LOG_FIELD_VOLUME: id, DM_LOG_FIELD_VOLUME_DEVID: volume.DevID, }).Debugf("Deleting device") err = devicemapper.DeleteDevice(d.ThinpoolDevice, volume.DevID) if err != nil { return err } if err := util.ObjectDelete(volume); err != nil { return err } return nil }
func (devices *DeviceSet) deleteDevice(info *DevInfo) error { if devices.doBlkDiscard { // This is a workaround for the kernel not discarding block so // on the thin pool when we remove a thinp device, so we do it // manually if err := devices.activateDeviceIfNeeded(info); err == nil { if err := devicemapper.BlockDeviceDiscard(info.DevName()); err != nil { log.Debugf("Error discarding block on device: %s (ignoring)", err) } } } devinfo, _ := devicemapper.GetInfo(info.Name()) if devinfo != nil && devinfo.Exists != 0 { if err := devices.removeDeviceAndWait(info.Name()); err != nil { log.Debugf("Error removing device: %s", err) return err } } if err := devices.openTransaction(info.Hash, info.DeviceId); err != nil { log.Debugf("Error opening transaction hash = %s deviceId = %d", "", info.DeviceId) return err } if err := devicemapper.DeleteDevice(devices.getPoolDevName(), info.DeviceId); err != nil { log.Debugf("Error deleting device: %s", err) return err } if err := devices.unregisterDevice(info.DeviceId, info.Hash); err != nil { return err } if err := devices.closeTransaction(); err != nil { return err } devices.markDeviceIdFree(info.DeviceId) return nil }
func (devices *DeviceSet) deleteDevice(info *DevInfo) error { if devices.doBlkDiscard { // This is a workaround for the kernel not discarding block so // on the thin pool when we remove a thinp device, so we do it // manually if err := devices.activateDeviceIfNeeded(info); err == nil { if err := devicemapper.BlockDeviceDiscard(info.DevName()); err != nil { log.Debugf("Error discarding block on device: %s (ignoring)", err) } } } devinfo, _ := devicemapper.GetInfo(info.Name()) if devinfo != nil && devinfo.Exists != 0 { if err := devices.removeDeviceAndWait(info.Name()); err != nil { log.Debugf("Error removing device: %s", err) return err } } if err := devicemapper.DeleteDevice(devices.getPoolDevName(), info.DeviceId); err != nil { log.Debugf("Error deleting device: %s", err) return err } devices.allocateTransactionId() devices.devicesLock.Lock() delete(devices.Devices, info.Hash) devices.devicesLock.Unlock() if err := devices.removeMetadata(info); err != nil { devices.devicesLock.Lock() devices.Devices[info.Hash] = info devices.devicesLock.Unlock() log.Debugf("Error removing meta data: %s", err) return err } return nil }
func (devices *DeviceSet) rollbackTransaction() error { log.Debugf("Rolling back open transaction: TransactionId=%d hash=%s device_id=%d", devices.OpenTransactionId, devices.DeviceIdHash, devices.DeviceId) // A device id might have already been deleted before transaction // closed. In that case this call will fail. Just leave a message // in case of failure. if err := devicemapper.DeleteDevice(devices.getPoolDevName(), devices.DeviceId); err != nil { log.Errorf("Warning: Unable to delete device: %s", err) } dinfo := &DevInfo{Hash: devices.DeviceIdHash} if err := devices.removeMetadata(dinfo); err != nil { log.Errorf("Warning: Unable to remove meta data: %s", err) } else { devices.markDeviceIdFree(devices.DeviceId) } if err := devices.removeTransactionMetaData(); err != nil { log.Errorf("Warning: Unable to remove transaction meta file %s: %s", devices.transactionMetaFile(), err) } return nil }
func (d *Driver) CreateVolume(id string, opts map[string]string) error { var ( size int64 err error ) backupURL := opts[convoydriver.OPT_BACKUP_URL] if backupURL != "" { objVolume, err := objectstore.LoadVolume(backupURL) if err != nil { return err } if objVolume.Driver != d.Name() { return fmt.Errorf("Cannot restore backup of %v to %v", objVolume.Driver, d.Name()) } size, err = d.getSize(opts, objVolume.Size) if err != nil { return err } if size != objVolume.Size { return fmt.Errorf("Volume size must match with backup's size") } } else { size, err = d.getSize(opts, d.DefaultVolumeSize) if err != nil { return err } } if size%(d.ThinpoolBlockSize*SECTOR_SIZE) != 0 { return fmt.Errorf("Size must be multiple of block size") } volume := d.blankVolume(id) exists, err := util.ObjectExists(volume) if err != nil { return err } if exists { return generateError(logrus.Fields{ LOG_FIELD_VOLUME: id, }, "Already has volume with specific uuid") } devID, err := d.allocateDevID() if err != nil { return err } log.WithFields(logrus.Fields{ LOG_FIELD_REASON: LOG_REASON_START, LOG_FIELD_EVENT: LOG_EVENT_CREATE, LOG_FIELD_OBJECT: LOG_OBJECT_VOLUME, LOG_FIELD_VOLUME: id, DM_LOG_FIELD_VOLUME_DEVID: devID, }).Debugf("Creating volume") err = devicemapper.CreateDevice(d.ThinpoolDevice, devID) if err != nil { return err } log.WithFields(logrus.Fields{ LOG_FIELD_REASON: LOG_REASON_START, LOG_FIELD_EVENT: LOG_EVENT_ACTIVATE, LOG_FIELD_OBJECT: LOG_OBJECT_VOLUME, LOG_FIELD_VOLUME: id, DM_LOG_FIELD_VOLUME_DEVID: devID, }).Debugf("Activating device for volume") err = devicemapper.ActivateDevice(d.ThinpoolDevice, id, devID, uint64(size)) if err != nil { log.WithFields(logrus.Fields{ LOG_FIELD_REASON: LOG_REASON_ROLLBACK, LOG_FIELD_EVENT: LOG_EVENT_REMOVE, LOG_FIELD_OBJECT: LOG_OBJECT_VOLUME, LOG_FIELD_VOLUME: id, DM_LOG_FIELD_VOLUME_DEVID: devID, }).Debugf("Removing device for volume due to fail to activate") if err := devicemapper.DeleteDevice(d.ThinpoolDevice, devID); err != nil { log.WithFields(logrus.Fields{ LOG_FIELD_REASON: LOG_REASON_FAILURE, LOG_FIELD_EVENT: LOG_EVENT_REMOVE, LOG_FIELD_OBJECT: LOG_OBJECT_VOLUME, LOG_FIELD_VOLUME: id, DM_LOG_FIELD_VOLUME_DEVID: devID, }).Debugf("Failed to remove device") } return err } volume.DevID = devID volume.Size = size volume.Snapshots = make(map[string]Snapshot) if err := util.ObjectSave(volume); err != nil { return err } dev, err := d.GetVolumeDevice(id) if err != nil { return err } if backupURL == "" { // format the device if _, err := util.Execute("mkfs", []string{"-t", "ext4", dev}); err != nil { return err } } else { if err := objectstore.RestoreDeltaBlockBackup(backupURL, dev); err != nil { return err } } return nil }
func (d *Driver) CreateVolume(id, baseID string, size int64) error { var err error if size%(d.ThinpoolBlockSize*SECTOR_SIZE) != 0 { return fmt.Errorf("Size must be multiple of block size") } volume := d.loadVolume(id) if volume != nil { return generateError(logrus.Fields{ LOG_FIELD_VOLUME: id, }, "Already has volume with specific uuid") } var image *Image if baseID != "" { image = d.loadImage(baseID) if image == nil { return generateError(logrus.Fields{ LOG_FIELD_IMAGE: baseID, }, "Cannot find activated base image") } if _, err := os.Stat(image.Device); err != nil { return generateError(logrus.Fields{ LOG_FIELD_IMAGE_DEV: image.Device, }, "Base image device doesn't exist") } if size != image.Size { return generateError(logrus.Fields{ LOG_FIELD_IMAGE: baseID, LOG_FIELD_VOLUME: id, }, "Volume has different size(%v) than base image(%v)", size, image.Size) } } devID, err := d.allocateDevID() if err != nil { return err } log.WithFields(logrus.Fields{ LOG_FIELD_REASON: LOG_REASON_START, LOG_FIELD_EVENT: LOG_EVENT_CREATE, LOG_FIELD_OBJECT: LOG_OBJECT_VOLUME, LOG_FIELD_VOLUME: id, LOG_FIELD_IMAGE: baseID, DM_LOG_FIELD_VOLUME_DEVID: devID, }).Debugf("Creating volume") err = devicemapper.CreateDevice(d.ThinpoolDevice, devID) if err != nil { return err } log.WithFields(logrus.Fields{ LOG_FIELD_REASON: LOG_REASON_START, LOG_FIELD_EVENT: LOG_EVENT_ACTIVATE, LOG_FIELD_OBJECT: LOG_OBJECT_VOLUME, LOG_FIELD_VOLUME: id, LOG_FIELD_IMAGE: baseID, DM_LOG_FIELD_VOLUME_DEVID: devID, }).Debugf("Activating device for volume") if image == nil { err = devicemapper.ActivateDevice(d.ThinpoolDevice, id, devID, uint64(size)) } else { err = devicemapper.ActivateDeviceWithExternal(d.ThinpoolDevice, id, devID, uint64(size), image.Device) } if err != nil { log.WithFields(logrus.Fields{ LOG_FIELD_REASON: LOG_REASON_ROLLBACK, LOG_FIELD_EVENT: LOG_EVENT_REMOVE, LOG_FIELD_OBJECT: LOG_OBJECT_VOLUME, LOG_FIELD_VOLUME: id, LOG_FIELD_IMAGE: baseID, DM_LOG_FIELD_VOLUME_DEVID: devID, }).Debugf("Removing device for volume due to fail to activate") if err := devicemapper.DeleteDevice(d.ThinpoolDevice, devID); err != nil { log.WithFields(logrus.Fields{ LOG_FIELD_REASON: LOG_REASON_FAILURE, LOG_FIELD_EVENT: LOG_EVENT_REMOVE, LOG_FIELD_OBJECT: LOG_OBJECT_VOLUME, LOG_FIELD_VOLUME: id, LOG_FIELD_IMAGE: baseID, DM_LOG_FIELD_VOLUME_DEVID: devID, }).Debugf("Failed to remove device") } return err } volume = &Volume{ UUID: id, DevID: devID, Size: size, Snapshots: make(map[string]Snapshot), } if image != nil { volume.Base = image.UUID image.VolumeRef[id] = true if err := d.saveImage(image); err != nil { return err } } if err := d.saveVolume(volume); err != nil { return err } return nil }
func (devices *DeviceSet) setupBaseImage() error { oldInfo, _ := devices.lookupDevice("") if oldInfo != nil && oldInfo.Initialized { return nil } if oldInfo != nil && !oldInfo.Initialized { log.Debugf("Removing uninitialized base image") if err := devices.deleteDevice(oldInfo); err != nil { return err } } if devices.thinPoolDevice != "" && oldInfo == nil { _, transactionId, dataUsed, _, _, _, err := devices.poolStatus() if err != nil { return err } if dataUsed != 0 { return fmt.Errorf("Unable to take ownership of thin-pool (%s) that already has used data blocks", devices.thinPoolDevice) } if transactionId != 0 { return fmt.Errorf("Unable to take ownership of thin-pool (%s) with non-zero transaction Id", devices.thinPoolDevice) } } log.Debugf("Initializing base device-mapper thin volume") id := devices.NextDeviceId // Create initial device if err := devicemapper.CreateDevice(devices.getPoolDevName(), &id); err != nil { return err } // Ids are 24bit, so wrap around devices.NextDeviceId = (id + 1) & 0xffffff log.Debugf("Registering base device (id %v) with FS size %v", id, devices.baseFsSize) info, err := devices.registerDevice(id, "", devices.baseFsSize) if err != nil { _ = devicemapper.DeleteDevice(devices.getPoolDevName(), id) return err } log.Debugf("Creating filesystem on base device-mapper thin volume") if err = devices.activateDeviceIfNeeded(info); err != nil { return err } if err := devices.createFilesystem(info); err != nil { return err } info.Initialized = true if err = devices.saveMetadata(info); err != nil { info.Initialized = false return err } return nil }