Ext3
code review regarding 64bit block number
Author: Laurent Vivier <Laurent.Vivier@bull.net>
Status: Draft
Last Modification: 2005/06/20
Copyright (c) 2005 Bull S.A.
RED shows fields that
should be changed to
address 64bit block number.
ORANGE shows fields that
should be changed if
we want to count blocks on a 64bit value (for instance, number of
blocks in a partition)
GREEN
shows fields we should add.
1. ON-DISK structures
1.1.
include/linux/ext3_fs.h
1.1.1. SuperBlock
struct
ext3_super_block {
/*00*/
__le32
s_inodes_count;
/*
Inodes count */
__le32
s_blocks_count;
/*
Blocks count */
__le32
s_r_blocks_count;
/*
Reserved blocks count */
__le32 s_free_blocks_count; /*
Free blocks
count */
These
fields count the total number of block in a partition.
If partition is big enough to address block using 64bit values,
we can have a total number of block (a counter) on 64bit. |
/*10*/
__le32
s_free_inodes_count; /* Free inodes count
*/
__le32
s_first_data_block; /* First
Data Block */
| s_first_data_block
should remain __le32 : its value is ever 0
or 1. |
__le32
s_log_block_size;
/*
Block size */
__le32
s_log_frag_size;
/* Fragment size */
/*20*/
__le32
s_blocks_per_group; /* # Blocks
per group */
__le32
s_frags_per_group; /*
#
Fragments per group */
__le32
s_inodes_per_group; /* # Inodes
per group */
blocks,
frags and inodes per group
are limited by the bitmap size.
64bit counter should not
be needed. |
__le32
s_mtime;
/* Mount time */
/*30*/
__le32
s_wtime;
/* Write time */
__le16
s_mnt_count;
/* Mount count */
__le16
s_max_mnt_count;
/* Maximal mount count */
__le16
s_magic;
/* Magic signature */
__le16
s_state;
/* File system state */
__le16
s_errors;
/* Behaviour when detecting errors */
__le16
s_minor_rev_level; /*
minor
revision level */
/*40*/
__le32
s_lastcheck;
/* time of last check */
__le32
s_checkinterval;
/* max. time between checks */
__le32
s_creator_os;
/* OS */
__le32
s_rev_level;
/* Revision level */
/*50*/
__le16
s_def_resuid;
/* Default uid for reserved blocks */
__le16
s_def_resgid;
/* Default gid for reserved blocks */
__le32
s_first_ino;
/* First non-reserved inode */
__le16 s_inode_size;
/* size of
inode structure */
| See struct ext3_inode for
comment |
__le16
s_block_group_nr;
/*
block group # of this superblock */
Numbers of block in a
group is
8 x numbers_of_bits_in_a_block.
With
4096 bytes block, we can manage 32768 (215)
blocks in a
group,
and thus maximum size of a group is 32768 x 4096 = 128 MiB,
and
if the maximum number of blocks in a partition is 232
( = 16
TiB filesystem size with 4Ki block size), the needed number
of block
is 232/ 215
= 232-15
= 217
= 131072 groups.
If
we have a 64 bit disk, maximum number of groups is
264/ 215
= 264-15
= 249
|
__le32
s_feature_compat;
/*
compatible feature set */
/*60*/
__le32
s_feature_incompat; /*
incompatible feature set
*/
__le32 s_feature_ro_compat; /*
readonly-compatible feature set */
/*68*/
__u8
s_uuid[16];
/* 128-bit uuid for volume */
/*78*/
char
s_volume_name[16];
/* volume name */
/*88*/
char
s_last_mounted[64]; /*
directory where last mounted */
/*C8*/
__le32
s_algorithm_usage_bitmap; /* For compression */
__u8
s_prealloc_blocks;
/* Nr of blocks to try to preallocate*/
__u8 s_prealloc_dir_blocks; /*
Nr to
preallocate for dirs */
__u16 s_reserved_gdt_blocks; /* Per group
desc for
online growth */
/*D0*/
__u8
s_journal_uuid[16]; /*
uuid of journal superblock */
/*E0*/
__le32
s_journal_inum;
/*
inode number of journal file */
__le32
s_journal_dev;
/*
device number of journal file */
__le32
s_last_orphan;
/*
start of list of inodes to delete */
__le32
s_hash_seed[4];
/*
HTREE hash seed */
__u8
s_def_hash_version; /*
Default hash version to use */
__u8 s_reserved_char_pad;
__u16 s_reserved_word_pad;
__le32 s_default_mount_opts;
__le32
s_first_meta_bg;
/* First metablock block group */
/*FC*/
__u32
s_reserved[190];
/* Padding
to the end of the block */
};
should become:
struct
ext3_super_block {
/*00*/
__le32
s_inodes_count;
/*
Inodes count */
__le32
s_blocks_count;
/*
Blocks count */
__le32
s_r_blocks_count;
/*
Reserved blocks count */
__le32 s_free_blocks_count; /*
Free blocks
count */
/*10*/
__le32 s_free_inodes_count; /*
Free inodes
count */
__le32
s_first_data_block; /* First
Data
Block */
__le32
s_log_block_size;
/*
Block size */
__le32
s_log_frag_size;
/* Fragment size */
/*20*/
__le32
s_blocks_per_group; /* # Blocks
per group */
__le32
s_frags_per_group; /*
#
Fragments per group */
__le32
s_inodes_per_group; /* # Inodes
per group */
__le32
s_mtime;
/* Mount time */
/*30*/
__le32
s_wtime;
/* Write time */
__le16
s_mnt_count;
/* Mount count */
__le16
s_max_mnt_count;
/* Maximal mount count */
__le16
s_magic;
/* Magic signature */
__le16
s_state;
/* File system state */
__le16
s_errors;
/* Behaviour when detecting errors */
__le16
s_minor_rev_level; /*
minor
revision level */
/*40*/
__le32
s_lastcheck;
/* time of last check */
__le32
s_checkinterval;
/* max. time between checks */
__le32
s_creator_os;
/* OS */
__le32
s_rev_level;
/* Revision level */
/*50*/
__le16
s_def_resuid;
/* Default uid for reserved blocks */
__le16
s_def_resgid;
/* Default gid for reserved blocks */
__le32
s_first_ino;
/* First non-reserved inode */
__le16
s_inode_size;
/*
size of inode structure */
__le16
s_block_group_nr;
/*
block group # of this superblock */
__le32
s_feature_compat;
/*
compatible feature set */
/*60*/
__le32
s_feature_incompat; /*
incompatible feature set
*/
__le32 s_feature_ro_compat; /*
readonly-compatible feature set */
/*68*/
__u8
s_uuid[16];
/* 128-bit uuid for volume */
/*78*/
char
s_volume_name[16];
/* volume name */
/*88*/
char
s_last_mounted[64]; /*
directory where last mounted */
/*C8*/
__le32
s_algorithm_usage_bitmap; /* For compression */
__u8
s_prealloc_blocks;
/* Nr of blocks to try to preallocate*/
__u8 s_prealloc_dir_blocks; /*
Nr to
preallocate for dirs */
__u16 s_reserved_gdt_blocks; /* Per group
desc for
online growth */
/*D0*/
__u8
s_journal_uuid[16]; /*
uuid of journal superblock */
/*E0*/
__le32
s_journal_inum;
/*
inode number of journal file */
__le32
s_journal_dev;
/*
device number of journal file */
__le32
s_last_orphan;
/*
start of list of inodes to delete */
__le32
s_hash_seed[4];
/*
HTREE hash seed */
/*F0*/
__u8
s_def_hash_version; /*
Default hash version to use */
__u8 s_reserved_char_pad;
__u16 s_reserved_word_pad;
__le32 s_default_mount_opts;
__le32
s_first_meta_bg;
/* First metablock block group */
/*FC*/
__le32
s_hi_blocks_count;
/*
Blocks count */
__le32
s_hi_r_blocks_count;
/* Reserved blocks count */
__le32 s_hi_free_blocks_count;
/* Free blocks
count */
__le32
s_hi_block_group_nr;
/*
block group # of this superblock */
/*10C*/
__u32
s_reserved[180];
/* Padding
to the end of the block */
};
If we want to reduce structure size, we could let s_block_group_nr to le16 as it seems it is only
used for debug purpose.
1.1.2. Group Descriptor
struct
ext3_group_desc
{
__le32
bg_block_bitmap;
/* Blocks bitmap block */
__le32
bg_inode_bitmap;
/* Inodes bitmap block */
__le32
bg_inode_table;
/*
Inodes table block */
__le16 bg_free_blocks_count; /* Free
blocks count */
__le16 bg_free_inodes_count; /* Free
inodes count */
__le16
bg_used_dirs_count; /*
Directories
count */
__u16 bg_pad;
__le32 bg_reserved[3];
};
should become:
struct
ext3_group_desc
{
__le32
bg_block_bitmap;
/* Blocks bitmap block */
__le32
bg_inode_bitmap;
/* Inodes bitmap block */
__le32
bg_inode_table;
/*
Inodes table block */
__le16 bg_free_blocks_count; /* Free
blocks count */
__le16 bg_free_inodes_count; /* Free
inodes count */
__le16
bg_used_dirs_count; /*
Directories
count */
__u16 bg_pad;
__le32
bg_hi_block_bitmap; /* Blocks
bitmap block */
__le32
bg_hi_inode_bitmap; /* Inodes
bitmap block */
__le32
bg_hi_inode_table; /*
Inodes
table block */
};
If we don't want to store high bits for all these fields, we can use a
relative addressing mode to the group base address.
For instance, if bg_block_bitmap
is lesser than the base address of the group, we add the base address
to this 32bit value.
And according to Andreas Dilger, we should swap to the METABG layout:
"A quick calculation shows
that the group descriptor table itself
will become too large to store in the first group before the filesystem
grows to 512TB:
<2^15 blocks/group * 2^12 bytes/block / 32 bytes/gdt <
2^22 gdt/group
2^15 blocks/group * 2^12 bytes/block * 2^22 group = 2^49 bytes = 512TB
This means at or before 512TB we will have to go to the METABG layout
to store the group descriptors in their respective groups, so we may
as well do this at 16TB and just do as you propose.
"
1.1.3. Inode
struct ext3_inode {
/*00*/
__le16
i_mode;
/* File mode */
__le16
i_uid;
/* Low 16
bits of Owner Uid */
__le32
i_size;
/* Size in
bytes */
__le32
i_atime;
/* Access time */
__le32
i_ctime;
/* Creation time */
/*10*/
__le32
i_mtime;
/* Modification time
*/
__le32
i_dtime;
/* Deletion Time */
__le16
i_gid;
/* Low 16
bits of Group Id */
__le16
i_links_count; /* Links count */
__le32
i_blocks;
/* Blocks count */
/*20*/
__le32
i_flags;
/* File flags */
union {
struct {
__u32 l_i_reserved1;
} linux1;
struct {
__u32 h_i_translator;
} hurd1;
struct {
__u32 m_i_reserved1;
} masix1;
}
osd1;
/* OS dependent 1 */
/*28*/
__le32
i_block[EXT3_N_BLOCKS];/*
Pointers to blocks */
/*64*/
__le32
i_generation; /* File version (for NFS) */
__le32
i_file_acl; /* File ACL */
__le32
i_dir_acl; /*
Directory ACL */
i_size
and i_dir_acl are used to
define a 64bit i_size
(in fs/ext3/inode.c, ext3_read_inode()) |
/*70*/
__le32
i_faddr;
/* Fragment address
*/
| This fields (and
following) seems not
used in linux. |
union {
struct {
__u8
l_i_frag;
/*
Fragment number */
__u8
l_i_fsize; /*
Fragment size */
__u16 i_pad1;
__le16 l_i_uid_high; /* these 2
fields */
__le16 l_i_gid_high; /* were reserved2[0]
*/
__u32 l_i_reserved2;
} linux2;
struct {
__u8
h_i_frag;
/*
Fragment number */
__u8
h_i_fsize; /*
Fragment size */
__u16 h_i_mode_high;
__u16 h_i_uid_high;
__u16 h_i_gid_high;
__u32 h_i_author;
} hurd2;
struct {
__u8
m_i_frag;
/*
Fragment number */
__u8
m_i_fsize; /*
Fragment size */
__u16 m_pad1;
__u32 m_i_reserved2[2];
} masix2;
}
osd2;
/* OS dependent 2 */
/*80*/
__le16 i_extra_isize;
__le16 i_pad1;
/*84*/};
WE SHOULD USE DYNAMIC INODE
SIZE TO STORE 64BIT BLOCK NUMBER
(i_extra_size)
or
SHOULD BE BASED ON EXTENTS
PATCH (use 48bit block number)
struct
ext3_inode {
/*00*/
__le16
i_mode;
/* File mode */
__le16
i_uid;
/* Low 16
bits of Owner Uid */
__le32
i_size;
/* Size in
bytes */
__le32
i_atime;
/* Access time */
__le32
i_ctime;
/* Creation time */
/*10*/
__le32
i_mtime;
/* Modification time
*/
__le32
i_dtime;
/* Deletion Time */
__le16
i_gid;
/* Low 16
bits of Group Id */
__le16
i_links_count; /* Links count */
__le32
i_blocks;
/* Blocks count */
/*20*/
__le32
i_flags;
/* File flags */
union {
struct {
__u32 l_i_reserved1;
} linux1;
struct {
__u32 h_i_translator;
} hurd1;
struct {
__u32 m_i_reserved1;
} masix1;
}
osd1;
/* OS dependent 1 */
/*28*/
__le32
i_block[EXT3_N_BLOCKS];/*
Pointers to blocks */
/*64*/
__le32
i_generation; /* File version (for NFS) */
__le32
i_file_acl; /* File ACL */
__le32
i_dir_acl; /*
Directory ACL */
/*70*/
__le32
i_faddr;
/* Fragment address
*/
union {
struct {
__u8
l_i_frag;
/*
Fragment number */
__u8
l_i_fsize; /*
Fragment size */
__u16 i_pad1;
__le16 l_i_uid_high; /* these 2
fields */
__le16 l_i_gid_high; /* were reserved2[0]
*/
__u32 l_i_reserved2;
} linux2;
struct {
__u8
h_i_frag;
/*
Fragment number */
__u8
h_i_fsize; /*
Fragment size */
__u16 h_i_mode_high;
__u16 h_i_uid_high;
__u16 h_i_gid_high;
__u32 h_i_author;
} hurd2;
struct {
__u8
m_i_frag;
/*
Fragment number */
__u8
m_i_fsize; /*
Fragment size */
__u16 m_pad1;
__u32 m_i_reserved2[2];
} masix2;
}
osd2;
/* OS dependent 2 */
/*80*/
__le16 i_extra_isize;
__le16 i_pad1;
/*84*/
__le32
i_hi_blocks;
/* Blocks count */
__le32 i_hi_block[EXT3_N_BLOCKS];/*
Pointers to blocks */
/*C0*/};
could impact superblock s_inode_size
field.
If we use extents patch, we don't need to increase inode size:
- block extend pointers are
stored in original i_block
space
- i_blocks (64) can be stored
in i_blocks
(32) and i_faddr (32)
or l_i_frag
(8) and l_i_fsize
(8)
1.1.4. New Group
struct ext3_new_group_input {
__u32
group;
/* Group number for this data */
__u32 block_bitmap; /* Absolute
block number of
block bitmap */
__u32 inode_bitmap; /* Absolute
block number of
inode bitmap */
__u32 inode_table; /*
Absolute block
number of inode table start */
__u32
blocks_count; /* Total number
of blocks in this
group */
__u16 reserved_blocks;
/* Number of reserved blocks in this group */
__u16 unused;
};
struct
ext3_new_group_data {
__u32 group;
__u32 block_bitmap;
__u32 inode_bitmap;
__u32 inode_table;
__u32 blocks_count;
__u16 reserved_blocks;
__u16 unused;
__u32 free_blocks_count;
};
As a size of a group is limited by the size of the bitmap block,
blocks_count and free_blocks_count
can stay a __u32.
These structures are used in an ioctl(), the best solution to keep
compatibility is to define new 64bit structure and new ioctl() calls.
struct
ext3_new_group_input64 {
__u32
group;
/* Group number for this data */
__u64 block_bitmap; /* Absolute
block number of
block bitmap */
__u64 inode_bitmap; /* Absolute
block number of
inode bitmap */
__u64 inode_table; /*
Absolute block
number of inode table start */
__u32
blocks_count; /* Total number
of blocks in this
group */
__u16 reserved_blocks;
/* Number of reserved blocks in this group */
__u16 unused;
};
struct
ext3_new_group_data64 {
__u32 group;
__u64 block_bitmap;
__u64 inode_bitmap;
__u64 inode_table;
__u32 blocks_count;
__u16 reserved_blocks;
__u16 unused;
__u32 free_blocks_count;
};
and we should define a new
iocl command:
#define EXT3_IOC_GROUP_ADD64
_IOW('f', 9,struct ext3_new_group_input64)
2. IN-MEMORY structures
2.1.
include/linux/ext3_fs_i.h
struct
ext3_reserve_window
{
__u32
_rsv_start; /* First byte
reserved */
__u32
_rsv_end;
/* Last byte reserved or
0 */
};
struct
ext3_inode_info {
__le32
i_data[15]; /* unconverted */
__u32 i_flags;
#ifdef
EXT3_FRAGMENTS
__u32
i_faddr;
__u8
i_frag_no;
__u8
i_frag_size;
#endif
__u32 i_file_acl;
__u32 i_dir_acl;
__u32 i_dtime;
__u32
i_block_group;
__u32
i_state;
/* Dynamic state flags for ext3 */
__u32
i_next_alloc_block;
__u32 i_next_alloc_goal;
struct
ext3_reserve_window_node i_rsv_window;
| Size of
i_rsv_window changes according to ext3_reserve_window node |
__u32
i_dir_start_lookup;
#ifdef
CONFIG_EXT3_FS_XATTR
struct rw_semaphore
xattr_sem;
#endif
#ifdef
CONFIG_EXT3_FS_POSIX_ACL
struct
posix_acl
*i_acl;
struct
posix_acl
*i_default_acl;
#endif
struct list_head
i_orphan; /* unlinked
but open inodes */
loff_t i_disksize;
/* on-disk additional length
*/
__u16 i_extra_isize;
struct semaphore
truncate_sem;
struct inode vfs_inode;
};
should become
struct
ext3_reserve_window
{
sector_t
_rsv_start; /* First byte
reserved */
sector_t
_rsv_end;
/* Last byte reserved or
0 */
};
struct
ext3_inode_info {
__le32
i_data[15]; /* unconverted */
__u32 i_flags;
#ifdef
EXT3_FRAGMENTS
sector_t
i_faddr;
__u8
i_frag_no;
__u8
i_frag_size;
#endif
__u32 i_file_acl;
__u32 i_dir_acl;
__u32 i_dtime;
group_t
i_block_group;
__u32
i_state;
/* Dynamic state flags for ext3 */
sector_t
i_next_alloc_block;
sector_t
i_next_alloc_goal;
struct
ext3_reserve_window_node i_rsv_window;
__u32
i_dir_start_lookup;
#ifdef
CONFIG_EXT3_FS_XATTR
struct rw_semaphore
xattr_sem;
#endif
#ifdef
CONFIG_EXT3_FS_POSIX_ACL
struct
posix_acl
*i_acl;
struct
posix_acl
*i_default_acl;
#endif
struct list_head
i_orphan; /* unlinked
but open inodes */
loff_t i_disksize;
/* on-disk additional length
*/
__u16 i_extra_isize;
struct semaphore
truncate_sem;
struct inode vfs_inode;
};
2.2.
include/linux/ext3_fs_sb.h
struct
ext3_sb_info {
unsigned long
s_frag_size; /* Size
of a
fragment in bytes */
unsigned long s_frags_per_block;/* Number of fragments per block */
unsigned long s_inodes_per_block;/* Number of inodes per block */
unsigned long s_frags_per_group;/* Number of fragments in a group */
unsigned long s_blocks_per_group;/* Number of blocks in a group */
unsigned long s_inodes_per_group;/* Number of inodes in a group */
unsigned long s_itb_per_group; /* Number of inode table
blocks
per group */
unsigned long
s_gdb_count; /*
Number of
group descriptor blocks */
unsigned long s_desc_per_block; /* Number of group descriptors per
block */
unsigned long s_groups_count; /* Number of groups
in the fs
*/
struct buffer_head * s_sbh; /*
Buffer
containing the super block */
struct ext3_super_block * s_es; /* Pointer to the super block in the
buffer */
struct buffer_head ** s_group_desc;
unsigned long s_mount_opt;
uid_t s_resuid;
gid_t s_resgid;
unsigned short s_mount_state;
unsigned short s_pad;
int s_addr_per_block_bits;
int s_desc_per_block_bits;
int s_inode_size;
int s_first_ino;
spinlock_t s_next_gen_lock;
u32 s_next_generation;
u32 s_hash_seed[4];
int s_def_hash_version;
struct percpu_counter s_freeblocks_counter;
struct percpu_counter s_freeinodes_counter;
struct percpu_counter s_dirs_counter;
should
manage sector_t type.
struct blockgroup_lock s_blockgroup_lock;
/* root of the per fs reservation window tree */
spinlock_t s_rsv_window_lock;
struct rb_root s_rsv_window_root;
struct ext3_reserve_window_node s_rsv_window_head;
/* Journaling */
struct inode * s_journal_inode;
struct journal_s * s_journal;
struct list_head s_orphan;
unsigned long s_commit_interval;
struct block_device *journal_bdev;
#ifdef
CONFIG_JBD_DEBUG
struct timer_list
turn_ro_timer;
/* For turning
read-only (crash
simulation)
*/
wait_queue_head_t
ro_wait_queue;
/* For people
waiting for the fs to go read-only */
#endif
#ifdef
CONFIG_QUOTA
char
*s_qf_names[MAXQUOTAS];
/* Names of quota files with journalled quota */
int
s_jquota_fmt;
/* Format of quota to use */
#endif
};
should
become
struct
ext3_sb_info {
unsigned long
s_frag_size; /* Size
of a
fragment in bytes */
unsigned long s_frags_per_block;/* Number of fragments per block */
unsigned long s_inodes_per_block;/* Number of inodes per block */
unsigned long s_frags_per_group;/* Number of fragments in a group */
unsigned long s_blocks_per_group;/* Number of blocks in a group */
unsigned long s_inodes_per_group;/* Number of inodes in a group */
unsigned long s_itb_per_group; /* Number of inode table
blocks
per group */
unsigned long
s_gdb_count; /*
Number of
group descriptor blocks */
unsigned long s_desc_per_block; /* Number of group descriptors per
block */
group_t
s_groups_count; /* Number of groups
in the fs
*/
struct buffer_head * s_sbh; /*
Buffer
containing the super block */
struct ext3_super_block * s_es; /* Pointer to the super block in the
buffer */
struct buffer_head ** s_group_desc;
unsigned long s_mount_opt;
uid_t s_resuid;
gid_t s_resgid;
unsigned short s_mount_state;
unsigned short s_pad;
int s_addr_per_block_bits;
int s_desc_per_block_bits;
int s_inode_size;
int s_first_ino;
spinlock_t s_next_gen_lock;
u32 s_next_generation;
u32 s_hash_seed[4];
int s_def_hash_version;
struct percpu_counter s_freeblocks_counter;
struct percpu_counter s_freeinodes_counter;
struct percpu_counter s_dirs_counter;
struct blockgroup_lock s_blockgroup_lock;
/* root of the per fs reservation window tree */
spinlock_t s_rsv_window_lock;
struct rb_root s_rsv_window_root;
struct ext3_reserve_window_node s_rsv_window_head;
/* Journaling */
struct inode * s_journal_inode;
struct journal_s * s_journal;
struct list_head s_orphan;
unsigned long s_commit_interval;
struct block_device *journal_bdev;
#ifdef
CONFIG_JBD_DEBUG
struct timer_list
turn_ro_timer;
/* For turning
read-only (crash simulation)
*/
wait_queue_head_t
ro_wait_queue;
/* For people
waiting for the fs to go read-only */
#endif
#ifdef
CONFIG_QUOTA
char
*s_qf_names[MAXQUOTAS];
/* Names of quota files with journalled quota */
int
s_jquota_fmt;
/* Format of quota to use */
#endif
};
2.3.
include/linux/percpu_counter.h
Add a 64bit compatible version of "percpu_counter".
#ifdef
CONFIG_SMP
struct
percpu_counter {
spinlock_t lock;
long
count;
long
*counters;
};
...
#else
...
struct
percpu_counter {
long
count;
};
should become
#ifdef
CONFIG_SMP
struct
percpu_counter {
spinlock_t lock;
#ifdef CONFIG_LBD
long
long count;
long
long *counters;
#else
long count;
long *counters;
#endif
};
...
#else
...
struct
percpu_counter {
#ifdef CONFIG_LBD
long
long count;
#else
long count;
#endif
};
3. Functions
3.1. Helpers
We use some functions inspired by JBD 64bit support patch by Zach Brown in "jbd and 64 bit block numbers"
at http://sourceforge.net/mailarchive/message.php?msg_id=9996513
void
ext3_write_split_le64(struct super_block * sb, __le32 *hi, __le32
*lo, u64 val)
{
*low =
cpu_to_le32(val & (u32)~0);
if
(EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_64BIT))
*high =
cpu_to_le32(val >> 32);
}
u64
ext3_read_split_le64(struct
super_block * sb, __le32 *hi, __le32 *lo)
{
u64 ret = le32_to_cpu(*low);
if
(EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_64BIT))
ret |=
(u64)le32_to_cpu(*high) << 32;
return ret;
} |
We use "sector_t" as defined in "include/asm-<arch>/types.h". It should be "u64" if "CONFIG_LBD" is defined,
"unsigned long" otherwise (see "include/linux/types.h").
We should define "group_t" to count the number of groups (see 1.1.1.), based on "CONFIG_LBD" too.
3.2. fs/ext3/acl.c
N/A
3.3. fs/ext3/acl.h
N/A
3.4. fs/ext3/balloc.c
3.4.1. ext3_get_group_desc()
block_group,
group_desc
and desc
are group numbers and thus should become "group_t".
struct
ext3_group_desc * ext3_get_group_desc(struct super_block * sb,
unsigned
int block_group,
struct buffer_head ** bh)
{
unsigned
long group_desc;
unsigned
long desc;
struct ext3_group_desc * gdp;
if (block_group >= EXT3_SB(sb)->s_groups_count) {
ext3_error (sb, "ext3_get_group_desc",
"block_group >= groups_count - "
"block_group = %d,
groups_count = %lu",
block_group, EXT3_SB(sb)->s_groups_count);
...
ext3_error (sb, "ext3_get_group_desc",
"Group descriptor not loaded - "
"block_group = %d,
group_desc = %lu,
desc = %lu",
block_group, group_desc, desc);
...
|
should become
struct ext3_group_desc *
ext3_get_group_desc(struct super_block * sb,
group_t
block_group,
struct buffer_head ** bh)
{
group_t
group_desc;
group_t
desc;
struct ext3_group_desc * gdp;
if (block_group >= EXT3_SB(sb)->s_groups_count) {
ext3_error (sb, "ext3_get_group_desc",
"block_group >= groups_count - "
"block_group = %lld,
groups_count = %llu",
(unsigned
long long)block_group,
(unsigned
long long)EXT3_SB(sb)->s_groups_count);
...
ext3_error (sb, "ext3_get_group_desc",
"Group descriptor not loaded - "
"block_group = %lld,
group_desc = %llu,
desc = %llu",
(unsigned
long long)block_group,
(unsigned
long long)group_desc,
(unsigned
long long)desc);
... |
3.4.1. read_block_bitmap()
block_group
is a block group number (group_t)
and bg_block_bitmap
is a sector number (sector_t).
static struct
buffer_head *
read_block_bitmap(struct
super_block *sb, unsigned int
block_group)
...
bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap));
if (!bh)
ext3_error (sb, "read_block_bitmap",
"Cannot read block bitmap - "
"block_group = %d,
block_bitmap = %u",
block_group, le32_to_cpu(desc->bg_block_bitmap)); |
should become
static struct
buffer_head *
read_block_bitmap(struct
super_block *sb, group_t
block_group)
...
bh = sb_bread(sb, ext3_read_split_le64(sb,
desc->bg_hi_block_bitmap,
desc->bg_block_bitmap));
if (!bh)
ext3_error (sb, "read_block_bitmap",
"Cannot read block bitmap - "
"block_group = %lld,
block_bitmap = %llu",
(unsigned
long long)block_group,
ext3_read_split_le64(sb,
desc->bg_hi_block_bitmap,
desc->bg_block_bitmap)); |