1. Linux 上的设备 (device)

Linux 操作系统中,各种设备驱动(device driver)通过设备控制器(device controller)来管理各种设备(device),其关系如下图所示:

这些设备之中,

  • 受同一个 device driver 管理的设备都有相同的 major number,这个数字可以看作设备的类别号码,被内核用于识别一类设备
  • 受同一个 device driver 管理的同一类设备中的每一个设备都有不同的 minor number,这个数字可以看作设备编号,被设备驱动用来识别每个设备

设备驱动主要有三大类:

  • 面向包的网络设备驱动(package oriented network device driver)
  • 面向块的存储设备驱动(block oriented storage device driver),提供缓冲式(buffered)的设备访问。
  • 面向字节的字符设备驱动 (byte oriented char device driver),有时也称为裸设备(raw devices),提供非缓冲的直接的设备访问(unbuffered direct access),比如串口设备,摄像头,声音设备等。实际上,除了网络设备和存储设备以外的其它设备都是某种字符设备。

除此以外,还有一类设备,称为伪设备(pseudo device),它们是软件设备。Linux 上的 device 不一定要有硬件设备,比如 /dev/null, /dev/zero 等。

关于字符设备和块设备的更多区别:

  • 块设备只能以块为单位接受输入和返回输出,而字符设备则以字节为单位。大多数设备是字符设备,因为它们不需要缓冲而且不以固定块大小进行操作。
  • 块设备对于I/O 请求有对应的缓冲区,因此它们可以选择以什么顺序进行响应,字符设备无须缓冲且被直接读写。对于存储设备而言调 读写的顺序作用巨大,因为在读写连续的扇区比分离的扇区更快。
  • 字符设备只能被顺序读写,而块设备可以随机访问。虽然块设备可随机访问,但是对于磁盘这类机械设备而言,顺序地组织块设备的访问可以提高性能。

用户空间的各种应用是通过 device driver 来操作设备的:

如果再详细一些就是这样的:

图片来源

从这个图上可以看出:

  • 网络设备驱动之上,分别有包调度器(packet scheduler),网络协议层(network protocols),NetFilter (防火墙)和 scoket 层,其中,网络设备驱动以 socket 作为应用层的接口
  • 块设备驱动之上,分别有 I/O Scheduler,通用块层(generic block layer)和文件系统,其中,块设备驱动以设备文件 (device file)作为应用层的接访问口
  • 字符设备驱动之上,分别有 Line discipline 和 terminals,其中,terminals 作为和应用的访问接口

Linux 系统中“一切皆文件”。每个设备,在 /dev 目录中都有对一个设备文件(device file),比如 /dev/sda 表示第一个 SCSI/IDE 盘,/dev/vda 表示第一个 virtio 磁盘。应用程序通过访问这些设备文件像操作文件一样来访问这些设备,可以使用的接口包括:

  • int open(const char *path, int oflag, ... )
  • int close(int fd);
  • ssize_t write(int fd, const void *buf, size_t nbyte)
  • ssize_t read(int fd, void *buf, size_t nbyte)
  • int ioctl(int d, int request, ...)

在 Linux 系统上,设备驱动可以被动态加载和删除

  • lsmod - 列出当前已经被加载的模块
  • insmod <module_file> - insert/load 指定的模块文件
  • modprobe <module> - insert/load 指定的 module,以及所有依赖
  • rmmod <module> - remove/unload 指定的module

2. Linux 设备的 major 和 minor number

2.1 用 ls 获取

上文谈到了 major 和 number。简单地,可以从 ls 命令的输出中看出 device 的这两个numbers:

root@controller:/home/sammy# cd /dev
root@controller:/dev# ls -l
total
crw------- root root 10, 175 Jul : agpgart
crw------- root root , Jul : autofs
brw-rw---- root disk , Jul : loop5
brw-rw---- root disk , Jul : loop6
brw-rw---- root disk , Jul : sda
brw-rw---- root disk , Jul : sda1
brw-rw---- root disk , Jul : sda2
brw-rw---- root disk , Jul : sda5
crw--w---- root tty , Jul : tty10
crw--w---- root tty , Jul : tty11
  • 以  'c' 开头的一行表示该设备是一个字符设备,以 'b' 开头的行表示这是一个块设备。
  • 10,175 这两个数字中,前面的 10 表示 major number,后面的 175 表示 minor number。

