linux Proc檔案系統介紹及運用總結
引言
先說一個剛剛發現的問題:
前兩天開啟測試機發現速度非常慢,top一看,發現java佔用CPU 99%
檢視對應pid,發現這個是新的話單採集程式gather:
#ps -ef | grep java Root 5762 1 99 14:41 pts/0 00:00:01 java -Xmx2048m -jar Gather-jar-with-dependencies.jar |
採集程式的工作是啟動4個執行緒,不斷從FTP上讀取檔案。檢視日誌,發現FTP上並沒有檔案,4個執行緒每隔一段時間去檢查一下FTP,所有執行緒都在正常寫日誌。看上去一切正常。
檢視程序狀態:
#cat /proc/5762/status Name: java State: S (sleeping) …… Threads: 5689 …… |
看到threads為5689的時候,真正冒了身冷汗。只啟動了4個執行緒,怎麼會出現這麼多執行緒呢?
由於這個程序已經運行了比較久的時間,測試目錄又比較多,這個程序是從哪個目錄開始的呢?
#ll /proc/9323/cwd lrwxrwxrwx 1 root root 0 Jun 8 11:51 /proc/9323/cwd -> /home/admin/work/BLTransfer/src/gather/20110509_56847_taobao-bn_2 |
到這個目錄,檢視版本的gather程式碼,發現FTP呼叫後在某個返回路徑上沒有呼叫close方法。
檢視FTP4j原始碼,發現FTP在呼叫setAutoNoopTimeout和Login後會呼叫startAutoNoopTimer()新啟一個執行緒定時處理無操作的情況。此外,在傳輸資料時FTPDataTransfer也會新開執行緒。
修改程式碼後,恢復正常。
PROC簡介
上處檢視的/proc/5762/status和/proc/9323/cwd正是proc檔案系統下的檔案。
與其它常見的檔案系統不同的是,Proc檔案系統並不是真正意義上的檔案系統,它存在於記憶體中,並不佔用磁碟空間,它包含一些結構化的目錄和虛擬檔案,向用戶呈現核心中的一些資訊,也可以用作一種從使用者空間向核心傳送資訊的手段。
這些虛擬檔案使用檢視命令檢視時會返回大量資訊,但檔案本身的大小卻會顯示為0位元組。此外,這些特殊檔案中大多數檔案的時間及日期屬性通常為當前系統時間和日期。
事實上,如ps、top等很多shell命令正是從proc系統中讀取資訊,且更具可讀性。
接下來,將詳細介紹proc檔案系統中每個檔案的資訊情況。
一、常見PROC檔案含義
/proc目錄下,每個程序都會有一個以PID命名的目錄,存放關於這個程序的資訊,同時還有許多相對固定的目錄,以存放與系統相關的資訊:
[[email protected] proc]$ ls /proc/ 1 10 2331 ……(每個程序一個目錄,略去) buddyinfo execdomains kallsyms misc stat vmstat bus fb kcore modules swaps xen cmdline filesystems keys mounts sys zoneinfo cpuinfo fs key-users net sysrq-trigger crypto ide kmsg partitions sysvipc devices interrupts loadavg schedstat tty diskstats iomem locks scsi uptime dma ioports mdstat self version driver irq meminfo slabinfo vmcore |
通過這些檔案,可以檢視大量系統資訊,例如CPU資訊、記憶體資訊、linux版本資訊等:
[[email protected] ~]$ cat /proc/cpuinfo processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 26 model name : Intel(R) Xeon(R) CPU E5504 @ 2.00GHz stepping : 5 cpu MHz : 2000.070 cache size : 4096 KB …… [[email protected] ~]$ cat /proc/version Linux version 2.6.18-131.el5.customxen ([email protected]) (gcc version 4.1.2 20071124 (Red Hat 4.1.2-42)) #1 SMP Tue Sep 15 15:46:11 CST 2009 |
先來看一下程序目錄的子目錄:
[[email protected] proc]$ ls /proc/22567 attr cmdline cpuset environ fd loginuid mem mountstats oom_score schedstat stat status wchan auxv coredump_filter cwd exe limits maps mounts oom_adj root smaps statm task |
主要檔案的含義總結如下:
檔名 |
內容 |
檔名 |
內容 |
cmdline |
程序啟動時的命令列引數 |
root |
指向程序根目錄 |
environ |
環境變更的值 |
stat |
程序狀態 |
cwd |
當前工作路徑 |
status |
程序狀態(友好) |
exe |
程序相關的可執行檔案 |
stack |
棧記錄(需CONFIG_STACKTRACE) |
fd |
檔案描述符目錄 |
smaps |
Maps擴充套件,顯示每個mapping的記憶體 |
maps |
可執行檔案和庫檔案圖 |
mem |
程序佔用的記憶體 |
例如:以目前的通話伺服器程式ECPWORKER為例,它的當前目錄和可執行檔案相關資訊如下:
[[email protected] proc]$ ll /proc/22559/cwd /proc/22559/exe lrwxrwxrwx 1 admin admin 0 06-09 09:00 /proc/22559/cwd -> /home/admin/work/ecpworker/bin lrwxrwxrwx 1 admin admin 0 06-09 09:00 /proc/22559/exe -> /home/admin/work/ecpworker/bin/ecp-master-worker |
它所有開啟的檔案描述符為:
[[email protected] proc]$ ll /proc/22559/fd lr-x------ 1 admin admin 64 06-09 08:58 0 -> /dev/null l-wx------ 1 admin admin 64 06-09 08:58 1 -> /home/admin/work/ecpworker/log/debug.log l-wx------ 1 admin admin 64 06-09 08:58 3 -> /home/admin/work/ecpworker/log/status/ecp_status.log l-wx------ 1 admin admin 64 06-09 08:58 4 -> /home/admin/work/ecpworker/log/error/ecp_error.log l-wx------ 1 admin admin 64 06-09 08:58 5 -> /home/admin/work/ecpworker/log/epollstatus/ecp_epoll_status.log lrwx------ 1 admin admin 64 06-09 08:58 10 -> socket:[79444512] lrwx------ 1 admin admin 64 06-09 08:58 12 -> socket:[79444514] lrwx------ 1 admin admin 64 06-09 08:58 14 -> socket:[79444516] lrwx------ 1 admin admin 64 06-09 08:58 16 -> socket:[79444518] lrwx------ 1 admin admin 64 06-09 08:58 18 -> socket:[79444520] lrwx------ 1 admin admin 64 06-09 08:58 20 -> socket:[79444522] lrwx------ 1 admin admin 64 06-09 08:58 22 -> socket:[79444524] lrwx------ 1 admin admin 64 06-09 08:58 24 -> socket:[79444526] lrwx------ 1 admin admin 64 06-09 08:58 26 -> socket:[79444528] lrwx------ 1 admin admin 64 06-09 08:58 28 -> socket:[79444530] lrwx------ 1 admin admin 64 06-09 08:58 30 -> socket:[79444532] lrwx------ 1 admin admin 64 06-09 08:58 32 -> socket:[79444534] lrwx------ 1 admin admin 64 06-09 08:58 34 -> socket:[79444536] lrwx------ 1 admin admin 64 06-09 08:58 36 -> socket:[79444538] lr-x------ 1 admin admin 64 06-09 08:58 6 -> eventpoll:[79444508] lrwx------ 1 admin admin 64 06-09 08:58 7 -> socket:[79444509] lrwx------ 1 admin admin 64 06-09 08:58 8 -> socket:[79444510] |
從中可以看出,它打開了4個日誌檔案,16個socket連線,以及一個eventpoll。而我們程式的設計方案,正是1個主程序開啟15個等待程序,主程序通過1個socket接收各子程序訊息,各子程序各開1個socket接收請求,通過epoll來排程響應。
二、檔案描述符限制修改
由於我們每接收一個請求,都會新分配一塊記憶體給它,並新開一個socket連線到電信,因此我們非常關心最大連線數。
這裡需要區分一下:
1、 系統最大檔案數可在/proc/sys/fs/file-max檔案中查詢(數值確實很大,但需要知道系統有這樣一個總數限制),而目前系統使用的檔案控制代碼數則在/proc/sys/fs/file-nr中:
[[email protected] SOURCES]$ cat /proc/sys/fs/file-max 544202 [[email protected] SOURCES]$ cat /proc/sys/fs/file-nr 2040 0 544202 |
2、 一個程序允許開啟的最大檔案數,可以用ulimit命令檢視:
[[email protected] SOURCES]$ ulimit –n core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 44064 max locked memory (kbytes, -l) 32 max memory size (kbytes, -m) unlimited open files (-n) 10240 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 10240 cpu time (seconds, -t) unlimited max user processes (-u) 44064 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited |
這個表中同時還包含了使用者最大程序數,訊息佇列最大數等。
當然,也可以在每個程序的proc目錄中找到更詳細的值:
[[email protected] proc]$ cat /proc/22559/limits Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 10485760 unlimited bytes Max core file size 0 unlimited bytes Max resident set unlimited unlimited bytes Max processes 44064 44064 processes Max open files 10240 10240 files Max locked memory 32768 32768 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 44064 44064 signals Max msgqueue size 819200 819200 bytes |
可以看出,目前,我們系統中已經將值設定為較大的10240。如果你發現你機子上的這些值為預設的1024,那麼最好還是調大一些,這個值對於伺服器來說很容易不夠用的。通過在檔案/etc/security/limits.conf中增加下面兩行可以設定此值,重新登陸生效:
* soft nofile 10240
* hard nofile 20480
當然,一般來說,如果需要增大系統設定的socket最大連線數,還需要修改原始檔並重新編譯:
1、修改/usr/src/kernels/2.6.18-131.el5.custom-x86_64/include/linux/posix_types.h
#undef __FD_SETSIZE
#define __FD_SETSIZE 10240 原值為1024
2、修改/usr/src/kernels/2.6.18-131.el5.custom-x86_64/include/linux/limits.h
#define NR_OPEN 90240 原值為1024
#define OPEN_MAX 10240 原值為1024
3、修改/usr/src/kernels/2.6.18-131.el5.custom-x86_64/include/linux/fs.h
#define INR_OPEN 10240 原值為1024
#define NR_FILE 65536 原值為8192
#define NR_RESERVED_FILES 128 原值為10.
4、修改/usr/src/kernels/2.6.18-131.el5.custom-x86_64/include/net /tcp.h
#define TCP_LHTABLE_SIZE 128 原值為32
5、重新編譯核心即可。
三、程序記憶體對映與動態庫載入
可以使用/proc/PID/maps和/proc/PID/smaps來檢視程序的記憶體對映,包括庫檔案和堆、棧等。
#cat /proc/23698/maps 00400000-00424000 r-xp ca:01 14778415 /home/admin/levy/SMSServer/trunk/bin/SMSServer 00625000-00626000 rw-p 00625000 00:00 0 1236a000-1238b000 rw-p 1236a000 00:00 0 3ce7e00000-3ce7e1c000 r-xp 00000000 ca:01 2097322 /lib64/ld-2.5.so 3ce8551000-3ce8556000 rw-p 3ce8551000 00:00 0 3ce8600000-3ce8602000 r-xp 00000000 ca:01 2097447 /lib64/libdl-2.5.so 3ce8e00000-3ce8e16000 r-xp 00000000 ca:01 2097462 /lib64/libpthread-2.5.so 3ce9017000-3ce901b000 rw-p 3ce9017000 00:00 0 3ce9600000-3ce9607000 r-xp 00000000 ca:01 2097463 /lib64/librt-2.5.so 3cfa000000-3cfa00d000 r-xp 00000000 ca:01 2097461 /lib64/libgcc_s-4.1.2-20080825.so.1 3cfac00000-3cface6000 r-xp 00000000 ca:01 10596444 /usr/lib64/libstdc++.so.6.0.8 3cfaeee000-3cfaf00000 rw-p 3cfaeee000 00:00 0 2b9ce3c77000-2b9ce3c79000 rw-p 2b9ce3c77000 00:00 0 2b9ce3c8d000-2b9ce3c8e000 rw-p 2b9ce3c8d000 00:00 0 2b9ce3c8e000-2b9ce3d7c000 r-xp ca:01 14583150 /home/admin/local/lib/libPocoNet.so.9 2b9ce41f2000-2b9ce41f3000 rw-p 2b9ce41f2000 00:00 0 2b9ce41f3000-2b9ce420f000 r-xp ca:01 14583172 /home/admin/local/lib/libPocoMySQL.so.9 2b9ce4410000-2b9ce445c000 r-xp ca:01 14583166 /home/admin/local/lib/libPocoUtil.so.9 2b9ce465e000-2b9ce4660000 rw-p 2b9ce465e000 00:00 0 2b9ce4660000-2b9ce47f4000 r-xp ca:01 14583165 /home/admin/local/lib/libPocoFoundation.so.9 2b9ce4a02000-2b9ce4a03000 rw-p 2b9ce4a02000 00:00 0 2b9ce4a03000-2b9ce4b1b000 r-xp ca:01 14583068 /home/admin/local/lib/libmysql.so.16.0.0 7fffc6e1d000-7fffc6e32000 rw-p 7ffffffea000 00:00 0 [stack] ffffffffff600000-ffffffffffe00000 ---p 00000000 00:00 0 [vdso] |
以SMSSERVER為例,它詳細顯示了SMSSERVER執行時的庫檔案記憶體對映,以及stack的地址:
也有一些記憶體對映後面是空的,說明這是匿名記憶體對映。可以通過/proc/PID/smaps檢視更詳細的資訊,例如檢視上述stack使用情況:
#cat /proc/23698/smaps …… 7fffc6e1d000-7fffc6e32000 rw-p 7ffffffea000 00:00 0 [stack] Size: 84 kB Rss: 16 kB Shared_Clean: 0 kB Shared_Dirty: 0 kB Private_Clean: 0 kB Private_Dirty: 16 kB Swap: 0 kB …… |
其中rw-p表示許可權,許可權共有以下幾種:
r = read
w = write
x = execute
s = shared
p = private (copy on write)
SIZE表示了這個對映的大小,RSS表示正在RAM中的資料大小。
Shared/Private_Clean/Dirty分別表示共享和私有庫有效頁和髒資料的大小。
這裡要注意的是,即使是共享庫,但如果使用者只有此一個程序時,也被統計在Private項裡。
那麼庫檔案是怎麼載入進入記憶體的呢?這裡也做一個簡單的介紹。
linux下的庫有兩種:靜態庫和共享庫(動態庫)。
二者的不同點在於程式碼被載入的時刻不同。 靜態庫的程式碼在編譯過程中已經被載入可執行程式,因此體積較大。共享庫的程式碼是在可執行程式執行時才載入記憶體的,在編譯過程中僅簡單的引用,因此程式碼體積較小。共享庫的好處是,不同的應用程式如果呼叫相同的庫,那麼在記憶體裡只需要有一份該共享庫的例項。
一般靜態庫的字尾是.a,它由原始檔編譯生成一堆.o,每個.o裡都包含這個編譯單元的符號表,然後用ar命令將很多.o轉換成.a形成。而動態庫的字尾為.so,由gcc加特定引數編譯產生。
對於一個可執行檔案,可以用如下命令檢視它的依賴庫,以簡訊伺服器SMSSERVER為例:
那麼編譯程式是如何找到這些庫檔案,並載入進來的呢?編譯器將先後搜尋:
1) elf檔案的DT_RPATH段(在編譯時指定目錄);
2) 環境變數LD_LIBRARY_PATH中指定的路徑;
3) /etc/ld.so.cache檔案列表;
4) /lib/,/usr/lib目錄;
如果找不到則會連結失敗。因此,如果出現找不到庫的情況,可以:
1)在編譯時-rpath指定目錄;
2)修改.bash_profile檔案在LD_LIBRARY_PATH中加入指定目錄;
3)修改/etc/ld.so.conf加入指定目錄,然後呼叫ldconfig重新生成/etc/ld.so.cache;
4)將動態庫放入/lib/,/usr/lib兩個預設路徑;
四、 系統調優相關檔案(/proc/sys目錄)
通常而言,/proc/sys目錄下的檔案是可讀可寫的,其它目錄大多隻可讀,。由於使用者可以通過修改值來達到修改執行時系統狀態的目的,我們有時也可以此來優化系統狀態。當然,修改proc值只會影響當前執行狀態,重啟後將失效。通常可以採用echo x > filename的方法來將值直接改入檔案。例如:
[[email protected] ~]$ cat /proc/sys/vm/swappiness 10 [[email protected] ~]$ echo 20 > /proc/sys/vm/swappiness |
下面對一些常見核心引數進行說明:
1、/proc/sys/kernel目錄:
檔名 |
含義 |
預設值 |
/proc/sys/kernel/msgmax |
程序間傳遞訊息的最大長度 |
8192 |
/proc/sys/kernel/msgmnb |
一個訊息佇列的最大長度 |
16384 |
/proc/sys/kernel/msgmni |
訊息佇列的最大數目 |
16 |
/proc/sys/kernel/shmall |
共享記憶體可使用總量 |
2097152 |
/proc/sys/kernel/shmmax |
核心所允許的最大共享記憶體段的大小 |
|
/proc/sys/kernel/threads-max |
核心所能使用的執行緒的最大數目 |
2048 |
/proc/sys/kernel/sem |
4個值,分別表示每個訊號集的最大訊號量數目,系統範圍內的最大訊號量總數目,每個訊號發生時的最大系統運算元目,系統範圍內的最大訊號集總數目 |
2、/proc/sys/vm目錄
檔名 |
含義 |
備註 |
/proc/sys/vm/swapiness |
系統進行交換行為的程度,數值(0-100)越高,越可能發生磁碟交換 |
60 |
/proc/sys/vm/page-cluster |
寫一次到swap區的時候寫入的頁面數量,0表示1頁,1表示2頁,2表示4頁 |
3 |
/proc/sys/vm/nr_pdflush_threads |
當前正在執行的pdflush程序數量,在I/O負載高的情況下,核心會自動增加更多的pdflush程序。Pdflush用於頁面置換時將資料寫回磁碟 |
|
/proc/sys/vm/min_free_kbytes |
強制Linux VM最低保留多少空閒記憶體 |
|
/proc/sys/vm/dirty_writeback_centisecs |
pdflush程序週期性間隔多久把髒資料寫回磁碟 |
500ms |
/proc/sys/vm/dirty_ratio |
如果程序產生的髒資料到達系統整體記憶體的百分比,此時程序自行把髒資料寫回磁碟 |
40 |
/proc/sys/vm/dirty_expire_centisecs |
如果髒資料在記憶體中駐留時間超過該值,pdflush程序在下一次將這些資料寫回磁碟 |
3000ms |
/proc/sys/vm/dirty_background_ratio |
髒資料到達系統整體記憶體的百分比,此時觸發pdflush程序把髒資料寫回磁碟 |
10 |
3、/proc/sys/net目錄
檔名 |
含義 |
預設值 |
/proc/sys/net/core/message_burst |
寫新的警告訊息所需的時間,在這個時間內系統接收到的其它警告訊息會被丟棄。這用於防止某些企圖用訊息“淹沒”系統的人所使用的拒絕服務(Denial of Service)攻擊。 |
50(5秒) |
/proc/sys/net/core/netdev_max_backlog |
在每個網路介面接收資料包的速率比核心處理這些包的速率快時,允許送到佇列的資料包的最大數目 |
300 |
/proc/sys/net/core/optmem_max |
每個套接字所允許的最大緩衝區大小 |
10240 |
/proc/sys/net/core/rmem_default |
接收套接字緩衝區大小的預設值 |
110592 |
/proc/sys/net/core/rmem_max |
接收套接字緩衝區大小的最大值 |
131071 |
/proc/sys/net/core/wmem_default |
傳送套接字緩衝區大小的預設值 |
110592 |
/proc/sys/net/core/wmem_max |
傳送套接字緩衝區大小的最大值 |
4、/proc/sys/net/ipv4目錄
涉及TCP/IP相關引數特別多,這裡只列舉一些常見的引數:
檔案 |
含義 |
預設值 |
/proc/sys/net/ipv4/ip_forward |
是否開啟IP轉發 |
0禁止 1轉發 |
/proc/sys/net/ipv4/ip_default_ttl |
一個數據報的生存週期(Time To Live),即最多經過多少路由器 |
64 |
/proc/sys/net/ipv4/ip_no_pmtu_disc |
在全域性範圍內關閉路徑MTU探測功能 |
0 |
/proc/sys/net/ipv4/route/min_pmtu |
最小路徑MTU的大小 |
552 |
/proc/sys/net/ipv4/ipfrag_time |
一個IP分段在記憶體中保留多少秒 |
30 |
/proc/sys/net/ipv4/tcp_syn_retries |
本機向外發起TCP SYN連線超時重傳的次數; 該值僅僅針對外出的連線,對於進來的連線由tcp_retries1控制 |
5 |
/proc/sys/net/ipv4/tcp_keepalive_probes |
丟棄TCP連線前,進行最大TCP保持連線偵測的次數 |
9 |
/proc/sys/net/ipv4/tcp_retries2 |
放棄在已經建立通訊狀態下的一個TCP資料包前進行重傳的次數 |
15 |
/proc/sys/net/ipv4/tcp_fin_timeout |
對於本端斷開的socket連線,TCP保持在FIN-WAIT-2狀態的時間 |
60 |
/proc/sys/net/ipv4/tcp_max_tw_buckets |
系統在同時所處理的最大timewait sockets 數目。純粹為了抵禦那些簡單的 DoS 攻擊 |
180000 |
/proc/sys/net/ipv4/tcp_tw_reuse |
是否允許重新應用處於TIME-WAIT狀態的socket用於新的TCP連線 |
0 |
/proc/sys/net/ipv4/tcp_max_syn_backlog |
對於那些依然還未獲得客戶端確認的連線請求,需要儲存在佇列中最大數目 |
1024 |
/proc/sys/net/ipv4/tcp_window_scaling |
設定tcp/ip會話的滑動視窗大小是否可變 |
1 |
/proc/sys/net/ipv4/tcp_reordering |
TCP流中重排序的資料報最大數量 |
3 |
5、常用網路優化策略:
1)優化系統套接字緩衝區
net.core.rmem_max=16777216
net.core.wmem_max=16777216
2)優化TCP接收/傳送緩衝區
net.ipv4.tcp_rmem=4096 87380 16777216
net.ipv4.tcp_wmem=4096 65536 16777216
3)優化網路裝置接收佇列
net.core.netdev_max_backlog=3000
4)關閉路由相關功能
net.ipv4.conf.lo.accept_source_route=0
net.ipv4.conf.all.accept_source_route=0
net.ipv4.conf.eth0.accept_source_route=0
net.ipv4.conf.default.accept_source_route=0
net.ipv4.conf.lo.accept_redirects=0
net.ipv4.conf.all.accept_redirects=0
net.ipv4.conf.eth0.accept_redirects=0
net.ipv4.conf.default.accept_redirects=0
net.ipv4.conf.lo.secure_redirects=0
net.ipv4.conf.all.secure_redirects=0
net.ipv4.conf.eth0.secure_redirects=0
net.ipv4.conf.default.secure_redirects=0
net.ipv4.conf.lo.send_redirects=0
net.ipv4.conf.all.send_redirects=0
net.ipv4.conf.eth0.send_redirects=0
net.ipv4.conf.default.send_redirects=0
5)優化TCP協議棧
開啟TCP SYN cookie選項,有助於保護伺服器免受SyncFlood攻擊。
net.ipv4.tcp_syncookies=1
開啟TIME-WAIT套接字重用功能,對於存在大量連線的Web伺服器非常有效。
net.ipv4.tcp_tw_recyle=1
net.ipv4.tcp_tw_reuse=1
減少處於FIN-WAIT-2連線狀態的時間,使系統可以處理更多的連線。
net.ipv4.tcp_fin_timeout=30
減少TCP KeepAlive連線偵測的時間,使系統可以處理更多的連線。
net.ipv4.tcp_keepalive_time=1800
增加TCP SYN佇列長度,使系統可以處理更多的併發連線。
net.ipv4.tcp_max_syn_backlog=8192
五、自定義PROC檔案和管理
如果你想自定義一個Proc項,可以採用如下方法:
struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent) |
其中,第一個引數為需要建立的檔名,第二個引數為許可權設定,第三個引數為父節點名字。如果為空,則建立在/proc/目錄下。create_proc_entry實際工作是生成proc_dir_entry,並將它註冊到檔案系統,連結上預設的檔案操作集file_operation。
當然,如果只是想要建立一個只讀的 proc 檔案,可以採用 create_proc_read_entry() 這個介面。這個介面其實就是給 proc_dir_entry 多賦了兩個值,其中 read_proc 是一個函式指標, data 是 read_proc 呼叫時傳給它一個引數。
static inline struct proc_dir_entry *create_proc_read_entry(const char *name,mode_t mode, struct proc_dir_entry *base, read_proc_t *read_proc, void * data) |
此外還有建立目錄、刪除proc項、讀檔案、寫檔案等方法,它們的定義如下:
struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent) void remove_proc_entry(const char *name, struct proc_dir_entry *parent) static ssize_t proc_file_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) static ssize_t proc_file_write(struct file *file, const char __user *buffer,size_t count, loff_t *ppos) |
proc_file_read為了讀到/proc系統中的資料,需要做如下三步:
1.申請記憶體頁 2.讀取資料填充到此記憶體頁 3.把資料從核心空間拷貝到使用者空間。
proc 檔案的讀需要自己提供一個 read_proc_t 型別的函式放在 proc_dir_entry 結構中供 proc_file_read() 函式呼叫。同樣,寫也需要提供write_proc_t型別的函式。它們的定義分別是:
typedef int (read_proc_t)(char *page, char **start, off_t off, int count,int *eof, void *data); typedef int (write_proc_t)(struct file *file, const char __user *buffer, unsigned long count, void *data); |
後記
/proc檔案系統包含了系統資訊和核心引數,內容非常豐富,有許多引數的理解和修改需要對linux原理、程序排程、記憶體管理等有很深的瞭解,才可以對其做出更好的分析和優化。本文提到的均為較常見的引數,更詳細的說明可以檢視linux幫助文件和網站。
感興趣的同學可以一起討論。如有錯誤,請指正。
謝謝大家。