Linux檔案系統的案頭應用

來源:互聯網
上載者:User


本文中要介紹一個所謂的"Linux 檔案系統的守護神",這是指一個能即時地觀察 Linux 檔案系統的變化情況的程式模組。能夠即時的觀察檔案系統的變化情況,並做出及時的適當的反應,這對於應用 Linux 做案頭電腦系統來說,是十分的有趣,也是十分的重要的。本文還要介紹 Linux 檔案系統的非同步 I/O 的擴充。同樣,這對於 Linux 系統的案頭應用也是關鍵的。
1、Linux 檔案系統的守護神
傳統的 Linux 檔案系統呈現給使用者程式的介面,確實是十分的乾淨利落。使用者程式可以開啟一個檔案,向檔案中線性寫入資料,從檔案的某一位置開始,線性讀出資料,關閉一個檔案,刪除一個檔案,建立一個檔案,等等。請看,只有這麼若干個簡潔的操作原語,可是卻能提供這麼多豐富的應用。但是,我們注意到,用於訪問 Linux 的檔案系統的這些操作原語,並沒有提供非常複雜的加鎖解鎖的功能。這是一件很奇妙的事情,如果來自不同的使用者程式的請求發生了衝突怎麼辦呢?
我們不妨走的再靠近一點,仔細的看看刪除一個檔案是怎樣進行的。如果已經有一個使用者程式在訪問一個檔案,而另外一個使用者程式正好要刪除這一個檔案,這時會發生些什麼呢?我們知道,Linux 的檔案系統是基於所謂的 inode 的,每個檔案都相伴有一個 inode。在 inode 中記錄了關於這個檔案的一些系統資訊,比如檔案的所有者,檔案相關的一些許可權記錄,關於檔案的若干個時間戳記,等等。在記憶體中的 inode 還維持著一個關於自己的使用計數。每當一個 inode 所代表的檔案被開啟一次,這個 inode 就把關於自己的使用計數加一。每當這個 inode 所代表的檔案一被關閉,這個 inode 就把關於自己的使用計數減一。當使用者程式刪除一個檔案的時候,相關的系統調用很快就返回到這個使用者程式,告訴它,相應的檔案已經被刪除了。但是相應的 inode 還是保留在系統中,inode 首先要檢查自己的使用計數,如果使用計數為零,那麼 Linux Kernel 才可以真正的去刪除這個檔案。如果使用計數大於零,也就是說,還有其它的使用者程式在訪問這一個檔案,那麼 Linux Kernel 需要等待這些其他的使用者程式一個個都完成對這一個檔案的訪問才行。也就是說,要等到這個 inode 的使用計數掉到零,才能真正的去刪除這一個檔案。
我們可以設想一下,如果有一個 MP3 播放程式在播放一首 MP3 音樂,我們覺得它不好聽,就到硬碟上找到這個檔案,把它 rm 掉了。這時候,MP3 播放程式並不受到影響,還是可以繼續播放這首 MP3 音樂,雖然這時候在檔案系統上用 ls 已經找不到這個 MP3 音樂檔案了。實際上,一直要到 MP3 播放程式停止播放這首 MP3 音樂,然後 Linux 檔案系統才真正的從硬碟上刪除這個 MP3 檔案。這個經驗和我們在 Windows 平台上遇到的截然不同。
在 Windows 平台上,當我們試圖在檔案夾視窗中用滑鼠點擊右鍵菜單刪除 Winamp 現正播放的一首 MP3 音樂的時候,Windows 系統會用一個彈出對話方塊告訴我們,這個檔案正在被使用,沒辦法刪除。Windows 系統的關於刪除檔案的這樣一個解釋,如果使用不當的話,會帶來一個滑稽可笑的問題。我們可以設想一下,使用者的一個 P2P 的檔案共用程式提供了一個 MP3 檔案以供別人下載,恰巧這個 MP3 音樂檔案十分的熱門,不斷的有人來下載,這個使用者最終決定要節省一下頻寬,想要把這個 MP3 音樂檔案刪除掉,但是 Windows 系統卻不允許使用者這樣做,因為這個 P2P 的檔案共用程式總是在使用這個 MP3 檔案。使用者要想刪除這個檔案,不得不先把 P2P 的檔案共用程式給停下來!呵呵。
但是 Linux 的檔案系統的操作原語也有它自己的問題。我們知道,在一個 Linux Shell 的命令列上,先 rm,然後再 ls,非常的乾淨,被 rm 的檔案沒有了,被刪除了。但是我們可以設想有一個圖形介面的檔案管理程式,當使用者從 Shell 的命令列上 rm 掉一個檔案的時候,這個圖形介面的檔案管理程式並沒有收到任何人發給它的任何訊息,它還以為什麼都沒有發生,被刪除掉的檔案還在那兒。這實在是很 U.G.L.Y. 啊。
那麼要想解決這個問題,一個明顯的但是非常不好的辦法,就是讓一個後台進程 Daemon 每隔一個很短的時間間隔,就檢查一下檔案系統上這個目錄的情況,看看有沒有發生什麼變化。這個辦法的缺點真的是顯而易見的,不但系統的效能受到影響,而且它的反應也還不是即時的。
如果我們需要使用者程式能夠即時地瞭解檔案系統上某一個目錄的變化情況,從即時這個角度出發,顯然,我們需要有一個中斷機制。我們都知道,硬體中斷能夠即時地把系統某一個組件的情況反映給中央處理器,同樣的,要想把位於系統核心中的檔案系統的情況即時地反映給使用者程式,我們也需要一個由作業系統核心到達使用者進程的軟體中斷機制。熟悉 Linux 系統編程的讀者朋友們立即就會想到,這個中斷機制在 Linux 系統中早已就有了,這就是訊號傳遞 signal。
找到了訊號傳遞這樣一個中斷使用者進程的機制,一切似乎都已齊備,看來可以動手實現這樣一個 Linux 檔案系統的守護神,來即時地監視檔案系統的變化情況,並且及時地把訊息通知給使用者程式了。不過且慢,讓我們搜尋一下 Linux Kernel,看看是否有別人也在做同樣的工作。哈哈,果不其然,原來這樣一個即時地監視檔案系統情況的機制早已在 Linux 核心中實現了。下面一段就是取自 Linux Kernel 文檔的一段小小常式,說明了 Linux Kernel 中的 dnotify 功能的用法。dnotify 就是指 directory notification,監視檔案系統上一個目錄中的情況。
#define _GNU_SOURCE /* needed to get the defines */
#include <fcntl.h> /* in glibc 2.2 this has the needed
values defined */
#include <signal.h>
#include <stdio.h>
#include <unistd.h>

