Linux内核与设备管理:USB存储驱动usb_storage/uas的安全卸载与复原
Linux内核与设备管理:USB存储驱动usb_storage/uas的安全卸载与复原
Linux内核模块安全卸载与复原的十步法
摘要
在Linux系统中,想要安全地卸载并重新加载USB存储驱动,必须先解除文件系统与进程占用,再按依赖关系逆序卸载模块,最后按需恢复加载。本文给出可直接执行的一步一命令实操清单,采用“箭头注释”逐字符解释每条命令,覆盖usb_storage
与其依赖uas
的处理策略,并以真实场景举例说明判读与排错方法,附流程图与术语表以便系统性理解。
一、前置知识与名词解释
内核模块是可按需装载的功能单元,USB存储链路常由uas
与usb_storage
协作完成。为避免含糊,先统一术语。
名称 | 全称与缩写(首次出现按规范) | 简要说明 |
---|---|---|
通用串行总线(Universal Serial Bus, USB) | USB | 外设总线标准,常见于U盘、移动硬盘等 |
小型计算机系统接口(Small Computer System Interface, SCSI) | SCSI | 通用存储访问协议栈概念 |
USB附加SCSI(USB Attached SCSI, UAS) | UAS | 走SCSI命令集的USB高效传输协议,Linux内核以uas 模块实现 |
USB存储类驱动 | usb_storage | 传统USB大容量存储驱动,部分设备在无UAS时退回使用 |
动态可加载内核模块(Loadable Kernel Module, LKM) | LKM | 通过modprobe /lsmod 管理的内核功能单元 |
挂载点(Mountpoint) | — | 文件系统在目录树中的挂载位置 |
设备断电/解绑 | — | 通过udisksctl power-off 、eject 或/sys 写接口让内核不再使用设备 |
结论先行:处理顺序应为“解除占用→卸载依赖者uas
→卸载被依赖者usb_storage
→按需恢复加载。
二、环境假设与操作目标
你当前的机器状态(来自实际输出)说明如下:
lsmod | grep usb_storage
# 输出:usb_storage 66636 1 uas
lsblk -o NAME,TRAN,MOUNTPOINT
# 输出未见 TRAN=usb 且挂载点非空的分区
结论先行:usb_storage
已被uas
占用且没有USB分区挂载。目标是安全卸载uas
与usb_storage
,并在需要时恢复。
三、流程总览与关键路径
flowchart LRA[确认模块与占用\nlsmod|grep] --> B[确认挂载点\nlsblk -o ...]B --> C{有挂载?}C -- 是 --> D[umount 分区\nsync]C -- 否 --> E[检查进程占用\nfuser -vm]D --> F[设备断电/解绑\nudisksctl / eject / sysfs delete]E --> FF --> G[先卸载 uas\nmodprobe -r uas]G --> H[再卸载 usb_storage\nmodprobe -r usb_storage]H --> I{需要恢复?}I -- 是 --> J[modprobe usb_storage]I -- 否 --> K[保持卸载状态]
结论先行:无论是否挂载,卸载顺序始终是“先uas
后usb_storage
,否则会提示 in use。
四、一步一命令的标准清单(逐字符箭头注释)
说明在前:下面是通用“十步法”的完整清单,每条命令都可单独复制执行。若你的现场“没有挂载且
usb_storage
被uas
占用”,请优先看第五章“最短路径实操”。
一、1.1 查看模块加载情况与占用关系
在任何操作前,先确定模块与占用链路,避免盲目卸载。
lsmod | grep usb_storage
# └─┬─┘ └──┬──┘ └──────────┘
# lsmod | usb_storage:要查找的模块名
# └─ 管道,把 lsmod 的输出交给 grep
# 作用:查看 usb_storage 是否加载、Used by 是否被 uas 占用
一、1.2 列出块设备、传输方式与挂载点
用以判定是否需要先卸载文件系统。
lsblk -o NAME,TRAN,MOUNTPOINT
# └──┬──┘ └─┬─┘ └──────────┘
# 命令 -o 指定输出列
# NAME/TRAN/MOUNTPOINT:设备名/传输方式/挂载点
# 作用:定位 TRAN=usb 且 MOUNTPOINT 非空的分区
二、2.1 卸载文件系统分区(示例:/dev/sdb1)
若上一步发现已挂载,这一步必须先做。
sudo umount /dev/sdb1
# └──┬┘ └──┬──┘ └─────┘
# sudo umount 设备文件
# 以 root 权限卸载,使内核停止使用该分区
二、2.2 同步缓存,降低风险
在移除硬件或卸载模块前,确保缓冲写入磁盘。
sync
# 单词 sync:把内存中未写入磁盘的数据写回磁盘
二、2.3 检查并清理占用进程(可选但常用)
避免因进程占用导致umount
失败或模块 in use。
sudo fuser -vm /dev/sdb1
# └──┬┘ └──┬┘ └┬┘ └──────┘
# sudo fuser -v -m 目标(分区或挂载点)
# -v:verbose 详细输出
# -m:把参数当作挂载点处理
# 作用:查看有哪些进程仍在占用
若需要强制清理:
sudo fuser -km /dev/sdb1
# └──┬┘ └──┬┘ └┬┘ └──────┘
# sudo fuser -k -m 目标
# -k:kill 杀掉占用进程
# -m:挂载点语义
三、3.1 让设备断电或从内核解绑(三选一)
只需任选其一,目的都是让内核彻底不再使用该设备。
sudo udisksctl power-off -b /dev/sdb
# └──┬┘ └──────────────┬─────────┘ └──┬──┘
# sudo udisksctl power-off -b /dev/sdb
# 提权 工具名 断电动作 block设备 目标整盘
或:
sudo eject /dev/sdb
# └──┬┘ └──┬┘ └─────┘
# sudo eject 设备
# 作用:弹出/解绑该块设备
或(最底层方式):
echo 1 | sudo tee /sys/block/sdb/device/delete
# └─┬─┘ └──┬┘ └──┬──┘ └──────────────┘
# echo 1 管道 sudo tee 目标文件
# 把“1”写入 delete,通知内核删除 sdb 这个设备
四、4.1 再次确认占用关系(可选)
确认Used by
是否归零。
lsmod | grep usb_storage
# 作用:检查 usb_storage 是否仍被其它模块占用
四、4.2 卸载依赖者模块uas
必须先卸载占用者uas
,否则usb_storage
会 in use。
sudo modprobe -r uas
# └──┬──┘ └──────┬──────┘ └─┘
# sudo modprobe -r uas
# 提权 模块管理 remove 卸载模块 模块名:USB Attached SCSI
四、4.3 卸载usb_storage
此时不应再报 in use。
sudo modprobe -r usb_storage
# └──┬──┘ └──────┬──────┘ └──────────┘
# sudo modprobe -r usb_storage
# 提权 模块管理 卸载 模块名(USB存储驱动)
五、5.1 按需恢复加载usb_storage
如果你需要恢复USB存储功能,重新加载即可。
sudo modprobe usb_storage
# └──┬──┘ └──────┬──────┘ └──────────┘
# sudo modprobe usb_storage
# 提权 加载模块 模块名
五、5.2 验证加载成功
确认模块已回到内核。
lsmod | grep usb_storage
# 看到 usb_storage 再次出现在列表中即为成功
解释在后:上面的清单把“解除文件系统占用→解绑/断电→卸载依赖者uas
→卸载usb_storage
→按需恢复”拆成独立、互不合并的命令,任何一步失败都可针对性排查,不会把问题混在一起。
四、1.3 常用命令与作用速查表
命令 | 关键参数 | 作用 | 典型失败原因 | |
---|---|---|---|---|
lsmod | ` | grep 模块名` | 查看模块是否加载、被谁占用 | 无 |
lsblk | -o NAME,TRAN,MOUNTPOINT | 查设备传输方式与挂载点 | 无 | |
umount | 设备或挂载点 | 卸载文件系统 | 仍被进程占用 | |
fuser | -vm /-km | 查看或杀占用进程 | 执行环境无psmisc 包 | |
udisksctl | power-off -b /dev/sdX | 逻辑断电 | 桌面环境缺失时不可用 | |
eject | 设备名 | 解绑/弹出设备 | 设备忙 | |
tee | 写/sys/block/.../delete | 内核层删除设备 | 路径写错 | |
modprobe | -r 模块名 | 卸载模块 | 被依赖 in use | |
modprobe | 模块名 | 加载模块 | 设备不匹配 |
五、案例演示:当前状态下的“最短路径实操”
场景复述:usb_storage ... 1 uas
且没有USB分区挂载。结论先行:直接卸载uas
再卸载usb_storage
即可。
二、1.1 卸载占用者模块uas
sudo modprobe -r uas
# └──┬──┘ └──────┬──────┘ └─┘
# sudo modprobe -r uas
# 提权 模块管理 卸载 模块名
二、1.2 确认uas
已卸载
lsmod | grep uas
# 无输出则说明 uas 不在了
二、1.3 卸载usb_storage
sudo modprobe -r usb_storage
# └──┬──┘ └──────┬──────┘ └──────────┘
# sudo modprobe -r usb_storage
二、1.4 需要恢复时只加载usb_storage
sudo modprobe usb_storage
# └──┬──┘ └──────┬──────┘ └──────────┘
# 提权 加载模块 模块名
解释在后:该“最短路径”省略了卸载分区与断电步骤,因为你现场没有挂载点;若未来插入U盘自动挂载,务必先umount
后再做模块操作。
六、扩展与排错:自动加载、强制卸载与三种解绑方式差异
结论先行:不要用强制卸载rmmod -f
,更不要在生产环境里图快。
三、1.1 三种解绑方式对比
方法 | 层级 | 优点 | 注意点 |
---|---|---|---|
udisksctl power-off -b /dev/sdX | 桌面服务层 | 逻辑断电,温和安全 | 依赖udisks2 |
eject /dev/sdX | 工具层 | 简单直观 | 有时仅逻辑弹出,未必断电 |
echo 1 > /sys/block/sdX/device/delete | 内核/sysfs | 最底层,效果直接 | 必须确认路径准确,误删风险高 |
三、1.2 防止UAS自动加载(可选)
部分老U盘在UAS下表现不稳定,可临时禁用UAS回退到usb_storage
。
echo "blacklist uas" | sudo tee /etc/modprobe.d/disable-uas.conf
# └──┬──┘ └──────────┬──────────┘ └──────────────┘
# echo 文本 管道 sudo tee 目标配置文件
# 写入一行:blacklist uas,用于阻止内核自动加载 uas
更新initramfs(部分发行版需要):
sudo update-initramfs -u
# └──┬──┘ └──────────┬──┘
# sudo update-initramfs -u
# 以 root 权限更新 initramfs,使黑名单在早期启动生效
恢复UAS自动加载:
sudo rm /etc/modprobe.d/disable-uas.conf
# └──┬┘ └──────────┬──────────┘
# sudo rm 配置文件
# 删除黑名单文件,允许 uas 再次自动加载
三、1.3 常见报错与对策
modprobe: FATAL: Module usb_storage is in use
先卸载uas
或其它依赖者,再卸载usb_storage
。若仍失败,检查是否有挂载或进程占用。umount: target is busy
用fuser -vm
找出进程并fuser -km
清理,或确认是否在该目录中工作导致“自占用”。
七、结论或总结
安全地卸载并恢复USB存储驱动的关键在于“先解除占用,再按依赖逆序卸载,最后按需恢复加载”。在实务中,占用者通常是uas
,被占用者是usb_storage
,顺序错误将直接导致 in use。结合流程图、一步一命令与箭头注释,配合fuser
和lsblk
的判读,你可以在任何发行版上稳定复现该流程并快速定位问题根因。