Linux·设备文件devfs

2023-11-17

目录

设备文件系统

devfs

udev(mdev)

关于file和inode数据结构在内核中的探究


设备文件系统

Linux引入了虚拟文件系统,从而使设备的访问可以像访问普通文件系统一样。因此在内核中描述打开文件的数据inode中的rdev成员用来记录设备文件对应到的设备号。设备文件也由一个对应的file_operations 数据对象,用来描述设备的操作接口。设备文件系统最早是采用devfs实现的,但是后来因为种种原因在2.6以后的内核中已经将其废弃而转而使用udev,他来本质上是没有区别都是在设备添加到系统中时在/dev目录下产生设备文件(机制相同),但是不同的是策略devfs的策略是将设备文件的创建过程放在了内核空间,而udev的策略是由内核提供机制而用户空间提供策略从而完成设备的创建,所以现在设备文件管理由两个软件可用分别是PC平台上的udev和嵌入式平台上的mdev。


devfs

接口均已经废弃,不在详细探究。

devfs_handle_t devfs_mk_dir(devfs_handle_t dir,const char* name,void* info);
devfs_handle_t devfs_register(devfs_handle_t de,const char* name,unsigned int flag,uinsigned int major,unsigned int minor,umode_t mode,void* ops,void* info);
devfs_handle_t devfs_unregister(devfs_handle_t de);

udev(mdev)

与devfs不同udev完全工作在用户空间,而内核通过netlink机制将,设备添加过程的相关信息通过netlink发送到用户空间的udev程序,netlink机制可以不理解是一种特殊的socket进程通讯方式,用户空间的udev接收到设备添加的信息后将完成设备文件的创建和设备文件操作接口等相关的配置和初始化操作。进而用户空间程序就能像访问普通文件一样访问设备了。


关于file和inode数据结构在内核中的探究

比较好奇设备文件在被多个用户进程打开后后续fops操作接口的file和inode是同一个还是个进程单独一个,因为file中还由一个private_data成员在驱动编程中是比较重要的所以接下来进行专门的验证。
编写一个虚拟的设备驱动如下

#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <asm/io.h>

//file open operation function 
static int char_drv_open(struct inode *inode , struct file *filp)
{
	printk(KERN_EMERG "inode:%08x file:%08x\n",inode,filp);
  printk(KERN_EMERG "private_data:%08x\n",filp->private_data);
  printk(KERN_EMERG "inode:%08x\n",inode);
  filp->private_data = 0x5A5A5A5A;
	return 0;
}
//file read operation function
static int char_drv_read(struct file *filp , char __user *buf , size_t cnt , loff_t *offt)
{
	return 0;
}
//file write operation function
static int char_drv_write(struct file *filp,const char __user *buf , size_t cnt , loff_t *offt)
{
	return 0;
}
//file close operation function
static int char_drv_release(struct inode *inode , struct file *filp)
{
	return 0;
}

//file operation function struct
static struct file_operations my_test_fop=
{
	.owner = THIS_MODULE,
	.open  = char_drv_open,
	.release = char_drv_release 
	
};

/* 设备结构体 */
struct test_dev
{
	dev_t devid; /* 设备号 */
	struct cdev cdev; /* cdev */
	struct class *class; /* 类 */
	struct device *device; /* 设备 */
	int major; /* 主设备号 */
	int minor; /* 次设备号 */
};

#define NEWCHRLED_CNT 1 /* 设备号个数 */
#define NEWCHRLED_NAME "newchrdev" /* 名字 */

struct test_dev   test_char_dev;

//module init   function
static int __init char_drv_test_init(void)
{
	//same hardware init 
	
	//apply device num 
	alloc_chrdev_region(&test_char_dev.devid, 0, NEWCHRLED_CNT,NEWCHRLED_NAME);
	
	test_char_dev.major = MAJOR(test_char_dev.devid); /* 获取主设备号 */
	test_char_dev.minor = MINOR(test_char_dev.devid); /* 获取次设备号 */
	printk(KERN_EMERG "major:%d minor:%d\n",test_char_dev.major ,test_char_dev.minor);
 
	//init dev struct
	cdev_init(&test_char_dev.cdev,&my_test_fop);
	//add dev to system
	cdev_add(&test_char_dev.cdev ,test_char_dev.devid ,NEWCHRLED_CNT );
	
	//build class
	test_char_dev.class = class_create(THIS_MODULE,"test2");
	if (IS_ERR(test_char_dev.class)) 
	{
		return PTR_ERR(test_char_dev.class);
	}
	//build device
	test_char_dev.device = device_create(test_char_dev.class,NULL ,test_char_dev.devid,NULL,"test2");
	if (IS_ERR(test_char_dev.device)) 
	{
		return PTR_ERR(test_char_dev.device);
	}
	
	return 0;
}
//module uninstall   function
static void __exit char_drv_test_exit(void)
{
	/* 注销字符设备 */
	cdev_del(&test_char_dev.cdev);
  /* 删除 cdev */
	unregister_chrdev_region(test_char_dev.devid, NEWCHRLED_CNT);
	
	device_destroy(test_char_dev.class, test_char_dev.devid);
	
	class_destroy(test_char_dev.class);
}
//module function band
module_init(char_drv_test_init);
module_exit(char_drv_test_exit);

