linux驱动开发-文件系统与设备文件

2019-07-13 06:14发布

  目录 1.Linux文件系统操作 Linux文件创建,打开,关闭函数 Linux下文件读写函数 2.C库文件操作 3.Linux文件系统 3.1根目录结构 3.2.VFS VFS 虚拟文件系统基础概念 Linux文件系统与设备驱动关系: 设备驱动结构体:file,inode inode结构体 inode之atime,mtime,ctime file结构体 3.3 sysfs文件系统 3.4 udev规则文件

1.Linux文件系统操作

Linux文件创建,打开,关闭函数

#文件权限最终由mode&umask决定 int creat (const char *filename,mode_t mode); //文件创建 int umask(int newmask); //修改文件权限 int open (const char *filename,int flags); //文件打开 int open (const char *filename,int flags,mode_t mode); //文件打开 int close (int fd);//fd=open(......)//文件关闭函数 其中 flag可为以下一个或组合:(当flags含O_CREAT时,open函数相当于创建文件函数) mode为以下一个或组合: 当然mode也可以用数字表示,方法如下: 权限数字含义: 数字含义 1 2 4 0   执行权限 写权限 读权限 无权限 文件权限各位含义(10705为例): 位数 第一位 第二位 第三位 第四位 第五位 作用 设置用户ID 设置组ID 用户权限 组权限 其他人权限   1 0 7(1+2+4) 0 5(1+4)   设置 不设置 执行;读;写 无权限 读;执行  因此10705等价与S_IRWXU|S_IROTH|SIXOTH|S_ISUID 文件打开后,就要对文件进行读写

Linux下文件读写函数

int read(int fd,const void *buf,size_t length); int write(int fd,const void *buf,size_t length); 指定位置读写: nt lseek(int fd,offset_t offset,int whence); lseek()将文件读写指针相对whence移动offset个字节,函数返回文件指针相对头问价的偏移量 SEEK_SET 相对文件开头 SEEK_CUR 相对文件读写指针的当前位置 SEEK_END 相对文件末尾

2.C库文件操作

利用标准C语言库进行文件读写

3.Linux文件系统

3.1根目录结构

目录 应放置档案内容 /bin 系统有很多放置执行档的目录,但/bin用于存放基本命令,单用户模式下也能运行. /boot 主要放置开机会使用到的档案,包括Linux核心档案以及开机选单与开机所需设定档等等。Linux kernel常用的档名为:vmlinuz ,如果使用的是grub这个开机管理程式,则还会存在/boot/grub/这个目录。 /dev 设备文件存储目录,应用程序通过对此目录下文件读写和控制以访问实际设备 /etc 系统配置文件所在地,一些服务器的配置文件也在这里,如用户账户及密码配置文件 /home 这是系统预设的使用者家目录(home directory)。 在你新增一个一般使用者帐号时,预设的使用者家目录都会规范到这里来。 /lib 系统库文件存放目录,其下的/lib/modules/目录,放置核心相关的模组(驱动程式)。 /media media是媒体的英文,这个/media底下放置的就是可移除的装置。 包括软碟、光碟、DVD等等装置都暂时挂载于此 /mnt 挂载储存设备的目录 /opt 可选的意思,有些软件被安装在这里 /root 系统管理员(root)的家目录。 因此即使单用户模式下仅仅挂在根目录,也能访问root目录 /sbin Linux有非常多指令是用来设定系统环境的,这些指令只有root才能够利用来设定系统,其他使用者最多只能用来查询而已。放在/sbin底下的为开机过程中所需要的,里面包括了开机、修复、还原系统所需要的指令。至于某些伺服器软体程式,一般则放置到/usr/sbin/当中。至于本机自行安装的软体所产生的系统执行档(system binary),则放置到/usr/local/sbin/当中了。常见的指令包括:fdisk, fsck, ifconfig, init, mkfs等等。 /srv srv可以视为service的缩写,是一些网路服务启动之后,这些服务所需要取用的资料目录。 常见的服务例如WWW, FTP等等。 举例来说,WWW伺服器需要的网页资料就可以放置在/srv/www/里面。呵呵,看来平时我们编写的代码应该放到这里了。 /tmp 这是让一般使用者或者是正在执行的程序暂时放置档案的地方。这个目录是任何人都能够存取的,所以你需要定期的清理一下。当然,重要资料不可放置在此目录啊。 因为FHS甚至建议在开机时,应该要将/tmp下的资料都删除。 /proc 这个目录本身是一个虚拟文件系统(virtual filesystem),它存在于内存中。 操作系统运行时,进程以及内核信息(比如CPU,硬盘分区,内存信息等)存放在这里.他放置的资料都是在内存当中, /sys 2.6以后内核所支持的sysfs文件系统被映射在此处 /tmp 用户运行时产生的临时文件,/tmp用来用来存储临时文件 /usr 系统存放程序的目录,比如用户命令,用户库 /var 这个目录的内容经常变动,比如/var/log 存放系统日志

