Commit 1142d28b authored by Theodore Y. Ts'o's avatar Theodore Y. Ts'o Committed by Linus Torvalds

Ext2/3 forward compatibility: on-line resizing

This patch allows forward compatibility with future filesystems which
are dynamically grown by using an alternate algorithm for storing the
block group descriptors.  It's also a bit more efficient, in that it
uses just a little bit less disk space.  Currently, the ext2 filesystem
format requires either relocating the inode table, or reserving space in
before doing the on-line resize.  The new scheme, which is documented in
"Planned Extensions to the Ext2/3 Filesystem", by Stephen Tweedie and I 
(see: http://e2fsprogs.sourceforge.net/extensions-ext23)
parent 841d9227
...@@ -476,12 +476,29 @@ static loff_t ext2_max_size(int bits) ...@@ -476,12 +476,29 @@ static loff_t ext2_max_size(int bits)
return res; return res;
} }
static unsigned long descriptor_loc(struct super_block *sb,
unsigned long logic_sb_block,
int nr)
{
struct ext2_sb_info *sbi = EXT2_SB(sb);
unsigned long bg, first_data_block, first_meta_bg;
first_data_block = le32_to_cpu(sbi->s_es->s_first_data_block);
first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
if (!EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_META_BG) ||
nr < first_meta_bg)
return (logic_sb_block + nr + 1);
bg = sbi->s_desc_per_block * nr;
return (first_data_block + 1 + (bg * sbi->s_blocks_per_group));
}
static int ext2_fill_super(struct super_block *sb, void *data, int silent) static int ext2_fill_super(struct super_block *sb, void *data, int silent)
{ {
struct buffer_head * bh; struct buffer_head * bh;
struct ext2_sb_info * sbi; struct ext2_sb_info * sbi;
struct ext2_super_block * es; struct ext2_super_block * es;
unsigned long sb_block = 1; unsigned long block, sb_block = 1;
unsigned long logic_sb_block = get_sb_block(&data); unsigned long logic_sb_block = get_sb_block(&data);
unsigned long offset = 0; unsigned long offset = 0;
unsigned long def_mount_opts; unsigned long def_mount_opts;
...@@ -689,7 +706,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) ...@@ -689,7 +706,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
goto failed_mount; goto failed_mount;
} }
for (i = 0; i < db_count; i++) { for (i = 0; i < db_count; i++) {
sbi->s_group_desc[i] = sb_bread(sb, logic_sb_block + i + 1); block = descriptor_loc(sb, logic_sb_block, i);
sbi->s_group_desc[i] = sb_bread(sb, block);
if (!sbi->s_group_desc[i]) { if (!sbi->s_group_desc[i]) {
for (j = 0; j < i; j++) for (j = 0; j < i; j++)
brelse (sbi->s_group_desc[j]); brelse (sbi->s_group_desc[j]);
......
...@@ -929,6 +929,23 @@ static loff_t ext3_max_size(int bits) ...@@ -929,6 +929,23 @@ static loff_t ext3_max_size(int bits)
return res; return res;
} }
static unsigned long descriptor_loc(struct super_block *sb,
unsigned long logic_sb_block,
int nr)
{
struct ext3_sb_info *sbi = EXT3_SB(sb);
unsigned long bg, first_data_block, first_meta_bg;
first_data_block = le32_to_cpu(sbi->s_es->s_first_data_block);
first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_META_BG) ||
nr < first_meta_bg)
return (logic_sb_block + nr + 1);
bg = sbi->s_desc_per_block * nr;
return (first_data_block + 1 + (bg * sbi->s_blocks_per_group));
}
static int ext3_fill_super (struct super_block *sb, void *data, int silent) static int ext3_fill_super (struct super_block *sb, void *data, int silent)
{ {
...@@ -936,7 +953,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) ...@@ -936,7 +953,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
struct ext3_super_block *es = 0; struct ext3_super_block *es = 0;
struct ext3_sb_info *sbi; struct ext3_sb_info *sbi;
unsigned long sb_block = get_sb_block(&data); unsigned long sb_block = get_sb_block(&data);
unsigned long logic_sb_block = 1; unsigned long block, logic_sb_block = 1;
unsigned long offset = 0; unsigned long offset = 0;
unsigned long journal_inum = 0; unsigned long journal_inum = 0;
unsigned long def_mount_opts; unsigned long def_mount_opts;
...@@ -1154,7 +1171,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) ...@@ -1154,7 +1171,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
goto failed_mount; goto failed_mount;
} }
for (i = 0; i < db_count; i++) { for (i = 0; i < db_count; i++) {
sbi->s_group_desc[i] = sb_bread(sb, logic_sb_block + i + 1); block = descriptor_loc(sb, logic_sb_block, i);
sbi->s_group_desc[i] = sb_bread(sb, block);
if (!sbi->s_group_desc[i]) { if (!sbi->s_group_desc[i]) {
printk (KERN_ERR "EXT3-fs: " printk (KERN_ERR "EXT3-fs: "
"can't read group descriptor %d\n", i); "can't read group descriptor %d\n", i);
......
...@@ -422,7 +422,8 @@ struct ext2_super_block { ...@@ -422,7 +422,8 @@ struct ext2_super_block {
__u8 s_reserved_char_pad; __u8 s_reserved_char_pad;
__u16 s_reserved_word_pad; __u16 s_reserved_word_pad;
__u32 s_default_mount_opts; __u32 s_default_mount_opts;
__u32 s_reserved[191]; /* Padding to the end of the block */ __u32 s_first_meta_bg; /* First metablock block group */
__u32 s_reserved[190]; /* Padding to the end of the block */
}; };
/* /*
...@@ -485,10 +486,12 @@ struct ext2_super_block { ...@@ -485,10 +486,12 @@ struct ext2_super_block {
#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 #define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 #define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004
#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008
#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
#define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff #define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff
#define EXT2_FEATURE_COMPAT_SUPP 0 #define EXT2_FEATURE_COMPAT_SUPP 0
#define EXT2_FEATURE_INCOMPAT_SUPP EXT2_FEATURE_INCOMPAT_FILETYPE #define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
EXT2_FEATURE_INCOMPAT_META_BG)
#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ #define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
EXT2_FEATURE_RO_COMPAT_BTREE_DIR) EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
......
...@@ -450,7 +450,8 @@ struct ext3_super_block { ...@@ -450,7 +450,8 @@ struct ext3_super_block {
__u8 s_reserved_char_pad; __u8 s_reserved_char_pad;
__u16 s_reserved_word_pad; __u16 s_reserved_word_pad;
__u32 s_default_mount_opts; __u32 s_default_mount_opts;
__u32 s_reserved[191]; /* Padding to the end of the block */ __u32 s_first_meta_bg; /* First metablock block group */
__u32 s_reserved[190]; /* Padding to the end of the block */
}; };
#ifdef __KERNEL__ #ifdef __KERNEL__
...@@ -529,8 +530,11 @@ static inline struct ext3_inode_info *EXT3_I(struct inode *inode) ...@@ -529,8 +530,11 @@ static inline struct ext3_inode_info *EXT3_I(struct inode *inode)
#define EXT3_FEATURE_INCOMPAT_FILETYPE 0x0002 #define EXT3_FEATURE_INCOMPAT_FILETYPE 0x0002
#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ #define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */
#define EXT3_FEATURE_INCOMPAT_META_BG 0x0010
#define EXT3_FEATURE_COMPAT_SUPP 0 #define EXT3_FEATURE_COMPAT_SUPP 0
#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
EXT2_FEATURE_INCOMPAT_META_BG)
#define EXT3_FEATURE_INCOMPAT_SUPP (EXT3_FEATURE_INCOMPAT_FILETYPE| \ #define EXT3_FEATURE_INCOMPAT_SUPP (EXT3_FEATURE_INCOMPAT_FILETYPE| \
EXT3_FEATURE_INCOMPAT_RECOVER) EXT3_FEATURE_INCOMPAT_RECOVER)
#define EXT3_FEATURE_RO_COMPAT_SUPP (EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \ #define EXT3_FEATURE_RO_COMPAT_SUPP (EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment