歡迎您光臨本站 註冊首頁

嵌入式linux下常見的文件系統

←手機掃碼閱讀     火星人 @ 2014-03-24 , reply:0

• RomFS:只讀文件系統,可以放在ROM空間,也
可以在系統的RAM中,嵌入式linux中常用來作
根文件系統
• RamFS:利用VFS自身結構而形成的內存文件系
統,使用系統的RAM空間
• JFFS/JFFS2:為Flash設計的日誌文件系統
• Yaffs:專門為Nand Flash設計
• proc:為內核和內核模塊將信息發送給進程提
供一種機制,可以查看系統模塊裝載的信息
• devFS:設備文件系統
Linux上的Ext2fs
• 支持4 TB 存儲、文件名稱最長1012 字元
• 可選擇邏輯塊
• 快速符號鏈接
• Ext2不適合flash設備
• 是為象IDE 設備那樣的塊設備設計的,邏輯塊大小必
須是512 byte、1 KB、2KB等
• 沒有提供對基於扇區的擦除/寫操作的良好管理
• 如果在一個扇區中擦除單個位元組,必須將整個扇區複製到
RAM,然後擦除,再重寫入
• 在出現電源故障時,Ext2fs 是不能防止崩潰的
• 文件系統不支持損耗平衡,縮短了flash的壽命
jffs/jffs2文件系統的優缺點
• 日誌文件系統
• 提供了更好的崩潰、掉電安全保護
• jffs2支持對flash的均勻磨損
• 在扇區級別上執行快閃記憶體擦除/寫/讀操作要
比Ext2文件系統好
• 文件系統接近滿時,JFFS2 會大大放慢運行
速度——垃圾收集
Nand上yaffs文件系統的優勢
• 專門為Nand flash設計的日誌文件系統
• jffs/jffs2不適合大容量的Nand flash
• jffs的日誌通過jffs_node建立在RAM中,佔用
RAM空間:對於128MB的Nand大概需要4MB的空間
來維護節點
• 啟動的時候需要掃描日誌節點,不適合大容量
的Nand flash
• FAT系統沒有日誌
編譯yaffs文件系統
• mtd的最新補丁升級?
• 介面更新,適合與yaffs
• 與原有的mtd驅動程序不兼容,需要重寫
• 如果使用舊mtd驅動需要定義Makefile中
MTD_OLD = -DCONFIG_YAFFS_USE_OLD_MTD
• 參考文檔: yaffs-rootfs-howto
• 最新版的yaffs網站:
http://www.aleph1.co.uk/armlinux/projects/yaffs
使用yaffs文件系統
• 通過cat /proc/yaffs命令可以看到yaffs系
統的相關信息
• mount -t yaffs /dev/mtdblock/0 /mnt/ya
ffs


關於Linux文件系統

JFFS全稱為:The Journalling Flash File System(日誌快閃記憶體文件系統)最初由瑞典的 Axis Communications 開發,Red Hat 的 David Woodhouse 對它進行了改進。作為用於微型嵌入式設備的原始快閃記憶體晶元的實際文件系統而出現。JFFS文件系統是日誌結構化的,這意味著它基本上是一長列節點。每個節點包含有關文件的部分信息 — 可能是文件的名稱、也許是一些數據。相對於 Ext2 fs,JFFS 因為有以下這些優點而在無盤嵌入式設備中越來越受歡迎:
  
   1 JFFS 在扇區級別上執行快閃記憶體擦除/寫/讀操作要比 Ext2 文件系統好。
   2 JFFS 提供了比 Ext2 更好的崩潰/掉電安全保護。當需要更改少量數據時,Ext2 文件系統將整個扇區複製到內存(DRAM)中,在內存中合併新數據,並寫回整個扇區。這意味著為了更改單個字,必須對整個扇區(64 KB)執行讀/擦除/寫常式 — 這樣做的效率非常低。要是運氣差,當正在 DRAM 中合併數據時,發生了電源故障或其它事故,那麼將丟失整個數據集合,因為在將數據讀入 DRAM 后就擦除了快閃記憶體扇區。JFFS 附加文件而不是重寫整個扇區,並且具有崩潰/掉電安全保護這一功能。
   3 這可能是最重要的一點:JFFS 是專門為象快閃記憶體晶元那樣的嵌入式設備創建的,所以它的整個設計提供了更好的快閃記憶體管理。
   要構建JFFS文件系統,首先要有硬體設備FLASH及支持JFFS文件系統的操作系統。


