- 論壇徽章:
- 0
|
第8章
+---------------------------------------------------+
| 寫一個(gè)塊設(shè)備驅(qū)動(dòng) |
+---------------------------------------------------+
| 作者:趙磊 |
| email: zhaoleidd@hotmail.com |
+---------------------------------------------------+
| 文章版權(quán)歸原作者所有。 |
| 大家可以自由轉(zhuǎn)載這篇文章,但原版權(quán)信息必須保留。 |
| 如需用于商業(yè)用途,請(qǐng)務(wù)必與原作者聯(lián)系,若因未取得 |
| 授權(quán)而收起的版權(quán)爭(zhēng)議,由侵權(quán)者自行負(fù)責(zé)。 |
+---------------------------------------------------+
本章的目的是讓讀者繼續(xù)休息,因此決定仍然搞一些簡(jiǎn)單的東西。
比如:給我們的驅(qū)動(dòng)程序模塊加上模塊參數(shù),這樣在加載模塊時(shí),可以通過(guò)參數(shù)設(shè)定塊設(shè)備的大小。
給我們模塊加參數(shù)的工作不難,這牽涉到1個(gè)宏:
module_param_named(name, value, type, perm)
name是參數(shù)的名稱
value是參數(shù)在模塊中對(duì)應(yīng)的變量
type是參數(shù)的類型
perm是參數(shù)的權(quán)限
如,在模塊中添加
int disk_size = 1024;
module_param_named(size, disk_size, int, S_IRUGO);
可以給模塊加上名稱為"size"的參數(shù),如果在加載模塊是使用insmod thismodule size=100,那么在模塊代碼中disk_size的值就是100。
相反,如果加載模塊時(shí)沒(méi)有指定參數(shù),那么模塊代碼中disk_size的值仍是默認(rèn)的1024。
S_IRUGO指定了這個(gè)參數(shù)的值在模塊加載以后可以被所有人通過(guò)/sys/module/[module_name]/parameters/看到,但無(wú)法修改。
好了,有關(guān)module_param_named就介紹到這里,細(xì)節(jié)可以google或者看linux/include/linux/moduleparam.h。
然后我們就要給這個(gè)模塊加個(gè)參數(shù),用來(lái)在加載時(shí)指定塊設(shè)備的大小。
參數(shù)的名字都已經(jīng)想好了,就叫size吧,類型嘛,32位無(wú)符號(hào)整數(shù)最大能設(shè)定到4G,而我們的野心看起來(lái)可能更大一些,
為了讓這個(gè)模塊支持4G以上的虛擬磁盤(當(dāng)然是內(nèi)存足夠的情況下),我們打算使用64位無(wú)符號(hào)整型。這樣能夠設(shè)定的最大值為16777216T,應(yīng)該夠了吧。
然后我們?cè)噲D找出module_param_named的參數(shù)中與unsigned long long對(duì)應(yīng)的type來(lái)。
結(jié)果是:google了,沒(méi)找到;看linux/include/linux/moduleparam.h了,還是沒(méi)找到。
結(jié)論是:目前的linux(2.6.28)還不支持unsigned long long類型的模塊參數(shù)。
更新一些的內(nèi)核中會(huì)不會(huì)有是將來(lái)的事,盡快搞定這一章的功能卻是現(xiàn)在面臨的問(wèn)題。
然后我們就開(kāi)始找解決方案:
1:給內(nèi)核打個(gè)補(bǔ)丁,看樣子不錯(cuò),但至少今天之類完成不了我們的程序了
并且這樣一來(lái),我們的程序只能在今后的內(nèi)核中運(yùn)行,而失去對(duì)舊版linux的兼容性。
2:指定設(shè)置磁盤大小的單位為M。這樣可設(shè)置的最大的數(shù)字就成了4G*1M,也就是4096T。
這個(gè)主意看似不錯(cuò)。而且看樣子10年內(nèi)機(jī)器的內(nèi)存應(yīng)該到不了這個(gè)容量。
3:用字符串來(lái)指定大小
這倒是可以解決所有問(wèn)題,并且我們可以支持16M、1G之類的設(shè)定,讓我們的程序看起來(lái)比較花哨。
缺點(diǎn)應(yīng)該是我們需要在程序中自己去解析傳入的字符串了,幸運(yùn)的是,實(shí)際的解析代碼比想象的容易一些。
因此,我們采用第3個(gè)方案,向模塊中添加一個(gè)名稱為size、類型為字符串的參數(shù),并且支持解析以K,M,G,T為單位的設(shè)定。
第1步:
向程序中添加以下參數(shù)申明。
static char *simp_blkdev_param_size = "16M";
module_param_named(size, simp_blkdev_param_size, charp, S_IRUGO);
char *simp_blkdev_param_size用于存儲(chǔ)設(shè)定的磁盤大小,我們把磁盤大小的默認(rèn)值指定為16M。
目前我們不允許用戶在模塊加載后改變磁盤大小,將來(lái)嘛,有可能增加這一功能,看起來(lái)很眩。
第2步:
原來(lái)的程序使用
#define SIMP_BLKDEV_BYTES (16*1024*1024)
定義磁盤大小,而現(xiàn)在我們不需要這一行了。
同時(shí),我們需要一個(gè)unsigned long long變量來(lái)存儲(chǔ)用戶設(shè)定的磁盤大小,因此我們?cè)黾舆@個(gè)變量:
static unsigned long long simp_blkdev_bytes;
然后把程序中所有使用SIMP_BLKDEV_BYTES的位置換成使用simp_blkdev_bytes變量。
第3步:
在模塊加載時(shí)對(duì)模塊參數(shù)進(jìn)行解析,設(shè)置simp_blkdev_bytes變量的值。
我們?cè)黾右粋(gè)函數(shù)進(jìn)行解析工作:
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()中調(diào)用這個(gè)函數(shù):
ret = getparam();
if (IS_ERR_VALUE(ret))
goto err_getparam;
當(dāng)然,err_getparam的位置讀者應(yīng)該能猜出來(lái)了。
這樣一來(lái),工作大概就完成了,讓我們看看結(jié)果:
使用默認(rèn)值:
# 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
#
設(shè)定成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
#
變態(tài)一下,還是設(shè)定成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
#
看樣子結(jié)果不錯(cuò)。
這一章中基本上沒(méi)有提到什么比較晦澀的知識(shí),而且看樣子通過(guò)這一章的學(xué)習(xí),大家也應(yīng)該休息好了。
如果讀者現(xiàn)在感覺(jué)到精神百倍,那么這一章的目的應(yīng)該就達(dá)到了。
<未完,待續(xù)> |
|