文件系统目录
随着linux内核的发展,其文件系统也在不断更新。下面我们看下我电脑目前使用的linux文件系统中根目录下的文件排布:
从上面我们可以看到当前的内核版本为4.15的该版本下的文件系统根目录下有很多文件。那么这些文件有哪些作用呢?我们来分析一下某些文件。
bin文件夹
这个文件夹包含基本命令,像ls、mkdir、cp等基本命令,都具有可执行属性。
sbin文件夹
这个文件夹包含了系统管理的命令,像modprobe、ifconfig等,都具有可执行属性。
dev文件夹
这个文件夹是设备文件的存储目录,应用程序通过对这些文件的读写和控制以访问实际的设备。
lib文件夹
这个文件夹存放的大都是系统的库文件。
mnt文件夹
这个文件夹一般用于存放挂载存储设备的挂载目录。
opt文件夹
这个文件夹是可选的意思,一般用户软件安装的位置就在这里。
proc文件夹
这个文件夹下是一个虚拟的文件系统。为什么说它是虚拟的?就是因为它的文件夹和文件不是存放在磁盘上的,是一直存放在内存中的,当内核结束时,该文件夹下的东西自动消失。这个虚拟文件系统记录了啥东西呢?它记录了操作系统运行时的进程及内核信息。我们可以通过访问这个文件夹知道此时操作系统发生了什么。
tmp文件夹
这个文件夹是用来存放临时文件的。
usr文件夹
这个文件夹是用来存放系统程序的,比如用户命令、用户库等。
var文件夹
这个文件夹里的内容经常变动,比如/var/log就是用来存放系统日志的目录。
sys文件夹
这个文件夹就有意思了,它里面是一个虚拟的文件系统。跟proc一样的,最初sys里面的内容就是从proc里拆离出来的。这个虚拟文件系统就是sysfs文件系统。linux设备驱动模型中总线、驱动和设备都可以在该文件系统中找到对应的节点。
文件系统与设备驱动
文件系统与设备驱动啥关系呢?首先我们先讨论一下什么是文件系统?其实文件系统就是存储设备组织文件的方法。能够掉电存储的设备上的组织文件方法我们称为实际的文件系统;只能在电情况下存储设备的组织方法我们称为虚拟的文件系统,因为掉电这个组织方法就不存在这个存储设备上了。像ext2、ext3、fat等等这么多种类的文件系统,都是有各自一套对存储设备文件的组织方法,使用这些组织方法可以让我们更方便使用存储设备上的文件,不然一大堆的二进制文件会看得脑壳疼。。。。
那么设备驱动又是啥呢?对于代码来说,简而言之,配置设备驱动就是那配置那一个个寄存器位,使得设备按照我们的预想工作。为了使用方便,在内核中定义了设备的结构体file_operations,配置设备驱动时,可以配置这个file_operations结构体中的变量或者方法。
那么二者有啥关系呢?我们一般配置某个设备的驱动代码时,是不会直接调用file_operations中的方法的,因为使用这个结构体太麻烦了。这时,我们会封装一层文件系统接口,然后当我们使用那个设备时,直接使用那个文件系统接口就可以了。当然了,这个文件系统就是虚拟的,它只是为了方便统一操作设备驱动,还有真实的文件系统,以及一些特殊文件等。我们可以看下文件系统与设备驱动的图:
在驱动程序设计中,比较重要的是这2个结构体file结构体、inode结构体。下面我们来讨论一下它们。
file结构体
// include/linux/fs.h
struct file {
801 union {
802 struct llist_node fu_llist;
803 struct rcu_head fu_rcuhead;
804 } f_u;
805 struct path f_path;
806 struct inode *f_inode; /* cached value */
807 const struct file_operations *f_op;
808
809 /*
810 * Protects f_ep_links, f_flags.
811 * Must not be taken from IRQ context.
812 */
813 spinlock_t f_lock;
814 atomic_long_t f_count;
815 unsigned int f_flags;
816 fmode_t f_mode;
817 struct mutex f_pos_lock;
818 loff_t f_pos;
819 struct fown_struct f_owner;
820 const struct cred *f_cred;
821 struct file_ra_state f_ra;
822
823 u64 f_version;
824 #ifdef CONFIG_SECURITY
825 void *f_security;
826 #endif
827 /* needed for tty driver, and maybe others */
828 void *private_data;
829
830 #ifdef CONFIG_EPOLL
831 /* Used by fs/eventpoll.c to link all the hooks to this file */
832 struct list_head f_ep_links;
833 struct list_head f_tfile_llink;
834 #endif /* #ifdef CONFIG_EPOLL */
835 struct address_space *f_mapping;
836 } __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
file结构体代表一个打开的文件,系统中每个打开的文件在内核空间都有一个关联的struct file。它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数。在文件的所有实例都关闭后,内核释放这个数据结构。
这个file结构体中保存了这么成员,其中文件的私有数据成员会被大量用到,用来携带处理接口的。
inode结构体
// include/linux/fs.h
struct inode {
556 umode_t i_mode;
557 unsigned short i_opflags;
558 kuid_t i_uid;
559 kgid_t i_gid;
560 unsigned int i_flags;
561
562 #ifdef CONFIG_FS_POSIX_ACL
563 struct posix_acl *i_acl;
564 struct posix_acl *i_default_acl;
565 #endif
566
567 const struct inode_operations *i_op;
568 struct super_block *i_sb;
569 struct address_space *i_mapping;
570
571 #ifdef CONFIG_SECURITY
572 void *i_security;
573 #endif
574
575 /* Stat data, not accessed from path walking */
576 unsigned long i_ino;
577 /*
578 * Filesystems may only read i_nlink directly. They shall us e the
579 * following functions for modification:
580 *
581 * (set|clear|inc|drop)_nlink
582 * inode_(inc|dec)_link_count
583 */
584 union {
585 const unsigned int i_nlink;
586 unsigned int __i_nlink;
587 };
588 dev_t i_rdev;
589 loff_t i_size;
590 struct timespec i_atime;
591 struct timespec i_mtime;
592 struct timespec i_ctime;
593 spinlock_t i_lock; /* i_blocks, i_bytes, maybe i _size */
594 unsigned short i_bytes;
595 unsigned int i_blkbits;
596 blkcnt_t i_blocks;
597
598 #ifdef __NEED_I_SIZE_ORDERED
599 seqcount_t i_size_seqcount;
600 #endif
601
602 /* Misc */
603 unsigned long i_state;
604 struct mutex i_mutex;
605
606 unsigned long dirtied_when; /* jiffies of first d irtying */
607
608 struct hlist_node i_hash;
609 struct list_head i_wb_list; /* backing dev IO lis t */
610 struct list_head i_lru; /* inode LRU list */
611 struct list_head i_sb_list;
612 union {
613 struct hlist_head i_dentry;
614 struct rcu_head i_rcu;
615 };
616 u64 i_version;
617 atomic_t i_count;
618 atomic_t i_dio_count;
619 atomic_t i_writecount;
620 #ifdef CONFIG_IMA
621 atomic_t i_readcount; /* struct files open RO */
622 #endif
623 const struct file_operations *i_fop; /* former ->i_op->def ault_file_ops */
624 struct file_lock_context *i_flctx;
625 struct address_space i_data;
626 struct list_head i_devices;
627 union {
628 struct pipe_inode_info *i_pipe;
629 struct block_device *i_bdev;
630 struct cdev *i_cdev;
631 };
632
633 __u32 i_generation;
634
635 #ifdef CONFIG_FSNOTIFY
636 __u32 i_fsnotify_mask; /* all events this i node cares about */
637 struct hlist_head i_fsnotify_marks;
638 #endif
639
640 void *i_private; /* fs or device private p ointer */
641 };
这个inode结构体记录了一个文件访问权限、属主、组、大小、生成时间、访问时间、最后修改时间以及在设备上的存储块等信息。对于表示设备文件的inode结构,i_rdev字段包含设备编号。Linux内核设备编号分为主设备编号和次设备编号,前者为dev_t的高12位,后者为dev_t的低20位。
查看/proc/devices可以知道系统中目前已经注册的设备。第一列为主设备号,第二列为设备名。
查看/dev目录可以获知系统中包含的设备文件。内核Documents目录下的devices.txt文件描述了Linux设备号的分配情况。
总结
详情请参考宋宝华老师的书。