aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>2008-01-28 23:58:26 -0500
committerTheodore Ts'o <tytso@mit.edu>2008-01-28 23:58:26 -0500
commit0fc1b451471dfc3cabd6e99ef441df9804616e63 (patch)
treeb018b6ddc5bb5f02b985b06c11f0c01adb38167a
parenta48380f769dfed6163fb82a68b13bd562ea1e027 (diff)
ext4: Add support for 48 bit inode i_blocks.
Use the __le16 l_i_reserved1 field of the linux2 struct of ext4_inode to represet the higher 16 bits for i_blocks. With this change max_file size becomes (2**48 -1 )* 512 bytes. We add a RO_COMPAT feature to the super block to indicate that inode have i_blocks represented as a split 48 bits. Super block with this feature set cannot be mounted read write on a kernel with CONFIG_LSF disabled. Super block flag EXT4_FEATURE_RO_COMPAT_HUGE_FILE Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
-rw-r--r--fs/ext4/inode.c58
-rw-r--r--fs/ext4/super.c62
-rw-r--r--include/linux/ext4_fs.h10
3 files changed, 119 insertions, 11 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index e6634550cfc8..bb89fe727bb1 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -2667,6 +2667,22 @@ void ext4_get_inode_flags(struct ext4_inode_info *ei)
2667 if (flags & S_DIRSYNC) 2667 if (flags & S_DIRSYNC)
2668 ei->i_flags |= EXT4_DIRSYNC_FL; 2668 ei->i_flags |= EXT4_DIRSYNC_FL;
2669} 2669}
2670static blkcnt_t ext4_inode_blocks(struct ext4_inode *raw_inode,
2671 struct ext4_inode_info *ei)
2672{
2673 blkcnt_t i_blocks ;
2674 struct super_block *sb = ei->vfs_inode.i_sb;
2675
2676 if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
2677 EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
2678 /* we are using combined 48 bit field */
2679 i_blocks = ((u64)le16_to_cpu(raw_inode->i_blocks_high)) << 32 |
2680 le32_to_cpu(raw_inode->i_blocks_lo);
2681 return i_blocks;
2682 } else {
2683 return le32_to_cpu(raw_inode->i_blocks_lo);
2684 }
2685}
2670 2686
2671void ext4_read_inode(struct inode * inode) 2687void ext4_read_inode(struct inode * inode)
2672{ 2688{
@@ -2715,8 +2731,8 @@ void ext4_read_inode(struct inode * inode)
2715 * recovery code: that's fine, we're about to complete 2731 * recovery code: that's fine, we're about to complete
2716 * the process of deleting those. */ 2732 * the process of deleting those. */
2717 } 2733 }
2718 inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
2719 ei->i_flags = le32_to_cpu(raw_inode->i_flags); 2734 ei->i_flags = le32_to_cpu(raw_inode->i_flags);
2735 inode->i_blocks = ext4_inode_blocks(raw_inode, ei);
2720 ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl_lo); 2736 ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl_lo);
2721 if (EXT4_SB(inode->i_sb)->s_es->s_creator_os != 2737 if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
2722 cpu_to_le32(EXT4_OS_HURD)) { 2738 cpu_to_le32(EXT4_OS_HURD)) {
@@ -2799,6 +2815,43 @@ bad_inode:
2799 return; 2815 return;
2800} 2816}
2801 2817
2818static int ext4_inode_blocks_set(handle_t *handle,
2819 struct ext4_inode *raw_inode,
2820 struct ext4_inode_info *ei)
2821{
2822 struct inode *inode = &(ei->vfs_inode);
2823 u64 i_blocks = inode->i_blocks;
2824 struct super_block *sb = inode->i_sb;
2825 int err = 0;
2826
2827 if (i_blocks <= ~0U) {
2828 /*
2829 * i_blocks can be represnted in a 32 bit variable
2830 * as multiple of 512 bytes
2831 */
2832 raw_inode->i_blocks_lo = cpu_to_le32((u32)i_blocks);
2833 raw_inode->i_blocks_high = 0;
2834 } else if (i_blocks <= 0xffffffffffffULL) {
2835 /*
2836 * i_blocks can be represented in a 48 bit variable
2837 * as multiple of 512 bytes
2838 */
2839 err = ext4_update_rocompat_feature(handle, sb,
2840 EXT4_FEATURE_RO_COMPAT_HUGE_FILE);
2841 if (err)
2842 goto err_out;
2843 /* i_block is stored in the split 48 bit fields */
2844 raw_inode->i_blocks_lo = cpu_to_le32((u32)i_blocks);
2845 raw_inode->i_blocks_high = cpu_to_le16(i_blocks >> 32);
2846 } else {
2847 ext4_error(sb, __FUNCTION__,
2848 "Wrong inode i_blocks count %llu\n",
2849 (unsigned long long)inode->i_blocks);
2850 }
2851err_out:
2852 return err;
2853}
2854
2802/* 2855/*
2803 * Post the struct inode info into an on-disk inode location in the 2856 * Post the struct inode info into an on-disk inode location in the
2804 * buffer-cache. This gobbles the caller's reference to the 2857 * buffer-cache. This gobbles the caller's reference to the
@@ -2853,7 +2906,8 @@ static int ext4_do_update_inode(handle_t *handle,
2853 EXT4_INODE_SET_XTIME(i_atime, inode, raw_inode); 2906 EXT4_INODE_SET_XTIME(i_atime, inode, raw_inode);
2854 EXT4_EINODE_SET_XTIME(i_crtime, ei, raw_inode); 2907 EXT4_EINODE_SET_XTIME(i_crtime, ei, raw_inode);
2855 2908
2856 raw_inode->i_blocks = cpu_to_le32(inode->i_blocks); 2909 if (ext4_inode_blocks_set(handle, raw_inode, ei))
2910 goto out_brelse;
2857 raw_inode->i_dtime = cpu_to_le32(ei->i_dtime); 2911 raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
2858 raw_inode->i_flags = cpu_to_le32(ei->i_flags); 2912 raw_inode->i_flags = cpu_to_le32(ei->i_flags);
2859 if (EXT4_SB(inode->i_sb)->s_es->s_creator_os != 2913 if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 7be27dbe76bf..2b9dc96ec43e 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1603,17 +1603,50 @@ static void ext4_orphan_cleanup (struct super_block * sb,
1603 1603
1604/* 1604/*
1605 * Maximal file size. There is a direct, and {,double-,triple-}indirect 1605 * Maximal file size. There is a direct, and {,double-,triple-}indirect
1606 * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks. 1606 * block limit, and also a limit of (2^48 - 1) 512-byte sectors in i_blocks.
1607 * We need to be 1 filesystem block less than the 2^32 sector limit. 1607 * We need to be 1 filesystem block less than the 2^48 sector limit.
1608 */ 1608 */
1609static loff_t ext4_max_size(int bits) 1609static loff_t ext4_max_size(int bits)
1610{ 1610{
1611 loff_t res = EXT4_NDIR_BLOCKS; 1611 loff_t res = EXT4_NDIR_BLOCKS;
1612 /* This constant is calculated to be the largest file size for a 1612 int meta_blocks;
1613 * dense, 4k-blocksize file such that the total number of 1613 loff_t upper_limit;
1614 /* This is calculated to be the largest file size for a
1615 * dense, file such that the total number of
1614 * sectors in the file, including data and all indirect blocks, 1616 * sectors in the file, including data and all indirect blocks,
1615 * does not exceed 2^32. */ 1617 * does not exceed 2^48 -1
1616 const loff_t upper_limit = 0x1ff7fffd000LL; 1618 * __u32 i_blocks_lo and _u16 i_blocks_high representing the
1619 * total number of 512 bytes blocks of the file
1620 */
1621
1622 if (sizeof(blkcnt_t) < sizeof(u64)) {
1623 /*
1624 * CONFIG_LSF is not enabled implies the inode
1625 * i_block represent total blocks in 512 bytes
1626 * 32 == size of vfs inode i_blocks * 8
1627 */
1628 upper_limit = (1LL << 32) - 1;
1629
1630 /* total blocks in file system block size */
1631 upper_limit >>= (bits - 9);
1632
1633 } else {
1634 /* We use 48 bit ext4_inode i_blocks */
1635 upper_limit = (1LL << 48) - 1;
1636
1637 /* total blocks in file system block size */
1638 upper_limit >>= (bits - 9);
1639 }
1640
1641 /* indirect blocks */
1642 meta_blocks = 1;
1643 /* double indirect blocks */
1644 meta_blocks += 1 + (1LL << (bits-2));
1645 /* tripple indirect blocks */
1646 meta_blocks += 1 + (1LL << (bits-2)) + (1LL << (2*(bits-2)));
1647
1648 upper_limit -= meta_blocks;
1649 upper_limit <<= bits;
1617 1650
1618 res += 1LL << (bits-2); 1651 res += 1LL << (bits-2);
1619 res += 1LL << (2*(bits-2)); 1652 res += 1LL << (2*(bits-2));
@@ -1621,6 +1654,10 @@ static loff_t ext4_max_size(int bits)
1621 res <<= bits; 1654 res <<= bits;
1622 if (res > upper_limit) 1655 if (res > upper_limit)
1623 res = upper_limit; 1656 res = upper_limit;
1657
1658 if (res > MAX_LFS_FILESIZE)
1659 res = MAX_LFS_FILESIZE;
1660
1624 return res; 1661 return res;
1625} 1662}
1626 1663
@@ -1789,6 +1826,19 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
1789 sb->s_id, le32_to_cpu(features)); 1826 sb->s_id, le32_to_cpu(features));
1790 goto failed_mount; 1827 goto failed_mount;
1791 } 1828 }
1829 if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
1830 /*
1831 * Large file size enabled file system can only be
1832 * mount if kernel is build with CONFIG_LSF
1833 */
1834 if (sizeof(root->i_blocks) < sizeof(u64) &&
1835 !(sb->s_flags & MS_RDONLY)) {
1836 printk(KERN_ERR "EXT4-fs: %s: Filesystem with huge "
1837 "files cannot be mounted read-write "
1838 "without CONFIG_LSF.\n", sb->s_id);
1839 goto failed_mount;
1840 }
1841 }
1792 blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size); 1842 blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size);
1793 1843
1794 if (blocksize < EXT4_MIN_BLOCK_SIZE || 1844 if (blocksize < EXT4_MIN_BLOCK_SIZE ||
diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h
index a8f3faea8eff..be25eca9c040 100644
--- a/include/linux/ext4_fs.h
+++ b/include/linux/ext4_fs.h
@@ -282,7 +282,7 @@ struct ext4_inode {
282 __le32 i_dtime; /* Deletion Time */ 282 __le32 i_dtime; /* Deletion Time */
283 __le16 i_gid; /* Low 16 bits of Group Id */ 283 __le16 i_gid; /* Low 16 bits of Group Id */
284 __le16 i_links_count; /* Links count */ 284 __le16 i_links_count; /* Links count */
285 __le32 i_blocks; /* Blocks count */ 285 __le32 i_blocks_lo; /* Blocks count */
286 __le32 i_flags; /* File flags */ 286 __le32 i_flags; /* File flags */
287 union { 287 union {
288 struct { 288 struct {
@@ -302,7 +302,7 @@ struct ext4_inode {
302 __le32 i_obso_faddr; /* Obsoleted fragment address */ 302 __le32 i_obso_faddr; /* Obsoleted fragment address */
303 union { 303 union {
304 struct { 304 struct {
305 __le16 l_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */ 305 __le16 l_i_blocks_high; /* were l_i_reserved1 */
306 __le16 l_i_file_acl_high; 306 __le16 l_i_file_acl_high;
307 __le16 l_i_uid_high; /* these 2 fields */ 307 __le16 l_i_uid_high; /* these 2 fields */
308 __le16 l_i_gid_high; /* were reserved2[0] */ 308 __le16 l_i_gid_high; /* were reserved2[0] */
@@ -404,6 +404,7 @@ do { \
404#if defined(__KERNEL__) || defined(__linux__) 404#if defined(__KERNEL__) || defined(__linux__)
405#define i_reserved1 osd1.linux1.l_i_reserved1 405#define i_reserved1 osd1.linux1.l_i_reserved1
406#define i_file_acl_high osd2.linux2.l_i_file_acl_high 406#define i_file_acl_high osd2.linux2.l_i_file_acl_high
407#define i_blocks_high osd2.linux2.l_i_blocks_high
407#define i_uid_low i_uid 408#define i_uid_low i_uid
408#define i_gid_low i_gid 409#define i_gid_low i_gid
409#define i_uid_high osd2.linux2.l_i_uid_high 410#define i_uid_high osd2.linux2.l_i_uid_high
@@ -670,6 +671,7 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
670#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 671#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
671#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 672#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
672#define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 673#define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
674#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008
673#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010 675#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
674#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020 676#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
675#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040 677#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
@@ -681,6 +683,7 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
681#define EXT4_FEATURE_INCOMPAT_META_BG 0x0010 683#define EXT4_FEATURE_INCOMPAT_META_BG 0x0010
682#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */ 684#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */
683#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 685#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
686#define EXT4_FEATURE_INCOMPAT_MMP 0x0100
684#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 687#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
685 688
686#define EXT4_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR 689#define EXT4_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR
@@ -695,7 +698,8 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
695 EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \ 698 EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \
696 EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \ 699 EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \
697 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \ 700 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \
698 EXT4_FEATURE_RO_COMPAT_BTREE_DIR) 701 EXT4_FEATURE_RO_COMPAT_BTREE_DIR |\
702 EXT4_FEATURE_RO_COMPAT_HUGE_FILE)
699 703
700/* 704/*
701 * Default values for user and/or group using reserved blocks 705 * Default values for user and/or group using reserved blocks