X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=lwext4%2Fext4_types.h;h=41cb33f215fea2bdc2402cbbfd3bb4be84f11c37;hb=809b27e9dcf7f7120b98b03b13ceb624302e8183;hp=89b9d22fca5f1eb03eae3cba0ab52252db16a450;hpb=7d87ccf68ce97eeedab27f963e832ce4377c098d;p=lwext4.git diff --git a/lwext4/ext4_types.h b/lwext4/ext4_types.h index 89b9d22..41cb33f 100644 --- a/lwext4/ext4_types.h +++ b/lwext4/ext4_types.h @@ -42,12 +42,23 @@ #ifndef EXT4_TYPES_H_ #define EXT4_TYPES_H_ +#ifdef __cplusplus +extern "C" { +#endif + #include "ext4_config.h" #include "ext4_blockdev.h" -#include "tree.h" +#include "misc/tree.h" +#include #include +#define EXT4_CHECKSUM_CRC32C 1 + +#define UUID_SIZE 16 + +#pragma pack(push, 1) + /* * Structure of the super block */ @@ -85,7 +96,7 @@ struct ext4_sblock { uint32_t features_compatible; /* Compatible feature set */ uint32_t features_incompatible; /* Incompatible feature set */ uint32_t features_read_only; /* Readonly-compatible feature set */ - uint8_t uuid[16]; /* 128-bit uuid for volume */ + uint8_t uuid[UUID_SIZE]; /* 128-bit uuid for volume */ char volume_name[16]; /* Volume name */ char last_mounted[64]; /* Directory where last mounted */ uint32_t algorithm_usage_bitmap; /* For compression */ @@ -101,7 +112,7 @@ struct ext4_sblock { /* * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set. */ - uint8_t journal_uuid[16]; /* UUID of journal superblock */ + uint8_t journal_uuid[UUID_SIZE]; /* UUID of journal superblock */ uint32_t journal_inode_number; /* Inode number of journal file */ uint32_t journal_dev; /* Device number of journal file */ uint32_t last_orphan; /* Head of list of inodes to delete */ @@ -126,7 +137,7 @@ struct ext4_sblock { uint64_t mmp_block; /* Block for multi-mount protection */ uint32_t raid_stripe_width; /* Blocks on all data disks (N * stride) */ uint8_t log_groups_per_flex; /* FLEX_BG group size */ - uint8_t reserved_char_pad; + uint8_t checksum_type; uint16_t reserved_pad; uint64_t kbytes_written; /* Number of lifetime kilobytes written */ uint32_t snapshot_inum; /* I-node number of active snapshot */ @@ -149,8 +160,18 @@ struct ext4_sblock { uint64_t last_error_block; /* Block involved of last error */ uint8_t last_error_func[32]; /* Function where the error happened */ uint8_t mount_opts[64]; - uint32_t padding[112]; /* Padding to the end of the block */ -} __attribute__((packed)); + uint32_t usr_quota_inum; /* inode for tracking user quota */ + uint32_t grp_quota_inum; /* inode for tracking group quota */ + uint32_t overhead_clusters; /* overhead blocks/clusters in fs */ + uint32_t backup_bgs[2]; /* groups with sparse_super2 SBs */ + uint8_t encrypt_algos[4]; /* Encryption algorithms in use */ + uint8_t encrypt_pw_salt[16]; /* Salt used for string2key algorithm */ + uint32_t lpf_ino; /* Location of the lost+found inode */ + uint32_t padding[100]; /* Padding to the end of the block */ + uint32_t checksum; /* crc32c(superblock) */ +}; + +#pragma pack(pop) #define EXT4_SUPERBLOCK_MAGIC 0xEF53 #define EXT4_SUPERBLOCK_SIZE 1024 @@ -183,104 +204,102 @@ struct ext4_sblock { /* * Compatible features */ -#define EXT4_FEATURE_COMPAT_DIR_PREALLOC 0x0001 -#define EXT4_FEATURE_COMPAT_IMAGIC_INODES 0x0002 -#define EXT4_FEATURE_COMPAT_HAS_JOURNAL 0x0004 -#define EXT4_FEATURE_COMPAT_EXT_ATTR 0x0008 -#define EXT4_FEATURE_COMPAT_RESIZE_INODE 0x0010 -#define EXT4_FEATURE_COMPAT_DIR_INDEX 0x0020 +#define EXT4_FCOM_DIR_PREALLOC 0x0001 +#define EXT4_FCOM_IMAGIC_INODES 0x0002 +#define EXT4_FCOM_HAS_JOURNAL 0x0004 +#define EXT4_FCOM_EXT_ATTR 0x0008 +#define EXT4_FCOM_RESIZE_INODE 0x0010 +#define EXT4_FCOM_DIR_INDEX 0x0020 /* * Read-only compatible features */ -#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 -#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 -#define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 -#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008 -#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010 -#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020 -#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040 -#define EXT4_FEATURE_RO_COMPAT_QUOTA 0x0100 -#define EXT4_FEATURE_RO_COMPAT_BIGALLOC 0x0200 -#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM 0x0400 +#define EXT4_FRO_COM_SPARSE_SUPER 0x0001 +#define EXT4_FRO_COM_LARGE_FILE 0x0002 +#define EXT4_FRO_COM_BTREE_DIR 0x0004 +#define EXT4_FRO_COM_HUGE_FILE 0x0008 +#define EXT4_FRO_COM_GDT_CSUM 0x0010 +#define EXT4_FRO_COM_DIR_NLINK 0x0020 +#define EXT4_FRO_COM_EXTRA_ISIZE 0x0040 +#define EXT4_FRO_COM_QUOTA 0x0100 +#define EXT4_FRO_COM_BIGALLOC 0x0200 +#define EXT4_FRO_COM_METADATA_CSUM 0x0400 /* * Incompatible features */ -#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001 -#define EXT4_FEATURE_INCOMPAT_FILETYPE 0x0002 -#define EXT4_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ -#define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ -#define EXT4_FEATURE_INCOMPAT_META_BG 0x0010 -#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */ -#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 -#define EXT4_FEATURE_INCOMPAT_MMP 0x0100 -#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 -#define EXT4_FEATURE_INCOMPAT_EA_INODE 0x0400 /* EA in inode */ -#define EXT4_FEATURE_INCOMPAT_DIRDATA 0x1000 /* data in dirent */ -#define EXT4_FEATURE_INCOMPAT_BG_USE_META_CSUM 0x2000 /* use crc32c for bg */ -#define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */ -#define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x8000 /* data in inode */ +#define EXT4_FINCOM_COMPRESSION 0x0001 +#define EXT4_FINCOM_FILETYPE 0x0002 +#define EXT4_FINCOM_RECOVER 0x0004 /* Needs recovery */ +#define EXT4_FINCOM_JOURNAL_DEV 0x0008 /* Journal device */ +#define EXT4_FINCOM_META_BG 0x0010 +#define EXT4_FINCOM_EXTENTS 0x0040 /* extents support */ +#define EXT4_FINCOM_64BIT 0x0080 +#define EXT4_FINCOM_MMP 0x0100 +#define EXT4_FINCOM_FLEX_BG 0x0200 +#define EXT4_FINCOM_EA_INODE 0x0400 /* EA in inode */ +#define EXT4_FINCOM_DIRDATA 0x1000 /* data in dirent */ +#define EXT4_FINCOM_BG_USE_META_CSUM 0x2000 /* use crc32c for bg */ +#define EXT4_FINCOM_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */ +#define EXT4_FINCOM_INLINE_DATA 0x8000 /* data in inode */ /* * EXT2 supported feature set */ -#define EXT2_FEATURE_COMPAT_SUPP 0x0000 +#define EXT2_SUPPORTED_FCOM 0x0000 -#define EXT2_FEATURE_INCOMPAT_SUPP \ - (EXT4_FEATURE_INCOMPAT_FILETYPE | EXT4_FEATURE_INCOMPAT_META_BG) +#define EXT2_SUPPORTED_FINCOM \ + (EXT4_FINCOM_FILETYPE | EXT4_FINCOM_META_BG) -#define EXT2_FEATURE_RO_COMPAT_SUPP \ - (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER | \ - EXT4_FEATURE_RO_COMPAT_LARGE_FILE | EXT4_FEATURE_RO_COMPAT_BTREE_DIR) +#define EXT2_SUPPORTED_FRO_COM \ + (EXT4_FRO_COM_SPARSE_SUPER | \ + EXT4_FRO_COM_LARGE_FILE) /* * EXT3 supported feature set */ -#define EXT3_FEATURE_COMPAT_SUPP (EXT4_FEATURE_COMPAT_DIR_INDEX) +#define EXT3_SUPPORTED_FCOM (EXT4_FCOM_DIR_INDEX) -#define EXT3_FEATURE_INCOMPAT_SUPP \ - (EXT4_FEATURE_INCOMPAT_FILETYPE | EXT4_FEATURE_INCOMPAT_META_BG) +#define EXT3_SUPPORTED_FINCOM \ + (EXT4_FINCOM_FILETYPE | EXT4_FINCOM_META_BG) -#define EXT3_FEATURE_RO_COMPAT_SUPP \ - (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER | \ - EXT4_FEATURE_RO_COMPAT_LARGE_FILE | EXT4_FEATURE_RO_COMPAT_BTREE_DIR) +#define EXT3_SUPPORTED_FRO_COM \ + (EXT4_FRO_COM_SPARSE_SUPER | EXT4_FRO_COM_LARGE_FILE) /* * EXT4 supported feature set */ -#define EXT4_FEATURE_COMPAT_SUPP (EXT4_FEATURE_COMPAT_DIR_INDEX) +#define EXT4_SUPPORTED_FCOM (EXT4_FCOM_DIR_INDEX) -#define EXT4_FEATURE_INCOMPAT_SUPP \ - (EXT4_FEATURE_INCOMPAT_FILETYPE | EXT4_FEATURE_INCOMPAT_META_BG | \ - EXT4_FEATURE_INCOMPAT_EXTENTS | EXT4_FEATURE_INCOMPAT_FLEX_BG | \ - EXT4_FEATURE_INCOMPAT_64BIT) +#define EXT4_SUPPORTED_FINCOM \ + (EXT4_FINCOM_FILETYPE | EXT4_FINCOM_META_BG | \ + EXT4_FINCOM_EXTENTS | EXT4_FINCOM_FLEX_BG | \ + EXT4_FINCOM_64BIT) -#define EXT4_FEATURE_RO_COMPAT_SUPP \ - (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER | \ - EXT4_FEATURE_RO_COMPAT_LARGE_FILE | EXT4_FEATURE_RO_COMPAT_GDT_CSUM | \ - EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \ - EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \ - EXT4_FEATURE_RO_COMPAT_BTREE_DIR | EXT4_FEATURE_RO_COMPAT_HUGE_FILE) +#define EXT4_SUPPORTED_FRO_COM \ + (EXT4_FRO_COM_SPARSE_SUPER | \ + EXT4_FRO_COM_METADATA_CSUM | \ + EXT4_FRO_COM_LARGE_FILE | EXT4_FRO_COM_GDT_CSUM | \ + EXT4_FRO_COM_DIR_NLINK | \ + EXT4_FRO_COM_EXTRA_ISIZE | EXT4_FRO_COM_HUGE_FILE) /*Ignored features: * RECOVER - journaling in lwext4 is not supported * (probably won't be ever...) * MMP - multi-mout protection (impossible scenario) * */ -#define FEATURE_INCOMPAT_IGNORED \ - EXT4_FEATURE_INCOMPAT_RECOVER | EXT4_FEATURE_INCOMPAT_MMP +#define EXT_FINCOM_IGNORED \ + EXT4_FINCOM_RECOVER | EXT4_FINCOM_MMP #if 0 /*TODO: Features incompatible to implement*/ -#define EXT4_FEATURE_INCOMPAT_SUPP - (EXT4_FEATURE_INCOMPAT_INLINE_DATA) +#define EXT4_SUPPORTED_FINCOM + (EXT4_FINCOM_INLINE_DATA) /*TODO: Features read only to implement*/ -#define EXT4_FEATURE_RO_COMPAT_SUPP - EXT4_FEATURE_RO_COMPAT_BIGALLOC |\ - EXT4_FEATURE_RO_COMPAT_METADATA_CSUM|\ - EXT4_FEATURE_RO_COMPAT_QUOTA) +#define EXT4_SUPPORTED_FRO_COM + EXT4_FRO_COM_BIGALLOC |\ + EXT4_FRO_COM_QUOTA) #endif struct ext4_fs { @@ -291,6 +310,10 @@ struct ext4_fs { uint64_t inode_blocks_per_level[4]; uint32_t last_inode_bg_id; + + struct jbd_fs *jbd_fs; + struct jbd_journal *jbd_journal; + struct jbd_trans *curr_trans; }; /* Inode table/bitmap not in use */ @@ -355,6 +378,8 @@ struct ext4_block_group_ref { #define EXT4_INODE_INDIRECT_BLOCK_COUNT \ (EXT4_INODE_BLOCKS - EXT4_INODE_DIRECT_BLOCK_COUNT) +#pragma pack(push, 1) + /* * Structure of an inode on the disk */ @@ -383,7 +408,8 @@ struct ext4_inode { uint16_t file_acl_high; uint16_t uid_high; uint16_t gid_high; - uint32_t reserved2; + uint16_t checksum_lo; /* crc32c(uuid+inum+inode) LE */ + uint16_t reserved2; } linux2; struct { uint16_t reserved1; @@ -392,10 +418,10 @@ struct ext4_inode { uint16_t gid_high; uint32_t author; } hurd2; - } __attribute__((packed)) osd2; + } osd2; uint16_t extra_isize; - uint16_t pad1; + uint16_t checksum_hi; /* crc32c(uuid+inum+inode) BE */ uint32_t ctime_extra; /* Extra change time (nsec << 2 | epoch) */ uint32_t mtime_extra; /* Extra Modification time (nsec << 2 | epoch) */ uint32_t atime_extra; /* Extra Access time (nsec << 2 | epoch) */ @@ -403,7 +429,9 @@ struct ext4_inode { uint32_t crtime_extra; /* Extra file creation time (nsec << 2 | epoch) */ uint32_t version_hi; /* High 32 bits for 64-bit version */ -} __attribute__((packed)); +}; + +#pragma pack(pop) #define EXT4_INODE_MODE_FIFO 0x1000 #define EXT4_INODE_MODE_CHARDEV 0x2000 @@ -460,53 +488,57 @@ struct ext4_inode_ref { #define EXT4_DIRECTORY_FILENAME_LEN 255 /**@brief Directory entry types. */ -enum { EXT4_DIRENTRY_UNKNOWN = 0, - EXT4_DIRENTRY_REG_FILE, - EXT4_DIRENTRY_DIR, - EXT4_DIRENTRY_CHRDEV, - EXT4_DIRENTRY_BLKDEV, - EXT4_DIRENTRY_FIFO, - EXT4_DIRENTRY_SOCK, - EXT4_DIRENTRY_SYMLINK }; - -union ext4_directory_entry_ll_internal { +enum { EXT4_DE_UNKNOWN = 0, + EXT4_DE_REG_FILE, + EXT4_DE_DIR, + EXT4_DE_CHRDEV, + EXT4_DE_BLKDEV, + EXT4_DE_FIFO, + EXT4_DE_SOCK, + EXT4_DE_SYMLINK }; + +#define EXT4_DIRENTRY_DIR_CSUM 0xDE + +#pragma pack(push, 1) + +union ext4_dir_en_internal { uint8_t name_length_high; /* Higher 8 bits of name length */ uint8_t inode_type; /* Type of referenced inode (in rev >= 0.5) */ -} __attribute__((packed)); +}; /** * Linked list directory entry structure */ -struct ext4_directory_entry_ll { +struct ext4_dir_en { uint32_t inode; /* I-node for the entry */ - uint16_t entry_length; /* Distance to the next directory entry */ - uint8_t name_length; /* Lower 8 bits of name length */ + uint16_t entry_len; /* Distance to the next directory entry */ + uint8_t name_len; /* Lower 8 bits of name length */ - union ext4_directory_entry_ll_internal in; + union ext4_dir_en_internal in; uint8_t name[EXT4_DIRECTORY_FILENAME_LEN]; /* Entry name */ -} __attribute__((packed)); +}; -struct ext4_directory_iterator { +struct ext4_dir_iter { struct ext4_inode_ref *inode_ref; - struct ext4_block current_block; - uint64_t current_offset; - struct ext4_directory_entry_ll *current; + struct ext4_block curr_blk; + uint64_t curr_off; + struct ext4_dir_en *curr; }; -struct ext4_directory_search_result { +struct ext4_dir_search_result { struct ext4_block block; - struct ext4_directory_entry_ll *dentry; + struct ext4_dir_en *dentry; }; /* Structures for indexed directory */ -struct ext4_directory_dx_countlimit { +struct ext4_dir_idx_climit { uint16_t limit; uint16_t count; }; -struct ext4_directory_dx_dot_entry { +struct ext4_dir_idx_dot_en { uint32_t inode; uint16_t entry_length; uint8_t name_length; @@ -514,7 +546,7 @@ struct ext4_directory_dx_dot_entry { uint8_t name[4]; }; -struct ext4_directory_dx_root_info { +struct ext4_dir_idx_rinfo { uint32_t reserved_zero; uint8_t hash_version; uint8_t info_length; @@ -522,39 +554,107 @@ struct ext4_directory_dx_root_info { uint8_t unused_flags; }; -struct ext4_directory_dx_entry { +struct ext4_dir_idx_entry { uint32_t hash; uint32_t block; }; -struct ext4_directory_dx_root { - struct ext4_directory_dx_dot_entry dots[2]; - struct ext4_directory_dx_root_info info; - struct ext4_directory_dx_entry entries[]; +struct ext4_dir_idx_root { + struct ext4_dir_idx_dot_en dots[2]; + struct ext4_dir_idx_rinfo info; + struct ext4_dir_idx_entry en[]; }; -struct ext4_fake_directory_entry { +struct ext4_fake_dir_entry { uint32_t inode; uint16_t entry_length; uint8_t name_length; uint8_t inode_type; }; -struct ext4_directory_dx_node { - struct ext4_fake_directory_entry fake; - struct ext4_directory_dx_entry entries[]; +struct ext4_dir_idx_node { + struct ext4_fake_dir_entry fake; + struct ext4_dir_idx_entry entries[]; }; -struct ext4_directory_dx_block { - struct ext4_block block; - struct ext4_directory_dx_entry *entries; - struct ext4_directory_dx_entry *position; +struct ext4_dir_idx_block { + struct ext4_block b; + struct ext4_dir_idx_entry *entries; + struct ext4_dir_idx_entry *position; }; +/* + * This goes at the end of each htree block. + */ +struct ext4_dir_idx_tail { + uint32_t reserved; + uint32_t checksum; /* crc32c(uuid+inum+dirblock) */ +}; + +/* + * This is a bogus directory entry at the end of each leaf block that + * records checksums. + */ +struct ext4_dir_entry_tail { + uint32_t reserved_zero1; /* Pretend to be unused */ + uint16_t rec_len; /* 12 */ + uint8_t reserved_zero2; /* Zero name length */ + uint8_t reserved_ft; /* 0xDE, fake file type */ + uint32_t checksum; /* crc32c(uuid+inum+dirblock) */ +}; + +#pragma pack(pop) + +#define EXT4_DIRENT_TAIL(block, blocksize) \ + ((struct ext4_dir_entry_tail *)(((char *)(block)) + ((blocksize) - \ + sizeof(struct ext4_dir_entry_tail)))) + #define EXT4_ERR_BAD_DX_DIR (-25000) #define EXT4_LINK_MAX 65000 +#define EXT4_BAD_INO 1 +#define EXT4_ROOT_INO 2 +#define EXT4_BOOT_LOADER_INO 5 +#define EXT4_UNDEL_DIR_INO 6 +#define EXT4_RESIZE_INO 7 +#define EXT4_JOURNAL_INO 8 + +#define EXT4_GOOD_OLD_FIRST_INO 11 + +#define EXT4_EXT_UNWRITTEN_MASK (1L << 15) + +#define EXT4_EXT_MAX_LEN_WRITTEN (1L << 15) +#define EXT4_EXT_MAX_LEN_UNWRITTEN \ + (EXT4_EXT_MAX_LEN_WRITTEN - 1) + +#define EXT4_EXT_GET_LEN(ex) to_le16((ex)->block_count) +#define EXT4_EXT_GET_LEN_UNWRITTEN(ex) \ + (EXT4_EXT_GET_LEN(ex) &= ~(EXT4_EXT_UNWRITTEN_MASK)) +#define EXT4_EXT_SET_LEN(ex, count) \ + ((ex)->block_count = to_le16(count)) + +#define EXT4_EXT_IS_UNWRITTEN(ex) \ + (EXT4_EXT_GET_LEN(ex) > EXT4_EXT_MAX_LEN_WRITTEN) +#define EXT4_EXT_SET_UNWRITTEN(ex) \ + ((ex)->block_count |= to_le16(EXT4_EXT_UNWRITTEN_MASK)) +#define EXT4_EXT_SET_WRITTEN(ex) \ + ((ex)->block_count &= ~(to_le16(EXT4_EXT_UNWRITTEN_MASK))) + +#pragma pack(push, 1) + +/* + * This is the extent tail on-disk structure. + * All other extent structures are 12 bytes long. It turns out that + * block_size % 12 >= 4 for at least all powers of 2 greater than 512, which + * covers all valid ext4 block sizes. Therefore, this tail structure can be + * crammed into the end of the block without having to rebalance the tree. + */ +struct ext4_extent_tail +{ + uint32_t et_checksum; /* crc32c(uuid+inum+extent_block) */ +}; + /* * This is the extent on-disk structure. * It's used at the bottom of the tree. @@ -590,18 +690,36 @@ struct ext4_extent_header { uint16_t magic; uint16_t entries_count; /* Number of valid entries */ uint16_t max_entries_count; /* Capacity of store in entries */ - uint16_t depth; /* Has tree real underlying blocks? */ - uint32_t generation; /* generation of the tree */ + uint16_t depth; /* Has tree real underlying blocks? */ + uint32_t generation; /* generation of the tree */ }; +#pragma pack(pop) + + +/* + * Types of blocks. + */ +typedef uint32_t ext4_lblk_t; +typedef uint64_t ext4_fsblk_t; + +/* + * Array of ext4_ext_path contains path to some extent. + * Creation/lookup routines use it for traversal/splitting/etc. + * Truncate uses it to simulate recursive walking. + */ struct ext4_extent_path { + ext4_fsblk_t p_block; struct ext4_block block; - uint16_t depth; + int32_t depth; + int32_t maxdepth; struct ext4_extent_header *header; struct ext4_extent_index *index; struct ext4_extent *extent; + }; + #define EXT4_EXTENT_MAGIC 0xF30A #define EXT4_EXTENT_FIRST(header) \ @@ -612,6 +730,64 @@ struct ext4_extent_path { ((struct ext4_extent_index *)(((char *)(header)) + \ sizeof(struct ext4_extent_header))) +/* + * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an + * initialized extent. This is 2^15 and not (2^16 - 1), since we use the + * MSB of ee_len field in the extent datastructure to signify if this + * particular extent is an initialized extent or an uninitialized (i.e. + * preallocated). + * EXT_UNINIT_MAX_LEN is the maximum number of blocks we can have in an + * uninitialized extent. + * If ee_len is <= 0x8000, it is an initialized extent. Otherwise, it is an + * uninitialized one. In other words, if MSB of ee_len is set, it is an + * uninitialized extent with only one special scenario when ee_len = 0x8000. + * In this case we can not have an uninitialized extent of zero length and + * thus we make it as a special case of initialized extent with 0x8000 length. + * This way we get better extent-to-group alignment for initialized extents. + * Hence, the maximum number of blocks we can have in an *initialized* + * extent is 2^15 (32768) and in an *uninitialized* extent is 2^15-1 (32767). + */ +#define EXT_INIT_MAX_LEN (1L << 15) +#define EXT_UNWRITTEN_MAX_LEN (EXT_INIT_MAX_LEN - 1) + +#define EXT_EXTENT_SIZE sizeof(struct ext4_extent) +#define EXT_INDEX_SIZE sizeof(struct ext4_extent_idx) + +#define EXT_FIRST_EXTENT(__hdr__) \ + ((struct ext4_extent *)(((char *)(__hdr__)) + \ + sizeof(struct ext4_extent_header))) +#define EXT_FIRST_INDEX(__hdr__) \ + ((struct ext4_extent_index *)(((char *)(__hdr__)) + \ + sizeof(struct ext4_extent_header))) +#define EXT_HAS_FREE_INDEX(__path__) \ + ((__path__)->header->entries_count < (__path__)->header->max_entries_count) +#define EXT_LAST_EXTENT(__hdr__) \ + (EXT_FIRST_EXTENT((__hdr__)) + (__hdr__)->entries_count - 1) +#define EXT_LAST_INDEX(__hdr__) \ + (EXT_FIRST_INDEX((__hdr__)) + (__hdr__)->entries_count - 1) +#define EXT_MAX_EXTENT(__hdr__) \ + (EXT_FIRST_EXTENT((__hdr__)) + (__hdr__)->max_entries_count - 1) +#define EXT_MAX_INDEX(__hdr__) \ + (EXT_FIRST_INDEX((__hdr__)) + (__hdr__)->max_entries_count - 1) + +#define EXT4_EXTENT_TAIL_OFFSET(hdr) \ + (sizeof(struct ext4_extent_header) + \ + (sizeof(struct ext4_extent) * (hdr)->max_entries_count)) + +/* + * ext4_ext_next_allocated_block: + * returns allocated block in subsequent extent or EXT_MAX_BLOCKS. + * NOTE: it considers block number from index entry as + * allocated block. Thus, index entries have to be consistent + * with leaves. + */ +#define EXT_MAX_BLOCKS (ext4_lblk_t) (-1) + +#define IN_RANGE(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1) + + +/******************************************************************************/ + /* EXT3 HTree directory indexing */ #define EXT2_HTREE_LEGACY 0 #define EXT2_HTREE_HALF_MD4 1 @@ -648,6 +824,8 @@ struct ext4_hash_info { #define EXT4_XATTR_INDEX_RICHACL 8 #define EXT4_XATTR_INDEX_ENCRYPTION 9 +#pragma pack(push, 1) + struct ext4_xattr_header { uint32_t h_magic; /* magic number for identification */ uint32_t h_refcount; /* reference count */ @@ -656,11 +834,11 @@ struct ext4_xattr_header { uint32_t h_checksum; /* crc32c(uuid+id+xattrblock) */ /* id = inum if refcount=1, blknum otherwise */ uint32_t h_reserved[3]; /* zero right now */ -} __attribute__((packed)); +}; struct ext4_xattr_ibody_header { uint32_t h_magic; /* magic number for identification */ -} __attribute__((packed)); +}; struct ext4_xattr_entry { uint8_t e_name_len; /* length of name */ @@ -669,9 +847,14 @@ struct ext4_xattr_entry { uint32_t e_value_block; /* disk block attribute is stored on (n/i) */ uint32_t e_value_size; /* size of attribute value */ uint32_t e_hash; /* hash value of name and value */ -} __attribute__((packed)); +}; + +#pragma pack(pop) struct ext4_xattr_item { + /* This attribute should be stored in inode body */ + bool in_inode; + uint8_t name_index; char *name; size_t name_len; @@ -689,10 +872,17 @@ struct ext4_xattr_ref { size_t ea_size; struct ext4_fs *fs; + void *iter_arg; + struct ext4_xattr_item *iter_from; + RB_HEAD(ext4_xattr_tree, ext4_xattr_item) root; }; +#define EXT4_XATTR_ITERATE_CONT 0 +#define EXT4_XATTR_ITERATE_STOP 1 +#define EXT4_XATTR_ITERATE_PAUSE 2 + #define EXT4_GOOD_OLD_INODE_SIZE 128 #define EXT4_XATTR_PAD_BITS 2 @@ -730,31 +920,328 @@ struct ext4_xattr_ref { /*****************************************************************************/ -#ifdef CONFIG_BIG_ENDIAN -static inline uint64_t to_le64(uint64_t n) +/* + * JBD stores integers in big endian. + */ + +#define JBD_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */ + +/* + * Descriptor block types: + */ + +#define JBD_DESCRIPTOR_BLOCK 1 +#define JBD_COMMIT_BLOCK 2 +#define JBD_SUPERBLOCK 3 +#define JBD_SUPERBLOCK_V2 4 +#define JBD_REVOKE_BLOCK 5 + +#pragma pack(push, 1) + +/* + * Standard header for all descriptor blocks: + */ +struct jbd_bhdr { + uint32_t magic; + uint32_t blocktype; + uint32_t sequence; +}; + +#pragma pack(pop) + +/* + * Checksum types. + */ +#define JBD_CRC32_CHKSUM 1 +#define JBD_MD5_CHKSUM 2 +#define JBD_SHA1_CHKSUM 3 +#define JBD_CRC32C_CHKSUM 4 + +#define JBD_CRC32_CHKSUM_SIZE 4 + +#define JBD_CHECKSUM_BYTES (32 / sizeof(uint32_t)) + +#pragma pack(push, 1) + +/* + * Commit block header for storing transactional checksums: + * + * NOTE: If FEATURE_COMPAT_CHECKSUM (checksum v1) is set, the h_chksum* + * fields are used to store a checksum of the descriptor and data blocks. + * + * If FEATURE_INCOMPAT_CSUM_V2 (checksum v2) is set, then the h_chksum + * field is used to store crc32c(uuid+commit_block). Each journal metadata + * block gets its own checksum, and data block checksums are stored in + * journal_block_tag (in the descriptor). The other h_chksum* fields are + * not used. + * + * If FEATURE_INCOMPAT_CSUM_V3 is set, the descriptor block uses + * journal_block_tag3_t to store a full 32-bit checksum. Everything else + * is the same as v2. + * + * Checksum v1, v2, and v3 are mutually exclusive features. + */ + +struct jbd_commit_header { + struct jbd_bhdr header; + uint8_t chksum_type; + uint8_t chksum_size; + uint8_t padding[2]; + uint32_t chksum[JBD_CHECKSUM_BYTES]; + uint64_t commit_sec; + uint32_t commit_nsec; +}; + +/* + * The block tag: used to describe a single buffer in the journal + */ +struct jbd_block_tag3 { + uint32_t blocknr; /* The on-disk block number */ + uint32_t flags; /* See below */ + uint32_t blocknr_high; /* most-significant high 32bits. */ + uint32_t checksum; /* crc32c(uuid+seq+block) */ +}; + +struct jbd_block_tag { + uint32_t blocknr; /* The on-disk block number */ + uint16_t checksum; /* truncated crc32c(uuid+seq+block) */ + uint16_t flags; /* See below */ + uint32_t blocknr_high; /* most-significant high 32bits. */ +}; + +#pragma pack(pop) + +/* Definitions for the journal tag flags word: */ +#define JBD_FLAG_ESCAPE 1 /* on-disk block is escaped */ +#define JBD_FLAG_SAME_UUID 2 /* block has same uuid as previous */ +#define JBD_FLAG_DELETED 4 /* block deleted by this transaction */ +#define JBD_FLAG_LAST_TAG 8 /* last tag in this descriptor block */ + +#pragma pack(push, 1) + +/* Tail of descriptor block, for checksumming */ +struct jbd_block_tail { + uint32_t checksum; +}; + +/* + * The revoke descriptor: used on disk to describe a series of blocks to + * be revoked from the log + */ +struct jbd_revoke_header { + struct jbd_bhdr header; + uint32_t count; /* Count of bytes used in the block */ +}; + +/* Tail of revoke block, for checksumming */ +struct jbd_revoke_tail { + uint32_t checksum; +}; + +#pragma pack(pop) + +#define JBD_USERS_MAX 48 +#define JBD_USERS_SIZE (UUID_SIZE * JBD_USERS_MAX) + +#pragma pack(push, 1) + +/* + * The journal superblock. All fields are in big-endian byte order. + */ +struct jbd_sb { +/* 0x0000 */ + struct jbd_bhdr header; + +/* 0x000C */ + /* Static information describing the journal */ + uint32_t blocksize; /* journal device blocksize */ + uint32_t maxlen; /* total blocks in journal file */ + uint32_t first; /* first block of log information */ + +/* 0x0018 */ + /* Dynamic information describing the current state of the log */ + uint32_t sequence; /* first commit ID expected in log */ + uint32_t start; /* blocknr of start of log */ + +/* 0x0020 */ + /* Error value, as set by journal_abort(). */ + int32_t error_val; + +/* 0x0024 */ + /* Remaining fields are only valid in a version-2 superblock */ + uint32_t feature_compat; /* compatible feature set */ + uint32_t feature_incompat; /* incompatible feature set */ + uint32_t feature_ro_compat; /* readonly-compatible feature set */ +/* 0x0030 */ + uint8_t uuid[UUID_SIZE]; /* 128-bit uuid for journal */ + +/* 0x0040 */ + uint32_t nr_users; /* Nr of filesystems sharing log */ + + uint32_t dynsuper; /* Blocknr of dynamic superblock copy*/ + +/* 0x0048 */ + uint32_t max_transaction; /* Limit of journal blocks per trans.*/ + uint32_t max_trandata; /* Limit of data blocks per trans. */ + +/* 0x0050 */ + uint8_t checksum_type; /* checksum type */ + uint8_t padding2[3]; + uint32_t padding[42]; + uint32_t checksum; /* crc32c(superblock) */ + +/* 0x0100 */ + uint8_t users[JBD_USERS_SIZE]; /* ids of all fs'es sharing the log */ + +/* 0x0400 */ +}; + +#pragma pack(pop) + +#define JBD_SUPERBLOCK_SIZE sizeof(struct jbd_sb) + +#define JBD_HAS_COMPAT_FEATURE(jsb,mask) \ + ((jsb)->header.blocktype >= to_be32(2) && \ + ((jsb)->feature_compat & to_be32((mask)))) +#define JBD_HAS_RO_COMPAT_FEATURE(jsb,mask) \ + ((jsb)->header.blocktype >= to_be32(2) && \ + ((jsb)->feature_ro_compat & to_be32((mask)))) +#define JBD_HAS_INCOMPAT_FEATURE(jsb,mask) \ + ((jsb)->header.blocktype >= to_be32(2) && \ + ((jsb)->feature_incompat & to_be32((mask)))) + +#define JBD_FEATURE_COMPAT_CHECKSUM 0x00000001 + +#define JBD_FEATURE_INCOMPAT_REVOKE 0x00000001 +#define JBD_FEATURE_INCOMPAT_64BIT 0x00000002 +#define JBD_FEATURE_INCOMPAT_ASYNC_COMMIT 0x00000004 +#define JBD_FEATURE_INCOMPAT_CSUM_V2 0x00000008 +#define JBD_FEATURE_INCOMPAT_CSUM_V3 0x00000010 + +/* Features known to this kernel version: */ +#define JBD_KNOWN_COMPAT_FEATURES 0 +#define JBD_KNOWN_ROCOMPAT_FEATURES 0 +#define JBD_KNOWN_INCOMPAT_FEATURES (JBD_FEATURE_INCOMPAT_REVOKE|\ + JBD_FEATURE_INCOMPAT_ASYNC_COMMIT|\ + JBD_FEATURE_INCOMPAT_64BIT|\ + JBD_FEATURE_INCOMPAT_CSUM_V2|\ + JBD_FEATURE_INCOMPAT_CSUM_V3) + +struct jbd_fs { + /* If journal block device is used, bdev will be non-null */ + struct ext4_blockdev *bdev; + struct ext4_inode_ref inode_ref; + struct jbd_sb sb; + + bool dirty; +}; + +struct jbd_buf { + uint64_t jbd_lba; + struct ext4_block block; + struct jbd_trans *trans; + struct jbd_block_rec *block_rec; + TAILQ_ENTRY(jbd_buf) buf_node; + TAILQ_ENTRY(jbd_buf) dirty_buf_node; +}; + +struct jbd_revoke_rec { + ext4_fsblk_t lba; + LIST_ENTRY(jbd_revoke_rec) revoke_node; +}; + +struct jbd_block_rec { + ext4_fsblk_t lba; + struct ext4_buf *buf; + struct jbd_trans *trans; + RB_ENTRY(jbd_block_rec) block_rec_node; + LIST_ENTRY(jbd_block_rec) tbrec_node; + TAILQ_HEAD(jbd_buf_dirty, jbd_buf) dirty_buf_queue; +}; + +struct jbd_trans { + uint32_t trans_id; + + uint32_t start_iblock; + int alloc_blocks; + int data_cnt; + uint32_t data_csum; + int written_cnt; + int error; + + struct jbd_journal *journal; + + TAILQ_HEAD(jbd_trans_buf, jbd_buf) buf_queue; + LIST_HEAD(jbd_revoke_list, jbd_revoke_rec) revoke_list; + LIST_HEAD(jbd_trans_block_rec, jbd_block_rec) tbrec_list; + TAILQ_ENTRY(jbd_trans) trans_node; +}; + +struct jbd_journal { + uint32_t first; + uint32_t start; + uint32_t last; + uint32_t trans_id; + uint32_t alloc_trans_id; + + uint32_t block_size; + + TAILQ_HEAD(jbd_trans_queue, jbd_trans) trans_queue; + TAILQ_HEAD(jbd_cp_queue, jbd_trans) cp_queue; + RB_HEAD(jbd_block, jbd_block_rec) block_rec_root; + + struct jbd_fs *jbd_fs; +}; + +/*****************************************************************************/ + +#define EXT4_CRC32_INIT (0xFFFFFFFFUL) + +/*****************************************************************************/ + +static inline uint64_t reorder64(uint64_t n) { - return ((n & 0xff) << 56) | ((n & 0xff00) << 40) | - ((n & 0xff0000) << 24) | ((n & 0xff000000LL) << 8) | - ((n & 0xff00000000LL) >> 8) | ((n & 0xff0000000000LL) >> 24) | + return ((n & 0xff) << 56) | + ((n & 0xff00) << 40) | + ((n & 0xff0000) << 24) | + ((n & 0xff000000LL) << 8) | + ((n & 0xff00000000LL) >> 8) | + ((n & 0xff0000000000LL) >> 24) | ((n & 0xff000000000000LL) >> 40) | ((n & 0xff00000000000000LL) >> 56); } -static inline uint32_t to_le32(uint32_t n) +static inline uint32_t reorder32(uint32_t n) { - return ((n & 0xff) << 24) | ((n & 0xff00) << 8) | - ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24); + return ((n & 0xff) << 24) | + ((n & 0xff00) << 8) | + ((n & 0xff0000) >> 8) | + ((n & 0xff000000) >> 24); } -static inline uint16_t to_le16(uint16_t n) +static inline uint16_t reorder16(uint16_t n) { - return ((n & 0xff) << 8) | ((n & 0xff00) >> 8); + return ((n & 0xff) << 8) | + ((n & 0xff00) >> 8); } +#ifdef CONFIG_BIG_ENDIAN +#define to_le64(_n) reorder64(_n) +#define to_le32(_n) reorder32(_n) +#define to_le16(_n) reorder16(_n) + +#define to_be64(_n) _n +#define to_be32(_n) _n +#define to_be16(_n) _n + #else #define to_le64(_n) _n #define to_le32(_n) _n #define to_le16(_n) _n + +#define to_be64(_n) reorder64(_n) +#define to_be32(_n) reorder32(_n) +#define to_be16(_n) reorder16(_n) #endif /****************************Access macros to ext4 structures*****************/ @@ -775,6 +1262,41 @@ static inline uint16_t to_le16(uint16_t n) (s, f, v) do { (s)->f = (v); } \ while (0) +/****************************Access macros to jbd2 structures*****************/ + +#define jbd_get32(s, f) to_be32((s)->f) +#define jbd_get16(s, f) to_be16((s)->f) +#define jbd_get8(s, f) (s)->f + +#define jbd_set32(s, f, v) \ + do { \ + (s)->f = to_be32(v); \ + } while (0) +#define jbd_set16(s, f, v) \ + do { \ + (s)->f = to_be16(v); \ + } while (0) +#define jbd_set8 \ + (s, f, v) do { (s)->f = (v); } \ + while (0) + +#ifdef __GNUC__ + #ifndef __unused + #define __unused __attribute__ ((__unused__)) + #endif +#else + #define __unused +#endif + +#ifndef offsetof +#define offsetof(type, field) \ + ((size_t)(&(((type *)0)->field))) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* EXT4_TYPES_H_ */ /**