導航:首頁 > 文件目錄 > 如何去寫一個文件系統

如何去寫一個文件系統

發布時間:2022-09-16 16:58:14

『壹』 文件系統是如何建立的

右擊,新建文件夾
針對各層簡要分析如下:

1.首先我們來分析最低層——設備驅動層,該層負責與外設——磁碟等——通訊。文件系統都需要和存儲設備打交道,而系統操作外設時離不開驅動程序。所以內核對文件的最後操作行為就是調用設備驅動程序完成從主存(內存)到輔存(磁碟)的數據傳輸。

文件系統相關的多數設備都屬於塊設備,常見的塊設備驅動程序有磁碟驅動,光碟機驅動等,之所以稱它們為塊設備,一個原因是它們讀寫數據都是成塊進行的,但是更重要的原因是它們管理的數據能夠被隨機訪問——不需要像字元設備那樣必須順序訪問。

2.設備驅動層的上一層是物理I/O層,該層主要作為計算機外部環境和系統的介面,負責系統和磁碟之間數據塊的交換。它要知道數據塊在磁碟中地存儲位置,也要知道文件數據塊在內存緩沖中的位置,另外,它不需要了解數據或文件的具體結構。可以看到,這層最主要的工作是識別磁碟扇區和內存緩沖塊[2]之間的映射關系。

3.再上層是基礎I/O監督層,該層主要負責選擇文件 I/O需要的設備,調度磁碟請求等工作,另外分配I/O緩沖和磁碟空間也在該層完成。由於塊設備需要隨機訪問數據,而且對速度響應要求較高,所以操作系統不能像對字元設備那樣簡單、直接地發送讀寫請求,而必須對讀寫請求重新優化排序,以能節省磁碟定址時間,另外也必須對請求提交採取非同步調度(尤其寫操作)的方式進行。總而言之,內核必須管理塊設備請求,而這項工作正是由該層負責的。

4.倒數第二層是邏輯I/O層,該層允許用戶和應用程序訪問記錄。它提供了通用的記錄(record)I/O操作,同時還維護基本文件數據。為了方便用戶操作和管理文件內容,文件內容往往被組織成記錄形式,所以操作系統為操作文件記錄提供了一個通用的邏輯操作層。

『貳』 如何寫一個核心系統,資料庫,分布式文件系統等等

當下,互聯網行業發展非常迅猛,分布式文件系統在其中的應用也非常普遍。一些朋友問起一些相關問題,如: 1/p/tfs/wiki/index/ 3. 視頻類的,單個文件大小大多在幾十兆或上百兆,與TAOTAO里的小圖片(幾K到幾十K)又不一樣。參照TAOBAO的文件系統,也許可以一試。GFS或者MooseFS也可以一試。商家,國內有個公司叫龍存,不知道費用如何。使用TFS,單文件跨塊存儲,如果支持的話,倒不妨一試。 4. 這個問題應該分成兩塊, 矢量圖形數據本身,應該還要藉助於空間資料庫(如Oracle Spatial, PostGIS, ArcSDE引擎等)進行存儲,因為它還是涉及到事務處理的。對外展現的圖形(影像),分級分塊,可以藉助於小文件聚合的思想。但是數據量,未必有前邊3個那麼大。普通的可隨機讀寫的GFS是不是能滿足需求

『叄』 如何製作linux根文件系統

