3.10内核上rmmod失败处理

前几天在一台测试机器上遇到了rmmod失败的现象,通过lsmod可以看到它的引用计数为1。但是我可以确定已经没有被使用了,所以这应该是一个代码中的bug。
从网上可以找到一篇写得非常好的rmmod失败的分析文章,里面还提供了一段代码,可以编译出一个ko文件,通过加载这个module并且传入有问题的module名字,可以达到强行问题module引用计数的效果,然后就可以使用rmmod命令来删除它了。
这篇文章的地址是 https://blog.csdn.net/gatieme...
作者也给出了代码的github地址https://github.com/gatieme/LD...
可是里面提供的源代码对应的内核版本是4以上的,我的机器是3.10,所以在编译的时候会遇到语法问题

[root@controller22860 force_rmmod]# make
echo /root/force_rmmod
/root/force_rmmod
echo 3.10.0-957.10.2.el7.x86_64
3.10.0-957.10.2.el7.x86_64
echo /lib/modules/3.10.0-957.10.2.el7.x86_64/build
/lib/modules/3.10.0-957.10.2.el7.x86_64/build
make -C /lib/modules/3.10.0-957.10.2.el7.x86_64/build M=/root/force_rmmod modules
make[1]: Entering directory `/usr/src/kernels/3.10.0-957.10.2.el7.x86_64'
  CC [M]  /root/force_rmmod/force_rmmod.o
/root/force_rmmod/force_rmmod.c: In function ‘force_cleanup_module’:
/root/force_rmmod/force_rmmod.c:85:17: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 4 has type ‘long unsigned int’ [-Wformat=]
                 mod->name ,mod->state, module_refcount(mod));
                 ^
In file included from /root/force_rmmod/force_rmmod.c:6:0:
/root/force_rmmod/force_rmmod.c:110:46: error: ‘struct module’ has no member named ‘refcnt’
         local_set((local_t*)per_cpu_ptr(&(mod->refcnt), cpu), 0);
                                              ^
include/asm-generic/local.h:29:43: note: in definition of macro ‘local_set’
 #define local_set(l,i) atomic_long_set((&(l)->a),(i))
                                           ^
include/asm-generic/percpu.h:46:2: note: in expansion of macro ‘__verify_pcpu_ptr’
  __verify_pcpu_ptr((__p));     \
  ^
include/linux/percpu.h:149:31: note: in expansion of macro ‘SHIFT_PERCPU_PTR’
 #define per_cpu_ptr(ptr, cpu) SHIFT_PERCPU_PTR((ptr), per_cpu_offset((cpu)))
                               ^
/root/force_rmmod/force_rmmod.c:110:29: note: in expansion of macro ‘per_cpu_ptr’
         local_set((local_t*)per_cpu_ptr(&(mod->refcnt), cpu), 0);
                             ^
compilation terminated due to -Wfatal-errors.

于是我简单分析了一下3.10的代码,发现它的 struct module 里面确实是没有定义 refcnt 这个成员的。所以需要修改一下 force_rmmod.c 的代码,我把报错那段改成了下面这样:

    //  清除驱动的引用计数
    int ref_cnt = 0;
    for_each_possible_cpu(cpu)
    {
        //local_set((local_t*)per_cpu_ptr(&(mod->refcnt), cpu), 0);
        //local_set(__module_ref_addr(mod, cpu), 0);
        if (per_cpu_ptr(mod->refptr, cpu)->decs) {
          printk("module has dec %d on cpu %d\n", per_cpu_ptr(mod->refptr, cpu)->decs, cpu);
          ref_cnt -= per_cpu_ptr(mod->refptr, cpu)->decs;
        }

        if (per_cpu_ptr(mod->refptr, cpu)->incs) {
          //module_put(mod);
          printk("module has inc %d on cpu %d\n", per_cpu_ptr(mod->refptr, cpu)->incs, cpu);
          ref_cnt += per_cpu_ptr(mod->refptr, cpu)->incs;
        }
    }
    for(int i = 0; i < ref_cnt; i++) {
        module_put(mod);
    }

主要的原理就是通过计算各个cpu上对该模块的引用计数累计得到当前的计数值,然后按照计数值做module_put动作,就可以把引用计数值降到0了,随后就可以正常rmmod了。

我把作者的repo fork之后修改了一下,新的文件在 https://github.com/yzx1983/LD...

你可能感兴趣的:(linux内核模块)