摘要:本文主要分析了uclinux 2.4內核的jffs文件系統機制。希望能對基於uclinux開發產品的廣大工程師有所幫助。

關鍵詞:uclinux vfs jffs

申明:這份文檔是按照自由軟體開放源代碼的精神發布的,任何人可以免費獲得、使用和重新發布,但是你沒有限制別人重新發布你發布內容的權利。發布本文的目的是希望它能對讀者有用,但沒有任何擔保,甚至沒有適合特定目的的隱含的擔保。更詳細的情況請參閱 GNU 通用公共許可證(GPL),以及GNU 自由文檔協議(GFDL)。

你應該已經和文檔一起收到一份GNU 通用公共許可證(GPL)的副本。如果還沒有,寫信給:
The Free Software Foundation, Inc., 675 Mass Ave, Cambridge,MA02139, USA

歡迎各位指出文檔中的錯誤與疑問


一、flash讀寫的特殊性
對於嵌入式系統,flash是很常見的一種設備,而大部分的嵌入式系統都是把文件系統建立在flash之上,由於對flash操作的特殊性,使得在flash上的文件系統和普通磁碟上的文件系統有很大的差別,對flash操作的特殊性包括:
(1) 不能對單個位元組進行擦除,最小的擦寫單位是一個block,有時候也稱為一個扇區。典型的一個block的大小是64k。不同的flash會有不同,具體參考flash晶元的規範。
(2) 寫操作只能對一個原來是空(也就是該地址的內容是全f)的位置操作,如果該位置非空,寫操作不起作用,也就是說如果要改寫一個原來已經有內容的空間,只能是讀出該sector到ram,在ram中改寫,然後寫整個sector。
由於這些特殊寫,所以在flash這樣的設備上建立文件也有自己獨特的特點,下面我們就以jffs為例進行分析。

二、jffs體系結構介紹
1、存儲結構
在jffs中,所有的文件和目錄是一樣對待的,都是用一個jffs_raw_inode來表示


整個flash上就是由一個一個的raw inode排列組成,一個目錄只有一個raw inode,對於文件則是由一個或多個raw inode組成。

2、文件組成
在文件系統mount到flash設備上的時候,會掃描flash,從而根據flash上的所有屬於一個文件的raw inode建立一個jffs_file結構以及node list。
下面的圖顯示了一個文件的組成


一個文件是由若干個jffs_node組成,每一個jffs_node是根據flash上得jffs_raw_inode而建立的,jffs_file主要維護兩個鏈表
版本鏈表:主要是描述該node創建的早晚,就是說version_head指向的是一個最老的node,也就意味著垃圾回收的時候最該回收的就是這個最老的node。
區域鏈表:這個鏈表主要是為讀寫文件創建的,version_head指向的node代表的文件數據區域是0~~~n-1 之後依次的節點分別是 n~~~m-1 m~~~~o-1 …….其中n

3、操作
對文件的讀操作應該是比較簡單,但是寫操作,包括更改文件名等操作都是引起一個新的jffs_node的誕生,同時要寫一個相映的raw inode到flash上,這樣的操作有可能導致前面的某個jffs_node上面的數據完全失效,從而導致對應flash上的raw inode的空間成為dirty。
下面舉一個例子可能會更清楚一些。

一個文件的range list是由上面的三個jffs_node組成,當我們做如下寫操作的時候
lseek( fd, 10, SEEK_SET );
write( fd, buf,40 );
第一個和最後一個node被截短了,第二個node完全被新數據替換,該node會從鏈表上摘下來,flash上空間變成dirty。如果做如下寫操作的時候
lseek( fd, 23, SEEK_SET );
write( fd, buf,5 );
此時,第二個node被分裂成兩個node,同時產生一個新的node,range鏈表的元素變成五個。




