callout_stop() should return 0 (fail) when the callout is currently

being serviced and indeed unstoppable.

A scenario to reproduce this case is:

- the callout is being serviced and at same time,
- callout_reset() is called on this callout that sets
  the CALLOUT_PENDING flag and at same time,
- callout_stop() is called on this callout and returns 1 (success)
  even if the callout is indeed currently running and unstoppable.

This issue was caught up while making r284245 (D2763) workaround, and
was discussed at BSDCan 2015.  Once applied the r284245 workaround
is not needed anymore and will be reverted.

Differential Revision:	https://reviews.freebsd.org/D3078
Reviewed by:		jhb
Sponsored by:		Verisign, Inc.
This commit is contained in:
jch 2015-08-18 10:15:09 +00:00
parent 24fa48b559
commit 7242654eab

View File

@ -1150,7 +1150,7 @@ _callout_stop_safe(struct callout *c, int safe)
struct callout_cpu *cc, *old_cc;
struct lock_class *class;
int direct, sq_locked, use_lock;
int not_on_a_list;
int not_on_a_list, not_running;
if (safe)
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, c->c_lock,
@ -1378,8 +1378,15 @@ _callout_stop_safe(struct callout *c, int safe)
}
}
callout_cc_del(c, cc);
/*
* If we are asked to stop a callout which is currently in progress
* and indeed impossible to stop then return 0.
*/
not_running = !(cc_exec_curr(cc, direct) == c);
CC_UNLOCK(cc);
return (1);
return (not_running);
}
void