2.2 major 和 minor 值的设置

历史上,设备的 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,比如:

 pty
ttyp
ttyS
lp
vcs
misc
input
sound
sg
usbBlock devices:
fd
sd
sr
sd
sd

3. 根据 major 和 minior numbers 识别磁盘类型

3.1 识别过程

根据以下步骤来识别磁盘类型:

(1)使用 stat 命令获取设备文件的 major 和 minor numbers。注意结果是16进制。

root@u1:/dev# stat -c %T /dev/vda #minor number

root@u1:/dev# stat -c %T /dev/vdb

root@u1:/dev# stat -c %T /dev/sda

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

(2)将16进制数字转化为10进制,并拼接字符串 /sys/dev/block/$decmajor:$minor/device/driver

/sys/dev/block/:/device/driver
/sys/dev/block/:/device/driver
/sys/dev/block/:/device/driver

(3)调用 readlink -f 命令,获取 device driver

root@u1:/dev# readlink -f /sys/dev/block/:/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/:/device/driver
/sys/bus/scsi/drivers/sd

从输出可以看出,/dev/vda 和 /dev/vdb 都是 virtio-block 类型的设备,而 /dev/sda 是 sd 即 SCSI 类型的设备。

常见的命名:

  • fd:软驱
  • hd:IDE 磁盘
  • sd:SCSI 磁盘
  • tty:terminals
  • vd:virtio 磁盘

3.2 virtio block driver 的实现

virtio-blk 驱动的实现代码在 https://github.com/spotify/linux/blob/master/drivers/block/virtio_blk.c。从中可以看出 major 和 minor number 分配,以及设备命名的方法。

(1)设备命名方法

if (index < ) {
sprintf(vblk->disk->disk_name, "vd%c", 'a' + index % );
} else if (index < ( + ) * ) {
sprintf(vblk->disk->disk_name, "vd%c%c",
'a' + index / - , 'a' + index % );
} else {
const unsigned int m1 = (index / - ) / - ;
const unsigned int m2 = (index / - ) % ;
const unsigned int m3 = index % ;
sprintf(vblk->disk->disk_name, "vd%c%c%c",
'a' + m1, 'a' + m2, 'a' + m3);
}

可见:

  • virtio-blk 设备的名称以 ‘vd’ 开头。从  ‘vda’ 开始递增,数目在 26 个以内时,增长至 ‘vdz’;如果超过 26,则从 ’vdaa‘ 一直增长至 ’vdzz‘;最高可以增长到 ’vdzzz‘。
  • 名称在设备被加载后被确定,在重新加载或者系统重启后会重新生成,因此对同一个设备其名称可能会发生变化。我的另一篇文章 理解 QEMU/KVM 和 Ceph(3):存储卷挂接和设备名称谈到了这种变化导致的问题。

(2)major number 是通过向内核注册来获取的

static int __init init(void)
{
major = register_blkdev(, "virtblk");
if (major < )
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);

参考链接:

