Fix up possibly racy module refcounting
authorNick Piggin <npiggin@suse.de>
Thu, 1 Apr 2010 08:09:40 +0000 (19:09 +1100)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 6 Apr 2010 02:50:02 +0000 (19:50 -0700)
commit5fbfb18d7a5b846946d52c4a10e3aaa213ec31b6
treebcfa13dec8cb2527c3007b3e5f957cb50e571c64
parent7da23b86e14b77c094b11a9fa5ef5b3758fc9193
Fix up possibly racy module refcounting

Module refcounting is implemented with a per-cpu counter for speed.
However there is a race when tallying the counter where a reference may
be taken by one CPU and released by another.  Reference count summation
may then see the decrement without having seen the previous increment,
leading to lower than expected count.  A module which never has its
actual reference drop below 1 may return a reference count of 0 due to
this race.

Module removal generally runs under stop_machine, which prevents this
race causing bugs due to removal of in-use modules.  However there are
other real bugs in module.c code and driver code (module_refcount is
exported) where the callers do not run under stop_machine.

Fix this by maintaining running per-cpu counters for the number of
module refcount increments and the number of refcount decrements.  The
increments are tallied after the decrements, so any decrement seen will
always have its corresponding increment counted.  The final refcount is
the difference of the total increments and decrements, preventing a
low-refcount from being returned.

Signed-off-by: Nick Piggin <npiggin@suse.de>
Acked-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
include/linux/module.h
kernel/module.c