根文件系統一直以來都是所有類Unix操作系統的一個重要組成部分,也可以認為是嵌入式Linux系統區別於其他一些傳統嵌入式操作系統的重要特徵,它給Linux帶來了許多強大和靈活的功能,同時也帶來了一些復雜性。我們需要清楚的了解根文件系統的基本結構,以及細心的選擇所需要的系統庫、內核模塊和應用程序等,並配置好各種初始化腳本文件,以及選擇合適的文件系統類型並把它放到實際的存儲設備的合適位置。
Linux的根文件系統以樹型結構組織,包含內核和系統管理所需要的各種文件和程序,一般說來根目錄」/」下的頂層目錄都有一些比較固定命名和用途。
下面列出了一個Linux根文件系統中的比較常見的目錄結構:
/bin 存放二進制可執行命令的目錄
該目錄下存放所有用戶都可以使用的、基本的命令,這些命令在掛接其它文件系統之前就可以使用,所以/bin目錄必須和根文件系統在同一個分區中。
/bin目錄下常用的命令有:cat,chgrp,chmod,cp,ls,sh,kill,mount,umount,mkdir,m knod,[,test等「[」命令其實就是test命令,我們在利用Busybox製作根文件系統時,在生成的bin目錄下,可以看到一些可執行的文件,也就是可用的一些命令。
/dev 存放設備文件的目錄
該目錄下存放的是設備文件,設備文件是Linux中特有的文件類型,在Linux系統下,以文件的方式訪問各種設備,即通過讀寫某個設備文件操作某個具體硬體。比如通過"dev/ttySAC0"文件可以操作串口0,通過"/dev/mtdblock1"可以訪問MTD設備的第2個分區。
/etc 存放系統管理和配置文件的目錄
該目錄下存放著各種配置文件,對於PC上的Linux系統,/etc目錄下的文件和目錄非常多,這些目錄文件是可選的,它們依賴於系統中所擁有的應用程序,依賴於這些程序是否需要配置文件。在嵌入式系統中,這些內容可以大為精減。
/home 用戶主目錄,比如用戶user的主目錄就是/home/user,可以用~user表示
用戶目錄,它是可選的,對於每個普通用戶,在/home目錄下都有一個以用戶名命名的子目錄,裡面存放用戶相關的配置文件。
/lib 存放動態鏈接共享庫的目錄
該目錄下存放共享庫和可載入(驅動程序),共享庫用於啟動系統。運行根文件系統中的可執行程序,比如:/bin /sbin 目錄下的程序。
/sbin存放系統管理員使用的管理程序的目錄
該目錄下存放系統命令,即只有管理員能夠使用的命令,系統命令還可以存放在/usr/sbin,/usr/local/sbin目錄下,/sbin目錄中存放的是基 本的系統命令,它們用於啟動系統,修復系統等,與/bin目錄相似,在掛接其他文件系統之前就可以使用/sbin,所以/sbin目錄必須和根文件系統在同一個分區中。
/sbin目錄下常用的命令有:shutdown reboot fdisk fsck等,本地用戶自己安裝的系統命令放在/usr/local/sbin目錄下。

/tmp 公用的臨時文件存儲點
用於存放臨時文件,通常是空目錄,一些需要生成臨時文件的程序用到的/tmp目錄下,所以/tmp目錄必須存在並可以訪問。
/root 系統管理員的主目錄
根用戶的目錄,與此對應,普通用戶的目錄是/home下的某個子目錄。
/mnt 系統提供這個目錄是讓用戶臨時掛載其他的文件系統。
用於臨時掛載某個文件系統的掛接點,通常是空目錄,也可以在裡面創建一引起空的子目錄,比如/mnt/cdram /mnt/hda1 。用來臨時掛載光碟、硬碟。
/proc 虛擬文件系統,可直接訪問這個目錄來獲取系統信息。
這是一個空目錄,常作為proc文件系統的掛接點,proc文件系統是個虛擬的文件系統,它沒有實際的存儲設備,裡面的目錄,文件都是由內核臨時生成的,用來表示系統的運行狀態,也可以操作其中的文件控制系統。
/usr 最龐大的目錄,要用到的應用程序和文件幾乎都在這個目錄。
/usr目錄的內容可以存在另一個分區中,在系統啟動後再掛接到根文件系統中的/usr目錄下。裡面存放的是共享、只讀的程序和數據,這表明/usr目錄下的內容可以在多個主機間共享,這些主要也符合FHS標準的。/usr中的文件應該是只讀的,其他主機相關的,可變的文件應該保存在其他目錄下,比如/var。/usr目錄在嵌入式中可以精減。
/var 某些大文件的溢出區
與/usr目錄相反,/var目錄中存放可變的數據,比如spool目錄(mail,news),log文件,臨時文件。
---------------------------------------------------------------------
一、移植環境:
1、 Ubuntu 10.10發行版
2、 u-boot.bin
3、 目標機:FS_S5PC100平台
4、 交叉編譯器 arm-cortex_a8-linux-gnueabi-gcc
---------------------------------------------------------------------
二、移植步驟
1、 源碼下載
我們選擇的版本是busybox-1.17.3.tar.bz2下載路徑為:
http://busybox.net/downloads/
2、 解壓源碼
$ tar xvf busybox-1.17.3.tar.bz2
3、 進入源碼目錄
$ cd busybox-1.17.3
4、 配置源碼
$ make menuconfig

Busybox Settings --->
Build Options --->
[*] Build BusyBox as a static binary (no shared libs)
[ ] Force NOMMU build
[ ] Build with Large File Support (for accessing files > 2 GB)
(arm-cortex_a8-linux-gnueabi-) Cross Compiler prefix
() Additional CFLAGS

5、 編譯
$ make
6、 安裝
busybox默認安裝路徑為源碼目錄下的_install
$ make install
7、 進入安裝目錄下
$ cd _install
$ ls
bin linuxrc sbin usr
8、 創建其他需要的目錄
$ mkdir dev etc mnt proc var tmp sys root
9、 添加庫
在_install目錄下創建一個lib文件夾,將工具鏈中的庫拷貝到lib目錄下
$ mkdir lib
$ cp /home/linux/x-tools/arm-cortex_a8-linux-gnueabi/arm-cortex_a8-linux-gnueabi/lib/* ./lib/
刪除lib下的所有目錄、.o文件和.a文件,對庫進行瘦身以減小文件系統的大小
$ rm *.o *.a
$ arm-cortex_a8-linux-gnueabi-strip lib/*
10、 添加系統啟動文件
在etc下添加文件inittab
$ vim /etc/inittab
文件內容如下:

#this is run first except when booting in single-user mode.
:: sysinit:/etc/init.d/rcS
# /bin/sh invocations on selected ttys
# Start an "askfirst" shell on the console (whatever that may be)
::askfirst:-/bin/sh
# Stuff to do when restarting the init process
::restart:/sbin/init
# Stuff to do before rebooting
::ctrlaltdel:/sbin/reboot

在etc下添加文件fstab
$ vim /etc/fstab
文件內容如下:
#device mount-point type options mp fsck order
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
這里我們掛在的文件系統有三個proc、sysfs和tmpfs,在內核中proc和sysfs默認都支持,而tmpfs是沒有支持的,我們需要添加tmpfs的支持
修改內核配置:
$ make menuconfigFile systems --->
Pseudo filesystems --->
[*] Virtual memory file system support (former shm fs)
[*] Tmpfs POSIX Access Control Lists
重新編譯內核
$ make zImage
在etc下創建init.d目錄,並在init.d下創建rcS文件
$ mkdir /etc/init.d -p
$ vim /etc/init.d/rcS
rcS文件內容為:
#!/bin/sh
# This is the first script called by init process
/bin/mount -a
為rcS添加可執行許可權:
$ chmod +x init.d/rcS
在etc下添加profile文件
$ vim /etc/profile
文件內容為:

#!/bin/sh
export HOSTNAME=farsight
export USER=root
export HOME=root
#export PS1="\[\u@\h \W\]\$ "
export PS1="[$USER@$HOSTNAME \W]\# "
PATH=/bin:/sbin:/usr/bin:/usr/sbin
LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
export PATH LD_LIBRARY_PATH

11、 設備文件創建
根文件系統中有一個設備節點是必須的,在dev下創建console節點
$ mknod dev/console c 5 1
重要:新製作的文件系統尺寸若超出8M,刪除不需要的庫文件。

『肆』 如何從零開始寫一個簡單的操作系統

(一)OS說明
今後,我就要開始折騰操作系統,有了一點小小干勁。

我的計劃是,先看過一份用於教育目的的系統源碼,再去翻找相應的資料(我手頭已有綠寶書),在翻資料的同時開始寫代碼,然後做好移植真機的工作,DONE!
我也明白,理性很豐滿,現實很骨感,這過程不會如同我計劃中這般簡單和輕松。但是,見難而退可不是我的風格(那樣我會被紅葉二小姐調戲的),不管如何,我都會,怎麼說呢,盡力吧。

出於課程需求,斯坦福那些人親自寫了一個名為「pintos」的系統。pintos的結構比較簡單,分為進程管理、文件系統、用戶程序、虛擬內存等幾個部分,也正是因為這個原因,我選擇pintos作為我的參考藍本,現在在讀它的源碼。

在接下來的幾個月時間里,不出意外的話,我會不斷的在博客上更新我的進度。

(三)交叉編譯環境
倘若我們要在ubuntu上編譯另外一個完整的OS,交叉編譯環境是必不可少的玩意,維基網路有雲:

交叉編譯器(英語:Cross compiler)是指一個在某個系統平台下可以產生另一個系統平台的可執行文件的編譯器。
(想起以前,我為了給路由器編譯OPENWRT,下載大量源碼,愣是編譯了幾天幾夜。那時候的我,真是「可愛」。)
為了配置好交叉編譯環境,我廢了好大力氣,最後勉強找到了組織。
編譯環境大致分為2部分,binutils和gcc。我先裝好gcc-4.9.1,之後下載gcc-4.9.1和binutils-2.25的源代碼,似乎gcc版本與binutils版本要對應來著…

開始編譯之前,需要准備全局變數(在命令行中敲入以下命令):

export PREFIX=」$HOME/opt/cross」
export TARGET=i686-elf
export PATH=」$PREFIX/bin:$PATH」
編譯Binutils
cd $HOME/binutils-2.25
mkdir build-binutils
cd build-binutils

#注意是在源碼目錄下面新建一個文件夾,然後cd到該文件夾里,然後才配置configure,不這么做的話,嘿嘿..
../binutils-x.y.z/configure –target=$TARGET –prefix=」$PREFIX」 –with-sysroot –disable-nls –disable-werror
make
make install
–disable-nls 告訴binutils,不要添加本地語言支持

–with-sysroot 告訴binutils,在交叉編譯器中允許sysroot

編譯GCC
cd $HOME/gcc-4.9.1
mkdir build-gcc
cd build-gcc

#注意是在源碼目錄下面新建一個文件夾,然後cd到該文件夾里,然後才配置configure,不這么做的話,嘿嘿..
../gcc-x.y.z/configure –target=$TARGET –prefix=」$PREFIX」 –disable-nls –enable-languages=c,c++ –without-headers
make all-gcc
make all-target-libgcc
make install-gcc
make install-target-libgcc
–disable-nls 告訴GCC,不要添加本地語言支持。

–without-headers 告訴GCC,不要依賴任何本地庫,我們必須在自己的OS中實現庫。

–enable-languages 告訴GCC,不要支持除了C、C++之外的語言。

提醒
不同機器配置不同,編譯速度也不同。

編譯這兩個軟體,我花了近3個鍾,機器配置之低自不必說,說了都是淚。

如果任何人的任何編譯過程出了任何問題,請仔細地、認真地、用心地再看看上面的命令,在你沒有弄懂它的原理之前,請不要擅自做任何「改進」(血淋淋、赤裸裸的教訓呀)。

(五)OS模糊框架
翻完了手頭的綠寶書,我才曉得,人都是被逼出來的。

操作系統的概念都差不多已經知道,接下來,該由「理論態」切換到「實踐態」了喔(書還是不能看太多,會中毒的–)。

對了,從別人推薦的地方弄來了一個框架(曾在android平台寫了幾萬代碼,我深深體會到框架的作用),輕松開工吧。

『伍』 如何用C寫一個虛擬的磁碟和文件系統

我是高手~ 告訴我你郵箱 我發給你

『陸』 如何設計一個小型文件系統,提供創建、打開、讀、寫、關閉、刪除文件的功能。

這是一個簡單的程序設計問題,學過c的人都會。在c 裡面提供了功能強大的文件管理函數,fopen ,fread,fwrite,fclose,等,多看一下,自己就會了

『柒』 如何製作和使用Jffs2文件系統

嵌入應用:如何製作和使用Jffs2文件系統 (zhuan)本文主要介紹如何在AT91SAM9261EK板子上製作和使用jffs2文件系統,使用的是linux-2.6.21內核。

首先配置MTD

$ make menuconfig
進入 Memory Technology Devices (MTD) --->
<*> Memory Technology Device (MTD) support
[*] Debugging
[*] MTD partitioning support
[*] Command line partition table parsing
[*] Direct char device access to MTD devices
[*] Caching block device access to MTD devices
RAM/ROM/Flash chip drivers ----->
<*> Detect non-CFI AMD/JEDEC-compatible flash chips
<*> Support for AMD/Fujitsu flash chips
Mapping drivers for chip access --->
[*] Support non-linear mappings of flash chips
Self-contained MTD device drivers --->
[*] Support for AT45... DataFlash
NAND Flash Device Drivers ---->
[*] NAND Device Support
[*] Support for NAND Flash /SmartMedia on AT91
File systems ---->
<*> Second extended fs support
[*] Inotify file change notification support
[*] Inotify support for user space
<*> Filesystem in Userspace support
Miscellaneous filesystems
<*> Journalling Flash File System v2 (JFFS2) support
[*] JFFS2 write-buffering support
<*> Compressed ROM file system support (cramfs)

以上配置中沒有列出的,都沒選;其配置僅做參考,可根據自己的需要自行配置。

$ make all

其次製作mtd-util工具

從網上下載zlib-1.2.3.tar.gz解壓縮$ cd zlib-1.2.3

$ ./configure –prefix=/usr/local/arm/3.4.1/arm-linux --shared

修改Makefile如下:

CC=arm-linux-gcc

LDSHARED=arm-linux-ld -shared

$ make all

$ make install

注意:這里是安裝在/usr/local/arm/3.4.1/arm-linux目錄下

由於交叉編譯mtd工具時需要zlib.h文件,所以在編譯之前先安裝zlib庫文件。

從網上下載mtd-snapshot-20050519.tar.bz2 解壓縮 $ cd mtd/util

修改該目錄下的Makefile:

CROSS=arm-linux-

$ make all

然後將該目錄下生成的 flash_erase,flash_eraseall, mkfs.jffs2工具放在ramdisk 文件系統中(我這里放在/bin目錄下),另外在ramdisk文件系統的dev目錄下要保證有mtd0~mtd9,mtdblock0~mtdblock9這些設備,如果沒有可參考 ramdisk文件系統的製作,也可從pc機相同目錄下拷貝,要加上文件屬性。

另外,需要將/arm-linux/lib目錄下的libz.so, libz.so.1, libz.so.1.2.3文件拷貝到ramdisk文件系統的/lib目錄下,否則mkfs.jffs2工具不能使用。

最後將新生成的uImage和ramdisk文件下載到板子上,起動系統,使用命令 cat /proc/mtd可以看到

dev: size erasesize name

mtd0: 00040000 00020000 "Partition 1"

mtd1: 0ffc0000 00020000 "Partition 2"

mtd2: 00420000 00000210 "spi0.0-AT45DB321x"

這里mtd0,mtd1是nandflash上的分區; mtd2是dataflsh上的分區,該分區上放有u-boot,uImage.img,ramdisk.img,所以我們這里可以使用空的nandflash上的兩個分區。使用之前要先用工具flash_erase或者flash_eraseall擦除nandflash,具體使用的步驟如下:

# flash_erase /dev/mtd1

製作jffs2映像

# cd /var/tmp

# mkdir jffs2 (jffs2下的目錄可以任意建)

# mkfs.jffs2 –d jffs2/ -o jffs2.img

# cp /var/tmp/jffs2/jffs2.img /dev/mtdblock1

最後# mount -t jffs2 /dev/mtdblock1 /mnt/mtd即可,使用結束可使用$ umount /mnt/mtd卸載.

如果只是當作普通的jffs2 來使用dataflash或者nandflash,可不必製作 jffs2映像,只需要最後一步,# mount -t jffs2 /dev/mtdblock1 /mnt/mtd即可。

AT91sam9263EK使用JFFS2根文件系統

在AT91sam9263EK成功配置了NFS根文件系統後,後來又想把JFFS2也移植到AT91sam9263EK上吧,說干就干。

1. 呵呵,其實很簡單我使用的linux-2.6.20內核里已經有jffs2 文件系統支持,選上jffs2即可

File systems --->

Miscellaneous filesystems --->

<*> Journalling Flash File System v2 (JFFS2) support

(0) JFFS2 debugging verbosity (0 = quiet, 2 = noisy)

[*] JFFS2 write-buffering support

[*] JFFS2 summary support (EXPERIMENTAL)

[*] JFFS2 XATTR support (EXPERIMENTAL)

[*] JFFS2 POSIX Access Control Lists

[*] JFFS2 Security Labels

[*] Advanced compression options for JFFS2

[*] JFFS2 ZLIB compression support

[*] JFFS2 RTIME compression support

[ ] JFFS2 RUBIN compression support

JFFS2 default compression mode (priority)

選上MTD支持

Device Drivers --->

Memory Technology Devices (MTD) --->

<*> Memory Technology Device (MTD) support

[ ] Debugging

<*> MTD concatenating support

[*] MTD partitioning support

< > RedBoot partition table parsing

[*] Command line partition table parsing

<*> ARM Firmware Suite partition parsing

--- User Moles And Translation Layers

<*> Direct char device access to MTD devices

<*> Caching block device access to MTD devices

<*> FTL (Flash Translation Layer) support

<*> NFTL (NAND Flash Translation Layer) support

[ ] Write support for NFTL

2. 從ttp://www.linux-mtd.infradead.org/上下載

mtd-utils-1.0.0.tar.gz 到宿主機。

解壓

tar xvzf mtd-utils-1.0.0.tar.gz

進入mtd-utils-1.0.0目錄修改Makefile進行編譯。

編譯出mkfs.jffs2,nandwrite等工具

3. 創建jffs2根文件系統:

首先要有一個其他類型的根文件系統,製作和獲取方式可以參見<< AT91sam9263EK使用NFS根文件系統>>

比如可以:

mount -t cramfs rootfs_lnxdemo.cramfs tmp/ -o loop

rootfs_lnxdemo.cramfs由atmel提供當然你可以自己製作,這里直接使用atmel的省去了製作的麻煩。

tar czvf target.tar.gz tmp/

生成jffs2根文件系統鏡像:

mkfs.jffs2 –l –s 0x400 –e 0x20000 –d tmp/ -o target.jffs2

4. 燒寫jffs2根文件系統鏡像到nand flash。

燒寫方法應該有多種常用的有2種(呵呵自己認為的):

a.通過nand編程器燒寫鏡像文件到nand flash晶元然後再焊接到pcb.

b.掛載nfs文件系統,使用nandwrite工具寫鏡像文件

到mtd設備。

第一種適合生產時使用,而我們測試時候比較適合使用第二種方式。

掛載nfs文件系統:

nandwrite –o /dev/mtd1 target.jffs2

或者是在nfs 根文件系統下:

mount –t jffs2 /dev/mtdblock1 /mnt

cd /mnt

tar xvzf ../target.tar.gz

umount /mnt

5. 配置內核啟動參數如下:

setenv bootargs mem=64M console=ttyS0 115200 root=/dev/mtdblock1 rootfstype=jffs2 rw

6. 重新啟動,呵呵內核使用jffs2文件系統自動掛載根文件系統到mtdblock1設備上。

ls 測試一下

vi test

hello this is for test jffs2 filesystem.

保存退出。

Sync

重新啟動

vi test

內容依舊。

Ok jffs2根文件系統引導成功。
Linux聯盟收集整理 ,轉貼請標明原始鏈接

『捌』 寫一個文件系統類 表示一個文件的路徑(Java)

一定有你需要的。
System.out.println(Thread.currentThread().getContextClassLoader().getResource(""));
System.out.println(Test.class.getClassLoader().getResource(""));
System.out.println(ClassLoader.getSystemResource(""));
System.out.println(Test.class.getResource(""));
System.out.println(Test.class.getResource("/"));
System.out.println(new File("").getAbsolutePath());
System.out.println(System.getProperty("user.dir"));
本地運行結果:
file:/D:/snsoft80/bin/apptrade/
file:/D:/snsoft80/bin/apptrade/
file:/D:/snsoft80/bin/apptrade/
file:/D:/snsoft80/bin/apptrade/hsy/
file:/D:/snsoft80/bin/apptrade/
D:\snsoft80\Workspc\apptrade
D:\snsoft80\Workspc\apptrade

『玖』 如何用C寫一個虛擬的磁碟和文件系統①

#include <stdio.h>
#include <stdlib.h> //為了使用抄exit()
int main()
{
char ch;
FILE* fp;
char fname[50]; //用於存放襲文件名
printf("輸入文件名:");
scanf("%s",fname);
fp=fopen(fname,"r"); //只供讀取
if(fp==NULL) //如果失敗了
{

『拾』 如何實現一個文件系統

摘要:本文目的是分析在Linux系統中如何實現新的文件系統。在介紹文件系統具體實現前先介紹文件系統的概念和作用,抽象出了文件系統概念模型。熟悉文件系統的內涵後,我們再近一步討論Linux系統中和文件系統的特殊風格和具體文件系統在Linux中組成結構,為讀者勾畫出Linux中文件系統工作的全景圖。最後,我們再通過Linux中最簡單的Romfs作實例分析實現文件系統的普遍步驟。(我們假定讀者已經對Linux文件系統初步了解)
什麼是文件系統
首先要談的概念就是什麼是文件系統,它的作用到底是什麼。
文件系統的概念雖然許多人都認為是再清晰不過的了,但其實我們往往在談論中或多或少地誇大或片縮小了它的實際概念(至少我時常混淆),或者說,有時借用了其它概念,有時說的又不夠全面。
比如在操作系統中,文件系統這個術語往往既被用來描述磁碟中的物理布局,比如有時我們說磁碟中的「文件系統」是EXT2或說把磁碟格式化成FAT32格式的「文件系統」等——這時所說的「文件系統」是指磁碟數據的物理布局格式;另外,文件系統也被用來描述內核中的邏輯文件結構,比如有時說的「文件系統」的介面或內核支持Ext2等「文件系統」——這時所說的文件系統都是內存中的數據組織結構而並非磁碟物理布局。還有些時候說「文件系統」負責管理用戶讀寫文件——這時所說的「文件系統」往往描述操作系統中的「文件管理系統」,也就是文件子系統。
雖然上面我們列舉了混用文件系統的概念的幾種情形,但是卻也不能說上述說法就是錯誤的,因為文件系統概念本身就囊括眾多概念,幾乎可以說在操作系統中自內存管理、系統調度到I/O系統、設備驅動等各個部分都和文件系統聯系密切,有些部分和文件系統甚至未必能明確劃分——所以不能只知道文件系統是系統中數據的存儲結構,一定要全面認識文件系統在操作系統中的角色,才能具備自己開發新文件系統的能力。
為了澄清文件系統的概念,必須先來看看文件系統在操作系統中處於何種角色,分析文件系統概念的內含外延。所以我們先拋開Linux文件系統的實例,而來看看操作系統中文件系統的普遍體系結構,從而增強對文件系統的理論認識。
下面以軟體組成的結構圖[1]的方式描述文件系統所涉及的內容。

我們針對各層做以簡要分析:
首先我們來分析最低層——設備驅動層,該層負責與外設——磁碟等——通訊。基於磁碟的文件系統都需要和存儲設備打交道,而系統操作外設離不開驅動程序。所以內核對文件的最後操作行為就是調用設備驅動程序完成從主存(內存)到輔存(磁碟)的數據傳輸。文件系統相關的多數設備都屬於塊設備,常見的塊設備驅動程序有磁碟驅動,光碟機驅動等,之所以稱它們為塊設備,一個原因是它們讀寫數據都是成塊進行的,但是更重要的原因是它們管理的數據能夠被隨機訪問——不需要向字元設備那樣必須順序訪問。
設備驅動層的上一層是物理I/O層,該層主要作為計算機外部環境和系統的介面,負責系統和磁碟交換數據塊。它要知道據塊在磁碟中存儲位置,也要知道文件數據塊在內存緩沖中的位置,另外它不需要了解數據或文件的具體結構。可以看到這層最主要的工作是標識別磁碟扇區和內存緩沖塊[2]之間的映射關系。
再上層是基礎I/O監督層,該層主要負責選擇文件 I/O需要的設備,調度磁碟請求等工作,另外分配I/O緩沖和磁碟空間也在該層完成。由於塊設備需要隨機訪問數據,而且對速度響應要求較高,所以操作系統不能向對字元設備那樣簡單、直接地發送讀寫請求,而必須對讀寫請求重新優化排序,以能節省磁碟定址時間,另外也必須對請求提交採取非同步調度(尤其寫操作)的方式進行。總而言之,內核對必須管理塊設備請求,而這項工作正是由該層負責的。
倒數第二層是邏輯I/O層,該層允許用戶和應用程序訪問記錄。它提供了通用的記錄(record)I/O操作,同時還維護基本文件數據。由於為了方便用戶操作和管理文件內容,文件內容往往被組織成記錄形式,所以操作系統為操作文件記錄提供了一個通用邏輯操作層。
和用戶最靠近的是訪問方法層,該層提供了一個從用戶空間到文件系統的標准介面,不同的訪問方法反映了不同的文件結構,也反映了不同的訪問數據和處理數據方法。這一層我們可以簡單地理解為文件系統給用戶提供的訪問介面——不同的文件格式(如順序存儲格式、索引存儲格式、索引順序存儲格式和哈希存儲格式等)對應不同的文件訪問方法。該層要負責將用戶對文件結構的操作轉化為對記錄的操作。

對比上面的層次圖我們再來分析一下數據流的處理過程,加深對文件系統的理解。
假如用戶或應用程序操作文件(創建/刪除),首先需要通過文件系統給用戶空間提供的訪問方法層進入文件系統,接著由使用邏輯I/O層對記錄進行給定操作,然後記錄將被轉化為文件塊,等待和磁碟交互。這里有兩點需要考慮——第一,磁碟管理(包括再磁碟空閑區分配文件和組織空閑區);第二,調度塊I/O請求——這些由基礎I/O監督層的工作。再下來文件塊被物理I/O層傳遞給磁碟驅動程序,最後磁碟驅動程序真正把數據寫入具體的扇區。至此文件操作完畢。

當然上面介紹的層次結構是理想情況下的理論抽象,實際文件系統並非一定要按照上面的層次或結構組織,它們往往簡化或合並了某些層的功能(比如Linux文件系統因為所有文件都被看作位元組流,所以不存在記錄,也就沒有必要實現邏輯I/O層,進而也不需要在記錄相關的處理)。但是大體上都需要經過類似處理。如果從處理對象上和系統獨立性上劃分,文件系統體系結構可以被分為兩大部分:——文件管理部分和操作系統I/O部分。文件管理系統負責操作內存中文件對象,並按文件的邏輯格式將對文件對象的操作轉化成對文件塊的操作;而操作系統I/O部分負責內存中的塊與物理磁碟中的數據交換。
數據表現形式再文件操作過程中也經歷了幾種變化:在用戶訪問文件系統看到的是位元組序列,而在位元組序列被寫入磁碟時看到的是內存中文件塊(在緩沖中),在最後將數據寫入磁碟扇區時看到的是磁碟數據塊[3]。
本文所說的實現文件系統主要針對最開始講到第二種情況——內核中的邏輯文件結構(但其它相關的文件管理系統和文件系統磁碟存儲格式也必須了解),我們用數據處理流圖來分析一下邏輯文件系統主要功能和在操作系統中所處的地位。

其中文件系統介面與物理布局管理是邏輯文件系統要負責的主要功能。
文件系統介面為用戶提供對文件系統的操作,比如open、close、read、write和訪問控制等,同時也負責處理文件的邏輯結構。
物理存儲布局管理,如同虛擬內存地址轉化為物理內存地址時,必須處理段頁結構一樣,邏輯文件結構必須轉化到物理磁碟中,所以也要處理物理分區和扇區的實際存儲位置,分配磁碟空間和內存中的緩沖也要在這里被處理。
所以說要實現文件系統就必須提供上面提到的兩種功能,缺一不可。

在了解了文件系統的功能後,我們針對Linux操作系統分析具體文件系統如何工作,進而掌握實現一個文件系統需要的步驟。
Linux 文件系統組成結構
Linux 文件系統的結構除了我們上面所提到的概念結構外,最主要有兩個特點,一個是文件系統抽象出了一個通用文件表示層——虛擬文件系統或稱做VFS。另外一個重要特點是它的文件系統支持動態安裝(或說掛載、登陸等),大多數文件系統都可以作為根文件系統的葉子接點被掛在到根文件目錄樹下的子目錄上。另外Linux系統在文件讀寫的I/O操作上也採取了一些先進技術和策略。
我們先從虛擬文件系統入手分析linux文件系統的特性,然後介紹有關文件系統的安裝、注冊和讀寫等概念。
虛擬文件系統
虛擬文件系統為用戶空間程序提供了文件系統介面。系統中所有文件系統不但依賴VFS共存,而且也依靠VFS系統協同工作。通過虛擬文件系統我們可以利用標準的UNIX文件系統調用對不同介質上的不同文件系統進行讀寫操作[4]。
虛擬文件系統的目的是為了屏蔽各種各樣不同文件系統的相異操作形式,使得異構的文件系統可以在統一的形式下,以標准化的方法訪問、操作。實現虛擬文件系統利用的主要思想是引入一個通用文件模型——該模型抽象出了文件系統的所有基本操作(該通用模型源於Unix風格的文件系統),比如讀、寫操作等。同時實際文件系統如果希望利用虛擬文件系統,既被虛擬文件系統支持,也必須將自身的諸如,「打開文件」、「讀寫文件」等操作行為以及「什麼是文件」,「什麼是目錄」等概念「修飾」成虛擬文件系統所要求的(定義的)形式,這樣才能夠被虛擬文件系統支持和使用。
我們可以借用面向對象的一些思想來理解虛擬文件系統,虛擬文件系統好比一個抽象類或介面,它定義(但不實現)了文件系統最常見的操作行為。而具體文件系統好比是具體類,它們是特定文件系統的實例。具體文件系統和虛擬文件系統的關系類似具體類繼承抽象類或實現介面。而在用戶看到或操作的都是抽象類或介面,但實際行為卻發生在具體文件系統實例上。至於如何將對虛擬文件系統的操作轉化到對具體文件系統的實例,就要通過注冊具體文件系統到系統,然後再安裝具體文件系統才能實現轉化,這點可以想像成面向對象中的多態概念。
我們個實舉例來說明具體文件系統如何通過虛擬文件系統協同工作。
例如:假設一個用戶輸入以下shell命令:
$ cp /hda/test1 /removable/test2
其中 /removable是MS-DOS磁碟的一個安裝點,而 /hda 是一個標準的第二擴展文件系統( Ext2)的目錄。cp命令不用了解test1或test2的具體文件系統,它所看到和操作的對象是VFS。cp首先要從ext3文件系統讀出test1文件,然後寫入MS-DOS文件系統中的test2。VFS會將找到ext3文件系統實例的讀方法,對test1文件進行讀取操作;然後找到MS-DOS(在Linux中稱VFAT)文件系統實例的寫方法,對test2文件進行寫入操作。可以看到 VFS是讀寫操作的統一界面,只要具體文件系統符合VFS所要求的介面,那麼就可以毫無障礙地透明通訊了。

Unix風格的文件系統
虛擬文件系統的通用模型源於Unix風格的文件系統,所謂Unix風格是指Unix傳統上文件系統傳統上使用了四種和文件系統相關的抽象概念:文件(file)、目錄項(dentry)、索引節點(inode)和安裝點(mount point)。
文件——在Unix中的文件都被看做是一有序位元組串,它們都有一個方便用戶或系統識別的名稱。另外典型的文件操作有讀、寫、創建和刪除等。
目錄項——不要和目錄概念搞混淆,在Linux中目錄被看作文件。而目錄項是文件路徑中的一部分。一個文件路徑的例子是「/home/wolfman/foo」——根目錄是/,目錄home,wolfman和文件foo都是目錄項。
索引節點——Unix系統將文件的相關信息(如訪問控制許可權、大小、擁有者、創建時間等等信息),有時被稱作文件的元數據(也就是說,數據的數據)被存儲在一個單獨的數據結構中,該結構被稱為索引節點(inode)。
安裝點——在Unix中,文件系統被安裝在一個特定的安裝點上,所有的已安裝文件系統都作為根文件系統樹中的葉子出現在系統中。
上述概念是Unix文件系統的邏輯數據結構,但相應的Unix文件系統(Ext2等)磁碟布局也實現了部分上述概念,比如文件信息(文件數據元)存儲在磁碟塊中的索引節點上。當文件被載如內存時,內核需要使用磁碟塊中的索引點來裝配內存中的索引接點。類似行為還有超級塊信息等。
對於非Unix風格文件系統,如FAT或NTFS,要想能被VFS支持,它們的文件系統代碼必須提供這些概念的虛擬形式。比如,即使一個文件系統不支持索引節點,它也必須在內存中裝配起索引節點結構體——如同本身固有一樣。或者,如果一個文件系統將目錄看作是一種特殊對象,那麼要想使用VFS,必須將目錄重新表示為文件形式。通常,這種轉換需要在使用現場引入一些特殊處理,使得非Unix文件系統能夠兼容Unix文件系統的使用規則和滿足VFS的需求。通過這些處理,非Unix文件系統便可以和VFS一同工作了,是性能上多少會受一些影響[5]。這點很重要,我們實現自己文件系統時必須提供(模擬)Unix風格文件系統的抽象概念。

Linux文件系統中使用的對象
Linux文件系統的對象就是指一些數據結構體,之所以稱它們是對象,是因為這些數據結構體不但包含了相關屬性而且還包含了操作自身結構的函數指針,這種將數據和方法進行封裝的思想和面向對象中對象概念一致,所以這里我們就稱它們是對象。
Linux文件系統使用大量對象,我們簡要分析以下VFS相關的對象,和除此還有和進程相關的一些其它對象。
VFS相關對象
這里我們不展開討論每個對象,僅僅是為了內容完整性,做作簡要說明。
VFS中包含有四個主要的對象類型,它們分別是:
超級塊對象,它代表特定的已安裝文件系統。
索引節點對象,它代表特定文件。
目錄項對象,它代表特定的目錄項。
文件對象,它代表和進程打開的文件。
每個主要對象中都包含一個操作對象,這些操作對象描述了內核針對主要對象可以使用的方法。最主要的幾種操作對象如下:
super_operations對象,其中包括內核針對特定文件系統所能調用的方法,比如read_inode()和sync_fs()方法等。
inode_operations對象,其中包括內核針對特定文件所能調用的方法,比如create()和link()方法等。
dentry_operations對象,其中包括內核針對特定目錄所能調用的方法,比如d_compare()和d_delete()方法等。
file對象,其中包括,進程針對已打開文件所能調用的方法,比如read()和write()方法等。
除了上述的四個主要對象外,VFS還包含了許多對象,比如每個注冊文件系統都是由file_system_type對象表示——描述了文件系統及其能力(如比如ext3或XFS);另外每一個安裝點也都利用vfsmount對象表示——包含了關於安裝點的信息,如位置和安裝標志等。

其它VFS對象
系統上的每一進程都有自己的打開文件,根文件系統,當前工作目錄,安裝點等等。另外還有幾個數據結構體將VFS層和文件的進程緊密聯系,它們分別是:file_struct 和fs_struct
file_struct結構體由進程描述符中的files項指向。所有包含進程的信息和它的文件描述符都包含在其中。第二個和進程相關的結構體是fs_struct。該結構由進程描述符的fs項指向。它包含文件系統和進程相關的信息。每種結構體的詳細信息不在這里說明了。

緩存對象
除了上述一些結構外,為了縮短文件操作響應時間,提高系統性能,Linux系統採用了許多緩存對象,例如目錄緩存、頁面緩存和緩沖緩存(已經歸入了頁面緩存),這里我們對緩存做簡單介紹。
頁高速緩存(cache)是 Linux內核實現的一種主要磁碟緩存。其目的是減少磁碟的I/O操作,具體的講是通過把磁碟中的數據緩存到物理內存中去,把對磁碟的I/O操作變為對物理內存的I/O操作。頁高速緩存是由RAM中的物理頁組成的,緩存中每一頁都對應著磁碟中的多個塊。每當內核開始執行一個頁I/O操作時(通常是對普通文件中頁大小的塊進行磁碟操作),首先會檢查需要的數據是否在高速緩存中,如果在,那麼內核就直接使用高速緩存中的數據,從而避免了訪問磁碟。
但我們知道文件系統只能以每次訪問數個塊的形式進行操作。內核執行所有磁碟操作都必須根據塊進行,一個塊包含一個或多個磁碟扇區。為此,內核提供了一個專門結構來管理緩沖buffer_head。緩沖頭[6]的目的是描述磁碟扇區和物理緩沖之間的映射關系和做I/O操作的容器。但是緩沖結構並非獨立存在,而是被包含在頁高速緩存中,而且一個頁高速緩存可以包含多個緩沖。我們將在文件後面的文件讀寫部分看到數據如何被從磁碟扇區讀入頁高速緩存中的緩沖中的。

文件系統的注冊和安裝
使用文件系統前必須對文件系統進行注冊和安裝,下面分別對這兩種行為做簡要介紹。
文件系統的注冊
VFS要想能將自己定義的介面映射到實際文件系統的專用方法上,必須能夠讓內核識別實際的文件系統,實際文件系統通過將代表自身屬性的文件類型對象(file_system_type)注冊(通過register_filesystem()函數)到內核,也就是掛到內核中的文件系統類型鏈表上,來達到使文件系統能被內核識別的目的。反過來內核也正是通過這條鏈表來跟蹤系統所支持的各種文件系統的。
我們簡要分析一下注冊步驟:
struct file_system_type {
const char *name; /*文件系統的名字*/
int fs_flags; /*文件系統類型標志*/
/*下面的函數用來從磁碟中讀取超級塊*/
struct super_block * (*read_super) (struct file_system_type *, int,
const char *, void *);
struct file_system_type * next; /*鏈表中下一個文件系統類型*/
struct list_head fs_supers; /*超級塊對象鏈表*/
};
其中最重要的一項是read_super()函數,它用來從磁碟上讀取超級塊,並且當文件系統被裝載時,在內存中組裝超級塊對象。要實現一個文件系統首先需要實現的結構體便是file_system_type結構體。
注冊文件系統只能保證文件系統能被系統識別,但此刻文件系統尚不能使用,因為它還沒有被安裝到特定的安裝點上。所以在使用文件系統前必須將文件系統安裝到安裝點上。
文件系統被實際安裝時,將在安裝點創建一個vfsmount結構體。該結構體用代表文件系統的實例——換句話說,代表一個安裝點。
vfsmount結構被定義在<linux/mount.h>中,下面是具體結構
―――――――――――――――――――――――――――――――――――――――
struct vfsmount
{
struct list_head mnt_hash; /*哈希表*/
struct vfsmount *mnt_parent; /*父文件系統*/
struct dentry *mnt_mountpoint; /*安裝點的目錄項對象*/
struct dentry *mnt_root; /*該文件系統的根目錄項對象*/
struct super_block *mnt_sb; /*該文件系統的超級塊*/
struct list_head mnt_mounts; /*子文件系統鏈表*/
struct list_head mnt_child; /*和父文件系統相關的子文件系統*/
atomic_t mnt_count; /*使用計數*/
int mnt_flags; /*安裝標志*/
char *mnt_devname; /*設備文件名字*/
struct list_head mnt_list; /*描述符鏈表*/
};
――――――――――――――――――――――――――――――――――――――
文件系統如果僅僅注冊,那麼還不能被用戶使用。要想使用它還必須將文件系統安裝到特定的安裝點後才能工作。下面我們接著介紹文件系統的安裝[7]過程。
安裝過程

用戶在用戶空間調用mount()命令——指定安裝點、安裝的設備、安裝類型等——安裝指定文件系統到指定目錄。mount()系統調用在內核中的實現函數為sys_mount(),該函數調用的主要常式是do_mount(),它會取得安裝點的目錄項對象,然後調用do_add_mount()常式。
do_add_mount()函數主要做的是首先使用do_kern_mount()函數創建一個安裝點,再使用graft_tree()將安裝點作為葉子與根目錄樹掛接起來。
整個安裝過程中最核心的函數就是do_kern_mount()了,為了創建一個新安裝點(vfsmount),該函數需要做一下幾件事情:
l 1 檢查安裝設備的權利,只有root許可權才有能力執行該操作。
l 2 Get_fs_type()在文件鏈表中取得相應文件系統類型(注冊時被填加到練表中)。
l 3 Alloc_vfsmnt()調用slab分配器為vfsmount結構體分配存儲空間,並把它的地址存放在mnt局部變數中。
l 4 初始化mnt->mnt_devname域
l 5 分配新的超級塊並初始化它。do_kern_mount( )檢查file_system_type描述符中的標志以決定如何進行如下操作:根據文件系統的標志位,選擇相應的方法讀取超級塊(比如對Ext2,romfs這類文件系統調用get_sb_dev();對於這種沒有實際設備的虛擬文件系統如 ramfs調用get_sb_nodev())——讀取超級塊最終要使用文件系統類型中的read_super方法。
安裝過程做的最主要工作是創建安裝點對象,掛接給定文件系統到根文件系統的指定接點下,然後初始化超級快對象,從而獲得文件系統基本信息和相關操作方法(比如讀取系統中某個inode的方法)。

總而言之,注冊過程是告之內核給定文件系統存在於系統內;而安裝是請求內核對給定文件系統進行支持,使文件系統真正可用。

轉載

閱讀全文

與如何去寫一個文件系統相關的資料

熱點內容
小米5s網路設置會怎麼樣 瀏覽:325
word2007空白處帶字體背景顏色 瀏覽:803
迷你編程第三章如何通關 瀏覽:342
win10系統怎麼卸載ie瀏覽器 瀏覽:587
uga字頭的字體在哪個文件 瀏覽:508
cad每次運行會產生log文件 瀏覽:158
單詞社交網路怎麼樣 瀏覽:406
ps矢量文件轉ai 瀏覽:82
清華大學蘇州大數據中心 瀏覽:620
電腦上怎麼搜索文件文件名忘了 瀏覽:360
永安行app在哪裡簽到 瀏覽:601
大數據在職業技能培訓中的應用 瀏覽:218
word文件管理器 瀏覽:82
貴安大數據產業園 瀏覽:229
excel該文件可能是只讀的 瀏覽:818
怎麼添加一個次要數據文件資料庫 瀏覽:399
linux怎麼裝系統 瀏覽:811
接觸到哪些信息是由資料庫管理 瀏覽:25
港版s7edge和亞太版本 瀏覽:284
無限循環數控編程序怎麼編程 瀏覽:979

友情鏈接