aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ext4/inode.c32
-rw-r--r--fs/ext4/super.c9
-rw-r--r--include/linux/ext4_fs.h3
3 files changed, 33 insertions, 11 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index bb89fe727bb1..9cf85721d83c 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -2671,14 +2671,20 @@ static blkcnt_t ext4_inode_blocks(struct ext4_inode *raw_inode,
2671 struct ext4_inode_info *ei) 2671 struct ext4_inode_info *ei)
2672{ 2672{
2673 blkcnt_t i_blocks ; 2673 blkcnt_t i_blocks ;
2674 struct super_block *sb = ei->vfs_inode.i_sb; 2674 struct inode *inode = &(ei->vfs_inode);
2675 struct super_block *sb = inode->i_sb;
2675 2676
2676 if (EXT4_HAS_RO_COMPAT_FEATURE(sb, 2677 if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
2677 EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) { 2678 EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
2678 /* we are using combined 48 bit field */ 2679 /* we are using combined 48 bit field */
2679 i_blocks = ((u64)le16_to_cpu(raw_inode->i_blocks_high)) << 32 | 2680 i_blocks = ((u64)le16_to_cpu(raw_inode->i_blocks_high)) << 32 |
2680 le32_to_cpu(raw_inode->i_blocks_lo); 2681 le32_to_cpu(raw_inode->i_blocks_lo);
2681 return i_blocks; 2682 if (ei->i_flags & EXT4_HUGE_FILE_FL) {
2683 /* i_blocks represent file system block size */
2684 return i_blocks << (inode->i_blkbits - 9);
2685 } else {
2686 return i_blocks;
2687 }
2682 } else { 2688 } else {
2683 return le32_to_cpu(raw_inode->i_blocks_lo); 2689 return le32_to_cpu(raw_inode->i_blocks_lo);
2684 } 2690 }
@@ -2829,8 +2835,9 @@ static int ext4_inode_blocks_set(handle_t *handle,
2829 * i_blocks can be represnted in a 32 bit variable 2835 * i_blocks can be represnted in a 32 bit variable
2830 * as multiple of 512 bytes 2836 * as multiple of 512 bytes
2831 */ 2837 */
2832 raw_inode->i_blocks_lo = cpu_to_le32((u32)i_blocks); 2838 raw_inode->i_blocks_lo = cpu_to_le32(i_blocks);
2833 raw_inode->i_blocks_high = 0; 2839 raw_inode->i_blocks_high = 0;
2840 ei->i_flags &= ~EXT4_HUGE_FILE_FL;
2834 } else if (i_blocks <= 0xffffffffffffULL) { 2841 } else if (i_blocks <= 0xffffffffffffULL) {
2835 /* 2842 /*
2836 * i_blocks can be represented in a 48 bit variable 2843 * i_blocks can be represented in a 48 bit variable
@@ -2841,12 +2848,23 @@ static int ext4_inode_blocks_set(handle_t *handle,
2841 if (err) 2848 if (err)
2842 goto err_out; 2849 goto err_out;
2843 /* i_block is stored in the split 48 bit fields */ 2850 /* i_block is stored in the split 48 bit fields */
2844 raw_inode->i_blocks_lo = cpu_to_le32((u32)i_blocks); 2851 raw_inode->i_blocks_lo = cpu_to_le32(i_blocks);
2845 raw_inode->i_blocks_high = cpu_to_le16(i_blocks >> 32); 2852 raw_inode->i_blocks_high = cpu_to_le16(i_blocks >> 32);
2853 ei->i_flags &= ~EXT4_HUGE_FILE_FL;
2846 } else { 2854 } else {
2847 ext4_error(sb, __FUNCTION__, 2855 /*
2848 "Wrong inode i_blocks count %llu\n", 2856 * i_blocks should be represented in a 48 bit variable
2849 (unsigned long long)inode->i_blocks); 2857 * as multiple of file system block size
2858 */
2859 err = ext4_update_rocompat_feature(handle, sb,
2860 EXT4_FEATURE_RO_COMPAT_HUGE_FILE);
2861 if (err)
2862 goto err_out;
2863 ei->i_flags |= EXT4_HUGE_FILE_FL;
2864 /* i_block is stored in file system block size */
2865 i_blocks = i_blocks >> (inode->i_blkbits - 9);
2866 raw_inode->i_blocks_lo = cpu_to_le32(i_blocks);
2867 raw_inode->i_blocks_high = cpu_to_le16(i_blocks >> 32);
2850 } 2868 }
2851err_out: 2869err_out:
2852 return err; 2870 return err;
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 2b9dc96ec43e..64067de70c6f 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1631,11 +1631,14 @@ static loff_t ext4_max_size(int bits)
1631 upper_limit >>= (bits - 9); 1631 upper_limit >>= (bits - 9);
1632 1632
1633 } else { 1633 } else {
1634 /* We use 48 bit ext4_inode i_blocks */ 1634 /*
1635 * We use 48 bit ext4_inode i_blocks
1636 * With EXT4_HUGE_FILE_FL set the i_blocks
1637 * represent total number of blocks in
1638 * file system block size
1639 */
1635 upper_limit = (1LL << 48) - 1; 1640 upper_limit = (1LL << 48) - 1;
1636 1641
1637 /* total blocks in file system block size */
1638 upper_limit >>= (bits - 9);
1639 } 1642 }
1640 1643
1641 /* indirect blocks */ 1644 /* indirect blocks */
diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h
index be25eca9c040..6ae91f40aaa2 100644
--- a/include/linux/ext4_fs.h
+++ b/include/linux/ext4_fs.h
@@ -178,8 +178,9 @@ struct ext4_group_desc
178#define EXT4_NOTAIL_FL 0x00008000 /* file tail should not be merged */ 178#define EXT4_NOTAIL_FL 0x00008000 /* file tail should not be merged */
179#define EXT4_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ 179#define EXT4_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */
180#define EXT4_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ 180#define EXT4_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
181#define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */ 181#define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */
182#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ 182#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */
183#define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */
183 184
184#define EXT4_FL_USER_VISIBLE 0x000BDFFF /* User visible flags */ 185#define EXT4_FL_USER_VISIBLE 0x000BDFFF /* User visible flags */
185#define EXT4_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ 186#define EXT4_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */