[parted-devel] [PATCH] Detect Ext4 (Parted Alioth #188)
Colin Watson
cjwatson at ubuntu.com
Fri Jan 9 12:41:21 UTC 2009
On Fri, Jan 09, 2009 at 10:56:38AM +0000, Colin Watson wrote:
> On Mon, Jan 05, 2009 at 11:25:27PM +0530, Debarshi Ray wrote:
> > I spent some time over the last couple of days trying to make
> > libparted detect Ext4 filesystems [1]. Here ([2] and below) is a very
> > preliminary 'git diff' against the current Git master. I have not yet
> > tested it extensively, but I just wanted to know whether I am on the
> > right track or not.
>
> The patch you committed seems to be strictly less capable than the one I
> put in the Trac report:
>
> http://parted.alioth.debian.org/cgi-bin/trac.cgi/ticket/188
>
> Perhaps the further improvements I made there could be integrated too?
Here's a version of my patch merged with yours. Although I have not yet
been able to test them extensively, the block count patches are
particularly important; without them, parted will detect the wrong
geometry for a >2TB ext4 filesystem.
Please consider including this patch as well as your detection patch.
Thanks in advance!
2009-01-09 Colin Watson <cjwatson at ubuntu.com>
* libparted/fs/ext2/ext2_fs.h (ext2_super_block): Expand to cover
new ext4 members.
(EXT2_SUPER_BLOCKS_COUNT, EXT2_SUPER_R_BLOCKS_COUNT,
EXT2_SUPER_FREE_BLOCKS_COUNT): Handle EXT4_FEATURE_INCOMPAT_64BIT.
(ext2_super_blocks_count_set, ext2_super_free_blocks_count_set,
ext2_super_r_blocks_count_set): New functions.
* libparted/fs/ext2/ext2.c (ext2_set_block_state,
ext2_commit_metadata): Use new block-count setting functions.
(ext2_open): Permit EXT4_FEATURE_INCOMPAT_64BIT.
* libparted/fs/ext2/ext2_mkfs.c (ext2_mkfs_write_meta,
ext2_mkfs_init_sb): Use new block-count setting functions.
* libparted/fs/ext2/ext2_resize.c (ext2_add_group, ext2_del_group,
ext2_grow_group, ext2_shrink_group): Use new block-count setting
functions.
(ext2_resize_fs): Refuse EXT4_FEATURE_INCOMPAT_EXTENTS.
* libparted/fs/ext2/interface.c (_ext2_generic_probe): ext4
filesystems may not necessarily have a journal (cf.
http://lwn.net/Articles/313514/).
(_ext4_ops): Flesh out to match ext3 (although many of these methods
will refuse most ext4 filesystems for the time being).
diff --git a/libparted/fs/ext2/ext2.c b/libparted/fs/ext2/ext2.c
index cf00ab1..86009c3 100644
--- a/libparted/fs/ext2/ext2.c
+++ b/libparted/fs/ext2/ext2.c
@@ -184,8 +184,8 @@ int ext2_set_block_state(struct ext2_fs *fs, blk_t block, int state, int updatem
fs->gd[group].bg_free_blocks_count = PED_CPU_TO_LE16
(EXT2_GROUP_FREE_BLOCKS_COUNT(fs->gd[group]) + diff);
- fs->sb.s_free_blocks_count = PED_CPU_TO_LE32
- (EXT2_SUPER_FREE_BLOCKS_COUNT(fs->sb) + diff);
+ ext2_super_free_blocks_count_set(&fs->sb,
+ EXT2_SUPER_FREE_BLOCKS_COUNT(fs->sb) + diff);
fs->metadirty |= EXT2_META_SB | EXT2_META_GD;
}
return 1;
@@ -605,7 +605,7 @@ int ext2_commit_metadata(struct ext2_fs *fs, int copies)
if (wmeta == EXT2_META_CLEAN)
return 1;
- fs->sb.s_r_blocks_count = PED_CPU_TO_LE32 (
+ ext2_super_r_blocks_count_set(&fs->sb,
fs->r_frac * (loff_t)EXT2_SUPER_BLOCKS_COUNT(fs->sb)
/ 100);
@@ -721,7 +721,8 @@ struct ext2_fs *ext2_open(struct ext2_dev_handle *handle, int state)
EXT2_FEATURE_COMPAT_HAS_DIR_INDEX)) ||
(EXT2_SUPER_FEATURE_INCOMPAT(fs->sb)
& ~(EXT2_FEATURE_INCOMPAT_FILETYPE |
- EXT3_FEATURE_INCOMPAT_RECOVER)) ||
+ EXT3_FEATURE_INCOMPAT_RECOVER |
+ EXT4_FEATURE_INCOMPAT_64BIT)) ||
(EXT2_SUPER_FEATURE_RO_COMPAT(fs->sb)
& ~(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER |
EXT2_FEATURE_RO_COMPAT_LARGE_FILE)))
diff --git a/libparted/fs/ext2/ext2_fs.h b/libparted/fs/ext2/ext2_fs.h
index d642518..84899a8 100644
--- a/libparted/fs/ext2/ext2_fs.h
+++ b/libparted/fs/ext2/ext2_fs.h
@@ -174,9 +174,9 @@ struct ext2_inode
struct ext2_super_block
{
uint32_t s_inodes_count; /* Inodes count */
- uint32_t s_blocks_count; /* Blocks count */
- uint32_t s_r_blocks_count; /* Reserved blocks count */
- uint32_t s_free_blocks_count; /* Free blocks count */
+ uint32_t s_blocks_count_lo; /* Blocks count */
+ uint32_t s_r_blocks_count_lo; /* Reserved blocks count */
+ uint32_t s_free_blocks_count_lo; /* Free blocks count */
uint32_t s_free_inodes_count; /* Free inodes count */
uint32_t s_first_data_block; /* First Data Block */
uint32_t s_log_block_size; /* Block size */
@@ -235,10 +235,38 @@ struct ext2_super_block
uint32_t s_journal_inum; /* inode number of journal file */
uint32_t s_journal_dev; /* device number of journal file */
uint32_t s_last_orphan; /* start of list of inodes to delete */
+ uint32_t s_hash_seed[4]; /* HTREE hash seed */
+ uint8_t s_def_hash_version; /* Default hash version to use */
+ uint8_t s_reserved_char_pad;
+ uint16_t s_desc_size; /* size of group descriptor */
+ uint32_t s_default_mount_opts;
+ uint32_t s_first_meta_bg; /* First metablock block group */
+ uint32_t s_mkfs_time; /* When the filesystem was created */
+ uint32_t s_jnl_blocks[17]; /* Backup of the journal inode */
+ /* 64bit support valid if EXT4_FEATURE_INCOMPAT_64BIT */
+ uint32_t s_blocks_count_hi; /* Blocks count */
+ uint32_t s_r_blocks_count_hi; /* Reserved blocks count */
+ uint32_t s_free_blocks_count_hi; /* Free blocks count */
+ uint16_t s_min_extra_isize; /* All inodes have at least # bytes */
+ uint16_t s_want_extra_isize; /* New inodes should reserve # bytes */
+ uint32_t s_flags; /* Miscellaneous flags */
+ uint16_t s_raid_stride; /* RAID stride */
+ uint16_t s_mmp_interval; /* # seconds to wait in MMP checking */
+ uint64_t s_mmp_block; /* Block for multi-mount protection */
+ uint32_t s_raid_stripe_width; /* blocks on all data disks (N*stride) */
+ uint8_t s_log_groups_per_flex; /* FLEX_BG group size */
+ uint8_t s_reserved_char_pad2;
+ uint16_t s_reserved_pad;
- uint32_t s_reserved[197]; /* Padding to the end of the block */
+ uint32_t s_reserved[162]; /* Padding to the end of the block */
};
+#define EXT2_SUPER_FEATURE_COMPAT(sb) (PED_LE32_TO_CPU((sb).s_feature_compat))
+#define EXT2_SUPER_FEATURE_INCOMPAT(sb) \
+ (PED_LE32_TO_CPU((sb).s_feature_incompat))
+#define EXT2_SUPER_FEATURE_RO_COMPAT(sb) \
+ (PED_LE32_TO_CPU((sb).s_feature_ro_compat))
+
#define EXT2_DIRENT_INODE(dir_ent) (PED_LE32_TO_CPU((dir_ent).inode))
#define EXT2_DIRENT_REC_LEN(dir_ent) (PED_LE16_TO_CPU((dir_ent).rec_len))
#define EXT2_DIRENT_NAME_LEN(dir_ent) ((dir_ent).name_len)
@@ -271,10 +299,44 @@ struct ext2_super_block
#define EXT2_INODE_BLOCK(inode, blk) (PED_LE32_TO_CPU((inode).i_block[blk]))
#define EXT2_SUPER_INODES_COUNT(sb) (PED_LE32_TO_CPU((sb).s_inodes_count))
-#define EXT2_SUPER_BLOCKS_COUNT(sb) (PED_LE32_TO_CPU((sb).s_blocks_count))
-#define EXT2_SUPER_R_BLOCKS_COUNT(sb) (PED_LE32_TO_CPU((sb).s_r_blocks_count))
+
+#define EXT2_SUPER_BLOCKS_COUNT(sb) \
+ ((EXT2_SUPER_FEATURE_INCOMPAT((sb)) & EXT4_FEATURE_INCOMPAT_64BIT) \
+ ? (((uint64_t) PED_LE32_TO_CPU((sb).s_blocks_count_hi) << 32) \
+ | PED_LE32_TO_CPU((sb).s_blocks_count_lo)) \
+ : PED_LE32_TO_CPU((sb).s_blocks_count_lo))
+#define EXT2_SUPER_R_BLOCKS_COUNT(sb) \
+ ((EXT2_SUPER_FEATURE_INCOMPAT((sb)) & EXT4_FEATURE_INCOMPAT_64BIT) \
+ ? (((uint64_t) PED_LE32_TO_CPU((sb).s_r_blocks_count_hi) << 32) \
+ | PED_LE32_TO_CPU((sb).s_r_blocks_count_lo)) \
+ : PED_LE32_TO_CPU((sb).s_r_blocks_count_lo))
#define EXT2_SUPER_FREE_BLOCKS_COUNT(sb) \
- (PED_LE32_TO_CPU((sb).s_free_blocks_count))
+ ((EXT2_SUPER_FEATURE_INCOMPAT((sb)) & EXT4_FEATURE_INCOMPAT_64BIT) \
+ ? (((uint64_t) PED_LE32_TO_CPU((sb).s_free_blocks_count_hi) << 32) \
+ | PED_LE32_TO_CPU((sb).s_free_blocks_count_lo)) \
+ : PED_LE32_TO_CPU((sb).s_free_blocks_count_lo))
+
+static inline void ext2_super_blocks_count_set(struct ext2_super_block *sb, uint64_t blk)
+{
+ sb->s_blocks_count_lo = PED_CPU_TO_LE32((uint32_t) blk);
+ if (EXT2_SUPER_FEATURE_INCOMPAT(*sb) & EXT4_FEATURE_INCOMPAT_64BIT)
+ sb->s_blocks_count_hi = PED_CPU_TO_LE32(blk >> 32);
+}
+
+static inline void ext2_super_free_blocks_count_set(struct ext2_super_block *sb, uint64_t blk)
+{
+ sb->s_free_blocks_count_lo = PED_CPU_TO_LE32((uint32_t) blk);
+ if (EXT2_SUPER_FEATURE_INCOMPAT(*sb) & EXT4_FEATURE_INCOMPAT_64BIT)
+ sb->s_free_blocks_count_hi = PED_CPU_TO_LE32(blk >> 32);
+}
+
+static inline void ext2_super_r_blocks_count_set(struct ext2_super_block *sb, uint64_t blk)
+{
+ sb->s_r_blocks_count_lo = PED_CPU_TO_LE32((uint32_t) blk);
+ if (EXT2_SUPER_FEATURE_INCOMPAT(*sb) & EXT4_FEATURE_INCOMPAT_64BIT)
+ sb->s_r_blocks_count_hi = PED_CPU_TO_LE32(blk >> 32);
+}
+
#define EXT2_SUPER_FREE_INODES_COUNT(sb) \
(PED_LE32_TO_CPU((sb).s_free_inodes_count))
#define EXT2_SUPER_FIRST_DATA_BLOCK(sb) \
@@ -308,11 +370,6 @@ struct ext2_super_block
#define EXT2_SUPER_FIRST_INO(sb) (PED_LE32_TO_CPU((sb).s_first_ino))
#define EXT2_SUPER_INODE_SIZE(sb) (PED_LE16_TO_CPU((sb).s_inode_size))
#define EXT2_SUPER_BLOCK_GROUP_NR(sb) (PED_LE16_TO_CPU((sb).s_block_group_nr))
-#define EXT2_SUPER_FEATURE_COMPAT(sb) (PED_LE32_TO_CPU((sb).s_feature_compat))
-#define EXT2_SUPER_FEATURE_INCOMPAT(sb) \
- (PED_LE32_TO_CPU((sb).s_feature_incompat))
-#define EXT2_SUPER_FEATURE_RO_COMPAT(sb) \
- (PED_LE32_TO_CPU((sb).s_feature_ro_compat))
#define EXT2_SUPER_UUID(sb) ((sb).s_uuid)
#define EXT2_SUPER_VOLUME_NAME(sb) ((sb).s_volume_name)
#define EXT2_SUPER_LAST_MOUNTED(sb) ((sb).s_last_mounted)
diff --git a/libparted/fs/ext2/ext2_mkfs.c b/libparted/fs/ext2/ext2_mkfs.c
index fa78a76..d29d0a9 100644
--- a/libparted/fs/ext2/ext2_mkfs.c
+++ b/libparted/fs/ext2/ext2_mkfs.c
@@ -240,7 +240,7 @@ static int ext2_mkfs_write_meta(struct ext2_dev_handle *handle,
gd[i].bg_reserved[1] = 0;
gd[i].bg_reserved[2] = 0;
- sb->s_free_blocks_count = PED_CPU_TO_LE32 (
+ ext2_super_free_blocks_count_set(sb,
EXT2_SUPER_FREE_BLOCKS_COUNT(*sb)
+ EXT2_GROUP_FREE_BLOCKS_COUNT(gd[i]));
}
@@ -424,14 +424,14 @@ static int ext2_mkfs_init_sb (struct ext2_super_block *sb, blk_t numblocks,
memset(sb, 0, 1024);
sb->s_inodes_count = PED_CPU_TO_LE32(numgroups * inodes_per_group);
- sb->s_blocks_count = PED_CPU_TO_LE32(numblocks);
- sb->s_r_blocks_count = PED_CPU_TO_LE32(((uint64_t)numblocks
+ ext2_super_blocks_count_set(sb, numblocks);
+ ext2_super_r_blocks_count_set(sb, ((uint64_t)numblocks
* reserved_block_percentage) / 100);
/* hack: this get's inc'd as we go through each group in
* ext2_mkfs_write_meta()
*/
- sb->s_free_blocks_count = 0;
+ ext2_super_free_blocks_count_set(sb, 0);
sb->s_free_inodes_count = PED_CPU_TO_LE32 (numgroups
* inodes_per_group);
sb->s_first_data_block = PED_CPU_TO_LE32(first_block);
diff --git a/libparted/fs/ext2/ext2_resize.c b/libparted/fs/ext2/ext2_resize.c
index 3da71f7..0f3692e 100644
--- a/libparted/fs/ext2/ext2_resize.c
+++ b/libparted/fs/ext2/ext2_resize.c
@@ -104,9 +104,9 @@ static int ext2_add_group(struct ext2_fs *fs, blk_t groupsize)
fs->sb.s_inodes_count = PED_CPU_TO_LE32(
EXT2_SUPER_INODES_COUNT(fs->sb)
+ EXT2_SUPER_INODES_PER_GROUP(fs->sb));
- fs->sb.s_blocks_count = PED_CPU_TO_LE32(
+ ext2_super_blocks_count_set(&fs->sb,
EXT2_SUPER_BLOCKS_COUNT(fs->sb) + groupsize);
- fs->sb.s_free_blocks_count = PED_CPU_TO_LE32(
+ ext2_super_free_blocks_count_set(&fs->sb,
EXT2_SUPER_FREE_BLOCKS_COUNT(fs->sb) + groupsize - admin);
fs->sb.s_free_inodes_count = PED_CPU_TO_LE32(
EXT2_SUPER_FREE_INODES_COUNT(fs->sb)
@@ -303,9 +303,9 @@ static int ext2_del_group(struct ext2_fs *fs)
fs->sb.s_inodes_count = PED_CPU_TO_LE32(
EXT2_SUPER_INODES_COUNT(fs->sb)
- EXT2_SUPER_INODES_PER_GROUP(fs->sb));
- fs->sb.s_blocks_count = PED_CPU_TO_LE32(
+ ext2_super_blocks_count_set(&fs->sb,
EXT2_SUPER_BLOCKS_COUNT(fs->sb) - groupsize);
- fs->sb.s_free_blocks_count = PED_CPU_TO_LE32(
+ ext2_super_free_blocks_count_set(&fs->sb,
EXT2_SUPER_FREE_BLOCKS_COUNT(fs->sb) - (groupsize - admin));
fs->sb.s_free_inodes_count = PED_CPU_TO_LE32(
EXT2_SUPER_FREE_INODES_COUNT(fs->sb)
@@ -357,7 +357,7 @@ static int ext2_grow_group(struct ext2_fs *fs, blk_t newsize)
for (i=gblocks;i<newsize;i++)
ext2_set_block_state(fs, groupoff + i, 0, 1);
- fs->sb.s_blocks_count = PED_CPU_TO_LE32(
+ ext2_super_blocks_count_set(&fs->sb,
EXT2_SUPER_BLOCKS_COUNT(fs->sb) + newsize - gblocks);
fs->metadirty |= EXT2_META_SB;
@@ -432,9 +432,9 @@ static int ext2_shrink_group(struct ext2_fs *fs, blk_t newsize)
}
i = gblocks - newsize;
- fs->sb.s_blocks_count = PED_CPU_TO_LE32(
+ ext2_super_blocks_count_set(&fs->sb,
EXT2_SUPER_BLOCKS_COUNT(fs->sb) - i);
- fs->sb.s_free_blocks_count = PED_CPU_TO_LE32(
+ ext2_super_free_blocks_count_set(&fs->sb,
EXT2_SUPER_FREE_BLOCKS_COUNT(fs->sb) - i);
fs->gd[group].bg_free_blocks_count = PED_CPU_TO_LE16(
EXT2_GROUP_FREE_BLOCKS_COUNT(fs->gd[group]) - i);
@@ -684,6 +684,14 @@ int ext2_resize_fs(struct ext2_fs *fs, blk_t newsize, PedTimer* timer)
fs->metadirty |= EXT2_META_SB;
}
+ if (EXT2_SUPER_FEATURE_INCOMPAT(fs->sb)
+ & EXT4_FEATURE_INCOMPAT_EXTENTS) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("Parted cannot resize ext4 file systems yet."));
+ return 0;
+ }
+
if (!ext2_determine_itoffset(fs) && ped_exception_throw (
PED_EXCEPTION_WARNING,
PED_EXCEPTION_OK_CANCEL,
diff --git a/libparted/fs/ext2/interface.c b/libparted/fs/ext2/interface.c
index 907f349..f2a95d7 100644
--- a/libparted/fs/ext2/interface.c
+++ b/libparted/fs/ext2/interface.c
@@ -28,6 +28,7 @@
static PedFileSystemType _ext2_type;
static PedFileSystemType _ext3_type;
+static PedFileSystemType _ext4_type;
struct ext2_dev_handle* ext2_make_dev_handle_from_parted_geometry(PedGeometry* geom);
@@ -51,24 +52,20 @@ _ext2_generic_probe (PedGeometry* geom, int expect_ext_ver)
is_ext3 = (EXT2_SUPER_FEATURE_COMPAT (sb)
& EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0;
- if (is_ext3) {
- is_ext4 = ((EXT2_SUPER_FEATURE_RO_COMPAT (sb)
- & EXT4_FEATURE_RO_COMPAT_HUGE_FILE)
- || (EXT2_SUPER_FEATURE_RO_COMPAT (sb)
- & EXT4_FEATURE_RO_COMPAT_DIR_NLINK)
- || (EXT2_SUPER_FEATURE_INCOMPAT (sb)
- & EXT4_FEATURE_INCOMPAT_EXTENTS)
- || (EXT2_SUPER_FEATURE_INCOMPAT (sb)
- & EXT4_FEATURE_INCOMPAT_64BIT));
- if (is_ext4)
- is_ext3 = 0;
- }
+ is_ext4 = ((EXT2_SUPER_FEATURE_RO_COMPAT (sb)
+ & EXT4_FEATURE_RO_COMPAT_HUGE_FILE)
+ || (EXT2_SUPER_FEATURE_RO_COMPAT (sb)
+ & EXT4_FEATURE_RO_COMPAT_DIR_NLINK)
+ || (EXT2_SUPER_FEATURE_INCOMPAT (sb)
+ & EXT4_FEATURE_INCOMPAT_EXTENTS)
+ || (EXT2_SUPER_FEATURE_INCOMPAT (sb)
+ & EXT4_FEATURE_INCOMPAT_64BIT));
if (expect_ext_ver == 2 && (is_ext3 || is_ext4))
return NULL;
- if (expect_ext_ver == 3 && !is_ext3)
+ if (expect_ext_ver == 3 && (!is_ext3 || is_ext4))
return NULL;
- else if (expect_ext_ver == 4 && !is_ext4)
+ if (expect_ext_ver == 4 && !is_ext4)
return NULL;
if (version > 0 && group_nr > 0) {
@@ -351,6 +348,18 @@ static PedFileSystemOps _ext3_ops = {
static PedFileSystemOps _ext4_ops = {
probe: _ext4_probe,
+#ifndef DISCOVER_ONLY
+ clobber: _ext2_clobber,
+ open: _ext2_open,
+ create: NULL,
+ close: _ext2_close,
+ check: _ext2_check,
+ resize: _ext2_resize,
+ copy: NULL,
+ get_create_constraint: _ext2_get_create_constraint,
+ get_copy_constraint: NULL,
+ get_resize_constraint: _ext2_get_resize_constraint
+#else /* !DISCOVER_ONLY */
clobber: NULL,
open: NULL,
create: NULL,
@@ -361,6 +370,7 @@ static PedFileSystemOps _ext4_ops = {
get_create_constraint: NULL,
get_copy_constraint: NULL,
get_resize_constraint: NULL
+#endif /* !DISCOVER_ONLY */
};
#define EXT23_BLOCK_SIZES ((int[6]){512, 1024, 2048, 4096, 8192, 0})
--
Colin Watson [cjwatson at ubuntu.com]
More information about the parted-devel
mailing list