linux啟動分析
1. 怎樣分析linux的性能指標
LR
監控
UNIX/Linux
系統方法
一、准備工作:
1.
可以通過兩種方法驗證伺服器上是否配置
rstatd
守護程序:
①使用
rup
命令,它用於報告計算機的各種統計信息,其中就包括
rstatd
的配置信息。使用命
令
rup
10.130.61.203,
此處
10.130.61.203
是要監視的
linux/Unix
伺服器的
IP
,如果該命令返回相關的
統計信息。則表示已經配置並且激活了
rstatd
守護進程;若未返回有意義的統計信息,或者出現一
條錯誤報告,則表示
rstatd
守護進程尚未被配置或有問題。
②使用
find
命令
#find / -name rpc.rstatd,
該命令用於查找系統中是否存在
rpc.rstatd
文件,如果沒有,說明系統沒
有安裝
rstatd
守護程序。
2
.
linux
需要下載
3
個包:
(
1
)
rpc.rstatd-4.0.1.tar.gz
(
2
)
rsh-0.17-14.i386.rpm
(
3
)
rsh-server-0.17-14.i386.rpm
3
.下載並安裝
rstatd
如果伺服器上沒有安裝
rstatd
程序(一般來說
LINUX
都沒有安裝)
,需要下載一個包才有這個服
務
,
包
名
字
是
rpc.rstatd-4.0.1.tar.gz.
這
是
一
個
源
碼
,
需
要
編
譯
,
下
載
並
安
裝
rstatd
(
可
以
在
http://sourceforge.net/projects/rstatd
這個地址下載)下載後,開始安裝,安裝步驟如下:
tar -xzvf rpc.rstatd-4.0.1.tar.gz
cd rpc.rstatd-4.0.1/
./configure
—配置操作
make
—進行編譯
make install
—開始安裝
rpc.rstatd
—啟動
rstatd
進程
「
rpcinfo -p
」命令來查看當前系統是否已經啟動了
rstatd
守護進程
只要保證
Linux
機器上的進程里有
rstatd
和
xinetd
這二個服務就可以用
LR
去監視了,通過以下
兩點可以檢查是否啟動:
1
)檢查是否啟動
: rsh server
監聽的
TCP
是
514
。
[root@mg04 root]# netstat -an |grep 514
tcp 0 0 0.0.0.0:514 0.0.0.0:* LISTEN
如果能看到
514
在監聽說明
rsh
伺服器已經啟動。
2
)檢查是否啟動
: rstatd
輸入命令
: rpcinfo -p
如果能看到類似如下信息:
程序版本協議埠
100001
5
udp
937
rstatd
100001
4
udp
937
rstatd
100001
3
udp
937
rstatd
100001
2
udp
937
rstatd
100001
1
udp
937
rstatd
那就說明
rstatd
服務啟動了
,(
當然這里也可以用
ps ax
代替
)
4
.安裝
rsh
和
rsh-server
兩個服務包方法
a.
卸載
rsh
# rpm
–
q
rsh----------
查看版本號
# rpm
-e
版本號
---------
卸載該版本。
b
.安裝
# rpm
–
ivh rsh-0.17-14.i386.rpm rsh-server-0.17-14.i386.rpm
在啟動
rpc.rstatd
時,
會報錯
「
Cannot register service: RPC: Unable to receive; errno = Ction refused
」
。
解決方法如下:
# /etc/init.d/portmap start
# /etc/init.d/nfs start
然後再次啟動
rpc.rstatd
就好了。
5
.安裝
xinetd
方法:
①查看
xinetd
服務:
[root@localhost ~]# rpm -q xinetd
xinetd-2.3.14-10.el5
②安裝
xinetd
服務:
[root@localhost ~]# yum install xinetd
如果安裝不起
xinetd
服務,執行下列操作命令後再次執行
yum install xinetd
命令進行安裝:
yum clean packages
清除緩存目錄下的軟體包
yum clean headers
清除緩存目錄下的
headers
yum clean oldheaders
清除緩存目錄下舊的
headers
yum clean, yum clean all (= yum clean packages; yum clean oldheaders)
清除緩存目錄下的軟體包
及舊的
headers
。
6
.啟動
xinetd
服務:
在有的系統中,通過如下命令重啟:
# service xinetd reload
# /sbin/service xinetd rstart
在
suse linux
中如下操作:
cd /etc/init.d/xinetd restart
2
)
安裝完成後配置
rstatd
目標守護進程
xinetd,
它的主配置文件是
/etc/xinetd.conf ,
它裡面內容是
一些如下的基本信息:
#
# xinetd.conf
#
# Copyright (c) 1998-2001 SuSE GmbH Nuernberg, Germany.
# Copyright (c) 2002 SuSE Linux AG, Nuernberg, Germany.
#
defaults
{
log_type
= FILE /var/log/xinetd.log
log_on_success = HOST EXIT DURATION
log_on_failure = HOST ATTEMPT
#
only_from
= localhost
instances
= 30
cps
= 50 10
#
# The specification of an interface is interesting, if we are on a firewall.
# For example, if you only want to provide services from an internal
# network interface, you may specify your internal interfaces IP-Address.
#
#
interface
= 127.0.0.1
}
includedir /etc/xinetd.d
我們這里需要修改的是
/etc/xinetd.d/
下的三個
conf
文件
rlogin
,rsh,rexec
這三個配置文件
,
打這
三個文件里的
disable = yes
都改成
disable = no ( disabled
用在默認的
{}
中禁止服務
)
或是把
# default:
off
都設置成
on
這個的意思就是在
xinetd
啟動的時候默認都啟動上面的三個服務
!
說明:我自己在配置時,沒有
disable = yes
這項,我就將
# default: off
改為:
default: on
,重啟後
(cd /etc/init.d/./xinetd restart
)通過
netstat -an |grep 514
查看,沒有返回。然後,我就手動在三個文
件中最後一行加入
disable
=
no
,再重啟
xinetd
,再使用
netstat
-an
|grep
514
查看,得到
tcp
0
0
0.0.0.0:514 0.0.0.0:* LISTEN
結果,表明
rsh
伺服器已經啟動。
看到網上有的地方說使用如下命令:
# service xinetd reload
# /sbin/service xinetd rstart
不知道是在什麼系統用的。
二、監控
linux
資源:
在
controller
中,將
System resource Graphs
中的
Unix resources
拖到右側的監控區域中,並單擊
滑鼠右鍵選擇「
Add
Measurements
」
,
在彈出的對話框中輸入被監控的
linux
系統的
IP
地址,然後選
擇需要監控的性能指標,並點擊「確定」
,出現如下結果:
Monitor name :UNIX Resources. Cannot initialize the monitoring on 10.10.15.62.
Error while creating the RPC client. Ensure that the machine can be connected and that it runs the
rstat daemon (use rpcinfo utility for this verification).
Detailed error: RPC: Failed to create RPC client.
RPC-TCP: Failed to establish RPC server address.
RPC-TCP: Failed to communicate with the portmapper on host '10.10.15.62'.
RPC: RPC call failed.
RPC-TCP: recv()/recvfrom() failed.
RPC-TCP: Timeout reached. (entry point: CFactory::Initialize). [MsgId: MMSG-47190]
檢查原因,發現是
Linux
系統中的防火牆開啟了並且阻擋了
LoadRunner
監控
Linux
系統的資源,
因此要將防火牆關閉。
關閉防火牆:
[root@localhost ~]# /etc/init.d/iptables stop;
三、監控
UNIX
lr
監控
UNIX
,
UNIX
先啟動一
rstatd
服務
以下是在
IBM AIX
系統中啟動
rstatd
服務的方法:
1
.使用
telnet
以
root
用戶的身份登錄入
AIX
系統
2
.在命令行提示符下輸入:
vi /etc/inetd.conf
3
.查找
rstatd
,找到
#rstatd
sunrpc_udp
udp
wait
root /usr/sbin/rpc.rstatd rstatd 100001 1-3
4
、將
#
去掉
5
、
:wq
保存修改結果
6
、命令提示符下輸入:
refresh
–
s inetd
重新啟動服務。
這樣使用
loadrunner
就可以監視
AIX
系統的性能情況了。
註:在
HP UNIX
系統上編輯完
inetd.conf
後,重啟
inetd
服務需要輸入
inetd -c
UNIX
上也可以用
rup
命令查看
rstatd
程序是否被配置並激活
若
rstatd
程序已經運行,
重啟時,
先查看進程
ps -ef |grep inet
,
然後殺掉進程,
再
refresh
–
s inetd
進行重啟。
2. 請幫忙分析Linux下mysql啟動不起來的原因
以下錯誤日誌提示,都是查看 MySQL 錯誤日誌得到,查看方法如下:
查看下 MySQL 配置文件 my.cnf 中有記錄,日誌記錄在/log/mysql/error.log下
?MySQL 配置文件 my.cnf 許可權問題導致無法啟動,錯誤提示:World-writable config file 『/etc/my.cnf』 is ignored
?Binlog 丟失導致無法啟動,錯誤日誌: File 『./mysql-bin.000001』 not found
?Binlog 無法讀取導致無法啟動,錯誤日誌:Failed to open log (file 『./mysql-bin.000001』, errno 13)
?不能創建 PID 導致無法啟動,錯誤日誌:Can』t start server: can』t create PID file: No such file or directory
?不能創建臨時文件導致無法啟動,錯誤日誌:mysqld: Can』t create/write to file 『/tmp/ibfguTtC』 (Errcode: 13)
?MySQL 服務無法識別導致無法啟動,錯誤提示:mysqld: unrecognized service
?MySQL 配置了過大的內存導致無法啟動,錯誤日誌:InnoDB: Cannot allocate memory for the buffer pool
?MySQL 啟動參數過多導致無法啟動,錯誤提示:Too many arguments (first extra is 『start』)
?MySQL 目錄許可權問題導致無法啟動,錯誤日誌:File 『./mysql-bin.index』 not found (Errcode:13 – Permission denied)
?MySQL 未初始化導致無法啟動,錯誤提示:can』t open the mysql.plugin table
?MySQL 啟動成功但未監聽埠
?MySQL ibdata1許可權問題導致無法啟動,錯誤日誌:InnoDB Operating system error number 13 in a file operation
?磁碟空間滿導致 MySQL 無法啟動
?進程殘留導致 MySQL 無法啟動
?MySQL 服務自動停止
這些是錯誤提示你對照去找你的原因就這么多了
3. 啟動linux(xubuntu)時在[ok] reached target sound card不動了
啟動linux(xubuntu)時在[ok] reached target sound card不動了
[OK] Reached initrd target default target
這個是在剛才編輯/etc/selinux/config這個文件里,重啟後出現的錯誤。
結果呢, [OK] Reached initrd target default target
在啟動里能看到,到了這兒,就再也進行不下去了。
分析加GOOGLE後,
在啟動是選擇e 進入到命令行編輯模式, 在倒數第二行 加上 selinux=0
然後能正常啟動中。
編輯上面提到的文件, 恢復原來的設置 selinux=targeted 。
4. 求Linux系統啟動過程分析
google , 下Linux系統啟動過程 你會得到一大堆的, 這個東西在基本的教科書上都有描述
http://publish.it168.com/2005/0825/20050825123701.shtml
很詳細的描述, 就不了,
沒必要也不值得為這個打一大段
5. linux dhcp啟動 失敗 求 高人分析下
出現問題的可能有以下幾個可能:
1. 配置文件有問題。
1.1 內容不符合語法結構,例如,少個分號;
1.2 聲明的子網和子網掩碼不符合;
2. 主機IP地址和聲明的子網不在同一網段。
3. 主機沒有配置IP地址。
4. 配置文件路徑出問題,比如在RHEL6以下的版本中,配置文件保存在了/etc/dhcpd.conf,但是在rhel6及以上版本中,卻保存在了/etc/dhcp/dhcpd.conf。
你檢查一下吧。
6. Linux 高級分析手段有哪些
高級分析手段如OProfile、gprof。
OProfile可以幫助用戶識別諸如模塊的佔用時間、循環的展開、高速緩存的使用率低、低效的類型轉換和冗餘操作、錯誤預測轉移等問題。它收集有關處理器事件的信息,其中包括TLB的故障、停機、存儲器訪問以及緩存命中和未命中的指令的攫取數量。
OProfile支持兩種采樣方式:基於事件的采樣(Event Based)和基於時間的采樣(Time Based)。基於事件的采樣是OProfile只記錄特定事件(比如L2緩存未命中)的發生次數,當達到用戶設定的定值時Oprofile就記錄一下(采一個樣)。這種方式需要CPU內部有性能計數器(Performace Counter)。基於時間的采樣是OProfile藉助OS時鍾中斷的機制,在每個時鍾中斷,OProfile都會記錄一次(采一次樣)。引入它的目的在於,提供對沒有性能計數器的CPU的支持,其精度相對於基於事件的采樣要低,因為要藉助OS時鍾中斷的支持,對於禁用中斷的代碼,OProfile不能對其進行分析。
OProfile在Linux上分兩部分,一個是內核模塊( oprofile.ko),另一個是用戶空間的守護進程( oprofiled)。前者負責訪問性能計數器或者注冊基於時間采樣的函數,並將采樣值置於內核的緩沖區內。後者在後台運行,負責從內核空間收集數據,寫入文件。其運行步驟如下。
1)初始化opcontrol--init
2)配置opcontrol--setup--event=...
3)啟動opcontrol--start
4)運行待分析的程序xxx
5)取出數據
opcontrol--mp
6)分析結果opreport-1./xxx
用GNU gprof可以列印出程序運行中各個函數消耗的時間,以幫助程序員找出眾多函數中耗時最多的函數;還可產生程序運行時的函數調用關系,包括調用次數,以幫助程序員分析程序的運行流程。GNU gprof的實現原理:在編譯和鏈接程序的時候〈使用-pg編譯和鏈接選項),gcc在應用程序的每個函數中都加入名為mcount (_mcount或_mcount,依賴於編譯器或操作系統)的函數,也就是說應用程序里的每一個函數都會調用mcount,而mcount會在內存中保存一張函數調用圖,並通過函數調用堆棧的形式查找子函數和父函數的地址。這張調用圖也保存了所有與函數相關的調用時間、調用次數等的所有信息。
7. Linux systemd 自啟動腳本無法正常運行(求助分析方向)
chmod +X /etc/rc.d/rc.local
8. linux kernel啟動失敗,如何分析問題所在
kernel可是linux內核,這個出問題了估計會比較麻煩。
undefined instruction
未定義的指令。
9. linux 啟動時何時初始化console,串口等
1、LINUX下TTY、CONSOLE、串口之間是怎樣的層次關系?具體的函數介面是怎樣的?串口是如何被調用的?
2、printk函數是把信息發送到控制台上吧?如何讓PRINTK把信息通過串口送出?或者說系統在什麼地方來決定是將信息送到顯示器還是串口?
3、start_kernel中一開始就用到了printk函數(好象是printk(linux_banner什麼的),在 這個時候整個內核還沒跑起來呢那這時候的printk是如何被調用的?在我們的系統中,系統啟動是用的現代公司的BOOTLOADER程序,後來好象跳到了LINUX下的head-armv.s, 然後跳到start_kernel,在bootloader 里串口已經是可用的了,那麼在進入內核後是不是要重新設置?
以上問題可能問的比較亂,因為我自己腦子里也比較亂,主要還是對tty,console,serial之間的關系,特別是串口是如何被調用的沒搞清這方面的資料又比較少(就情景分析中講了一點),希望高手能指點一二,非常謝!
我最近也在搞這方面的東西,也是寫一個串口設備的驅動
搞了將近一個月了,其中上網找資料,看源代碼,什麼都做了
但還是一蹋糊塗的,有些問題還是不明白,希望一起討論討論
在/proc/device(沒記錯應該是這個文件)
裡面有一個叫serial的驅動,其主設備號是4,次設備號是64-12X(沒記錯應該是這個范圍)
大家都知道,串口的次設備號是從64開始的,串口1 /dev/ttyS0就對應次設備號64,串口2就對應65
問題是現在我機上只有兩個串口,它注冊這么多次設備號來干什麼?
對於一個接在串口1的設備,在我注冊驅動的時候
我是需要自己找一個主設備號呢?
還是就用主設備號4,次設備號從上面12X的後面選?
還是就用主設備號4,次設備號64?
在linux的內核中有一個tty層,我看好像有些串口驅動是從這里開始的
例如調用tty_register_driver()來注冊驅動
就像在pci子系統里調用pci_register_driver()那樣的
那麼,用這種機制來注冊的驅動,
它是直接對串口的埠操作呢(例如用inb(),outb()....之類的)
還是某些更底層的驅動介面呢?
這些問題纏了我很久都沒解決,搞得最後不得不放棄
現在轉向用戶空間的應用程序,看能不能有些更高效的方法來實現
(在用戶空間只能用open("/dev/ttyS0", O_RDWR)來實現了)
另外還有,系統里已經為我們實現了串口的驅動
所以我們在用戶空間的程序里直接open("/dev/ttyS0")就可用了
但是現在要寫的是接在串口上的設備的驅動
在內核模塊中可不可以包含某個頭文件,然後就可以直接用串口驅動中的介面呢?
看到你們的問題後,感覺很有典型性,因此花了點工夫看了一下,做了一些心得貼在這里,歡迎討論並指正:
1、LINUX下TTY、CONSOLE、串口之間是怎樣的層次關系?具體的函數介面是怎樣的?串口是如何被調用的?
tty和console這些概念主要是一些虛設備的概念,而串口更多的是指一個真正的設備驅動Tty實際是一類終端I/O設備的抽象,它實際上更多的是一個管理的概念,它和tty_ldisc(行規程)和tty_driver(真實設備驅動)組合在一起,目的是向上層的VFS提供一個統一的介面通過file_operations結構中的tty_ioctl可以對其進行配置。查tty_driver,你將得到n個結果,實際都是相關晶元的驅動因此,可以得到的結論是(實際情況比這復雜得多):每個描述tty設備的tty_struct在初始化時必然掛如了某個具體晶元的字元設備驅動(不一定是字元設備驅動),可以是很多,包括顯卡或串口chip不知道你的ARM Soc是那一款,不過看情況你們應該用的是常見的chip,這些驅動實際上都有而console是一個緩沖的概念,它的目的有一點類似於tty實際上console不僅和tty連在一起,還和framebuffer連在一起,具體的原因看下面的鍵盤的中斷處理過程Tty的一個子集需要使用console(典型的如主設備號4,次設備號1―64),但是要注意的是沒有console的tty是存在的
而串口則指的是tty_driver舉個典型的例子:
分析一下鍵盤的中斷處理過程:
keyboard_interrupt―>handle_kbd_event―>handle_keyboard_event―>handle_scancode
void handle_scancode(unsigned char scancode, int down)
{
……..
tty = ttytab? ttytab[fg_console]: NULL;
if (tty && (!tty->driver_data)) {
……………
tty = NULL;
}
………….
schele_console_callback();
}
這段代碼中的兩個地方很值得注意,也就是除了獲得tty外(通過全局量tty記錄),還進行了console 回顯schele_console_callbackTty和console的關系在此已經很明了!!!
2、printk函數是把信息發送到控制台上吧?如何讓PRINTK把信息通過串口送出?或者說系統在什麼地方來決定是將信息送到顯示器還是串口?
具體看一下printk函數的實現就知道了,printk不一定是將信息往控制台上輸出,設置kernel的啟動參數可能可以打到將信息送到顯示器的效果。函數前有一段英文,很有意思:
/*This is printk. It can be called from any context. We want it to work.
*
* We try to grab the console_sem. If we succeed, it's easy - we log the output and
* call the console drivers. If we fail to get the semaphore we place the output
* into the log buffer and return. The current holder of the console_sem will
* notice the new output in release_console_sem() and will send it to the
* consoles before releasing the semaphore.
*
* One effect of this deferred printing is that code which calls printk() and
* then changes console_loglevel may break. This is because console_loglevel
* is inspected when the actual printing occurs.
*/
這段英文的要點:要想對console進行操作,必須先要獲得console_sem信號量如果獲得console_sem信號量,則可以「log the output and call the console drivers」,反之,則「place the output into the log buffer and return」,實際上,在代碼:
asmlinkage int printk(const char *fmt, ...)
{
va_list args;
unsigned long flags;
int printed_len;
char *p;
static char printk_buf[1024];
static int log_level_unknown = 1;
if (oops_in_progress) { /*如果為1情況下,必然是系統發生crush*/
/* If a crash is occurring, make sure we can't deadlock */
spin_lock_init(&logbuf_lock);
/* And make sure that we print immediately */
init_MUTEX(&console_sem);
}
/* This stops the holder of console_sem just where we want him */
spin_lock_irqsave(&logbuf_lock, flags);
/* Emit the output into the temporary buffer */
va_start(args, fmt);
printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);/*對傳入的buffer進行處理,注意還不是
真正的對終端寫,只是對傳入的string進行格式解析*/
va_end(args);
/*Copy the output into log_buf. If the caller didn't provide appropriate log level tags, we insert them here*/
/*注釋很清楚*/
for (p = printk_buf; *p; p++) {
if (log_level_unknown) {
if (p[0] != '<' || p[1] < '0' || p[1] > '7' || p[2] != '>') {
emit_log_char('<');
emit_log_char(default_message_loglevel + '0');
emit_log_char('>');
}
log_level_unknown = 0;
}
emit_log_char(*p);
if (*p == ' ')
log_level_unknown = 1;
}
if (!arch_consoles_callable()) {
/*On some architectures, the consoles are not usable on secondary CPUs early in the boot process.*/
spin_unlock_irqrestore(&logbuf_lock, flags);
goto out;
}
if (!down_trylock(&console_sem)) {
/*We own the drivers. We can drop the spinlock and let release_console_sem() print the text*/
spin_unlock_irqrestore(&logbuf_lock, flags);
console_may_schele = 0;
release_console_sem();
} else {
/*Someone else owns the drivers. We drop the spinlock, which allows the semaphore holder to
proceed and to call the console drivers with the output which we just proced.*/
spin_unlock_irqrestore(&logbuf_lock, flags);
}
out:
return printed_len;
}
實際上printk是將format後的string放到了一個buffer中,在適當的時候再加以show,這也回答了在start_kernel中一開始就用到了printk函數的原因
3、start_kernel中一開始就用到了printk函數(好象是printk(linux_banner什麼的),在這個時候整個內核還沒跑起來呢。那這時候的printk是如何被調用的?在我們的系統中,系統啟動是用的現代公司的BOOTLOADER程序,後來好象跳到了LINUX下的head-armv.s, 然後跳到start_kernel,在bootloader 里串口已經是可用的了,那麼在進入內核後是不是要重新設置?
Bootloader一般會做一些基本的初始化,將kernel拷貝物理空間,然後再跳到kernel去執行。可以肯定的是kernel肯定要對串口進行重新設置,原因是Bootloader有很多種,有些不一定對串口進行設置,內核不能依賴於bootloader而存在。
多謝樓上大俠,分析的很精闢。我正在看printk函數。
我們用的CPU是hynix的hms7202。在評估板上是用串口0作
控制台,所有啟動過程中的信息都是通過該串口送出的。
在bootloader中定義了函數ser_printf通過串口進行交互。
但我還是沒想明白在跳轉到linux內核而console和串口尚未
初始化時printk是如何能夠工作的?我看了start_kernel
的過程(並通過超級終端作了一些跟蹤),console的初始化
是在console_init函數里,而串口的初始化實際上是在1號
進程里(init->do_basic_setup->do_initcalls->rs_init),
那麼在串口沒有初始化以前prink是如何工作的?特別的,在
start_kernel一開始就有printk(linux_banner),而這時候
串口和console都尚未初始化呢。
在start_kernel一開始就有printk(linux_banner),而這時候串口和console都尚未初始化?
仔細分析printk可以對該問題進行解答代碼中的:
/* Emit the output into the temporary buffer */
va_start(args, fmt);
printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
va_end(args);
將輸入放到了printk_buf中,接下來的
for (p = printk_buf; *p; p++) {
if (log_level_unknown) {
if (p[0] != '<' || p[1] < '0' || p[1] > '7' || p[2] != '>') {
emit_log_char('<');
emit_log_char(default_message_loglevel + '0');
emit_log_char('>');
}
log_level_unknown = 0;
}
emit_log_char(*p);
if (*p == ' ')
log_level_unknown = 1;
}
則將printk_buf中的內容進行解析並放到全局的log_buf(在emit_log_char函數)中if (!down_trylock(&console_sem)) {
/*
* We own the drivers. We can drop the spinlock and let
* release_console_sem() print the text
*/
spin_unlock_irqrestore(&logbuf_lock, flags);
console_may_schele = 0;
release_console_sem();
} else {
/*
* Someone else owns the drivers. We drop the spinlock, which
* allows the semaphore holder to proceed and to call the
* console drivers with the output which we just proced.
*/
spin_unlock_irqrestore(&logbuf_lock, flags);
}
則是根據down_trylock(&console_sem)的結果調用release_console_sem(),在release_console_sem()中才真正的對全局的log_buf中的內容相應的console設備驅動進行處理。至此,可以得到如下的一些結論:
(1)printk的主操作實際上還是針對一個buffer(log_buf),該buffer中的內容是否顯示(或者說向終端輸出),則要看是否可以獲得console_sem(2)printk所在的文件為printk.c,是和體系結構無關的,因此對任何平台都一樣。 可以推測的結論是:
(1)kernel在初始化時將console_sem標為了locked,因此在start_kernel一開始的printk(linux_banner)中實際只將輸入寫入了緩沖,等在串口和console初始化後,對printk的調用才一次將緩沖中的內容向串口和console輸出。 (2)在串口和console的初始化過程中,必然有對console_sem的up操作。
(3)因此,在embedded的調試中,如果在console的初始化之前系統出了問題,不會有任何的輸出。 唯一可以使用的只能是led或jtag了。(4)因此,你的問題可以看出解答。2.console的初始化.
不知道你用的是那一個內核版本,在我看的2.4.18和2.4.19中,都是在start_kernel中就對console進行的初始化。從前面的分析來看,console的初始化不應該太晚,否則log_buf有可能溢出。
多謝樓上,分析的很精彩!
我們用的內核版本是2.4.18,console的初始化確實是在
start_kernel->console->init。關於tty和串口,我這里還想再問一下tty設備的操作的總入口
是
static struct file_operations tty_fops = {
llseek: no_llseek,
read: tty_read,
write: tty_write,
poll: tty_poll,
ioctl: tty_ioctl,
open: tty_open,
release: tty_release,
fasync: tty_fasync,
};
而對串口的操作定義在:
static struct tty_driver serial_driver 這個結構中
serial.c中的多數函數都是填充serial_driver中的函數指針
那麼在對串口操作時,應該是先調用tty_fops中的操作(比如
tty_open等),然後再分流到具體的串口操作(rs_open等)吧?
但tty_driver(對串口就是serial_driver)中有很多函數指針
並不跟file_operations中的函數指針對應,不知道這些對應
不上的操作是如何被執行的?比如put_char,flush_char,read_proc,
write_proc,start,stop等。
以下是我對這個問題的一些理解:
這實際上還是回到原先的老問題,即tty和tty_driver之間的關系。從實現上看,tty_driver實際上是tty機制的實現組件之一,借用面向對象設計中的常用例子,這時的tty_driver就象是tty這部汽車的輪胎,tty這部汽車要正常運行,還要tty_ldisc(行規程),termios,甚至struct tq_struct tq_hangup(看tty_struct)等基礎設施。它們之間的關系並非繼承。至於tty_driver中的函數指針,再打個C++中的比喻,它們實際上很象虛函數,也就是說,可以定義它們,但並不一定實現它們、實際上還不用說tty_driver,只要查一下serial_driver都會發現n多個具體的實現,但對各個具體的設備,其tty_driver中的函數不一定全部實現、所以put_char,flush_char,read_proc, write_proc,start,stop這些函數的情況是有可能實現,也有可能不實現 即使被實現,也不一定為上層(VFS層)所用.