基於Linux2.6的YAFFS文件系統移植
v1.0,2005-6-6
一、YAFFS文件系統簡介
YAFFS,Yet Another Flash File System,是一種類似於JFFS/JFFS2的專門為Flash設計的嵌入式文件系統。與JFFS相比,它減少了一些功能,因此速度更快、佔用內存更少。
YAFFS和JFFS都提供了寫均衡,垃圾收集等底層操作。它們的不同之處在於:
(1)、JFFS是一種日誌文件系統,通過日誌機制保證文件系統的穩定性。YAFFS僅僅借鑒了日誌系統的思想,不提供日誌機能,所以穩定性不如JAFFS,但是資源佔用少。
(2)、JFFS中使用多級鏈表管理需要回收的臟塊,並且使用系統生成偽隨機變數決定要回收的塊,通過這種方法能提供較好的寫均衡,在YAFFS中是從頭到尾對塊搜索,所以在垃圾收集上JFFS的速度慢,但是能延長NAND的壽命。
(3)、JFFS支持文件壓縮,適合存儲容量較小的系統;YAFFS不支持壓縮,更適合存儲容量大的系統。
YAFFS 還帶有NAND晶元驅動,並為嵌入式系統提供了直接訪問文件系統的API,用戶可以不使用Linux中的MTD和VFS,直接對文件進行操作。NAND Flash大多採用MTD+YAFFS的模式。MTD( Memory Technology Devices,內存技術設備)是對Flash操作的介面,提供了一系列的標準函數,將硬體驅動設計和系統程序設計分開。
二、YAFFS文件系統的移植
yaffs代碼可以從http://www.aleph1.co.uk/armlinux/projects/下載(yaffs代碼包括yaffs_ecc
.c,yaffs_fileem.c,yaffs_fs.c,yaffs_guts.c,yaffs_mtdif.c,yaffs_ramem.c。)
表一 Yaffs文件系統源代碼相關文件及功能描述
文件名 功 能
yaffs_ecc.c ECC校驗演算法
yaffs_fileem.c 測試flash
yaffs_fs.c 文件系統介面函數
yaffs_guts.c Yaffs文件系統演算法
yaffs_mtdif.c NAND函數
yaffs_ramem.c Ramdisk實現
1.內核中沒有YAFFS,所以需要自己建立YAFFS目錄,並把下載的YAFFS代碼複製到該目錄下面。
#mkdir fs/yaffs
#cp *.c(yaffs source code) fs/yaffs
2.修改fs/Kconfig,使得可以配置yaffs :
source "fs/yaffs/Kconfig"
3.修改fs/makefile,添加如下內容:
obj-$(CONFIG_YAFFS_FS) += yaffs/
4.在fs目錄下生成yaffs目錄,並在裡面生成一個makefile 和Kconfig
Makefile 內容為:
yaffs-objs := yaffs_fs.o yaffs_guts.o yaffs_mtdif.o yaffs_ecc.o
EXTRA_CFLAGS += $(YAFFS_CONFIGS) -DCONFIG_KERNEL_2_6
Kconfig內容為:
#
# YAFFS file system configurations
#
config YAFFS_FS
tristate "Yet Another Flash Filing System(YAFFS) file system support"
help
YAFFS, for Yet Another Flash Filing System, is a filing system
optimised for NAND Flash chips.

To compile the YAFFS file system support as a module, choose M here:
the module will be called yaffs.

If unsure, say N.

Further information on YAFFS is available at
<http://www.aleph1.co.uk/yaffs/>.

config YAFFS_MTD_ENABLED
bool "NAND mtd support"
depends on YAFFS_FS
help
This adds the yaffs file system support for working with a NAND mtd.

If unsure, say Y.

config YAFFS_RAM_ENABLED
bool "yaffsram file system support"
depends on YAFFS_FS
help
This adds the yaffsram file system support. Nice for testing on x86,
but uses 2MB of RAM. Don't enable for NAND-based targets.

If unsure, say N.

comment "WARNING: mtd and/or yaffsram support should be selected"
depends on YAFFS_FS && !YAFFS_MTD_ENABLED && !YAFFS_RAM_ENABLED

config YAFFS_USE_OLD_MTD
bool "Old mtd support"
depends on YAFFS_FS && 0
help
Enable this to use the old MTD stuff that did not have yaffs support.
You can use this to get around compilation problems, but the best
thing to do is to upgrade your MTD support. You will get better speed.

If unsure, say N.

config YAFFS_USE_NANDECC
bool "Use ECC functions of the generic MTD-NAND driver"
depends on YAFFS_FS
default y
help
This enables the ECC functions of the generic MTD-NAND driver.
This will not work if you are using the old mtd.

