LINUX块设备驱动<8>
第 8章
+---------------------------------------------------+
| 写一个块设备驱动 |
+---------------------------------------------------+
| 作者:赵磊 |
| email: [email protected] |
+---------------------------------------------------+
| 文章版权归原作者所有。 |
| 大家可以自由转载这篇文章,但原版权信息必须保留。 |
| 如需用于商业用途,请务必与原作者联系,若因未取得 |
| 授权而收起的版权争议,由侵权者自行负责。 |
+---------------------------------------------------+
本章的目的是让读者继续休息,因此决定仍然搞一些简单的东西
比如:给我们的驱动程序模块加上模块参数,这样在加载模块时,可以通过参数设定块设备的大小
给我们模块加参数的工作不难,这牵涉到 1个宏:
module_param_named(name, value, type, perm)
name是参数的名称
value是参数在模块中对应的变量
type是参数的类型
perm是参数的权限
如,在模块中添加
int disk_size = 1024;
module_param_named(size, disk_size, int, S_IRUGO);
可以给模块加上名称为 "size"的参数,如果在加载模块是使用 insmod thismodule size=1 ,那么
在模块代码中 disk_size的值就是 1
相反,如果加载模块时没有指定参数,那么模块代码中disk_size的值仍是默认的 1024
S_IRUGO指定了这个参数的值在模块加载以后可以被所有人通过/sys/module/
[module_name]/parameters/看到,但无法修改
----------------------- Page 61-----------------------
好了,有关 module_param_named就介绍到这里,细节可以 google或者看
linux/include/linux/moduleparam.h
然后我们就要给这个模块加个参数,用来在加载时指定块设备的大小
参数的名字都已经想好了,就叫size吧,类型嘛,32位无符号整数最大能设定到 4G ,而我们的野心看
起来可能更大一些,
为了让这个模块支持 4G以上的虚拟磁盘(当然是内存足够的情况下) ,我们打算使用 64位无符号整型
这样能够设定的最大值为 16777216T ,应该够了吧
然后我们试图找出module_param_named的参数中与 unsigned long long对应的 type来
结果是:google了,没找到;看 linux/include/linux/moduleparam.h了,还是没找到
结论是:目前的 linux(2.6.28)还不支持 unsigned long long类型的模块参数
更新一些的内核中会不会有是将来的事,尽快搞定这一章的功能却是现在面临的问题
然后我们就开始找解决方案:
1 :给内核打个补丁,看样子不错,但至少今天之类完成不了我们的程序了
并且这样一来,我们的程序只能在今后的内核中运行,而失去对旧版 linux的兼容性
2 :指定设置磁盘大小的单位为 M。这样可设置的最大的数字就成了 4G*1M ,也就是4096T
这个主意看似不错。而且看样子1 年内机器的内存应该到不了这个容量
3 :用字符串来指定大小
这倒是可以解决所有问题,并且我们可以支持 16M、1G之类的设定,让我们的程序看起来比较花哨
缺点应该是我们需要在程序中自己去解析传入的字符串了,幸运的是,实际的解析代码比想象的容易
一些
因此,我们采用第 3个方案,向模块中添加一个名称为 size、类型为字符串的参数,并且支持解析以
K,M,G,T为单位的设定
第 1步:
向程序中添加以下参数申明
static char *simp_blkdev_param_size = "16M";
module_param_named(size, simp_blkdev_param_size, charp, S_IRUGO);
char *simp_blkdev_param_size用于存储设定的磁盘大小,我们把磁盘大小的默认值指定为 16M
目前我们不允许用户在模块加载后改变磁盘大小,将来嘛,有可能增加这一功能,看起来很眩
第 2步:
原来的程序使用
#define SIMP_BLKDEV_BYTES (16*1024*1024)
定义磁盘大小,而现在我们不需要这一行了
同时,我们需要一个unsigned long long变量来存储用户设定的磁盘大小,因此我们增加这个变量:
static unsigned long long simp_blkdev_bytes;
然后把程序中所有使用 SIMP_BLKDEV_BYTES的位置换成使用 simp_blkdev_bytes变量
第 3步:
----------------------- Page 62-----------------------
在模块加载时对模块参数进行解析,设置simp_blkdev_bytes变量的值
我们增加一个函数进行解析工作:
int getparam(void)
{
char unit;
char tailc;
if (sscanf(simp_blkdev_param_size, "%llu%c%c", &simp_blkdev_bytes,
&unit, &tailc) != 2) {
return -EINVAL;
}
if (!simp_blkdev_bytes)
return -EINVAL;
switch (unit) {
case ‘g‘:
case ‘G‘:
simp_blkdev_bytes <<= 30;
break;
case ‘m‘:
case ‘M‘:
simp_blkdev_bytes <<= 20;
break;
case ‘k‘:
case ‘K‘:
simp_blkdev_bytes <<= 10;
break;
case ‘b‘:
case ‘B‘:
break;
default:
return -EINVAL;
}
/* make simp_blkdev_bytes fits sector‘s size */
simp_blkdev_bytes = (simp_blkdev_bytes + (1<<9) - 1) & ~((1ULL<<9) - 1);
return 0;
}
然后在 simp_blkdev_init()中调用这个函数:
ret = getparam();
----------------------- Page 63-----------------------
if (IS_ERR_VALUE(ret))
goto err_getparam;
当然,err_getparam的位置读者应该能猜出来了
这样一来,工作大概就完成了,让我们看看结果:
使用默认值:
# insmod simp_blkdev.ko
# 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): 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
Command (m for help): q
#
设定成 20M :
# rmmod simp_blkdev
# insmod simp_blkdev.ko size=20M
# 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.
The number of cylinders for this disk is set to 1280.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
(e.g., DOS FDISK, OS/2 FDISK)
----------------------- Page 64-----------------------
Warning: invalid flag 0x of partition table 4 will be corrected by w(rite)
Command (m for help): p
Disk /dev/simp_blkdev: 20 MB, 20971520 bytes
1 heads, 32 sectors/track, 1280 cylinders
Units = cylinders of 32 * 512 = 16384 bytes
Device Boot Start End Blocks Id System
Command (m for help): q
#
变态一下,还是设定成 20M ,但用k作单位:
# rmmod simp_blkdev
# insmod simp_blkdev.ko size=20480k
# 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.
The number of cylinders for this disk is set to 1280.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
(e.g., DOS FDISK, OS/2 FDISK)
Warning: invalid flag 0x of partition table 4 will be corrected by w(rite)
Command (m for help): p
Disk /dev/simp_blkdev: 20 MB, 20971520 bytes
1 heads, 32 sectors/track, 1280 cylinders
Units = cylinders of 32 * 512 = 16384 bytes
Device Boot Start End Blocks Id System
Command (m for help): q
#
----------------------- Page 65-----------------------
看样子结果不错
这一章中基本上没有提到什么比较晦涩的知识,而且看样子通过这一章的学习,大家也应该休息好了
如果读者现在感觉到精神百倍,那么这一章的目的应该就达到了
<未完,待续>
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。