1、内核为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,却没有
2、引用者。
这可能是模块插入内核时出错而引起的,这里先不研究,先关注怎么把它强制卸载掉,虽然
insmod加载是临时的,所以通过重启电脑可以解决一些问题,但是不能总是依靠重启啊。
解决方法:编写模块mymod中把问题模块target的引用计数置为0,就可以顺利卸载掉target了!
代码
[java] view plaincopy
1. #include
3、 #include
4、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"n
5、ame:%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_
6、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.
7、 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(mo
8、d)); 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); 4
9、7. 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_modul
10、e); 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 */
11、 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_whi
12、ch_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. #
13、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
14、 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
15、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.
16、 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






