diff options
author | Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> | 2008-01-28 23:58:26 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2008-01-28 23:58:26 -0500 |
commit | 0fc1b451471dfc3cabd6e99ef441df9804616e63 (patch) | |
tree | b018b6ddc5bb5f02b985b06c11f0c01adb38167a | |
parent | a48380f769dfed6163fb82a68b13bd562ea1e027 (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.c | 58 | ||||
-rw-r--r-- | fs/ext4/super.c | 62 | ||||
-rw-r--r-- | include/linux/ext4_fs.h | 10 |
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 | } |
2670 | static 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 | ||
2671 | void ext4_read_inode(struct inode * inode) | 2687 | void 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 | ||
2818 | static 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 | } | ||
2851 | err_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 | */ |
1609 | static loff_t ext4_max_size(int bits) | 1609 | static 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 |