NB Use NAND ECC does not work at present with yaffsram.

If unsure, say Y.

config YAFFS_ECC_WRONG_ORDER
bool "Use the same ecc byte order as Steven Hill's nand_ecc.c"
depends on YAFFS_FS
help
This makes yaffs_ecc.c use the same ecc byte order as
Steven Hill's nand_ecc.c. If not set, then you get the
same ecc byte order as SmartMedia.

If unsure, say N.

config YAFFS_USE_GENERIC_RW
bool "Use Linux file caching layer"
default y
depends on YAFFS_FS
help
Use generic_read/generic_write for reading/writing files. This
enables the use of the Linux file caching layer.

If you disable this, then caching is disabled and file read/write
is direct.

If unsure, say Y.

config YAFFS_USE_HEADER_FILE_SIZE
bool "Use object header size"
depends on YAFFS_FS
help
When the flash is scanned, two file sizes are constructed:
* The size taken from the object header for the file.
* The size figured out by scanning the data chunks.
If this option is enabled, then the object header size is used,
otherwise the scanned size is used.

If unsure, say N.

config YAFFS_DISABLE_CHUNK_ERASED_CHECK
bool "Turn off debug chunk erase check"
depends on YAFFS_FS
default y
help
Enabling this turns off the test that chunks are erased in flash
before writing to them. This is safe, since the write verification
will fail. Suggest enabling the test (ie. say N)
during development to help debug things.

If unsure, say Y.

#config YAFFS_DISABLE_WRITE_VERIFY
# bool "Disable write verify (DANGEROUS)"
# depends on YAFFS_FS && EXPERIMENTAL
# help
# I am severely reluctant to provide this config. Disabling the
# verification is not a good thing to do since NAND writes can
# fail silently. Disabling the write verification will cause your
# teeth to rot, rats to eat your corn and give you split ends.
# You have been warned. ie. Don't uncomment the following line.
#
# If unsure, say N.
#

config YAFFS_SHORT_NAMES_IN_RAM
bool "Cache short names in RAM"
depends on YAFFS_FS
default y
help
If this config is set, then short names are stored with the
yaffs_Object. This costs an extra 16 bytes of RAM per object,
but makes look-ups faster.

If unsure, say Y.
5.在/arch/arm/mach-s3c2410/mach-smdk2410.c找到smdk_default_nand_part結構,修改nand分區,如下:
struct mtd_partition smdk_default_nand_part[] = {
[0] = {
.name = "vivi",
.size = 0x00020000,
.offset = 0x00000000,
},
[1] = {
.name = "param",
.size = 0x00010000,
.offset = 0x00020000,
},
[2] = {
.name = "kernel",
.size = 0x00100000,
.offset = 0x00030000,
},
[3] = {
.name = "root",
.size = 0x01900000,
.offset = 0x00130000,
},
[4] = {
.name = "user",
.size = 0x025d0000,
.offset = 0x01a30000,
}
};
註:此分區要結合vivi裡面的分區來進行設置。
6.配置內核時選中MTD支持:
Memory Technology Devices (MTD) --->
<*> Memory Technology Device (MTD) support

MTD partitioning support
……
--- User Modules And Translation Layers
<*> Direct char device access to MTD devices
<*> Caching block device access to MTD devices
……
NAND Flash Device Drivers --->
<*> NAND Device Support
<*> NAND Flash support for S3C2410 SoC

S3C2410 NAND driver debug
7.配置內核時選中YAFFS支持:
File systems --->
Miscellaneous filesystems --->
<*> Yet Another Flash Filing System(YAFFS) file system support

NAND mtd support

Use ECC functions of the generic MTD-NAND driver

Use Linux file caching layer

Turn off debug chunk erase check