//license and author
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Smile");

CPP 折叠 复制 全屏

编写应用程序如下:

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(void)
{
	int fd = open("/dev/test2",O_RDWR);
	if(fd<0)
	{
		perror("open");
	}
	getc(stdin);
	return 0;
}		

结论
经过实验验证,设备文件每打开一次,内核都会在内核空间创建file对象而inode是指向同一数据块。具体输出如下:

//安装模块
[  466.459870] major:250 minor:0
//第一次执行
[  534.073202] inode:f437da00 file:f02cea80
[  534.073205] private_data:00000000
[  534.073207] inode:f437da00
//第二次执行
[  548.632708] inode:f437da00 file:f02bd000
[  548.632712] private_data:00000000
[  548.632713] inode:f437da00
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux·设备文件devfs 的相关文章

  • 对 sf:: 的未定义引用

    我想用 C 制作 GUI 应用程序 发现 SFML 是一个不错的选择 幸运的是 我使用的是 Linux 所以 SFML 2 4 已经安装在我的系统上 所以我开始搜索一些教程并找到了一个制作简单窗口的教程 但是当我运行代码时 出现错误 提示未
  • 测试linux下磁盘空间不足

    我有一个程序 当写入某个文件的磁盘空间不足时 该程序可能会死掉 我不确定是否是这种情况 我想运行它并查看 但我的测试服务器不会很快耗尽空间 有什么办法可以嘲笑这种行为吗 看起来没有任何方法可以在 Ubuntu 中设置文件夹 文件大小限制 并
  • 使用 sed 将 old-link-url 替换为 new-link-url

    我正在 bash 中编写一个脚本 将 old link url 替换为 new link url 我的问题是 sed 由于斜杠而无法替换 url 如果我只输入一些文字就可以了 my code sed e s old link new lin
  • 原生 Linux 应用程序可像 ResHacker 一样编辑 Win32 PE

    我想运行自动修改 dll服务 用户提交特定的 dll 我在服务器上修改它 然后用户可以下载 dll的修改版本 是否有任何本机 Linux 应用程序提供常见的 Win32 PE 修改功能 例如图标 字符串 加速器 对话等 至少提供命令行或脚本
  • 如何从“git log”中查看 Git 中的特定版本?

    My git log显示为 enter code here git trial git log commit 4c5bc66ae50780cf8dcaf032da98422aea6e2cf7 Author king lt email pro
  • grails 上的同步块在 Windows 上有效,但在 Linux 上无效

    我有一个 grails 应用程序 它依赖于服务中的同步块 当我在 Windows 上运行它时 同步按预期工作 但当我在 ams linux 上运行时 会出现 StaleObjectStateException 该问题在以下示例中重现 cla
  • 如何在 Linux x86_64 上模拟 iret

    我正在编写一个基于 Intel VT 的调试器 由于当 NMI Exiting 1 时 iret 指令在 vmx guest 中的性能发生了变化 所以我应该自己处理vmx主机中的NMI 否则 guest会出现nmi可重入错误 我查了英特尔手
  • sqlite 插入需要很长时间

    我正在将不到 200 000 行插入到 sqlite 数据库表中 我只是在终端中通过 sqlite3 使用一个非常简单的 sql 文件 我打赌它已经运行了至少 30 分钟 这是正常现象还是我应该关闭该过程并尝试不同的方法 sqlite中的插
  • 无关的库链接

    我有一个可能有点愚蠢的问题 因为我很确定我可能已经知道答案了 假设你有静态库A 动态共享库B和你的linux下的程序C 假设库 A 调用库 B 中的函数 并且您的程序调用库 A 中的函数 现在假设 C 在 A 中调用的所有函数都不使用 B
  • 是否从页面缓存中的脏页面进行文件读取?

    当字节写入文件时 内核不会立即将这些字节写入磁盘 而是将这些字节存储在页缓存中的脏页中 回写缓存 问题是 如果在脏页刷新到磁盘之前发出文件读取 则将从缓存中的脏页提供字节 还是首先将脏页刷新到磁盘 然后进行磁盘读取以提供字节 将它们存储在进
  • 具有少量父设备属性的 udev 规则

    我需要复杂且通用的udev规则来确定插入任何 USB 集线器的特定端口的 USB 设备 所以 我必须结合设备树不同层的父属性 我有这个 udevadm info query all name dev ttyUSB0 attribute wa
  • 如何从类似于 eclipse 的命令行创建可运行的 jar 文件

    我知道 eclipse 会生成一个可运行的 jar 文件 其中提取并包含在该 jar 文件中的所有库 jar 文件 从命令提示符手动创建 jar 文件时如何执行类似的操作 我需要将所有 lib jar 解压到类文件夹中吗 目前我正在使用 j
  • python:numpy 运行脚本两次

    当我将 numpy 导入到 python 脚本中时 该脚本会执行两次 有人可以告诉我如何阻止这种情况 因为我的脚本中的所有内容都需要两倍的时间 这是一个例子 usr bin python2 from numpy import print t
  • 套接字:监听积压并接受

    listen sock backlog 在我看来 参数backlog限制连接数量 这是我的测试代码 server initialize the sockaddr of server server sin family AF INET ser
  • 将数组传递给函数名称冲突

    Specs GNU bash 版本 3 1 17 无法升级 Premise 我一直在摆弄数组 我想知道是否有任何方法可以让函数的本地变量与所述函数外部的数组同名 Example 在下面的示例中 我将尝试显示该问题 Working bin b
  • numpy 未定义符号:PyFPE_jbuf

    我正在尝试使用一百万首歌曲数据集 为此我必须安装 python 表 numpy cython hdf5 numexpr 等 昨天我设法安装了我需要的所有内容 在使用 hdf5 遇到一些麻烦之后 我下载了预编译的二进制包并将它们保存在我的 b
  • gethostbyname() 或 getnameinfo() 如何在后台工作?

    How gethostbyname or getnameinfo 在后台工作 include
  • 如何使用AWK脚本检查表的所有列数据类型? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 在这里 我正在检查表中第一列的数据类型 但我想知道AWK中表的所有列数据类型 我尝试过 但只能获得一列数据类型 例如 Column 1
  • 伊迪德信息

    重新定义问题 有什么方法可以获取所连接显示器的序列号吗 我想收集显示器的Eid信息 当我使用 logverbose 选项运行 X 时 我可以从 xorg 0 log 文件中获取它 但问题是 如果我切换显示器 拔出当前显示器 然后插入另一个显
  • 无法安装 WWW::Curl::Easy: SZBALINT/WWW-Curl-4.17.tar.gz : make NO

    我正在尝试在我的 Fedora 26 机器上安装 WWW Curl Easy gcc c I usr include D REENTRANT D GNU SOURCE O2 g pipe Wall Werror format securit

