Linux 操做系统中,各类设备驱动(device driver)经过设备控制器(device controller)来管理各类设备(device),其关系以下图所示:html
这些设备之中,linux
设备驱动主要有三大类:git
除此之外,还有一类设备,称为伪设备(pseudo device),它们是软件设备。Linux 上的 device 不必定要有硬件设备,好比 /dev/null, /dev/zero 等。github
关于字符设备和块设备的更多区别:网络
用户空间的各类应用是经过 device driver 来操做设备的:socket
若是再详细一些就是这样的:svg
(图片来源)oop
从这个图上能够看出:性能
Linux 系统中“一切皆文件”。每一个设备,在 /dev 目录中都有对一个设备文件(device file),好比 /dev/sda 表示第一个 SCSI/IDE 盘,/dev/vda 表示第一个 virtio 磁盘。应用程序经过访问这些设备文件像操做文件同样来访问这些设备,可使用的接口包括:网站
在 Linux 系统上,设备驱动能够被动态加载和删除
上文谈到了 major 和 number。简单地,能够从 ls 命令的输出中看出 device 的这两个numbers:
root@controller:/home/sammy# cd /dev root@controller:/dev# ls -l total 0 crw------- 1 root root 10, 175 Jul 18 15:24 agpgart crw------- 1 root root 10, 235 Jul 18 15:24 autofs brw-rw---- 1 root disk 7, 5 Jul 18 15:24 loop5 brw-rw---- 1 root disk 7, 6 Jul 18 15:24 loop6 brw-rw---- 1 root disk 8, 0 Jul 18 15:24 sda brw-rw---- 1 root disk 8, 1 Jul 18 15:24 sda1 brw-rw---- 1 root disk 8, 2 Jul 18 15:24 sda2 brw-rw---- 1 root disk 8, 5 Jul 18 15:24 sda5 crw--w---- 1 root tty 4, 10 Jul 18 15:24 tty10 crw--w---- 1 root tty 4, 11 Jul 18 15:24 tty11
历史上,设备的 major number 采用的是注册制,各设备厂家在 http://www.lanana.org/ 中注册他们的设备所使用的 major number。从 http://www.lanana.org/docs/device-list/devices-2.6+.txt 中还能够看出来 linux 2.6 内核中所分配的静态major numbers。
可是,如今,这个注册网站已经没有人维护了,取而代之的是动态分配制度。分配者是linux 内核的 udev 模块。它将保证在本系统中,<major number>:<minor number>的组合是惟一的,而在这个范围以外,它不会保证其唯一性。一旦分配好了后,你就能够从 /proc/device 文件中读出所分配的 major numbers,好比:
2 pty 3 ttyp 4 ttyS 6 lp 7 vcs 10 misc 13 input 14 sound 21 sg 180 usbBlock devices: 2 fd 8 sd 11 sr 65 sd 66 sd
根据如下步骤来识别磁盘类型:
(1)使用 stat 命令获取设备文件的 major 和 minor numbers。注意结果是16进制。
root@u1:/dev# stat -c %T /dev/vda #minor number 0 root@u1:/dev# stat -c %T /dev/vdb 10 root@u1:/dev# stat -c %T /dev/sda 0 root@u1:/dev# stat -c %t /dev/vda #major number fd root@u1:/dev# stat -c %t /dev/vdb fd root@u1:/dev# stat -c %t /dev/sda 8
(2)将16进制数字转化为10进制,并拼接字符串 /sys/dev/block/$decmajor:$minor/device/driver
/sys/dev/block/253:0/device/driver /sys/dev/block/253:16/device/driver /sys/dev/block/8:0/device/driver
(3)调用 readlink -f 命令,获取 device driver
root@u1:/dev# readlink -f /sys/dev/block/253:0/device/driver /sys/bus/virtio/drivers/virtio_blk
root@u1:/dev# readlink -f /sys/dev/block/253:16/device/driver
/sys/bus/virtio/drivers/virtio_blk
root@u1:/dev# readlink -f /sys/dev/block/8:0/device/driver /sys/bus/scsi/drivers/sd
从输出能够看出,/dev/vda 和 /dev/vdb 都是 virtio-block 类型的设备,而 /dev/sda 是 sd 即 SCSI 类型的设备。
常见的命名:
virtio-blk 驱动的实现代码在 https://github.com/spotify/linux/blob/master/drivers/block/virtio_blk.c。从中能够看出 major 和 minor number 分配,以及设备命名的方法。
(1)设备命名方法
if (index < 26) { sprintf(vblk->disk->disk_name, "vd%c", 'a' + index % 26); } else if (index < (26 + 1) * 26) { sprintf(vblk->disk->disk_name, "vd%c%c", 'a' + index / 26 - 1, 'a' + index % 26); } else { const unsigned int m1 = (index / 26 - 1) / 26 - 1; const unsigned int m2 = (index / 26 - 1) % 26; const unsigned int m3 = index % 26; sprintf(vblk->disk->disk_name, "vd%c%c%c", 'a' + m1, 'a' + m2, 'a' + m3); }
可见:
(2)major number 是经过向内核注册来获取的
static int __init init(void) { major = register_blkdev(0, "virtblk"); if (major < 0) return major; return register_virtio_driver(&virtio_blk); }
register_blkdev 这个方法是内核系统调用,用于注册一个块设备,须要指定主设备号。若是指定的设备号为0,则会由系统自动分配一个。该方法调用以后,就能够在/proc/devices文件中看到该块设备以及它的 major number。
(3)minor number 是由设备的 index (索引)转化而来的
vblk->disk->first_minor = index_to_minor(index);
参考连接: