Linux设备驱动开发详解-Note(10)--- Linux 文件系统与设备文件系统(2)

来源:互联网 发布:java调用https接口 编辑:程序博客网 时间:2024/05/17 18:41

Linux 文件系统与设备文件系统(2)

成于坚持,败于止步

Linux 文件系统目录结构 

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

1./bin 

包含基本命令,如 ls、cp、mkdir 等,这个目录中的文件都是可执行的。 

2./boot 

Linux 系统的内核及引导系统程序所需要的文件,如 vmlinuz、initrd.img 文件都位于这个目录中。 

3./dev 

设备文件存储目录,应用程序通过对这些文件的读写和控制就可以访问实际的设备。 

4./etc 

系统配置文件的所在地,一些服务器的配置文件也在这里,如用户账号及密码配置文件。

5./home 

普通用户的家目录。 

6./lib 

库文件存放目录。 

7./lost+found 

在 Ext2 或 Ext3 文件系统中,当系统意外崩溃或机器意外关机时会产生一些文件碎片放在这里。 

8./mnt 

/mnt 这个目录一般是用于存放挂载储存设备的挂载目录的,比如有 cdrom 等目录,可以参看/etc/fstab 的定义。有时我们可以把让系统开机自动挂载文件系统,把挂载点放在这里也是可以的。 

9./opt 

opt 是“可选”的意思,有些软件包会被安装在这里,比如在 Fedora Core 5.0 中的 OpenOffice 就是安装在这里,用户自己编译的软件包也可以安装在这个目录中。 

10./proc 

操作系统运行时,进程及内核信息(比如 CPU、硬盘分区、内存信息等)存放在这里。/proc 目录为伪文件系统 proc 的挂载目录,proc 并不是真正的文件系统,它存在于内存之中。 

11./root 

Linux 超级权限用户 root 的家目录。 

12./sbin 

存放可执行文件,大多是涉及系统管理的命令,是超级权限用户 root 的可执行命令存放地 ,普通用户无权限执行这个目录下 的命令 ,这个目录和/usr/sbin;/usr/X11R6/sbin 或/usr/local/sbin 目录是相似的。 

13./tmp 

有时用户运行程序的时候会产生临时文件,/tmp 用来存放临时文件。 

14./usr 

这个是系统存放程序的目录,比如命令、帮助文件等,它包含很多文件和目录,Linux 发行版提供的软件包大多被安装在这里。

15./var 

var 表示的是变化的意思,这个目录的内容经常变动,如/var 的/var/log 目录被用来存放系统日志。 

16./sys 

Linux 2.6 内核所支持的 sysfs 文件系统被映射在此目录。Linux 设备驱动模型中的总线、驱动和设备都可以在 sysfs 文件系统中找到对应的节点。当内核检测到在系统中出现了新设备后,内核会在 sysfs 文件系统中为该新设备生成一项新的记录。 

17./initrd 

若在启动过程中使用了 initrd 映像作为临时根文件系统,则在执行完其上的/linuxrc 挂接真正的根文件系统后,原来的初始 RAM 文件系统被映射到/initrd 目录。

Linux 文件系统与设备驱动 

图 5.1 所示为 Linux 系统中虚拟文件系统、磁盘文件(存放于 RamDisk、Flash、ROM、SD 卡、U 盘等文件系统中的文件也属于磁盘文件)及一般的设备文件与设备驱动程序之间的关系。 

应用程序和 VFS 之间的接口是系统调用,而 VFS 与磁盘文件系统以及普通设备之间的接口是 file_operations 结构体成员函数,这个结构体包含对文件进行打开、关闭、读写、控制的一系列成员函数。 

由于字符设备的上层没有磁盘文件系统,所以字符设备的 file_operations 成员函数就直接由设备驱动提供了,file_operations 正是字符设备驱动的核心。


而对于块存储设备而言,ext2、fat、jffs2 等文件系统中会实现针对 VFS 的file_operations 成员函数,设备驱动层将看不到 file_operations 的存在。磁盘文件系统和设备驱动会将对磁盘上文件的访问最终转换成对磁盘上柱面和扇区的访问。 

在设备驱动程序的设计中,一般而言,会关心结构体 file 和 inode 这两个结构体。 

1.file 结构体 

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

