<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      《Linux內(nèi)核設(shè)計(jì)與實(shí)現(xiàn)》讀書筆記(十七)- 設(shè)備與模塊

      本章主要討論與linux的設(shè)備驅(qū)動和設(shè)備管理的相關(guān)的4個(gè)內(nèi)核成分,設(shè)備類型,模塊,內(nèi)核對象,sysfs。

      主要內(nèi)容:

      • 設(shè)備類型
      • 內(nèi)核模塊
      • 內(nèi)核對象
      • sysfs
      • 總結(jié)

       

      1. 設(shè)備類型

      linux中主要由3種類型的設(shè)備,分別是:

      設(shè)備類型

      代表設(shè)備

      特點(diǎn)

      訪問方式

      塊設(shè)備 硬盤,光盤 隨機(jī)訪問設(shè)備中的內(nèi)容 一般都是把設(shè)備掛載為文件系統(tǒng)后再訪問
      字符設(shè)備 鍵盤,打印機(jī) 只能順序訪問(一個(gè)一個(gè)字符或者一個(gè)一個(gè)字節(jié)) 一般不掛載,直接和設(shè)備交互
      網(wǎng)絡(luò)設(shè)備 網(wǎng)卡 打破了Unix "所有東西都是文件" 的設(shè)計(jì)原則 通過套接字API來訪問

       

      除了以上3種典型的設(shè)備之外,其實(shí)Linux中還有一些其他的設(shè)備類型,其中見的較多的應(yīng)該算是"偽設(shè)備"。

      所謂"偽設(shè)備",其實(shí)就是一些虛擬的設(shè)備,僅提供訪問內(nèi)核功能而已,沒有物理設(shè)備與之關(guān)聯(lián)。

      典型的"偽設(shè)備"就是 /dev/random(內(nèi)核隨機(jī)數(shù)發(fā)生器), /dev/null(空設(shè)備), /dev/zero(零設(shè)備), /dev/full(滿設(shè)備)

       

      2. 內(nèi)核模塊

      Linux內(nèi)核是模塊化組成的,內(nèi)核中的模塊可以按需加載,從而保證內(nèi)核啟動時(shí)不用加載所有的模塊,即減少了內(nèi)核的大小,也提高了效率。

      通過編寫內(nèi)核模塊來給內(nèi)核增加功能或者接口是個(gè)很好的方式(既不用重新編譯內(nèi)核,也方便調(diào)試和刪除)。

       

      2.1 內(nèi)核模塊示例

      內(nèi)核模塊可以帶參數(shù)也可以不帶參數(shù),不帶參數(shù)的內(nèi)核模塊比較簡單。

      我之前的幾篇隨筆中用于測試的例子都是用不帶參數(shù)的內(nèi)核模塊來實(shí)驗(yàn)的。

       

      2.1.1. 無參數(shù)的內(nèi)核模塊

      參考:

      《Linux內(nèi)核設(shè)計(jì)與實(shí)現(xiàn)》讀書筆記(六)- 內(nèi)核數(shù)據(jù)結(jié)構(gòu)

      《Linux內(nèi)核設(shè)計(jì)與實(shí)現(xiàn)》讀書筆記(八)- 中斷下半部的處理

      《Linux內(nèi)核設(shè)計(jì)與實(shí)現(xiàn)》讀書筆記(十一)- 定時(shí)器和時(shí)間管理

       

      2.1.2. 帶參數(shù)的內(nèi)核模塊

      構(gòu)造帶參數(shù)的內(nèi)核模塊其實(shí)也不難,內(nèi)核中已經(jīng)提供了簡單的框架來給我們聲明參數(shù)。

      1. module_param(name, type, perm) : 定義一個(gè)模塊參數(shù)

      + 參數(shù) name :: 既是用戶可見的參數(shù)名,也是模塊中存放模塊參數(shù)的變量名

      + 參數(shù) type :: 參數(shù)的類型(byte, short, int, uint, long, ulong, charp, bool...) byte型存放在char變量中,bool型存放在int變量中

      + 參數(shù) perm :: 指定模塊在 sysfs 文件系統(tǒng)中對應(yīng)的文件權(quán)限(關(guān)于 sysfs 的內(nèi)容后面介紹)

       

      static int stu_id = 0;  // 默認(rèn)id
      module_param(stu_id, int, 0644);

       

      2. module_param_named(name, variable, type, perm) : 定義一個(gè)模塊參數(shù),并且參數(shù)對內(nèi)對外的名稱不一樣

      + 參數(shù) name :: 用戶可見的參數(shù)名

      + 參數(shù) variable :: 模塊中存放模塊參數(shù)的變量名

      + 參數(shù) type和perm :: 同 module_param 中的 type 和 perm

       

      static char* stu_name_in = "default name"; // 默認(rèn)名字
      module_param_named(stu_name_out, stu_name_in ,charp, 0644);
      /* stu_name_out 是對用戶開放的名稱
       * stu_name_in 是內(nèi)核模塊內(nèi)部使用的名稱
       */

       

      3. module_param_string(name, string, len, perm) : 拷貝字符串到指定的字符數(shù)組

      + 參數(shù) name :: 用戶可見的參數(shù)名

      + 參數(shù) string :: 模塊中存放模塊參數(shù)的變量名

      + 參數(shù) len :: string 參數(shù)的緩沖區(qū)長度

      + 參數(shù) perm :: 同 module_param 中的 perm

       

      static char str_in[BUF_LEN];
      module_param_string(str_out, str_in, BUF_LEN, 0);
      /* perm=0 表示完全禁止 sysfs 項(xiàng) */

       

      4. module_param_array(name, type, nump, perm) : 定義數(shù)組類型的模塊參數(shù)

      + 參數(shù) name :: 同 module_param 中的 name

      + 參數(shù) type :: 同 module_param 中的 type

      + 參數(shù) nump :: 整型指針,存放數(shù)組的長度

      + 參數(shù) perm :: 同 module_param 中的 perm

       

      #define MAX_ARR_LEN 5
      static int arr_len;
      static int arr_in[MAX_ARR_LEN];
      module_param_array(arr_in, int, &arr_len, 0644);

       

      5. module_param_array_named(name, array, type, nump, perm) : 定義數(shù)組類型的模塊參數(shù),并且數(shù)組參數(shù)對內(nèi)對外的名稱不一樣

      + 參數(shù) name :: 數(shù)組參數(shù)對外的名稱

      + 參數(shù) array :: 數(shù)組參數(shù)對內(nèi)的名稱

      + 參數(shù) type,nump,perm :: 同 module_param_array 中的 type,nump,perm

       

      #define MAX_ARR_LEN 5
      static int arr_len;
      static int arr_in[MAX_ARR_LEN];
      module_param_array_named(arr_out, arr_in, int, &arr_len, 0644);

       

      6. 參數(shù)描述宏

      可以通過 MODULE_PARM_DESC() 來給內(nèi)核模塊的參數(shù)添加一些描述信息。

      這些描述信息在編譯完內(nèi)核模塊后,可以通過 modinfo  命令查看。

       

      static int stu_id = 0;  // 默認(rèn)id
      module_param(stu_id, int, 0644);
      MODULE_PARM_DESC(stu_id, "學(xué)生ID,默認(rèn)為 0");  // 這句就是描述內(nèi)核模塊參數(shù) stu_id 的語句

       

      7. 帶參數(shù)的內(nèi)核模塊的示例

      示例代碼:test_paramed_km.c

      定義了3個(gè)內(nèi)核模塊參數(shù),分別是 int型,char*型,數(shù)組型的。

      #include<linux/init.h>
      #include<linux/module.h>
      #include<linux/kernel.h>
      
      MODULE_LICENSE("Dual BSD/GPL");
      
      struct student
      {
          int id;
          char* name;
      };
      static void print_student(struct student*);
      
      static int stu_id = 0;  // 默認(rèn)id
      module_param(stu_id, int, 0644);
      MODULE_PARM_DESC(stu_id, "學(xué)生ID,默認(rèn)為 0");
      
      static char* stu_name_in = "default name"; // 默認(rèn)名字
      module_param_named(stu_name_out, stu_name_in ,charp, 0644);
      MODULE_PARM_DESC(stu_name, "學(xué)生姓名,默認(rèn)為 default name");
      
      #define MAX_ARR_LEN 5
      static int arr_len;
      static int arr_in[MAX_ARR_LEN];
      module_param_array_named(arr_out, arr_in, int, &arr_len, 0644);
      MODULE_PARM_DESC(arr_in, "數(shù)組參數(shù),默認(rèn)為空");
      
      static int test_paramed_km_init(void)
      {
          struct student* stu1;
          int i;
          
          /* 進(jìn)入內(nèi)核模塊 */
          printk(KERN_ALERT "*************************\n");
          printk(KERN_ALERT "test_paramed_km is inited!\n");
          printk(KERN_ALERT "*************************\n");
          // 根據(jù)參數(shù)生成 struct student 信息
          // 如果沒有參數(shù)就用默認(rèn)參數(shù)
          printk(KERN_ALERT "alloc one student....\n");
          stu1 = kmalloc(sizeof(*stu1), GFP_KERNEL);
          stu1->id = stu_id;
          stu1->name = stu_name_in;
          print_student(stu1);
      
          // 模塊數(shù)組
          for (i = 0; i < arr_len; ++i) {
              printk(KERN_ALERT "arr_value[%d]: %d\n", i, arr_in[i]);
          }
      
          
          return 0;
      }
      
      static void test_paramed_km_exit(void)
      {
          /* 退出內(nèi)核模塊 */
          printk(KERN_ALERT "*************************\n");
          printk(KERN_ALERT "test_paramed_km is exited!\n");
          printk(KERN_ALERT "*************************\n");
          printk(KERN_ALERT "\n\n\n\n\n");
      }
      
      static void print_student(struct student *stu)
      {
          if (stu != NULL)
          {
              printk(KERN_ALERT "**********student info***********\n");
              printk(KERN_ALERT "student id   is: %d\n", stu->id);
              printk(KERN_ALERT "student name is: %s\n", stu->name);
              printk(KERN_ALERT "*********************************\n");
          }
          else
              printk(KERN_ALERT "the student info is null!!\n");    
      }
      
      module_init(test_paramed_km_init);
      module_exit(test_paramed_km_exit);
      View Code

       

      上面的示例對應(yīng)的 Makefile 如下:

      # must complile on customize kernel
      obj-m += paramed_km.o
      paramed_km-objs := test_paramed_km.o
      
      #generate the path
      CURRENT_PATH:=$(shell pwd)
      #the current kernel version number
      LINUX_KERNEL:=$(shell uname -r)
      #the absolute path
      LINUX_KERNEL_PATH:=/usr/src/kernels/$(LINUX_KERNEL)
      #complie object
      all:
          make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
          rm -rf modules.order Module.symvers .*.cmd *.o *.mod.c .tmp_versions *.unsigned
      #clean
      clean:
          rm -rf modules.order Module.symvers .*.cmd *.o *.mod.c *.ko .tmp_versions *.unsigned
      View Code 

      內(nèi)核模塊運(yùn)行方法:(我的運(yùn)行環(huán)境是 CentOS 6.3 x86_64)

      [root@vbox chap17]# uname -r
      2.6.32-279.el6.x86_64
      [root@vbox chap17]# ll
      total 8
      -rw-r--r-- 1 root root  538 Dec  1 19:37 Makefile
      -rw-r--r-- 1 root root 2155 Dec  1 19:37 test_paramed_km.c
      [root@vbox chap17]# make    <-- 編譯內(nèi)核
      make -C /usr/src/kernels/2.6.32-279.el6.x86_64 M=/root/chap17 modules
      make[1]: Entering directory `/usr/src/kernels/2.6.32-279.el6.x86_64'
        CC [M]  /root/chap17/test_paramed_km.o
        LD [M]  /root/chap17/paramed_km.o
        Building modules, stage 2.
        MODPOST 1 modules
        CC      /root/chap17/paramed_km.mod.o
        LD [M]  /root/chap17/paramed_km.ko.unsigned
        NO SIGN [M] /root/chap17/paramed_km.ko
      make[1]: Leaving directory `/usr/src/kernels/2.6.32-279.el6.x86_64'
      rm -rf modules.order Module.symvers .*.cmd *.o *.mod.c .tmp_versions *.unsigned
      [root@vbox chap17]# ll   <-- 編譯內(nèi)核后,多了 paramed_km.ko 文件
      total 124
      -rw-r--r-- 1 root root    538 Dec  1 19:37 Makefile
      -rw-r--r-- 1 root root 118352 Dec  1 19:37 paramed_km.ko
      -rw-r--r-- 1 root root   2155 Dec  1 19:37 test_paramed_km.c
      
      <-- 通過 modinfo 命令可以查看對內(nèi)核模塊參數(shù)的注釋
      [root@vbox chap17]# modinfo  paramed_km.ko
      filename:       paramed_km.ko
      license:        Dual BSD/GPL
      srcversion:     C52F97687B033738742800D
      depends:
      vermagic:       2.6.32-279.el6.x86_64 SMP mod_unload modversions
      parm:           stu_id:學(xué)生ID,默認(rèn)為 0 (int)
      parm:           stu_name_out:charp
      parm:           stu_name_in:學(xué)生姓名,默認(rèn)為 default name
      parm:           arr_out:array of int
      parm:           arr_in:數(shù)組參數(shù),默認(rèn)為空
      
      <-- 3 個(gè)參數(shù)都是默認(rèn)的
      [root@vbox chap17]# insmod paramed_km.ko
      [root@vbox chap17]# rmmod paramed_km.ko
      [root@vbox chap17]# dmesg | tail -16  <-- 結(jié)果中顯示2個(gè)默認(rèn)參數(shù),第3個(gè)數(shù)組參數(shù)默認(rèn)為空,所以不顯示
      *************************
      test_paramed_km is inited!
      *************************
      alloc one student....
      **********student info***********
      student id   is: 0
      student name is: default name
      *********************************
      *************************
      test_paramed_km is exited!
      *************************
      
      <-- 3 個(gè)參數(shù)都被設(shè)置
      [root@vbox chap17]# insmod paramed_km.ko stu_id=100 stu_name_out=myname arr_out=1,2,3,4,5
      [root@vbox chap17]# rmmod paramed_km.ko
      [root@vbox chap17]# dmesg | tail -21
      *************************
      test_paramed_km is inited!
      *************************
      alloc one student....
      **********student info***********
      student id   is: 100
      student name is: myname
      *********************************
      arr_value[0]: 1
      arr_value[1]: 2
      arr_value[2]: 3
      arr_value[3]: 4
      arr_value[4]: 5
      *************************
      test_paramed_km is exited!
      *************************
      View Code 

      2.2 內(nèi)核模塊的位置

      2.2.1.  內(nèi)核代碼外

      上面的例子,以及之前博客中內(nèi)核模塊的例子都是把模塊代碼放在內(nèi)核之外來運(yùn)行的。

       

      2.2.2. 內(nèi)核代碼中

      內(nèi)核模塊的代碼也可以直接放到內(nèi)核代碼樹中。

      如果你開發(fā)了一種驅(qū)動,并且希望被加入到內(nèi)核中,那么,可以在編寫驅(qū)動的時(shí)候就將完成此驅(qū)動功能的內(nèi)核模塊加到內(nèi)核代碼樹中 driver 的相應(yīng)位置。

      將內(nèi)核模塊加入內(nèi)核代碼樹中之后,不需要另外寫 Makefile,修改內(nèi)核代碼樹中的已有的 Makefile 就行。

      比如,寫了一個(gè)某種字符設(shè)備相關(guān)的驅(qū)動,可以把它加到內(nèi)核代碼的 /drivers/char 下,

      同時(shí)修改 /drivers/char下的Makefie,仿照里面已有的內(nèi)容,增加新驅(qū)動的編譯相關(guān)內(nèi)容即可。

       

      之后,在編譯內(nèi)核的時(shí)候會將新的驅(qū)動以內(nèi)核模塊的方式編譯出來。

       

      2.3 內(nèi)核模塊相關(guān)操作

      2.3.1. 模塊安裝

      make modules_install  <-- 把隨內(nèi)核編譯出來的模塊安裝到合適的目錄中( /lib/modules/version/kernel )

       

      2.3.2. 模塊依賴性

      linux中自動生產(chǎn)模塊依賴性的命令:

      depmod     <-- 產(chǎn)生內(nèi)核依賴關(guān)系信息
      depmod -A  <-- 只為新模塊生成依賴信息(速度更快)

       

      2.3.3. 模塊的載入

      內(nèi)核模塊實(shí)驗(yàn)時(shí)已經(jīng)用過:

      insmod module.ko
      
      <-- 推薦使用以下的命令, 自動加載依賴的模塊
      modprobe module [module parameters]

       

      2.3.4. 模塊的卸載

      內(nèi)核模塊實(shí)驗(yàn)時(shí)已經(jīng)用過:

      rmmod module.ko
      
      <-- 推薦使用以下的命令, 自動卸載依賴的模塊
      modprobe -r module

       

      2.3.5. 模塊導(dǎo)出符號表

      內(nèi)核模塊被載入后,就動態(tài)的加載到內(nèi)核中,為了能讓其他內(nèi)核模塊使用其功能,需要將其中函數(shù)導(dǎo)出。

      內(nèi)核模塊中導(dǎo)出函數(shù)的方法:

      EXPORT_SYMBOL(函數(shù)名)       <-- 接在要導(dǎo)出的函數(shù)后面即可
      EXPORT_SYMBOL_GPL(函數(shù)名)   <-- 和EXPORT_SYMBOL一樣,區(qū)別在于只對標(biāo)記為GPL協(xié)議的模塊可見

       

      內(nèi)核模塊導(dǎo)出符號表 示例

      + 首先編寫一個(gè)導(dǎo)出函數(shù)的模塊 module_A: test_module_A.c

      #include<linux/init.h>
      #include<linux/module.h>
      #include<linux/kernel.h>
      
      MODULE_LICENSE("Dual BSD/GPL");
      
      static int test_export_A_init(void)
      {
          /* 進(jìn)入內(nèi)核模塊 */
          printk(KERN_ALERT "*************************\n");
          printk(KERN_ALERT "ENTRY test_export_A!\n");
          printk(KERN_ALERT "*************************\n");
          printk(KERN_ALERT "\n\n\n\n\n");
          return 0;
      }
      
      static void test_export_A_exit(void)
      {
          /* 退出內(nèi)核模塊 */
          printk(KERN_ALERT "*************************\n");
          printk(KERN_ALERT "EXIT test_export_A!\n");
          printk(KERN_ALERT "*************************\n");
          printk(KERN_ALERT "\n\n\n\n\n");
      }
      
      /* 要導(dǎo)出的函數(shù) */
      int export_add10(int param)
      {
          printk(KERN_ALERT "param from other module is : %d\n", param);
          return param + 10;
      }
      EXPORT_SYMBOL(export_add10);
      
      module_init(test_export_A_init);
      module_exit(test_export_A_exit);
      View Code 

      test_module_A.c 的 Makefile

      # must complile on customize kernel
      obj-m += export_A.o
      export_A-objs := test_export_A.o
      
      #generate the path
      CURRENT_PATH:=$(shell pwd)
      #the current kernel version number
      LINUX_KERNEL:=$(shell uname -r)
      #the absolute path
      LINUX_KERNEL_PATH:=/usr/src/kernels/$(LINUX_KERNEL)
      #complie object
      all:
          make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
          rm -rf modules.order .*.cmd *.o *.mod.c .tmp_versions *.unsigned
      #clean
      clean:
          rm -rf modules.order Module.symvers .*.cmd *.o *.mod.c *.ko .tmp_versions *.unsigned
      View Code 

      + 再編寫一個(gè)內(nèi)核模塊 module_B,使用 module_A 導(dǎo)出的函數(shù) : test_module_B.c

      #include<linux/init.h>
      #include<linux/module.h>
      #include<linux/kernel.h>
      
      MODULE_LICENSE("Dual BSD/GPL");
      
      extern int export_add10(int);   // 這個(gè)函數(shù)是 module_A 中實(shí)現(xiàn)的
      
      static int test_export_B_init(void)
      {
          /* 進(jìn)入內(nèi)核模塊 */
          printk(KERN_ALERT "*************************\n");
          printk(KERN_ALERT "ENTRY test_export_B!\n");
          printk(KERN_ALERT "*************************\n");
          printk(KERN_ALERT "\n\n\n\n\n");
      
          /* 調(diào)用 module_A 導(dǎo)出的函數(shù) */
          printk(KERN_ALERT "result from test_export_A: %d\n", export_add10(100));
          
          return 0;
      }
      
      static void test_export_B_exit(void)
      {
          /* 退出內(nèi)核模塊 */
          printk(KERN_ALERT "*************************\n");
          printk(KERN_ALERT "EXIT test_export_B!\n");
          printk(KERN_ALERT "*************************\n");
          printk(KERN_ALERT "\n\n\n\n\n");
      }
      
      module_init(test_export_B_init);
      module_exit(test_export_B_exit);
      View Code

       

      test_module_B.c 的 Makefile

      # must complile on customize kernel
      obj-m += export_B.o
      export_B-objs := test_export_B.o
      
      #generate the path
      CURRENT_PATH:=$(shell pwd)
      #the current kernel version number
      LINUX_KERNEL:=$(shell uname -r)
      #the absolute path
      LINUX_KERNEL_PATH:=/usr/src/kernels/$(LINUX_KERNEL)
      #complie object
      all:
          make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
          rm -rf modules.order Module.symvers .*.cmd *.o *.mod.c .tmp_versions *.unsigned
      #clean
      clean:
          rm -rf modules.order Module.symvers .*.cmd *.o *.mod.c *.ko .tmp_versions *.unsigned
      View Code

      + 測試方法

      1. 將 test_export_A.c 和對應(yīng)的 Makefile 拷貝到 module_A 文件夾中

      2. 將 test_export_B.c 和對應(yīng)的 Makefile 拷貝到 module_B 文件夾中

      3. 編譯 module_A 中的 test_export_A.c

      4. 將編譯 module_A 后生成的 Module.symvers 拷貝到 module_B 文件夾中

      5. 編譯 module_B 中的 test_export_B.c

      6. 先安裝 模塊A,再安裝模塊B

      7. dmesg 查看log

      8. 用 rmmod 卸載模塊B 和 模塊A (注意卸載順序,先卸載B再卸載A)

      [root@vbox chap17]# ll
      total 8
      drwxrwxr-x 2 root root 4096 Dec  7 22:14 module_A
      drwxrwxr-x 2 root root 4096 Dec  7 22:14 module_B
      [root@vbox chap17]# ll module_A
      total 8
      -rw-r--r-- 1 root root 517 Dec  7 21:58 Makefile
      -rw-r--r-- 1 root root 893 Dec  7 21:58 test_export_A.c
      [root@vbox chap17]# ll module_B
      total 8
      -rw-r--r-- 1 root root 532 Dec  7 21:58 Makefile
      -rw-r--r-- 1 root root 830 Dec  7 21:58 test_export_B.c
      
      [root@vbox chap17]# cd module_A/
      [root@vbox module_A]# ll
      total 8
      -rw-r--r-- 1 root root 517 Dec  7 21:58 Makefile
      -rw-r--r-- 1 root root 893 Dec  7 21:58 test_export_A.c
      [root@vbox module_A]# make
      make -C /usr/src/kernels/2.6.32-279.el6.x86_64 M=/root/chap17/module_A modules
      make[1]: Entering directory `/usr/src/kernels/2.6.32-279.el6.x86_64'
        CC [M]  /root/chap17/module_A/test_export_A.o
        LD [M]  /root/chap17/module_A/export_A.o
        Building modules, stage 2.
        MODPOST 1 modules
        CC      /root/chap17/module_A/export_A.mod.o
        LD [M]  /root/chap17/module_A/export_A.ko.unsigned
        NO SIGN [M] /root/chap17/module_A/export_A.ko
      make[1]: Leaving directory `/usr/src/kernels/2.6.32-279.el6.x86_64'
      rm -rf modules.order .*.cmd *.o *.mod.c .tmp_versions *.unsigned
      [root@vbox module_A]# ll
      total 120
      -rw-r--r-- 1 root root 110452 Dec  7 22:31 export_A.ko
      -rw-r--r-- 1 root root    517 Dec  7 21:58 Makefile
      -rw-r--r-- 1 root root     69 Dec  7 22:31 Module.symvers
      -rw-r--r-- 1 root root    893 Dec  7 21:58 test_export_A.c
      
      [root@vbox module_A]# cd ../module_B
      [root@vbox module_B]# ll
      total 8
      -rw-r--r-- 1 root root 532 Dec  7 21:58 Makefile
      -rw-r--r-- 1 root root 830 Dec  7 21:58 test_export_B.c
      [root@vbox module_B]# cp ../module_A/Module.symvers .
      [root@vbox module_B]# ll
      total 12
      -rw-r--r-- 1 root root 532 Dec  7 21:58 Makefile
      -rw-r--r-- 1 root root  69 Dec  7 22:32 Module.symvers
      -rw-r--r-- 1 root root 830 Dec  7 21:58 test_export_B.c
      [root@vbox module_B]# make
      make -C /usr/src/kernels/2.6.32-279.el6.x86_64 M=/root/chap17/module_B modules
      make[1]: Entering directory `/usr/src/kernels/2.6.32-279.el6.x86_64'
        CC [M]  /root/chap17/module_B/test_export_B.o
        LD [M]  /root/chap17/module_B/export_B.o
        Building modules, stage 2.
        MODPOST 1 modules
        CC      /root/chap17/module_B/export_B.mod.o
        LD [M]  /root/chap17/module_B/export_B.ko.unsigned
        NO SIGN [M] /root/chap17/module_B/export_B.ko
      make[1]: Leaving directory `/usr/src/kernels/2.6.32-279.el6.x86_64'
      rm -rf modules.order Module.symvers .*.cmd *.o *.mod.c .tmp_versions *.unsigned
      [root@vbox module_B]# ll
      total 116
      -rw-r--r-- 1 root root 108596 Dec  7 22:32 export_B.ko
      -rw-r--r-- 1 root root    532 Dec  7 21:58 Makefile
      -rw-r--r-- 1 root root    830 Dec  7 21:58 test_export_B.c
      
      [root@vbox module_B]# insmod ../module_A/export_A.ko 
      [root@vbox module_B]# insmod export_B.ko 
      [root@vbox module_B]# dmesg | tail -18
      *************************
      ENTRY test_export_A!
      *************************
      
      
      
      
      
      *************************
      ENTRY test_export_B!
      *************************
      
      
      
      
      
      param from other module is : 100
      result from test_export_A: 110
      
      [root@vbox module_B]# rmmod export_B
      [root@vbox module_B]# rmmod export_A
      View Code 

      注:
      1. 必須把編譯模塊A后生成的 Module.symvers 拷貝到module_B 中再編譯模塊B,否在模塊B找不到模塊A導(dǎo)出的函數(shù)

      2. 先安裝模塊A,再安裝模塊B。

      3. 先卸載模塊B,再卸載模塊A。

      4. 安裝卸載如果不按照上面的順序,會有錯(cuò)誤提示,大家可以試試看。

      5. 我實(shí)驗(yàn)的系統(tǒng)是 CentOS6.3 x86_64

       

       

      3. 內(nèi)核對象

      2.6內(nèi)核中增加了一個(gè)引人注目的新特性--統(tǒng)一設(shè)備模型(device model)。

      統(tǒng)一設(shè)備模型的最初動機(jī)是為了實(shí)現(xiàn)智能的電源管理,linux 內(nèi)核為了實(shí)現(xiàn)智能電源管理,需要建立表示系統(tǒng)中所有設(shè)備拓?fù)潢P(guān)系的樹結(jié)構(gòu),

      這樣在關(guān)閉電源時(shí),可以從樹的節(jié)點(diǎn)開始關(guān)閉。

       

      實(shí)現(xiàn)了統(tǒng)一設(shè)備模型之后,還給內(nèi)核帶來了如下的好處:

      1. 代碼重復(fù)最小化(統(tǒng)一處理的東西多了)

      2. 可以列舉系統(tǒng)中所有設(shè)備,觀察它們的狀態(tài),并查看它們連接的總線

      3. 可以將系統(tǒng)中的全部設(shè)備以樹的形式完整,有效的展示出來--包括所有總線和內(nèi)部連接

      4. 可以將設(shè)備和其對應(yīng)的驅(qū)動聯(lián)系起來,反之亦然

      5. 可以將設(shè)備按照類型加以歸類,無需理解物理設(shè)備的拓?fù)浣Y(jié)構(gòu)

      6. 可以沿設(shè)備樹的葉子向其根的反向依次遍歷,以保證能以正確的順序關(guān)閉設(shè)備電源

       

      3.1 kobject 簡介

      統(tǒng)一設(shè)備模型的核心部分就是 kobject,通過下面對kobject結(jié)構(gòu)體的介紹,可以大致了解它是如何使得各個(gè)物理設(shè)備能夠以樹結(jié)構(gòu)的形式組織起來的。

       

      3.1.1. kobject

      kobject的定義在 <linux/kobject.h> 中

      struct kobject {
          const char        *name;                   /* kobject 名稱 */
          struct list_head    entry;               /* kobject 鏈表 */
          struct kobject        *parent;             /* kobject 的父對象,說明kobject是有層次結(jié)構(gòu)的 */
          struct kset        *kset;                   /* kobject 的集合,接下來有詳細(xì)介紹 */
          struct kobj_type    *ktype;              /* kobject 的類型,接下來有詳細(xì)介紹 */
          struct sysfs_dirent    *sd;                 /* 在sysfs中,這個(gè)結(jié)構(gòu)體表示kobject的一個(gè)inode結(jié)構(gòu)體,sysfs之后也會介紹 */
          struct kref        kref;                    /* 提供 kobject 的引用計(jì)數(shù) */
          /* 一些標(biāo)志位  */
          unsigned int state_initialized:1;       
          unsigned int state_in_sysfs:1;
          unsigned int state_add_uevent_sent:1;
          unsigned int state_remove_uevent_sent:1;
          unsigned int uevent_suppress:1;
      };
      View Code

       

      kobject 本身不代表什么實(shí)際的內(nèi)容,一般都是嵌在其他數(shù)據(jù)結(jié)構(gòu)中來發(fā)揮作用。(感覺有點(diǎn)像內(nèi)核數(shù)據(jù)結(jié)構(gòu)鏈表的節(jié)點(diǎn))

      比如 <linux/cdev.h> 中的 struct cdev (表示字符設(shè)備的struct)

      struct cdev {
          struct kobject kobj;    /* 嵌在 cdev 中的kobject */
          struct module *owner;   
          const struct file_operations *ops;
          struct list_head list;
          dev_t dev;
          unsigned int count;
      };

       

       

      cdev中嵌入了kobject之后,就可以通過 cdev->kboj.parent 建立cdev之間的層次關(guān)系,通過 cdev->kobj.entry 獲取關(guān)聯(lián)的所有cdev設(shè)備等。

      總之,嵌入了kobject之后,cdev設(shè)備之間就有了樹結(jié)構(gòu)關(guān)系,cdev設(shè)備和其他設(shè)備之間也有可層次關(guān)系。

       

      3.1.2. ktype

      ktype是為了描述一族的kobject所具有的普遍屬性,也就是將這一族的kobject的屬性統(tǒng)一定義一下,避免每個(gè)kobject分別定義。

      (感覺有點(diǎn)像面向?qū)ο笳Z言中的抽象類或者接口)

       

      ktype的定義很簡單,參見<linux/kobject.h>

      struct kobj_type {
          void (*release)(struct kobject *kobj);  /* kobject的引用計(jì)數(shù)降到0時(shí)觸發(fā)的析構(gòu)函數(shù),負(fù)責(zé)釋放和清理內(nèi)存的工作 */
          struct sysfs_ops *sysfs_ops;            /* sysfs操作相關(guān)的函數(shù) */
          struct attribute **default_attrs;       /* kobject 相關(guān)的默認(rèn)屬性 */
      }; 

      3.1.3. kset

      kset是kobject對象的集合體,可以所有相關(guān)的kobject置于一個(gè)kset之中,比如所有“塊設(shè)備”可以放在一個(gè)表示塊設(shè)備的kset中。

       

      kset的定義也不復(fù)雜,參見 <linux/kobject.h>

      struct kset {
          struct list_head list;    /* 表示kset中所有kobject的鏈表 */
          spinlock_t list_lock;     /* 用于保護(hù) list 的自旋鎖*/
          struct kobject kobj;      /* kset中嵌入的一個(gè)kobject,使得kset也可以表現(xiàn)的像一樣kobject一樣*/
          struct kset_uevent_ops *uevent_ops;  /* 處理kset中kobject的熱插拔事件 提供了與用戶空間熱插拔進(jìn)行通信的機(jī)制 */
      };

       

       

      kset和kobject之間的關(guān)系

      3.1.4. kobject,ktype和kset之間的關(guān)系

      這3個(gè)概念中,kobject是最基本的。kset和ktype是為了將kobject進(jìn)行分類,以便將共通的處理集中處理,從而減少代碼量,也增加維護(hù)性。

      這里kset和ktype都是為了將kobject進(jìn)行分類,為什么會有2中分類呢?

      從整個(gè)內(nèi)核的代碼來看,其實(shí)kset的數(shù)量是多于ktype的數(shù)量的,同一種ktype的kobject可以位于不同的kset中。

      做個(gè)不是很恰當(dāng)?shù)谋扔鳎绻裬object比作一個(gè)人的話,kset相當(dāng)于一個(gè)一個(gè)國家,ktype則相當(dāng)于人種(比如黃種人,白種人等等)。

      人種的類型只有少數(shù)幾個(gè),但是國家確有很多,人種的目的是描述一群人的共通屬性,而國家的目地則是為了管理一群人。

      同樣,ktype側(cè)重于描述,kset側(cè)重于管理。

       

      3.1.5. kref

      kref記錄kobject被引用的次數(shù),當(dāng)引用計(jì)數(shù)降到0的時(shí)候,則執(zhí)行release函數(shù)釋放相關(guān)資源。

       

      kref的定義參見:<linux/kref.h>

      struct kref {
          atomic_t refcount;  /* 只有一個(gè)表示引用計(jì)數(shù)的屬性,atomic_t 類型表示對它的訪問是原子操作 */
      };
      
      void kref_set(struct kref *kref, int num);  /* 設(shè)置引用計(jì)數(shù)的值 */
      void kref_init(struct kref *kref);          /* 初始化引用計(jì)數(shù) */
      void kref_get(struct kref *kref);           /* 增加引用計(jì)數(shù) +1 */
      int kref_put(struct kref *kref, void (*release) (struct kref *kref)); /* 減少引用計(jì)數(shù) -1 當(dāng)減少到0時(shí),釋放相應(yīng)資源 */
      View Code

       

      上面這些函數(shù)的具體實(shí)現(xiàn)可以參考內(nèi)核代碼  lib/kref.c

       

      3.2 kobject 操作

      kobject的相關(guān)都在 <linux/kobject.h> 中定義了,主要由以下一些:

      extern void kobject_init(struct kobject *kobj, struct kobj_type *ktype);  /* 初始化一個(gè)kobject,設(shè)置它是哪種ktype */
      extern int __must_check kobject_add(struct kobject *kobj,
                          struct kobject *parent,
                          const char *fmt, ...);   /* 設(shè)置此kobject的parent,將此kobject加入到現(xiàn)有對象層次結(jié)構(gòu)中 */
      extern int __must_check kobject_init_and_add(struct kobject *kobj,
                               struct kobj_type *ktype,
                               struct kobject *parent,
                               const char *fmt, ...); /* 初始化kobject,完成kobject_add 函數(shù)的功能*/
      
      extern void kobject_del(struct kobject *kobj); /* 將此kobject從現(xiàn)有對象層次結(jié)構(gòu)中取消 */
      
      extern struct kobject * __must_check kobject_create(void); /* 創(chuàng)建一個(gè)kobject,比kobject_init更常用 */
      extern struct kobject * __must_check kobject_create_and_add(const char *name,
                              struct kobject *parent); /* 創(chuàng)建一個(gè)kobject,并將其加入到現(xiàn)有對象層次結(jié)構(gòu)中 */
      
      extern int __must_check kobject_rename(struct kobject *, const char *new_name);  /* 改變kobject的名稱 */
      extern int __must_check kobject_move(struct kobject *, struct kobject *); /* 給kobject設(shè)置新的parent */
      
      extern struct kobject *kobject_get(struct kobject *kobj); /* 增加kobject的引用計(jì)數(shù) +1 */
      extern void kobject_put(struct kobject *kobj);            /* 減少kobject的引用計(jì)數(shù) -1 */
      
      extern char *kobject_get_path(struct kobject *kobj, gfp_t flag);  /* 生成并返回與給定的一個(gè)kobj和kset相關(guān)聯(lián)的路徑 */
      View Code

      上面這些函數(shù)的具體實(shí)現(xiàn)可以參考內(nèi)核代碼  lib/kobject.c

       

      4. sysfs

      sysfs是一個(gè)處于內(nèi)存中的虛擬文件系統(tǒng),它提供了kobject對象層次結(jié)構(gòu)的視圖。

      可以用下面這個(gè)命令來查看 /sys 的結(jié)構(gòu)

      tree /sys       # 顯示所有目錄和文件
      或者
      tree -L 1 /sys  # 只顯示一層目錄 

      4.1 sysfs中的kobject

      既然sysfs是kobject的視圖,那么內(nèi)核中肯定提供了在sysfs中操作kobject的API。

      kobject結(jié)構(gòu)體中與sysfs關(guān)聯(lián)的字段就是 「struct sysfs_dirent    *sd; 」這是一個(gè)目錄項(xiàng)結(jié)構(gòu),它表示kobject在sysfs中的位置。

      關(guān)于目錄項(xiàng),可以參考:《Linux內(nèi)核設(shè)計(jì)與實(shí)現(xiàn)》讀書筆記(十三)- 虛擬文件系統(tǒng)

       

      4.1.1. sysfs中添加和刪除kobject非常簡單,就是上面介紹的 kobject操作中提到的

      extern int __must_check kobject_add(struct kobject *kobj,
                          struct kobject *parent,
                          const char *fmt, ...);   /* 設(shè)置此kobject的parent,將此kobject加入到現(xiàn)有對象層次結(jié)構(gòu)中 */
      extern int __must_check kobject_init_and_add(struct kobject *kobj,
                               struct kobj_type *ktype,
                               struct kobject *parent,
                               const char *fmt, ...); /* 初始化kobject,完成kobject_add 函數(shù)的功能*/
      
      extern void kobject_del(struct kobject *kobj); /* 將此kobject從現(xiàn)有對象層次結(jié)構(gòu)中取消 */
      ... ...等等
      View Code

      添加了kobject之后,只會增加文件夾,不會增加文件。

      因?yàn)閗object在sysfs中就是映射成一個(gè)文件夾。

       

      添加刪除kobject的示例代碼如下:

      /******************************************************************************
       * @file    : test_kobject.c
       * @author  : wangyubin
       * @date    : Tue Dec 24 09:49:53 2013
       * 
       * @brief   : 測試 kobject的創(chuàng)建和刪除
       * history  : init
       ******************************************************************************/
      
      #include<linux/init.h>
      #include<linux/module.h>
      #include<linux/kernel.h>
      #include<linux/kobject.h>
      
      MODULE_LICENSE("Dual BSD/GPL");
      
      struct kobject* kobj = NULL;
      
      static int test_kobject_init(void)
      {
          /* 初始化kobject,并加入到sysfs中 */    
          kobj = kobject_create_and_add("test_kobject", NULL);
          
          /* 進(jìn)入內(nèi)核模塊 */
          printk(KERN_ALERT "*************************\n");
          printk(KERN_ALERT "test_kobject is inited!\n");
          printk(KERN_ALERT "*************************\n");
          
          return 0;
      }
      
      static void test_kobject_exit(void)
      {
          /* 如果 kobj 不為空,則將其從sysfs中刪除 */
          if (kobj != NULL)
              kobject_del(kobj);
          /* 退出內(nèi)核模塊 */
          printk(KERN_ALERT "*************************\n");
          printk(KERN_ALERT "test_kobject is exited!\n");
          printk(KERN_ALERT "*************************\n");
          printk(KERN_ALERT "\n\n\n\n\n");
      }
      
      module_init(test_kobject_init);
      module_exit(test_kobject_exit);
      View Code

      對應(yīng)的Makefile

      # must complile on customize kernel
      obj-m += mykobject.o
      mykobject-objs := test_kobject.o
      
      #generate the path
      CURRENT_PATH:=$(shell pwd)
      #the current kernel version number
      LINUX_KERNEL:=$(shell uname -r)
      #the absolute path
      LINUX_KERNEL_PATH:=/usr/src/kernels/$(LINUX_KERNEL)
      #complie object
      all:
          make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
          rm -rf modules.order Module.symvers .*.cmd *.o *.mod.c .tmp_versions *.unsigned
      #clean
      clean:
          rm -rf modules.order Module.symvers .*.cmd *.o *.mod.c *.ko .tmp_versions *.unsigned
      View Code

      測試方法:(我使用的測試系統(tǒng)是:Centos6.5 x86)

      [root@localhost test_kobject]# ll                             <-- 開始時(shí)只有2個(gè)文件,一個(gè)測試代碼,一個(gè)Makefile
      total 8
      -rw-r--r-- 1 root root 533 Dec 24 09:44 Makefile
      -rw-r--r-- 1 root root 908 Dec 24 09:44 test_kobject.c
      [root@localhost test_kobject]# make                           <-- 編譯用于測試的內(nèi)核模塊
      make -C /usr/src/kernels/2.6.32-431.el6.i686 M=/home/wyb/chap17/test_kobject modules
      make[1]: Entering directory `/usr/src/kernels/2.6.32-431.el6.i686'
        CC [M]  /home/wyb/chap17/test_kobject/test_kobject.o
        LD [M]  /home/wyb/chap17/test_kobject/mykobject.o
        Building modules, stage 2.
        MODPOST 1 modules
        CC      /home/wyb/chap17/test_kobject/mykobject.mod.o
        LD [M]  /home/wyb/chap17/test_kobject/mykobject.ko.unsigned
        NO SIGN [M] /home/wyb/chap17/test_kobject/mykobject.ko
      make[1]: Leaving directory `/usr/src/kernels/2.6.32-431.el6.i686'
      rm -rf modules.order Module.symvers .*.cmd *.o *.mod.c .tmp_versions *.unsigned
      [root@localhost test_kobject]# ll                             <-- 編譯后多出來的一個(gè)內(nèi)核模塊 ***.ko
      total 100
      -rw-r--r-- 1 root root   533 Dec 24 09:44 Makefile
      -rw-r--r-- 1 root root 91902 Dec 24 09:54 mykobject.ko
      -rw-r--r-- 1 root root   908 Dec 24 09:44 test_kobject.c
      [root@localhost test_kobject]# ll /sys/                        <-- 安裝內(nèi)核模塊 mykobject.ko 之前的 sysfs結(jié)構(gòu)
      total 0
      drwxr-xr-x  2 root root 0 Dec 24 09:28 block
      drwxr-xr-x 17 root root 0 Dec 24 09:28 bus
      drwxr-xr-x 40 root root 0 Dec 24 09:28 class
      drwxr-xr-x  4 root root 0 Dec 24 09:28 dev
      drwxr-xr-x 12 root root 0 Dec 24 09:28 devices
      drwxr-xr-x  4 root root 0 Dec 24 09:28 firmware
      drwxr-xr-x  3 root root 0 Dec 24 09:28 fs
      drwxr-xr-x  2 root root 0 Dec 24 09:44 hypervisor
      drwxr-xr-x  5 root root 0 Dec 24 09:28 kernel
      drwxr-xr-x 84 root root 0 Dec 24 09:46 module
      drwxr-xr-x  2 root root 0 Dec 24 09:44 power
      [root@localhost test_kobject]# insmod mykobject.ko              <-- 安裝內(nèi)核模塊 
      [root@localhost test_kobject]# ll /sys/                         <-- 安裝后,sysfs中多了一個(gè)文件夾 test_kobject
      total 0
      drwxr-xr-x  2 root root 0 Dec 24 09:28 block
      drwxr-xr-x 17 root root 0 Dec 24 09:28 bus
      drwxr-xr-x 40 root root 0 Dec 24 09:28 class
      drwxr-xr-x  4 root root 0 Dec 24 09:28 dev
      drwxr-xr-x 12 root root 0 Dec 24 09:28 devices
      drwxr-xr-x  4 root root 0 Dec 24 09:28 firmware
      drwxr-xr-x  3 root root 0 Dec 24 09:28 fs
      drwxr-xr-x  2 root root 0 Dec 24 09:44 hypervisor
      drwxr-xr-x  5 root root 0 Dec 24 09:28 kernel
      drwxr-xr-x 85 root root 0 Dec 24 09:54 module
      drwxr-xr-x  2 root root 0 Dec 24 09:44 power
      drwxr-xr-x  2 root root 0 Dec 24 09:55 test_kobject
      [root@localhost test_kobject]# ll /sys/test_kobject/             <-- 追加kobject只能增加文件夾,文件夾中是沒有文件的
      total 0
      [root@localhost test_kobject]# rmmod mykobject.ko                <-- 卸載內(nèi)核模塊
      [root@localhost test_kobject]# ll /sys/                          <-- 卸載后,sysfs 中的文件夾 test_kobject 也消失了
      total 0
      drwxr-xr-x  2 root root 0 Dec 24 09:28 block
      drwxr-xr-x 17 root root 0 Dec 24 09:28 bus
      drwxr-xr-x 40 root root 0 Dec 24 09:28 class
      drwxr-xr-x  4 root root 0 Dec 24 09:28 dev
      drwxr-xr-x 12 root root 0 Dec 24 09:28 devices
      drwxr-xr-x  4 root root 0 Dec 24 09:28 firmware
      drwxr-xr-x  3 root root 0 Dec 24 09:28 fs
      drwxr-xr-x  2 root root 0 Dec 24 09:44 hypervisor
      drwxr-xr-x  5 root root 0 Dec 24 09:28 kernel
      drwxr-xr-x 84 root root 0 Dec 24 09:55 module
      drwxr-xr-x  2 root root 0 Dec 24 09:44 power
      View Code 

      4.1.2. sysfs中添加文件

      kobject是映射成sysfs中的目錄,那sysfs中的文件是什么呢?

      其實(shí)sysfs中的文件就是kobject的屬性,屬性的來源有2個(gè):

      + 默認(rèn)屬性 :: kobject所關(guān)聯(lián)的ktype中的 default_attrs 字段

      默認(rèn)屬性 default_attrs 的類型是結(jié)構(gòu)體 struct attribute, 定義在 <linux/sysfs.h>

      struct attribute {
          const char        *name;   /* sysfs文件樹中的文件名 */
          struct module        *owner; /* x86體系結(jié)構(gòu)中已經(jīng)不再繼續(xù)使用了,可能在其他體系結(jié)構(gòu)中還會使用 */
          mode_t            mode;   /* sysfs中該文件的權(quán)限 */
      };

      ktype中的 default_attrs 字段(即默認(rèn)屬性)描述了sysfs中的文件,還有一個(gè)字段 sysfs_ops 則描述了如何使用默認(rèn)屬性。

      struct sysfs_ops 的定義也在 <linux/sysfs.h>

      struct sysfs_ops {
          /* 在讀sysfs文件時(shí)該方法被調(diào)用 */
          ssize_t    (*show)(struct kobject *kobj, struct attribute *attr,char *buffer);
          /* 在寫sysfs文件時(shí)該方法被調(diào)用 */
          ssize_t    (*store)(struct kobject *kobj,struct attribute *attr,const char *buffer, size_t size);
      };

       

      show 方法在讀取sysfs中文件時(shí)調(diào)用,它會拷貝attr提供的屬性到buffer指定的緩沖區(qū)

      store  方法在寫sysfs中文件時(shí)調(diào)用,它會從buffer中讀取size字節(jié)的數(shù)據(jù)到attr提供的屬性中

       

      增加默認(rèn)屬性的示例代碼

      /******************************************************************************
       * @file    : test_kobject_default_attr.c
       * @author  : wangyubin
       * @date    : Tue Dec 24 10:28:09 2013
       * 
       * @brief   : 測試 kobject 的默認(rèn)屬性的創(chuàng)建和刪除
       * history  : init
       ******************************************************************************/
      
      #include<linux/init.h>
      #include<linux/module.h>
      #include<linux/kernel.h>
      #include<linux/kobject.h>
      #include<linux/sysfs.h>
      
      MODULE_LICENSE("Dual BSD/GPL");
      
      static void myobj_release(struct kobject*);
      static ssize_t my_show(struct kobject *, struct attribute *, char *);
      static ssize_t my_store(struct kobject *, struct attribute *, const char *, size_t);
      
      /* 自定義的結(jié)構(gòu)體,2個(gè)屬性,并且嵌入了kobject */
      struct my_kobj 
      {
          int ival;
          char* cname;
          struct kobject kobj;
      };
      
      static struct my_kobj *myobj = NULL;
      
      /* my_kobj 的屬性 ival 所對應(yīng)的sysfs中的文件,文件名 val */
      static struct attribute val_attr = {
          .name = "val",
          .owner = NULL,
          .mode = 0666,
      };
      
      /* my_kobj 的屬性 cname 所對應(yīng)的sysfs中的文件,文件名 name */
      static struct attribute name_attr = {
          .name = "name",
          .owner = NULL,
          .mode = 0666,
      };
      
      static int test_kobject_default_attr_init(void)
      {
          struct attribute *myattrs[] = {NULL, NULL, NULL};
          struct sysfs_ops *myops = NULL;
          struct kobj_type *mytype = NULL;
      
          /* 初始化 myobj */
          myobj = kmalloc(sizeof(struct my_kobj), GFP_KERNEL);
          if (myobj == NULL)
              return -ENOMEM;
      
          /* 配置文件 val 的默認(rèn)值 */
          myobj->ival = 100;
          myobj->cname = "test";
      
          /* 初始化 ktype */
          mytype = kmalloc(sizeof(struct kobj_type), GFP_KERNEL);
          if (mytype == NULL)
              return -ENOMEM;
      
          /* 增加2個(gè)默認(rèn)屬性文件 */
          myattrs[0] = &val_attr;
          myattrs[1] = &name_attr;
      
          /* 初始化ktype的默認(rèn)屬性和析構(gòu)函數(shù) */
          mytype->release = myobj_release;
          mytype->default_attrs = myattrs;
      
          /* 初始化ktype中的 sysfs */
          myops = kmalloc(sizeof(struct sysfs_ops), GFP_KERNEL);
          if (myops == NULL)
              return -ENOMEM;
      
          myops->show = my_show;
          myops->store = my_store;
          mytype->sysfs_ops = myops;
      
          /* 初始化kobject,并加入到sysfs中 */
          memset(&myobj->kobj, 0, sizeof(struct kobject)); /* 這一步非常重要,沒有這一步init kobject會失敗 */
          if (kobject_init_and_add(&myobj->kobj, mytype, NULL, "test_kobj_default_attr"))
              kobject_put(&myobj->kobj);
      
          printk(KERN_ALERT "*************************\n");
          printk(KERN_ALERT "test_kobject_default_attr is inited!\n");
          printk(KERN_ALERT "*************************\n");
          
          return 0;
      }
      
      static void test_kobject_default_attr_exit(void)
      {
          kobject_del(&myobj->kobj);
          kfree(myobj);
          
          /* 退出內(nèi)核模塊 */
          printk(KERN_ALERT "*************************\n");
          printk(KERN_ALERT "test_kobject_default_attr is exited!\n");
          printk(KERN_ALERT "*************************\n");
          printk(KERN_ALERT "\n\n\n\n\n");
      }
      
      static void myobj_release(struct kobject *kobj) 
      {
          printk(KERN_ALERT, "release kobject");
          kobject_del(kobj);
      }
      
      /* 讀取屬性文件 val 或者name時(shí)會執(zhí)行此函數(shù) */
      static ssize_t my_show(struct kobject *kboj, struct attribute *attr, char *buf) 
      {
          printk(KERN_ALERT "SHOW -- attr-name: [%s]\n", attr->name);    
          if (strcmp(attr->name, "val") == 0)
              return sprintf(buf, "%d\n", myobj->ival);
          else
              return sprintf(buf, "%s\n", myobj->cname);
      }
      
      /* 寫入屬性文件 val 或者name時(shí)會執(zhí)行此函數(shù) */
      static ssize_t my_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t len) 
      {
          printk(KERN_ALERT "STORE -- attr-name: [%s]\n", attr->name);
          if (strcmp(attr->name, "val") == 0)
              sscanf(buf, "%d\n", &myobj->ival);
          else
              sscanf(buf, "%s\n", myobj->cname);        
          return len;
      }
      
      module_init(test_kobject_default_attr_init);
      module_exit(test_kobject_default_attr_exit);
      View Code

      對應(yīng)的Makefile如下:

      # must complile on customize kernel
      obj-m += mykobject_with_default_attr.o
      mykobject_with_default_attr-objs := test_kobject_default_attr.o
      
      #generate the path
      CURRENT_PATH:=$(shell pwd)
      #the current kernel version number
      LINUX_KERNEL:=$(shell uname -r)
      #the absolute path
      LINUX_KERNEL_PATH:=/usr/src/kernels/$(LINUX_KERNEL)
      #complie object
      all:
          make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
          rm -rf modules.order Module.symvers .*.cmd *.o *.mod.c .tmp_versions *.unsigned
      #clean
      clean:
          rm -rf modules.order Module.symvers .*.cmd *.o *.mod.c *.ko .tmp_versions *.unsigned
      View Code

      測試方法:(我使用的測試系統(tǒng)是:Centos6.5 x86)

      ############################ 編譯 ########################################################
      [root@localhost test_kobject_defalt_attr]# ll
      total 8
      -rw-r--r-- 1 root root  582 Dec 24 15:02 Makefile
      -rw-r--r-- 1 root root 4032 Dec 24 16:58 test_kobject_default_attr.c
      [root@localhost test_kobject_defalt_attr]# make
      make -C /usr/src/kernels/2.6.32-431.el6.i686 M=/home/wyb/chap17/test_kobject_defalt_attr modules
      make[1]: Entering directory `/usr/src/kernels/2.6.32-431.el6.i686'
        CC [M]  /home/wyb/chap17/test_kobject_defalt_attr/test_kobject_default_attr.o
      /home/wyb/chap17/test_kobject_defalt_attr/test_kobject_default_attr.c: In function ‘myobj_release’:
      /home/wyb/chap17/test_kobject_defalt_attr/test_kobject_default_attr.c:109: warning: too many arguments for format
        LD [M]  /home/wyb/chap17/test_kobject_defalt_attr/mykobject_with_default_attr.o
        Building modules, stage 2.
        MODPOST 1 modules
        CC      /home/wyb/chap17/test_kobject_defalt_attr/mykobject_with_default_attr.mod.o
        LD [M]  /home/wyb/chap17/test_kobject_defalt_attr/mykobject_with_default_attr.ko.unsigned
        NO SIGN [M] /home/wyb/chap17/test_kobject_defalt_attr/mykobject_with_default_attr.ko
      make[1]: Leaving directory `/usr/src/kernels/2.6.32-431.el6.i686'
      rm -rf modules.order Module.symvers .*.cmd *.o *.mod.c .tmp_versions *.unsigned
      [root@localhost test_kobject_defalt_attr]# ll
      total 104
      -rw-r--r-- 1 root root   582 Dec 24 15:02 Makefile
      -rw-r--r-- 1 root root 96805 Dec 24 16:58 mykobject_with_default_attr.ko
      -rw-r--r-- 1 root root  4032 Dec 24 16:58 test_kobject_default_attr.c
      
      ############################ 安裝 ########################################################
      [root@localhost test_kobject_defalt_attr]# insmod mykobject_with_default_attr.ko 
      [root@localhost test_kobject_defalt_attr]# ll /sys/                           <-- kobject對應(yīng)的文件夾
      total 0
      drwxr-xr-x  2 root root 0 Dec 24 15:50 block
      drwxr-xr-x 17 root root 0 Dec 24 15:50 bus
      drwxr-xr-x 40 root root 0 Dec 24 15:50 class
      drwxr-xr-x  4 root root 0 Dec 24 15:50 dev
      drwxr-xr-x 12 root root 0 Dec 24 15:50 devices
      drwxr-xr-x  4 root root 0 Dec 24 15:50 firmware
      drwxr-xr-x  3 root root 0 Dec 24 15:50 fs
      drwxr-xr-x  2 root root 0 Dec 24 16:06 hypervisor
      drwxr-xr-x  5 root root 0 Dec 24 15:50 kernel
      drwxr-xr-x 85 root root 0 Dec 24 16:59 module
      drwxr-xr-x  2 root root 0 Dec 24 16:06 power
      drwxr-xr-x  2 root root 0 Dec 24 16:59 test_kobj_default_attr
      [root@localhost test_kobject_defalt_attr]# ll /sys/test_kobj_default_attr/    <-- kobject的2個(gè)屬性文件
      total 0
      -rw-rw-rw- 1 root root 4096 Dec 24 16:59 name
      -rw-rw-rw- 1 root root 4096 Dec 24 16:59 val
      [root@localhost test_kobject_defalt_attr]# dmesg                              <-- dmesg 中只有初始化的信息
      *************************
      test_kobject_default_attr is inited!
      *************************
      
      ############################  讀取屬性文件 ###############################################
      [root@localhost test_kobject_defalt_attr]# cat /sys/test_kobj_default_attr/val  <-- 屬性值就是我們在測試代碼中輸入的值
      100
      [root@localhost test_kobject_defalt_attr]# cat /sys/test_kobj_default_attr/name <-- 屬性值就是我們在測試代碼中輸入的值
      test
      [root@localhost test_kobject_defalt_attr]# dmesg                              <-- dmesg 中多了2條讀取屬性文件的log
      SHOW -- attr-name: [val]
      SHOW -- attr-name: [name]
      
      ############################ 寫入屬性文件 ################################################
      [root@localhost test_kobject_defalt_attr]# echo "200" > /sys/test_kobj_default_attr/val         <-- val文件中寫入 200
      [root@localhost test_kobject_defalt_attr]# echo "abcdefg" > /sys/test_kobj_default_attr/name    <-- name文件中寫入 adcdefg
      [root@localhost test_kobject_defalt_attr]# dmesg                              <-- dmesg 中又多了2條寫入屬性文件的log
      STORE -- attr-name: [val]
      STORE -- attr-name: [name]
      [root@localhost test_kobject_defalt_attr]# cat /sys/test_kobj_default_attr/val     <-- 再次查看 val文件中的值,已變?yōu)?00
      200
      [root@localhost test_kobject_defalt_attr]# cat /sys/test_kobj_default_attr/name    <-- 再次查看 name文件中的值,已變?yōu)閍bcdefg
      abcdefg
      
      ############################ 卸載 ########################################################
      [root@localhost test_kobject_defalt_attr]# rmmod mykobject_with_default_attr.ko
      View Code

      :參考博客 Linux設(shè)備模型 (2)

       

      + 新屬性 :: kobject 自己定義的屬性

      一般來說,使用默認(rèn)屬性就足夠了。因?yàn)榫哂泄餐琸type的kobject在本質(zhì)上區(qū)別都不大,比如都是塊設(shè)備的kobject,

      它們使用默認(rèn)的屬性集合不但可以讓事情簡單,有助于代碼合并,還可以使類似的對象在sysfs中的外觀一致。

       

      在一些特殊的情況下,kobject可能會需要自己特有的屬性。內(nèi)核也充分考慮到了這些情況,提供了創(chuàng)建或者刪除新屬性的方法。

      在sysfs中文件的操作方法參見: fs/sysfs/file.c

      /* 文件的相關(guān)操作非常多,這里只列出創(chuàng)建文件和刪除文件的方法 */
      
      /**
       * 給 kobj 增加一個(gè)新的屬性 attr
       * kobj 對應(yīng)sysfs中的一個(gè)文件夾, attr 對應(yīng)sysfs中的一個(gè)文件
       */
      int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
      {
          BUG_ON(!kobj || !kobj->sd || !attr);
      
          return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);
      
      }
      
      /**
       * 給 kobj 刪除一個(gè)新的屬性 attr
       * kobj 對應(yīng)sysfs中的一個(gè)文件夾, attr 對應(yīng)sysfs中的一個(gè)文件
       */
      void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr)
      {
          sysfs_hash_and_remove(kobj->sd, attr->name);
      }
      View Code 

      除了可以在sysfs中增加/刪除的文件,還可以在sysfs中增加或者刪除一個(gè)符號鏈接。

      具體實(shí)現(xiàn)參見:fs/sysfs/symlink.c

      /* 下面只列出了創(chuàng)建和刪除符號鏈接的方法,其他方法請參考 symlink.c 文件 */
      
      /**
       * 在kobj對應(yīng)的文件夾中創(chuàng)建一個(gè)符號鏈接指向 target
       * 符號鏈接的名稱就是 name
       */
      int sysfs_create_link(struct kobject *kobj, struct kobject *target,
                    const char *name)
      {
          return sysfs_do_create_link(kobj, target, name, 1);
      }
      
      
      void sysfs_remove_link(struct kobject * kobj, const char * name)
      {
          struct sysfs_dirent *parent_sd = NULL;
      
          if (!kobj)
              parent_sd = &sysfs_root;
          else
              parent_sd = kobj->sd;
      
          sysfs_hash_and_remove(parent_sd, name);
      }
      View Code 

      增加新的屬性的示例代碼 (這里只演示了增加文件的方法,增加符號鏈接的方法與之類似)

      /******************************************************************************
       * @file    : test_kobject_new_attr.c
       * @author  : wangyubin
       * @date    : Tue Dec 24 17:10:31 2013
       * 
       * @brief   : 測試 kobject 中增加和刪除新屬性
       * history  : init
       ******************************************************************************/
      
      #include<linux/init.h>
      #include<linux/module.h>
      #include<linux/kernel.h>
      #include<linux/kobject.h>
      #include<linux/sysfs.h>
      
      MODULE_LICENSE("Dual BSD/GPL");
      
      static void myobj_release(struct kobject*);
      static ssize_t my_show(struct kobject *, struct attribute *, char *);
      static ssize_t my_store(struct kobject *, struct attribute *, const char *, size_t);
      
      /* 自定義的結(jié)構(gòu)體,其中嵌入了kobject,通過屬性 c_attr 來控制增加或者刪除新屬性 */
      struct my_kobj 
      {
          int c_attr;                 /* 值為0:刪除新屬性, 值為1:增加新屬性*/
          int new_attr;
          struct kobject kobj;
      };
      
      static struct my_kobj *myobj = NULL;
      
      /* my_kobj 的屬性 c_attr 所對應(yīng)的sysfs中的文件,文件名 c_attr */
      static struct attribute c_attr = {
          .name = "c_attr",
          .owner = NULL,
          .mode = 0666,
      };
      
      /* 用于動態(tài)增加或者刪除的新屬性 */
      static struct attribute new_attr = {
          .name = "new_attr",
          .owner = NULL,
          .mode = 0666,
      };
      
      static int test_kobject_new_attr_init(void)
      {
          struct attribute *myattrs[] = {NULL, NULL};
          struct sysfs_ops *myops = NULL;
          struct kobj_type *mytype = NULL;
      
          /* 初始化 myobj */
          myobj = kmalloc(sizeof(struct my_kobj), GFP_KERNEL);
          if (myobj == NULL)
              return -ENOMEM;
      
          /* 配置文件 val 的默認(rèn)值 */
          myobj->c_attr = 0;
      
          /* 初始化 ktype */
          mytype = kmalloc(sizeof(struct kobj_type), GFP_KERNEL);
          if (mytype == NULL)
              return -ENOMEM;
      
          /* 增加1個(gè)默認(rèn)屬性文件 */
          myattrs[0] = &c_attr;
      
          /* 初始化ktype的默認(rèn)屬性和析構(gòu)函數(shù) */
          mytype->release = myobj_release;
          mytype->default_attrs = myattrs;
      
          /* 初始化ktype中的 sysfs */
          myops = kmalloc(sizeof(struct sysfs_ops), GFP_KERNEL);
          if (myops == NULL)
              return -ENOMEM;
      
          myops->show = my_show;
          myops->store = my_store;
          mytype->sysfs_ops = myops;
      
          /* 初始化kobject,并加入到sysfs中 */
          memset(&myobj->kobj, 0, sizeof(struct kobject)); /* 這一步非常重要,沒有這一步init kobject會失敗 */
          if (kobject_init_and_add(&myobj->kobj, mytype, NULL, "test_kobj_new_attr"))
              kobject_put(&myobj->kobj);
      
          printk(KERN_ALERT "*************************\n");
          printk(KERN_ALERT "test_kobject_new_attr is inited!\n");
          printk(KERN_ALERT "*************************\n");
          
          return 0;
      }
      
      static void test_kobject_new_attr_exit(void)
      {
          kobject_del(&myobj->kobj);
          kfree(myobj);
          
          /* 退出內(nèi)核模塊 */
          printk(KERN_ALERT "*************************\n");
          printk(KERN_ALERT "test_kobject_new_attr is exited!\n");
          printk(KERN_ALERT "*************************\n");
          printk(KERN_ALERT "\n\n\n\n\n");
      }
      
      static void myobj_release(struct kobject *kobj) 
      {
          printk(KERN_ALERT "release kobject");
          kobject_del(kobj);
      }
      
      /* 讀取屬性文件 c_attr 或者 new_attr 時(shí)會執(zhí)行此函數(shù) */
      static ssize_t my_show(struct kobject *kboj, struct attribute *attr, char *buf) 
      {
          printk(KERN_ALERT "SHOW -- attr-name: [%s]\n", attr->name);
          if (strcmp(attr->name, "c_attr") == 0)
              return sprintf(buf, "%d\n", myobj->c_attr);
          else if (strcmp(attr->name, "new_attr") == 0)
              return sprintf(buf, "%d\n", myobj->new_attr);
      
          return 0;
      }
      
      /* 寫入屬性文件c_attr 或者 new_attr 時(shí)會執(zhí)行此函數(shù) */
      static ssize_t my_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t len) 
      {
          printk(KERN_ALERT "STORE -- attr-name: [%s]\n", attr->name);
          if (strcmp(attr->name, "c_attr") == 0)
              sscanf(buf, "%d\n", &myobj->c_attr);
          else if (strcmp(attr->name, "new_attr") == 0)
              sscanf(buf, "%d\n", &myobj->new_attr);
      
          if (myobj->c_attr == 1)     /* 創(chuàng)建新的屬性文件 */
          {
              if (sysfs_create_file(kobj, &new_attr))
                  return -1;
              else
                  myobj->new_attr = 100; /* 新屬性文件的值默認(rèn)設(shè)置為 100  */
          }
          
          if (myobj->c_attr == 0)     /* 刪除新的屬性文件 */
              sysfs_remove_file(kobj, &new_attr);
          
          return len;
      }
      
      module_init(test_kobject_new_attr_init);
      module_exit(test_kobject_new_attr_exit);
      View Code

      對應(yīng)的Makefile如下:

      # must complile on customize kernel
      obj-m += mykobject_with_new_attr.o
      mykobject_with_new_attr-objs := test_kobject_new_attr.o
      
      #generate the path
      CURRENT_PATH:=$(shell pwd)
      #the current kernel version number
      LINUX_KERNEL:=$(shell uname -r)
      #the absolute path
      LINUX_KERNEL_PATH:=/usr/src/kernels/$(LINUX_KERNEL)
      #complie object
      all:
          make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
          rm -rf modules.order Module.symvers .*.cmd *.o *.mod.c .tmp_versions *.unsigned
      #clean
      clean:
          rm -rf modules.order Module.symvers .*.cmd *.o *.mod.c *.ko .tmp_versions *.unsigned
      View Code 

      測試方法:(我使用的測試系統(tǒng)是:Centos6.5 x86)

      根據(jù)測試代碼,增加/刪除新屬性是根據(jù)默認(rèn)屬性 c_attr 的值來決定的。

      c_attr 設(shè)置為0 時(shí),刪除新屬性 new_attr

      c_attr 設(shè)置為1 時(shí),新增新屬性 new_attr

      ############################ 編譯,安裝,卸載同測試默認(rèn)屬性時(shí)一樣 #######################
      ... 省略 ...
      ############################ 動態(tài)增加新屬性文件 #########################################
      [root@localhost test_kobject_new_attr]# ll /sys/test_kobj_new_attr/            <-- 默認(rèn)沒有新屬性 new_attr
      total 0
      -rw-rw-rw- 1 root root 4096 Dec 24 18:47 c_attr
      [root@localhost test_kobject_new_attr]# cat /sys/test_kobj_new_attr/c_attr     <-- c_attr 的值為0
      0
      [root@localhost test_kobject_new_attr]# echo "1" > /sys/test_kobj_new_attr/c_attr <-- c_attr 的值設(shè)為1
      [root@localhost test_kobject_new_attr]# ll /sys/test_kobj_new_attr/            <-- 增加了新屬性 new_attr
      total 0
      -rw-rw-rw- 1 root root 4096 Dec 24 19:02 c_attr
      -rw-rw-rw- 1 root root 4096 Dec 24 19:02 new_attr
      
      ############################ 動態(tài)刪除屬性文件 ###########################################
      [root@localhost test_kobject_new_attr]# echo "0" > /sys/test_kobj_new_attr/c_attr   <-- c_attr 的值為0
      [root@localhost test_kobject_new_attr]# ll /sys/test_kobj_new_attr/                 <-- 刪除了新屬性 new_attr
      total 0
      -rw-rw-rw- 1 root root 4096 Dec 24 19:03 c_attr
      View Code 

      4.1.3. sysfs相關(guān)約定

      為了保持sysfs的干凈和直觀,在內(nèi)核開發(fā)中涉及到sysfs相關(guān)內(nèi)容時(shí),需要注意以下幾點(diǎn):

      + sysfs屬性保證每個(gè)文件只導(dǎo)出一個(gè)值,該值為文本形式并且可以映射為簡單的C類型

      + sysfs中要以一個(gè)清晰的層次組織數(shù)據(jù)

      + sysfs提供內(nèi)核到用戶空間的服務(wù)

       

      4.2 基于sysfs的內(nèi)核事件

      內(nèi)核事件層也是利用kobject和sysfs來實(shí)現(xiàn)的,用戶空間通過監(jiān)控sysfs中kobject的屬性的變化來異步的捕獲內(nèi)核中kobject發(fā)出的信號。

      用戶空間可以通過一種netlink的機(jī)制來獲取內(nèi)核事件。

      內(nèi)核空間向用戶空間發(fā)送信號使用 kobject_uevent() 函數(shù),具體參見: <linux/kobject.h>

      int kobject_uevent(struct kobject *kobj, enum kobject_action action);

       

      下面用個(gè)小例子演示一些內(nèi)核事件的實(shí)現(xiàn)原理:

      4.2.1. 內(nèi)核模塊安裝或者刪除時(shí),會發(fā)送 KOBJ_ADD 或者 KOBJ_REMOVE 的消息

      內(nèi)核模塊的代碼就用上面最簡單的那個(gè)例子 test_kobject.c 的代碼即可

       

      4.2.2. 用戶態(tài)程序: 通過 netlink機(jī)制來接收 kobject 的事件通知

      /******************************************************************************
       * @file    : test_netlink_client.c
       * @author  : wangyubin
       * @date    : Tue Dec 24 19:48:54 2013
       * 
       * @brief   : 通過 netlink機(jī)制接收kobject發(fā)出的信號
       * history  : init
       ******************************************************************************/
      
      #include <stdio.h>  
      #include <stdlib.h>  
      #include <string.h>  
      #include <errno.h>  
      #include <sys/types.h>  
      #include <asm/types.h>  
      #include <sys/socket.h>    
      #include <linux/netlink.h>  
      
      void MonitorNetlinkUevent()  
      {  
          int sockfd;  
          struct sockaddr_nl sa;  
          int len;  
          char buf[4096];  
          struct iovec iov;  
          struct msghdr msg;  
          int i;  
        
          memset(&sa,0,sizeof(sa));  
          sa.nl_family = AF_NETLINK;  
          sa.nl_groups = NETLINK_KOBJECT_UEVENT;  
          sa.nl_pid = 0;//getpid(); both is ok  
          memset(&msg,0,sizeof(msg));  
          iov.iov_base = (void *)buf;  
          iov.iov_len = sizeof(buf);  
          msg.msg_name = (void *)&sa;  
          msg.msg_namelen = sizeof(sa);  
          msg.msg_iov = &iov;  
          msg.msg_iovlen = 1;  
        
          sockfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);  
          if(sockfd == -1)  
              printf("socket creating failed:%s\n",strerror(errno));  
          if(bind(sockfd,(struct sockaddr *)&sa,sizeof(sa)) == -1)  
              printf("bind error:%s\n", strerror(errno));  
          while(1) {  
            memset(buf, 0, sizeof(buf));  
            len=recvmsg(sockfd, &msg, 0);  
            if(len < 0){}  
              //printf("receive error\n");  
            else if(len < 32||len > sizeof(buf))  
              printf("invalid message");  
            for(i=0; i<len; i++)  
              if(*(buf+i) == '\0')  
                  buf[i] = '\n';  
            printf("received %d bytes\n%s\n", len, buf);  
          }  
      }  
      
      int main(int argc, char *argv[])
      {
          MonitorNetlinkUevent();
          return 0;
      }
      View Code

       

      :代碼是拷貝的 《Linux設(shè)備節(jié)點(diǎn)創(chuàng)建》內(nèi)核kobject上報(bào)uevent過濾規(guī)則 中的用戶態(tài)程序部分

       

      4.2.3. 測試方法:(我使用的測試系統(tǒng)是:Centos6.5 x86)

      ############################ 編譯并啟動用戶態(tài)程序 (窗口1)###################################
      [root@localhost test_kobject_event]# ll
      total 4
      -rw-r--r-- 1 root root 1846 Dec 24 20:36 test_netlink_client.c
      [root@localhost test_kobject_event]# gcc -o test_netlink_client test_netlink_client.c     <-- 編譯用戶態(tài)程序
      [root@localhost test_kobject_event]# ./test_netlink_client                                <-- 啟動后等待內(nèi)核kobject的事件到來
      
      ############################ 安裝內(nèi)核模塊并查看用戶態(tài)程序輸出 (窗口2)#######################
      [root@localhost test_kobject]# insmod mykobject.ko                         <-- 在窗口2中安裝內(nèi)核模塊,窗口1中會接收到 KOBJ_ADD 信號
      ############################ 卸載內(nèi)核模塊并查看用戶態(tài)程序輸出 (窗口2)#######################
      [root@localhost test_kobject]# rmmod mykobject.ko                          <-- 在窗口2中安裝內(nèi)核模塊,窗口1中會接收到 KOBJ_REMOVE 信號
      View Code

       

      5. 總結(jié)

      kobject加sysfs給內(nèi)核帶來的好處不是三言兩語能夠說得清楚的,上面的例子也只是通過簡單的使用來直觀的感受一下kobject,例子本身沒有什么實(shí)際意義。

      最后一個(gè)例子中使用了 netlink機(jī)制,我在之前的項(xiàng)目中使用過netlink來監(jiān)控系統(tǒng)進(jìn)程的I/O信息,對netlink有一些初步的了解。

      但是例子中只是用來獲取一下 kobject的事件而已,這里主要為了說明kobject,netlink的相關(guān)內(nèi)容以后有機(jī)會再補(bǔ)充。

      posted @ 2017-08-25 15:27  閆寶平  閱讀(477)  評論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 97久久综合亚洲色hezyo| 亚洲中文字幕无码中字| 免费无码一区二区三区蜜桃| 中文字幕人妻有码久视频| 色就色中文字幕在线视频| 五原县| 国产午夜福利不卡在线观看| 精品久久丝袜熟女一二三| 国产国产乱老熟女视频网站97| 亚洲午夜爱爱香蕉片| 精品国产成人午夜福利| 亚洲成人av在线资源| 久久精品女人天堂av| 狠狠躁夜夜躁人人爽天天5| 久久国产精品精品国产色| 久99久热只有精品国产99| 嘉祥县| 麻豆一区二区三区香蕉视频| 亚洲蜜臀av乱码久久| 亚洲一区二区三区播放| 一个人看的www视频免费观看| 日韩伦理片一区二区三区| 亚洲AV乱码毛片在线播放| 亚洲欧美另类久久久精品播放的| 国产麻豆精品一区一区三区| 最新亚洲人成无码网站欣赏网| 日韩精品中文字幕人妻| 熟妇人妻中文a∨无码| 久久91精品牛牛| 亚洲高清日韩专区精品| 国产乱人伦真实精品视频| 丰满岳乱妇三级高清| 日韩精品亚洲专在线电影| 欧美日韩国产综合草草| 挺进粗大尤物人妻中文字幕| 国产精品二区中文字幕| 国产乱码精品一区二三区| 日韩全网av在线| 国产成人综合色视频精品| 亚洲女人天堂成人av在线| 国内精品久久久久影视|