libext2fs: Fix FEATURE_RO_COMPAT_HUGE_FILE && !HUGE_FILE_FL

If the RO compat HUGE_FILE feature flag is set, but the inode's
HUGE_FILE_FL flag is not set, we should still pay attention to the
high 32 bits of the i_blocks filed.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
bitmap-optimize
Theodore Ts'o 2009-10-21 01:46:58 -04:00
parent ba5131f6d4
commit 5d10807070
1 changed files with 40 additions and 27 deletions

View File

@ -21,6 +21,7 @@
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <errno.h>
#include "ext2_fs.h"
#include "ext2fs.h"
@ -28,48 +29,60 @@
errcode_t ext2fs_iblk_add_blocks(ext2_filsys fs, struct ext2_inode *inode,
blk64_t num_blocks)
{
unsigned long long b;
unsigned long long b = inode->i_blocks;
if ((fs->super->s_feature_ro_compat &
EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
(inode->i_flags & EXT4_HUGE_FILE_FL)) {
b = inode->i_blocks +
(((long long) inode->osd2.linux2.l_i_blocks_hi) << 32);
b += num_blocks;
inode->i_blocks = b & 0xFFFFFFFF;
if (!(fs->super->s_feature_ro_compat &
EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ||
!(inode->i_flags & EXT4_HUGE_FILE_FL))
num_blocks *= fs->blocksize / 512;
b += num_blocks;
if (fs->super->s_feature_ro_compat &
EXT4_FEATURE_RO_COMPAT_HUGE_FILE) {
b += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32;
inode->osd2.linux2.l_i_blocks_hi = b >> 32;
} else
inode->i_blocks += (fs->blocksize / 512) * num_blocks;
} else if (b > 0xFFFFFFFF)
return EOVERFLOW;
inode->i_blocks = b & 0xFFFFFFFF;
return 0;
}
errcode_t ext2fs_iblk_sub_blocks(ext2_filsys fs, struct ext2_inode *inode,
blk64_t num_blocks)
{
unsigned long long b;
unsigned long long b = inode->i_blocks;
if ((fs->super->s_feature_ro_compat &
EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
(inode->i_flags & EXT4_HUGE_FILE_FL)) {
b = inode->i_blocks +
(((long long) inode->osd2.linux2.l_i_blocks_hi) << 32);
b -= num_blocks;
inode->i_blocks = b & 0xFFFFFFFF;
if (!(fs->super->s_feature_ro_compat &
EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ||
!(inode->i_flags & EXT4_HUGE_FILE_FL))
num_blocks *= fs->blocksize / 512;
if (num_blocks > b)
return EOVERFLOW;
b -= num_blocks;
if (fs->super->s_feature_ro_compat &
EXT4_FEATURE_RO_COMPAT_HUGE_FILE) {
b += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32;
inode->osd2.linux2.l_i_blocks_hi = b >> 32;
} else
inode->i_blocks -= (fs->blocksize / 512) * num_blocks;
}
inode->i_blocks = b & 0xFFFFFFFF;
return 0;
}
errcode_t ext2fs_iblk_set(ext2_filsys fs, struct ext2_inode *inode, blk64_t b)
{
if ((fs->super->s_feature_ro_compat &
EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
(inode->i_flags & EXT4_HUGE_FILE_FL)) {
inode->i_blocks = b & 0xFFFFFFFF;
if (!(fs->super->s_feature_ro_compat &
EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ||
!(inode->i_flags & EXT4_HUGE_FILE_FL))
b *= fs->blocksize / 512;
inode->i_blocks = b & 0xFFFFFFFF;
if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_HUGE_FILE)
inode->osd2.linux2.l_i_blocks_hi = b >> 32;
} else
inode->i_blocks = (fs->blocksize / 512) * b;
else if (b >> 32)
return EOVERFLOW;
return 0;
}