技術(shù)員聯(lián)盟提供win764位系統(tǒng)下載,win10,win7,xp,裝機(jī)純凈版,64位旗艦版,綠色軟件,免費(fèi)軟件下載基地!

當(dāng)前位置:主頁 > 教程 > 服務(wù)器類 >

Linux中文件執(zhí)行中的鎖定的怪現(xiàn)象

來源:技術(shù)員聯(lián)盟┆發(fā)布時間:2019-02-17 12:16┆點(diǎn)擊:

  本來今天不準(zhǔn)備開電腦了,太困了,想睡覺,然而一哥們兒短信都發(fā)過來了,要問個問題,于是還是打開了電腦,沒想到是一個很有代表性的問題,順便也牽扯了前些天我的工作中的一個bug,值得記錄下來。問題如下:

  linux下,一個可執(zhí)行文件exe1正在執(zhí)行中,rm –f可以將其刪除,mv可以將其移除,mv $other exe1也可以將其替換,但是cp $other exe1則顯示文件忙,求解。

  這實(shí)際上并不是一個真正的問題,因?yàn)橹灰愕幕A(chǔ)知識扎實(shí),這個問題顯然很簡單,原因只有一個,那就是linux文件基于引用計數(shù)?,F(xiàn)在問題是這些個命令如何來操作一個文件的引用計數(shù)。下面的討論都是基于獨(dú)占打開的模式。

  如果一個文件已經(jīng)被打開,那么它的引用計數(shù)會增加1,如果調(diào)用了rm,實(shí)際上底層只是unlink了一下,也就是說將它的引用計數(shù)減少1,這樣雖然你在界面上(命令行或者GUI)看不到它了,但是它被打開時的計數(shù)還在,只有當(dāng)它被關(guān)閉的時候,引用計數(shù)變?yōu)?,才徹底刪除它。

  再說mv命令,它實(shí)際上只是一個源文件的rename而已,如果mv的目標(biāo)本來就存在,那么在目標(biāo)上執(zhí)行一個類似rm的效果,也就是unlink一下,結(jié)合引用計數(shù)的理論,目標(biāo)文件如果已經(jīng)被打開,那么當(dāng)關(guān)閉的時候?qū)⒉粡?fù)存在,如果本來就沒有被打開,那么mv的時候,目標(biāo)直接被刪除,因?yàn)閡nlink之后,它的引用計數(shù)變成了0。

  最后看一下cp命令,cp的話并不觸動源文件和目標(biāo)文件元數(shù)據(jù)本身(時間戳除外),它只是打開源文件和目標(biāo)文件,在源文件上執(zhí)行read,然后將結(jié)果write到目標(biāo)文件,實(shí)質(zhì)上是一個IO操作,對于可執(zhí)行文件,是獨(dú)占打開的,并不允許寫入,因此會出錯。

  這里就不再列出內(nèi)核源碼了,可以自行參考系統(tǒng)調(diào)用的實(shí)現(xiàn)而加深理解,不過最好別干巴巴的看,還是結(jié)合strace以及objdump比較好,要知道是怎么以及什么時候調(diào)用的,以及調(diào)用參數(shù)是什么,否則就和八股文沒區(qū)別了。那么這和我工作中的bug有什么關(guān)系呢?這個bug源于OpenVPN的日志記錄,并且配置了日志回滾,回滾配置文件關(guān)鍵字段如下:

  size 4M

  missingok

  rotate 9

  compress

  delaycompress

  create 644 xx xx

  …

  結(jié)果當(dāng)日志回滾成了vpn.log.1之后,這個vpn.log.1依然繼續(xù)被寫入。這個原因正是rename造成的。在logrotate的man頁面中,有一個copytruncate配置,其含義就是不進(jìn)行rename,而只是copy,然后將原來的文件truncate,加入這個就可以了。

  千萬不要小看這些很簡單的命令,真正理解的人并不多,即使真正的理解,出現(xiàn)問題,能真正對應(yīng)到原理也不多,很簡單的東西如果能徹底做到透徹的理解并且活用,再往深入學(xué)習(xí)才是有意義的。