1. 程式人生 > >從基本理解到深入探究 Linux kernel 通知鏈(notifier chain)【轉】

從基本理解到深入探究 Linux kernel 通知鏈(notifier chain)【轉】

see sta seconds 內核和 一定的 mut 內核模塊 val spa

轉自:https://blog.csdn.net/u014134180/article/details/86563754

版權聲明:本文為博主原創文章,未經博主允許不得轉載。——Wu_Being https://blog.csdn.net/u014134180/article/details/86563754
文章目錄
基本理解Linux 內核事件通知鏈
1. TP 驅動相關代碼
2. LCM 背光相關代碼
3. 運行結果
深入探究Linux 內核事件通知鏈
1. 通知鏈的引入
2. 四種通知鏈的類型
原子通知鏈(Atomic notifier chains)
可阻塞通知鏈(Blocking notifier chains)

原始通知鏈(Raw notifierchains)
SRCU 通知鏈(SRCU notifier chains)
3. 一個簡單的通知鏈實例
基本理解Linux 內核事件通知鏈
內核事件通知鏈一個比較典型的例子就是Display 背光通知TP suspend和resume 的過程,我們這裏先從高通平臺的LCD 背光通知TP suspend 入場,以快速理解Linux 內核事件通知鏈應用。

1. TP 驅動相關代碼
kernel/msm-4.9/drivers/input/touchscreen/xxxxx_touch/xxxx_core.c
TP 驅動probe 函數裏指定到背光通知回調函數fb_notifier_callback,並註冊到通知鏈裏。fb_notifier_callback 函數根據收到的通知event信息調用TS resume 或suspend 函數。


static int xxx_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
... ...
ts_data->fb_notif.notifier_call = fb_notifier_callback;
ret = fb_register_client(&ts_data->fb_notif);
}

static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data)

{
struct fb_event *evdata = data;
int *blank;
struct xxx_ts_data *xxx_data = container_of(self, struct xxx_ts_data, fb_notif);

printk("[xxx][WU] event = %ld, FB_EVENT_BLANK = %d or FB_EARLY_EVENT_BLANK = %d",
event, FB_EVENT_BLANK); //16 == 9 or 16; 9 == 9 or 16
if (evdata && evdata->data && event == FB_EARLY_EVENT_BLANK \
&& fts_data && fts_data->client) {
blank = evdata->data;
printk("[FTS][WU] blank = %d", *blank);

if (*blank == FB_BLANK_UNBLANK){//0
printk("[FTS][WU] fts_ts_resume FB_BLANK_UNBLANK = %d", FB_BLANK_UNBLANK);
fts_ts_resume(&fts_data->client->dev);
}
else if (*blank == FB_BLANK_POWERDOWN){//4
printk("[FTS][WU] fts_ts_suspend FB_BLANK_POWERDOWN = %d", FB_BLANK_POWERDOWN);
fts_ts_suspend(&fts_data->client->dev);
}
}
return 0;
}

註:若對上面container_of有題問,可參考文章 《從基本理解到深入探究Linux kernel container_of 宏》

2. LCM 背光相關代碼
kernel/msm-4.9/drivers/video/fbdev/core/fbmem.c
LCM 背光代碼根據相關場景給通知鏈發送相關事件的通知,通知鏈收到通知就執行上面的背光通知回調函數fb_notifier_callback,fb_notifier_callback函數根據不同event事件執行不同的函數。

int fb_blank(struct fb_info *info, int blank)
{ ...
early_ret = fb_notifier_call_chain(FB_EARLY_EVENT_BLANK, &event);// FB_EARLY_EVENT_BLANK = 16
if (info->fbops->fb_blank)
ret = info->fbops->fb_blank(blank, info);
if (!ret)
fb_notifier_call_chain(FB_EVENT_BLANK, &event); //FB_EVENT_BLANK = 9
else {
/** if fb_blank is failed then revert effects of
* the early blank event. */
if (!early_ret)
fb_notifier_call_chain(FB_R_EARLY_EVENT_BLANK, &event);
}
return ret;
}
...
void fb_set_suspend(struct fb_info *info, int state)
{
struct fb_event event;

event.info = info;
if (state) {
fb_notifier_call_chain(FB_EVENT_SUSPEND, &event); // FB_EVENT_SUSPEND = 0x02
info->state = FBINFO_STATE_SUSPENDED;
} else {
info->state = FBINFO_STATE_RUNNING;
fb_notifier_call_chain(FB_EVENT_RESUME, &event); // FB_EVENT_RESUME = 0x03
}
}