识别 Linux上的设备(磁盘)类型的更多相关文章

  1. Linux上把新磁盘扩展到已有分区中(基于LVM)

    0.在不重启服务器的前提下找到新加的磁盘 --查看主机总线号 ls /sys/class/scsi_host/ --根据查询结果生成刷新磁盘语句 echo "- - -" > ...

  2. kvm上的Linux虚拟机使用virtio磁盘

    kvm上的Linux虚拟机使用virtio磁盘 系统:centos6.6  64位 网上的文章比较少,怎麽将Linux虚拟机的磁盘改为使用virtio磁盘 因为centos6或以上系统已经包含了vir ...

  3. linux上测试磁盘IO速度

    运维工作,经常要测试服务器硬件性能,以此来判断是否存在性能瓶颈. 下面介绍在linux上测试磁盘IO速度的工具: 1.hdparm CentOS中,安装的两种方法: 1) yum安装. # yum i ...

  4. IDE 设备(磁盘/CD-ROM)配置不正确。“ide1:1”上具有一个 IDE 从设备,但没有主设备。此配置在虚拟机中无法正常运行。请使用配置编辑器将磁盘/CD-ROM 从“ide1:1”移到“ide1:0”。

    开启vmware报这个错: IDE 设备(磁盘/CD-ROM)配置不正确.“ide1:1”上具有一个 IDE 从设备,但没有主设备.此配置在虚拟机中无法正常运行.请使用配置编辑器将磁盘/CD-ROM ...

  5. Ubuntu上识别不到安卓设备或者显示出“????”,提示No Permission

    一:Ubuntu上识别不到安卓设备 1.lsusb找到设备的Vendor ID 2.cd ~/.android 3.vim adb_usb.ini 4.把设备的VendorID添加进来,如设备ID为2 ...

  6. linux kvm虚拟机快速构建及磁盘类型

    KVM命令管理 virsh命令:用来管理各虚拟机的接口命令查看/创建/停止/关闭...支持交互模式格式:virsh 控制指令 [虚拟机名称] [参数] [root@room1pc01 桌面]# vir ...

  7. 【linux相识相知】磁盘分区及文件系统管理详解

    磁盘,提供持久的数据存储,它不像我们的内存,如果突然断电了,在内存中的数据一般都会被丢掉了,内存中的数据在保存的时候,会被写到硬盘里面,磁盘也是一种I/O设备. 我们都知道磁盘分区完成之后,还要进行格 ...

  8. Linux上配置使用iSCSI详细说明

    本文详细介绍iSCSI相关的内容,以及在Linux上如何实现iSCSI. 第1章 iSCSI简介 1.1 scsi和iscsi 传统的SCSI技术是存储设备最基本的标准协议,但通常需要设备互相靠近并用 ...

  9. 第5章 Linux上管理文件系统

    5.1 机械硬盘 机械硬盘由多块盘片组成,它们都绕着主轴旋转.每块盘片上下方都有读写磁头悬浮在盘片上下方,它们与盘片的距离极小.在每次读写数据时盘片旋转,读写磁头被磁臂控制着不断的移动来读取其中的数据 ...

随机推荐

  1. Win10 UWP系列:更新UWP时注意的问题——TargetDeviceFamily

    前几天把CurrencyExchanger提交到微软参加Master认证,结果没有通过,反馈了一些错误,看来微软检查还是比较仔细的. 错误主要有: Visual feedback helps user ...

  2. 基于Metronic的Bootstrap开发框架经验总结(12)--页面链接收藏夹功能的实现

    在一个系统里面,往往有很多菜单项目,每个菜单项对应一个页面,一般用户只需要用到一些常用的功能,如果每次都需要去各个层次的菜单里面去找对应的功能,那确实有点繁琐.特别是在菜单繁多,而客户又对系统整体不熟 ...

  3. DevExtreme 学习应用[2]

    DevExtreme 学习应用[2] 调用WebService数据 1那么首先建立WebService using System; using System.Collections.Generic; ...

  4. MSSQL 2012安装报错之0x858C001B

    之前安装 Microsoft Sql Server 2012 R2 的时候总是报这样的错误: SQL Server Setup has encountered the following error: ...

  5. [工具] Firemonkey Style 调色工具(可另存 Style 文件)

    版本:2016.12.21 (新增可取代颜色) 下载:[工具]OneStylePalette_调色工具_20161221.zip 版本:2016.12.09 (新增可导出全平台的 Style) 下载: ...

  6. 从零开始学Python第七周:面向对象进阶(需修改)

    一,类的属性 (1)示例 通过属性获取已经创建对象的个数 class Plane: pCount = 0 #类属性 def __init__(self,name,category): self.nam ...

  7. 转载:《TypeScript 中文入门教程》 4、类

    版权 文章转载自:https://github.com/zhongsp 建议您直接跳转到上面的网址查看最新版本. 介绍 传统的JavaScript程序使用函数和基于原型的继承来创建可重用的组件,但这对 ...

  8. PHP工作笔记:yii2各种功能汇总

    数据库操纵: 基础知识:数据库基础 查询语句: 使用yii migrate管理.生成数据库 Yii2 AR find用法 Yii2.0 对数据库 查询的一些简单的操作 修改语句: Yii 修改数据的两 ...

  9. 关于C#消息调度(作业日志)

    在Windows定时作业中,其实有多种关于作业调度形式,比如Windows Services 和 Windows Form 都可以做到,各有各的好处.现在来介绍下使用插件的形式进行定时作业. 1.用q ...

  10. jQuery siteslider 动画幻灯片

    在线实例 效果一 效果二 使用方法 <div class="container demo-1">             <div id="slider ...