歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

利用Kprobe探測內核中的變量

今天遇到一個問題,需要探測內核中buffer cache block的大小。我想到了Kprobe這個神奇的工具,並且很好的探測到了內核中的變量值,非常的方便,在此分享一下。

采用dd等工具寫設備的時候,是需要經過塊設備層的buffer cache,當請求塊大小小於buffer cache的block_size時,Linux的策略是首先需要從磁盤load數據至buffer cache,然後再將新寫入的“局部數據”寫入buffer cache。這一步驟完成之後,會將整個buffer cache標識成dirty,掛載到設備所屬的radix tree上,然後定時喚醒後台writeback線程刷新dirty block至磁盤。今天對linux-3.2和linux-2.6.23的順序寫進行了對比測試,發現請求大小在512至2048之間時,Linux-3.2的性能居然比Linux-2.6.23還差。測試後得到的性能特征似乎與buffer cache的塊大小有關系,因此,我采用Kprobe對兩個版本的塊大小進行了探測驗證。

為了探測這個值,首先需要找一個合適的探測點,根據代碼分析的結果,我選擇在__block_write_begin函數中調用create_empty_buffers函數時的機會點,采用Kprobe插入一段代碼,打印buffer cache block_size的值。探測點位置的源代碼如下所示:

int __block_write_begin(struct page *page, loff_t pos, unsigned len,
get_block_t *get_block)
{
。。。

blocksize = 1 << inode->i_blkbits;
if (!page_has_buffers(page))
create_empty_buffers(page, blocksize, 0);
head = page_buffers(page);
bbits = inode->i_blkbits;
block = (sector_t)page->index << (PAGE_CACHE_SHIFT - bbits);
。。。
}

通過上面函數,我們知道blocksize就是buffer cache block塊大小,因此,我們可以截獲create_empty_buffers函數之後,打印傳入的第二個參數就可以得到buffer cache塊大小值了。截獲create_empty_buffers函數很簡單,通過kallsyms_lookup_name函數或者/proc/kallsyms就可以得到截獲函數對應的內存地址。關鍵的問題在於截獲這個函數之後,我們如果得到他的第二個參數,這就關系到函數的參數傳遞問題了。

在X86_64平台上,Linux的參數傳遞通過如下9個寄存器完成,分別為:RDI,RSI,RDX,RCX,RAX,R8,R9,R10,R11。在pre_handler函數中,我們可以得到寄存器組變量,通過寄存器組變量我們可以通過RSI寄存器得到create_empty_buffers函數傳入的第二個參數值。對於Linux-2.6.23版本,函數調用過程中寄存器在棧中布局定義如下:

struct pt_regs {
unsigned long r15;
unsigned long r14;
unsigned long r13;
unsigned long r12;
unsigned long rbp;
unsigned long rbx;
/* arguments: non interrupts/non tracing syscalls only save upto here*/
unsigned long r11;
unsigned long r10;
unsigned long r9;
unsigned long r8;
unsigned long rax;
unsigned long rcx;
unsigned long rdx;
unsigned long rsi;
unsigned long rdi;
unsigned long orig_rax;
/* end of arguments */
/* cpu exception frame or undefined */
unsigned long rip;
unsigned long cs;
unsigned long eflags;
unsigned long rsp;
unsigned long ss;
/* top of stack page */
}; 

Copyright © Linux教程網 All Rights Reserved