Cache short names in RAM
8.編譯內核並將內核下載到開發板的flash中。
三、Yaffs文件系統測試:
1.內核啟動之後,在啟動信息裡面可以看到如下內容:
NAND device: Manufacturer ID: 0xec, Chip ID: 0x76 (Samsung NAND 64MiB 3,3V 8-bit)
Scanning device for bad blocks
Creating 5 MTD partitions on "NAND 64MiB 3,3V 8-bit":
0x00000000-0x00020000 : "vivi"
0x00020000-0x00030000 : "param"
0x00030000-0x00130000 : "kernel"
0x00130000-0x01a30000 : "root"
0x01a30000-0x04100000 : "user"
2.如果在內核裡面添加了proc文件系統的支持那麼你在proc裡面可以看到有關yaffs的信息
~ # cat proc/filesystems
nodev sysfs
nodev rootfs
nodev bdev
nodev proc
nodev sockfs
nodev pipefs
nodev futexfs
nodev tmpfs
nodev eventpollfs
nodev devpts
nodev ramfs
vfat
nodev devfs
nodev nfs
yaffs
nodev rpc_pipefs
3.查看dev目錄下相關目錄可以看到:
~ # ls dev/mtd -al
drwxr-xr-x 1 root root 0 Jan 1 00:00 .
drwxr-xr-x 1 root root 0 Jan 1 00:00 ..
crw-rw-rw- 1 root root 90, 0 Jan 1 00:00 0
cr--r--r-- 1 root root 90, 1 Jan 1 00:00 0ro
crw-rw-rw- 1 root root 90, 2 Jan 1 00:00 1
cr--r--r-- 1 root root 90, 3 Jan 1 00:00 1ro
crw-rw-rw- 1 root root 90, 4 Jan 1 00:00 2
cr--r--r-- 1 root root 90, 5 Jan 1 00:00 2ro
crw-rw-rw- 1 root root 90, 6 Jan 1 00:00 3
cr--r--r-- 1 root root 90, 7 Jan 1 00:00 3ro
crw-rw-rw- 1 root root 90, 8 Jan 1 00:00 4
cr--r--r-- 1 root root 90, 9 Jan 1 00:00 4ro

~ # ls dev/mtdblock/ -al
drwxr-xr-x 1 root root 0 Jan 1 00:00 .
drwxr-xr-x 1 root root 0 Jan 1 00:00 ..
brw------- 1 root root 31, 0 Jan 1 00:00 0
brw------- 1 root root 31, 1 Jan 1 00:00 1
brw------- 1 root root 31, 2 Jan 1 00:00 2
brw------- 1 root root 31, 3 Jan 1 00:00 3
brw------- 1 root root 31, 4 Jan 1 00:00 4
4.mount、umount
建立mount目錄
~ #mkdir /mnt/flash0
~ #mkdir /mnt/flash1
Mountblockdevice設備
~ #mount ?t yaffs /dev/mtdblock/3 /mnt/flash0
~ #mount ?t yaffs /dev/mtdblock/4 /mnt/flash1
~ #cp 1.txt /mnt/flash0
~ #cp 2.txt /mnt/flash1
查看mount上的目錄,可以看到該目錄下有剛才拷貝的文件,將其umount后,再次mount上來可以發現拷貝的文件仍然存在,這時刪除該文件然後umount,再次mount后,可以發現拷貝的文件已經被刪除,由此可以該分區可以正常讀寫。
5.在flash上建立根文件系統
~ # mount ?t yaffs /dev/mtdblock/3 /mnt/flash0
~ #cp (your rootfs) /mnt/flash0
~ #umount /mnt/flash0
重新啟動,改變啟動參數:
param set linux_cmd_line "noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0"
重新啟動,開發板就可以從flash啟動根文件系統了。
註:這裡你得在內核中添加devfs文件系統的支持,否則內核無法找到/dev/mtdblock/3目錄



