• linux一切皆文件之块设备文件(四)


    一、知识准备

    1、在linux中,一切皆为文件,所有不同种类的类型都被抽象成文件(比如:块设备,socket套接字,pipe队列)
    2、操作这些不同的类型就像操作文件一样,比如增删改查等
    3、块设备是将信息存储在大小固定的块中,每一个块都有自己的地址,块设备支持随机访问。典型的块设备比如我们使用的硬盘


    二、环境准备

    组件 版本
    OS Ubuntu 16.04.4 LTS

    三、主设备号(major)与次设备号(minor)

    ● 当一块磁盘被注册到操作系统的时候,会被分配主设备号与次设备号
    ● 其中主设备号代表了该设备属于的类型,次设备号代表了该设备在操作系统中的唯一标识

    主设备号

    root@Bastion:~# ls -l /dev/sd*
    brw-rw---- 1 root disk 8,  0 9月  30 17:47 /dev/sda
    brw-rw---- 1 root disk 8,  1 9月  30 17:47 /dev/sda1
    

    sda的主设备号是8,代表了sda这块磁盘是属于8这个类型的,那8是什么类型的?

    root@Bastion:~# grep 8 /proc/devices
    108 ppp
    128 ptm
    248 pps
      8 sd
    

    在/proc/devices告诉我们,8是属于sd类型的,那sd又是啥意思?

    打开 https://www.kernel.org/doc/Documentation/admin-guide/devices.txt

       8 block	SCSI disk devices (0-15)
    		  0 = /dev/sda		First SCSI disk whole disk
    		 16 = /dev/sdb		Second SCSI disk whole disk
    		 32 = /dev/sdc		Third SCSI disk whole disk
    		    ...
    		240 = /dev/sdp		Sixteenth SCSI disk whole disk
    
    		Partitions are handled in the same way as for IDE
    		disks (see major number 3) except that the limit on
    		partitions is 15.
    

    终于清楚的看到,8这个类型代表了块设备,并且是SCSI 硬盘

    次设备号

    由于/dev/sda做了1个分区/dev/sda1,再加上原有的/dev/sda,操作系统内核给二者打上了唯一的标记:
    8,0 代表了/dev/sda
    8,1 代表了/dev/sda1

    小结一下:
    主设备号:代表着某一类型的设备,比如SCSI硬盘、虚拟硬盘、USB等等
    次设备号:操作系统分配的整数,与主设备号一起(major,minor),组成了该设备在操作系统当中唯一的ID

    四、块设备文件

    ● 块设备文件是连接用户空间和内核空间的桥梁,通过块设备文件描述符,能够找到内核中的设备驱动程序
    ● 通过内核中的驱动程序从而对该设备进行读写

       +----------------------+
       | user space           |
       |                      |
       |      +---------+     |
       |      | test.py |     |
       |      +---------+     |
       +----------------------+
                   |
                   |
              +----v----+
              |/dev/sda1|
              +----+----+
                   |
                   |(8,1)
                   |
    +---------------------------------------------
    | kernel space |                             |
    |              |                             |
    |              v                             |
    |        +-----+----+      +---------------+ |
    |        | major:8  |      | device driver | |
    |        +-----+----+      |               | |
    |              |           +---------------+ |       +--------+
    |              +---------->|  minor:1      |-------->| device |
    |                          +---------------+ |       +--------+
    |                          |               | |
    |                          +---------------+ |
    +--------------------------------------------+
    
    

    五、测试

    (a)首先虚拟一个块设备文件

    root@Bastion:~# dd if=/dev/zero of=/tmp/device_test bs=1M count=100
    100+0 records in
    100+0 records out
    104857600 bytes (105 MB, 100 MiB) copied, 0.0890014 s, 1.2 GB/s
    root@Bastion:~# mknod /dev/device_test b 7 80
    root@Bastion:~# losetup /dev/device_test /tmp/device_test
    

    我们已经虚拟出一个块设备文件了,由于是通过losetup虚拟出来的,所以major号只能为7

    下面将该块设备格式化、挂载:

    root@Bastion:~# mkfs.ext4 /dev/device_test
    mke2fs 1.42.13 (17-May-2015)
    Discarding device blocks: done
    Creating filesystem with 102400 1k blocks and 25688 inodes
    Filesystem UUID: f38c24be-851b-41ff-8d55-4e692d5a4c83
    Superblock backups stored on blocks:
    	8193, 24577, 40961, 57345, 73729
    
    Allocating group tables: done
    Writing inode tables: done
    Creating journal (4096 blocks): done
    Writing superblocks and filesystem accounting information: done
    
    root@Bastion:~# mount /dev/device_test /mnt
    
    root@Bastion:~# df -h | grep /mnt
    /dev/device_test   93M  1.6M   85M   2% /mnt
    root@Bastion:/mnt# ls -l /dev/device_test
    brw-r--r-- 1 root root 7, 80 Nov 12 09:54 /dev/device_test
    

    至此,我们拥有了一个块设备,并且大小为100M

    (b)测试脚本

    准备一个python文件,每秒往test.log写入hello world

    root@Bastion:/mnt# more device_test.py
    import time
    f = open('test.log','a+')
    while 1:
        f.write('hello world
    ')
        time.sleep(1)
    

    运行并查看其打开的文件描述符

    root@Bastion:/mnt# python device_test.py &
    [1] 25873
    root@Bastion:/mnt# lsof -n | grep 25873
    COMMAND     PID   TID             USER   FD      TYPE             DEVICE  SIZE/OFF       NODE NAME
    ...
    python    25873                   root    3u      REG               7,80      8923         14 /mnt/test.log
    
    

    整理一下我们的信息:

    ● 首先运行脚本,它的进程号为25873。脚本的逻辑是需要打开test.log,然后进行读写
    ● 由于脚本中是相对路径,并且当前目录在/mnt下,/mnt相关联的硬盘是/dev/device_test
    ● 进程通过/dev/device_test拿到了该设备的设备号(7,80)
    ● 通过设备号在内存中找到对应的设备驱动程序,然后通过设备驱动程序对块设备进行读写
    ● 在块设备上没有发现test.log,首先创建一个,然后开始对该文件每秒写入一句'hello world'


    六、小结

    ● 当块设备挂载的时候,会先在操作系统的/dev下创建一个块设备文件,并且分配主设备号与次设备号
    ● 块设备文件是连接用户空间和内核空间的桥梁,应用程序通过它能够找到在内核中的设备驱动,从而实现对设备的读写



    至此,本文结束
    在下才疏学浅,有撒汤漏水的,请各位不吝赐教...

  • 相关阅读:
    总结类初始化时的代码执行顺序
    Calcite数据源适配器对时间字段的操作问题
    如何自定义一个Calcite对Tablesaw查询的适配器
    Redis集群 Redis Cluster
    培养代码逻辑
    在线查看office文件的两种方法
    WPF Prism框架合集(9.Dialog)
    WPF Prism框架合集(8.Navigation)
    WPF Prism框架合集(7.Mvvm)
    springboot @OneToOne 解决JPA双向死循环/返回json数据死循环
  • 原文地址:https://www.cnblogs.com/MrVolleyball/p/9993137.html
Copyright © 2020-2023  润新知