Development
Debug
如何新增一個 Block device attribute 在 /sys 下面
最簡單的方式可以透過以下的 macro 來達成
DEVICE_ATTR(_name, _mode, _show, _store)
另外針對 bus 或是 class 等 /sys 位置,還有 BUS_ATTR 與 CLASS_ATTR 可使用,使用方式與 DEVICE_ATTR 大同小異
在參數的部分講解如下 _name:在 sys fs 下生成的檔案名稱 _mode:生成檔案的權限 _show:讀取的 callback function,影響 cat 這個檔案會顯示什麼 _store: 寫入的 callback function,寫入檔案發生什麼
show 的 callback function 的簡單範例如下
static ssize_t xxx_show(struct device *dev,struct device_attribute *attr, char *buf)
{
return scnprintf(buf, PAGE_SIZE, "%d\n", XXX_flag);
}
關於這邊為什麼要用 scnprintf 而不是 snprintf,網路上有人做過研究 總結來說,snprintf 回傳的結果是 預期的字串長度(src 的長度) 而非實際寫入長度(可參考LWN),相反的 scnprintf 是回傳實際寫入的長度(可能 src 比 des 長,就會受限在 des 的長度),如果是要作為 function 回傳寫入字串的長度,scnprintf 就會是比較安全的選擇
store 的 callback function 的簡單範例如下
static ssize_t xxx_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
if (!strncmp(buf, 0, &num))
debug_on = false;
else
debug_on = true;
return count;
}
當定義好 show 與 store function 之後,接著就需要定義 device attritube
static DEVICE_ATTR(xxx, 0666, xxx_show, xxx_store);
定義之後不會就這樣生效,還需要在 device init 的時候加上這麼一段
ret = device_create_file(dev->device, &dev_attr_xxx);
if (ret != 0) {
dev_err(&pdev->dev,"Failed to create xxx sysfs files: %d\n", ret);
return ret;
}
並在 device exit 時加上
device_remove_file(dev->device, &dev_attr_ioerror_debug);
Tracing
blktrace
Introduction
blktrace 可用於記錄與分析 block 層處理 IO 的狀態
Prerequisite
- Enable CONFIG_BLK_DEV_IO_TRACE
- Get userspace tool from git://git.kernel.org/pub/scm/linux/kernel/git/axboe/blktrace.git
Usage
在使用之前,需要先做以下兩件事
- 開啟 tracing 後 kernel module 必須全部重 build
- 進入 blktrace 的資料夾,進行 make,並將 blktrace 與 blkparse 抓到機器上面
進入機器之後需要檢查 debugfs file system 有沒有 mount 起來,如果沒有則需要執行
mount -t debugfs debugfs /sys/kernel/debug
接著先介紹最基本使用方式
blktrace -d <Target device> -o - | blkparse -i -
此時如何有 IO 到 device 就會出現如同以下的訊息
<1> <2> <3> <4> <5> <6> <7><8> <9>
8,0 3 1 0.000000000 697 G W 223490 + 8 [kjournald]
8,0 3 2 0.000001829 697 P R [kjournald]
8,0 3 3 0.000002197 697 Q W 223490 + 8 [kjournald]
8,0 3 4 0.000005533 697 M W 223498 + 8 [kjournald]
8,0 3 5 0.000008607 697 M W 223506 + 8 [kjournald]
8,0 3 6 0.000011569 697 M W 223514 + 8 [kjournald]
8,0 3 7 0.000014407 697 M W 223522 + 8 [kjournald]
8,0 3 8 0.000017367 697 M W 223530 + 8 [kjournald]
8,0 3 9 0.000020161 697 M W 223538 + 8 [kjournald]
8,0 3 10 0.000024062 697 D W 223490 + 56 [kjournald]
8,0 1 11 0.009507758 0 C W 223490 + 56 [0]
8,0 1 12 0.009538995 697 G W 223546 + 8 [kjournald]
8,0 1 13 0.009540033 697 P R [kjournald]
8,0 1 14 0.009540313 697 Q W 223546 + 8 [kjournald]
8,0 1 15 0.009542980 697 D W 223546 + 8 [kjournald]
8,0 1 16 0.013542170 0 C W 223546 + 8 [0]
依序解析每一個欄位的意思為
- Device major, minor
- CPU ID
- Sequence number (用途不明)
- Time stamp
- PID
- Action
- RWBS field
- Start block + number of block
- Process name
關於 RWBS field 一共有以下數種
R: Read
W: Write
B: Barrier
S: Synchronous
N: (目前沒看到相關的定義)
而 action 方面還看的懂的部分約有以下數種
- C: Complete,表示 IO 不論成功或是失敗,已經由下層 driver 處理完畢並回覆結果
- D: Issued/Dispatch,表示 Block layer 這一層該做的工作都已經完成,並將 IO 遞交給底層 driver
- I: Inserted,IO 已經被送入 IO scheduler 之類的地方等待進行處理
- Q: Queued,block layer 準備把上層的 BIO queue 起來,從文件上面的說明,這個時候 IO 還沒有正式進到 block layer 之中。
其他還有一些 action 因為沒有看懂完全的用途,等未來有用到時再補上來
Reference
- https://www.mimuw.edu.pl/~lichota/09-10/Optymalizacja-open-source/Materialy/10%20-%20Dysk/gelato_ICE06apr_blktrace_brunelle_hp.pdf
- https://www.cse.unsw.edu.au/~aaronc/iosched/doc/blktrace.html
Event tracing
https://lwn.net/Articles/379903/ https://github.com/spotify/linux/blob/master/Documentation/trace/events.txt