资源描述
内核为2.6.32。
卸载模块target时,不管是否为强制卸载,都输出:
ERROR:Module target is in use.
用lsmod查看target,发现Used by计数为1,而据我所知,没有其它模块依赖target。
编写模块检查target的module结构,发现:
target->state == 0 // 模块存活
module_refcount(target) == 1 // 模块引用计数为1
list_empty(target->modules_which_use_me) == 1 // 模块依赖列表为空
这个就很奇怪,模块的引用计数为1,却没有引用者。
这可能是模块插入内核时出错而引起的,这里先不研究,先关注怎么把它强制卸载掉,虽然
insmod加载是临时的,所以通过重启电脑可以解决一些问题,但是不能总是依靠重启啊。
解决方法:编写模块mymod中把问题模块target的引用计数置为0,就可以顺利卸载掉target了!
代码
[java] view plaincopy
1. #include<linux/init.h>
2. #include<linux/module.h>
3. #include<linux/kernel.h>
4. #include<linux/list.h>
5. #include<linux/cpumask.h>
6.
7. static int __init mymod_init(void)
8. {
9. struct module *mod,*relate;
10. int cpu;
11.
12. // 打印本模块的模块名和模块状态
13. printk(KERN_ALERT"[insmod mymod] name:%s state:%d\n",THIS_MODULE->name,THIS_MODULE->state);
14.
15. // 遍历模块列表,查找target模块
16. list_for_each_entry(mod,THIS_MODULE->list.prev,list)
17. {
18. if(strcmp(mod->name,"target")==0) {
19.
20. // 打印target的模块名、模块状态、引用计数
21. printk(KERN_ALERT"name:%s state:%d refcnt:%u ",mod->name,mod->state,module_refcount(mod));
22.
23. // 打印出所有依赖target的模块名
24. if(!list_empty(&mod->modules_which_use_me)) {
25. list_for_each_entry(relate,&mod->modules_which_use_me,modules_which_use_me)
26. printk(KERN_ALERT"%s ",relate->name);
27. } else
28. printk(KERN_ALERT"used by NULL\n");
29.
30. // 把target的引用计数置为0
31. for_each_possible_cpu(cpu)
32. local_set(__module_ref_addr(mod,cpu),0);
33.
34. // 再看看target的名称、状态、引用计数
35. printk(KERN_ALERT"name:%s state:%d refcnt:%u\n",mod->name,mod->state,module_refcount(mod));
36. }
37. }
38. return 0;
39. }
40.
41. static void __exit mymod_exit(void)
42. {
43. printk(KERN_ALERT"[rmmod mymod] name:%s state:%d\n",THIS_MODULE->name,THIS_MODULE->state);
44. }
45.
46. module_init(mymod_init);
47. module_exit(mymod_exit);
48.
49. MODULE_AUTHOR("Zhangsk");
50. MODULE_LICENSE("GPL");
51. MODULE_DESCRIPTION("Why module can not be removed");
内核
@include/linux/module.h:
[java] view plaincopy
1. extern struct module __this_module;
2. #define THIS_MODULE (&__this_module);
3.
4. enum module_state{
5. MODULE_STATE_LIVE; // 模块存活,0
6. MODULE_STATE_COMING; // 正在加载模块,1
7. MODULE_STATE_GOING; // 正在卸载模块,2
8. };
9.
10. struct module {
11. enum module_state state; // 模块状态
12.
13. /* Member of list of modules */
14. struct list_head list; // 内核模块链表
15.
16. /* Unique handle for this module */
17. char name[MODULE_NAME_LEN]; //模块名称
18.
19. ...
20.
21. #ifdef CONFIG_MODULE_UNLOAD
22. /* What modules depend on me? */
23. struct list_head modules_which_use_me;
24.
25. /* Who is waiting for us to be unloaded */
26. struct task_struct *waiter;
27.
28. /* Destruction function. */
29. void (*exit) (void);
30.
31. #ifdef CONFIG_SMP
32. char *refptr;
33. #else
34. local_t ref;
35. #endif
36. #endif
37.
38. ...
39.
40. };
41.
42. static inline local_t *__module_ref_addr(struct module *mod, int cpu)
43. {#ifdef CONFIG_SMP
44. return (local_t *) (mod->refptr + per_cpu_offset(cpu));
45. #else
46. return &mod->ref;
47. #endif
48. }
@include/asm-generic/atomic.h:
[java] view plaincopy
1. typedef atomic64_t atomic_long_t;
@include/linux/types.h:
[java] view plaincopy
1. typedef struct {
2. volatile int counter;
3. } atomic_t;
4.
5. #ifdef CONFIG_64BIT
6. typedef struct {
7. volatile long counter;
8. } atomic64_t;
9. #endif
@arch/x86/include/asm/local.h:
[java] view plaincopy
1. typedef struct {
2. atomic_long_t a;
3. } local_t;
4.
5. #define local_read(l) atomic_long_read(&(l)->a)
6. #define local_set(l, i) atomic_long_set(&(l)->a, (i))
7.
8. //此外还有加减操作
@include/asm-generic/percpu.h:
[java] view plaincopy
1. #ifdef CONFIG_SMP
2.
3. /** per_cpu_offset() is the offset that has to be added to a percpu variable to get the instance for
4. * a certain processor. * Most arches use the __per_cpu_offset array for those offsets but some arches have their own
5. * ways of determining the offset (x86_64, s390).
6. */
7.
8. #ifndef __per_cpu_offset
9. extern unsigned long __per_cpu_offset[NR_CPUS];
10. #define per_cpu_offset(x) (__per_cpu_offset[x])
11. #endif
展开阅读全文