随机推荐

  • IDEA远程调试

    1 概述 原理 本机和远程主机的两个 VM 之间使用 Debug 协议通过 Socket 通信 传递调试指令和调试信息 被调试程序的远程虚拟机 作为 Debug 服务端 监听 Debug 调试指令 jdwp是Java Debug Wire
  • 23062day4

    制作一个简易圆形时钟 头文件 ifndef WIDGET H define WIDGET H include
  • 大话水声通信技术---(BFSK仿真)

    在之前的理论篇中 笔者梳理了水声通信相关的理论知识体系 本次笔者给出了一套基于BFSK的水声通信系统 该系统已经在实际的硬件中得到了验证 通信声呐仿真BPSK方式 几点假设 1 基于射线声学理论 2 几何衰减按球面波传播衰减规律衰减 不考虑
  • python报错之paramiko.ssh_exception.SSHException: EOF during negotiation

    方案1 此方法引自https www cnblogs com lidq p 12030662 html 查找sftp server的位置 find name sftp server 然后查看ssh的配置文件 vim etc ssh sshd
  • matplotlib画二维分布图

    假设我们有一组二维数据 x y label 3 542485 1 977398 1 3 018896 2 556416 1 7 551510 1 580030 1 2 114999 0 004466 1 8 127113 1 274372
  • 51单片机—使用PWM对直流电机调速

    文章目录 什么是PWM PWM是怎么对直流电机进行调速的 通过定时器中断实现PWM调速 上代码 什么是PWM PWM 脉宽调制 是靠改变脉冲宽度来控制输出电压 通过改变周期来控制其输出频率 脉冲可以理解为是IO口的一次高低电平改变 PWM是
  • echarts坐标轴上的刻度竖着排列 并且超出隐藏

    首先 把坐标轴上的刻度竖着排列 大家第一反应肯定想到的是 echarts里的rotate属性 在xAxis里设置axisLabel rotate就搞定了 但是会发现这样垂直展示的话 可能不是很美观 所以就找到了格式器formatter 变成
  • docker构建部署node后端项目

    文章目录 简介 详细过程 1 将node项目打包成 tar 2 将node项目 tar打包成 tar gz 3 构建Dockerfile文件 4 执行命令打包镜像 简介 本次主要想记录一下docker部署node后端项目的过程 方便后面如果
  • CMU15-213 课程笔记 01-课程概览

    知识点 这门课的目的 深入理解当你执行代码时 计算机在做什么 LLDB 基于 LLVM 的命令行调试器 类似 GBD 内存引用 Bug typedef struct int a 2 double d struct t double fun
  • 如何确定一次完整的请求过程——服务链路跟踪

    微服务体系下 一个请求会调用多个服务 整个请求就会形成一个调用链 普通的日志输出是无法将整个体系串联起来 调用过程中某一个节点出现异常 定位排查难度系数增高 这种情况下就需要一个组件 来分析系统性能 展现调用链路 以便出现故障时快速定位并解
  • 【笔记整理】通信原理第四章复习——数字基带传输

    4 1 引言 数字基带信号 数字信号 补充 基带信号 指未经调制的信号 特征是其频谱从零频率或很低频率开始 占据较宽的频带 基带在传输前 必须经过一些处理或某些变换 比如码型变换 波形变换和频谱变换 才能送入信道中传输 处理或变换是为了使信
  • Django-rest-framework框架

    目录 一 Web应用模式 1 1 前后端不分离 二 API接口 三 接口测试工具 Postman 四 RESTful API规范 4 1 数据的安全保障 4 2 接口特征表现 4 3 多数据版本共存 4 4 数据即是资源 均使用名词 可复数
  • VHDL语言实现8位LED流水灯

    VHDL语言实现8位LED流水灯 包含对50MHz时钟信号分频产生1Hz信号 library ieee use ieee std logic 1164 all use ieee std logic unsigned all entity l
  • 1、mos管的工作原理

    文章目录 一 导体 绝缘体 半导体 二 半导体的制作 掺杂 pn结 半导体的单向导电性 三 mos管的工作原理 源极 栅极和漏极 nmos和pmos 电路符号 四 总结 一 导体 绝缘体 半导体 导体 能够导电的介质 绝缘体 不能导电的介质
  • 程序猿眼中的协议:TCP / IP 五层网络模型

    哈喽 大家好 我是你们的老朋友 保护小周 本期为大家带来的是 网络基础原理中的 TCP IP 五层网络模型 主要从协议的概念 网络模型 数据分层传输的流程 几个方面讲解 看完之后可以轻松的理解数据是如何在网络中传输的 确定不来看看嘛 更多精
  • List循环删除集合

    目录 For循环遍历List 增强For循环遍历List 迭代器iterator的remove方法 创建新的对象添加值 For循环遍历List 删除后list大小发生变化 因此索引发生变化 所以删除的元素不是你想要的 解决办法 倒着遍历li
  • qt学习笔记(五) QGraphicsPixmapItem与QGraphicsScene的编程实例 图标拖动渐变效果

    应大家的要求 还是把完整的工程文件贴出来 大家省点事 http www kuaipan cn file id 48923272389086450 htm 先看看运行效果 我用的群创7寸屏 主机是mini2440 分辨率是800 480 程序
  • 转】M1卡密钥破解,收藏

    M1卡说明及使用proxmark3破解方法 看了网上写的一些关于M1卡的文章 多数有些误导之嫌 首先谈谈M1卡的规格 M1卡的容量为1KB 好多网上写8KB 这里其实是有个误区 应该是8K位 1Byte 1B 8位 其实也就是说8k位想到于
  • Oracle数据库启动过程

    一 Oracle数据库的四种状态 Oracle数据库有四种状态 SHUTDOWN NOMOUNT MOUNT OPEN 二 Oracle数据库的启动过程详解 Oracle数据库启动主要包括三个过程 1 shutdown状态 数据库没有启动
  • Linux·设备文件devfs

    目录 设备文件系统 devfs udev mdev 关于file和inode数据结构在内核中的探究 设备文件系统 Linux引入了虚拟文件系统 从而使设备的访问可以像访问普通文件系统一样 因此在内核中描述打开文件的数据inode中的rdev