diff options
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r-- | fs/ext4/inode.c | 32 |
1 files changed, 25 insertions, 7 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 | } |
2851 | err_out: | 2869 | err_out: |
2852 | return err; | 2870 | return err; |