Linux内核notify通知笔录

前沿

本篇文章围绕三个问题来讲述,并解释案例代码演示,从而更进一步的了解该机制。

1.Notify机制是什么?

notify是一种内核子模块相互之间通信一种机制。如设备状态变化,电源事件等场景。另外它是一种通过事件驱动的通信机制,允许某个组建在特定事件发生时主动通知其他组件。内核中依据不同的上下文存在多种类型的形式,每种形式都有其特定的功能应用场景。

2.Notify实现原理?

该机制模式就好比发布订阅机制一样,发布者发布消息,订阅者订阅相关的数信息。当有事件发生时,通过通知链调用订阅者提前注册的数据机制,然后订阅者收到对应的消息处理。有中断触发方式,上下文触发方式。

3.Notify内核中如何使用?

发布消息:

cpp 复制代码
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>

// 定义全局通知链头
BLOCKING_NOTIFIER_HEAD(my_notifier_chain);
EXPORT_SYMBOL(my_notifier_chain);  // 确保正确导出

// 发送通知函数
int send_notification(unsigned long val, void *v)
{

    printk(KERN_INFO "MODULE A: Notifier chain head: %px\n", my_notifier_chain.head);
    if (my_notifier_chain.head == NULL) {
        printk(KERN_ERR "MODULE A: Notifier chain is empty!\n");
    }
    printk(KERN_INFO "MODULE A: Sending notification (val=%lu)\n", val);
    int ret = blocking_notifier_call_chain(&my_notifier_chain, val, v);
    printk(KERN_INFO "MODULE A: Notification result: %d\n", ret);
    return ret;
}
EXPORT_SYMBOL(send_notification);

// 添加设备文件操作以手动触发通知
static ssize_t trigger_write(struct file *filp, const char __user *buf, size_t count, loff_t *off)
{
    char msg[100];
    if (copy_from_user(msg, buf, count))
        return -EFAULT;
    msg[count] = '\0';
    
    send_notification(100, msg);
    return count;
}

static struct file_operations fops = {
    .write = trigger_write,
};

static int major;

static int __init module_a_init(void)
{
    major = register_chrdev(0, "notify_trigger", &fops);
    printk(KERN_INFO "MODULE A: Loaded (major=%d)\n", major);
    printk(KERN_INFO "MODULE A: Use 'echo \"message\" > /dev/notify_trigger' to test\n");
    return 0;
}

static void __exit module_a_exit(void)
{
    unregister_chrdev(major, "notify_trigger");
    printk(KERN_INFO "MODULE A: Unloaded\n");
}

module_init(module_a_init);
module_exit(module_a_exit);
MODULE_LICENSE("GPL");

订阅消息:

cpp 复制代码
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/kernel.h>

// 声明外部符号
extern struct blocking_notifier_head my_notifier_chain;

// 回调函数
static int my_notifier_call(struct notifier_block *nb, 
                          unsigned long val, void *v)
{
    printk(KERN_INFO "MODULE B: ===== NOTIFICATION RECEIVED =====\n");
    printk(KERN_INFO "MODULE B: Event value: %lu\n", val);
    printk(KERN_INFO "MODULE B: Message: %s\n", (char *)v);
    printk(KERN_INFO "MODULE B: ===== END NOTIFICATION =====\n");
    return NOTIFY_OK;
}

// 定义通知块
static struct notifier_block my_notifier = {
    .notifier_call = my_notifier_call,
    .priority = 0,
};

static int __init module_b_init(void)
{
    int ret;
    
    // 注册通知回调
    ret = blocking_notifier_chain_register(&my_notifier_chain, &my_notifier);
    
    if (ret) {
        printk(KERN_ERR "MODULE B: Registration failed: %d\n", ret);
        return ret;
    }
    
    printk(KERN_INFO "MODULE B: Successfully registered notifier\n");
    printk(KERN_INFO "MODULE B: Current notifier chain: %px\n", &my_notifier_chain);
    return 0;
}

static void __exit module_b_exit(void)
{
    blocking_notifier_chain_unregister(&my_notifier_chain, &my_notifier);
    printk(KERN_INFO "MODULE B: Unregistered notifier\n");
}

module_init(module_b_init);
module_exit(module_b_exit);
MODULE_LICENSE("GPL");
MODULE_SOFTDEP("pre: module_a");

Makefile:

cpp 复制代码
obj-m := module_a.o module_b.o

KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

all:
	$(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
	$(MAKE) -C $(KDIR) M=$(PWD) clean

按照先写入module_a之后在写入module_b,然后在系统/dev目录下创建设备,之后通过该对应的设备填充信息触发a模块调用通知链从而b模块收到对应的消息。如下输入日志:

cpp 复制代码
[36699.868674] module_a: loading out-of-tree module taints kernel.
[36699.869060] module_a: module verification failed: signature and/or required key missing - tainting kernel
[36699.871047] MODULE A: Loaded (major=242)
[36699.871048] MODULE A: Use 'echo "message" > /dev/notify_trigger' to test
[36705.974380] MODULE B: Successfully registered notifier
[36705.974381] MODULE B: Current notifier chain: ffffffffc09300e0
[36763.437614] MODULE A: Notifier chain head: ffffffffc094d000
[36763.437616] MODULE A: Sending notification (val=100)
[36763.437617] MODULE B: ===== NOTIFICATION RECEIVED =====
[36763.437617] MODULE B: Event value: 100
[36763.437618] MODULE B: Message: Hello World

[36763.437618] MODULE B: ===== END NOTIFICATION =====
[36763.437619] MODULE A: Notification result: 1

以上就是notify学习笔记,后续还会更新内核源代码详细实现过程!

相关推荐
辞旧 lekkk3 小时前
【Qt】信号和槽
linux·开发语言·数据库·qt·学习·mysql·萌新
腾讯蓝鲸智云3 小时前
【运维自动化-节点管理】节点管理的插件策略如何使用
运维·自动化·云计算·sass·paas
疯狂成瘾者5 小时前
服务器的单体和集群
运维·服务器
liuhuizuikeai6 小时前
可视化门禁---Linux/Qt+SqLite篇
linux·运维·qt
初願致夕霞6 小时前
基于系统调用的Linux网络编程——UDP与TCP
linux·网络·c++·tcp/ip·udp
charlie1145141919 小时前
嵌入式Linux驱动开发——新 API 字符设备驱动完整教程 - 从设备结构体到应用测试
linux·运维·驱动开发
飞Link9 小时前
2000 亿砸向算力:字节跳动 AI 基建跨越,后端与运维的“万亿 Token”生死战
运维·人工智能
消失的旧时光-19439 小时前
C语言对象模型系列(四)《Linux 内核里的 container_of 到底是什么黑魔法?》—— 一篇讲透 Linux 内核的“对象模型”核心技巧
linux·c语言·算法
SWAGGY..10 小时前
Linux系统编程:(二)基础指令详解
linux·运维·服务器
kdxiaojie10 小时前
U-Boot分析【学习笔记】(3)
linux·笔记·学习