一.问题: 
前些日子在工作中遇到一个文件,当rmmod一个模块的时候,在模块的exit函数中阻塞了,rmmod进程杀也杀不掉,永远呆在那里,发现它已经是D(disk sleep)状态了,真的无能为力了吗?我不相信这个事实,所以今天在稍微闲暇的时候换换脑子,终于有了解决办法。
二.分析: 
解铃还须系铃人,既然是在内核中出了问题,还是需要在内核中寻找办法,解决这类问题的前提是对内核卸载模块的精确理解,流程都理解透了,害怕找不到原因吗?原因都找到了,办法肯定是有的! (这也是我从公司学习到的最重要的东西!), 我按照这个原则,查到了rmmod最终调用的代码:
 
以上注释了4处,分别解释如下:
情况0: 有其它模块依赖要卸载的模块。模块a是否依赖模块b,这个在模块a加载的时候调用resolve_symbol抉择,如果模块a的symbol在模块b中,则依赖
情况1: 只有LIVE状态的模块才能被卸载。
情况2: 引用计数在有其它模块或者内核本身引用的时候不为0,要卸载就要等待它们不引用为止。
情况3: 这个情况比较普遍,因为模块万一在使用过程中oom或者依赖它的模块oom或者模块本身写的不好有bug从而破坏了一些数据结构,那么可能造成exit函数中阻塞,最终rmmod不返回! 
三.尝试一下: 
     针对情况3,举一个例子来模拟:
 
编译为test.ko,最终在rmmod test的时候会阻塞,rmmod永不返回了!很显然是cleanup_module出了问题,因此再写一个模块来卸载它!在编译模块之前,首先要在/proc/kallsym中找到以下这行:
f88de380 d __this_module        [XXXX无法卸载的模块名称] 
这是因为modules链表没有被导出,如果被导出的话,正确的方式应该是遍历这个链表来比对模块名称的。
以下的模块加载了以后,上述模块就可以被rmmod了:
 
然后加载上述模块后,前面的模块就可以卸载了。
四.更深入的一些解释: 
针对这个模块导致的无法卸载的问题,还有另一种方解决式,就是在别的module中complete掉这个completion,这个completion当然是无法直接得到的,还是要通过/proc/kallsyms得到这个completion的地址,然后强制转换成completion并完成它:
 
当然这种方式是最好的了,否则如果使用替换exit的方式,会导致前面的那个阻塞的rmmod无法退出。你可能想在新编写的模块中调用try_to_wake_up函数,然而这也是不妥当的,因为它可能在wait_for_completion,而wait_for_completion中大量引用了已经被替换exit回调函数进而被卸载的模块数据,比如:
spin_unlock_irq(&x->wait.lock);
schedule();
spin_lock_irq(&x->wait.lock);
 
其中x就是那个模块里面的,既然x已经没有了(使用替换exit的方式已经成功卸载了模块,模块被free,x当然就不复存在了),刚刚被唤醒运行的rmmod就会oops,但是不管怎样,一个进程的oops一般是没有问题的,因此还是可以干掉它的,这种oops一般不会破坏其它的内核数据,一般都是由于引用已经被free的指针引起的(当然还真的可能有危险情况哦...)。 既然知道这些rmmod都是阻塞在睡眠里面,那么我们只需要强制唤醒它们就可以了,至于说被唤醒后oops了怎么办?由内核处理啦,或者听天由命!因此考虑以下的代码:
 
然后再ps -e一下,基本没有那个rmmod进程了。一个[State:  D (disk sleep)]的进程这样完蛋了。
     以上代码基本都是硬编码的地址以及进程号,真正的代码应该使用参数来传递这些信息,就会比较方便了!
     既然模块结构都可以拿到,它的任意字段就可以被任意赋值,哪里出了问题就重新赋值哪里!既然内核空间都进入了,导不导出符号就不是根本问题了,就算没有procfs的kallsym,也一样能搞定,因为你能控制整个内存! 
五.防删除: 
我们可以在自己的模块初始化的时候将其引用计数设置成一个比较大的数,或者设置一下别的模块结构体字段,防治被rmmod,然而别人也可以再写一个模块把这些字段设置回去,简单的使用上述方式就可以干掉你的防删除模块,这是一个矛与盾的问题,关键是,别让人拥有root权限。 
六.总结: 
代码都拿到手了,流程还看不懂吗?流程都懂了,还怕定位不到问题吗?问题都定位了,还能解决不了吗?只要没有人为因素,事实上任何技术问题都是能解决的( 这是我从公司学习到的最重要的东西 ! ),所谓的不可能只是规范上的规定或者说既然你误操作了或者你的代码有bug,与其说去按照上述方式搞定它,还不如不搞定它,而是改正你自己的错误!

     解决模块由于阻塞而无法删除问题有下面的过程:
1.写一个模块替换exit函数,且设置引用计数为0,状态为LIVE,然后rmmod;
2.强制try_to_wake_up那个rmmod进程,注意不能使用wake_up,因为队列可能已经不在了,而应该直接唤醒task_struct;
3.听天由命! 

附:内核缺页 
在do_page_fault中,如果缺页发生在内核空间,最终OOPS的话,会调用die:
die("Oops", regs, error_code);
在die中,如果没有处在中断以及没有设置panic-on-oops的话,最终将以SIGSEGV退出当前进程:
if (in_interrupt())
    panic("Fatal exception in interrupt");
