[转]写一个块设备驱动(第八章)
第8章
+---------------------------------------------------+
|???????????????? 寫一個塊設備驅動????????????????? |
+---------------------------------------------------+
| 作者:趙磊??????????????????????????????????????? |
| email: zhaoleidd@hotmail.com????????????????????? |
+---------------------------------------------------+
| 文章版權歸原作者所有。??????????????????????????? |
| 大家可以自由轉載這篇文章,但原版權信息必須保留。? |
| 如需用于商業用途,請務必與原作者聯系,若因未取得? |
| 授權而收起的版權爭議,由侵權者自行負責。????????? |
+---------------------------------------------------+
本章的目的是讓讀者繼續休息,因此決定仍然搞一些簡單的東西。
比如:給我們的驅動程序模塊加上模塊參數,這樣在加載模塊時,可以通過參數設定塊設備的大小。
給我們模塊加參數的工作不難,這牽涉到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=100,那么在模塊代碼中disk_size的值就是100。
相反,如果加載模塊時沒有指定參數,那么模塊代碼中disk_size的值仍是默認的1024。
S_IRUGO指定了這個參數的值在模塊加載以后可以被所有人通過/sys/module/[module_name]/parameters/看到,但無法修改。
好了,有關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。
這個主意看似不錯。而且看樣子10年內機器的內存應該到不了這個容量。
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步:
在模塊加載時對模塊參數進行解析,設置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();
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 0x0000 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)
Warning: invalid flag 0x0000 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 0x0000 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
#
看樣子結果不錯。
這一章中基本上沒有提到什么比較晦澀的知識,而且看樣子通過這一章的學習,大家也應該休息好了。
如果讀者現在感覺到精神百倍,那么這一章的目的應該就達到了。
<未完,待續>
?
轉載于:https://blog.51cto.com/freshpassport/615663
總結
以上是生活随笔為你收集整理的[转]写一个块设备驱动(第八章)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 工作的感触
- 下一篇: 安装lighttpd