从基本理解到深入探究 Linux kernel 通知链(notifier chain)

基本理解Linux 内核事件通知链

内核事件通知链一个比较典型的例子就是Display 背光通知TP suspend和resume 的过程,我们这里先从的LCD 背光通知TP suspend 入场,以快速理解Linux 内核事件通知链应用。

1. TP 驱动相关代码

kernel-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-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


[32m[ 1045.412245] [33mPM[0m: suspend entry 2019-01-13 19:15:43.130364966 UTC // linux kernel 进入休眠
// 退出休眠与进入休眠的UTC时间戳一差,就是kernel 休眠的时间(19:15:55 - 19:15:43)
// 按电源键唤醒系统亮屏 ... ...
[32m[ 1050.799717] [33mPM[0m: suspend exit 2019-01-13 19:15:55.594697461 UTC // linux kernel 退出休眠
[32m[ 1051.144198] [0m[xxx][WU] event = 16, FB_EVENT_BLANK = 9	// 背光发送两次event,一次是16一次是9
[32m[ 1051.144211] [0m[xxx][WU] event = 9, FB_EVENT_BLANK = 9
[32m[ 1051.144221] [0m[xxx][WU] blank = 0 						// 其中参数的blank 为0 调用TP resume
[32m[ 1051.144232] [0m[xxx][WU] xxx_ts_resume FB_BLANK_UNBLANK = 0
[32m[ 1051.144233] [33m[xxx]xxx_ts_resume[0m: Enter
[32m[ 1051.146266] [33m[xxx]xxx_ts_resume[0m: Exit(1668)
// 亮屏了10s后,按电源键灭屏 ... ...
[32m[ 1061.519665] [0m[xxx][WU] event = 16, FB_EVENT_BLANK = 9	// 背光发送两次event,一次是16一次是9
[32m[ 1061.519680] [0m[xxx][WU] event = 9, FB_EVENT_BLANK = 9
[32m[ 1061.519690] [0m[xxx][WU] blank = 4 						// 其中参数的blank 为4 调用TP suspend
[32m[ 1061.519702] [0m[xxx][WU] xxx_ts_suspend FB_BLANK_POWERDOWN = 4
[32m[ 1061.519703] [33m[xxx]xxx_ts_suspend[0m: Enter
[32m[ 1061.523594] [33m[xxx]xxx_ts_suspend[0m: Exit(1609)
[32m[ 1061.528000] [33m mdss_dsi_panel_power_off 					// 然后display 下电
[32m[ 1061.529240] [33mhbtp[31m: hbtp->input_dev not ready!
[32m[ 1061.532073] [33mPM[0m: suspend entry 2019-01-13 19:16:06.327045373 UTC
...
[32m[ 1061.649485] [33mPM[0m: suspend exit 2019-01-13 19:16:06.444469957 UTC
[32m[ 1061.853378] [33mPM[0m: suspend entry 2019-01-13 19:16:06.648349227 UTC
[32m[ 1061.853419] [33mPM[0m: Syncing filesystems ... done.
[32m[ 1061.888011] [33mPM[0m: Preparing system for sleep (mem)
[32m[ 1061.888187] [0mFreezing user space processes ... (elapsed 3.964 seconds) done.
[32m[ 1065.852448] [0mFreezing remaining freezable tasks ... (elapsed 0.009 seconds) done.
[32m[ 1065.861693] [33mPM[0m: Suspending system (mem)
[32m[ 1065.861723] [0mSuspending console(s) (use no_console_suspend to debug)
// 因为TP已经休眠了, 上面 fb_set_suspend 函数也发来fb set supend 事件,不过这次已经无效了
[32m[ 1065.895347] [0m[xxx][WU] event = 2, FB_EVENT_BLANK = 9, FB_EVENT_SUSPEND = 2 // fb_set_suspend
[32m[ 1065.933676] [0m[xxx][WU] event = 2, FB_EVENT_BLANK = 9, FB_EVENT_SUSPEND = 2 // fb_set_suspend
[32m[ 1066.742596] [33mPM[0m: 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 <adaplas@pol.net>
 *
 *	2001 - Documented with DocBook
 *	- Brad Douglas <brad@neruo.com>
 *
 * 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的数据结构组织方式如下:
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.运行结果
wucb0122@wucb0122-ubuntu14:~/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

wucb0122@wucb0122-ubuntu14:~/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'

wucb0122@wucb0122-ubuntu14:~/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

wucb0122@wucb0122-ubuntu14:~/Codes/notifier_chain/raw-notifer-chain$ sudo insmod raw-chain-notifier.ko 
[sudo] password for wucb0122: 
wucb0122@wucb0122-ubuntu14:~/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

wucb0122@wucb0122-ubuntu14:~/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'

wucb0122@wucb0122-ubuntu14:~/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

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

Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢!
《从基本理解到深入探究Linux kernel 通知链(notifier chain)》:https://blog.csdn.net/u014134180/article/details/86563754

  • 19
    点赞
  • 86
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值