@@ -162,7 +162,22 @@ func (p *PoolDevice) transition(ctx context.Context, deviceName string, tryingSt
162162 result = multierror .Append (result , uerr )
163163 }
164164
165- return result .ErrorOrNil ()
165+ return unwrapError (result )
166+ }
167+
168+ // unwrapError converts multierror.Error to the original error when it is possible.
169+ // multierror 1.1.0 has the similar function named Unwrap, but it requires Go 1.14.
170+ func unwrapError (e * multierror.Error ) error {
171+ if e == nil {
172+ return nil
173+ }
174+
175+ // If the error can be expressed without multierror, return the original error.
176+ if len (e .Errors ) == 1 {
177+ return e .Errors [0 ]
178+ }
179+
180+ return e .ErrorOrNil ()
166181}
167182
168183// CreateThinDevice creates new devmapper thin-device with given name and size.
@@ -184,21 +199,7 @@ func (p *PoolDevice) CreateThinDevice(ctx context.Context, deviceName string, vi
184199 defer func () {
185200 // We've created a devmapper device, but failed to activate it, try rollback everything
186201 if activeErr != nil {
187- // Delete the device first.
188- delErr := p .deleteDevice (ctx , info )
189- if delErr != nil {
190- // Failed to rollback, mark the device as faulty and keep metadata in order to
191- // preserve the faulty device ID
192- retErr = multierror .Append (retErr , delErr , p .metadata .MarkFaulty (ctx , info .Name ))
193- return
194- }
195-
196- // The devmapper device has been successfully deleted, deallocate device ID
197- if err := p .RemoveDevice (ctx , info .Name ); err != nil {
198- retErr = multierror .Append (retErr , err )
199- return
200- }
201-
202+ retErr = p .rollbackActivate (ctx , info , activeErr )
202203 return
203204 }
204205
@@ -230,6 +231,23 @@ func (p *PoolDevice) CreateThinDevice(ctx context.Context, deviceName string, vi
230231 return nil
231232}
232233
234+ func (p * PoolDevice ) rollbackActivate (ctx context.Context , info * DeviceInfo , activateErr error ) error {
235+ // Delete the device first.
236+ delErr := p .deleteDevice (ctx , info )
237+ if delErr != nil {
238+ // Failed to rollback, mark the device as faulty and keep metadata in order to
239+ // preserve the faulty device ID
240+ return multierror .Append (activateErr , delErr , p .metadata .MarkFaulty (ctx , info .Name ))
241+ }
242+
243+ // The devmapper device has been successfully deleted, deallocate device ID
244+ if err := p .RemoveDevice (ctx , info .Name ); err != nil {
245+ return multierror .Append (activateErr , err )
246+ }
247+
248+ return activateErr
249+ }
250+
233251// createDevice creates thin device
234252func (p * PoolDevice ) createDevice (ctx context.Context , info * DeviceInfo ) error {
235253 if err := p .transition (ctx , info .Name , Creating , Created , func () error {
@@ -275,21 +293,7 @@ func (p *PoolDevice) CreateSnapshotDevice(ctx context.Context, deviceName string
275293 defer func () {
276294 // We've created a devmapper device, but failed to activate it, try rollback everything
277295 if activeErr != nil {
278- // Delete the device first.
279- delErr := p .deleteDevice (ctx , snapInfo )
280- if delErr != nil {
281- // Failed to rollback, mark the device as faulty and keep metadata in order to
282- // preserve the faulty device ID
283- retErr = multierror .Append (retErr , delErr , p .metadata .MarkFaulty (ctx , snapInfo .Name ))
284- return
285- }
286-
287- // The devmapper device has been successfully deleted, deallocate device ID
288- if err := p .RemoveDevice (ctx , snapInfo .Name ); err != nil {
289- retErr = multierror .Append (retErr , err )
290- return
291- }
292-
296+ retErr = p .rollbackActivate (ctx , snapInfo , activeErr )
293297 return
294298 }
295299
@@ -490,7 +494,13 @@ func (p *PoolDevice) RemoveDevice(ctx context.Context, deviceName string) error
490494func (p * PoolDevice ) deleteDevice (ctx context.Context , info * DeviceInfo ) error {
491495 if err := p .transition (ctx , info .Name , Removing , Removed , func () error {
492496 // Send 'delete' message to thin-pool
493- return dmsetup .DeleteDevice (p .poolName , info .DeviceID )
497+ e := dmsetup .DeleteDevice (p .poolName , info .DeviceID )
498+
499+ // Ignores the error if the device has been deleted already.
500+ if e != nil && ! errors .Is (e , unix .ENODATA ) {
501+ return e
502+ }
503+ return nil
494504 }); err != nil {
495505 return errors .Wrapf (err , "failed to delete device %q (dev id: %d)" , info .Name , info .DeviceID )
496506 }
0 commit comments