3. 運行結果
下面是板子運行的log(已經屏蔽客戶信息),我們在下面在log解釋原理比較簡明吧!
從運行結果可以知道高通背光通知TP過程中,先休眠TP再休眠LCM。


[ 1045.412245] PM: suspend entry 2019-01-13 19:15:43.130364966 UTC // linux kernel 進入休眠
// 退出休眠與進入休眠的UTC時間戳一差,就是kernel 休眠的時間(19:15:55 - 19:15:43)
// 按電源鍵喚醒系統亮屏 ... ...
[ 1050.799717] PM: suspend exit 2019-01-13 19:15:55.594697461 UTC // linux kernel 退出休眠
[ 1051.144198] [xxx][WU] event = 16, FB_EVENT_BLANK = 9 // 背光發送兩次event,一次是16一次是9
[ 1051.144211] [xxx][WU] event = 9, FB_EVENT_BLANK = 9
[ 1051.144221] [xxx][WU] blank = 0 // 其中參數的blank 為0 調用TP resume
[ 1051.144232] [xxx][WU] xxx_ts_resume FB_BLANK_UNBLANK = 0
[ 1051.144233] [xxx]xxx_ts_resume: Enter
[ 1051.146266] [xxx]xxx_ts_resume: Exit(1668)
// 亮屏了10s後,按電源鍵滅屏 ... ...
[ 1061.519665] [xxx][WU] event = 16, FB_EVENT_BLANK = 9 // 背光發送兩次event,一次是16一次是9
[ 1061.519680] [xxx][WU] event = 9, FB_EVENT_BLANK = 9
[ 1061.519690] [xxx][WU] blank = 4 // 其中參數的blank 為4 調用TP suspend
[ 1061.519702] [xxx][WU] xxx_ts_suspend FB_BLANK_POWERDOWN = 4
[ 1061.519703] [xxx]xxx_ts_suspend: Enter
[ 1061.523594] [xxx]xxx_ts_suspend: Exit(1609)
[ 1061.528000]  mdss_dsi_panel_power_off // 然後高通display 下電
[ 1061.529240] hbtp: hbtp->input_dev not ready!
[ 1061.532073] PM: suspend entry 2019-01-13 19:16:06.327045373 UTC
...
[ 1061.649485] PM: suspend exit 2019-01-13 19:16:06.444469957 UTC
[ 1061.853378] PM: suspend entry 2019-01-13 19:16:06.648349227 UTC
[ 1061.853419] PM: Syncing filesystems ... done.
[ 1061.888011] PM: Preparing system for sleep (mem)
[ 1061.888187] Freezing user space processes ... (elapsed 3.964 seconds) done.
[ 1065.852448] Freezing remaining freezable tasks ... (elapsed 0.009 seconds) done.
[ 1065.861693] PM: Suspending system (mem)
[ 1065.861723] Suspending console(s) (use no_console_suspend to debug)
// 因為TP已經休眠了, 上面 fb_set_suspend 函數也發來fb set supend 事件,不過這次已經無效了
[ 1065.895347] [xxx][WU] event = 2, FB_EVENT_BLANK = 9, FB_EVENT_SUSPEND = 2 // fb_set_suspend
[ 1065.933676] [xxx][WU] event = 2, FB_EVENT_BLANK = 9, FB_EVENT_SUSPEND = 2 // fb_set_suspend
[ 1066.742596] PM: suspend exit 2019-01-13 19:16:27.002118646 UTC

總結下來就三個函數:

int fb_register_client(struct notifier_block *nb)
int fb_unregister_client(struct notifier_block *nb)
int fb_notifier_call_chain(unsigned long val, void *v)
上面三個函數就只是簡單調用系統接口,如下代碼 linux/drivers/video/fbdev/core/fb_notify.c

/*
* linux/drivers/video/fb_notify.c
*
* Copyright (C) 2006 Antonino Daplas <[email protected]>
*
* 2001 - Documented with DocBook
* - Brad Douglas <[email protected]>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*/
#include <linux/fb.h>
#include <linux/notifier.h>
#include <linux/export.h>

static BLOCKING_NOTIFIER_HEAD(fb_notifier_list);

/**
* fb_register_client - register a client notifier
* @nb: notifier block to callback on events
*/
int fb_register_client(struct notifier_block *nb)
{
return blocking_notifier_chain_register(&fb_notifier_list, nb);
}
EXPORT_SYMBOL(fb_register_client);

