• 强力卸载内核模块


    概述

    内核为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了!

    代码

    #include<linux/init.h>
    #include<linux/module.h>
    #include<linux/kernel.h>
    #include<linux/list.h>
    #include<linux/cpumask.h>
    
    static int __init mymod_init(void)
    {
            struct module *mod,*relate;
            int cpu;
    
            // 打印本模块的模块名和模块状态
            printk(KERN_ALERT"[insmod mymod] name:%s state:%d\n",THIS_MODULE->name,THIS_MODULE->state);
    
           // 遍历模块列表,查找target模块
            list_for_each_entry(mod,THIS_MODULE->list.prev,list)
            {
                    if(strcmp(mod->name,"target")==0) { 
    
                            // 打印target的模块名、模块状态、引用计数
                            printk(KERN_ALERT"name:%s state:%d refcnt:%u ",mod->name,mod->state,module_refcount(mod));
    
                            // 打印出所有依赖target的模块名
                            if(!list_empty(&mod->modules_which_use_me)) { 
                                    list_for_each_entry(relate,&mod->modules_which_use_me,modules_which_use_me)
                                            printk(KERN_ALERT"%s ",relate->name);
                            } else
                                    printk(KERN_ALERT"used by NULL\n");
    
                            // 把target的引用计数置为0
                            for_each_possible_cpu(cpu)
                                    local_set(__module_ref_addr(mod,cpu),0);
    
                            // 再看看target的名称、状态、引用计数
                            printk(KERN_ALERT"name:%s state:%d refcnt:%u\n",mod->name,mod->state,module_refcount(mod));
                    }
            }
            return 0;
    }
    
    static void __exit mymod_exit(void)
    {
            printk(KERN_ALERT"[rmmod mymod] name:%s state:%d\n",THIS_MODULE->name,THIS_MODULE->state);
    }
    
    module_init(mymod_init);
    module_exit(mymod_exit);
    
    MODULE_AUTHOR("Zhangsk");
    MODULE_LICENSE("GPL");
    MODULE_DESCRIPTION("Why module can not be removed");
    
    

    内核

     

    @include/linux/module.h:

    extern struct module __this_module;
    #define THIS_MODULE (&__this_module);
    
    enum module_state{ 
        MODULE_STATE_LIVE; // 模块存活,0 
        MODULE_STATE_COMING; // 正在加载模块,1 
        MODULE_STATE_GOING; // 正在卸载模块,2
    }; 
    
    struct module { 
        enum module_state state; // 模块状态 
    
        /* Member of list of modules */ 
        struct list_head list; // 内核模块链表 
    
        /* Unique handle for this module */ 
        char name[MODULE_NAME_LEN]; //模块名称 
    
        ...
    
    #ifdef CONFIG_MODULE_UNLOAD
         /* What modules depend on me? */ 
        struct list_head modules_which_use_me;
    
         /* Who is waiting for us to be unloaded */ 
        struct task_struct *waiter;
    
         /* Destruction function. */ 
        void (*exit) (void);
    
    #ifdef CONFIG_SMP 
        char *refptr;
    #else 
        local_t ref;
    #endif
    #endif 
    
        ...
    
    };
    
    static inline local_t *__module_ref_addr(struct module *mod, int cpu)
    {#ifdef CONFIG_SMP
         return (local_t *) (mod->refptr + per_cpu_offset(cpu));
    #else
         return &mod->ref;
    #endif
    }

    @include/asm-generic/atomic.h:

    typedef atomic64_t atomic_long_t;
    

    @include/linux/types.h:

    typedef struct { 
        volatile int counter;
    } atomic_t;
    
    #ifdef CONFIG_64BIT
    typedef struct { 
        volatile long counter;
    } atomic64_t;
    #endif

    @arch/x86/include/asm/local.h:

    typedef struct {
        atomic_long_t a;
    } local_t; 
    
    #define local_read(l) atomic_long_read(&(l)->a)
    #define local_set(l, i) atomic_long_set(&(l)->a, (i))
    
    //此外还有加减操作

    @include/asm-generic/percpu.h:

    #ifdef CONFIG_SMP
    
    /** per_cpu_offset() is the offset that has to be added to a percpu variable to get the instance for
      * a certain processor. * Most arches use the __per_cpu_offset array for those offsets but some arches have their own
      * ways of determining the offset (x86_64, s390). 
      */
    
    #ifndef __per_cpu_offset
    extern unsigned long __per_cpu_offset[NR_CPUS];
    #define per_cpu_offset(x) (__per_cpu_offset[x])
    #endif

     

  • 相关阅读:
    内置函数(十)
    常用命令
    函数式编程(九)——map,filter,reduce
    函数(八)-函数和匿名函数
    设计模式(十三)——观察者模式
    Confluence 6 重要缓存和监控
    Confluence 6 数据中心的缓存
    Confluence 6 配置文件和key
    Confluence 6 缓存性能示例
    Confluence 6 缓存性能优化
  • 原文地址:https://www.cnblogs.com/aiwz/p/6333372.html
Copyright © 2020-2023  润新知