目前flash的文件系統比較多,用的比較多的就是JFFS2文件系統。基於NOR flash上的JFFS2文件系統可以說算是比較成熟了,支持NAND flash的JFFS2也已經發布了。源代碼可以到http://www.linux-mtd.infradead.org上面下載。但是在我的測試過程中,在nand flash上掛接的JFFS2文件系統很不穩定,經常有CRC錯誤產生。特別是進行寫操作的時候,每次複位都會產生CRC錯誤,可以說支持NAND flash的JFFS2文件系統目前還不成熟。而YAFFS文件系統則是專門針對NAND flash的,源代碼可以到
http://www.aleph1.co.uk/yaffs/index.html上下載。在測試過程中穩定性能比JFFS2文件系統要穩定的多,而且mount分區的時間也比JFFS2文件系統少的多。用JFFS2 mount一個2m的文件系統大約需要1s。下面分別介紹在uclinux下面使用JFFS2和YAFFS文件系統。
1、JFFS2
到http://www.linux-mtd.infradead.org上面下載最新的MTD和JFFS2壓縮包。壓縮包裡面還有有關的內核補丁和一些MTD的相關工具。主要的補丁就是ilookup-2.4.23.patch,因為最新的MTD驅動中要用到一個ilookup()函數。打完補丁、更新了MTD驅動和JFFS2文件系統之後就開始寫自己nand flash驅動了。如果不想把JFFS2作為根文件系統的話,還需要修改MTD_BLOCK_MAJOR。驅動可以參考裡面的例子,最簡單的就是參考spia.c。
寫驅動主要工作是定義flash分區結構、定義flash讀寫地址、寫控制flash的**_hwcontrol()函數。具體的操作要看所用的nand flash的晶元資料。相對NOR flash來說驅動要簡單多了。:)
改完之後再配置
Memory Technology Devices(MTD)下
CONFIG_MTD=Y
CONFIG_MTD_DEBUG=Y
CONFIG_MTD_DEBUG_VERBOSE=3
CONFIG_MTD_PARTITIONS=Y
CONFIG_MTD_CHAR=Y
CONFIG_MTD_BLOCK=Y
NAND Flash Device Drivers下
CONFIG_MTD_NAND=Y
定義自己的驅動文件
File systems下
CONFIG_JFFS2_FS=Y
CONFIG_JFFS2_FS_DEBUG=2
CONFIG_JFFS2_FS_NAND=y /*這個是新加的*/
在uClinux v1.3.4 Configuration下
Flash Tools下
CONFIG_USER_MTDUTILS=Y
CONFIG_USER_MTDUTILS_ERASE=Y
CONFIG_USER_MTDUTILS_ERASEALL=Y
CONFIG_USER_MTDUTILS_MKFSJFFS2=Y
最後就是辛苦了調試工作了。:(MTD驅動調試完之後,就可以在上面掛接JFFS2文件系統了。參看flash分區情況:cat /proc/mtd,擦除分區:eraseall /dev/mtd*.例如把第一個分區mount到/mnt目錄下面:
先:eraseall /dev/mtd0
然後:mount -t jffs2 /dev/mtdblock0 /mnt
2、YAFFS
YAFFS意義為'yet another flash file system',也是一個開源的文件系統。YAFFS是目前為止唯一一個專門為NAND flash設計的文件系統,具有很好的可移植性,能夠在linux,uclinux,和wince
下面運行。
在http://www.aleph1.co.uk/yaffs/index.html上下載源代碼。壓縮包裡面也包含YAFFS的說明文檔。YAFFS文件系統的源文件就devextras.h,yaffs_ecc.c,yaffs_ecc.h,yaffs_guts.c,yaffs_guts.h,yaffs_mtdif.h,yaffs_mtdif.c和yportenv.h
另外需要配置的宏:CONFIG_YAFFS_FS 和CONFIG_YAFFS_MTD_ENABLED,就是配置在mtd上面掛接YAFFS,其它還有一些輔助配置需要時也可以配置。
在fs目錄下面建一個yaffs目錄,把以上說的文件考裡面去,新建一個makefile:
O_TARGET := yaffs.o
obj-y := yaffs_fs.o yaffs_guts.o yaffs_mtdif.o yaffs_ecc.o
obj-m := $(O_TARGET)
include $(TOPDIR)/Rules.make
接下來就是改fs目錄下面config.in和makefile,在配置YAFFS的時候,把YAFFS連接進去。
如果像前面一樣已經把NAND MTD驅動調好了,加YAFFS就很簡單了。因為YAFFS是自己做ECC校驗的,所以要把MTD驅動裡面的ECC去掉。在驅動裡面改成this->eccmode = NAND_ECC_NONE就可以了。
另外YAFFS是用mkyaffs來擦除flash,所以在mtd-utils中加上mkyaffs.c,一起編譯進去。
最後就是編譯了,呵呵。中間會有一些警告沒有關係的,就是寫沒有用的變數和函數,不過話說回來YAFFS的代碼寫的確實不太規範。當然它的性能確實沒話說。有興趣的可以試一下。

[火星人 ] 嵌入式linux下常見的文件系統已經有746次圍觀

http://coctec.com/docs/linux/show-post-132473.html