/**
* fb_unregister_client - unregister a client notifier
* @nb: notifier block to callback on events
*/
int fb_unregister_client(struct notifier_block *nb)
{
return blocking_notifier_chain_unregister(&fb_notifier_list, nb);
}
EXPORT_SYMBOL(fb_unregister_client);

/**
* fb_notifier_call_chain - notify clients of fb_events
*
*/
int fb_notifier_call_chain(unsigned long val, void *v)
{
return blocking_notifier_call_chain(&fb_notifier_list, val, v);
}
EXPORT_SYMBOL_GPL(fb_notifier_call_chain);

註:EXPORT_SYMBOL_GPL 是導出參數的函數給kernel其他地方使用,要加include頭文件。

一般會使用這個幾個接口就行了,若不想放棄請看下面深入探究Linux 內核事件通知鏈。

深入探究Linux 內核事件通知鏈
1. 通知鏈的引入
Linux內核中各個子系統相互依賴,當其中某個子系統狀態發生改變時,就必須使用一定的機制告知使用其服務的其他子系統,以便其他子系統采取相應的措施。為滿足這樣的需求,內核實現了事件通知鏈機制(notification chain)。
通知鏈只能用在各個子系統之間,而不能在內核和用戶空間進行事件的通知。組成內核的核心系統代碼均位於kernel目錄下,通知鏈表位於kernel/notifier.c中,對應的頭文件為include/linux/notifier.h。
事件通知鏈表是一個事件處理函數的列表,每個通知鏈都與某個或某些事件有關,當特定的事件發生時,就調用相應的事件通知鏈中的回調函數,進行相應的處理。

2. 四種通知鏈的類型
內核使用struct notifier_block結構代表一個notifier

struct notifier_block;
typedef int (*notifier_fn_t)(struct notifier_block *nb,
unsigned long action, void *data); //notifier回調函數類型

struct notifier_block {
notifier_fn_t notifier_call; //回調函數
struct notifier_block __rcu *next; //用於掛到通知鏈上
int priority;
}; //notifier 結構體

內核提供了四種不同類型的notifier chain,notifier block 和 notifier chain的數據結構組織方式如下:


原子通知鏈(Atomic notifier chains)
之所以被稱為原子通知鏈,是因為通知鏈元素的回調函數(當事件發生時要執行的函數)在中斷或原子操作上下文中運行,不允許阻塞。

struct atomic_notifier_head {
spinlock_t lock; // 自旋鎖保護通知鏈
struct notifier_block __rcu *head; //通知鏈元素的鏈表
};

原子通知鏈對應的API

//1.初始化一個原子通知鏈
#define ATOMIC_NOTIFIER_HEAD(name) \
struct atomic_notifier_head name = \
ATOMIC_NOTIFIER_INIT(name)

//2.註冊一個notifier block 到通知鏈
extern int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
struct notifier_block *nb);

//3.發送一個事件到通知鏈上的notifier block
extern int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
unsigned long val, void *v);

//4.從通知鏈刪除一個notifier block
extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
struct notifier_block *nb);


相關函數定義如下

/*
* Atomic notifier chain routines. Registration and unregistration
* use a spinlock, and call_chain is synchronized by RCU (no locks).
*/
int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
struct notifier_block *n)
{
unsigned long flags;
int ret;
spin_lock_irqsave(&nh->lock, flags);
ret = notifier_chain_register(&nh->head, n);
spin_unlock_irqrestore(&nh->lock, flags);
return ret;
}
int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
struct notifier_block *n)
{
unsigned long flags;
int ret;
spin_lock_irqsave(&nh->lock, flags);
ret = notifier_chain_unregister(&nh->head, n);
spin_unlock_irqrestore(&nh->lock, flags);
synchronize_rcu();
return ret;
}
/**
* Calls each function in a notifier chain in turn. The functions
* run in an atomic context, so they must not block.
* This routine uses RCU to synchronize with changes to the chain.
*/
int __atomic_notifier_call_chain(struct atomic_notifier_head *nh,
unsigned long val, void *v,
int nr_to_call, int *nr_calls)
{
int ret;
rcu_read_lock();
ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
rcu_read_unlock();
return ret;
}
int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
unsigned long val, void *v)
{
return __atomic_notifier_call_chain(nh, val, v, -1, NULL);
}

可阻塞通知鏈(Blocking notifier chains)
通知鏈元素的回調函數在進程上下文中運行,允許阻塞。

