写一个块设备驱动 5

转载 2012年03月30日 15:13:55

第 5章

+---------------------------------------------------+
|                 写一个块设备驱动                   |
+---------------------------------------------------+
| 作者:赵磊                                         |
| email: zhaoleidd@hotmail.com                      |
+---------------------------------------------------+
| 文章版权归原作者所有。                             |
| 大家可以自由转载这篇文章,但原版权信息必须保留。   |
| 如需用于商业用途,请务必与原作者联系,若因未取得   |
| 授权而收起的版权争议,由侵权者自行负责。           |
+---------------------------------------------------+

既然上一章结束时我们已经预告了本章的内容,

那么本章中我们就让这个块设备有能力告知操作系统它的“物理结构”

当然,对于基于内存的块设备来说,什么样的物理结构并不重要,

这就如同从酒吧带mm回家时不需要打听她的姓名一样

但如果不幸遇到的是兼职,并且带她去不入流的招待所时,

建议最好还是先串供一下姓名、生日和职业等信息,

以便JJ查房时可以伪装成情侣

同样,如果要实现的是真实的物理块设备驱动,

那么返回设备的物理结构时大概不能这么随意

对于块设备驱动程序而言,我们现在需要关注那条目前只有一行的 struct 
block_device_operations simp_blkdev_fops结构

----------------------- Page 32-----------------------

到目前为止,它存在的目的仅仅是因为它必须存在,但马上我们将发现它存在的另一个目的:为块设备

驱动添加获得块设备物理结构的接口

对于具有极强钻研精神的极品读者来说,大概在第一章中就会自己去看 struct 
block_device_operations结构,然后将发现这个结构其实还挺复杂:
struct block_device_operations {
        int (*open) (struct block_device *, fmode_t);
        int (*release) (struct gendisk *, fmode_t);
        int (*locked_ioctl) (struct block_device *, fmode_t, unsigned, unsigned 
long);
        int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
        int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned 
long);
        int (*direct_access) (struct block_device *, sector_t,
                                                void **, unsigned long *);
        int (*media_changed) (struct gendisk *);
        int (*revalidate_disk) (struct gendisk *);
        int (*getgeo)(struct block_device *, struct hd_geometry *);
        struct module *owner;
};
在前几章中,我们邂逅过其中的 owner成员变量,它用于存储这个结构的所有者,也就是我们的模块,

因此我们做了如下的赋值:

.owner                = THIS_MODULE,
而这一章中,我们将与它的同胞妹妹------getgeo也亲密接触一下

我们要做的是:

1 :在block_device_operations中增加 getgeo成员变量初值的设定,指向我们的“获得块设备物理

结构”函数

2 :实现我们的“获得块设备物理结构”函数

第一步很简单,我们暂且为“获得块设备物理结构”函数取个名字叫simp_blkdev_getgeo()吧,也避免

了在下文中把这么一大堆汉字拷来拷去

在 simp_blkdev_fops中添加 .getgeo指向simp_blkdev_getgeo ,也就是把simp_blkdev_fops结

构改成这个样子:

struct block_device_operations simp_blkdev_fops = {
         .owner                = THIS_MODULE,
         .getgeo                = simp_blkdev_getgeo,
};

第二步难一些,但也难不到哪去,在代码中的struct block_device_operations 
simp_blkdev_fops这行之前找个空点的场子,把如下函数插进去:
static int simp_blkdev_getgeo(struct block_device *bdev,

----------------------- Page 33-----------------------

                struct hd_geometry *geo)
{
        /*
         * capacity        heads        sectors        cylinders
         * 0~16M        1        1        0~32768
         * 16M~512M        1        32        1024~32768
         * 512M~16G        32        32        1024~32768
         * 16G~...        255        63        2088~...
         */
        if (SIMP_BLKDEV_BYTES < 16 * 1024 * 1024) {
                geo->heads = 1;
                geo->sectors = 1;

        } else if (SIMP_BLKDEV_BYTES < 512 * 1024 * 1024) {
                geo->heads = 1;
                geo->sectors = 32;
        } else if (SIMP_BLKDEV_BYTES < 16ULL * 1024 * 1024 * 1024) {
                geo->heads = 32;
                geo->sectors = 32;
        } else {
                geo->heads = 255;
                geo->sectors = 63;
        }

