linux3 x 核心如何強制解除安裝模組?

2021-06-28 02:44:48 字數 4630 閱讀 5726

一、問題現象:

在insmod時呼叫的init函式**執行過程中出現oops,導致rmmod解除安裝失敗,此時不得不重啟目標板?

no!下面是《精通linux裝置驅動程式開發》中模擬滑鼠的輸入裝置驅動的核心模組vms.c**:

#include #include #include #include #include #include static struct platform_device *vms_dev;

static struct input_dev *vms_input_dev;

static ssize_t write_vms(struct device *dev, struct device_attribute *attr, const char *buffer, size_t count)

device_attr(coordinates, 0644, null, write_vms);

static struct attribute *vms_attrs = ;

static struct attribute_group vms_attr_group = ;

static int __init vms_init(void)

printk("vms_dev = 0x%x\n", vms_dev);

err = sysfs_create_group(&vms_dev->dev.kobj, &vms_attr_group);

if (err)

printk("vms_init++++++++++\n");

vms_input_dev = input_allocate_device();

if (!vms_input_dev)

//vms_input_dev->name = "vms_device";

strcpy(vms_input_dev->name, "vms test"); // oops!,程式退出

set_bit(ev_rel, vms_input_dev->evbit);

set_bit(rel_x, vms_input_dev->relbit);

set_bit(rel_y, vms_input_dev->relbit);

input_register_device(vms_input_dev);

//strcpy(vms_input_dev->name, "vms test");

printk("virtual mouse driver initialized.\n");

return 0;

}static void __exit vms_cleanup(void)

module_init(vms_init);

module_exit(vms_cleanup);

module_license("dual bsd/gpl");

module_author("xumin");

insmod ./vms.ko後通過dmesg看到的資訊:

然後sudo rmmod vms模組,會發現解除安裝不了:

我們知道,rmmod是呼叫sys_delete_module函式進行刪除模組的,下面是其具體實現的的解析:

所以需要通過編寫專門用於解除安裝vms核心模組的核心模組force_rmmod,下面是force_rmmod.c的源**:

#include #include #include #include #include #include #include #include static void force(void)

static int __init force_rmmod_init(void)

else

mod->state = 0;

mod->exit = force;

for_each_possible_cpu(cpu)

local_set((local_t*)per_cpu_ptr(mod->refptr, cpu), 0);

//local_set(__module_ref_addr(mod, cpu), 0);

//per_cpu_ptr(mod->refptr, cpu)->decs;

//module_put(mod);

printk("[after]:name:%s, state:%d, refcnt:%u\n",

mod->name, mod->state, module_refcount(mod));

}} return 0;

}static void __exit force_rmmod_exit(void)

module_init(force_rmmod_init);

module_exit(force_rmmod_exit);

module_license("gpl");

通過安裝force_rmmod.ko後,會發現vms模組目前的引用計數為1,且狀態處於1,通過上面對sys_delete_module函式的理解得知,刪除乙個模組,需要將模組狀態置為0,且引用計數置為0。

下面是模組的基本知識:

extern struct module __this_module;

#define this_module (&__this_module);

enum module_state;

struct module ;

static inline local_t *__module_ref_addr(struct module *mod, int cpu)

但若僅將設定模組的引用計數和狀態為0,還是會出現sys_delete_module因呼叫模組exit的函式(即vms_cleanup函式)而出現宕機的問題(因為程式出現oops,導致input_register_device(vms_input_dev); 根本沒有執行,而該exit函式卻呼叫了input_unregister_device(vms_input_dev); ,從而導致宕機)。為了解決這個問題,需要把exit換成乙個能成功執行的函式。但問題依然沒能完全解決,雖然此時可以rmmod vms成功,執行lsmod也查知vms在模組鍊錶中已經刪除,但vms模組因為在oops之前已經執行過 vms_dev = platform_device_register_******("vms", -1, null, 0); 仍然會導致後續再執行insmod ./vms.ko時失敗,因為該註冊函式對應的登出函式沒有被呼叫到。vms_dev是乙個核心變數符號,通過sudo cat /proc/kallsyms | grep vms_dev 可以得知vms_dev的位址。(注意,在ubuntu下,必須使用root許可權才能獲取到符號位址!)然後在force_rmmod.c的exit函式中將這個vms_dev登出掉。但這種做很麻煩,每次都要手動去獲取vms_dev的位址。其實核心可以通過kallsyms_lookup_name函式獲取到vms_dev的位址,見force_rmmod的exit**。

在執行insmod ./force_rmmod.ko之後,便可以隨心所欲地安裝和解除安裝vms.ko了。

三、問題解決思路

1、首先弄懂核心模組為啥無法刪除? rmmod是通過sys_delete_module來解除安裝模組的,刪除核心模組的必要條件是該模組的引用計數為0,且狀態為「module_state_live; // 模組存活,0」,然後才呼叫模組的exit函式。如果執行exit時失敗,甚至系統宕機,我們需要分析模組的init函式,仔細分析其流程,設計我們自己的exit函式。

2、執行cat /proc/kallsyms | grep vms_dev,結果發現其符號位址為0。原來是ubuntu的安全機制處理的結果,需要root許可權才能檢視位址。其對應的核心中獲取符號位址的方法是:kallsyms_lookup_name函式。

3、程式出現rmmod失敗的原因一是解除安裝的模組被其他模組引用,或者模組的初始化**出現bug,雖沒有其他模組引用,但其模組引用計數也是1。所以需要仔細排查模組初始化**中是否有異常退出的情況發生。

四、force_rmmod.c對應的makefile(vms.c對應的makefile類似)

kvers = $(shell uname -r)

obj-m := force_rmmod.o

all: kernel_modules

kernel_modules:

make -c /lib/modules/$(kvers)/build m=$(shell pwd) modules

clean:

make -c /lib/modules/$(kvers)/build m=$(curdir) clean

lucene3 x核心類介紹

b 索引核心類 b o b directory b 描述lucene索引存放的位置,是乙個抽象類,由子類負責指定索引存在位置 記憶體或者磁碟 b indexwrite b r 負責建立或者開啟新索引,以及對索引做增刪改操作 b analyzer b 文字檔案在被索引前需要經過它進行分析,把它的物件在...

linux核心 x86 32位核心啟動流程

arch x86 boot header.s 執行 start,第274行 global start start 然後跳轉執行start of setup,準備實模式建立堆疊,bss段清0,為下步c語言執行建立環境。start of setup 然後跳轉到c 執行main jump to c cod...

如何編譯核心Linux

我裝的是 linux 2.4.20 這個連線進行 c 配置核心前的準備工作 配置核心前的準備工作 cd usr include rm rf asm linux scsi asm generic 或改名儲存 ln s usr src linux include asm i386 asm ln s us...