Linux驱动_热插拔_挂载U盘和TF卡

提示:Linux 下实现U盘和TF卡挂载


前言

最近学习的模块是Linux 驱动下的热插拔技术知识点,讨论的知识点具体包括:

  • 内核如何发送事件到用户空间
  • uevent 事件
  • kset_uevent_ops 结构体
  • netlink 监听广播知识点
  • uevent_helper 机制 【暂未讲解,网上很多资料说明】

那么实际热插拔在驱动上面怎么应用的呢? 基本上这里要将的首先是知识点 udev/mdev 是具体的应用知识点,然后实际举例说明 如何配置驱动的。
其实系统基于热插拔技术已经很完善了,写好了的。但是还是需要工程师配置规则,配置实现方式的。

参考资料

驱动-热插拔-内核发送事件到用户空间-uevent
驱动-热插拔-kset_uevent_ops知识点
驱动-热插拔-Netlink广播监听内核状态

热插拔

一、 udev mdev 知识点

udev - 现代 Linux 系统的标准

udevUserspace /dev的缩写。它是当前绝大多数桌面、服务器和移动版 Linux 发行版(如 Ubuntu, Fedora, Debian, Android等)的标准设备管理器。

核心特点

  • 运行在用户空间(Userspace):与它的前任(devfs,运行在内核空间)不同,udev 是一个用户空间的守护进程(systemd-udevd)。这使得它更加灵活和稳定,不会因为一个错误导致内核崩溃。

  • 与内核通过 netlink 通信udev 监听内核通过 netlink 套接字发出的 uevent 事件。每当内核检测到一个设备被加入(如插入U盘)或移除时,它会向用户空间广播一个 uevent,udev 接收到后就会执行相应的规则。

  • 基于规则的强大灵活性udev 的核心是它的规则文件(通常位于 /etc/udev/rules.d//lib/udev/rules.d/)。这些规则允许管理员:

1、动态创建设备节点:决定设备节点的名称(如永远将某个特定的U盘命名为 /dev/my_backup_disk)、权限和所有者。

2、自动加载内核模块:当设备插入时,自动加载所需的驱动模块。

3、触发自定义脚本:设备插入时自动挂载文件系统、启动某个程序,或者发送通知。
  • 依赖 systemd(在现代系统中):虽然早期 udev 可以独立运行,但现在它已是 systemd 项目的一部分,并由systemd-udevd服务管理,与整个系统初始化过程深度集成。

工作流程简述

  • 内核检测到硬件变化(新增或移除)。

  • 内核发送一个 uevent 到用户空间。

  • systemd-udevd 守护进程接收到该事件。

  • udev 根据规则文件(rules.d)中的规则匹配事件信息(如设备类型、厂商ID、产品ID等)。

  • 根据匹配的规则,udev /dev 下创建或删除设备节点,并可能执行其他操作(如运行脚本、设置权限等)。

mdev - 嵌入式系统的轻量级选择

mdev mini-udev 的缩写,它是 BusyBox 工具集提供的一个精简版的设备管理工具。BusyBox 被称为“嵌入式 Linux 的瑞士军刀”,它将许多常用 Unix 工具打包成一个单一的可执行文件。

核心特点

  • 极度轻量级mdev 的设计目标是体积小、依赖少、资源占用低,非常适合资源受限的嵌入式系统或极简环境。

  • 也运行在用户空间:和 udev 一样,它也是用户空间程序。

  • 配置简单:它的配置通常只有一个文件:/etc/mdev.conf。这个文件的语法比 udev 的规则简单得多,主要用于设置设备节点的权限、所有者和偶尔执行简单的命令。

  • 需要内核支持 uevent_helpermdev 的工作方式与 udev 不同。它依赖于内核的uevent_helper机制。当内核发生 uevent 时,如果 /sys/kernel/uevent_helper 文件被设置了(例如设置为 /sbin/mdev),内核就会直接执行这个 helper 程序(即 mdev),并将事件细节作为环境变量传递给它。这是一种更简单但效率较低的方式。

工作流程简述

  • 系统启动时,初始化脚本(通常是 /etc/init.d/rcS)会执行以下两行关键命令:
echo /sbin/mdev > /proc/sys/kernel/hotplug  # 设置热插拔助手程序为 mdev
mdev -s                                      # 在启动时扫描 /sys 并初始化 /dev 目录
  • 内核检测到热插拔事件。

  • 内核查看 hotplug 设置,发现是 /sbin/mdev

  • 内核直接调用/sbin/mdev程序来处理这个事件。

  • mdev 根据 /etc/mdev.conf 中的配置,创建或删除 /dev 下的设备节点。

udev/mdev 对比总结

特性udevmdev
全称Userspace /devmini-udev
来源systemd 项目BusyBox 工具集
体积/资源较大,功能完整极小,非常轻量
应用场景桌面、服务器、移动设备等现代通用 Linux 系统资源紧张的嵌入式系统、Initramfs 早期用户空间
配置方式复杂的规则文件(/etc/udev/rules.d/*.rules)简单的配置文件(/etc/mdev.conf)
通信机制通过 netlink 套接字主动监听内核事件通过内核的 uevent_helper 机制被内核调用
功能极其强大(动态节点、模块加载、触发脚本等)基础(创建节点、设置权限)
依赖依赖 systemd 和较完整的用户空间环境只依赖 BusyBox,几乎可在任何环境运行

二、使用udev 挂载U盘和TF卡

配置buildroot文件系统支持udev

    我们编写了一个名为 mdev 的应用程序, 用来处理 uevent 事件, 而实际上 udevmdev 的可执行程序都是很复杂的, 也并不需要我们自己来写, 只需要在构建 buildroot 文件系统时勾选对应的选项即可。 首先来到 buildroot 的源码目录下。

在这里插入图片描述

然后使用以下命令加载 rk3568 的默认配置文件并进入到图形化配置界面

make rockchip_rk3568_defconfig
make menuconfig

在这里插入图片描述

最终实现如下效果配置:
在这里插入图片描述

最终烧写固件镜像,查看是否已经启动了udev: 命令如下

ps -aux | grep -nR udev

在这里插入图片描述
检查到/sbin/udevd 进程就表示当前系统使用的是 udev, 至此配置 buildroot 文件系统支持udev 就完成了

使用 udev 挂载U盘和TF步骤

先总结 给出 挂载的步骤,从大方向上面先了解一下步骤。

udev挂载U盘步骤

步骤编号主要步骤关键内容/命令示例简要说明
1了解基础udev 规则,sysfsudev 运行在用户空间,监听内核事件,并根据规则响应。
2创建 udev 规则文件ACTION==“add”, KERNEL==“sd[b-z]?*”, … 在 /etc/udev/rules.d/ 目录下创建 .rules 文件定义规则。
3编写挂载/卸载脚本mount -t vfat /dev/$1 /mnt/usb脚本需可执行,负责挂载(创建目录)和卸载(卸载并删除目录)操作。
4设置脚本权限chmod +x /path/to/your/script.sh确保 udev 能够执行你编写的脚本。
5重载 udev 规则sudo udevadm control --reload-rules使新的规则文件生效23。
6调试与测试udevadm monitor --property插入和拔出U盘,使用 mount, lsblk 检查挂载情况。

udev挂载TF步骤

步骤编号核心步骤关键内容/命令示例要点说明
1识别设备属性udevadm monitor --property插入TF卡,观察其属性,找到 SUBSYSTEM 和 KERNEL 等关键标识。
2创建 udev 规则文件ACTION==“add”, SUBSYSTEM==“block”, …在 /etc/udev/rules.d/ 下创建 .rules 文件,编写匹配TF卡的规则。
3编写挂载/卸载脚本mount /dev/$1 /mnt/tfcard脚本需可执行,负责安全地挂载(创建目录)和卸载(卸载并删除目录)。
4设置脚本权限chmod +x /path/to/script.sh确保 udev 有权限执行你的脚本。
5重载并测试规则sudo udevadm control --reload-rules重新加载规则并触发事件进行测试。
6调试与验证journalctl -f 或 tail -f /var/log/syslog查看系统日志,使用 lsblk 或 mount 命令验证挂载是否成功。

使用udev 挂载U盘

这里举例,简单实操,实际这些步骤都是写在系统里面提前配置好的。

创建 udev 规则文件

udev 规则文件通常存放在 /etc/udev/rules.d/ 目录下,文件通常以数字开头(如 99-usb-mount.rules),数字越小优先级越高。

比如我们创建一个 001.rules 文件,内容如下:

KERNEL=="sd[a-z][0-9]", SUBSYSTEM=="block", ACTION=="add", RUN+="/etc/udev/rules.d/usb/usb-add.sh %k"
SUBSYSTEM=="block", ACTION=="remove", RUN+="/etc/udev/rules.d/usb/usb-remove.sh"

  • ACTION=="add": 表示设备添加事件。

  • KERNEL=="sd[a-z][0-9]*": 匹配设备名称,如 sda1, sdb1 等。

  • SUBSYSTEMS=="block": 确认设备属于USB子系统。

  • RUN+="...": 指定要执行的脚本,%k 是内核提供的设备名(如 sda1)。

  • 规则文件命名时,数字越小优先级越高。更详细的匹配键(如 ENV{ID_FS_TYPE}=="vfat" 匹配文件系统类型)可以让规则更精确
    在这里插入图片描述

编写挂载/卸载脚本

上面规则001.rules 文件里面已经配置了 不同action 下的路径,那么我们在对应的文件夹下创建执行文件并编写脚本即可

[root@topeet:/etc/udev/rules.d]# cd usb
[root@topeet:/etc/udev/rules.d/usb]# ls -l
total 8
----rwxrwx 1 root root 42 Aug 27 11:32 usb-add.sh
----rwxrwx 1 root root 35 Aug 27 11:32 usb-remove.sh
[root@topeet:/etc/udev/rules.d/usb]#
[root@topeet:/etc/udev/rules.d/usb]#
[root@topeet:/etc/udev/rules.d/usb]# cat usb-add.sh
#!/bin/sh
/bin/mount -t vfat /dev/$1 /mnt
[root@topeet:/etc/udev/rules.d/usb]#
[root@topeet:/etc/udev/rules.d/usb]#
[root@topeet:/etc/udev/rules.d/usb]# cat usb-remove.sh
#!/bin/sh
sync
/bin/umount -l /mnt
[root@topeet:/etc/udev/rules.d/usb]#
[root@topeet:/etc/udev/rules.d/usb]#

具体来说, usb-add.sh 脚本和 usb-remove.sh 脚本如下:

#!/bin/sh
/bin/mount -t vfat /dev/$1 /mnt/

#!/bin/sh
sync
/bin/umount -l /mnt/


设置脚本权限

我们是自己调试,拿着机器直接输入命令:在 /etc/udev/rules.d/usb 目录下:

chmod 777 *

如下结果:
在这里插入图片描述

重载 udev 规则并触发新规则

让新规则生效:

sudo udevadm control --reload-rules  # 重新加载规则文件
sudo udevadm trigger                 # 可选:重新触发所有设备事件,立即测试规则

或者直接重启机器即可

插拔U盘,看实际结果

在这里插入图片描述

使用udev 挂载TF卡

TF 卡挂载到/mnt 目录下, 在不做任何修改的情况下, 直接插入TF卡, 会发现 TF 卡直接挂载到了/mnt/sdcard 目录,如下:
在这里插入图片描述

这是因为在/lib/udev/rules.d 目录下已经帮我们添加了很多的 udev 规则, 如下图所示

在这里插入图片描述

这里的规则文件跟我们上一小节自己创建的规则文件所实现的作用是相同的, 只是 /etc/udev/rules.d/目录的规则文件比/lib/udev/rules.d 目录的规则文件优先级高。
所以要实现 TF 卡自动挂载到/mnt 命令让就需要进入到 /etc/udev/rules.d/目录下, 这次我们创建一个名为 002.rules 的文件
在这里插入图片描述

创建 udev 规则文件 002.rules

KERNEL=="mmcblk[0-9]p[0-9]", SUBSYSTEM=="block", ACTION=="add", RUN+="/etc/udev/rules.d/tf/tf-add.sh %k"
SUBSYSTEM=="block", ACTION=="remove", RUN+="/etc/udev/rules.d/tf/tf-remove.sh"

加载、卸载脚本 tf-add.sh 、tf-remove.sh

 
tf-add.sh

#!/bin/sh
/bin/mount -t vfat /dev/$1 /mnt


tf-remove.sh

#!/bin/sh
sync
/bin/umount -l /mnt





授权可执行脚本

进入脚本文件夹: /etc/udev/rules.d/tf 批量授权 chmod 777 * 结果如下

在这里插入图片描述

重载 udev 规则并触发新规则

让新规则生效:

sudo udevadm control --reload-rules  # 重新加载规则文件
sudo udevadm trigger                 # 可选:重新触发所有设备事件,立即测试规则

或者直接重启机器即可

插拔TF卡 验证结果

  • 拔出 TF 卡。
  • 重新插入 TF 卡。
  • 使用lsblk、mountdf -h命令检查 TF 卡是否已自动挂载到你指定的目录。
  • 使用 sudo tail -f /var/log/syslog journalctl -f 查看系统日志,检查是否有来自你的脚本的日志或任何错误信息。
    如下,看实际结果:

在这里插入图片描述

三、使用mdev 挂载U盘和TF卡

上面udev 挂载U盘和TF卡已经举例说明,这里其实就是方式不一样,更简单而已,也是基于配置来的。

mdev 环境搭建及验证

     对于环境配置,配置menuconfig 系统支持mdev 以及支持busybox 这里暂不讲解,可以自行查阅资料实现。

验证命令 ps -aux | grep -nR mdev

在这里插入图片描述

检查到/sbin/mdev 进程就表示当前系统使用的是 mdev, 至此配置 buildroot 文件系统支持mdev 就完成了。

mdev 挂载U盘

配置规则文件

mdev 使用/etc/mdev.conf 文件来配置 mdev 工具的规则和行为, 要想使用 mdev 自动挂载 U 盘需要向/etc/mdev.conf 文件中添加以下两条规则,

sd[a-z][0-9] 0:0 666 @/etc/mdev/usb_insert.sh
sd[a-z] 0:0 666 $/etc/mdev/usb_remove.sh

下面是对上述两个规则的详细介绍:

  • (1) sd[a-z][0-9] 是一个正则表达式模式, 用于匹配以"sd"开头, 后跟一个小写字母和一
    个数字的设备节点, 例如 /dev/sda1、 /dev/sdb2 等。
  • (2)0:0 666表示设置设备节点的所有者和权限。 0:0 表示所有者和所属组的用户 ID
    ID 均为 0, 即 root 用户。 666 表示权限为可读可写。
  • (3) @/etc/mdev/usb_insert.sh 表示当符合规则的设备插入时, mdev 会执行 /etc/mdev/u sb_insert.sh 脚本。 @ 符号表示执行的是一个 shell 命令。
  • (4)$/etc/mdev/usb_remove.sh表示当符合规则的设备移除时, mdev 会执行 /etc/mdev/ usb_remove.sh 脚本。 $ 符号表示执行的是一个内部命令。

默认的/etc/mdev.conf 本身就是有一些规则的,继续添加两条规则

在这里插入图片描述
如下:
在这里插入图片描述

加载和卸载脚本并配置到系统

规则添加完成之后就要去对应的目录下添加 usb_insert.sh usb_remove.sh 脚本文件了,
首先创建/etc/mdev目录并进入到该目录创建 usb_insert.sh usb_remove.sh 并授权
在这里插入图片描述
脚本如下:

usb_insert.sh 
#!/bin/sh

if [ -d /sys/block/*/$MDEV ]; then
    mount /dev/$MDEV /mnt
    sync
fi


usb_remove.sh

#!/bin/sh
sync
umount -l /mnt


查看实际验证结果

插入U盘之前和插入U盘之后,结果如下:
在这里插入图片描述

在这里插入图片描述

可以看到 U 盘 sda1 就成功挂载到了/mnt 目录,我们在拔出U盘 挂载的U盘就会消失 了。

mdev 挂载TF 卡

配置规则文件

我们实现了 U 盘的自动挂载, 而为了帮助同学们举一反三, 本小节要使用 mdev 实现 TF 卡的自动挂载,跟 U 盘自动挂载相同, TF 卡自动挂载也需要向/etc/mdev.conf 文件中添加以下两条类似的规则

mmcblk[0-9]p[0-9] 0:0 666 @/etc/mdev/tf_insert.sh
mmcblk[0-9] 0:0 666 $/etc/mdev/tf_remove.sh

每一行都是一个规则, 具有以下格式:

<设备节点正则表达式> <设备的所有者:设备的所属组> <设备的权限> <设备插入或移除时需要执行的命令>

下面是对上述两个规则的详细介绍:

  • (1) mmcblk[0-9]p[0-9] 是一个正则表达式模式, 用于匹配以 "mmcblk" 开头的 TF 卡块设
    备, 例如 /dev/mmcblk1p1 等。
  • (2)0:0 666表示设置设备节点的所有者和权限。 0:0 表示所有者和所属组的用户 ID
    ID均为 0, 即 root 用户。 666 表示权限为可读可写。
  • (3) @/etc/mdev/tf_insert.sh 表示当符合规则的设备插入时, mdev 会执行 /etc/mdev/tf_i nsert.sh 脚本。 @ 符号表示执行的是一个 shell 命令。
  • (4) $/etc/mdev/tf_remove.sh 表示当符合规则的设备移除时, mdev 会执行 /etc/mdev/tf_remove.sh 脚本。 $ 符号表示执行的是一个内部命令。

配置加载、卸载脚本

root@RK356X:/]# cd /etc/
[root@RK356X:/etc]# cd mdev/
[root@RK356X:/etc/mdev]# ls -l
total 16
-rw-r--r-- 1 root root 75 Aug 27 20:07 tf_insert.sh
-rw-r--r-- 1 root root 35 Aug 27 20:07 tf_remove.sh
-rwxrwxrwx 1 root root 84 Aug  2  2024 usb_insert.sh
-rwxrwxrwx 1 root root 31 Aug  2  2024 usb_remove.sh
[root@RK356X:/etc/mdev]# cat tf_insert.sh
#!/bin/sh
if [ -d /sys/block/*/$MDEV ]; then
mount /dev/$MDEV /mnt
sync
fi
[root@RK356X:/etc/mdev]# cat tf_remove.sh
#!/bin/sh
sync
/bin/umount -l /mnt
[root@RK356X:/etc/mdev]#

即如下:

tf_insert.sh
#!/bin/sh
if [ -d /sys/block/*/$MDEV ]; then
mount /dev/$MDEV /mnt
sync
fi


tf_remove.sh
#!/bin/sh
sync
/bin/umount -l /mnt

TF插拔验证

在这里插入图片描述

在这里插入图片描述

总结

  • 这里才是热插拔的一个实际案例,实际简单的案例
  • 搞清楚udev/mdev 这才是热插拔机制核心的应用机制
  • 通过实际案例udev/mdev 实现U盘和TF卡挂载卸载
  • 这里只是简单的规则,加载和卸载,实际应用中会有一定的比较全的机制 但核心思想就这些
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

野火少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值