static volatile int event_fd;
// 訊號處理常式
static void handler(int sig, siginfo_t *si, void *data)
{
event_fd = si->si_fd;
}

int main(void)
{
struct sigaction act;
int fd;

// 登記訊號處理常式
act.sa_sigaction = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
sigaction(SIGRTMIN, &act, NULL);

// 需要瞭解目前的目錄"."的情況
fd = open(".", O_RDONLY);
fcntl(fd, F_SETSIG, SIGRTMIN);
fcntl(fd, F_NOTIFY, DN_MODIFY|DN_CREATE|DN_MULTISHOT);
/* we will now be notified if any of the files
in "." is modified or new files are created */
while (1) {
// 收到訊號後,就會執行訊號處理常式。
// 而 pause() 也就結束了。
pause();
printf("Got event on fd=%d\n", event_fd);
}
}
上面這一小段常式,對於熟悉 Linux 系統編程的讀者朋友們來說,是很容易理解的。程式首先註冊一個訊號處理常式,然後通知 Kernel,我要觀察 fd 上的 DN_MODIFY 和 DN_CREATE 和 DN_MULTISHOT 事件。(關於這些事件的詳細定義,請讀者朋友們參閱文後所列的參考資料。) Linux Kernel 收到這個請求後,把相應的 fd 的 inode 給做上記號,然後 Linux Kernel 和使用者應用程式就自顧自去處理各自的別的事情去了。等到 inode 上發生了相應的事件,Linux Kernel 就把訊號發給使用者進程,於是開始執行訊號處理常式,使用者程式對檔案系統上的變化也就可以及時的做出反應了。而在這整個過程中,系統以及使用者程式的正常運行基本上未受到效能上的影響。這裡還需要說明的是,dnotify 並沒有通過增加新的系統調用來完成它的功能,而是通過 fcntl 來完成任務的。增加一個系統調用,相對來說是一個很大的手術,而且如果設計不當,處理得不好的話,傷疤會一直留在那裡,這是 Linux Kernel 的開發人員們所非常不願意見到的事情。
2、Linux 檔案系統的非同步 I/O 擴充
對於案頭電腦系統來說,能夠快速的響應使用者的請求,這也是十分關鍵的。換句話說,當使用者移動滑鼠的時候,不管系統進行中什麼天大的、重要的、神聖的、不可打斷的工作,它都得立即停下,並且要讓滑鼠立即流暢的在電腦螢幕上完美地運動起來。對於習慣在傳統的 Linux 命令列上工作的讀者朋友們來說,讓滑鼠能夠在任何時間都可以在電腦螢幕上向無頭蒼蠅一樣地亂竄,竟然被當成是最重要的系統任務,這實在有一點讓人難以接受。不過,當你從 Linux 命令列上轉移到 GNOME 或者 KDE 這樣的圖形介面的使用者環境的時候,滑鼠被鎖死,百分之百的也是會讓你失去理智的。所以,還是讓我們接受這一個現實,看一看如何才能增加系統的響應速度吧。
從檔案系統的角度講,特別是考慮到網路檔案系統,它的響應速度有可能會相當的慢。當使用者在檔案管理程式中,選擇了對檔案進行某一個操作以後,檔案系統可能會需要相當長的時間,才能完成這一操作。如果檔案管理程式必須要等待檔案系統完成這一操作,然後才能繼續的話,這顯然會給檔案管理程式的使用者帶來非常不愉快的經曆。解決這一個問題的辦法,就是要實現非同步檔案系統 I/O。
在 Linux 的 Gnome 案頭環境中,由 GnomeVFS 包裹了真正的 Linux 檔案系統 I/O,實現了一個非同步檔案系統 I/O 介面 API。我們可以看到下面這個用 GnomeVFS 開啟檔案的例子。