3.2.VFS

VFS 虚拟文件系统基础概念

        Linux 允许众多不同的文件系统共存,并支持跨文件系统的文件操作,这是因为有虚拟文件系统的存在。虚拟文件系统,即VFS(Virtual File System)是 Linux 内核中的一个软件抽象层。它通过一些数据结构及其方法向实际的文件系统如 ext2,vfat 提供接口机制。

Linux文件系统与设备驱动关系:

可以看到 字符设备上层没有类似ext2的文件系统,所以访问字符设备的file_operations成员函数直接由字符设备驱动提供 块设备访问方法有两种:
  • 不通过文件系统直接访问裸设备
  • 通过文件系统访问,file_operations的实现位于文件系统,文件系统把针对文件的读写,转换为针对块原始扇区的读写

设备驱动结构体:file,inode

Linux字符设备中的两个重要结构体(file、inode),含源代码 Linux inode理解

inode结构体

       文件储存在硬盘上,硬盘的最小存储单位叫做"扇区"(Sector)。每个扇区储存512字节(相当于0.5KB)操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个"块"(block)。这种由多个扇区组成的"块",是文件存取的最小单位。"块"的大小,最常见的是4KB,即连续八个 sector组成一个 block。        文件数据都储存在"块"中,那么很显然,我们还必须找到一个地方储存文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做inode,中文译名为"索引节点"。 inodo中包括的内容如下:(总之,除了文件名以外的所有文件信息,都存在inode之中。至于为什么没有文件名,下文会有详细解释。)
  1. 文件字节数
  2. 文件拥有者ID
  3. 文件的Group ID
  4. 文件的读写执行权限
  5. 文件的时间戳(ctime指inode上一次变动的时间,mtime指文件内容上一次变动的时间,atime指文件上一次打开的时间)
  6. 链接数,即有多少个文件名指向这个inode
  7. 文件数据block位置
用stat命令查看文件的inode信息,如下:

inode之atime,mtime,ctime

时间戳 解释 备注 Access (atime) 在终端上用cat、more 、less、grep、sed、 cp 、file 一个文件时,此文件的Access的时间记录都会被更新(空文件例外),纯粹的access是不会影响modify和change,但会受到modify行为的影响。 ls等命令访问后时间也更新 Modify (mtime) 当更改了一个文件的内容的时候,此文件的modify的时间记录会被更新。用ls -l看到的文件时间是最近一次modify的时间。modify的行为是三个行为中最有影响力的行为,它发生以后,会使文件的access记录与change记录也同时得到更新。对于目录也是如此。 更改数据后更新,但是拷贝,剪切等操作不会更新该时间 change (ctime) 对一个文件或者目录作mv、chown、chgrp操作后,它的Change时间记录被更新,change时间会受到modify行为的影响。用ls -lc看到的文件时间是最近一次change的时间。 拷贝等操作后更新,mtime,atime更新后,change也会更新

