|
在文件拷貝時候,scp一個占磁盤空間300G大?。╠u命令的結(jié)果)左右的目錄到另外一臺機(jī)器上,du命令發(fā)現(xiàn)該目錄占用的磁盤空間變大了,約330多G。為什么會多出來這30G呢? 分析可能原因: 一.原機(jī)器的block大小為1024k,新機(jī)器的block大小為4096k,可能是文件系統(tǒng)block大小引起的。 拷貝的數(shù)據(jù)文件大概有1000個,文件塊的影響也就是1000*4K=4M,而空間增大了約30G,所以不可能是原因一。 二.有些文件存在空洞??斩磗cp到新機(jī)器后,被填充,占用磁盤空間。 實驗:在本機(jī)上cp一個有空洞的文件,發(fā)現(xiàn)cp前后占用的磁盤大小未變,而scp到另一臺機(jī)器后,空洞被填滿,占用磁盤塊變大。
背景知識: ll和du –s讀取的文件大小和占用磁盤空間數(shù)據(jù)來源 struct stat { dev_t st_dev; /* device */ ino_t st_ino; /* inode */ mode_t st_mode; /* protection */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ dev_t st_rdev; /* device type (if inode device) */ off_t st_size; /* total size, in bytes */ blksize_t st_blksize; /* blocksize for filesystem I/O */ blkcnt_t st_blocks; /* number of blocks allocated */ time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ time_t st_ctime; /* time of last status change */ }; 自己編寫一個小C程序通過fstat函數(shù),取得文件狀態(tài),st_size就是ll看到的文件大小,st_blksize是系統(tǒng)每次read,write等i/o的buff大小,通常和文件系統(tǒng)塊大小一致,st_blocks是占用的 文件系統(tǒng)的塊數(shù),這個塊區(qū)別以文件系統(tǒng)的塊,一般是512字節(jié)。Du命令讀取st_blocks(du會根據(jù)命令參數(shù)轉(zhuǎn)換)。 實驗過程:創(chuàng)建一個空洞文件file.hole。通過lseek將文件偏移量指針超過文件末尾。 實驗機(jī)器:block大小為4k. ll file.hole -rw-r--r-- 1 zhangfan zhangfan 16394 Jun 22 15:08 file.hole du -sh file.hole 8.0K file.hole 可以看到,空洞部分沒有占用block. cp一個空洞文件 cp file.hole file.hole.cp ll file.hole.cp -rw-r--r-- 1 zhangfan zhangfan 16394 Jul 10 15:51 file.hole.cp du -sh file.hole.cp 8.0K file.hole.cp trace一下系統(tǒng)調(diào)用的過程 read(3, "abcdefghij\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096 write(4, "abcdefghij\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096 read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096 lseek(4, 4096, SEEK_CUR) = 8192 read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096 lseek(4, 4096, SEEK_CUR) = 12288 read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096 lseek(4, 4096, SEEK_CUR) = 16384 read(3, "ABCDEFGHIJ", 4096) = 10 write(4, "ABCDEFGHIJ", 10) = 10 read(3, "", 4096) = 0 close(4) = 0 close(3) = 0 只write了有具體內(nèi)容的塊,空洞沒有write,但是lseek是一直在變的,所以cp不會拷貝空洞。 通過看cp的源碼,可以看到cp的具體過程: 1、 判斷目標(biāo)文件是否存在,如果存在則清空目標(biāo)文件,如果不存在則創(chuàng)建目標(biāo)文件 2、根據(jù)目標(biāo)文件的邏輯塊大小,創(chuàng)建拷貝緩沖區(qū) 3、判斷源文件是否有空洞:文件大小/文件塊大小 > 塊數(shù) ? 4、讀取源文件存放到緩沖區(qū),每次讀取一塊 5、在第3步中判斷,如果存在文件空洞,則對緩沖區(qū)數(shù)據(jù)進(jìn)行判斷,如果緩沖區(qū)中的數(shù)據(jù)均為0,則認(rèn)為該數(shù)據(jù)快為空洞,否則認(rèn)為是正常文件數(shù)據(jù) 6、如果數(shù)據(jù)塊為空洞,則調(diào)用lseek,在目標(biāo)文件中創(chuàng)建一個空洞;否則拷貝緩沖區(qū)數(shù)據(jù)到目標(biāo)文件 7、判斷本次讀取是否讀到源文件的文件尾,如果是,則判斷本次讀取的是否是空洞,如果是空洞則在文件的最后寫入"" 8、重復(fù)1 ~ 7 9、關(guān)閉目標(biāo)文件、源文件 Scp file.hole到另外一臺機(jī)器 Scp后的文件 ll file.hole -rw-r--r-- 1 zhangfan zhangfan 16394 Jul 10 15:57 file.hole du -sh file.hole 20K file.hole 再trace一下scp. read(3, "abcdefghij\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096 write(6, "abcdefghij\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096 read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096 write(6, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096 read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096 write(6, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096 read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096 write(6, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096 read(3, "ABCDEFGHIJ", 10) = 10 空洞也被write了,所以du -s會變大 。cp對于稀疏文件的支持(sparse file),是由選項控制的,--sparse=(auto|always|never),默認(rèn)是支持(auto),具體請man。scp應(yīng)該不支持稀疏文件,所以scp這樣的文件,會被填充成0 ;不過,tar(-S選項)、rsync(也是-S)都是支持的,所有scp的時候可以跟他們配合著用。 |
|
|