enum _GnomeVFSOpenMode {
GNOME_VFS_OPEN_NONE = 0,
GNOME_VFS_OPEN_READ = 1 << 0,
GNOME_VFS_OPEN_WRITE = 1 << 1,
GNOME_VFS_OPEN_RANDOM = 1 << 2
};
typedef enum _GnomeVFSOpenMode GnomeVFSOpenMode;
typedef void (* GnomeVFSAsyncOpenCallback)
(GnomeVFSAsyncHandle *handle,
GnomeVFSResult result,
gpointer callback_data);
GnomeVFSResult gnome_vfs_async_open
(GnomeVFSAsyncHandle **handle_return,
const gchar *text_uri,
GnomeVFSOpenMode open_mode,
GnomeVFSAsyncOpenCallback callback,
gpointer callback_data);
我們注意到,上面的程式碼片段中,使用者程式為了開啟一個檔案,向 GnomeVFS 註冊了一個 call back 常式。在註冊了這一個 call back 常式之後,函數調用就立即返回給使用者程式,使用者程式就可以處理自己的別的事情去了,比如進一步響應來自使用者的其??肭螅?鵲取6?蔽募?低懲瓿啥暈募?拇蚩?僮饕院螅珿nomeVFS 就會調用剛剛註冊的 call back 常式,通知使用者程式,檔案已經開啟。
3、小結
我們在本文中瞭解了 Linux Kernel 中的 dnotify,可以協助我們即時地監視檔案系統分類樹中的變化情況;也瞭解了 Gnome 案頭環境的 GnomeVFS 非同步檔案系統 I/O 擴充;可以協助使用者程式不至於被檔案系統的請求所 Block。這兩個功能對於 Linux 系統在案頭上的應用都是很重要的。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.