devmapper: async remove device using Cleanup
Fix: #3923 Signed-off-by: Eric Ren <renzhen@linux.alibaba.com>
This commit is contained in:
parent
2c5279e820
commit
b6bf7b97c2
@ -25,6 +25,7 @@ The following configuration flags are supported:
|
|||||||
* `pool_name` - a name to use for the devicemapper thin pool. Pool name
|
* `pool_name` - a name to use for the devicemapper thin pool. Pool name
|
||||||
should be the same as in `/dev/mapper/` directory
|
should be the same as in `/dev/mapper/` directory
|
||||||
* `base_image_size` - defines how much space to allocate when creating the base device
|
* `base_image_size` - defines how much space to allocate when creating the base device
|
||||||
|
* `async_remove` - flag to async remove device using snapshot GC's cleanup callback
|
||||||
|
|
||||||
Pool name and base image size are required snapshotter parameters.
|
Pool name and base image size are required snapshotter parameters.
|
||||||
|
|
||||||
|
@ -40,6 +40,9 @@ type Config struct {
|
|||||||
// Defines how much space to allocate when creating base image for container
|
// Defines how much space to allocate when creating base image for container
|
||||||
BaseImageSize string `toml:"base_image_size"`
|
BaseImageSize string `toml:"base_image_size"`
|
||||||
BaseImageSizeBytes uint64 `toml:"-"`
|
BaseImageSizeBytes uint64 `toml:"-"`
|
||||||
|
|
||||||
|
// Flag to async remove device using Cleanup() callback in snapshots GC
|
||||||
|
AsyncRemove bool `toml:"async_remove"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadConfig reads devmapper configuration file from disk in TOML format
|
// LoadConfig reads devmapper configuration file from disk in TOML format
|
||||||
|
@ -122,6 +122,14 @@ func (m *PoolMetadata) AddDevice(ctx context.Context, info *DeviceInfo) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChangeDeviceState changes the device state given the device name in devices bucket.
|
||||||
|
func (m *PoolMetadata) ChangeDeviceState(ctx context.Context, name string, state DeviceState) error {
|
||||||
|
return m.UpdateDevice(ctx, name, func(deviceInfo *DeviceInfo) error {
|
||||||
|
deviceInfo.State = state
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// MarkFaulty marks the given device and corresponding devmapper device ID as faulty.
|
// MarkFaulty marks the given device and corresponding devmapper device ID as faulty.
|
||||||
// The snapshotter might attempt to recreate a device in 'Faulty' state with another devmapper ID in
|
// The snapshotter might attempt to recreate a device in 'Faulty' state with another devmapper ID in
|
||||||
// subsequent calls, and in case of success it's status will be changed to 'Created' or 'Activated'.
|
// subsequent calls, and in case of success it's status will be changed to 'Created' or 'Activated'.
|
||||||
|
@ -84,7 +84,7 @@ func (p *PoolDevice) ensureDeviceStates(ctx context.Context) error {
|
|||||||
var faultyDevices []*DeviceInfo
|
var faultyDevices []*DeviceInfo
|
||||||
var activatedDevices []*DeviceInfo
|
var activatedDevices []*DeviceInfo
|
||||||
|
|
||||||
if err := p.metadata.WalkDevices(ctx, func(info *DeviceInfo) error {
|
if err := p.WalkDevices(ctx, func(info *DeviceInfo) error {
|
||||||
switch info.State {
|
switch info.State {
|
||||||
case Suspended, Resumed, Deactivated, Removed, Faulty:
|
case Suspended, Resumed, Deactivated, Removed, Faulty:
|
||||||
case Activated:
|
case Activated:
|
||||||
@ -494,6 +494,18 @@ func (p *PoolDevice) RemovePool(ctx context.Context) error {
|
|||||||
return result.ErrorOrNil()
|
return result.ErrorOrNil()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkDeviceState changes the device's state in metastore
|
||||||
|
func (p *PoolDevice) MarkDeviceState(ctx context.Context, name string, state DeviceState) error {
|
||||||
|
return p.metadata.ChangeDeviceState(ctx, name, state)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WalkDevices iterates all devices in pool metadata
|
||||||
|
func (p *PoolDevice) WalkDevices(ctx context.Context, cb func(info *DeviceInfo) error) error {
|
||||||
|
return p.metadata.WalkDevices(ctx, func(info *DeviceInfo) error {
|
||||||
|
return cb(info)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Close closes pool device (thin-pool will not be removed)
|
// Close closes pool device (thin-pool will not be removed)
|
||||||
func (p *PoolDevice) Close() error {
|
func (p *PoolDevice) Close() error {
|
||||||
return p.metadata.Close()
|
return p.metadata.Close()
|
||||||
|
@ -303,10 +303,19 @@ func (s *Snapshotter) removeDevice(ctx context.Context, key string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deviceName := s.getDeviceName(snapID)
|
deviceName := s.getDeviceName(snapID)
|
||||||
|
if !s.config.AsyncRemove {
|
||||||
if err := s.pool.RemoveDevice(ctx, deviceName); err != nil {
|
if err := s.pool.RemoveDevice(ctx, deviceName); err != nil {
|
||||||
log.G(ctx).WithError(err).Errorf("failed to remove device")
|
log.G(ctx).WithError(err).Errorf("failed to remove device")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// The asynchronous cleanup will do the real device remove work.
|
||||||
|
log.G(ctx).WithField("device", deviceName).Debug("async remove")
|
||||||
|
if err := s.pool.MarkDeviceState(ctx, deviceName, Removed); err != nil {
|
||||||
|
log.G(ctx).WithError(err).Errorf("failed to mark device as removed")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -486,3 +495,34 @@ func (s *Snapshotter) withTransaction(ctx context.Context, writable bool, fn fun
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Snapshotter) Cleanup(ctx context.Context) error {
|
||||||
|
var removedDevices []*DeviceInfo
|
||||||
|
|
||||||
|
if !s.config.AsyncRemove {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.pool.WalkDevices(ctx, func(info *DeviceInfo) error {
|
||||||
|
if info.State == Removed {
|
||||||
|
removedDevices = append(removedDevices, info)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
log.G(ctx).WithError(err).Errorf("failed to query devices from metastore")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result *multierror.Error
|
||||||
|
for _, dev := range removedDevices {
|
||||||
|
log.G(ctx).WithField("device", dev.Name).Debug("cleanup device")
|
||||||
|
if err := s.pool.RemoveDevice(ctx, dev.Name); err != nil {
|
||||||
|
log.G(ctx).WithField("device", dev.Name).Error("failed to cleanup device")
|
||||||
|
result = multierror.Append(result, err)
|
||||||
|
} else {
|
||||||
|
log.G(ctx).WithField("device", dev.Name).Debug("cleanuped device")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.ErrorOrNil()
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user