Linux驱动开发之文件系统

 

简介

Linux系统中采用的文件系统有很多种,以下是一些常用的文件系统:

  • ext4:是Linux系统中使用最广泛的文件系统,支持文件大小高达1EB(EB级别的文件系统尚未被广泛使用)。它支特数据日志和元数据日志,提供了更好的文 件系统稳定性。
  • XFS:是一种高性能的日志文件系统,适用于大容量文件系统和强烈的/○操作。它支特高速读取和写入,可以处理大量的小文件和大文件
  • Bts:是一种新的文件系统,支持快照、压缩、多设备、白动修复等功能。它是一个多用途的文件系统,可以适用于很多场景。
  • NTFS:是一种Windows系统中常用的文件系统,Linux系统中也可以读取和写入NTFS文件系统。但由于其专有技术,Linux系统不能直接使用NTFS文件系统。
  • FAT32:是一种简单的文件系统,适用于移动存储设备和其他低容量设备。它具有良好的兼容性,可以被大多数操作系统所支持。 总之,Linux系统支持多种不同的文件系统,用户可以根据自己的需求选择适合自己的文件系统。

目录结构

进入Linux根目录(即“/”,Linux文件系统的入口,也是处于最高一级的目录),运行“ls–l”命令,看到Linux包含以下目录。

  1. /bin 包含基本命令,如ls、cp、mkdir等,这个目录中的文件都是可执行的。
  2. /sbin 包含系统命令,如modprobe、hwclock、ifconfig等,大多是涉及系统管理的命令,这个目录中的文件都是可执行的。
  3. /dev 设备文件存储目录,应用程序通过对这些文件的读写和控制以访问实际的设备。
  4. /etc 系统配置文件的所在地,一些服务器的配置文件也在这里,如用户账号及密码配置文件。busybox的启动脚本也存放在该目录。
  5. /lib 系统库文件存放目录等。
  6. /mnt 这个目录一般是用于存放挂载储存设备的挂载目录,比如含有cdrom等目录。可以参看/etc/fstab的定义。有时我们可以让系统开机自动挂载文件系统,并把挂载点放在这里。
  7. /opt opt是“可选”的意思,有些软件包会被安装在这里。
  8. /proc 操作系统运行时,进程及内核信息(比如CPU、硬盘分区、内存信息等)存放在这里。/proc目录为伪文件系统proc的挂载目录,proc并不是真正的文件系统,它存在于内存之中。
  9. /tmp 用户运行程序的时候,有时会产生临时文件,/tmp用来存放临时文件。
  10. /usr 这个是系统存放程序的目录,比如用户命令、用户库等。
  11. /var var表示的是变化的意思,这个目录的内容经常变动,如/var的/var/log目录被用来存放系统日志。
  12. /sys Linux 2.6以后的内核所支持的sysfs文件系统被映射在此目录上。Linux设备驱动模型中的总线、驱动和设备都可以在sysfs文件系统中找到对应的节点。当内核检测到在系统中出现了新设备后,内核会在sysfs文件系统中为该新设备生成一项新的记录。

相互关系

Linux中虚拟文件系统、磁盘/Flash文件系统及一般的设备文件与设备驱动程序之间的关系如下: 关系

应用程序和VFS之间的接口是系统调用,而VFS与文件系统以及设备文件之间的接口是file_operations结构体成员函数,这个结构体包含对文件进行打开、关闭、读写、控制的一系列成员函数,关系如下图所示: 2 由于字符设备的上层没有类似于磁盘的ext2等文件系统,所以字符设备的file_operations成员函数就直接由设备驱动提供了。块设备有两种访问方法,一种方法是不通过文件系统直接访问裸设备,在Linux内核实现了统一的def_blk_fops这一file_operations,它的源代码位于fs/block_dev.c,所以当我们运行类似于“dd if=/dev/sdb1of=sdb1.img”的命令把整个/dev/sdb1裸分区复制到sdb1.img的时候,内核走的是def_blk_fops这个file_operations;另外一种方法是通过文件系统来访问块设备,file_operations的实现则位于文件系统内,文件系统会把针对文件的读写转换为针对块设备原始扇区的读写。ext2、fat、Btrfs等文件系统中会实现针对VFS的file_operations成员函数,设备驱动层将看不到file_operations的存在。 在设备驱动程序的设计中,一般而言,会关心file和inode这两个结构体。

file结构体

file结构体代表一个打开的文件,系统中每个打开的文件在内核空间都有一个关联的struct file。它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数。在文件的所有实例都关闭后,内核释放这个数据结构。在内核和驱动源代码中,struct file的指针通常被命名为file或filp(即file pointer)。代码清单5.3给出了文件结构体的定义。

struct file {
 union {
     struct llist_node    fu_llist;
     struct rcu_head      fu_rcuhead;
 } f_u;
 struct path              f_path;
#define f_dentry          f_path.dentry
 struct inode             *f_inode;      /* cached value */
 const struct file_operations*f_op;      /* 和文件关联的操作*/

 /*
  * Protects f_ep_links, f_flags.
  * Must not be taken from IRQ context.
  */
 spinlock_t          f_lock;
 atomic_long_t       f_count;
 unsigned int        f_flags;       /*文件标志,如O_RDONLY、O_NONBLOCK、O_SYNC*/
 fmode_t             f_mode;        /*文件读/写模式,FMODE_READ和FMODE_WRITE*/
 struct mutex        f_pos_lock;
 loff_t              f_pos;         /* 当前读写位置 */
 struct fown_struct  f_owner;
 const struct cred   *f_cred;
 struct file_ra_statef_ra;

u64                f_version;
#ifdef CONfiG_SECURITY
 void         *f_security;
#endif
 /* needed for tty driver, and maybe others */
 void         *private_data;        /*文件私有数据*/

#ifdef CONfiG_EPOLL
 /* Used by fs/eventpoll.c to link all the hooks to this file */
 struct list_head     f_ep_links;
 struct list_head     f_tfile_llink;
#endif                              /* #ifdef CONfiG_EPOLL */
 struct address_space*f_mapping;
} __attribute__((aligned(4)));      /* lest something weird decides that 2 is OK */

inode结构体

VFS inode包含文件访问权限、属主、组、大小、生成时间、访问时间、最后修改时间等信息。它是Linux管理文件系统的最基本单位,也是文件系统连接任何子目录、文件的桥梁,inode结构体的定义如代码清单5.4所示。

struct inode {
    ...
    umode_t i_mode;            /* inode的权限 */
    uid_t i_uid;               /* inode拥有者的id */
    gid_t i_gid;               /* inode所属的群组id */
    dev_t i_rdev;              /* 若是设备文件,此字段将记录设备的设备号 */
    loff_t i_size;             /* inode所代表的文件大小 */

    struct timespec i_atime;   /* inode最近一次的存取时间 */
    struct timespec i_mtime;   /* inode最近一次的修改时间 */
    struct timespec i_ctime;   /* inode的产生时间 */

    unsigned int        i_blkbits;
    blkcnt_t        i_blocks;  /* inode所使用的block数,一个block为512 字节 */
    union {
      struct pipe_inode_info  *i_pipe;
      struct block_device *i_bdev;
                               /* 若是块设备,为其对应的block_device结构体指针 */
      struct cdev *i_cdev;     /* 若是字符设备,为其对应的cdev结构体指针 */
    }
    ...
};

对于表示设备文件的inode结构,i_rdev字段包含设备编号。Linux内核设备编号分为主设备编号和次设备编号,前者为dev_t的高12位,后者为dev_t的低20位。下列操作用于从一个inode中获得主设备号和次设备号:

unsigned int iminor(struct inode *inode);
unsigned int imajor(struct inode *inode);

查看cat /proc/devices文件可以获知系统中注册的设备,第1列为主设备号,第2列为设备名,如:

/ # cat /proc/devices
Character devices:
  1 mem
  4 /dev/vc/0
  4 tty
  5 /dev/tty
  5 /dev/console
  5 /dev/ptmx
  7 vcs
 10 misc
 13 input
 29 fb
 81 video4linux
 89 i2c
 90 mtd
116 alsa
128 ptm
136 pts
180 usb
189 usb_device
207 ttymxc
226 drm
250 ttyLP
251 watchdog
252 ptp
253 pps
254 rtc

Block devices:
  1 ramdisk
259 blkext
  7 loop
  8 sd
 31 mtdblock
179 mmc

查看/dev目录可以获知系统中包含的设备文件,日期的前两列给出了对应设备的主设备号和次设备号:

/ # ls /dev/ -al
total 4
crw-rw----    1 0        0          10, 235 Jan  1  1970 autofs
crw-rw----    1 0        0           5,   1 Aug  5 04:31 console
crw-rw----    1 0        0          10,  62 Jan  1  1970 cpu_dma_latency

主设备号是与驱动对应的概念,同一类设备一般使用相同的主设备号,不同类的设备一般使用不同的主设备号(但是也不排除在同一主设备号下包含有一定差异的设备)。因为同一驱动可支持多个同类设备,因此用次设备号来描述使用该驱动的设备的序号,序号一般从0开始。 内核Documents目录下的devices.txt文件描述了Linux设备号的分配情况,它由LANANA(the Linux Assigned Names and Numbers authority,网址为http://www.lanana.org/)组织维护,Torben Mathiasen(device@lanana.org)是其中的主要维护者。