一、知識準備 1、在linux中,一切皆為文件,所有不同種類的類型都被抽象成文件(比如:塊設備,socket套接字,pipe隊列) 2、操作這些不同的類型就像操作文件一樣,比如增刪改查等 3、塊設備是將信息存儲在大小固定的塊中,每一個塊都有自己的地址,塊設備支持隨機訪問。典型的塊設備比如我們使用的硬 ...
一、知識準備
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\n')
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下創建一個塊設備文件,並且分配主設備號與次設備號
● 塊設備文件是連接用戶空間和內核空間的橋梁,應用程式通過它能夠找到在內核中的設備驅動,從而實現對設備的讀寫
至此,本文結束
在下才疏學淺,有撒湯漏水的,請各位不吝賜教...