2016-07-04 26 views
2

當文件系統不覆蓋整個分區時,如何才能找到文件系統在塊設備上實際佔用多少空間?文件系統佔用的全部空間

考慮基本的例子來演示的核心問題:

dd if=/dev/zero bs=1024 count=20480 of=something.img 

losetup -f $PWD/something.img 

mke2fs /dev/loop0 

mount /dev/loop0 /mnt 

df -k /mnt給出了這樣的輸出:

Filesystem  1K-blocks Used Available Use% Mounted on 
/dev/loop0   19827 172  18631 1% /mnt 

我創建精確2048KB的設備,但statvfs()系統調用(和類似於上面顯示的df)報告文件系統僅需要19827KB。

看來,statvfs()只報告可供用戶使用的塊,但不報告文件系統的完整實際大小。

到目前爲止,我能找到的僅有的ext2/3/4,具體哈克解決tune2fs -l /dev/loop0 | grep 'Block count:'dumpe2fs -h /dev/loop0 | grep 'Block count:'。更清潔一點就是使用libext2fs庫(e2fprogs包的一部分)來讀取超級塊,但我更喜歡文件系統中立的系統調用(如果可用)。

回答

1

如果您正在尋找一個POSIX系統調用來檢索設備級別的信息,我相信沒有。

對於文件系統級信息[便攜]電話,據我所知,你就可以檢索data blocks總數,而不是剩餘開銷(如inode tables等)。

的問題

statvfs(2)fstatvfs(2)將檢索 「可用」(又名data blocks)文件系統級信息(例如,vfatext2ext3 ...),而不是基本的設備級別的信息(例如,/dev/loop0/dev/sda,...)。

A [部分/可能的非便攜式解決方案

[EDIT 3]:未什麼OP是尋找(這僅僅是 信息設備級別和不覆蓋的情況下文件系統 不映射整個設備大小)。

在Linux下(假定一個相對較新的內核版本),你可以用ioctl(2)檢索以字節爲單位的設備大小(由blockdev(8)執行同樣的方法):

#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <string.h> 

#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 

#include <unistd.h> 

#include <sys/ioctl.h> 

#include <linux/fs.h> 

int main(void) { 
     int fd = 0; 
     unsigned long long size = 0; 

     if (getuid() != 0) { 
       puts("You need to be root."); 
       exit(EXIT_FAILURE); 
     } 

     if ((fd = open("/dev/loop0", O_RDONLY)) < 0) { 
       printf("open(): %s\n", strerror(errno)); 
       exit(EXIT_FAILURE); 
     } 

     if (ioctl(fd, BLKGETSIZE64, &size) < 0) { 
       printf("ioctl(): %s\n", strerror(errno)); 
       exit(EXIT_FAILURE); 
     } 

     printf("%llu\n", size); 

     return 0; 
} 

編輯

正如評論中所述,這是device level information,所以 如果文件系統不是地圖整個設備大小,它不會解決 的問題(我們還不知道文件系統 在設備中佔用的總大小)。

的便攜式解決方案:)

嘗試我怕你真的,真的需要手工盡一切步步

你需要知道確切的文件系統,瞭解其結構,並做所有的數學。例如,在你的例子中,你正在使用一個20MiB的Ext2文件系統。因此,結構看起來像這樣(簡化的例子的緣故):

塊0

  • 引導記錄和額外的引導記錄數據:1塊(2 * 512字節)

塊組0

  • Superblock中:1塊(1024個字節)

  • 塊組描述符表,塊位圖和索引節點位圖:3塊

  • Inode Table:214塊

    ...的數據塊...

塊組1

  • 超級塊(備份):1塊

  • 塊組描述符表(備份),塊位圖和索引節點位圖:3塊

  • Inode Table:214塊

    ...的數據塊...

塊組2

  • 塊位圖和索引節點位圖:2塊

  • inode表:214塊

    ...的數據塊...

現在,通過做數學

  • 1 + 1 + 3 + 214 + 1 + 3 + 214 + 2 + 214 ==

薩姆至(您可以用statvfs(2)檢索):

  • 653 + 19827 == 20480塊

編輯2

正如註釋所討論的,Ext2超級block count已經包含由文件所佔據的總系統(不僅像我以前認爲的那樣可用的塊)。一個簡單的測試觀察它(跳過錯誤檢查的簡單[示例]):

#include <stdio.h> 
#include <string.h> 
#include <inttypes.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <fcntl.h> 

