Chinaunix首页 | 论坛 | 博客
  • 博客访问: 50262
  • 博文数量: 21
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2014-08-15 13:27
文章分类
文章存档

2014年(21)

我的朋友

分类: 嵌入式

2014-09-01 13:02:15

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)。代码清单给出了文件结构体的定义。 


[html] view plaincopy
  1. struct file {  
  2.     /*  
  3.      * fu_list becomes invalid after file_free is called and queued via  
  4.      * fu_rcuhead for RCU freeing  
  5.      */  
  6.     union {  
  7.         struct list_head    fu_list;  
  8.         struct rcu_head     fu_rcuhead;  
  9.     } f_u;  
  10.     struct path     f_path;  
  11. #define f_dentry    f_path.dentry  
  12. #define f_vfsmnt    f_path.mnt  
  13.     const struct file_operations    *f_op;  
  14.     spinlock_t      f_lock;  /* f_ep_links, f_flags, no IRQ */  
  15. #ifdef CONFIG_SMP  
  16.     int         f_sb_list_cpu;  
  17. #endif  
  18.     atomic_long_t       f_count;  
  19.     unsigned int        f_flags;  
  20.     fmode_t         f_mode;  
  21.     loff_t          f_pos;  
  22.     struct fown_struct  f_owner;  
  23.     const struct cred   *f_cred;  
  24.     struct file_ra_state    f_ra;  
  25.   
  26.     u64         f_version;  
  27. #ifdef CONFIG_SECURITY  
  28.     void            *f_security;  
  29. #endif  
  30.     /* needed for tty driver, and maybe others */  
  31.     void            *private_data;  
  32.   
  33. #ifdef CONFIG_EPOLL  
  34.     /* Used by fs/eventpoll.c to link all the hooks to this file */  
  35.     struct list_head    f_ep_links;  
  36.     struct list_head    f_tfile_llink;  
  37. #endif /* #ifdef CONFIG_EPOLL */  
  38.     struct address_space    *f_mapping;  
  39. #ifdef CONFIG_DEBUG_WRITECOUNT  
  40.     unsigned long f_mnt_write_state;  
  41. #endif  
  42. };  
文件读/写模式 mode、标志 f_flags 都是设备驱动关心的内容,而私有数据指针private_data 在设备驱动中被广泛应用,大多被指向设备驱动自定义用于描述设备的结构体。 


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

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


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

[html] view plaincopy
  1. struct inode {  
  2.     /* RCU path lookup touches following: */  
  3.     umode_t         i_mode;  
  4.     uid_t           i_uid;  
  5.     gid_t           i_gid;  
  6.     const struct inode_operations   *i_op;  
  7.     struct super_block  *i_sb;  
  8.   
  9.     spinlock_t      i_lock; /* i_blocks, i_bytes, maybe i_size */  
  10.     unsigned int        i_flags;  
  11.     unsigned long       i_state;  
  12. #ifdef CONFIG_SECURITY  
  13.     void            *i_security;  
  14. #endif  
  15.     struct mutex        i_mutex;  
  16.   
  17.   
  18.     unsigned long       dirtied_when;   /* jiffies of first dirtying */  
  19.   
  20.     struct hlist_node   i_hash;  
  21.     struct list_head    i_wb_list;  /* backing dev IO list */  
  22.     struct list_head    i_lru;      /* inode LRU list */  
  23.     struct list_head    i_sb_list;  
  24.     union {  
  25.         struct list_head    i_dentry;  
  26.         struct rcu_head     i_rcu;  
  27.     };  
  28.     unsigned long       i_ino;  
  29.     atomic_t        i_count;  
  30.     unsigned int        i_nlink;  
  31.     dev_t           i_rdev;  
  32.     unsigned int        i_blkbits;  
  33.     u64         i_version;  
  34.     loff_t          i_size;  
  35. #ifdef __NEED_I_SIZE_ORDERED  
  36.     seqcount_t      i_size_seqcount;  
  37. #endif  
  38.     struct timespec     i_atime;  
  39.     struct timespec     i_mtime;  
  40.     struct timespec     i_ctime;  
  41.     blkcnt_t        i_blocks;  
  42.     unsigned short          i_bytes;  
  43.     struct rw_semaphore i_alloc_sem;  
  44.     const struct file_operations    *i_fop; /* former ->i_op->default_file_ops */  
  45.     struct file_lock    *i_flock;  
  46.     struct address_space    *i_mapping;  
  47.     struct address_space    i_data;  
  48. #ifdef CONFIG_QUOTA  
  49.     struct dquot        *i_dquot[MAXQUOTAS];  
  50. #endif  
  51.     struct list_head    i_devices;  
  52.     union {  
  53.         struct pipe_inode_info  *i_pipe;  
  54.         struct block_device *i_bdev;  
  55.         struct cdev     *i_cdev;  
  56.     };  
  57.   
  58.     __u32           i_generation;  
  59.   
  60. #ifdef CONFIG_FSNOTIFY  
  61.     __u32           i_fsnotify_mask; /* all events this inode cares about */  
  62.     struct hlist_head   i_fsnotify_marks;  
  63. #endif  
  64.   
  65. #ifdef CONFIG_IMA  
  66.     atomic_t        i_readcount; /* struct files open RO */  
  67. #endif  
  68.     atomic_t        i_writecount;  
  69. #ifdef CONFIG_FS_POSIX_ACL  
  70.     struct posix_acl    *i_acl;  
  71.     struct posix_acl    *i_default_acl;  
  72. #endif  
  73.     void            *i_private; /* fs or device private pointer */  
  74. };  
对于表示设备文件的 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 列为设备名,如下所示: 

[html] view plaincopy
  1. Character devices:   
  2.   1 mem   
  3.   2 pty   
  4.   3 ttyp   
  5.   4 /dev/vc/0   
  6.   4 tty   
  7.   5 /dev/tty   
  8.   5 /dev/console   
  9.   5 /dev/ptmx   
  10.   7 vcs   
  11.  10 misc   
  12.  13 input   
  13.  21 sg   
  14.  29 fb   
  15. 128 ptm   
  16. 136 pts   
  17. 171 ieee1394   
  18. 180 usb   
  19. 189 usb_device   
  20.    
  21. Block devices:   
  22.   1 ramdisk   
  23.   2 fd   
  24.   ......  
杳看/dev 目录可以获知系统中包含的设备文件,日期的前两列给出了对应设备的主设备号和次设备号,如下所示: 
[html] view plaincopy
  1. crw-rw---- 1 root uucp 4, 64 Jan 30 2003 /dev/ttyS0   
  2. 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 , 网 址 :)组织维护,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 能注意到这点并且为它创建对应的设备节点。

阅读(1239) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~