diff options
-rw-r--r-- | fs/ext4/inode.c | 32 | ||||
-rw-r--r-- | fs/ext4/super.c | 9 | ||||
-rw-r--r-- | include/linux/ext4_fs.h | 3 |
3 files changed, 33 insertions, 11 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index bb89fe727bb..9cf85721d83 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, struct ext4_inode_info *ei) { blkcnt_t i_blocks ; - struct super_block *sb = ei->vfs_inode.i_sb; + struct inode *inode = &(ei->vfs_inode); + struct super_block *sb = inode->i_sb; if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) { /* we are using combined 48 bit field */ i_blocks = ((u64)le16_to_cpu(raw_inode->i_blocks_high)) << 32 | le32_to_cpu(raw_inode->i_blocks_lo); - return i_blocks; + if (ei->i_flags & EXT4_HUGE_FILE_FL) { + /* i_blocks represent file system block size */ + return i_blocks << (inode->i_blkbits - 9); + } else { + return i_blocks; + } } else { return le32_to_cpu(raw_inode->i_blocks_lo); } @@ -2829,8 +2835,9 @@ static int ext4_inode_blocks_set(handle_t *handle, * i_blocks can be represnted in a 32 bit variable * as multiple of 512 bytes */ - raw_inode->i_blocks_lo = cpu_to_le32((u32)i_blocks); + raw_inode->i_blocks_lo = cpu_to_le32(i_blocks); raw_inode->i_blocks_high = 0; + ei->i_flags &= ~EXT4_HUGE_FILE_FL; } else if (i_blocks <= 0xffffffffffffULL) { /* * i_blocks can be represented in a 48 bit variable @@ -2841,12 +2848,23 @@ static int ext4_inode_blocks_set(handle_t *handle, if (err) goto err_out; /* i_block is stored in the split 48 bit fields */ - raw_inode->i_blocks_lo = cpu_to_le32((u32)i_blocks); + raw_inode->i_blocks_lo = cpu_to_le32(i_blocks); raw_inode->i_blocks_high = cpu_to_le16(i_blocks >> 32); + ei->i_flags &= ~EXT4_HUGE_FILE_FL; } else { - ext4_error(sb, __FUNCTION__, - "Wrong inode i_blocks count %llu\n", - (unsigned long long)inode->i_blocks); + /* + * i_blocks should be represented in a 48 bit variable + * as multiple of file system block size + */ + err = ext4_update_rocompat_feature(handle, sb, + EXT4_FEATURE_RO_COMPAT_HUGE_FILE); + if (err) + goto err_out; + ei->i_flags |= EXT4_HUGE_FILE_FL; + /* i_block is stored in file system block size */ + i_blocks = i_blocks >> (inode->i_blkbits - 9); + raw_inode->i_blocks_lo = cpu_to_le32(i_blocks); + raw_inode->i_blocks_high = cpu_to_le16(i_blocks >> 32); } err_out: return err; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 2b9dc96ec43..64067de70c6 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1631,11 +1631,14 @@ static loff_t ext4_max_size(int bits) upper_limit >>= (bits - 9); } else { - /* We use 48 bit ext4_inode i_blocks */ + /* + * We use 48 bit ext4_inode i_blocks + * With EXT4_HUGE_FILE_FL set the i_blocks + * represent total number of blocks in + * file system block size + */ upper_limit = (1LL << 48) - 1; - /* total blocks in file system block size */ - upper_limit >>= (bits - 9); } /* indirect blocks */ diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h index be25eca9c04..6ae91f40aaa 100644 --- a/include/linux/ext4_fs.h +++ b/include/linux/ext4_fs.h @@ -178,8 +178,9 @@ struct ext4_group_desc #define EXT4_NOTAIL_FL 0x00008000 /* file tail should not be merged */ #define EXT4_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ #define EXT4_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ -#define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */ +#define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */ #define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ +#define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */ #define EXT4_FL_USER_VISIBLE 0x000BDFFF /* User visible flags */ #define EXT4_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ |