Merge pull request #3567 from renzhengeek/renzhen/devmapper

devmapper: activate dm device if snap device marked as activated
This commit is contained in:
Michael Crosby 2019-08-30 14:47:45 -04:00 committed by GitHub
commit 95301fee3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 12 deletions

View File

@ -73,23 +73,41 @@ func NewPoolDevice(ctx context.Context, config *Config) (*PoolDevice, error) {
return poolDevice, nil return poolDevice, nil
} }
// ensureDeviceStates marks devices with incomplete states (after crash) as 'Faulty' // ensureDeviceStates updates devices to their real state:
// - marks devices with incomplete states (after crash) as 'Faulty'
// - activates devices if they are marked as 'Activated' but the dm
// device is not active, which can happen to a stopped container
// after a reboot
func (p *PoolDevice) ensureDeviceStates(ctx context.Context) error { func (p *PoolDevice) ensureDeviceStates(ctx context.Context) error {
var devices []*DeviceInfo var faultyDevices []*DeviceInfo
var activatedDevices []*DeviceInfo
if err := p.metadata.WalkDevices(ctx, func(info *DeviceInfo) error { if err := p.metadata.WalkDevices(ctx, func(info *DeviceInfo) error {
switch info.State { switch info.State {
case Activated, Suspended, Resumed, Deactivated, Removed, Faulty: case Suspended, Resumed, Deactivated, Removed, Faulty:
return nil case Activated:
activatedDevices = append(activatedDevices, info)
default:
faultyDevices = append(faultyDevices, info)
} }
devices = append(devices, info)
return nil return nil
}); err != nil { }); err != nil {
return errors.Wrap(err, "failed to query devices from metastore") return errors.Wrap(err, "failed to query devices from metastore")
} }
var result *multierror.Error var result *multierror.Error
for _, dev := range devices { for _, dev := range activatedDevices {
if p.IsActivated(dev.Name) {
continue
}
log.G(ctx).Warnf("devmapper device %q marked as %q but not active, activating it", dev.Name, dev.State)
if err := p.activateDevice(ctx, dev); err != nil {
result = multierror.Append(result, err)
}
}
for _, dev := range faultyDevices {
log.G(ctx). log.G(ctx).
WithField("dev_id", dev.DeviceID). WithField("dev_id", dev.DeviceID).
WithField("parent", dev.ParentName). WithField("parent", dev.ParentName).
@ -350,7 +368,7 @@ func (p *PoolDevice) DeactivateDevice(ctx context.Context, deviceName string, de
return nil return nil
} }
// IsActivated returns true if thin-device is activated and not suspended // IsActivated returns true if thin-device is activated
func (p *PoolDevice) IsActivated(deviceName string) bool { func (p *PoolDevice) IsActivated(deviceName string) bool {
infos, err := dmsetup.Info(deviceName) infos, err := dmsetup.Info(deviceName)
if err != nil || len(infos) != 1 { if err != nil || len(infos) != 1 {
@ -358,11 +376,11 @@ func (p *PoolDevice) IsActivated(deviceName string) bool {
return false return false
} }
if devInfo := infos[0]; devInfo.Suspended { if devInfo := infos[0]; devInfo.TableLive {
return false return true
} }
return true return false
} }
// IsLoaded returns true if thin-device is visible for dmsetup // IsLoaded returns true if thin-device is visible for dmsetup

View File

@ -161,7 +161,9 @@ func TestPoolDeviceMarkFaulty(t *testing.T) {
err := store.AddDevice(testCtx, &DeviceInfo{Name: "1", State: Unknown}) err := store.AddDevice(testCtx, &DeviceInfo{Name: "1", State: Unknown})
assert.NilError(t, err) assert.NilError(t, err)
err = store.AddDevice(testCtx, &DeviceInfo{Name: "2", State: Activated}) // Note: do not use 'Activated' here because pool.ensureDeviceStates() will
// try to activate the real dm device, which will fail on a faked device.
err = store.AddDevice(testCtx, &DeviceInfo{Name: "2", State: Deactivated})
assert.NilError(t, err) assert.NilError(t, err)
pool := &PoolDevice{metadata: store} pool := &PoolDevice{metadata: store}
@ -177,7 +179,7 @@ func TestPoolDeviceMarkFaulty(t *testing.T) {
assert.Equal(t, Faulty, info.State) assert.Equal(t, Faulty, info.State)
assert.Equal(t, "1", info.Name) assert.Equal(t, "1", info.Name)
case 2: case 2:
assert.Equal(t, Activated, info.State) assert.Equal(t, Deactivated, info.State)
assert.Equal(t, "2", info.Name) assert.Equal(t, "2", info.Name)
default: default:
t.Error("unexpected walk call") t.Error("unexpected walk call")