struct blocking_notifier_head {
struct rw_semaphore rwsem;
struct notifier_block *head;
};

可阻塞通知鏈對應的API

//1.初始化一個阻塞通知鏈
#define BLOCKING_NOTIFIER_HEAD(name) \
struct blocking_notifier_head name = \
BLOCKING_NOTIFIER_INIT(name)

//2.註冊一個notifier block 到通知鏈
extern int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
struct notifier_block *nb);

//3.發送一個事件到通知鏈上的notifier block
extern int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
unsigned long val, void *v);

//4.從通知鏈刪除一個notifier block
extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
struct notifier_block *nb);

相關函數定義如下

/*
* Blocking notifier chain routines. All access to the chain is
* synchronized by an rwsem.
*/
int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
struct notifier_block *n)
{
int ret;
/*
* This code gets used during boot-up, when task switching is
* not yet working and interrupts must remain disabled. At
* such times we must not call down_write().
*/
if (unlikely(system_state == SYSTEM_BOOTING))
return notifier_chain_register(&nh->head, n);
down_write(&nh->rwsem);
ret = notifier_chain_register(&nh->head, n);
up_write(&nh->rwsem);
return ret;
}
int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
struct notifier_block *n)
{
int ret;
/*
* This code gets used during boot-up, when task switching is
* not yet working and interrupts must remain disabled. At
* such times we must not call down_write().
*/
if (unlikely(system_state == SYSTEM_BOOTING))
return notifier_chain_unregister(&nh->head, n);
down_write(&nh->rwsem);
ret = notifier_chain_unregister(&nh->head, n);
up_write(&nh->rwsem);
return ret;
}
int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
unsigned long val, void *v,
int nr_to_call, int *nr_calls)
{
int ret = NOTIFY_DONE;
/*
* We check the head outside the lock, but if this access is
* racy then it does not matter what the result of the test
* is, we re-check the list after having taken the lock anyway:
*/
if (rcu_access_pointer(nh->head)) {
down_read(&nh->rwsem);
ret = notifier_call_chain(&nh->head, val, v, nr_to_call,
nr_calls);
up_read(&nh->rwsem);
}
return ret;
}
int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
unsigned long val, void *v)
{
return __blocking_notifier_call_chain(nh, val, v, -1, NULL);
}


原始通知鏈(Raw notifierchains)
對通知鏈元素的回調函數沒有任何限制,所有鎖和保護機制都由調用者維護。

struct raw_notifier_head {
struct notifier_block *head;
};

原始通知鏈對應的API

//1.初始化一個原始通知鏈
#define RAW_NOTIFIER_HEAD(name) \
struct raw_notifier_head name = \
RAW_NOTIFIER_INIT(name)

//2.註冊一個notifier block 到通知鏈
extern int raw_notifier_chain_register(struct raw_notifier_head *nh,
struct notifier_block *nb);

//3.發送一個事件到通知鏈上的notifier block
extern int raw_notifier_call_chain(struct raw_notifier_head *nh,
unsigned long val, void *v);

//4.從通知鏈刪除一個notifier block
extern int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
struct notifier_block *nb);

相關函數定義如下

/*
* Raw notifier chain routines. There is no protection;
* the caller must provide it. Use at your own risk!
*/
int raw_notifier_chain_register(struct raw_notifier_head *nh,
struct notifier_block *n)
{
return notifier_chain_register(&nh->head, n);
}
int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
struct notifier_block *n)
{
return notifier_chain_unregister(&nh->head, n);
}
int __raw_notifier_call_chain(struct raw_notifier_head *nh,
unsigned long val, void *v,
int nr_to_call, int *nr_calls)
{
return notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
}
int raw_notifier_call_chain(struct raw_notifier_head *nh,
unsigned long val, void *v)
{
return __raw_notifier_call_chain(nh, val, v, -1, NULL);
}


SRCU 通知鏈(SRCU notifier chains)
可阻塞通知鏈的一種變體。對應的鏈表頭:

struct srcu_notifier_head {
struct mutex mutex;
struct srcu_struct srcu;
struct notifier_block *head;
};

SRCU 通知鏈對應的API

