LINUX字符设备驱动程序原理总结
LINUX字符设备驱动程序原理总结
2010年07月08日
一)设备的输入/输出原理
通常,任何数据都必须通过内核空间才能到达应用程序的缓冲上。例如:对一个设备的读操作会引起数据被至少复制两遍,一遍是将内容复制到内核缓冲中,另一遍是将其再次复制到用户缓冲中。这是为了保证数据的可靠性和安全性所付出的代价。
但是,当字符设备驱动程序在低速字符设备上读写操作时,它通常直接将数据从用户空间的缓冲中复制到设备上。
二)I/O和字符设备
字符设备包括两种类型的设备: 1)低速的字符设备,也就是流设备,一般是终端和连续的端口。 在流设备上不能进行随机访问,也就是只能调用read和write来实现与该设备的通信。而不能使用mmap。由于read和write是同步的,当进程进行write和read调用时,它通常会阻塞,并要一直到操作完成后才能从系统调用里返回。这意味着在存储完成后驱动程序才会允许进程继续执行.本来可以用于运行代码的时间浪费在等待设备驱动程序上.
用下面的例子说明这一点:
time dd if=/dev/zero of=/dev/tty bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB) copied, 1.99129 s, 5.3 MB/s
real 0m1.997s
user 0m0.000s
sys 0m0.144s
这里只向终端写了堆空字符串,整个命令用了1.997秒,而实际上花在CPU的时间却只有0.144s,结论是剩下的时间都用在了驱动程序的阻塞上。 2)高速的字符设备 在高速的字符设备上允许随机访问,也就是支持mmap系统调用,这使得应用程序可以查看该设备驱动程序必须提供的所有数据.一般是很大的一个存储区域.
一个支持mmap系统调用的字符设备驱动程序,是不需要read和write调用的.因为它的读写操作会变得几乎像配给一大块内存一样简单.从而可以减少对系统调用的使用.
mmap()函数用来将某个文件内容映射到内存中,对该内存区域的访问即是直接对该文件内容读写.调用成功返回映射区的内存起始地址,进程可直接操作起始地址为该值的有效地址,否则返回-1。
一个简单的mmap示例:
#include
#include
#include
#include
#include
#define ERROR(x) do{ perror(x);\
exit (EXIT_FAILURE); } while(0)
int
main (int argc, char *argv[])
{
const int nbytes = 4096;
void *ptr;
int fd = open("/dev/zero", O_RDWR); //打开/dev/zero设备
if (fd == -1) ERROR("open");
ptr = mmap(0, nbytes, PROT_READ|PROT_WRITE,
MAP_PRIVATE, fd, 0); //调用mmap函数,将/dev/zero设备节点映射到*ptr中的地址,
//这个内存区域大小为4096个字节,权限是可读/可写
if (ptr == MAP_FAILED) ERROR("mmap");
memset(ptr, 1, nbytes); //填充*ptr这个内存区域为1
munmap(ptr, nbytes); //释放*ptr这个内存映像
return 0;
}
三)块设备,文件系统和I/O
1)块设备是磁盘及其他使用文件系统的存储设备的基础.
2)要访问一个设备,可以有两种方法:直接访问或者通过文件系统访问.
直接访问设备:
.分区:fdisk
.格式化:mkfs
.对设备节点的复制:cp /dev/sda sda.img或者 dd /dev/sda f=sda.img bs=8M
通过文件系统访问:
.通过mount命令挂载:mount /dev/sda1 /mnt/disk1之后对/mnt/disk1进行访问
用一个例子来说明两种访问方式的区别
备份整个磁盘/dev/sda的内容
直接访问方式:
cp /dev/sda sda.img
通过文件系统访问方式:
mount /dev/sda1 /mnt/disk1
tar cvzf /mnt/disk1 sda.tar.gz
总结两种方式的区别:
1)直接通过设备节点备份,可以备份磁盘的所有内容,包括启动块,而通过文件系统方式进行备份则不包括启动块等信息。
2)直接通过设备节点备份是备份了磁盘的所有数据,即磁盘/分区为30GB,备份后的文件也是30GB,而通过对文件系统打包备份,则有多少数据则打包多少数据。
四)缓冲区缓存和文件系统缓存
1)缓冲区缓存用来存储块设备可写和可读的块,在操作系统中叫buffer,由块设备驱动程序进行管理.它有以下几个特点:
.当一个进程要向一个块设备写数据时,首先数据会被复制到缓冲区缓存中的一个块里.块设备驱动程序不是马上被调用,当内核决定应该将数据块写回设备上时,它才会调用驱动程序.
.内核原则上会尽可能久地将每个读写块的副本保存在缓冲区缓存中..优点一是优化了系统的性能,因为想从磁盘上读数据的进程,只要从高速存储器中读取就可以了..优点二是cache允许内核把临近的数据块连接起来,将它们合并成一个大的写磁盘,这样可以提高磁盘的利用率..优点三cache的应用减少了启动磁盘的次数,因为在被写回磁盘前,一个块已经更新过了,这样内核只需要执行一次写操作而不需要两次.
.缺点是如果系统崩溃或者掉电,而数据如果还没写到设备上时,数据就会丢失.
应用缓冲区缓存的例子:
第一步查看当前系统中memory的buffers的大少,这里是40400
[root@test1 ~]# free
total used free shared buffers cached
Mem: 515600 221304 294296 0 40400 143780
-/+ buffers/cache: 37124 478476
Swap: 1052248 0 1052248
第二步从/dev/zero上的一个字符设备复制到了4MB数据到ramdisk设备/dev/ram0上的一个块设备.
[root@test1 ~]# dd if=/dev/zero f=/dev/ram0 bs=1k count=4096
第三步查看当