        geo->cylinders = SIMP_BLKDEV_BYTES>>9/geo->heads/geo->sectors;

        return 0;
}
因为这里我们用到了 struct hd_geometry结构,所以还要增加一行#include <linux/hdreg.h>

这个函数的目的,是选择适当的物理结构信息装入 struct hd_geometry *geo结构
当然,为了克服上一章中只能分成 2个区的问题,我们应该尽可能增加磁道的数量

希望读者不要理解成分几个区就需要几个磁道,这意味着一个磁道一个区,也意味着每个区必须一般大

由于分区总是以磁道为边界,尽可能增加磁道的数量不仅仅是为了让块设备容纳更多的分区,

更重要的是让分区的实际大小更接近于分区时的指定值,也就是提高实际做出的分区容量的精度

不过对于设置的物理结构值,还存在一个限制,就是struct hd_geometry中的数值上限
我们看 struct hd_geometry的内容:
struct hd_geometry {
        unsigned char heads;
        unsigned char sectors;

----------------------- Page 34-----------------------

        unsigned short cylinders;
        unsigned long start;
};
unsigned char的磁头数和每磁道扇区数决定了其255的上限,同样,unsigned short的磁道数决
定了其65535的上限
这还不算,但在前一章中,我们知道对于现代硬盘,磁头数和每磁道扇区数通常取的值是 255和 63 ,
再组合上这里的 65535的磁道数上限,hd_geometry能够表示的最大块设备容量是
255*63*65535*512/1024/1024/1024=502G
显然目前linux支持的最大硬盘容量大于 502G ,那么对于这类块设备,内核是如何通过 hd_geometry

结构表示其物理结构的呢?

诀窍不在内核,而在于用户态程序如 fdisk等通过内核调用获得 hd_geometry结构后,
会舍弃hd_geometry.cylinders内容,取而代之的是直接通过 hd_geometry中的磁头数和每磁道扇

区数以及硬盘大小去计算磁道数

因此对于超过 502G的硬盘,由于用户程序得出的磁道数与 hd_geometry.cylinders无关,所以我们
往往在 fdisk中能看到这块硬盘的磁道数大于 65535

刚才扯远了,现在言归正题,我们决定让这个函数对于任何尺寸的块设备,总是试图返回比较漂亮的物

理结构

漂亮意味着返回的物理结构既要保证拥有足够多的磁道,也要保证磁头数和每磁道扇区数不超过 255和
63 ,同时最好使用程序员看起来比较顺眼的数字,
如:1、2、4、8、16、32、64等
当然,我们也希望找到某个 One Shot公式适用于所有大小的块设备,但很遗憾目前作者没找到,因此

采用了分段计算的方法:

首先考虑容量很小的块设备:

  即使磁头数和每磁道扇区数都是 1 ,磁道数也不够多时,我们会将磁头数和每磁道扇区数都固定为 1 ,

以使磁道数尽可能多,以提高分区的精度

  因此磁道数随块设备容量而上升

  虽然我们已经知道了磁道数其实可以超过 unsigned short的 65535上限,但在这里却没有必要,因

此我们要给磁道数设置一个上限

  因为不想让上限超过 65535 ,同时还希望上限也是一个程序员喜欢的数字,因此这里选择了32768
  当然,当磁道数超过 32768时,已经意味着块设备容量不那么小了,也就没有必要使用这种情况中如此

苛刻的磁头数和每磁道扇区数了

  简单来说,当块设备容量小于 1个磁头、每磁道1扇区和 32768个磁道对应的容量--也就是 16M时,

我们将按照这种情况处理

然后假设块设备容量已经大于 16M了:
  我们希望保证块设备包含足够多的磁道,这里我们认为1024个磁道应该不少了
  磁道的最小值发生在块设备容量为 16M的时候,这时使用 1024作为磁道数,可以计算出磁头数*每磁
