的write方法有哪些引數_一文讀懂 Linux 核心執行時引數配置
技術標籤:的write方法有哪些引數
作者簡介:Daemon.Wu, Linux 核心效能優化工程師,就職於某微小手機廠從事手機效能優化。座右銘:知行合一。
版權宣告:本文最先發表於“泰曉科技” 微信公眾號,歡迎轉載,轉載時請在文章的開頭保留本宣告。
Linux 核心執行時配置簡介
Linux 核心的子系統有各種配置引數,比如記憶體管理中記憶體回收的水位資訊,CPU 排程中的各種排程器配置資訊,檔案回寫中 dirty page 的配置等。
無需修改核心原始碼,使用者就可以通過 sysctl 命令在執行時設定這些引數。
具體的配置引數可以檢視核心文件目錄 Documentation/sysctl/
sysctl 命令配置舉例
比如,設定記憶體子系統的 dropcaches
引數,可使用:
$systcl-wvm.drop_caches=1
sysctl 命令使用了哪些介面
使用 strace 追蹤 sysctl 命令的系統呼叫可發現該命令最終是訪問 /proc/sys/drop_caches
這個檔案。
[email protected]:~$sudostracesysctl-wvm.drop_caches=1
execve("/sbin/sysctl",["sysctl","-w","vm.drop_caches=1"],[/*16vars*/])=0
brk(NULL)=0x2016000
...
stat("/proc/sys/vm/drop_caches",{st_mode=S_IFREG|0200,st_size=0,...})=0
open("/proc/sys/vm/drop_caches",O_WRONLY|O_CREAT|O_TRUNC,0666)=3
fstat(3,{st_mode=S_IFREG|0200,st_size=0,...})=0
write(3,"1\n",2)=2
close(3)=0
fstat(1,{st_mode=S_IFCHR|0620,st_rdev=makedev(136,1),...})=0
write(1,"vm.drop_caches=1\n",19vm.drop_caches=1
)=19
close(1)=0
close(2)=0
exit_group(0)=?
+++exitedwith0+++
由此就可知,systcl 命令是通過 /proc/sys/
目錄下的各個介面檔案實現配置的。該目錄下包含以下子目錄:
[email protected]:/proc/sys$tree-L1
.
├──abi
├──debug
├──dev#裝置相關資訊
├──fs#特定的檔案系統,比如fd,inode,dentry,quotatuning
├──kernel#tuning全域性引數,比如cpu排程,printk,softirq,hung_task,numa,watchdog等
├──net#網路子系統相關引數,比如ipv4,ipv6,icmp,igmp等
└──vm#tuning記憶體管理相關引數,buffer和cache的管理
sysctl 介面暨 procfs 工作流程
那麼在核心中各子系統是如何匯出這些引數到 procfs,並允許使用者通過 echo, cat 等工具操作這些節點來設定引數的呢?
在 kernel/sysctl.c
中定義了某個子系統下的某個引數的相關 ctl_table
,比如 vm.dropcaches
。
- 先設定 vm 目錄的引數,訪問許可權為 555,並設定 child 屬性為
vm_table
。 vm_table
結構體陣列包含了 VM 子系統的引數,比如dropcaches
引數,設定了該節點的訪問許可權為 644;data 屬性值為sysctl_drop_caches
,該變數在fs/drop_caches.c
中定義;- 該節點的讀寫處理函式
drop_caches_sysctl_hander
,在fs/drop_caches.c
中實現,通過dointvec_minmax
來讀出資料 。 - 最後填充好
ctl_table
結構體後在sysctl_init
入口函式註冊這些結構體陣列。
相關程式碼如下:
/*Thedefaultsysctltables:*/
staticstructctl_tablesysctl_base_table[]={
{
.procname="kernel",///proc/sys/kernel
.mode=0555,
.child=kern_table,
},
{
.procname="vm",///proc/sys/vm
.mode=0555,
.child=vm_table,
},
{
.procname="fs",///proc/sys/fs
.mode=0555,
.child=fs_table,
},
{
.procname="debug",///proc/sys/debug
.mode=0555,
.child=debug_table,
},
{
.procname="dev",///proc/sys/dev
.mode=0555,
.child=dev_table,
},
{}
};
staticstructctl_tablevm_table[]={
...
{
.procname="drop_caches",
.data=&sysctl_drop_caches,
.maxlen=sizeof(int),//vm.drop_caches變數4各位元組
.mode=0644,///proc/sys/vm/drop_caches訪問許可權"644"
.proc_handler=drop_caches_sysctl_handler,//handler
.extra1=&one,
.extra2=&four,
},
...
};
int__initsysctl_init(void)
{
structctl_table_header*hdr;
//註冊ctl_table
hdr=register_sysctl_table(sysctl_base_table);
kmemleak_not_leak(hdr);
return0;
}
intdrop_caches_sysctl_handler(structctl_table*table,intwrite,
void__user*buffer,size_t*length,loff_t*ppos)
{
intret;
ret=proc_dointvec_minmax(table,write,buffer,length,ppos);
if(ret)
returnret;
if(write){//如果是寫資料
staticintstfu;
if(sysctl_drop_caches&1){
//如果drop_caches=1則清pagecache
iterate_supers(drop_pagecache_sb,NULL);
count_vm_event(DROP_PAGECACHE);
}
if(sysctl_drop_caches&2){
//如果drop_caches=2則清pagecache和slab
drop_slab();
count_vm_event(DROP_SLAB);
}
if(!stfu){
pr_info("%s(%d):drop_caches:%d\n",
current->comm,task_pid_nr(current),
sysctl_drop_caches);
}
stfu|=sysctl_drop_caches&4;
}
return0;
}
通過上述分析,大致梳理了 sysctl 介面在 kernel 中執行的大致流程。
如何新增一個 sysctl 介面
接下來,學以致用,我們可以在 /proc/sys
這個根目錄下寫一個 my_sysctl
的節點,首先定義並填充 ctl_table
結構體,並通過 register_sysctl_table
註冊到系統。
#include
#include
#include
staticintdata;
staticstructctl_table_header*my_ctl_header;
intmy_sysctl_callback(
structctl_table*table,
intwrite,void__user*buffer,
size_t*lenp,loff_t*ppos)
{
intrc=proc_dointvec(
table,write,buffer,lenp,ppos);
if(write){
printk("writeoperation,curdata=%d\n",
*((unsignedint*)table->data));
}
}
/*Thedefaultsysctltables:*/
staticstructctl_tablemy_sysctl_table[]={
{
.procname="my_sysctl",
.mode=0644,
.data=&data,
.maxlen=sizeof(unsignedint),
.proc_handler=my_sysctl_callback,
},
{
},
};
staticint__initsysctl_test_init(void)
{
printk("sysctltestinit...\n");
my_ctl_header=register_sysctl_table(my_sysctl_table);
return0;
}
staticvoid__exitsysctl_test_exit(void)
{
printk("sysctltestexit...\n");
unregister_sysctl_table(my_ctl_header);
}
通過 qemu 進入目標檔案系統,使用 insmod 註冊驅動,在 /proc/sys
目錄下出現 my_sysctl
節點,此時就可以通過 cat/echo
命令向該節點讀寫資料,也可以直接通過 systcl 設定該引數。
/mnt#insmodsysctl_test.ko
[89.904485]sysctltestinit...
/mnt#sysctlmy_sysctl
my_sysctl=0
/mnt#sysctl-wmy_sysctl=2
[151.278213]writeoperation,curdata=2
/mnt#sysctlmy_sysctl
my_sysctl=2
/mnt#cat/proc/sys/my_sysctl
2
為簡便起見,大家也可以直接用 Linux Lab 來快速開展實驗,具體可以參考 “Linux Lab 文件的 4.1.2 節” https://gitee.com/tinylab/linux-lab#412-使用核心模組。
❝獎金+贈書+星球會員,"泰曉科技" 社群推出三大舉措加速原創孵化,速速看過來(請點選下方圖片連結):
❞
掃 碼關 注 我們
再 + 好 友 tinylab
進 泰 曉技 術群
泰 曉 科 技
關注“泰曉科技”!點“在看”