struct file {/* * fu_list becomes invalid after file_free is called and queued via * fu_rcuhead for RCU freeing */union {struct list_headfu_list;struct rcu_head fu_rcuhead;} f_u;struct pathf_path;#define f_dentryf_path.dentry#define f_vfsmntf_path.mntconst struct file_operations*f_op;spinlock_tf_lock;  /* f_ep_links, f_flags, no IRQ */#ifdef CONFIG_SMPintf_sb_list_cpu;#endifatomic_long_tf_count;unsigned int f_flags;fmode_tf_mode;loff_tf_pos;struct fown_structf_owner;const struct cred*f_cred;struct file_ra_statef_ra;u64f_version;#ifdef CONFIG_SECURITYvoid*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_headf_ep_links;struct list_headf_tfile_llink;#endif /* #ifdef CONFIG_EPOLL */struct address_space*f_mapping;#ifdef CONFIG_DEBUG_WRITECOUNTunsigned long f_mnt_write_state;#endif};
文件读/写模式 mode、标志 f_flags 都是设备驱动关心的内容,而私有数据指针private_data 在设备驱动中被广泛应用,大多被指向设备驱动自定义用于描述设备的结构体。 

驱动程序中经常会使用如下类似的代码来检测用户打开文件的读写方式。

if (file->f_mode & FMODE_WRITE) //用户要求可写 { } if (file->f_mode & FMODE_READ) //用户要求可读 { } 
下面的代码可用于判断以阻塞还是非阻塞方式打开设备文件。
if (file->f_flags & O_NONBLOCK)    //非阻塞      pr_debug("open: non-blocking\n"); else                                    //阻塞      pr_debug("open: blocking\n"); 
2.inode 结构体 

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

struct inode {/* RCU path lookup touches following: */umode_ti_mode;uid_ti_uid;gid_ti_gid;const struct inode_operations*i_op;struct super_block*i_sb;spinlock_ti_lock;/* i_blocks, i_bytes, maybe i_size */unsigned inti_flags;unsigned longi_state;#ifdef CONFIG_SECURITYvoid*i_security;#endifstruct mutexi_mutex;unsigned longdirtied_when;/* jiffies of first dirtying */struct hlist_nodei_hash;struct list_headi_wb_list;/* backing dev IO list */struct list_headi_lru;/* inode LRU list */struct list_headi_sb_list;union {struct list_headi_dentry;struct rcu_headi_rcu;};unsigned longi_ino;atomic_ti_count;unsigned inti_nlink;dev_ti_rdev;unsigned inti_blkbits;u64i_version;loff_ti_size;#ifdef __NEED_I_SIZE_ORDEREDseqcount_ti_size_seqcount;#endifstruct timespeci_atime;struct timespeci_mtime;struct timespeci_ctime;blkcnt_ti_blocks;unsigned short          i_bytes;struct rw_semaphorei_alloc_sem;const struct file_operations*i_fop;/* former ->i_op->default_file_ops */struct file_lock*i_flock;struct address_space*i_mapping;struct address_spacei_data;#ifdef CONFIG_QUOTAstruct dquot*i_dquot[MAXQUOTAS];#endifstruct list_headi_devices;union {struct pipe_inode_info*i_pipe;struct block_device*i_bdev;struct cdev*i_cdev;};__u32i_generation;#ifdef CONFIG_FSNOTIFY__u32i_fsnotify_mask; /* all events this inode cares about */struct hlist_headi_fsnotify_marks;#endif#ifdef CONFIG_IMAatomic_ti_readcount; /* struct files open RO */#endifatomic_ti_writecount;#ifdef CONFIG_FS_POSIX_ACLstruct posix_acl*i_acl;struct posix_acl*i_default_acl;#endifvoid*i_private; /* fs or device private pointer */};
对于表示设备文件的 inode 结构,i_rdev 字段包含设备编号。Linux 2.6 设备编号分为主设备编号和次设备编号,前者为 dev_t 的高 12 位,后者为 dev_t 的低 20 位。

下列操作用于从一个 inode 中获得主设备号和次设备号: 

unsigned int iminor(struct inode *inode); 

unsigned int imajor(struct inode *inode); 

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

Character devices:   1 mem   2 pty   3 ttyp   4 /dev/vc/0   4 tty   5 /dev/tty   5 /dev/console   5 /dev/ptmx   7 vcs  10 misc  13 input  21 sg  29 fb 128 ptm 136 pts 171 ieee1394 180 usb 189 usb_device  Block devices:   1 ramdisk   2 fd   ......
杳看/dev 目录可以获知系统中包含的设备文件,日期的前两列给出了对应设备的主设备号和次设备号,如下所示:
crw-rw---- 1 root uucp 4, 64 Jan 30 2003 /dev/ttyS0 brw-rw---- 1 root disk 8, 0 Jan 30 2003 /dev/sda 
主设备号是与驱动对应的概念,同一类设备一般使用相同的主设备号,不同类的设备一般使用不同的主设备号(但是也不排除在同一主设备号下包含有一定差异的设备)。因为同一驱动可支持多个同类设备,因此用次设备号来描述使用该驱动的设备的序号,序号一般从 0 开始。 

内核 Documents 目录下的 devices.txt 文件描述了 Linux 设备号的分配情况,它由LANANA ( The Linux Assigned Names And Numbers Authority , 网 址 :http://www.lanana.org/)组织维护,Torben Mathiasen 是其中的主要维护者。需要注意的是,LANANA 给出的设备号标准并不是硬性规定,在具体的设备驱动程序中,尽管一般会遵循 LANANA,但是也可以有例外。

udev 设备文件系统 

udev 与 devfs 的区别 

尽管 devfs 有这样和那样的优点,但是,在 Linux 2.6 内核中,devfs 被认为是过时的方法,并最终被抛弃,udev 取代了它。

udev 完全在用户态工作,利用设备加入或移除时内核所发送的热插拔事件(hotplug event)来工作。在热插拔时,设备的详细信息会由内核输出到位于/sys 的 sysfs 文件系统。

udev 的设备命名策略、权限控制和事件处理都是在用户态下完成的,它利用 sysfs 中的信息来进行创建设备文件节点等工作。 

由于 udev 根据系统中硬件设备的状态动态更新设备文件,进行设备文件的创建和删除等,因此,在使用 udev 后,/dev 目录下就会只包含系统中真正存在的设备了。 devfs 与 udev 的另一个显著区别在于:采用 devfs,当一个并不存在的/dev 节点被打开的时候,devfs 能自动加载对应的驱动,而 udev 则不能。这是因为 udev 的设计者认为 Linux 应该在设备被发现的时候加载驱动模块,而不是当它被访问的时候。udev的设计者认为 devfs 所提供的打开/dev 节点时自动加载驱动的功能对于一个配置正确
的计算机是多余的。系统中所有的设备都应该产生热插拔事件并加载恰当的驱动,而udev 能注意到这点并且为它创建对应的设备节点。

就到这里了,O(∩_∩)O~

我的专栏地址:http://blog.csdn.net/column/details/linux-driver-note.html

待续。。。。

原创粉丝点击