前言

在分析块设备驱动之前,整体规划如下:

	1. 介绍qemu使Linux内核挂载块设备。
	2. 介绍块设备驱动挂载过程。
	3. 介绍块设备驱动运行过程。

本章先重点介绍使用qemu使Linux内核和根文件系统挂载块设备的操作执行过程。
为什么要介绍在qemu中使Linux内核和根文件系统挂载块设备?我们为什么要操作这些繁琐的步骤?
下面着重回答一下为什么要使用QEMU中挂载块设备,是因为我们在上一章《QEMU+GDB调试Linux内核总结(全)》[link][https://blog.csdn.net/weixin_37867857/article/details/88205130]中介绍了要使用gdb调试linux内核代码必须使用qemu启动,并且设置调试模式才能够启动。其实如果有其他的方式和方案也可以,只不过个人觉得这个操作比较方便并且实用性高。而且在gdb调试中随时可以终止调试设置断点,这个在应用层是没有的。在应用层如果终止调试的话直接程序退出了,但是内核中是不会的。
为什么要操作这些繁琐的步骤呢?上面一句话已经回答了这个问题。
为了防止损伤硬盘,我们会以虚拟硬盘的形式挂载在磁盘中,下面第一章中我们会先介绍虚拟磁盘的制作和设置。

1. 虚拟磁盘的制作

虚拟磁盘,顾名思义这个磁盘是虚拟的,也可以在磁盘里面写入东西而不会丢失,除非虚拟磁盘损坏(损坏的方式有很多:重新格式化,挂载之后关机之前忘了卸载等都有可能损坏虚拟磁盘,但是好在都是虚拟磁盘的磁盘内容损坏,不会伤及物理磁盘)。虚拟磁盘也是云计算的一个重要的基础,所谓云计算也就是远程虚拟机的集群化部署。
话题扯的有点远了,言归正传,制作虚拟磁盘命令如下:

qemu-img create -f qcow2 disk.img 200M 	#现阶段的虚拟磁盘空间不用太大,200M就行了qcow2格式的
dd if=/dev/zero of=./disk.img bs=1M count=200  		# 清空我们的虚拟磁盘。
 mkfs.ext2 -q ./disk.img         # 磁盘格式化成ext2
mount -t ext2 disk.img /mnt/         # 本地磁盘挂载测试
umount /mnt						# 本地磁盘卸载测试;
qemu-system-x86_64 -kernel ./boot/bzImage -initrd ./initramfs.img -hdc ./disk.img -append "console=ttyS0" -nographic      # 虚拟机启动磁盘测试
#进入虚拟机后使用 ls /dev | grep sd测试虚拟机磁盘是否已经有了,比不加-hdc ./disk.img多了一个sda
#紧接着使用mount /dev/sda /mnt目录做一个挂载测试,最好是在本地磁盘挂载测试时候拷贝一个文件测试

下面是我执行如上命令的时候的执行记录:

root@ubuntu:/home/alex/kernel# qemu-img create -f qcow2 disk.img 200M
Formatting 'disk.img', fmt=qcow2 size=209715200 encryption=off cluster_size=65536 lazy_refcounts=off 
root@ubuntu:/home/alex/kernel# dd if=/dev/zero of=./disk.img bs=1M count=200
200+0 records in
200+0 records out
209715200 bytes (210 MB) copied, 3.28703 s, 63.8 MB/s
root@ubuntu:/home/alex/kernel# mkfs.ext2 -q ./disk.img 
./disk.img is not a block special device.
Proceed anyway? (y,n) y
root@ubuntu:/home/alex/kernel# mount -t ext2 disk.img /mnt/
root@ubuntu:/home/alex/kernel# ls /mnt/
lost+found
root@ubuntu:/home/alex/kernel# cd /mnt/
root@ubuntu:/mnt# mkdir alex
root@ubuntu:/mnt# ls
alex  lost+found
root@ubuntu:/home/alex/kernel# umount /mnt/

以下是虚拟机启动磁盘后的测试,也就是执行完qemu-system-x86_64 -kernel ./boot/bzImage -initrd ./initramfs.img -hdc ./disk.img -append "console=ttyS0" -nographic之后的执行记录:

/ # ls 
bin      etc      linuxrc  root     sys
dev      init     proc     sbin     usr
/ # ls /dev/sda 
/dev/sda
/ # mkdir mnt
/ # ls
bin      etc      linuxrc  proc     sbin     usr
dev      init     mnt      root     sys
/ # mount -t ext2 /dev/sda /mnt/    
mount: mounting /dev/sda on /mnt/ failed: No such device
/ # mount -t loop /dev/sda /mnt/          # 执行完两次之后心里有点烦躁,本着司马当活马医的心态直接使用mount /dev/sda/mnt
mount: mounting /dev/sda on /mnt/ failed: No such device
#先使用fdisk -l看磁盘是否真正有效,发现内核能够发现磁盘。
/ # fdisk -l

Disk /dev/sda: 209 MB, 209715200 bytes
255 heads, 63 sectors/track, 25 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

Disk /dev/sda doesn't contain a valid partition table
/ # mount /dev/sda /mnt/      #挂载成功
[  229.258151] EXT4-fs (sda): mounted filesystem without journal
/ # ls /mnt/							# 查看文件,和在制作时候创建的文件名一致。
alex        lost+found

OK,经过上述步骤,证明物理磁盘挂载成功到我们编译好的内核版本,下一章进行gdb调试。

qemu启动磁盘+GDB调试内核代码。

上一章中我们已经学会了怎么在内核镜像使用qemu加磁盘并且成功挂载上磁盘的操作。本章中我们学习怎么使用此调试内核代码。
如同内核调试步骤一样,正常的启动虚拟机除了加上-hdc ./disk.img我们的启动命令之外,我们还要添加-S -s的调试步骤。命令如下:

 qemu-system-x86_64 -kernel ./boot/bzImage -initrd ./initramfs.img -hdc ./disk.img -append "console=ttyS0" -nographic -S -s```
 然后启动另外一个终端敲gdb调试命令:

gdb vmlinux

gdb运行结果如下:
```shell
alex@ubuntu:/usr/src/linux-2.6.32.20$ gdb vmlinux 
GNU gdb (GDB) 7.9
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from vmlinux...done.
(gdb) target remote:1234
Remote debugging using :1234
0x0000000000000000 in per_cpu.irq_stack_union ()
(gdb) c
Continuing.
Remote connection closed
(gdb) q
alex@ubuntu:/usr/src/linux-2.6.32.20$ gdb vmlinux 
GNU gdb (GDB) 7.9
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from vmlinux...done.
(gdb) target remote:1234
Remote debugging using :1234
0x0000000000000000 in per_cpu.irq_stack_union ()
(gdb) b blkdev_open
Breakpoint 1 at 0xffffffff8116fc90: file fs/block_dev.c, line 1303.
(gdb) c
Continuing.

这时候我们看到gdb阻塞到continue回显步骤了,是因为我们打了一个断点,断点函数名称为blkdev_open。
我们只需要在启动的虚拟机里面执行如下:

cat /dev/sda 

执行如上命令后,gdb效果如下,可以看到,我们可以正常的查看代码,并且分析代码了。而且分析代码跟我们上述的cat命令有关,否则gdb调试还处于阻塞状态。
在这里插入图片描述
好了,本章就先介绍如何使用qemu挂载虚拟硬盘,并且使用gdb调试和块设备相关的代码。下一章重点介绍块设备驱动代码框架。

Logo

更多推荐