file结构体

        在设备驱动中,这也是个非常重要的数据结构,必须要注意一点,这里的file与用户空间程序中的FILE指针是不同的,用户空间FILE是定义在C库中,从来不会出现在内核中。而struct file,却是内核当中的数据结构,因此,它也不会出现在用户层程序中。        file结构体指示一个已经打开的文件(设备对应于设备文件),其实系统中的每个打开的文件在内核空间都有一个相应的struct file结构体,它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数,直至文件被关闭。如果文件被关闭,内核就会释放相应的数据结构。      在内核源码中,struct file要么表示为file,或者为filp(意指“file pointer”), 注意区分一点,file指的是struct file本身,而filp是指向这个结构体的指针。

3.3 sysfs文件系统

打开终端,在/sys目录下,用命令tree打印树形目录 可以发现/sys结构可以描述如下: 设备存储在/sys/devices目录下,而诸如总线(bus),类(class)下的设备,实际只是链接,最终 链接到/sysy/devices下的设备

3.4 udev规则文件

udev规则采用行为单位,每一行代表一个规则,每个规则分为一个或多个匹配部分和赋值部分. 匹配关键词包括: ACTION: 事件行为,例如:add remove KERNEL: 内核设备名,例如:sda,ttyUSB* DEVPATH: 设备的devpath路径, SUBSYSTEM: 设备的子系统名称,例如sda的子系统为block BUS: 设备在devpath中的总线名称,例如:USB DRIVER: 设备在devpath中的设备驱动名称,例如ide-cdrom SYSFS{filename} 设备的devpath路径下,设备的属性文件"filename"中的内容 ENV{key}: 环境变量。在一条规则中,可以设定最多五条环境变量的 匹配键。 PROGRAM: 调用外部命令。 RESULT: 外部命令 PROGRAM 的返回结果。 ATTR: ATTRS - 匹配设备的sysfs属性,或任何双亲设备的sysfs属性  ,例如:ATTR{size},ATTR{address} 注意: devpath:devpath是指一个设备在sysfs文件系统(/sys)下的相对路径,该路径包含了指定设备的属性文件。udev里的多数命令都是针对devpath操作的。例如:sda的devpath是/block/sda,sda2的devpath是/block/sda/sda2 udev的重要赋值键: NAME: 在 /dev下产生的设备文件名。只有第一次对某个设备的 NAME 的赋值行为生效,之后匹配的规则再对该设备的 NAME 赋值行为将被忽略。如果没有任何规则对设备的 NAME 赋值,udev 将使用内核设备名称来产生设备文件。 SYMLINK: 为 /dev/下的设备文件产生符号链接。由于 udev 只能为某个设备产生一个设备文件,所以为了不覆盖系统默认的 udev 规则所产生的文件,推荐使用符号链接。 OWNER, GROUP, MODE: 为设备设定权限。 udev 的值和可调用的替换操作符 Linux 用户可以随意地定制 udev 规则文件的值。例如:my_root_disk, my_printer。同时也可以引用下面的替换操作符:
$kernel, %k:设备的内核设备名称,例如:sda、cdrom。
$number, %n:设备的内核号码,例如:sda3 的内核号码是 3。
$devpath, %p:设备的 devpath路径。
$id, %b:设备在 devpath里的 ID 号。
$sysfs{file}, %s{file}:设备的 sysfs里 file 的内容。其实就是设备的属性值。
$env{key}, %E{key}:一个环境变量的值。
$major, %M:设备的 major 号。
$minor %m:设备的 minor 号。
$result, %c:PROGRAM 返回的结果。
$parent, %P:父设备的设备文件名。
$root, %r:udev_root的值,默认是 /dev/。
$tempnode, %N:临时设备名。
%%:符号 % 本身。
$$:符号 $ 本身。 例子:       添加串口线,根据芯片自动绑定对应串口别名,参考博客USB hub 多usb接口重映射:udev 规则