@@ -75,6 +75,33 @@ func NewPoolDevice(ctx context.Context, config *Config) (*PoolDevice, error) {
7575 return poolDevice , nil
7676}
7777
78+ func retry (ctx context.Context , f func () error ) error {
79+ var (
80+ maxRetries = 100
81+ retryDelay = 100 * time .Millisecond
82+ retryErr error
83+ )
84+
85+ for attempt := 1 ; attempt <= maxRetries ; attempt ++ {
86+ retryErr = f ()
87+ if retryErr == nil {
88+ return nil
89+ } else if retryErr != unix .EBUSY {
90+ return retryErr
91+ }
92+
93+ // Don't spam logs
94+ if attempt % 10 == 0 {
95+ log .G (ctx ).WithError (retryErr ).Warnf ("retrying... (%d of %d)" , attempt , maxRetries )
96+ }
97+
98+ // Devmapper device is busy, give it a bit of time and retry removal
99+ time .Sleep (retryDelay )
100+ }
101+
102+ return retryErr
103+ }
104+
78105// ensureDeviceStates updates devices to their real state:
79106// - marks devices with incomplete states (after crash) as 'Faulty'
80107// - activates devices if they are marked as 'Activated' but the dm
@@ -393,30 +420,13 @@ func (p *PoolDevice) DeactivateDevice(ctx context.Context, deviceName string, de
393420 }
394421
395422 if err := p .transition (ctx , deviceName , Deactivating , Deactivated , func () error {
396- var (
397- maxRetries = 100
398- retryDelay = 100 * time .Millisecond
399- retryErr error
400- )
401-
402- for attempt := 1 ; attempt <= maxRetries ; attempt ++ {
403- retryErr = dmsetup .RemoveDevice (deviceName , opts ... )
404- if retryErr == nil {
405- return nil
406- } else if retryErr != unix .EBUSY {
407- return retryErr
408- }
409-
410- // Don't spam logs
411- if attempt % 10 == 0 {
412- log .G (ctx ).WithError (retryErr ).Warnf ("failed to deactivate device, retrying... (%d of %d)" , attempt , maxRetries )
423+ return retry (ctx , func () error {
424+ if err := dmsetup .RemoveDevice (deviceName , opts ... ); err != nil {
425+ return errors .Wrap (err , "failed to deactivate device" )
413426 }
414427
415- // Devmapper device is busy, give it a bit of time and retry removal
416- time .Sleep (retryDelay )
417- }
418-
419- return retryErr
428+ return nil
429+ })
420430 }); err != nil {
421431 return errors .Wrapf (err , "failed to deactivate device %q" , deviceName )
422432 }
@@ -493,14 +503,15 @@ func (p *PoolDevice) RemoveDevice(ctx context.Context, deviceName string) error
493503
494504func (p * PoolDevice ) deleteDevice (ctx context.Context , info * DeviceInfo ) error {
495505 if err := p .transition (ctx , info .Name , Removing , Removed , func () error {
496- // Send 'delete' message to thin-pool
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
506+ return retry (ctx , func () error {
507+ // Send 'delete' message to thin-pool
508+ e := dmsetup .DeleteDevice (p .poolName , info .DeviceID )
509+ // Ignores the error if the device has been deleted already.
510+ if e != nil && ! errors .Is (e , unix .ENODATA ) {
511+ return e
512+ }
513+ return nil
514+ })
504515 }); err != nil {
505516 return errors .Wrapf (err , "failed to delete device %q (dev id: %d)" , info .Name , info .DeviceID )
506517 }
0 commit comments