@@ -25,6 +25,7 @@ import (
2525
2626 "github.com/hashicorp/go-multierror"
2727 "github.com/pkg/errors"
28+ "golang.org/x/sys/unix"
2829
2930 "github.com/containerd/containerd/log"
3031 "github.com/containerd/containerd/snapshots/devmapper/dmsetup"
@@ -160,7 +161,22 @@ func (p *PoolDevice) transition(ctx context.Context, deviceName string, tryingSt
160161 result = multierror .Append (result , uerr )
161162 }
162163
163- return result .ErrorOrNil ()
164+ return unwrapError (result )
165+ }
166+
167+ // unwrapError converts multierror.Error to the original error when it is possible.
168+ // multierror 1.1.0 has the similar function named Unwrap, but it requires Go 1.14.
169+ func unwrapError (e * multierror.Error ) error {
170+ if e == nil {
171+ return nil
172+ }
173+
174+ // If the error can be expressed without multierror, return the original error.
175+ if len (e .Errors ) == 1 {
176+ return e .Errors [0 ]
177+ }
178+
179+ return e .ErrorOrNil ()
164180}
165181
166182// CreateThinDevice creates new devmapper thin-device with given name and size.
@@ -182,21 +198,7 @@ func (p *PoolDevice) CreateThinDevice(ctx context.Context, deviceName string, vi
182198 defer func () {
183199 // We've created a devmapper device, but failed to activate it, try rollback everything
184200 if activeErr != nil {
185- // Delete the device first.
186- delErr := p .deleteDevice (ctx , info )
187- if delErr != nil {
188- // Failed to rollback, mark the device as faulty and keep metadata in order to
189- // preserve the faulty device ID
190- retErr = multierror .Append (retErr , delErr , p .metadata .MarkFaulty (ctx , info .Name ))
191- return
192- }
193-
194- // The devmapper device has been successfully deleted, deallocate device ID
195- if err := p .RemoveDevice (ctx , info .Name ); err != nil {
196- retErr = multierror .Append (retErr , err )
197- return
198- }
199-
201+ retErr = p .rollbackActivate (ctx , info , activeErr )
200202 return
201203 }
202204
@@ -228,6 +230,23 @@ func (p *PoolDevice) CreateThinDevice(ctx context.Context, deviceName string, vi
228230 return nil
229231}
230232
233+ func (p * PoolDevice ) rollbackActivate (ctx context.Context , info * DeviceInfo , activateErr error ) error {
234+ // Delete the device first.
235+ delErr := p .deleteDevice (ctx , info )
236+ if delErr != nil {
237+ // Failed to rollback, mark the device as faulty and keep metadata in order to
238+ // preserve the faulty device ID
239+ return multierror .Append (activateErr , delErr , p .metadata .MarkFaulty (ctx , info .Name ))
240+ }
241+
242+ // The devmapper device has been successfully deleted, deallocate device ID
243+ if err := p .RemoveDevice (ctx , info .Name ); err != nil {
244+ return multierror .Append (activateErr , err )
245+ }
246+
247+ return activateErr
248+ }
249+
231250// createDevice creates thin device
232251func (p * PoolDevice ) createDevice (ctx context.Context , info * DeviceInfo ) error {
233252 if err := p .transition (ctx , info .Name , Creating , Created , func () error {
@@ -273,21 +292,7 @@ func (p *PoolDevice) CreateSnapshotDevice(ctx context.Context, deviceName string
273292 defer func () {
274293 // We've created a devmapper device, but failed to activate it, try rollback everything
275294 if activeErr != nil {
276- // Delete the device first.
277- delErr := p .deleteDevice (ctx , snapInfo )
278- if delErr != nil {
279- // Failed to rollback, mark the device as faulty and keep metadata in order to
280- // preserve the faulty device ID
281- retErr = multierror .Append (retErr , delErr , p .metadata .MarkFaulty (ctx , snapInfo .Name ))
282- return
283- }
284-
285- // The devmapper device has been successfully deleted, deallocate device ID
286- if err := p .RemoveDevice (ctx , snapInfo .Name ); err != nil {
287- retErr = multierror .Append (retErr , err )
288- return
289- }
290-
295+ retErr = p .rollbackActivate (ctx , snapInfo , activeErr )
291296 return
292297 }
293298
@@ -465,7 +470,13 @@ func (p *PoolDevice) RemoveDevice(ctx context.Context, deviceName string) error
465470func (p * PoolDevice ) deleteDevice (ctx context.Context , info * DeviceInfo ) error {
466471 if err := p .transition (ctx , info .Name , Removing , Removed , func () error {
467472 // Send 'delete' message to thin-pool
468- return dmsetup .DeleteDevice (p .poolName , info .DeviceID )
473+ e := dmsetup .DeleteDevice (p .poolName , info .DeviceID )
474+
475+ // Ignores the error if the device has been deleted already.
476+ if e != nil && errors .Cause (e ) != unix .ENODATA {
477+ return e
478+ }
479+ return nil
469480 }); err != nil {
470481 return errors .Wrapf (err , "failed to delete device %q (dev id: %d)" , info .Name , info .DeviceID )
471482 }
0 commit comments