ext3/ext4: Factor out disk addressability check

As part of adding support for OCFS2 to mount huge volumes, we need to
check that the sector_t and page cache of the system are capable of
addressing the entire volume.

An identical check already appears in ext3 and ext4. This patch moves
the addressability check into its own function in fs/libfs.c and
modifies ext3 and ext4 to invoke it.

[Edited to -EINVAL instead of BUG_ON() for bad blocksize_bits -- Joel]

Signed-off-by: Patrick LoPresti <lopresti@gmail.com>
Cc: linux-ext4@vger.kernel.org
Acked-by: Andreas Dilger <adilger@dilger.ca>
Signed-off-by: Joel Becker <joel.becker@oracle.com>

authored by

Patrick J. LoPresti and committed by
Joel Becker
30ca22c7 729963a1

+36 -7
+2 -2
fs/ext3/super.c
··· 1849 1849 goto failed_mount; 1850 1850 } 1851 1851 1852 - if (le32_to_cpu(es->s_blocks_count) > 1853 - (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) { 1852 + if (generic_check_addressable(sb->s_blocksize_bits, 1853 + le32_to_cpu(es->s_blocks_count))) { 1854 1854 ext3_msg(sb, KERN_ERR, 1855 1855 "error: filesystem is too large to mount safely"); 1856 1856 if (sizeof(sector_t) < 8)
+3 -5
fs/ext4/super.c
··· 2831 2831 * Test whether we have more sectors than will fit in sector_t, 2832 2832 * and whether the max offset is addressable by the page cache. 2833 2833 */ 2834 - if ((ext4_blocks_count(es) > 2835 - (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) || 2836 - (ext4_blocks_count(es) > 2837 - (pgoff_t)(~0ULL) >> (PAGE_CACHE_SHIFT - sb->s_blocksize_bits))) { 2834 + ret = generic_check_addressable(sb->s_blocksize_bits, 2835 + ext4_blocks_count(es)); 2836 + if (ret) { 2838 2837 ext4_msg(sb, KERN_ERR, "filesystem" 2839 2838 " too large to mount safely on this system"); 2840 2839 if (sizeof(sector_t) < 8) 2841 2840 ext4_msg(sb, KERN_WARNING, "CONFIG_LBDAF not enabled"); 2842 - ret = -EFBIG; 2843 2841 goto failed_mount; 2844 2842 } 2845 2843
+29
fs/libfs.c
··· 913 913 } 914 914 EXPORT_SYMBOL(generic_file_fsync); 915 915 916 + /** 917 + * generic_check_addressable - Check addressability of file system 918 + * @blocksize_bits: log of file system block size 919 + * @num_blocks: number of blocks in file system 920 + * 921 + * Determine whether a file system with @num_blocks blocks (and a 922 + * block size of 2**@blocksize_bits) is addressable by the sector_t 923 + * and page cache of the system. Return 0 if so and -EFBIG otherwise. 924 + */ 925 + int generic_check_addressable(unsigned blocksize_bits, u64 num_blocks) 926 + { 927 + u64 last_fs_block = num_blocks - 1; 928 + 929 + if (unlikely(num_blocks == 0)) 930 + return 0; 931 + 932 + if ((blocksize_bits < 9) || (blocksize_bits > PAGE_CACHE_SHIFT)) 933 + return -EINVAL; 934 + 935 + if ((last_fs_block > 936 + (sector_t)(~0ULL) >> (blocksize_bits - 9)) || 937 + (last_fs_block > 938 + (pgoff_t)(~0ULL) >> (PAGE_CACHE_SHIFT - blocksize_bits))) { 939 + return -EFBIG; 940 + } 941 + return 0; 942 + } 943 + EXPORT_SYMBOL(generic_check_addressable); 944 + 916 945 /* 917 946 * No-op implementation of ->fsync for in-memory filesystems. 918 947 */
+2
include/linux/fs.h
··· 2374 2374 2375 2375 extern int generic_file_fsync(struct file *, int); 2376 2376 2377 + extern int generic_check_addressable(unsigned, u64); 2378 + 2377 2379 #ifdef CONFIG_MIGRATION 2378 2380 extern int buffer_migrate_page(struct address_space *, 2379 2381 struct page *, struct page *);