Kenel Model 測試node
本內核模塊測試主要是由三個子系統組成:用戶態測試,內核態測試和接口測試。內核態測試經過編寫內核模塊代碼,直接對avl原文件進行測試,能夠執行全部的指令。出於運行安全的考慮,用戶態的進程沒法直接訪問硬件和內核的內存空間,而是經過字符設備(ioctl)進入內核態調用,用戶態測試時能夠看到內核態經過printk函數的輸出。接口測試用於檢測內核態與用戶態之間的交互點,重點是要檢查數據的交換,傳遞和控制管理過程,以及相互邏輯依賴關係等。整體結構以下:安全
avl的測試包括下圖幾個方面,以add爲例,具體說明avl函數接口測試的實現。框架
1、 內核態函數
Module中首先須要建立的文件有:avlat-test.h,avlat-add.c,Makefile.in 。其中avlat-test.h是包含全部測試的頭文件(仿造spl內核模塊編寫便可),avlat-add.c是測試文件,Makefile.in是輔助編譯生成文件(4.2中已提到)。測試
增長結點有三種狀況:增長單個結點,增長多個結點,增長已存在結點。對應於這三種狀況,能夠設計三個測試用例。ui
1.增長單個結點spa
static int avlat_add_test_1(struct file *file, void *arg) { avl_tree_t *avl_test_tree; avlat_t *avlat_node, *first_node, *last_node; uint32_t avl_value=5, rc = 0; // step1: initial avl
avl_test_tree = kmalloc(sizeof(*avl_test_tree), GFP_KERNEL); avl_create(avl_test_tree, avl_test_compare, sizeof (avlat_t), offsetof(avlat_t, avl_node)); if (avl_numnodes(avl_test_tree) != 0) { printk("Error: avlat_add_test_1-1.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step2: add sigle avl node and check avl_numnodes
avlat_node = kmalloc(sizeof(*avlat_node), GFP_KERNEL); avlat_node->avl_key=avl_value; avl_add(avl_test_tree, avlat_node); if (avl_numnodes(avl_test_tree) != 1) { printk("Error: avlat_add_test_1-2.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step3: check avl_first & avl_last
first_node = avl_first(avl_test_tree); last_node = avl_last(avl_test_tree); if ((first_node->avl_key != last_node->avl_key) || (first_node->avl_key != avl_value)) { printk("Error: avlat_add_test_1-3.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step4: remove avl node
avl_remove(avl_test_tree, avlat_node); if (avl_numnodes(avl_test_tree) != 0) { printk("Error: avlat_add_test_1-4.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } kfree(avlat_node); // step5: destroy avl node
avl_destroy(avl_test_tree); kfree(avl_test_tree); return rc; }
2.增長多個結點設計
增長結點的測試用例爲{10, 99, 178, 106, 7, 4, 44, 55, 1765, 200},以下圖:3d
代碼:code
static int avlat_add_test_2(struct file *file, void *arg) { avl_tree_t *avl_test_tree; avlat_t *avlat_node[10], *first_node, *last_node; uint32_t key_value[10]={10, 99, 178, 106, 7, 4, 44, 55, 1765, 200}; uint32_t i, num=10, rc=0; // step1: initial avl
avl_test_tree = kmalloc(sizeof(*avl_test_tree), GFP_KERNEL); avl_create(avl_test_tree, avl_test_compare, sizeof (avlat_t), offsetof(avlat_t, avl_node)); if (avl_numnodes(avl_test_tree) != 0) { printk("Error: avlat_add_test_2-1.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step2: add multiple avl node and check avl_numnodes
for (i=0; i<num; i++) { avlat_node[i] = kmalloc(sizeof(*avlat_node[i]), GFP_KERNEL); avlat_node[i]->avl_key=key_value[i]; avl_add(avl_test_tree, avlat_node[i]); } if (avl_numnodes(avl_test_tree) != num) { printk("Error: avlat_add_test_2-2.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step3: check avl_first
first_node = avl_first(avl_test_tree); if (first_node->avl_key != 4) { printk("Error: avlat_add_test_2-3.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step4: check avl_last
last_node = avl_last(avl_test_tree); if (last_node->avl_key != 1765) { printk("Error: avlat_add_test_2-4.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step5: remove first avl node
avl_remove(avl_test_tree, avlat_node[1]); if (avl_numnodes(avl_test_tree) != (num-1)) { printk("Error: avlat_add_test_2-5.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } kfree(avlat_node[1]); // step6: check avl_first
first_node = avl_first(avl_test_tree); if (first_node->avl_key != 4) { printk("Error: avlat_add_test_2-6.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step7: check avl_last
last_node = avl_last(avl_test_tree); if (last_node->avl_key != 1765) { printk("Error: avlat_add_test_2-7.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step8: remove all avl nodes
for (i=0; i<num; i++) { if (i==1) { continue; } avl_remove(avl_test_tree, avlat_node[i]); kfree(avlat_node[i]); } if (avl_numnodes(avl_test_tree) != 0) { printk("Error: avlat_add_test_2-8.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step9: destroy avl node
avl_destroy(avl_test_tree); kfree(avl_test_tree); return rc; }
3.增長已存在結點
增長已存在的結點的,會報錯。
代碼:
static int avlat_add_test_3(struct file *file, void *arg) { avl_tree_t *avl_test_tree; avlat_t *avlat_node, *first_node, *last_node; uint32_t avl_value=12, rc=0; // step1: initial avl
avl_test_tree = kmalloc(sizeof(*avl_test_tree), GFP_KERNEL); avl_create(avl_test_tree, avl_test_compare, sizeof (avlat_t), offsetof(avlat_t, avl_node)); if (avl_numnodes(avl_test_tree) != 0) { printk("Error: avlat_add_test_2-1.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step2: add sigle avl node and check avl_numnodes
avlat_node = kmalloc(sizeof(*avlat_node), GFP_KERNEL); avlat_node->avl_key=avl_value; avl_add(avl_test_tree, avlat_node); if (avl_numnodes(avl_test_tree) != 1) { printk("Error: avlat_add_test_3-2.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } /*// step3: add exists avl node and check avl_numnodes avl_add(avl_test_tree, avlat_node); if (avl_numnodes(avl_test_tree) != 1) { printk("Error: avlat_add_test_3-3.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; }*/ // step4: check avl_first & avl_last
first_node = avl_first(avl_test_tree); last_node = avl_last(avl_test_tree); if ((first_node->avl_key != last_node->avl_key) || (first_node->avl_key != avl_value)) { printk("Error: avlat_add_test_3-4.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } // step5: remove avl node
avl_remove(avl_test_tree, avlat_node); if (avl_numnodes(avl_test_tree) != 0) { printk("Error: avlat_add_test_3-5.\n"); avlat_destroy_avl_tree(avl_test_tree); rc = ERRNO_INFO_NUM; return rc; } kfree(avlat_node); // step6: destroy avl node
avl_destroy(avl_test_tree); kfree(avl_test_tree); return rc; }
2、用戶態
在cmd文件夾中的avlat文件夾中建立avlat.h和avlat.c,搭建用戶態框架。能夠直接經過虛擬機執行指令,主要指令用法以下:
3、用戶態和內核態的通訊
用戶態和內核態的通訊經過ioctl來實現,用戶態經過ioctl接口設備進入內核態調用。在module文件夾中新建文件avlat-ctl.c,並在include中創建頭文件avlat-ctl.h,來具體實現ioctl接口通訊。
申請設備:
ioctl接口在內核態的主要實現關鍵代碼:
static long avlat_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int rc = 0; /* Ignore tty ioctls */ if ((cmd & 0xffffff00) == ((int)'T') << 8) return -ENOTTY; switch (cmd) { case AVLAT_CFG: rc = avlat_ioctl_cfg(file, cmd, arg); break; case AVLAT_CMD: rc = avlat_ioctl_cmd(file, cmd, arg); break; default: avlat_print(file, "Bad ioctl command %d\n", cmd); rc = -EINVAL; break; } return rc; }
ioctl接口在用戶態的調用:
用戶態進入內核態調用運行結果:
標註:此篇僅用以說明內核模塊測試的用戶態和內核態的交互經過代碼具體實現的思路,不包含具體代碼及代碼指導。