if (panic_on_oops) {
    printk(KERN_EMERG "Fatal exception: panic in 5 seconds/n");
    set_cu rrent_state(TASK_UNINTERRUPTIBLE);
    schedule_timeout(5 * HZ);
    panic("Fatal exception");
}
do_exit(SIGSEGV);
这样,如果唤醒睡眠在模块exit中的rmmod,显然在被唤醒之后,检测变量会导致缺页(由于变量已经被free了),因此会进入die("Oops"...),最终退出rmmod进程,这个也是很合理的哦!因此上述的清理D状态的进程还是可以用的。

本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1271022

linux内核模块的强制删除-结束rmmod这类disk sleep进程相关推荐

  1. 一文了解linux 内核模块 强制卸载

    [推荐阅读] 需要多久才能看完linux内核源码? 概述Linux内核驱动之GPIO子系统API接口 一篇长文叙述Linux内核虚拟地址空间的基本概括 0 问题:某项目中,关于一种调用设备驱动程序,出 ...

  2. linux 内核模块 强制卸载

    0 问题:某项目中,关于一种调用设备驱动程序,出现异常时,驱动设备无法正常退出(lsmod 显示驱动设备被占用.无法rmmod 退出),也无法继续使用的问题. 1 linux 模块 内核模块是Linu ...

  3. linux内核模块相关命令:lsmod,depmod,modprobe,modinfo,insmod,rmmod 使用说明

    原文链接:http://www.cnblogs.com/jacklikedogs/p/4659249.html inux内核模块相关命令:lsmod,depmod,modprobe,modinfo,i ...

  4. linux路由器文件目录,路由器挂载U盘文件和文件夹删除不掉,linux系统强制删除文件和文件夹命令...

    电脑文件夹删除不掉该怎么解决呢?最近有不少的小伙伴都问小编遇到电脑文件夹删除不掉的情况该要怎么解决,所以不知道怎么解决这个问题的小伙伴,就赶紧来看看小编在下面给你们分享快速删除电脑文件夹的详细操作方法 ...

  5. Linux 删除文件夹和文件的命令(强制删除包括非空文件)

    linux删除目录很简单,很多人还是习惯用rmdir,不过一旦目录非空,就陷入深深的苦恼之中,现在使用rm -rf命令即可. 直接rm就可以了,不过要加两个参数-rf 即:rm -rf 目录名字 -r ...

  6. linux 删除模块命令,Linux系统中的Modprobe命令:添加和删除Linux内核模块的方法

    在本文中,我们将说明如何使用modprobe命令在Linux内核中添加和删除Linux内核模块.modprobe是kmod的一部分,kmod是一种二进制文件,可实现用于管理Linux内核模块的多个程序 ...

  7. linux 删除多个软件下载,linux强制删除软件强力清除残留配置

    Linux概述在系统使用过程中, 不可避免的要安装各种软件, 当软件不用时, 需要卸载释放空间, Linux 安装卸载软件不像Win那样有很完善的软件管理机制, 就算Win自己的不够给力, 也有大量第 ...

  8. linux清理内存垃圾 强力,linux强制删除软件强力清除残留配置

    Linux概述在系统使用过程中, 不可避免的要安装各种软件, 当软件不用时, 需要卸载释放空间, Linux 安装卸载软件不像Win那样有很完善的软件管理机制, 就算Win自己的不够给力, 也有大量第 ...

  9. linux桌面卷积文件删除不掉,Linux 删除文件夹和文件的命令(强制删除包括非空文件)...

    linux删除目录很简单,很多人还是习惯用rmdir,不过一旦目录非空,就陷入深深的苦恼之中,现在使用rm -rf命令即可. 直接rm就可以了,不过要加两个参数-rf 即:rm -rf 目录名字 -r ...

最新文章

  1. Python数据清理终极指南(2020版)
  2. 北大计算机博士生先于OpenAI发表预训练语言模型求解数学题论文,曾被顶会拒绝...
  3. windows与linux下的\r\n
  4. Linux 下 VNC配置和使用(本机控制本机)
  5. Django从理论到实战(part35)--QuerySetAPI
  6. 『C#基础』调用CMD的一个小工具
  7. java getid_Java TimeZone getID()方法与示例
  8. 基于 HTTP/2 的全新 APNs 协议
  9. thinkphp5.0.6 连接SQLServer2008r2 配置总结
  10. 开机未发现nvidia控制面板_Nvidia控制面板打不开,怎么办?
  11. 记录安卓,IOS安装kali的办法
  12. Java桌面程序打包全过程
  13. java面试题大全(整理版)
  14. 冯诺依曼机与现代计算机的比较
  15. c++ 定义一个字符栈类Stack(包括类的实现)。数据成员包括一个存放字符的数组stck[ ]和一个栈指针tos。栈数组的尺寸由常量SIZE确定。栈的基本操作为Push()和Pop()。
  16. 收房入住注意事项及程序
  17. 学计算机多大显卡够用,4GB显存过气、买新显卡非8GB不选?2分钟搞懂多大显存适合你...
  18. 汉字字符内码查询_VB小程序,字符与内码
  19. ipad硬解ID,苹果硬解ID锁
  20. windows+ubuntu双系统启动引导修复教程

热门文章

  1. 使用Hexo在Github搭建静态博客
  2. Linux软raid创建和维护
  3. 北电ERS1600,8300,8600交换机的基本技术-第六章 二层冗余技术(MLT,SMLT,IST)
  4. 8 基于管道的持久化存储 scrapy
  5. 直接通过Binder的onTransact完成跨进程通信
  6. 《并行计算的编程模型》一2.4.1 GASNet段
  7. Qt计算器开发(二):信号槽实现数学表达式合法性检查
  8. HDUOJ------Worm
  9. 华为三层交换机(5328)DHCP中继应用配置实例
  10. 修改中断向量ESC退出