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 的相关文章

  • 在ubuntu中打开spyder

    我想在ubuntu中打开spyder Python IDE 通常我会在 shell 中编写 spyder 它会打开spyder IDE 现在 当我在shell中编写spyder时 它只是换行 什么也没有发生 类似于按 enter 我如何找回
  • bash 将输出重定向到文件,但结果不完整

    重定向命令输出的问题已经被问过很多次了 但是我有一个奇怪的行为 我使用的是 bash shell debian 版本 4 3 30 1 release 并尝试将输出重定向到文件 但并非所有内容都记录在文件中 我尝试运行的 bin 文件是 l
  • /sys/device/ 和 dmidecode 报告的不同 CPU 缓存大小

    我正在尝试获取系统中不同缓存级别的大小 我尝试了两种技术 a 使用 sys device 中的信息 这是输出 cat sys devices system cpu cpu0 cache index1 size 32K cat sys dev
  • 正则表达式删除块注释也删除 * 选择器

    我正在尝试使用 bash 从 css 文件中删除所有块注释 我有以下 sed 命令的正则表达式 sed r s w s w d 这可以很好地去除块注释 例如 This is a comment this is another comment
  • 为 Linux 编译 Objective-C 应用程序(API 覆盖范围)

    我可能在这里问一些奇怪的问题 但我不确定从哪里开始 问题是我正在考虑使用 Obj C 和 Foundation 类在 Mac 上编写一个命令行工具 但存在一个非常大的风险 那就是我希望能够为不同的 Linux 发行版编译它 以便将来作为服务
  • Ubuntu Python shebang 线不工作

    无法让 shebang 线在 Ubuntu 中为 python 脚本工作 我每次只收到命令未找到错误 test py usr bin env python print Ran which python usr bin python 在 sh
  • Linux 使用 boost asio 拒绝套接字绑定权限

    我在绑定套接字时遇到问题 并且以用户身份运行程序时权限被拒绝 这行代码会产生错误 acceptor new boost asio ip tcp acceptor io boost asio ip tcp endpoint boost asi
  • 为什么 fork 炸弹没有使 android 崩溃?

    这是最简单的叉子炸弹 我在许多 Linux 发行版上执行了它 但它们都崩溃了 但是当我在 android 终端中执行此操作时 即使授予后也没有效果超级用户权限 有什么解释为什么它没有使 Android 系统崩溃吗 一句话 ulimit Li
  • 如何才能将 TCP 连接返回到同一端口?

    机器是 RHEL 5 3 内核 2 6 18 有时我在 netstat 中注意到我的应用程序有连接 建立了 TCP 连接本地地址 and 国外地址是一样的 其他人也报告了同样的问题 症状与链接中描述的相同 客户端连接到本地运行的服务器的端口
  • 在内核代码中查找函数的最佳方法[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我开始浏览内核代码 遇到的一件事是如何跟踪函数调用 结构定义等 有没有一种好的方法可以快速跳转到函数定义并退出 我尝试过 Source N
  • Linux 中 m 标志和 o 标志将存储在哪里

    我想知道最近收到的路由器通告的 m 标志和 o 标志的值 从内核源代码中我知道存储了 m 标志和 o 标志 Remember the managed otherconf flags from most recently received R
  • 在 C 中使用单个消息队列是否可以实现双向通信

    我希望服务器向客户端发送一些消息 并让客户端确认它 我被分配了这个任务 我可以在 C linux 中使用单个消息队列来完成它还是我需要创建两个 谢谢 是的 可以使用 sysV 消息队列来做到这一点 从您之前的问题来看 您正在使用该队列 您可
  • docker 非 root 绑定安装权限,WITH --userns-remap

    all 尝试让绑定安装权限正常工作 我的目标是在容器中绑定安装卷 以便 a 容器不以 root 用户身份运行入口点 二 docker daemon 配置了 userns remap 这样容器 主机上没有 root c 我可以绑定挂载和读 写
  • 我们真的应该使用 Chef 来管理 sudoers 文件吗?

    这是我的问题 我担心如果 Chef 破坏了 sudoers 文件中的某些内容 可能是 Chef 用户错误地使用了说明书 那么服务器将完全无法访问 我讨厌我们完全失去客户的生产服务器 因为我们弄乱了 sudoers 文件并且无法再通过 ssh
  • 如何使用 Cloud Init 挂载未格式化的 EBS 卷

    Context 我正在使用https wiki jenkins io display JENKINS Amazon EC2 Plugin https wiki jenkins io display JENKINS Amazon EC2 Pl
  • 在centos中安装sqlite3 dev和其他包

    我正在尝试使用 cpanel 在 centos 机器上安装 sqlite dev 和其他库 以便能够编译应用程序 我对 debian 比 centos 更熟悉 我知道我需要的库是 libsqlite3 dev libkrb5 dev lib
  • 从 ttyUSB0 写入和读取,无法得到响应

    我对 Linux tty 不太有经验 我的环境是带有丰富 USB 串行的 Raspbian 什么有效 stty F dev ttyUSB0 38400 cu l dev ttyUSB0 s 38400 cu to dev ttyUSB0作品
  • 使用非规范地址检索内存数据会导致 SIGSEGV 而不是 SIGBUS

    我无法使用以下汇编代码产生 总线错误 这里我使用的内存地址不是合法的 规范地址 那么 我怎样才能触发该错误呢 我在带有 NASM 2 14 02 的 Ubuntu 20 04 LTS 下运行这段代码 但它会导致负载出现 SIGSEGV 分段
  • 如何根据标签将单个 XML 文件拆分为多个

    我有一个带有标签的 XML 文件 我想像这样分割文件
  • 如何获取 (Linux) 机器的 IP 地址?

    这个问题和之前问的几乎一样如何获取本地计算机的IP地址 https stackoverflow com questions 122208 get the ip address of local computer 问题 但是我需要找到一个的I

随机推荐

  • 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