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 goto failed_mount; 1850 } 1851 1852 - if (le32_to_cpu(es->s_blocks_count) > 1853 - (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) { 1854 ext3_msg(sb, KERN_ERR, 1855 "error: filesystem is too large to mount safely"); 1856 if (sizeof(sector_t) < 8)
··· 1849 goto failed_mount; 1850 } 1851 1852 + if (generic_check_addressable(sb->s_blocksize_bits, 1853 + le32_to_cpu(es->s_blocks_count))) { 1854 ext3_msg(sb, KERN_ERR, 1855 "error: filesystem is too large to mount safely"); 1856 if (sizeof(sector_t) < 8)
+3 -5
fs/ext4/super.c
··· 2831 * Test whether we have more sectors than will fit in sector_t, 2832 * and whether the max offset is addressable by the page cache. 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))) { 2838 ext4_msg(sb, KERN_ERR, "filesystem" 2839 " too large to mount safely on this system"); 2840 if (sizeof(sector_t) < 8) 2841 ext4_msg(sb, KERN_WARNING, "CONFIG_LBDAF not enabled"); 2842 - ret = -EFBIG; 2843 goto failed_mount; 2844 } 2845
··· 2831 * Test whether we have more sectors than will fit in sector_t, 2832 * and whether the max offset is addressable by the page cache. 2833 */ 2834 + ret = generic_check_addressable(sb->s_blocksize_bits, 2835 + ext4_blocks_count(es)); 2836 + if (ret) { 2837 ext4_msg(sb, KERN_ERR, "filesystem" 2838 " too large to mount safely on this system"); 2839 if (sizeof(sector_t) < 8) 2840 ext4_msg(sb, KERN_WARNING, "CONFIG_LBDAF not enabled"); 2841 goto failed_mount; 2842 } 2843
+29
fs/libfs.c
··· 913 } 914 EXPORT_SYMBOL(generic_file_fsync); 915 916 /* 917 * No-op implementation of ->fsync for in-memory filesystems. 918 */
··· 913 } 914 EXPORT_SYMBOL(generic_file_fsync); 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 + 945 /* 946 * No-op implementation of ->fsync for in-memory filesystems. 947 */
+2
include/linux/fs.h
··· 2374 2375 extern int generic_file_fsync(struct file *, int); 2376 2377 #ifdef CONFIG_MIGRATION 2378 extern int buffer_migrate_page(struct address_space *, 2379 struct page *, struct page *);
··· 2374 2375 extern int generic_file_fsync(struct file *, int); 2376 2377 + extern int generic_check_addressable(unsigned, u64); 2378 + 2379 #ifdef CONFIG_MIGRATION 2380 extern int buffer_migrate_page(struct address_space *, 2381 struct page *, struct page *);