道扇区数=32
  这里暂且把磁头数和每磁道扇区数固定为 1和 32 ,而让磁道数随着块设备容量的增大而增加
  同时,我们还是磁道的上限设置成 32768 ,这时的块设备容量为 512M
  总结来说,当块设备容量在 16M和 512M之间时,我们把磁头数和每磁道扇区数固定为 1和 32

----------------------- Page 35-----------------------

然后对于容量大于 512M的块设备:
  与上述处理相似,当块设备容量在 512M和 16G之间时,我们把磁头数和每磁道扇区数固定为 32和
32

最后的一种情况:

  块设备已经足够大了,大到即使我们使用磁头数和每磁道扇区数的上限,

  也能获得足够多的磁道数。这时把磁头数和每磁道扇区数固定为 255和 63
  至于磁道数就算出多少是多少了,即使超过 unsigned short的上限也无所谓,反正用不着

随着这个函数解说到此结束,我们对代码的修改也结束了

现在开始试验:

编译和加载:

# make
make -C /lib/modules/2.6.27.4/build 
SUBDIRS=/mnt/host_test/simp_blkdev/simp_blkdev_step05 modules
make[1]: Entering directory `/mnt/ltt-kernel'
  CC [M]  /mnt/host_test/simp_blkdev/simp_blkdev_step05/simp_blkdev.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /mnt/host_test/simp_blkdev/simp_blkdev_step05/simp_blkdev.mod.o
  LD [M]  /mnt/host_test/simp_blkdev/simp_blkdev_step05/simp_blkdev.ko
make[1]: Leaving directory `/mnt/ltt-kernel'
# insmod simp_blkdev.ko
#
用 fdisk打开设备文件
# fdisk /dev/simp_blkdev
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF 
disklabel
Building a new DOS disklabel. Changes will remain in memory only,
until you decide to write them. After that, of course, the previous
content won't be recoverable.

Warning: invalid flag 0x      of partition table 4 will be corrected by w(rite)

Command (m for help):

看看设备的物理结构:

Command (m for help): p

Disk /dev/simp_blkdev: 16 MB, 16777216 bytes
1 heads, 32 sectors/track, 1024 cylinders
Units = cylinders of 32 * 512 = 16384 bytes

           Device Boot      Start         End      Blocks   Id  System

----------------------- Page 36-----------------------

Command (m for help):
我们发现,现在的设备有 1个磁头、32扇区每磁道、1024个磁道

这是符合代码中的处理的

本章的内容也不是太难,连同上一章,我们已经休息 2章了

聪明的读者可能已经猜到作者打算说什么了

不错,下一章会有一个 surprise

<未完,待续>


相关文章推荐

写一个块设备驱动(5)

第5章 +---------------------------------------------------+ |                 写一个块设备驱动      ...

写一个块设备驱动

  • 2014年09月19日 21:25
  • 182KB
  • 下载

写一个块设备驱动

  • 2014年03月19日 15:43
  • 147KB
  • 下载

写一个块设备驱动 (7)

第7章 +---------------------------------------------------+ |                 写一个块设备驱动      ...

写一个块设备驱动 9

第 9章 +---------------------------------------------------+ |                 写一个块设备驱动           ...
  • bm7623
  • bm7623
  • 2012年03月30日 15:17
  • 463

写一个块设备驱动(8)

第8章 +---------------------------------------------------+ |                 写一个块设备驱动      ...

第14章 写一个块设备驱动

第14章 +---------------------------------------------------+ |                 写一个块设备驱动             ...
  • opendba
  • opendba
  • 2012年06月13日 18:18
  • 486

第13章 写一个块设备驱动

第13章 +---------------------------------------------------+ |                 写一个块设备驱动             ...
  • opendba
  • opendba
  • 2012年06月13日 18:16
  • 339

写一个块设备驱动13,14(转)

第13章 +---------------------------------------------------+ |???????????????? 写一个
  • dieqms
  • dieqms
  • 2014年11月13日 19:39
  • 139

写一个块设备驱动(11)

第11章 +---------------------------------------------------+ |                 写一个块设备驱动     ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:写一个块设备驱动 5
举报原因:
原因补充:

(最多只允许输入30个字)