//1.初始化一個SRCU通知鏈
#ifdef CONFIG_TREE_SRCU
#define _SRCU_NOTIFIER_HEAD(name, mod) \
static DEFINE_PER_CPU(struct srcu_data, name##_head_srcu_data); \
mod struct srcu_notifier_head name = \
SRCU_NOTIFIER_INIT(name, name##_head_srcu_data)

#else
#define _SRCU_NOTIFIER_HEAD(name, mod) \
mod struct srcu_notifier_head name = \
SRCU_NOTIFIER_INIT(name, name)

#endif

//2.註冊一個notifier block 到通知鏈
extern int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
struct notifier_block *nb);

//3.發送一個事件到通知鏈上的notifier block
extern int raw_notifier_call_chain(struct raw_notifier_head *nh,
unsigned long val, void *v);

//4.從通知鏈刪除一個notifier block
extern int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
unsigned long val, void *v);


相關函數定義如下

#ifdef CONFIG_SRCU
/*
* SRCU notifier chain routines. Registration and unregistration
* use a mutex, and call_chain is synchronized by SRCU (no locks).
*/
int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
struct notifier_block *n)
{
int ret;
/*
* This code gets used during boot-up, when task switching is
* not yet working and interrupts must remain disabled. At
* such times we must not call mutex_lock().
*/
if (unlikely(system_state == SYSTEM_BOOTING))
return notifier_chain_register(&nh->head, n);
mutex_lock(&nh->mutex);
ret = notifier_chain_register(&nh->head, n);
mutex_unlock(&nh->mutex);
return ret;
}
int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
struct notifier_block *n)
{
int ret;
/*
* This code gets used during boot-up, when task switching is
* not yet working and interrupts must remain disabled. At
* such times we must not call mutex_lock().
*/
if (unlikely(system_state == SYSTEM_BOOTING))
return notifier_chain_unregister(&nh->head, n);
mutex_lock(&nh->mutex);
ret = notifier_chain_unregister(&nh->head, n);
mutex_unlock(&nh->mutex);
synchronize_srcu(&nh->srcu);
return ret;
}
int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
unsigned long val, void *v,
int nr_to_call, int *nr_calls)
{
int ret;
int idx;
idx = srcu_read_lock(&nh->srcu);
ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
srcu_read_unlock(&nh->srcu, idx);
return ret;
}
int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
unsigned long val, void *v)
{
return __srcu_notifier_call_chain(nh, val, v, -1, NULL);
}
#endif /* CONFIG_SRCU */

3. 一個簡單的通知鏈實例
我們可以自己寫一個內核模塊在Ubuntu 運行驗證一下通知鏈的使用方法。

1.模塊代碼
/**
* file : raw-notifer-chain.c
* owner: wuchengbing
* data : 20190125
*
*/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
//#include <linux/fs.h>
//#include <linux/delay.h>
#include <linux/notifier.h>

// define notifier event type
#define EVENT_A 0x01
#define EVENT_B 0x02

static RAW_NOTIFIER_HEAD(raw_chain_list); //define notifer chain list

// define callback function
int raw_notifer_callback(struct notifier_block *nb, unsigned long event, void *v)
{
switch (event) {
case EVENT_A:
printk("raw_notifer_callback running EVENT_A\n");
break;
case EVENT_B:
printk("raw_notifer_callback running EVENT_B\n");
break;
default:
break;
}

return NOTIFY_DONE;
}

// define notifier block
static struct notifier_block raw_notif = {
.notifier_call = raw_notifer_callback, //appoint notifier callback function
};

static int __init raw_notifier_init(void)
{
printk("raw_notifier_chain_register\n\n");
raw_notifier_chain_register(&raw_chain_list, &raw_notif);

printk("raw_notifier call EVENT_A\n");
raw_notifier_call_chain(&raw_chain_list, EVENT_A, NULL);

printk("raw_notifier call EVENT_B\n");
raw_notifier_call_chain(&raw_chain_list, EVENT_B, NULL);

return 0;
}

static void __exit raw_notifier_exit(void)
{
printk("raw_notifier_chain_unregister\n\n");
raw_notifier_chain_unregister(&raw_chain_list, &raw_notif);
}

module_init(raw_notifier_init);
module_exit(raw_notifier_exit);

MODULE_AUTHOR("Wu_Being");
MODULE_LICENSE("GPL");


2.Makefile 文件
##
# file : Makefile
# owner: wuchengbing
# data : 20190125
##

obj-m += raw-chain-notifier.o # geneate modules ko file
CURRENT_PATH := $(shell pwd) # current core path
LINUX_KERNEL := $(shell uname -r) # kernel version

# kernel core path
LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL)

# make or make all
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules

# make clean
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean


