1. 程式人生 > >linux Proc檔案系統介紹及運用總結

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幫助文件和網站。

感興趣的同學可以一起討論。如有錯誤,請指正。

謝謝大家。