Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 189497
b: refs/heads/master
c: 5fbfb18
h: refs/heads/master
i:
  189495: a17a7fb
v: v3
  • Loading branch information
Nick Piggin authored and Linus Torvalds committed Apr 6, 2010
1 parent 138b432 commit a032bd3
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 16 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 7da23b86e14b77c094b11a9fa5ef5b3758fc9193
refs/heads/master: 5fbfb18d7a5b846946d52c4a10e3aaa213ec31b6
14 changes: 7 additions & 7 deletions trunk/include/linux/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,8 @@ struct module
void (*exit)(void);

struct module_ref {
int count;
unsigned int incs;
unsigned int decs;
} __percpu *refptr;
#endif

Expand Down Expand Up @@ -463,9 +464,9 @@ static inline void __module_get(struct module *module)
{
if (module) {
preempt_disable();
__this_cpu_inc(module->refptr->count);
__this_cpu_inc(module->refptr->incs);
trace_module_get(module, _THIS_IP_,
__this_cpu_read(module->refptr->count));
__this_cpu_read(module->refptr->incs));
preempt_enable();
}
}
Expand All @@ -478,11 +479,10 @@ static inline int try_module_get(struct module *module)
preempt_disable();

if (likely(module_is_live(module))) {
__this_cpu_inc(module->refptr->count);
__this_cpu_inc(module->refptr->incs);
trace_module_get(module, _THIS_IP_,
__this_cpu_read(module->refptr->count));
}
else
__this_cpu_read(module->refptr->incs));
} else
ret = 0;

preempt_enable();
Expand Down
35 changes: 27 additions & 8 deletions trunk/kernel/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -521,11 +521,13 @@ static void module_unload_init(struct module *mod)
int cpu;

INIT_LIST_HEAD(&mod->modules_which_use_me);
for_each_possible_cpu(cpu)
per_cpu_ptr(mod->refptr, cpu)->count = 0;
for_each_possible_cpu(cpu) {
per_cpu_ptr(mod->refptr, cpu)->incs = 0;
per_cpu_ptr(mod->refptr, cpu)->decs = 0;
}

/* Hold reference count during initialization. */
__this_cpu_write(mod->refptr->count, 1);
__this_cpu_write(mod->refptr->incs, 1);
/* Backwards compatibility macros put refcount during init. */
mod->waiter = current;
}
Expand Down Expand Up @@ -664,12 +666,28 @@ static int try_stop_module(struct module *mod, int flags, int *forced)

unsigned int module_refcount(struct module *mod)
{
unsigned int total = 0;
unsigned int incs = 0, decs = 0;
int cpu;

for_each_possible_cpu(cpu)
total += per_cpu_ptr(mod->refptr, cpu)->count;
return total;
decs += per_cpu_ptr(mod->refptr, cpu)->decs;
/*
* ensure the incs are added up after the decs.
* module_put ensures incs are visible before decs with smp_wmb.
*
* This 2-count scheme avoids the situation where the refcount
* for CPU0 is read, then CPU0 increments the module refcount,
* then CPU1 drops that refcount, then the refcount for CPU1 is
* read. We would record a decrement but not its corresponding
* increment so we would see a low count (disaster).
*
* Rare situation? But module_refcount can be preempted, and we
* might be tallying up 4096+ CPUs. So it is not impossible.
*/
smp_rmb();
for_each_possible_cpu(cpu)
incs += per_cpu_ptr(mod->refptr, cpu)->incs;
return incs - decs;
}
EXPORT_SYMBOL(module_refcount);

Expand Down Expand Up @@ -846,10 +864,11 @@ void module_put(struct module *module)
{
if (module) {
preempt_disable();
__this_cpu_dec(module->refptr->count);
smp_wmb(); /* see comment in module_refcount */
__this_cpu_inc(module->refptr->decs);

trace_module_put(module, _RET_IP_,
__this_cpu_read(module->refptr->count));
__this_cpu_read(module->refptr->decs));
/* Maybe they're waiting for us to drop reference? */
if (unlikely(!module_is_live(module)))
wake_up_process(module->waiter);
Expand Down

0 comments on commit a032bd3

Please sign in to comment.