3.運行結果
[email protected]:~/Codes/notifier_chain/raw-notifer-chain$ ls -l
total 8
-rw-rw-r-- 1 wucb0122 wucb0122 453 1月 25 10:10 Makefile
-rw-rw-r-- 1 wucb0122 wucb0122 1440 1月 25 10:08 raw-chain-notifier.c

[email protected]:~/Codes/notifier_chain/raw-notifer-chain$ make
make -C /usr/src/linux-headers-3.13.0-147-generic M=/home/wucb0122/Codes/notifier_chain/raw-notifer-chain modules
make[1]: Entering directory `/usr/src/linux-headers-3.13.0-147-generic‘
CC [M] /home/wucb0122/Codes/notifier_chain/raw-notifer-chain/raw-chain-notifier.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/wucb0122/Codes/notifier_chain/raw-notifer-chain/raw-chain-notifier.mod.o
LD [M] /home/wucb0122/Codes/notifier_chain/raw-notifer-chain/raw-chain-notifier.ko
make[1]: Leaving directory `/usr/src/linux-headers-3.13.0-147-generic‘

[email protected]:~/Codes/notifier_chain/raw-notifer-chain$ls -ltr
total 36
-rw-rw-r-- 1 wucb0122 wucb0122 1440 1月 25 10:08 raw-chain-notifier.c
-rw-rw-r-- 1 wucb0122 wucb0122 451 1月 25 10:12 Makefile
-rw-rw-r-- 1 wucb0122 wucb0122 4752 1月 25 10:12 raw-chain-notifier.o
-rw-rw-r-- 1 wucb0122 wucb0122 83 1月 25 10:12 modules.order
-rw-rw-r-- 1 wucb0122 wucb0122 966 1月 25 10:12 raw-chain-notifier.mod.c
-rw-rw-r-- 1 wucb0122 wucb0122 0 1月 25 10:12 Module.symvers
-rw-rw-r-- 1 wucb0122 wucb0122 2784 1月 25 10:12 raw-chain-notifier.mod.o
-rw-rw-r-- 1 wucb0122 wucb0122 5395 1月 25 10:12 raw-chain-notifier.ko

[email protected]:~/Codes/notifier_chain/raw-notifer-chain$ sudo insmod raw-chain-notifier.ko
[sudo] password for wucb0122:
[email protected]:~/Codes/notifier_chain/raw-notifer-chain$ sudo dmesg -c
...
[153967.504748] raw_chain_notifier: module verification failed: signature and/or required key missing - tainting kernel
[153967.505121] raw_notifier_chain_register
[153967.505121]
[153967.505123] raw_notifier call EVENT_A
[153967.505124] raw_notifer_callback running EVENT_A
[153967.505124] raw_notifier call EVENT_B
[153967.505125] raw_notifer_callback running EVENT_B

[email protected]:~/Codes/notifier_chain/raw-notifer-chain$ make clean
make -C /usr/src/linux-headers-3.13.0-147-generic M=/home/wucb0122/Codes/notifier_chain/raw-notifer-chain clean
make[1]: Entering directory `/usr/src/linux-headers-3.13.0-147-generic‘
CLEAN /home/wucb0122/Codes/notifier_chain/raw-notifer-chain/.tmp_versions
CLEAN /home/wucb0122/Codes/notifier_chain/raw-notifer-chain/Module.symvers
make[1]: Leaving directory `/usr/src/linux-headers-3.13.0-147-generic‘

[email protected]:~/Codes/notifier_chain/raw-notifer-chain$ ls -ltr
total 8
-rw-rw-r-- 1 wucb0122 wucb0122 451 1月 25 10:12 Makefile
-rw-rw-r-- 1 wucb0122 wucb0122 1479 1月 25 10:19 raw-chain-notifier.c

[email protected]:~/Codes/notifier_chain/raw-notifer-chain$ sudo rmmod raw-chain-notifier.ko
[email protected]:~/Codes/notifier_chain/raw-notifer-chain$ sudo dmesg -c
[154548.347863] raw_notifier_chain_unregister
[154548.347863]
[email protected]:~/Codes/notifier_chain/raw-notifer-chain$


Wu_Being博客聲明:本人博客歡迎轉載,請標明博客原文和原鏈接!謝謝!
《從基本理解到深入探究Linux kernel 通知鏈(notifier chain)》:https://blog.csdn.net/u014134180/article/details/86563754
---------------------
作者:Wu_Being
來源:CSDN
原文:https://blog.csdn.net/u014134180/article/details/86563754
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!

從基本理解到深入探究 Linux kernel 通知鏈(notifier chain)【轉】