struct ext2_super_block { 
     uint32_t  s_inodes_count; 
     uint32_t  s_blocks_count; 
     uint32_t  s_r_blocks_count; 
     uint32_t  s_free_blocks_count; 
     uint32_t  s_free_inodes_count; 
     uint32_t  s_first_data_block; 
     uint32_t  s_log_block_size; 
     uint32_t  s_dummy3[7]; 
     unsigned char s_magic[2]; 
     uint16_t  s_state; 
     uint32_t  s_dummy5[8]; 
     uint32_t  s_feature_compat; 
     uint32_t  s_feature_incompat; 
     uint32_t  s_feature_ro_compat; 
     unsigned char s_uuid[16]; 
     char   s_volume_name[16]; 
     char   s_last_mounted[64]; 
     uint32_t  s_algorithm_usage_bitmap; 
     uint8_t   s_prealloc_blocks; 
     uint8_t   s_prealloc_dir_blocks; 
     uint16_t  s_reserved_gdt_blocks; 
     uint8_t   s_journal_uuid[16]; 
     uint32_t  s_journal_inum; 
     uint32_t  s_journal_dev; 
     uint32_t  s_last_orphan; 
     uint32_t  s_hash_seed[4]; 
     uint8_t   s_def_hash_version; 
     uint8_t   s_jnl_backup_type; 
     uint16_t  s_reserved_word_pad; 
     uint32_t  s_default_mount_opts; 
     uint32_t  s_first_meta_bg; 
     uint32_t  s_mkfs_time; 
     uint32_t  s_jnl_blocks[17]; 
     uint32_t  s_blocks_count_hi; 
     uint32_t  s_r_blocks_count_hi; 
     uint32_t  s_free_blocks_hi; 
     uint16_t  s_min_extra_isize; 
     uint16_t  s_want_extra_isize; 
     uint32_t  s_flags; 
     uint16_t  s_raid_stride; 
     uint16_t  s_mmp_interval; 
     uint64_t  s_mmp_block; 
     uint32_t  s_raid_stripe_width; 
     uint32_t  s_reserved[163]; 
}; 

int main(void) { 
     int fd = 0; 
     struct ext2_super_block sb; 

     /* Reset sb memory */ 
     memset(&sb, 0, sizeof(struct ext2_super_block)); 

     /* 
     * /tmp/loop.img created with: 
     * 
     * dd if=/dev/zero bs=1024 count=20480 of=/tmp/loop.img 
     * 
     * ... and the ext2 file system maps the entire device. 
     * 
     */ 
     fd = open("/tmp/loop.img", O_RDONLY); 

     /* Jump to superblock */ 
     lseek(fd, 1024, SEEK_SET); 

     /* Read the superblock */ 
     read(fd, &sb, sizeof(struct ext2_super_block)); 

     /* Print the total block count */ 
     printf("s_blocks_count: %" PRIu32 "\n", sb.s_blocks_count); /* Prints 20480 */ 

     return 0; 
} 

最後的一些想法

  • 做手工真是瘋了,國際海事組織(你必須有一個非常,非常充分的理由這樣做:))EDIT 2]:這比我更簡單以前認爲,因爲[可能]所有的文件系統超級塊[可能]包含總塊數(見相關討論的答案評論)。
  • 如果我是你,我會評估多少個不同的操作系統那段代碼應該運行,並且只用非便攜式調用來實現設備級別信息收集器(他們是直接系統調用[if任何]或庫實現)由每個操作系統提供。然後,構建過程將能夠確定和配置代碼以在目標機器上正確編譯[編輯2]:這仍然是最好的方法(利用各自的文件系統庫)。
  • 如果你真的不想(或需要)編碼任何東西,而你只是在尋找一個特定於Linux的命令行工具來檢索這些數據(在設備級別),請使用:blockdev --getsize64 /dev/loop0 [編輯2]:這是設備級別的信息,它不是問題涉及的內容。
  • [編輯否則,如果設備級別的信息是不夠的(在情況下,文件系統只映射器件尺寸的一部分),你已經有了答案:做dumpe2fstune2fs和一樣。
+0

「您指向的每個操作系統提供的非便攜式調用」很不幸地是錯誤的:查詢循環設備或分區/塊設備的大小不會有幫助,如果文件系統不涵蓋整個設備/分區。 – Dummy00001

+0

是的,的確如此。因此,基本上,如果您想要覆蓋這種情況,則需要根據其結構手動計算文件系統開銷... – pah

+0

特定於文件系統的計算文件系統大小的方法要簡單得多,實際上:大多數(如果不是全部的話)文件系統的大小都是在其超級塊中編碼的。請參閱https://github.com/tytso/e2fsprogs/blob/master/lib/blkid/probe.h – Dummy00001

相關問題