问题反馈: 应用开发同事反馈同一个句柄,也就是同一个字符设备为何允许多个进程访问,能否修复?
分析思路:
Step1: 通过lsof查看具体有哪些进程在访问指定的字符设备节点
lsof 命令用于识别不同进程正在访问的文件,是故障排除和系统维护不可或缺的工具,与 netstat 和 fuser 命令类似

Step2: 确实存在当OPTSCDevice进程访问节点/dev/opt_idf2_dio后,
/opt test/idf2 dio demo 也都是同时可以open该节点/dev/opt_idf2_dio
那么如何实现呢?这种情况在Linux设备驱动开发中很常见
1. 为什么同一个句柄允许两个进程open控制?
设备驱动设计问题
// 典型的驱动open函数可能这样写:
static int mydev_open(struct inode *inode, struct file *filp)
{
// 没有检查设备是否已被其他进程打开
return 0; // 总是成功
}
根本原因:
-
缺少互斥检查:驱动没有跟踪设备是否已被打开
-
默认允许:Linux内核默认允许多个进程打开同一字符设备
-
设计需求:某些设备确实需要允许多进程访问(如串口、摄像头)
2. 解决方案
方案1:驱动层加锁(推荐)
在设备驱动中添加打开计数和互斥机制:
#include <linux/mutex.h>
static DEFINE_MUTEX(dev_lock);
static int dev_open_count = 0;
static int mydev_open(struct inode *inode, struct file *filp)
{
mutex_lock(&dev_lock);
if (dev_open_count > 0) {
mutex_unlock(&dev_lock);
return -EBUSY; // 设备忙,返回错误
}
dev_open_count++;
mutex_unlock(&dev_lock);
// 其他初始化代码
return 0;
}
static int mydev_release(struct inode *inode, struct file *filp)
{
mutex_lock(&dev_lock);
dev_open_count--;
mutex_unlock(&dev_lock);
return 0;
}
方案2:使用文件锁(应用层解决)
在应用层使用**flock() 或 fcntl()**:
#include <sys/file.h>
int fd = open("/dev/opt_idf2_dio", O_RDWR);
if (fd < 0) {
// 处理错误
}
// 尝试获取独占锁
if (flock(fd, LOCK_EX | LOCK_NB) == -1) {
if (errno == EWOULDBLOCK) {
printf("Device is already in use by another process\n");
close(fd);
exit(1);
}
}
// 使用设备...
flock(fd, LOCK_UN); // 释放锁
close(fd);
实际代码通过driver层来修复:
diff --git a/drivers/opt_idf2/opt-idf2-dio.c b/drivers/opt_idf2/opt-idf2-dio.c
index 2bd8fe60c48b..267e406afd61 100755
--- a/drivers/opt_idf2/opt-idf2-dio.c
+++ b/drivers/opt_idf2/opt-idf2-dio.c
@@ -139,6 +139,8 @@
#define LOG_INFO (1 << 3)
#define LOG_DEBUG (1 << 4)
+static int dev_open_count = 0;^M
+^M
//static unsigned int g_log_flg = LOG_ERROR | LOG_WARN | LOG_NOTICE | LOG_INFO | LOG_DEBUG;
static unsigned int g_log_flg = LOG_ERROR | LOG_WARN | LOG_NOTICE;
@@ -303,14 +305,15 @@ void opt_shutdown_fn(void)
{
// 同步文件系统(在工作队列中允许阻塞)
pr_info("[%s] Syncing filesystems and shutdown OS ...\n", __func__);
+ pr_info("[%s] Cansel shutdown OS just for battery test ...\n", __func__);^M
//opt_printk("[%s] Syncing filesystems and shutdown OS ...\n", __func__);
//kernel_sys_sync();
//kernel_sync(); // 正确的方法
- ksys_sync();
+ // ksys_sync();^M
/* 立即强制关机 - 适用于"shutdown -r now"场景 */
//kernel_power_off();
- rk8xx_battery_shutdown();
+ // rk8xx_battery_shutdown();^M
/* 如果希望更优雅的关机,可以使用:
* orderly_poweroff(true);
@@ -513,7 +516,13 @@ static int opt_idf2_dio_open(struct inode *inode, struct file *filp)
struct opt_idf2_dio_dev *dio_dev = container_of(inode->i_cdev, struct opt_idf2_dio_dev, cdev);
LOGD("+ %s\r\n",__FUNCTION__);
mutex_lock(&dio_dev->mutex_lock); //上锁
+ if (dev_open_count > 0) {^M
+ printk("[%s] failed, pls check it. \n", __func__);^M
+ mutex_unlock(&dio_dev->mutex_lock);^M
+ return -EBUSY; // 设备忙,返回错误^M
+ }^M
filp->private_data = dio_dev;
+ dev_open_count++;^M
mutex_unlock(&dio_dev->mutex_lock); //解锁
LOGD("- %s\r\n",__FUNCTION__);
return 0;
@@ -1085,8 +1094,12 @@ static long opt_idf2_dio_ioctl(struct file *filp, unsigned int cmd, unsigned lon
static int opt_idf2_dio_release(struct inode *inode, struct file *filp)
{
- // struct opt_idf2_dio_dev *dio_dev = container_of(inode->i_cdev, struct opt_idf2_dio_dev, cdev);
+ struct opt_idf2_dio_dev *dio_dev = container_of(inode->i_cdev, struct opt_idf2_dio_dev, cdev);^M
// LOGD("+ %s\r\n",__FUNCTION__);
+ printk("[%s] -------- \n", __func__);^M
+ mutex_lock(&dio_dev->mutex_lock); //上锁^M
+ dev_open_count--;^M
+ mutex_unlock(&dio_dev->mutex_lock); //解锁^M
return 0;
}
@@ -1229,7 +1242,7 @@ static int opt_idf2_dio_probe(struct platform_device *pdev)
int ret;
struct device *dev = &pdev->dev;
struct opt_idf2_dio_dev *dio_dev;
- printk(" idf2 opt_idf2_dio_probe!\n");
+ printk("hzs opt_idf2_dio_probe! version: v2.0.1 \n");^M
opt_printk("+ %s opt_printk idf2 dio probed+LIU driver ver:0.01\r\n",__FUNCTION__);
dio_dev = kzalloc(sizeof(*dio_dev), GFP_KERNEL);
if (NULL == dio_dev){
(END)
烧录kernel验证系统功能:

测试即可实现:
