寫一個塊設備驅動

第 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-----------------------

看樣子結果不錯

這一章中基本上沒有提到什麼比較晦澀的知識,而且看樣子通過這一章的學習,大家也應該休息好了

如果讀者現在感覺到精神百倍,那麼這一章的目的應該就達到了

<未完,待續>


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章