* [PATCH] Journal support for ext2 @ 2008-02-17 19:07 Bean 2008-02-17 22:34 ` Bean 2008-02-18 6:03 ` Robert Millan 0 siblings, 2 replies; 16+ messages in thread From: Bean @ 2008-02-17 19:07 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 1570 bytes --] Hi, This patch extends fshelp for general journal handling, it also implement journaling for ext2 file system. 2008-02-18 Bean <bean123ch@gmail.com> * fs/ext2.c (EXT3_FEATURE_COMPAT_HAS_JOURNAL): New macro. (EXT3_JOURNAL_MAGIC_NUMBER): Likewise. (EXT3_JOURNAL_DESCRIPTOR_BLOCK): Likewise. (EXT3_JOURNAL_COMMIT_BLOCK): Likewise. (EXT3_JOURNAL_SUPERBLOCK_V1): Likewise. (EXT3_JOURNAL_SUPERBLOCK_V2): Likewise. (EXT3_JOURNAL_REVOKE_BLOCK): Likewise. (EXT3_JOURNAL_FLAG_ESCAPE): Likewise. (EXT3_JOURNAL_FLAG_SAME_UUID): Likewise. (EXT3_JOURNAL_FLAG_DELETED): Likewise. (EXT3_JOURNAL_FLAG_LAST_TAG): Likewise. (grub_ext2_sblock): New members for journal support. (grub_ext3_journal_header): New structure. (grub_ext3_journal_revoke_header): Likewise. (grub_ext3_journal_block_tag): Likewise. (grub_ext3_journal_sblock): Likewise. (grub_fshelp_node): New members logfile and journal. (grub_ext2_blockgroup): Moved behind grub_ext2_read_block, use grub_fshelp_map_block to get real block number. (grub_ext2_read_block): use grub_fshelp_map_block to get real block number. (grub_ext2_read_inode): Likewise. (grub_ext3_get_journal): New function. (grub_read_inode): Initialize journal structure by calling grub_ext3_get_journal. (grub_ext2_close): Release memory used by journal. * fs/fshelp.c (grub_fshelp_map_block): New function. * include/grub/fshelp.h (grub_fshelp_journal_type): New enum. (GRUB_FSHELP_JOURNAL_UNUSED_MAPPING): New macro. (grub_fshelp_journal): New structure. (grub_fshelp_map_block): New function prototype. -- Bean [-- Attachment #2: jour.diff --] [-- Type: text/plain, Size: 13556 bytes --] diff --git a/fs/ext2.c b/fs/ext2.c index ec66582..1a9871e 100644 --- a/fs/ext2.c +++ b/fs/ext2.c @@ -71,6 +71,21 @@ ? EXT2_GOOD_OLD_INODE_SIZE \ : grub_le_to_cpu16 (data->sblock.inode_size)) +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 + +#define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U + +#define EXT3_JOURNAL_DESCRIPTOR_BLOCK 1 +#define EXT3_JOURNAL_COMMIT_BLOCK 2 +#define EXT3_JOURNAL_SUPERBLOCK_V1 3 +#define EXT3_JOURNAL_SUPERBLOCK_V2 4 +#define EXT3_JOURNAL_REVOKE_BLOCK 5 + +#define EXT3_JOURNAL_FLAG_ESCAPE 1 +#define EXT3_JOURNAL_FLAG_SAME_UUID 2 +#define EXT3_JOURNAL_FLAG_DELETED 4 +#define EXT3_JOURNAL_FLAG_LAST_TAG 8 + /* The ext2 superblock. */ struct grub_ext2_sblock { @@ -109,6 +124,21 @@ struct grub_ext2_sblock char volume_name[16]; char last_mounted_on[64]; grub_uint32_t compression_info; + grub_uint8_t prealloc_blocks; + grub_uint8_t prealloc_dir_blocks; + grub_uint16_t reserved_gdt_blocks; + grub_uint8_t journal_uuid[16]; + grub_uint32_t journal_inum; + grub_uint32_t journal_dev; + grub_uint32_t last_orphan; + grub_uint32_t hash_seed[4]; + grub_uint8_t def_hash_version; + grub_uint8_t jnl_backup_type; + grub_uint16_t reserved_word_pad; + grub_uint32_t default_mount_opts; + grub_uint32_t first_meta_bg; + grub_uint32_t mkfs_time; + grub_uint32_t jnl_blocks[17]; }; /* The ext2 blockgroup. */ @@ -166,6 +196,36 @@ struct ext2_dirent grub_uint8_t filetype; }; +struct grub_ext3_journal_header +{ + grub_uint32_t magic; + grub_uint32_t block_type; + grub_uint32_t sequence; +}; + +struct grub_ext3_journal_revoke_header +{ + struct grub_ext3_journal_header header; + grub_uint32_t count; + grub_uint32_t data[0]; +}; + +struct grub_ext3_journal_block_tag +{ + grub_uint32_t block; + grub_uint32_t flags; +}; + +struct grub_ext3_journal_sblock +{ + struct grub_ext3_journal_header header; + grub_uint32_t block_size; + grub_uint32_t maxlen; + grub_uint32_t first; + grub_uint32_t sequence; + grub_uint32_t start; +}; + struct grub_fshelp_node { struct grub_ext2_data *data; @@ -181,6 +241,8 @@ struct grub_ext2_data grub_disk_t disk; struct grub_ext2_inode *inode; struct grub_fshelp_node diropen; + struct grub_fshelp_node logfile; + grub_fshelp_journal_t journal; }; #ifndef GRUB_UTIL @@ -188,21 +250,6 @@ static grub_dl_t my_mod; #endif \f - -/* Read into BLKGRP the blockgroup descriptor of blockgroup GROUP of - the mounted filesystem DATA. */ -inline static grub_err_t -grub_ext2_blockgroup (struct grub_ext2_data *data, int group, - struct grub_ext2_block_group *blkgrp) -{ - return grub_disk_read (data->disk, - ((grub_le_to_cpu32 (data->sblock.first_data_block) + 1) - << LOG2_EXT2_BLOCK_SIZE (data)), - group * sizeof (struct grub_ext2_block_group), - sizeof (struct grub_ext2_block_group), (char *) blkgrp); -} - - static int grub_ext2_read_block (grub_fshelp_node_t node, int fileblock) { @@ -221,7 +268,9 @@ grub_ext2_read_block (grub_fshelp_node_t node, int fileblock) grub_uint32_t indir[blksz / 4]; if (grub_disk_read (data->disk, - grub_le_to_cpu32 (inode->blocks.indir_block) + grub_fshelp_map_block(data->journal, + grub_le_to_cpu32 (inode->blocks.indir_block), + grub_ext2_read_block) << log2_blksz, 0, blksz, (char *) indir)) return grub_errno; @@ -237,13 +286,17 @@ grub_ext2_read_block (grub_fshelp_node_t node, int fileblock) grub_uint32_t indir[blksz / 4]; if (grub_disk_read (data->disk, - grub_le_to_cpu32 (inode->blocks.double_indir_block) + grub_fshelp_map_block(data->journal, + grub_le_to_cpu32 (inode->blocks.double_indir_block), + grub_ext2_read_block) << log2_blksz, 0, blksz, (char *) indir)) return grub_errno; if (grub_disk_read (data->disk, - grub_le_to_cpu32 (indir[rblock / perblock]) + grub_fshelp_map_block(data->journal, + grub_le_to_cpu32 (indir[rblock / perblock]), + grub_ext2_read_block) << log2_blksz, 0, blksz, (char *) indir)) return grub_errno; @@ -259,9 +312,23 @@ grub_ext2_read_block (grub_fshelp_node_t node, int fileblock) blknr = -1; } - return blknr; + return grub_fshelp_map_block (data->journal, blknr, grub_ext2_read_block); } +/* Read into BLKGRP the blockgroup descriptor of blockgroup GROUP of + the mounted filesystem DATA. */ +inline static grub_err_t +grub_ext2_blockgroup (struct grub_ext2_data *data, int group, + struct grub_ext2_block_group *blkgrp) +{ + return grub_disk_read (data->disk, + (grub_fshelp_map_block (data->journal, + grub_le_to_cpu32 (data->sblock.first_data_block) + 1, + grub_ext2_read_block) + << LOG2_EXT2_BLOCK_SIZE (data)), + group * sizeof (struct grub_ext2_block_group), + sizeof (struct grub_ext2_block_group), (char *) blkgrp); +} /* Read LEN bytes from the file described by DATA starting with byte POS. Return the amount of read bytes in READ. */ @@ -308,8 +375,10 @@ grub_ext2_read_inode (struct grub_ext2_data *data, /* Read the inode. */ if (grub_disk_read (data->disk, - ((grub_le_to_cpu32 (blkgrp.inode_table_id) + blkno) - << LOG2_EXT2_BLOCK_SIZE (data)), + grub_fshelp_map_block(data->journal, + grub_le_to_cpu32 (blkgrp.inode_table_id) + blkno, + grub_ext2_read_block) + << LOG2_EXT2_BLOCK_SIZE (data), EXT2_INODE_SIZE (data) * blkoff, sizeof (struct grub_ext2_inode), (char *) inode)) return grub_errno; @@ -317,6 +386,163 @@ grub_ext2_read_inode (struct grub_ext2_data *data, return 0; } +static void +grub_ext3_get_journal (struct grub_ext2_data *data) +{ + char buf[1 << (LOG2_BLOCK_SIZE (data))]; + struct grub_ext3_journal_sblock *jsb; + grub_fshelp_journal_t log; + int last_num, num, block, log2bs; + grub_uint32_t seq; + + auto void next_block (void); + void next_block (void) + { + block++; + if (block >= log->last_block) + block = log->first_block; + } + + data->journal = 0; + + if (! (data->sblock.feature_compatibility & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) + return; + + if (! data->sblock.journal_inum) + return; + + data->logfile.data = data; + data->logfile.ino = data->sblock.journal_inum; + data->logfile.inode_read = 1; + + if (grub_ext2_read_inode (data, data->logfile.ino, &data->logfile.inode)) + return; + + log2bs = LOG2_EXT2_BLOCK_SIZE (data); + if (grub_fshelp_read_file (data->disk, &data->logfile, 0, + 0, sizeof (struct grub_ext3_journal_sblock), + buf, grub_ext2_read_block, + sizeof (buf), log2bs) != + sizeof (struct grub_ext3_journal_sblock)) + return; + + jsb = (struct grub_ext3_journal_sblock *) &buf[0]; + if (grub_be_to_cpu32 (jsb->header.magic) != EXT3_JOURNAL_MAGIC_NUMBER) + return; + + /* Empty journal. */ + if (! jsb->start) + return; + + log = grub_malloc (sizeof (struct grub_fshelp_journal) + + grub_be_to_cpu32 (jsb->maxlen) * sizeof (grub_uint32_t)); + if (! log) + return; + + log->type = GRUB_FSHELP_JOURNAL_TYPE_FILE; + log->node = &data->logfile; + log->first_block = grub_be_to_cpu32 (jsb->first); + log->last_block = grub_be_to_cpu32 (jsb->maxlen); + log->start_block = grub_be_to_cpu32 (jsb->start); + + last_num = num = 0; + block = log->start_block; + seq = grub_be_to_cpu32 (jsb->sequence); + + while (1) + { + struct grub_ext3_journal_header *jh; + + if (grub_fshelp_read_file (data->disk, &data->logfile, 0, + block << (log2bs + 9), sizeof (buf), + buf, grub_ext2_read_block, + log->last_block << (log2bs + 9), + log2bs) != + (int) sizeof (buf)) + break; + + jh = (struct grub_ext3_journal_header *) &buf[0]; + if (grub_be_to_cpu32 (jh->magic) != EXT3_JOURNAL_MAGIC_NUMBER) + break; + + if (grub_be_to_cpu32 (jh->sequence) != seq) + break; + + log->mapping[num++] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING; + next_block(); + + switch (grub_be_to_cpu32 (jh->block_type)) + { + case EXT3_JOURNAL_DESCRIPTOR_BLOCK: + { + struct grub_ext3_journal_block_tag *tag; + int ofs, flags; + + ofs = sizeof (struct grub_ext3_journal_header); + + do + { + tag = (struct grub_ext3_journal_block_tag *) &buf[ofs]; + ofs += sizeof (struct grub_ext3_journal_block_tag); + + if (ofs > (int) sizeof (buf)) + break; + + flags = grub_be_to_cpu32 (tag->flags); + if (! (flags & EXT3_JOURNAL_FLAG_SAME_UUID)) + ofs += 16; + + log->mapping[num++] = grub_be_to_cpu32 (tag->block); + next_block(); + } + while (! (flags & EXT3_JOURNAL_FLAG_LAST_TAG)); + + continue; + } + + case EXT3_JOURNAL_COMMIT_BLOCK: + { + seq++; + last_num = num - 1; + continue; + } + + case EXT3_JOURNAL_REVOKE_BLOCK: + { + struct grub_ext3_journal_revoke_header *jrh; + grub_uint32_t i; + + jrh = (struct grub_ext3_journal_revoke_header *) jh; + + for (i = 0; i < grub_be_to_cpu32 (jrh->count); i++) + { + int j; + grub_uint32_t map; + + map = grub_be_to_cpu32 (jrh->data[i]); + for (j = 0; j < num; j++) + if (log->mapping[j] == map) + log->mapping[j] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING; + } + + continue; + } + default: + num = 0; + goto quit; + } + } + +quit: + if (! last_num) + grub_free (log); + else + { + log->num_mappings = last_num; + data->journal = log; + } +} + static struct grub_ext2_data * grub_ext2_mount (grub_disk_t disk) { @@ -336,12 +562,14 @@ grub_ext2_mount (grub_disk_t disk) if (grub_le_to_cpu16 (data->sblock.magic) != EXT2_MAGIC) goto fail; + data->disk = disk; + grub_ext3_get_journal (data); + data->diropen.data = data; data->diropen.ino = 2; data->diropen.inode_read = 1; data->inode = &data->diropen.inode; - data->disk = disk; grub_ext2_read_inode (data, 2, data->inode); if (grub_errno) @@ -540,7 +768,11 @@ grub_ext2_open (struct grub_file *file, const char *name) static grub_err_t grub_ext2_close (grub_file_t file) { - grub_free (file->data); + if (file->data) + { + grub_free (((struct grub_ext2_data *) file->data)->journal); + grub_free (file->data); + } #ifndef GRUB_UTIL grub_dl_unref (my_mod); diff --git a/fs/fshelp.c b/fs/fshelp.c index bbb58ac..5eefefd 100644 --- a/fs/fshelp.c +++ b/fs/fshelp.c @@ -310,3 +310,31 @@ grub_fshelp_log2blksize (unsigned int blksize, unsigned int *pow) return GRUB_ERR_NONE; } + +int +grub_fshelp_map_block (grub_fshelp_journal_t log, int block, + int (*get_block) (grub_fshelp_node_t node, int block)) +{ + int map_block; + + if ((! log) || (log->type == GRUB_FSHELP_JOURNAL_TYPE_NONE)) + return block; + + for (map_block = log->num_mappings - 1; map_block >= 0; map_block--) + { + if (log->mapping[map_block] == block) + break; + } + + if (map_block < 0) + return block; + + map_block += log->start_block; + if (map_block >= log->last_block) + map_block -= log->last_block - log->first_block; + + if (log->type == GRUB_FSHELP_JOURNAL_TYPE_BLOCK) + return log->blkno + map_block; + else + return get_block (log->node, map_block); +} diff --git a/include/grub/fshelp.h b/include/grub/fshelp.h index e25dd16..da8e5a5 100644 --- a/include/grub/fshelp.h +++ b/include/grub/fshelp.h @@ -34,6 +34,31 @@ enum grub_fshelp_filetype GRUB_FSHELP_SYMLINK }; +enum grub_fshelp_journal_type + { + GRUB_FSHELP_JOURNAL_TYPE_NONE, + GRUB_FSHELP_JOURNAL_TYPE_BLOCK, + GRUB_FSHELP_JOURNAL_TYPE_FILE + }; + +#define GRUB_FSHELP_JOURNAL_UNUSED_MAPPING (grub_uint32_t) -1 + +struct grub_fshelp_journal +{ + int type; + union + { + grub_fshelp_node_t node; + grub_uint32_t blkno; + }; + int first_block; + int last_block; + int start_block; + int num_mappings; + grub_uint32_t mapping[0]; +}; +typedef struct grub_fshelp_journal *grub_fshelp_journal_t; + /* Lookup the node PATH. The node ROOTNODE describes the root of the directory tree. The node found is returned in FOUNDNODE, which is either a ROOTNODE or a new malloc'ed node. ITERATE_DIR is used to @@ -75,4 +100,8 @@ unsigned int EXPORT_FUNC(grub_fshelp_log2blksize) (unsigned int blksize, unsigned int *pow); +int +EXPORT_FUNC(grub_fshelp_map_block) (grub_fshelp_journal_t log, int block, + int (*get_block) (grub_fshelp_node_t node, int block)); + #endif /* ! GRUB_FSHELP_HEADER */ ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH] Journal support for ext2 2008-02-17 19:07 [PATCH] Journal support for ext2 Bean @ 2008-02-17 22:34 ` Bean 2008-02-17 23:25 ` Bean 2008-02-18 6:03 ` Robert Millan 1 sibling, 1 reply; 16+ messages in thread From: Bean @ 2008-02-17 22:34 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 71 bytes --] This new patch add journal support for reiserfs file system. -- Bean [-- Attachment #2: jour_reiserfs.diff --] [-- Type: text/plain, Size: 12425 bytes --] diff --git a/fs/reiserfs.c b/fs/reiserfs.c index a4c60ca..610fadd 100644 --- a/fs/reiserfs.c +++ b/fs/reiserfs.c @@ -52,7 +52,8 @@ #define REISERFS_SUPER_BLOCK_OFFSET 0x10000 #define REISERFS_MAGIC_LEN 12 -#define REISERFS_MAGIC_STRING "ReIsEr2Fs\0\0\0" +#define REISERFS_MAGIC_STRING "ReIsEr" +#define REISERFS_MAGIC_DESC_BLOCK "ReIsErLB" /* If the 3rd bit of an item state is set, then it's visible. */ #define GRUB_REISERFS_VISIBLE_MASK ((grub_uint16_t) 0x04) #define REISERFS_MAX_LABEL_LENGTH 16 @@ -109,8 +110,6 @@ struct grub_reiserfs_superblock grub_uint32_t inode_generation; } __attribute__ ((packed)); -#ifdef GRUB_REISERFS_JOURNALING -# error "Journaling not yet supported." struct grub_reiserfs_journal_header { grub_uint32_t last_flush_uid; @@ -118,15 +117,20 @@ struct grub_reiserfs_journal_header grub_uint32_t mount_id; } __attribute__ ((packed)); -struct grub_reiserfs_transaction_header +struct grub_reiserfs_description_block { grub_uint32_t id; grub_uint32_t len; grub_uint32_t mount_id; - char *data; - char checksum[12]; + grub_uint32_t real_blocks[0]; +} __attribute__ ((packed)); + +struct grub_reiserfs_commit_block +{ + grub_uint32_t id; + grub_uint32_t len; + grub_uint32_t real_blocks[0]; } __attribute__ ((packed)); -#endif struct grub_reiserfs_stat_item_v1 { @@ -228,6 +232,7 @@ struct grub_reiserfs_data { struct grub_reiserfs_superblock superblock; grub_disk_t disk; + grub_fshelp_journal_t journal; }; /* Internal-only functions. Not to be used outside of this file. */ @@ -504,8 +509,8 @@ grub_reiserfs_get_item (struct grub_reiserfs_data *data, do { grub_disk_read (data->disk, - (((grub_disk_addr_t) block_number * block_size) - >> GRUB_DISK_SECTOR_BITS), + grub_fshelp_map_block (data->journal, block_number, 0) + * (block_size >> GRUB_DISK_SECTOR_BITS), (((grub_off_t) block_number * block_size) & (GRUB_DISK_SECTOR_SIZE - 1)), block_size, (char *) block_header); @@ -655,8 +660,8 @@ grub_reiserfs_read_symlink (grub_fshelp_node_t node) block_size = grub_le_to_cpu16 (node->data->superblock.block_size); len = grub_le_to_cpu16 (found.header.item_size); - block = (((grub_disk_addr_t) found.block_number * block_size) - >> GRUB_DISK_SECTOR_BITS); + block = (grub_fshelp_map_block (node->data->journal, found.block_number, 0) + * (block_size >> GRUB_DISK_SECTOR_BITS)); offset = grub_le_to_cpu16 (found.header.item_location); symlink_buffer = grub_malloc (len); @@ -674,6 +679,115 @@ grub_reiserfs_read_symlink (grub_fshelp_node_t node) return 0; } +static void +grub_reiserfs_get_journal (struct grub_reiserfs_data *data) +{ + int block_size = grub_le_to_cpu16 (data->superblock.block_size); + char buf[block_size]; + struct grub_reiserfs_journal_header *jh; + grub_fshelp_journal_t log; + grub_uint32_t seq_id, mount_id; + int num_blocks = grub_le_to_cpu32 (data->superblock.journal_original_size); + int base_block = grub_le_to_cpu32 (data->superblock.journal_block); + int last_num, num, block; + + data->journal = 0; + + if (! data->superblock.journal_block) + return; + + if (grub_disk_read (data->disk, + (base_block + num_blocks) + * (block_size >> GRUB_DISK_SECTOR_BITS), + 0, sizeof (struct grub_reiserfs_journal_header), + buf)) + return; + + log = grub_malloc (sizeof (struct grub_fshelp_journal) + + num_blocks * sizeof (grub_uint32_t)); + if (! log) + return; + + jh = (struct grub_reiserfs_journal_header *) &buf[0]; + + log->type = GRUB_FSHELP_JOURNAL_TYPE_BLOCK; + log->blkno = base_block; + log->first_block = 0; + log->last_block = num_blocks; + log->start_block = grub_le_to_cpu32 (jh->unflushed_offset); + + seq_id = grub_le_to_cpu32 (jh->last_flush_uid); + mount_id = grub_le_to_cpu32 (jh->mount_id); + + last_num = num = 0; + block = log->start_block; + + while (1) + { + struct grub_reiserfs_description_block *db; + struct grub_reiserfs_commit_block *cb; + grub_uint32_t i, len, half_len, id; + + if (grub_disk_read (data->disk, + (base_block + block) + * (block_size >> GRUB_DISK_SECTOR_BITS), + 0, sizeof (buf), buf)) + break; + + if (grub_memcmp (&buf[block_size - REISERFS_MAGIC_LEN], + REISERFS_MAGIC_DESC_BLOCK, + sizeof (REISERFS_MAGIC_DESC_BLOCK) - 1)) + break; + + db = (struct grub_reiserfs_description_block *) &buf[0]; + id = grub_le_to_cpu32 (db->id); + len = grub_le_to_cpu32 (db->len); + if ((grub_le_to_cpu32 (db->id) <= seq_id) && (id <= mount_id)) + break; + + log->mapping[num++] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING; + half_len = ((block_size - 24) >> 2); + if (half_len > len) + half_len = len; + + for (i = 0; i < half_len; i++) + log->mapping[num++] = db->real_blocks[i]; + + block += grub_le_to_cpu32 (db->len) + 1; + if (block >= log->last_block) + block -= log->last_block; + + if (grub_disk_read (data->disk, + (base_block + block) + * (block_size >> GRUB_DISK_SECTOR_BITS), + 0, sizeof (buf), buf)) + break; + + cb = (struct grub_reiserfs_commit_block *) &buf[0]; + if ((grub_le_to_cpu32 (cb->id) != id) || + (grub_le_to_cpu32 (cb->len) != len)) + break; + + for (i = 0; i < len - half_len; i++) + log->mapping[num++] = cb->real_blocks[i]; + + last_num = num; + log->mapping[num++] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING; + + block++; + if (block >= log->last_block) + block -= log->last_block; + }; + + if (! last_num) + grub_free (log); + else + { + log->num_mappings = last_num; + data->journal = log; + } +} + /* Fill the mounted filesystem structure and return it. */ static struct grub_reiserfs_data * grub_reiserfs_mount (grub_disk_t disk) @@ -687,12 +801,13 @@ grub_reiserfs_mount (grub_disk_t disk) if (grub_errno) goto fail; if (grub_memcmp (data->superblock.magic_string, - REISERFS_MAGIC_STRING, REISERFS_MAGIC_LEN)) + REISERFS_MAGIC_STRING, sizeof (REISERFS_MAGIC_STRING) - 1)) { grub_error (GRUB_ERR_BAD_FS, "not a reiserfs filesystem"); goto fail; } data->disk = disk; + grub_reiserfs_get_journal (data); return data; fail: @@ -740,8 +855,8 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item, struct grub_reiserfs_item_header *item_headers; grub_disk_read (data->disk, - (((grub_disk_addr_t) block_number * block_size) - >> GRUB_DISK_SECTOR_BITS), + grub_fshelp_map_block (data->journal, block_number, 0) + * (block_size >> GRUB_DISK_SECTOR_BITS), (((grub_off_t) block_number * block_size) & (GRUB_DISK_SECTOR_SIZE - 1)), block_size, (char *) block_header); @@ -835,7 +950,8 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item, { struct grub_reiserfs_stat_item_v1 entry_v1_stat; grub_disk_read (data->disk, - ((grub_disk_addr_t) entry_block_number * block_size) >> GRUB_DISK_SECTOR_BITS, + grub_fshelp_map_block (data->journal, entry_block_number, 0) + * (block_size >> GRUB_DISK_SECTOR_BITS), grub_le_to_cpu16 (entry_item->header.item_location), sizeof (entry_v1_stat), (char *) &entry_v1_stat); @@ -877,7 +993,8 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item, { struct grub_reiserfs_stat_item_v2 entry_v2_stat; grub_disk_read (data->disk, - ((grub_disk_addr_t) entry_block_number * block_size) >> GRUB_DISK_SECTOR_BITS, + grub_fshelp_map_block (data->journal, entry_block_number, 0) + * (block_size >> GRUB_DISK_SECTOR_BITS), grub_le_to_cpu16 (entry_item->header.item_location), sizeof (entry_v2_stat), (char *) &entry_v2_stat); @@ -1025,8 +1142,8 @@ grub_reiserfs_open (struct grub_file *file, const char *name) { struct grub_reiserfs_stat_item_v1 entry_v1_stat; grub_disk_read (data->disk, - (((grub_disk_addr_t) block_number * block_size) - >> GRUB_DISK_SECTOR_BITS), + grub_fshelp_map_block (data->journal, block_number, 0) + * (block_size >> GRUB_DISK_SECTOR_BITS), entry_location + (((grub_off_t) block_number * block_size) & (GRUB_DISK_SECTOR_SIZE - 1)), @@ -1039,8 +1156,8 @@ grub_reiserfs_open (struct grub_file *file, const char *name) { struct grub_reiserfs_stat_item_v2 entry_v2_stat; grub_disk_read (data->disk, - (((grub_disk_addr_t) block_number * block_size) - >> GRUB_DISK_SECTOR_BITS), + grub_fshelp_map_block (data->journal, block_number, 0) + * (block_size >> GRUB_DISK_SECTOR_BITS), entry_location + (((grub_off_t) block_number * block_size) & (GRUB_DISK_SECTOR_SIZE - 1)), @@ -1108,8 +1225,8 @@ grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len) switch (found.type) { case GRUB_REISERFS_DIRECT: - block = (((grub_disk_addr_t) found.block_number * block_size) - >> GRUB_DISK_SECTOR_BITS); + block = (grub_fshelp_map_block (data->journal, found.block_number, 0) + * (block_size >> GRUB_DISK_SECTOR_BITS)); grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block); if (initial_position < current_position + item_size) { @@ -1141,8 +1258,8 @@ grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len) if (! indirect_block_ptr) goto fail; grub_disk_read (found.data->disk, - (((grub_disk_addr_t) found.block_number * block_size) - >> GRUB_DISK_SECTOR_BITS), + grub_fshelp_map_block (data->journal, found.block_number, 0) + * (block_size >> GRUB_DISK_SECTOR_BITS), grub_le_to_cpu16 (found.header.item_location), item_size, (char *) indirect_block_ptr); if (grub_errno) @@ -1153,9 +1270,10 @@ grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len) && current_position < final_position; indirect_block++) { - block = ((grub_disk_addr_t) - grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) - * block_size) >> GRUB_DISK_SECTOR_BITS; + block = grub_fshelp_map_block (data->journal, + grub_le_to_cpu32 (indirect_block_ptr[indirect_block]), + 0) + * (block_size >> GRUB_DISK_SECTOR_BITS); grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block); if (current_position + block_size >= initial_position) { @@ -1254,6 +1372,7 @@ grub_reiserfs_close (grub_file_t file) struct grub_fshelp_node *node = file->data; struct grub_reiserfs_data *data = node->data; + grub_free (data->journal); grub_free (data); grub_free (node); #ifndef GRUB_UTIL ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH] Journal support for ext2 2008-02-17 22:34 ` Bean @ 2008-02-17 23:25 ` Bean 2008-02-20 21:37 ` Yoshinori K. Okuji 0 siblings, 1 reply; 16+ messages in thread From: Bean @ 2008-02-17 23:25 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 2434 bytes --] Some adjustment in this patch: as the get_block function is only used when journal type is GRUB_FSHELP_JOURNAL_TYPE_FILE, i move it to grub_fshelp_journal instead of using it as a parameter for grub_fshelp_map_block. also add changelog for reiserfs.c. 2008-02-18 Bean <bean123ch@gmail.com> * fs/fshelp.c (grub_fshelp_map_block): New function. * include/grub/fshelp.h (grub_fshelp_journal_type): New enum. (GRUB_FSHELP_JOURNAL_UNUSED_MAPPING): New macro. (grub_fshelp_journal): New structure. (grub_fshelp_map_block): New function prototype. * fs/ext2.c (EXT3_FEATURE_COMPAT_HAS_JOURNAL): New macro. (EXT3_JOURNAL_MAGIC_NUMBER): Likewise. (EXT3_JOURNAL_DESCRIPTOR_BLOCK): Likewise. (EXT3_JOURNAL_COMMIT_BLOCK): Likewise. (EXT3_JOURNAL_SUPERBLOCK_V1): Likewise. (EXT3_JOURNAL_SUPERBLOCK_V2): Likewise. (EXT3_JOURNAL_REVOKE_BLOCK): Likewise. (EXT3_JOURNAL_FLAG_ESCAPE): Likewise. (EXT3_JOURNAL_FLAG_SAME_UUID): Likewise. (EXT3_JOURNAL_FLAG_DELETED): Likewise. (EXT3_JOURNAL_FLAG_LAST_TAG): Likewise. (grub_ext2_sblock): New members for journal support. (grub_ext3_journal_header): New structure. (grub_ext3_journal_revoke_header): Likewise. (grub_ext3_journal_block_tag): Likewise. (grub_ext3_journal_sblock): Likewise. (grub_fshelp_node): New members logfile and journal. (grub_ext2_blockgroup): Use grub_fshelp_map_block to get real block number. (grub_ext2_read_block): Likewise. (grub_ext2_read_inode): Likewise. (grub_ext3_get_journal): New function. (grub_read_inode): Initialize journal using grub_ext3_get_journal. (grub_ext2_close): Release memory used by journal. * fs/reiserfs.c (REISERFS_MAGIC_STRING): Changed to "ReIsEr". (REISERFS_MAGIC_DESC_BLOCK): New macro. (grub_reiserfs_transaction_header): Renamed to grub_reiserfs_description_block, replace field data with real_blocks. (grub_reiserfs_commit_block): New structure. (grub_reiserfs_data): New member journal. (grub_reiserfs_get_item): Use grub_fshelp_map_block to get real block number. (grub_reiserfs_read_symlink): Likewise. (grub_reiserfs_iterate_dir): Likewise. (grub_reiserfs_open): Likewise. (grub_reiserfs_read): Likewise. (grub_reiserfs_get_journal): New function. (grub_reiserfs_mount): Use "ReIsEr" as super block magic, as there are three varieties ReIsErFs, ReIsEr2Fs and ReIsEr3Fs. Initialize journal using grub_reiserfs_get_journal. (grub_reiserfs_close): Release memory used by journal. -- Bean [-- Attachment #2: jour2.diff --] [-- Type: text/plain, Size: 25163 bytes --] diff --git a/fs/ext2.c b/fs/ext2.c index ec66582..5dffd69 100644 --- a/fs/ext2.c +++ b/fs/ext2.c @@ -71,6 +71,21 @@ ? EXT2_GOOD_OLD_INODE_SIZE \ : grub_le_to_cpu16 (data->sblock.inode_size)) +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 + +#define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U + +#define EXT3_JOURNAL_DESCRIPTOR_BLOCK 1 +#define EXT3_JOURNAL_COMMIT_BLOCK 2 +#define EXT3_JOURNAL_SUPERBLOCK_V1 3 +#define EXT3_JOURNAL_SUPERBLOCK_V2 4 +#define EXT3_JOURNAL_REVOKE_BLOCK 5 + +#define EXT3_JOURNAL_FLAG_ESCAPE 1 +#define EXT3_JOURNAL_FLAG_SAME_UUID 2 +#define EXT3_JOURNAL_FLAG_DELETED 4 +#define EXT3_JOURNAL_FLAG_LAST_TAG 8 + /* The ext2 superblock. */ struct grub_ext2_sblock { @@ -109,6 +124,21 @@ struct grub_ext2_sblock char volume_name[16]; char last_mounted_on[64]; grub_uint32_t compression_info; + grub_uint8_t prealloc_blocks; + grub_uint8_t prealloc_dir_blocks; + grub_uint16_t reserved_gdt_blocks; + grub_uint8_t journal_uuid[16]; + grub_uint32_t journal_inum; + grub_uint32_t journal_dev; + grub_uint32_t last_orphan; + grub_uint32_t hash_seed[4]; + grub_uint8_t def_hash_version; + grub_uint8_t jnl_backup_type; + grub_uint16_t reserved_word_pad; + grub_uint32_t default_mount_opts; + grub_uint32_t first_meta_bg; + grub_uint32_t mkfs_time; + grub_uint32_t jnl_blocks[17]; }; /* The ext2 blockgroup. */ @@ -166,6 +196,36 @@ struct ext2_dirent grub_uint8_t filetype; }; +struct grub_ext3_journal_header +{ + grub_uint32_t magic; + grub_uint32_t block_type; + grub_uint32_t sequence; +}; + +struct grub_ext3_journal_revoke_header +{ + struct grub_ext3_journal_header header; + grub_uint32_t count; + grub_uint32_t data[0]; +}; + +struct grub_ext3_journal_block_tag +{ + grub_uint32_t block; + grub_uint32_t flags; +}; + +struct grub_ext3_journal_sblock +{ + struct grub_ext3_journal_header header; + grub_uint32_t block_size; + grub_uint32_t maxlen; + grub_uint32_t first; + grub_uint32_t sequence; + grub_uint32_t start; +}; + struct grub_fshelp_node { struct grub_ext2_data *data; @@ -181,6 +241,8 @@ struct grub_ext2_data grub_disk_t disk; struct grub_ext2_inode *inode; struct grub_fshelp_node diropen; + struct grub_fshelp_node logfile; + grub_fshelp_journal_t journal; }; #ifndef GRUB_UTIL @@ -196,7 +258,8 @@ grub_ext2_blockgroup (struct grub_ext2_data *data, int group, struct grub_ext2_block_group *blkgrp) { return grub_disk_read (data->disk, - ((grub_le_to_cpu32 (data->sblock.first_data_block) + 1) + (grub_fshelp_map_block (data->journal, + grub_le_to_cpu32 (data->sblock.first_data_block) + 1) << LOG2_EXT2_BLOCK_SIZE (data)), group * sizeof (struct grub_ext2_block_group), sizeof (struct grub_ext2_block_group), (char *) blkgrp); @@ -221,7 +284,8 @@ grub_ext2_read_block (grub_fshelp_node_t node, int fileblock) grub_uint32_t indir[blksz / 4]; if (grub_disk_read (data->disk, - grub_le_to_cpu32 (inode->blocks.indir_block) + grub_fshelp_map_block(data->journal, + grub_le_to_cpu32 (inode->blocks.indir_block)) << log2_blksz, 0, blksz, (char *) indir)) return grub_errno; @@ -237,13 +301,15 @@ grub_ext2_read_block (grub_fshelp_node_t node, int fileblock) grub_uint32_t indir[blksz / 4]; if (grub_disk_read (data->disk, - grub_le_to_cpu32 (inode->blocks.double_indir_block) + grub_fshelp_map_block(data->journal, + grub_le_to_cpu32 (inode->blocks.double_indir_block)) << log2_blksz, 0, blksz, (char *) indir)) return grub_errno; if (grub_disk_read (data->disk, - grub_le_to_cpu32 (indir[rblock / perblock]) + grub_fshelp_map_block(data->journal, + grub_le_to_cpu32 (indir[rblock / perblock])) << log2_blksz, 0, blksz, (char *) indir)) return grub_errno; @@ -259,10 +325,9 @@ grub_ext2_read_block (grub_fshelp_node_t node, int fileblock) blknr = -1; } - return blknr; + return grub_fshelp_map_block (data->journal, blknr); } - /* Read LEN bytes from the file described by DATA starting with byte POS. Return the amount of read bytes in READ. */ static grub_ssize_t @@ -308,8 +373,9 @@ grub_ext2_read_inode (struct grub_ext2_data *data, /* Read the inode. */ if (grub_disk_read (data->disk, - ((grub_le_to_cpu32 (blkgrp.inode_table_id) + blkno) - << LOG2_EXT2_BLOCK_SIZE (data)), + grub_fshelp_map_block(data->journal, + grub_le_to_cpu32 (blkgrp.inode_table_id) + blkno) + << LOG2_EXT2_BLOCK_SIZE (data), EXT2_INODE_SIZE (data) * blkoff, sizeof (struct grub_ext2_inode), (char *) inode)) return grub_errno; @@ -317,6 +383,164 @@ grub_ext2_read_inode (struct grub_ext2_data *data, return 0; } +static void +grub_ext3_get_journal (struct grub_ext2_data *data) +{ + char buf[1 << LOG2_BLOCK_SIZE (data)]; + struct grub_ext3_journal_sblock *jsb; + grub_fshelp_journal_t log; + int last_num, num, block, log2bs; + grub_uint32_t seq; + + auto void next_block (void); + void next_block (void) + { + block++; + if (block >= log->last_block) + block = log->first_block; + } + + data->journal = 0; + + if (! (data->sblock.feature_compatibility & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) + return; + + if (! data->sblock.journal_inum) + return; + + data->logfile.data = data; + data->logfile.ino = data->sblock.journal_inum; + data->logfile.inode_read = 1; + + if (grub_ext2_read_inode (data, data->logfile.ino, &data->logfile.inode)) + return; + + log2bs = LOG2_EXT2_BLOCK_SIZE (data); + if (grub_fshelp_read_file (data->disk, &data->logfile, 0, + 0, sizeof (struct grub_ext3_journal_sblock), + buf, grub_ext2_read_block, + sizeof (buf), log2bs) != + sizeof (struct grub_ext3_journal_sblock)) + return; + + jsb = (struct grub_ext3_journal_sblock *) &buf[0]; + if (grub_be_to_cpu32 (jsb->header.magic) != EXT3_JOURNAL_MAGIC_NUMBER) + return; + + /* Empty journal. */ + if (! jsb->start) + return; + + log = grub_malloc (sizeof (struct grub_fshelp_journal) + + grub_be_to_cpu32 (jsb->maxlen) * sizeof (grub_uint32_t)); + if (! log) + return; + + log->type = GRUB_FSHELP_JOURNAL_TYPE_FILE; + log->node = &data->logfile; + log->get_block = grub_ext2_read_block; + log->first_block = grub_be_to_cpu32 (jsb->first); + log->last_block = grub_be_to_cpu32 (jsb->maxlen); + log->start_block = grub_be_to_cpu32 (jsb->start); + + last_num = num = 0; + block = log->start_block; + seq = grub_be_to_cpu32 (jsb->sequence); + + while (1) + { + struct grub_ext3_journal_header *jh; + + if (grub_fshelp_read_file (data->disk, &data->logfile, 0, + block << (log2bs + 9), sizeof (buf), + buf, grub_ext2_read_block, + log->last_block << (log2bs + 9), + log2bs) != + (int) sizeof (buf)) + break; + + jh = (struct grub_ext3_journal_header *) &buf[0]; + if (grub_be_to_cpu32 (jh->magic) != EXT3_JOURNAL_MAGIC_NUMBER) + break; + + if (grub_be_to_cpu32 (jh->sequence) != seq) + break; + + log->mapping[num++] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING; + next_block(); + + switch (grub_be_to_cpu32 (jh->block_type)) + { + case EXT3_JOURNAL_DESCRIPTOR_BLOCK: + { + struct grub_ext3_journal_block_tag *tag; + int ofs, flags; + + ofs = sizeof (struct grub_ext3_journal_header); + + do + { + tag = (struct grub_ext3_journal_block_tag *) &buf[ofs]; + ofs += sizeof (struct grub_ext3_journal_block_tag); + + if (ofs > (int) sizeof (buf)) + break; + + flags = grub_be_to_cpu32 (tag->flags); + if (! (flags & EXT3_JOURNAL_FLAG_SAME_UUID)) + ofs += 16; + + log->mapping[num++] = grub_be_to_cpu32 (tag->block); + next_block(); + } + while (! (flags & EXT3_JOURNAL_FLAG_LAST_TAG)); + + continue; + } + + case EXT3_JOURNAL_COMMIT_BLOCK: + { + seq++; + last_num = num - 1; + continue; + } + + case EXT3_JOURNAL_REVOKE_BLOCK: + { + struct grub_ext3_journal_revoke_header *jrh; + grub_uint32_t i; + + jrh = (struct grub_ext3_journal_revoke_header *) jh; + + for (i = 0; i < grub_be_to_cpu32 (jrh->count); i++) + { + int j; + grub_uint32_t map; + + map = grub_be_to_cpu32 (jrh->data[i]); + for (j = 0; j < num; j++) + if (log->mapping[j] == map) + log->mapping[j] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING; + } + + continue; + } + default: + last_num = 0; + goto quit; + } + } + +quit: + if (! last_num) + grub_free (log); + else + { + log->num_mappings = last_num; + data->journal = log; + } +} + static struct grub_ext2_data * grub_ext2_mount (grub_disk_t disk) { @@ -336,12 +560,14 @@ grub_ext2_mount (grub_disk_t disk) if (grub_le_to_cpu16 (data->sblock.magic) != EXT2_MAGIC) goto fail; + data->disk = disk; + grub_ext3_get_journal (data); + data->diropen.data = data; data->diropen.ino = 2; data->diropen.inode_read = 1; data->inode = &data->diropen.inode; - data->disk = disk; grub_ext2_read_inode (data, 2, data->inode); if (grub_errno) @@ -540,7 +766,11 @@ grub_ext2_open (struct grub_file *file, const char *name) static grub_err_t grub_ext2_close (grub_file_t file) { - grub_free (file->data); + if (file->data) + { + grub_free (((struct grub_ext2_data *) file->data)->journal); + grub_free (file->data); + } #ifndef GRUB_UTIL grub_dl_unref (my_mod); diff --git a/fs/fshelp.c b/fs/fshelp.c index bbb58ac..d3c2423 100644 --- a/fs/fshelp.c +++ b/fs/fshelp.c @@ -72,7 +72,7 @@ grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode, void free_node (grub_fshelp_node_t node) { - if (node != rootnode && node != currroot) + if (node != rootnode && node != currroot) grub_free (node); } @@ -310,3 +310,30 @@ grub_fshelp_log2blksize (unsigned int blksize, unsigned int *pow) return GRUB_ERR_NONE; } + +int +grub_fshelp_map_block (grub_fshelp_journal_t log, int block) +{ + int map_block; + + if ((! log) || (log->type == GRUB_FSHELP_JOURNAL_TYPE_NONE)) + return block; + + for (map_block = log->num_mappings - 1; map_block >= 0; map_block--) + { + if ((int) log->mapping[map_block] == block) + break; + } + + if (map_block < 0) + return block; + + map_block += log->start_block; + if (map_block >= log->last_block) + map_block -= log->last_block - log->first_block; + + if (log->type == GRUB_FSHELP_JOURNAL_TYPE_BLOCK) + return log->blkno + map_block; + else + return log->get_block (log->node, map_block); +} diff --git a/fs/reiserfs.c b/fs/reiserfs.c index a4c60ca..79e559a 100644 --- a/fs/reiserfs.c +++ b/fs/reiserfs.c @@ -52,7 +52,8 @@ #define REISERFS_SUPER_BLOCK_OFFSET 0x10000 #define REISERFS_MAGIC_LEN 12 -#define REISERFS_MAGIC_STRING "ReIsEr2Fs\0\0\0" +#define REISERFS_MAGIC_STRING "ReIsEr" +#define REISERFS_MAGIC_DESC_BLOCK "ReIsErLB" /* If the 3rd bit of an item state is set, then it's visible. */ #define GRUB_REISERFS_VISIBLE_MASK ((grub_uint16_t) 0x04) #define REISERFS_MAX_LABEL_LENGTH 16 @@ -109,8 +110,6 @@ struct grub_reiserfs_superblock grub_uint32_t inode_generation; } __attribute__ ((packed)); -#ifdef GRUB_REISERFS_JOURNALING -# error "Journaling not yet supported." struct grub_reiserfs_journal_header { grub_uint32_t last_flush_uid; @@ -118,15 +117,20 @@ struct grub_reiserfs_journal_header grub_uint32_t mount_id; } __attribute__ ((packed)); -struct grub_reiserfs_transaction_header +struct grub_reiserfs_description_block { grub_uint32_t id; grub_uint32_t len; grub_uint32_t mount_id; - char *data; - char checksum[12]; + grub_uint32_t real_blocks[0]; +} __attribute__ ((packed)); + +struct grub_reiserfs_commit_block +{ + grub_uint32_t id; + grub_uint32_t len; + grub_uint32_t real_blocks[0]; } __attribute__ ((packed)); -#endif struct grub_reiserfs_stat_item_v1 { @@ -228,6 +232,7 @@ struct grub_reiserfs_data { struct grub_reiserfs_superblock superblock; grub_disk_t disk; + grub_fshelp_journal_t journal; }; /* Internal-only functions. Not to be used outside of this file. */ @@ -504,8 +509,8 @@ grub_reiserfs_get_item (struct grub_reiserfs_data *data, do { grub_disk_read (data->disk, - (((grub_disk_addr_t) block_number * block_size) - >> GRUB_DISK_SECTOR_BITS), + grub_fshelp_map_block (data->journal, block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS), (((grub_off_t) block_number * block_size) & (GRUB_DISK_SECTOR_SIZE - 1)), block_size, (char *) block_header); @@ -655,8 +660,8 @@ grub_reiserfs_read_symlink (grub_fshelp_node_t node) block_size = grub_le_to_cpu16 (node->data->superblock.block_size); len = grub_le_to_cpu16 (found.header.item_size); - block = (((grub_disk_addr_t) found.block_number * block_size) - >> GRUB_DISK_SECTOR_BITS); + block = (grub_fshelp_map_block (node->data->journal, found.block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS)); offset = grub_le_to_cpu16 (found.header.item_location); symlink_buffer = grub_malloc (len); @@ -674,6 +679,115 @@ grub_reiserfs_read_symlink (grub_fshelp_node_t node) return 0; } +static void +grub_reiserfs_get_journal (struct grub_reiserfs_data *data) +{ + int block_size = grub_le_to_cpu16 (data->superblock.block_size); + char buf[block_size]; + struct grub_reiserfs_journal_header *jh; + grub_fshelp_journal_t log; + grub_uint32_t seq_id, mount_id; + int num_blocks = grub_le_to_cpu32 (data->superblock.journal_original_size); + int base_block = grub_le_to_cpu32 (data->superblock.journal_block); + int last_num, num, block; + + data->journal = 0; + + if (! data->superblock.journal_block) + return; + + if (grub_disk_read (data->disk, + (base_block + num_blocks) + * (block_size >> GRUB_DISK_SECTOR_BITS), + 0, sizeof (struct grub_reiserfs_journal_header), + buf)) + return; + + log = grub_malloc (sizeof (struct grub_fshelp_journal) + + num_blocks * sizeof (grub_uint32_t)); + if (! log) + return; + + jh = (struct grub_reiserfs_journal_header *) &buf[0]; + + log->type = GRUB_FSHELP_JOURNAL_TYPE_BLOCK; + log->blkno = base_block; + log->first_block = 0; + log->last_block = num_blocks; + log->start_block = grub_le_to_cpu32 (jh->unflushed_offset); + + seq_id = grub_le_to_cpu32 (jh->last_flush_uid); + mount_id = grub_le_to_cpu32 (jh->mount_id); + + last_num = num = 0; + block = log->start_block; + + while (1) + { + struct grub_reiserfs_description_block *db; + struct grub_reiserfs_commit_block *cb; + grub_uint32_t i, len, half_len, id; + + if (grub_disk_read (data->disk, + (base_block + block) + * (block_size >> GRUB_DISK_SECTOR_BITS), + 0, sizeof (buf), buf)) + break; + + if (grub_memcmp (&buf[block_size - REISERFS_MAGIC_LEN], + REISERFS_MAGIC_DESC_BLOCK, + sizeof (REISERFS_MAGIC_DESC_BLOCK) - 1)) + break; + + db = (struct grub_reiserfs_description_block *) &buf[0]; + id = grub_le_to_cpu32 (db->id); + len = grub_le_to_cpu32 (db->len); + if ((grub_le_to_cpu32 (db->id) <= seq_id) && (id <= mount_id)) + break; + + log->mapping[num++] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING; + half_len = ((block_size - 24) >> 2); + if (half_len > len) + half_len = len; + + for (i = 0; i < half_len; i++) + log->mapping[num++] = db->real_blocks[i]; + + block += grub_le_to_cpu32 (db->len) + 1; + if (block >= log->last_block) + block -= log->last_block; + + if (grub_disk_read (data->disk, + (base_block + block) + * (block_size >> GRUB_DISK_SECTOR_BITS), + 0, sizeof (buf), buf)) + break; + + cb = (struct grub_reiserfs_commit_block *) &buf[0]; + if ((grub_le_to_cpu32 (cb->id) != id) || + (grub_le_to_cpu32 (cb->len) != len)) + break; + + for (i = 0; i < len - half_len; i++) + log->mapping[num++] = cb->real_blocks[i]; + + last_num = num; + log->mapping[num++] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING; + + block++; + if (block >= log->last_block) + block -= log->last_block; + }; + + if (! last_num) + grub_free (log); + else + { + log->num_mappings = last_num; + data->journal = log; + } +} + /* Fill the mounted filesystem structure and return it. */ static struct grub_reiserfs_data * grub_reiserfs_mount (grub_disk_t disk) @@ -687,12 +801,13 @@ grub_reiserfs_mount (grub_disk_t disk) if (grub_errno) goto fail; if (grub_memcmp (data->superblock.magic_string, - REISERFS_MAGIC_STRING, REISERFS_MAGIC_LEN)) + REISERFS_MAGIC_STRING, sizeof (REISERFS_MAGIC_STRING) - 1)) { grub_error (GRUB_ERR_BAD_FS, "not a reiserfs filesystem"); goto fail; } data->disk = disk; + grub_reiserfs_get_journal (data); return data; fail: @@ -740,8 +855,8 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item, struct grub_reiserfs_item_header *item_headers; grub_disk_read (data->disk, - (((grub_disk_addr_t) block_number * block_size) - >> GRUB_DISK_SECTOR_BITS), + grub_fshelp_map_block (data->journal, block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS), (((grub_off_t) block_number * block_size) & (GRUB_DISK_SECTOR_SIZE - 1)), block_size, (char *) block_header); @@ -835,7 +950,8 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item, { struct grub_reiserfs_stat_item_v1 entry_v1_stat; grub_disk_read (data->disk, - ((grub_disk_addr_t) entry_block_number * block_size) >> GRUB_DISK_SECTOR_BITS, + grub_fshelp_map_block (data->journal, entry_block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS), grub_le_to_cpu16 (entry_item->header.item_location), sizeof (entry_v1_stat), (char *) &entry_v1_stat); @@ -877,7 +993,8 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item, { struct grub_reiserfs_stat_item_v2 entry_v2_stat; grub_disk_read (data->disk, - ((grub_disk_addr_t) entry_block_number * block_size) >> GRUB_DISK_SECTOR_BITS, + grub_fshelp_map_block (data->journal, entry_block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS), grub_le_to_cpu16 (entry_item->header.item_location), sizeof (entry_v2_stat), (char *) &entry_v2_stat); @@ -1025,8 +1142,8 @@ grub_reiserfs_open (struct grub_file *file, const char *name) { struct grub_reiserfs_stat_item_v1 entry_v1_stat; grub_disk_read (data->disk, - (((grub_disk_addr_t) block_number * block_size) - >> GRUB_DISK_SECTOR_BITS), + grub_fshelp_map_block (data->journal, block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS), entry_location + (((grub_off_t) block_number * block_size) & (GRUB_DISK_SECTOR_SIZE - 1)), @@ -1039,8 +1156,8 @@ grub_reiserfs_open (struct grub_file *file, const char *name) { struct grub_reiserfs_stat_item_v2 entry_v2_stat; grub_disk_read (data->disk, - (((grub_disk_addr_t) block_number * block_size) - >> GRUB_DISK_SECTOR_BITS), + grub_fshelp_map_block (data->journal, block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS), entry_location + (((grub_off_t) block_number * block_size) & (GRUB_DISK_SECTOR_SIZE - 1)), @@ -1108,8 +1225,8 @@ grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len) switch (found.type) { case GRUB_REISERFS_DIRECT: - block = (((grub_disk_addr_t) found.block_number * block_size) - >> GRUB_DISK_SECTOR_BITS); + block = (grub_fshelp_map_block (data->journal, found.block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS)); grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block); if (initial_position < current_position + item_size) { @@ -1141,8 +1258,8 @@ grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len) if (! indirect_block_ptr) goto fail; grub_disk_read (found.data->disk, - (((grub_disk_addr_t) found.block_number * block_size) - >> GRUB_DISK_SECTOR_BITS), + grub_fshelp_map_block (data->journal, found.block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS), grub_le_to_cpu16 (found.header.item_location), item_size, (char *) indirect_block_ptr); if (grub_errno) @@ -1153,9 +1270,9 @@ grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len) && current_position < final_position; indirect_block++) { - block = ((grub_disk_addr_t) - grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) - * block_size) >> GRUB_DISK_SECTOR_BITS; + block = (grub_fshelp_map_block (data->journal, + grub_le_to_cpu32 (indirect_block_ptr[indirect_block])) * + (block_size >> GRUB_DISK_SECTOR_BITS)); grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block); if (current_position + block_size >= initial_position) { @@ -1254,6 +1371,7 @@ grub_reiserfs_close (grub_file_t file) struct grub_fshelp_node *node = file->data; struct grub_reiserfs_data *data = node->data; + grub_free (data->journal); grub_free (data); grub_free (node); #ifndef GRUB_UTIL diff --git a/include/grub/fshelp.h b/include/grub/fshelp.h index e25dd16..d575007 100644 --- a/include/grub/fshelp.h +++ b/include/grub/fshelp.h @@ -34,6 +34,35 @@ enum grub_fshelp_filetype GRUB_FSHELP_SYMLINK }; +enum grub_fshelp_journal_type + { + GRUB_FSHELP_JOURNAL_TYPE_NONE, + GRUB_FSHELP_JOURNAL_TYPE_BLOCK, + GRUB_FSHELP_JOURNAL_TYPE_FILE + }; + +#define GRUB_FSHELP_JOURNAL_UNUSED_MAPPING (grub_uint32_t) -1 + +struct grub_fshelp_journal +{ + int type; + union + { + struct + { + grub_fshelp_node_t node; + int (*get_block) (grub_fshelp_node_t node, int block); + }; + grub_uint32_t blkno; + }; + int first_block; + int last_block; + int start_block; + int num_mappings; + grub_uint32_t mapping[0]; +}; +typedef struct grub_fshelp_journal *grub_fshelp_journal_t; + /* Lookup the node PATH. The node ROOTNODE describes the root of the directory tree. The node found is returned in FOUNDNODE, which is either a ROOTNODE or a new malloc'ed node. ITERATE_DIR is used to @@ -75,4 +104,7 @@ unsigned int EXPORT_FUNC(grub_fshelp_log2blksize) (unsigned int blksize, unsigned int *pow); +int +EXPORT_FUNC(grub_fshelp_map_block) (grub_fshelp_journal_t log, int block); + #endif /* ! GRUB_FSHELP_HEADER */ ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH] Journal support for ext2 2008-02-17 23:25 ` Bean @ 2008-02-20 21:37 ` Yoshinori K. Okuji 2008-02-21 3:12 ` Bean 0 siblings, 1 reply; 16+ messages in thread From: Yoshinori K. Okuji @ 2008-02-20 21:37 UTC (permalink / raw) To: The development of GRUB 2 On Monday 18 February 2008 00:25, Bean wrote: > Some adjustment in this patch: as the get_block function is only used > when journal type is GRUB_FSHELP_JOURNAL_TYPE_FILE, i move it to > grub_fshelp_journal instead of using it as a parameter for > grub_fshelp_map_block. also add changelog for reiserfs.c. Thanks for your effort. However, I don't like one part. It is about types. Although I understand why you did this way, it is not a good thing that you use "int" for block addressing. This is a fundamental issue in fshelp. Because of this, filesystem support is not 64-bit safe. I don't urge you to fix everything, but please don't increase the mess. Okuji ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Journal support for ext2 2008-02-20 21:37 ` Yoshinori K. Okuji @ 2008-02-21 3:12 ` Bean 2008-02-21 21:16 ` Yoshinori K. Okuji 0 siblings, 1 reply; 16+ messages in thread From: Bean @ 2008-02-21 3:12 UTC (permalink / raw) To: The development of GRUB 2 On Thu, Feb 21, 2008 at 5:37 AM, Yoshinori K. Okuji <okuji@enbug.org> wrote: > On Monday 18 February 2008 00:25, Bean wrote: > > Some adjustment in this patch: as the get_block function is only used > > when journal type is GRUB_FSHELP_JOURNAL_TYPE_FILE, i move it to > > grub_fshelp_journal instead of using it as a parameter for > > grub_fshelp_map_block. also add changelog for reiserfs.c. > > Thanks for your effort. However, I don't like one part. It is about types. > Although I understand why you did this way, it is not a good thing that you > use "int" for block addressing. This is a fundamental issue in fshelp. > Because of this, filesystem support is not 64-bit safe. > > I don't urge you to fix everything, but please don't increase the mess. Ok, perhaps i can change all the block type to grub_uint64_t while i'm fixing this ? -- Bean ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Journal support for ext2 2008-02-21 3:12 ` Bean @ 2008-02-21 21:16 ` Yoshinori K. Okuji 2008-03-05 17:24 ` Bean 0 siblings, 1 reply; 16+ messages in thread From: Yoshinori K. Okuji @ 2008-02-21 21:16 UTC (permalink / raw) To: The development of GRUB 2 On Thursday 21 February 2008 04:12, Bean wrote: > On Thu, Feb 21, 2008 at 5:37 AM, Yoshinori K. Okuji <okuji@enbug.org> wrote: > > On Monday 18 February 2008 00:25, Bean wrote: > > > Some adjustment in this patch: as the get_block function is only used > > > when journal type is GRUB_FSHELP_JOURNAL_TYPE_FILE, i move it to > > > grub_fshelp_journal instead of using it as a parameter for > > > grub_fshelp_map_block. also add changelog for reiserfs.c. > > > > Thanks for your effort. However, I don't like one part. It is about > > types. Although I understand why you did this way, it is not a good thing > > that you use "int" for block addressing. This is a fundamental issue in > > fshelp. Because of this, filesystem support is not 64-bit safe. > > > > I don't urge you to fix everything, but please don't increase the mess. > > Ok, perhaps i can change all the block type to grub_uint64_t while i'm > fixing this ? Great. :) Okuji ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Journal support for ext2 2008-02-21 21:16 ` Yoshinori K. Okuji @ 2008-03-05 17:24 ` Bean 2008-03-14 6:11 ` Bean 0 siblings, 1 reply; 16+ messages in thread From: Bean @ 2008-03-05 17:24 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 3031 bytes --] Hi, I have converted all block type in fshelp to grub_disk_addr_t, the file system driver should be 64-bit enabled by now. 2008-03-05 Bean <bean123ch@gmail.com> * fs/fshelp.c (grub_fshelp_map_block): New function. (grub_fshelp_find_file): Use 64-bit type for pos and block address. Use `>>' and `&' operator to avoid 64-bit divide and modulo. * include/grub/fshelp.h (grub_fshelp_journal_type): New enum. (GRUB_FSHELP_JOURNAL_UNUSED_MAPPING): New macro. (grub_fshelp_journal): New structure. (grub_fshelp_map_block): New function prototype. (grub_fshelp_read_file): Use grub_disk_addr_t as block type. (grub_fshelp_map_block): Likewise. * fs/ext2.c (EXT3_FEATURE_COMPAT_HAS_JOURNAL): New macro. (EXT3_JOURNAL_MAGIC_NUMBER): Likewise. (EXT3_JOURNAL_DESCRIPTOR_BLOCK): Likewise. (EXT3_JOURNAL_COMMIT_BLOCK): Likewise. (EXT3_JOURNAL_SUPERBLOCK_V1): Likewise. (EXT3_JOURNAL_SUPERBLOCK_V2): Likewise. (EXT3_JOURNAL_REVOKE_BLOCK): Likewise. (EXT3_JOURNAL_FLAG_ESCAPE): Likewise. (EXT3_JOURNAL_FLAG_SAME_UUID): Likewise. (EXT3_JOURNAL_FLAG_DELETED): Likewise. (EXT3_JOURNAL_FLAG_LAST_TAG): Likewise. (grub_ext2_sblock): New members for journal support. (grub_ext3_journal_header): New structure. (grub_ext3_journal_revoke_header): Likewise. (grub_ext3_journal_block_tag): Likewise. (grub_ext3_journal_sblock): Likewise. (grub_fshelp_node): New members logfile and journal. (grub_ext2_read_block): Change block type to grub_disk_addr_t. Use grub_fshelp_map_block to get real block number. (grub_ext2_blockgroup): Use grub_fshelp_map_block to get real block number. (grub_ext2_read_inode): Likewise. (grub_ext3_get_journal): New function. (grub_read_inode): Initialize journal using grub_ext3_get_journal. (grub_ext2_close): Release memory used by journal. * fs/reiserfs.c (REISERFS_MAGIC_STRING): Changed to "ReIsEr". (REISERFS_MAGIC_DESC_BLOCK): New macro. (grub_reiserfs_transaction_header): Renamed to grub_reiserfs_description_block, replace field data with real_blocks. (grub_reiserfs_commit_block): New structure. (grub_reiserfs_data): New member journal. (grub_reiserfs_get_item): Use grub_fshelp_map_block to get real block number. (grub_reiserfs_read_symlink): Likewise. (grub_reiserfs_iterate_dir): Likewise. (grub_reiserfs_open): Likewise. (grub_reiserfs_read): Likewise. (grub_reiserfs_get_journal): New function. (grub_reiserfs_mount): Use "ReIsEr" as super block magic, as there are three varieties ReIsErFs, ReIsEr2Fs and ReIsEr3Fs. Initialize journal using grub_reiserfs_get_journal. (grub_reiserfs_close): Release memory used by journal. * fs/affs.c (grub_affs_read_block): Change block type to grub_disk_addr_t. Use type cast to avoid 64-bit divide and modulo. * fs/hfsplus.c (grub_hfsplus_read_block): Change block type to grub_disk_addr_t. * fs/ntfs.c (grub_ntfs_read_block): Likewise. * fs/udf.c (grub_udf_read_block): Change block type to grub_disk_addr_t. Use type cast to avoid warning. * fs/xfs.c (grub_xfs_read_block): Likewise. -- Bean [-- Attachment #2: jour3.diff --] [-- Type: application/octet-stream, Size: 34068 bytes --] diff --git a/fs/affs.c b/fs/affs.c index 8ebfa40..e02bbc3 100644 --- a/fs/affs.c +++ b/fs/affs.c @@ -109,8 +109,8 @@ static grub_dl_t my_mod; #endif \f -static int -grub_affs_read_block (grub_fshelp_node_t node, int fileblock) +static grub_disk_addr_t +grub_affs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) { int links; grub_uint32_t pos; @@ -120,7 +120,7 @@ grub_affs_read_block (grub_fshelp_node_t node, int fileblock) /* Find the block that points to the fileblock we are looking up by following the chain until the right table is reached. */ - for (links = fileblock / (data->htsize); links; links--) + for (links = (grub_uint32_t) fileblock / (data->htsize); links; links--) { grub_disk_read (data->disk, block + data->blocksize - 1, data->blocksize * (GRUB_DISK_SECTOR_SIZE @@ -133,7 +133,7 @@ grub_affs_read_block (grub_fshelp_node_t node, int fileblock) } /* Translate the fileblock to the block within the right table. */ - fileblock = fileblock % (data->htsize); + fileblock = (grub_uint32_t) fileblock % data->htsize; grub_disk_read (data->disk, block, GRUB_AFFS_BLOCKPTR_OFFSET + (data->htsize - fileblock - 1) * sizeof (pos), @@ -567,4 +567,3 @@ GRUB_MOD_FINI(affs) { grub_fs_unregister (&grub_affs_fs); } - diff --git a/fs/ext2.c b/fs/ext2.c index ec66582..ce7b2fa 100644 --- a/fs/ext2.c +++ b/fs/ext2.c @@ -71,6 +71,21 @@ ? EXT2_GOOD_OLD_INODE_SIZE \ : grub_le_to_cpu16 (data->sblock.inode_size)) +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 + +#define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U + +#define EXT3_JOURNAL_DESCRIPTOR_BLOCK 1 +#define EXT3_JOURNAL_COMMIT_BLOCK 2 +#define EXT3_JOURNAL_SUPERBLOCK_V1 3 +#define EXT3_JOURNAL_SUPERBLOCK_V2 4 +#define EXT3_JOURNAL_REVOKE_BLOCK 5 + +#define EXT3_JOURNAL_FLAG_ESCAPE 1 +#define EXT3_JOURNAL_FLAG_SAME_UUID 2 +#define EXT3_JOURNAL_FLAG_DELETED 4 +#define EXT3_JOURNAL_FLAG_LAST_TAG 8 + /* The ext2 superblock. */ struct grub_ext2_sblock { @@ -109,6 +124,21 @@ struct grub_ext2_sblock char volume_name[16]; char last_mounted_on[64]; grub_uint32_t compression_info; + grub_uint8_t prealloc_blocks; + grub_uint8_t prealloc_dir_blocks; + grub_uint16_t reserved_gdt_blocks; + grub_uint8_t journal_uuid[16]; + grub_uint32_t journal_inum; + grub_uint32_t journal_dev; + grub_uint32_t last_orphan; + grub_uint32_t hash_seed[4]; + grub_uint8_t def_hash_version; + grub_uint8_t jnl_backup_type; + grub_uint16_t reserved_word_pad; + grub_uint32_t default_mount_opts; + grub_uint32_t first_meta_bg; + grub_uint32_t mkfs_time; + grub_uint32_t jnl_blocks[17]; }; /* The ext2 blockgroup. */ @@ -166,6 +196,36 @@ struct ext2_dirent grub_uint8_t filetype; }; +struct grub_ext3_journal_header +{ + grub_uint32_t magic; + grub_uint32_t block_type; + grub_uint32_t sequence; +}; + +struct grub_ext3_journal_revoke_header +{ + struct grub_ext3_journal_header header; + grub_uint32_t count; + grub_uint32_t data[0]; +}; + +struct grub_ext3_journal_block_tag +{ + grub_uint32_t block; + grub_uint32_t flags; +}; + +struct grub_ext3_journal_sblock +{ + struct grub_ext3_journal_header header; + grub_uint32_t block_size; + grub_uint32_t maxlen; + grub_uint32_t first; + grub_uint32_t sequence; + grub_uint32_t start; +}; + struct grub_fshelp_node { struct grub_ext2_data *data; @@ -181,6 +241,8 @@ struct grub_ext2_data grub_disk_t disk; struct grub_ext2_inode *inode; struct grub_fshelp_node diropen; + struct grub_fshelp_node logfile; + grub_fshelp_journal_t journal; }; #ifndef GRUB_UTIL @@ -196,20 +258,21 @@ grub_ext2_blockgroup (struct grub_ext2_data *data, int group, struct grub_ext2_block_group *blkgrp) { return grub_disk_read (data->disk, - ((grub_le_to_cpu32 (data->sblock.first_data_block) + 1) + (grub_fshelp_map_block (data->journal, + grub_le_to_cpu32 (data->sblock.first_data_block) + 1) << LOG2_EXT2_BLOCK_SIZE (data)), group * sizeof (struct grub_ext2_block_group), sizeof (struct grub_ext2_block_group), (char *) blkgrp); } -static int -grub_ext2_read_block (grub_fshelp_node_t node, int fileblock) +static grub_disk_addr_t +grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) { struct grub_ext2_data *data = node->data; struct grub_ext2_inode *inode = &node->inode; int blknr; - int blksz = EXT2_BLOCK_SIZE (data); + unsigned int blksz = EXT2_BLOCK_SIZE (data); int log2_blksz = LOG2_EXT2_BLOCK_SIZE (data); /* Direct blocks. */ @@ -221,7 +284,8 @@ grub_ext2_read_block (grub_fshelp_node_t node, int fileblock) grub_uint32_t indir[blksz / 4]; if (grub_disk_read (data->disk, - grub_le_to_cpu32 (inode->blocks.indir_block) + grub_fshelp_map_block(data->journal, + grub_le_to_cpu32 (inode->blocks.indir_block)) << log2_blksz, 0, blksz, (char *) indir)) return grub_errno; @@ -237,13 +301,15 @@ grub_ext2_read_block (grub_fshelp_node_t node, int fileblock) grub_uint32_t indir[blksz / 4]; if (grub_disk_read (data->disk, - grub_le_to_cpu32 (inode->blocks.double_indir_block) + grub_fshelp_map_block(data->journal, + grub_le_to_cpu32 (inode->blocks.double_indir_block)) << log2_blksz, 0, blksz, (char *) indir)) return grub_errno; if (grub_disk_read (data->disk, - grub_le_to_cpu32 (indir[rblock / perblock]) + grub_fshelp_map_block(data->journal, + grub_le_to_cpu32 (indir[rblock / perblock])) << log2_blksz, 0, blksz, (char *) indir)) return grub_errno; @@ -259,10 +325,9 @@ grub_ext2_read_block (grub_fshelp_node_t node, int fileblock) blknr = -1; } - return blknr; + return grub_fshelp_map_block (data->journal, blknr); } - /* Read LEN bytes from the file described by DATA starting with byte POS. Return the amount of read bytes in READ. */ static grub_ssize_t @@ -308,8 +373,9 @@ grub_ext2_read_inode (struct grub_ext2_data *data, /* Read the inode. */ if (grub_disk_read (data->disk, - ((grub_le_to_cpu32 (blkgrp.inode_table_id) + blkno) - << LOG2_EXT2_BLOCK_SIZE (data)), + grub_fshelp_map_block(data->journal, + grub_le_to_cpu32 (blkgrp.inode_table_id) + blkno) + << LOG2_EXT2_BLOCK_SIZE (data), EXT2_INODE_SIZE (data) * blkoff, sizeof (struct grub_ext2_inode), (char *) inode)) return grub_errno; @@ -317,6 +383,169 @@ grub_ext2_read_inode (struct grub_ext2_data *data, return 0; } +static void +grub_ext3_get_journal (struct grub_ext2_data *data) +{ + char buf[1 << LOG2_BLOCK_SIZE (data)]; + struct grub_ext3_journal_sblock *jsb; + grub_fshelp_journal_t log; + int last_num, num, block, log2bs; + grub_uint32_t seq; + + auto void next_block (void); + void next_block (void) + { + block++; + if (block >= log->last_block) + block = log->first_block; + } + + data->journal = 0; + + if (! (data->sblock.feature_compatibility & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) + return; + + if (! data->sblock.journal_inum) + return; + + data->logfile.data = data; + data->logfile.ino = data->sblock.journal_inum; + data->logfile.inode_read = 1; + + if (grub_ext2_read_inode (data, data->logfile.ino, &data->logfile.inode)) + return; + + log2bs = LOG2_EXT2_BLOCK_SIZE (data); + if (grub_fshelp_read_file (data->disk, &data->logfile, 0, + 0, sizeof (struct grub_ext3_journal_sblock), + buf, grub_ext2_read_block, + sizeof (buf), log2bs) != + sizeof (struct grub_ext3_journal_sblock)) + return; + + jsb = (struct grub_ext3_journal_sblock *) &buf[0]; + if (grub_be_to_cpu32 (jsb->header.magic) != EXT3_JOURNAL_MAGIC_NUMBER) + return; + + /* Empty journal. */ + if (! jsb->start) + return; + + log = grub_malloc (sizeof (struct grub_fshelp_journal) + + grub_be_to_cpu32 (jsb->maxlen) * sizeof (grub_disk_addr_t)); + if (! log) + return; + + log->type = GRUB_FSHELP_JOURNAL_TYPE_FILE; + log->node = &data->logfile; + log->get_block = grub_ext2_read_block; + log->first_block = grub_be_to_cpu32 (jsb->first); + log->last_block = grub_be_to_cpu32 (jsb->maxlen); + log->start_block = grub_be_to_cpu32 (jsb->start); + + last_num = num = 0; + block = log->start_block; + seq = grub_be_to_cpu32 (jsb->sequence); + + while (1) + { + struct grub_ext3_journal_header *jh; + + if (grub_fshelp_read_file (data->disk, &data->logfile, 0, + block << (log2bs + 9), sizeof (buf), + buf, grub_ext2_read_block, + log->last_block << (log2bs + 9), + log2bs) != + (int) sizeof (buf)) + break; + + jh = (struct grub_ext3_journal_header *) &buf[0]; + if (grub_be_to_cpu32 (jh->magic) != EXT3_JOURNAL_MAGIC_NUMBER) + break; + + if (grub_be_to_cpu32 (jh->sequence) != seq) + break; + + log->mapping[num++] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING; + next_block(); + + switch (grub_be_to_cpu32 (jh->block_type)) + { + case EXT3_JOURNAL_DESCRIPTOR_BLOCK: + { + struct grub_ext3_journal_block_tag *tag; + int ofs, flags; + + ofs = sizeof (struct grub_ext3_journal_header); + + do + { + tag = (struct grub_ext3_journal_block_tag *) &buf[ofs]; + ofs += sizeof (struct grub_ext3_journal_block_tag); + + if (ofs > (int) sizeof (buf)) + break; + + flags = grub_be_to_cpu32 (tag->flags); + if (! (flags & EXT3_JOURNAL_FLAG_SAME_UUID)) + ofs += 16; + + log->mapping[num++] = grub_be_to_cpu32 (tag->block); + next_block(); + } + while (! (flags & EXT3_JOURNAL_FLAG_LAST_TAG)); + + continue; + } + + case EXT3_JOURNAL_COMMIT_BLOCK: + { + seq++; + last_num = num - 1; + continue; + } + + case EXT3_JOURNAL_REVOKE_BLOCK: + { + struct grub_ext3_journal_revoke_header *jrh; + grub_uint32_t i; + + jrh = (struct grub_ext3_journal_revoke_header *) jh; + + for (i = 0; i < grub_be_to_cpu32 (jrh->count); i++) + { + int j; + grub_uint32_t map; + + map = grub_be_to_cpu32 (jrh->data[i]); + for (j = 0; j < num; j++) + if (log->mapping[j] == map) + log->mapping[j] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING; + } + + continue; + } + default: + last_num = 0; + goto quit; + } + } + +quit: + if (! last_num) + grub_free (log); + else + { + int size; + + size = sizeof (struct grub_fshelp_journal) + + last_num * sizeof (grub_disk_addr_t); + + log->num_mappings = last_num; + data->journal = grub_realloc (log, size); + } +} + static struct grub_ext2_data * grub_ext2_mount (grub_disk_t disk) { @@ -336,12 +565,14 @@ grub_ext2_mount (grub_disk_t disk) if (grub_le_to_cpu16 (data->sblock.magic) != EXT2_MAGIC) goto fail; + data->disk = disk; + grub_ext3_get_journal (data); + data->diropen.data = data; data->diropen.ino = 2; data->diropen.inode_read = 1; data->inode = &data->diropen.inode; - data->disk = disk; grub_ext2_read_inode (data, 2, data->inode); if (grub_errno) @@ -540,7 +771,11 @@ grub_ext2_open (struct grub_file *file, const char *name) static grub_err_t grub_ext2_close (grub_file_t file) { - grub_free (file->data); + if (file->data) + { + grub_free (((struct grub_ext2_data *) file->data)->journal); + grub_free (file->data); + } #ifndef GRUB_UTIL grub_dl_unref (my_mod); diff --git a/fs/fshelp.c b/fs/fshelp.c index bbb58ac..13a81b6 100644 --- a/fs/fshelp.c +++ b/fs/fshelp.c @@ -72,7 +72,7 @@ grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode, void free_node (grub_fshelp_node_t node) { - if (node != rootnode && node != currroot) + if (node != rootnode && node != currroot) grub_free (node); } @@ -223,25 +223,26 @@ grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode, grub_ssize_t grub_fshelp_read_file (grub_disk_t disk, grub_fshelp_node_t node, void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector, - unsigned offset, unsigned length), - int pos, grub_size_t len, char *buf, - int (*get_block) (grub_fshelp_node_t node, int block), + unsigned offset, + unsigned length), + grub_off_t pos, grub_size_t len, char *buf, + grub_disk_addr_t (*get_block) (grub_fshelp_node_t node, + grub_disk_addr_t block), grub_off_t filesize, int log2blocksize) { - int i; - int blockcnt; + grub_disk_addr_t i, blockcnt; int blocksize = 1 << (log2blocksize + GRUB_DISK_SECTOR_BITS); /* Adjust LEN so it we can't read past the end of the file. */ - if (len > filesize) - len = filesize; + if (pos + len > filesize) + len = filesize - pos; - blockcnt = ((len + pos) + blocksize - 1) / blocksize; + blockcnt = ((len + pos) + blocksize - 1) >> (log2blocksize + GRUB_DISK_SECTOR_BITS); - for (i = pos / blocksize; i < blockcnt; i++) + for (i = pos >> (log2blocksize + GRUB_DISK_SECTOR_BITS); i < blockcnt; i++) { - int blknr; - int blockoff = pos % blocksize; + grub_disk_addr_t blknr; + int blockoff = pos & (blocksize - 1); int blockend = blocksize; int skipfirst = 0; @@ -255,7 +256,7 @@ grub_fshelp_read_file (grub_disk_t disk, grub_fshelp_node_t node, /* Last block. */ if (i == blockcnt - 1) { - blockend = (len + pos) % blocksize; + blockend = (len + pos) & (blocksize - 1); /* The last portion is exactly blocksize. */ if (! blockend) @@ -263,7 +264,7 @@ grub_fshelp_read_file (grub_disk_t disk, grub_fshelp_node_t node, } /* First block. */ - if (i == pos / blocksize) + if (i == (pos >> (log2blocksize + GRUB_DISK_SECTOR_BITS))) { skipfirst = blockoff; blockend -= skipfirst; @@ -310,3 +311,30 @@ grub_fshelp_log2blksize (unsigned int blksize, unsigned int *pow) return GRUB_ERR_NONE; } + +grub_disk_addr_t +grub_fshelp_map_block (grub_fshelp_journal_t log, grub_disk_addr_t block) +{ + int map_block; + + if (! log) + return block; + + for (map_block = log->num_mappings - 1; map_block >= 0; map_block--) + { + if (log->mapping[map_block] == block) + break; + } + + if (map_block < 0) + return block; + + map_block += log->start_block; + if (map_block >= log->last_block) + map_block -= log->last_block - log->first_block; + + if (log->type == GRUB_FSHELP_JOURNAL_TYPE_BLOCK) + return log->blkno + map_block; + else + return log->get_block (log->node, map_block); +} diff --git a/fs/hfsplus.c b/fs/hfsplus.c index fe72539..f4106f0 100644 --- a/fs/hfsplus.c +++ b/fs/hfsplus.c @@ -285,8 +285,8 @@ static int grub_hfsplus_cmp_extkey (struct grub_hfsplus_key *keya, /* Search for the block FILEBLOCK inside the file NODE. Return the blocknumber of this block on disk. */ -static int -grub_hfsplus_read_block (grub_fshelp_node_t node, int fileblock) +static grub_disk_addr_t +grub_hfsplus_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) { struct grub_hfsplus_btnode *nnode = 0; int blksleft = fileblock; diff --git a/fs/ntfs.c b/fs/ntfs.c index 8247efb..1c6adb8 100644 --- a/fs/ntfs.c +++ b/fs/ntfs.c @@ -333,8 +333,8 @@ retry: return 0; } -static int -grub_ntfs_read_block (grub_fshelp_node_t node, int block) +static grub_disk_addr_t +grub_ntfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t block) { struct grub_ntfs_rlst *ctx; diff --git a/fs/reiserfs.c b/fs/reiserfs.c index b536b21..87a754c 100644 --- a/fs/reiserfs.c +++ b/fs/reiserfs.c @@ -52,7 +52,8 @@ #define REISERFS_SUPER_BLOCK_OFFSET 0x10000 #define REISERFS_MAGIC_LEN 12 -#define REISERFS_MAGIC_STRING "ReIsEr2Fs\0\0\0" +#define REISERFS_MAGIC_STRING "ReIsEr" +#define REISERFS_MAGIC_DESC_BLOCK "ReIsErLB" /* If the 3rd bit of an item state is set, then it's visible. */ #define GRUB_REISERFS_VISIBLE_MASK ((grub_uint16_t) 0x04) #define REISERFS_MAX_LABEL_LENGTH 16 @@ -109,8 +110,6 @@ struct grub_reiserfs_superblock grub_uint32_t inode_generation; } __attribute__ ((packed)); -#ifdef GRUB_REISERFS_JOURNALING -# error "Journaling not yet supported." struct grub_reiserfs_journal_header { grub_uint32_t last_flush_uid; @@ -118,15 +117,20 @@ struct grub_reiserfs_journal_header grub_uint32_t mount_id; } __attribute__ ((packed)); -struct grub_reiserfs_transaction_header +struct grub_reiserfs_description_block { grub_uint32_t id; grub_uint32_t len; grub_uint32_t mount_id; - char *data; - char checksum[12]; + grub_uint32_t real_blocks[0]; +} __attribute__ ((packed)); + +struct grub_reiserfs_commit_block +{ + grub_uint32_t id; + grub_uint32_t len; + grub_uint32_t real_blocks[0]; } __attribute__ ((packed)); -#endif struct grub_reiserfs_stat_item_v1 { @@ -228,6 +232,7 @@ struct grub_reiserfs_data { struct grub_reiserfs_superblock superblock; grub_disk_t disk; + grub_fshelp_journal_t journal; }; /* Internal-only functions. Not to be used outside of this file. */ @@ -504,8 +509,8 @@ grub_reiserfs_get_item (struct grub_reiserfs_data *data, do { grub_disk_read (data->disk, - (((grub_disk_addr_t) block_number * block_size) - >> GRUB_DISK_SECTOR_BITS), + grub_fshelp_map_block (data->journal, block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS), (((grub_off_t) block_number * block_size) & (GRUB_DISK_SECTOR_SIZE - 1)), block_size, (char *) block_header); @@ -655,8 +660,8 @@ grub_reiserfs_read_symlink (grub_fshelp_node_t node) block_size = grub_le_to_cpu16 (node->data->superblock.block_size); len = grub_le_to_cpu16 (found.header.item_size); - block = (((grub_disk_addr_t) found.block_number * block_size) - >> GRUB_DISK_SECTOR_BITS); + block = (grub_fshelp_map_block (node->data->journal, found.block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS)); offset = grub_le_to_cpu16 (found.header.item_location); symlink_buffer = grub_malloc (len + 1); @@ -675,6 +680,124 @@ grub_reiserfs_read_symlink (grub_fshelp_node_t node) return 0; } +static void +grub_reiserfs_get_journal (struct grub_reiserfs_data *data) +{ + int block_size = grub_le_to_cpu16 (data->superblock.block_size); + char buf[block_size]; + struct grub_reiserfs_journal_header *jh; + grub_fshelp_journal_t log; + grub_uint32_t seq_id, mount_id; + int num_blocks = grub_le_to_cpu32 (data->superblock.journal_original_size); + int base_block = grub_le_to_cpu32 (data->superblock.journal_block); + int last_num, num, block; + + data->journal = 0; + + if (! data->superblock.journal_block) + return; + + if (grub_disk_read (data->disk, + (base_block + num_blocks) + * (block_size >> GRUB_DISK_SECTOR_BITS), + 0, sizeof (struct grub_reiserfs_journal_header), + buf)) + return; + + log = grub_malloc (sizeof (struct grub_fshelp_journal) + + num_blocks * sizeof (grub_disk_addr_t)); + if (! log) + return; + + jh = (struct grub_reiserfs_journal_header *) &buf[0]; + + log->type = GRUB_FSHELP_JOURNAL_TYPE_BLOCK; + log->blkno = base_block; + log->first_block = 0; + log->last_block = num_blocks; + log->start_block = grub_le_to_cpu32 (jh->unflushed_offset); + + seq_id = grub_le_to_cpu32 (jh->last_flush_uid); + mount_id = grub_le_to_cpu32 (jh->mount_id); + + last_num = num = 0; + block = log->start_block; + + while (1) + { + struct grub_reiserfs_description_block *db; + struct grub_reiserfs_commit_block *cb; + grub_uint32_t i, len, half_len, id, mid; + + if (grub_disk_read (data->disk, + (base_block + block) + * (block_size >> GRUB_DISK_SECTOR_BITS), + 0, sizeof (buf), buf)) + break; + + if (grub_memcmp (&buf[block_size - REISERFS_MAGIC_LEN], + REISERFS_MAGIC_DESC_BLOCK, + sizeof (REISERFS_MAGIC_DESC_BLOCK) - 1)) + break; + + db = (struct grub_reiserfs_description_block *) &buf[0]; + id = grub_le_to_cpu32 (db->id); + len = grub_le_to_cpu32 (db->len); + mid = grub_le_to_cpu32 (db->mount_id); + if ((id <= seq_id) && (mid <= mount_id)) + break; + + log->mapping[num++] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING; + half_len = ((block_size - 24) >> 2); + if (half_len > len) + half_len = len; + + for (i = 0; i < half_len; i++) + log->mapping[num++] = db->real_blocks[i]; + + block += grub_le_to_cpu32 (db->len) + 1; + if (block >= log->last_block) + block -= log->last_block; + + if (grub_disk_read (data->disk, + (base_block + block) + * (block_size >> GRUB_DISK_SECTOR_BITS), + 0, sizeof (buf), buf)) + break; + + cb = (struct grub_reiserfs_commit_block *) &buf[0]; + if ((grub_le_to_cpu32 (cb->id) != id) || + (grub_le_to_cpu32 (cb->len) != len)) + break; + + for (i = 0; i < len - half_len; i++) + log->mapping[num++] = cb->real_blocks[i]; + + last_num = num; + log->mapping[num++] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING; + + block++; + if (block >= log->last_block) + block -= log->last_block; + + seq_id = id; + mount_id = mid; + }; + + if (! last_num) + grub_free (log); + else + { + int size; + + size = sizeof (struct grub_fshelp_journal) + + last_num * sizeof (grub_disk_addr_t); + + log->num_mappings = last_num; + data->journal = grub_realloc (log, size); + } +} + /* Fill the mounted filesystem structure and return it. */ static struct grub_reiserfs_data * grub_reiserfs_mount (grub_disk_t disk) @@ -688,12 +811,13 @@ grub_reiserfs_mount (grub_disk_t disk) if (grub_errno) goto fail; if (grub_memcmp (data->superblock.magic_string, - REISERFS_MAGIC_STRING, REISERFS_MAGIC_LEN)) + REISERFS_MAGIC_STRING, sizeof (REISERFS_MAGIC_STRING) - 1)) { grub_error (GRUB_ERR_BAD_FS, "not a reiserfs filesystem"); goto fail; } data->disk = disk; + grub_reiserfs_get_journal (data); return data; fail: @@ -741,8 +865,8 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item, struct grub_reiserfs_item_header *item_headers; grub_disk_read (data->disk, - (((grub_disk_addr_t) block_number * block_size) - >> GRUB_DISK_SECTOR_BITS), + grub_fshelp_map_block (data->journal, block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS), (((grub_off_t) block_number * block_size) & (GRUB_DISK_SECTOR_SIZE - 1)), block_size, (char *) block_header); @@ -836,7 +960,8 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item, { struct grub_reiserfs_stat_item_v1 entry_v1_stat; grub_disk_read (data->disk, - ((grub_disk_addr_t) entry_block_number * block_size) >> GRUB_DISK_SECTOR_BITS, + grub_fshelp_map_block (data->journal, entry_block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS), grub_le_to_cpu16 (entry_item->header.item_location), sizeof (entry_v1_stat), (char *) &entry_v1_stat); @@ -878,7 +1003,8 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item, { struct grub_reiserfs_stat_item_v2 entry_v2_stat; grub_disk_read (data->disk, - ((grub_disk_addr_t) entry_block_number * block_size) >> GRUB_DISK_SECTOR_BITS, + grub_fshelp_map_block (data->journal, entry_block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS), grub_le_to_cpu16 (entry_item->header.item_location), sizeof (entry_v2_stat), (char *) &entry_v2_stat); @@ -1026,8 +1152,8 @@ grub_reiserfs_open (struct grub_file *file, const char *name) { struct grub_reiserfs_stat_item_v1 entry_v1_stat; grub_disk_read (data->disk, - (((grub_disk_addr_t) block_number * block_size) - >> GRUB_DISK_SECTOR_BITS), + grub_fshelp_map_block (data->journal, block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS), entry_location + (((grub_off_t) block_number * block_size) & (GRUB_DISK_SECTOR_SIZE - 1)), @@ -1040,8 +1166,8 @@ grub_reiserfs_open (struct grub_file *file, const char *name) { struct grub_reiserfs_stat_item_v2 entry_v2_stat; grub_disk_read (data->disk, - (((grub_disk_addr_t) block_number * block_size) - >> GRUB_DISK_SECTOR_BITS), + grub_fshelp_map_block (data->journal, block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS), entry_location + (((grub_off_t) block_number * block_size) & (GRUB_DISK_SECTOR_SIZE - 1)), @@ -1109,8 +1235,8 @@ grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len) switch (found.type) { case GRUB_REISERFS_DIRECT: - block = (((grub_disk_addr_t) found.block_number * block_size) - >> GRUB_DISK_SECTOR_BITS); + block = (grub_fshelp_map_block (data->journal, found.block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS)); grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block); if (initial_position < current_position + item_size) { @@ -1142,8 +1268,8 @@ grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len) if (! indirect_block_ptr) goto fail; grub_disk_read (found.data->disk, - (((grub_disk_addr_t) found.block_number * block_size) - >> GRUB_DISK_SECTOR_BITS), + grub_fshelp_map_block (data->journal, found.block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS), grub_le_to_cpu16 (found.header.item_location), item_size, (char *) indirect_block_ptr); if (grub_errno) @@ -1154,9 +1280,9 @@ grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len) && current_position < final_position; indirect_block++) { - block = ((grub_disk_addr_t) - grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) - * block_size) >> GRUB_DISK_SECTOR_BITS; + block = (grub_fshelp_map_block (data->journal, + grub_le_to_cpu32 (indirect_block_ptr[indirect_block])) * + (block_size >> GRUB_DISK_SECTOR_BITS)); grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block); if (current_position + block_size >= initial_position) { @@ -1255,6 +1381,7 @@ grub_reiserfs_close (grub_file_t file) struct grub_fshelp_node *node = file->data; struct grub_reiserfs_data *data = node->data; + grub_free (data->journal); grub_free (data); grub_free (node); #ifndef GRUB_UTIL diff --git a/fs/sfs.c b/fs/sfs.c index a453bc6..99081bd 100644 --- a/fs/sfs.c +++ b/fs/sfs.c @@ -219,8 +219,8 @@ grub_sfs_read_extent (struct grub_sfs_data *data, unsigned int block, return grub_error (GRUB_ERR_FILE_READ_ERROR, "SFS extent not found"); } -static int -grub_sfs_read_block (grub_fshelp_node_t node, int fileblock) +static grub_disk_addr_t +grub_sfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) { int blk = node->block; int size = 0; @@ -239,7 +239,7 @@ grub_sfs_read_block (grub_fshelp_node_t node, int fileblock) if (err) return 0; - if (fileblock < size) + if (fileblock < (unsigned int) size) return fileblock + blk; fileblock -= size; diff --git a/fs/udf.c b/fs/udf.c index e07d962..511291b 100644 --- a/fs/udf.c +++ b/fs/udf.c @@ -404,8 +404,8 @@ grub_udf_read_icb (struct grub_udf_data *data, return 0; } -static int -grub_udf_read_block (grub_fshelp_node_t node, int fileblock) +static grub_disk_addr_t +grub_udf_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) { char *ptr; int len; @@ -429,7 +429,7 @@ grub_udf_read_block (grub_fshelp_node_t node, int fileblock) len /= sizeof (struct grub_udf_short_ad); while (len > 0) { - if (fileblock < (int) U32 (ad->length)) + if (fileblock < U32 (ad->length)) return ((U32 (ad->position) & GRUB_UDF_EXT_MASK) ? 0 : (grub_udf_get_block (node->data, node->part_ref, @@ -448,7 +448,7 @@ grub_udf_read_block (grub_fshelp_node_t node, int fileblock) len /= sizeof (struct grub_udf_long_ad); while (len > 0) { - if (fileblock < (int) U32 (ad->length)) + if (fileblock < U32 (ad->length)) return ((U32 (ad->block.block_num) & GRUB_UDF_EXT_MASK) ? 0 : (grub_udf_get_block (node->data, ad->block.part_ref, diff --git a/fs/xfs.c b/fs/xfs.c index 88d22be..78dc904 100644 --- a/fs/xfs.c +++ b/fs/xfs.c @@ -220,8 +220,8 @@ grub_xfs_read_inode (struct grub_xfs_data *data, grub_uint64_t ino, } -static int -grub_xfs_read_block (grub_fshelp_node_t node, int fileblock) +static grub_disk_addr_t +grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) { struct grub_xfs_btree_node *leaf = 0; int ex, nrec; @@ -292,8 +292,8 @@ grub_xfs_read_block (grub_fshelp_node_t node, int fileblock) for (ex = 0; ex < nrec; ex++) { grub_uint64_t start = GRUB_XFS_EXTENT_BLOCK (exts, ex); - int offset = GRUB_XFS_EXTENT_OFFSET (exts, ex); - int size = GRUB_XFS_EXTENT_SIZE (exts, ex); + unsigned int offset = GRUB_XFS_EXTENT_OFFSET (exts, ex); + unsigned int size = GRUB_XFS_EXTENT_SIZE (exts, ex); /* Sparse block. */ if (fileblock < offset) diff --git a/include/grub/fshelp.h b/include/grub/fshelp.h index e25dd16..32d47a3 100644 --- a/include/grub/fshelp.h +++ b/include/grub/fshelp.h @@ -34,6 +34,34 @@ enum grub_fshelp_filetype GRUB_FSHELP_SYMLINK }; +enum grub_fshelp_journal_type + { + GRUB_FSHELP_JOURNAL_TYPE_BLOCK, + GRUB_FSHELP_JOURNAL_TYPE_FILE + }; + +#define GRUB_FSHELP_JOURNAL_UNUSED_MAPPING (grub_disk_addr_t) -1 + +struct grub_fshelp_journal +{ + int type; + union + { + struct + { + grub_fshelp_node_t node; + grub_disk_addr_t (*get_block) (grub_fshelp_node_t node, grub_disk_addr_t block); + }; + grub_disk_addr_t blkno; + }; + int first_block; + int last_block; + int start_block; + int num_mappings; + grub_disk_addr_t mapping[0]; +}; +typedef struct grub_fshelp_journal *grub_fshelp_journal_t; + /* Lookup the node PATH. The node ROOTNODE describes the root of the directory tree. The node found is returned in FOUNDNODE, which is either a ROOTNODE or a new malloc'ed node. ITERATE_DIR is used to @@ -64,15 +92,18 @@ EXPORT_FUNC(grub_fshelp_find_file) (const char *path, grub_ssize_t EXPORT_FUNC(grub_fshelp_read_file) (grub_disk_t disk, grub_fshelp_node_t node, void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector, - unsigned offset, - unsigned length), - int pos, grub_size_t len, char *buf, - int (*get_block) (grub_fshelp_node_t node, - int block), + unsigned offset, + unsigned length), + grub_off_t pos, grub_size_t len, char *buf, + grub_disk_addr_t (*get_block) (grub_fshelp_node_t node, + grub_disk_addr_t block), grub_off_t filesize, int log2blocksize); unsigned int EXPORT_FUNC(grub_fshelp_log2blksize) (unsigned int blksize, unsigned int *pow); +grub_disk_addr_t +EXPORT_FUNC(grub_fshelp_map_block) (grub_fshelp_journal_t log, grub_disk_addr_t block); + #endif /* ! GRUB_FSHELP_HEADER */ ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH] Journal support for ext2 2008-03-05 17:24 ` Bean @ 2008-03-14 6:11 ` Bean 2008-03-14 6:45 ` Marco Gerards 0 siblings, 1 reply; 16+ messages in thread From: Bean @ 2008-03-14 6:11 UTC (permalink / raw) To: The development of GRUB 2 On Thu, Mar 6, 2008 at 1:24 AM, Bean <bean123ch@gmail.com> wrote: > Hi, > > I have converted all block type in fshelp to grub_disk_addr_t, the > file system driver should be 64-bit enabled by now. Any comment ? i would like to check it in if there is no objection. -- Bean ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Journal support for ext2 2008-03-14 6:11 ` Bean @ 2008-03-14 6:45 ` Marco Gerards 0 siblings, 0 replies; 16+ messages in thread From: Marco Gerards @ 2008-03-14 6:45 UTC (permalink / raw) To: The development of GRUB 2 Bean <bean123ch@gmail.com> writes: > On Thu, Mar 6, 2008 at 1:24 AM, Bean <bean123ch@gmail.com> wrote: >> Hi, >> >> I have converted all block type in fshelp to grub_disk_addr_t, the >> file system driver should be 64-bit enabled by now. > > Any comment ? i would like to check it in if there is no objection. Sorry, at the moment I am swamped with work :-/. Hopefully I will have the time to review all patches during the weekend. -- Marco ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Journal support for ext2 2008-02-17 19:07 [PATCH] Journal support for ext2 Bean 2008-02-17 22:34 ` Bean @ 2008-02-18 6:03 ` Robert Millan 2008-02-18 6:15 ` Bean 1 sibling, 1 reply; 16+ messages in thread From: Robert Millan @ 2008-02-18 6:03 UTC (permalink / raw) To: The development of GRUB 2 On Mon, Feb 18, 2008 at 03:07:54AM +0800, Bean wrote: > Hi, > > This patch extends fshelp for general journal handling, it also > implement journaling for ext2 file system. In which situations is this needed, reading writing or both? -- Robert Millan <GPLv2> I know my rights; I want my phone call! <DRM> What use is a phone call… if you are unable to speak? (as seen on /.) ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Journal support for ext2 2008-02-18 6:03 ` Robert Millan @ 2008-02-18 6:15 ` Bean 2008-02-18 14:51 ` Robert Millan 0 siblings, 1 reply; 16+ messages in thread From: Bean @ 2008-02-18 6:15 UTC (permalink / raw) To: The development of GRUB 2 On Feb 18, 2008 2:03 PM, Robert Millan <rmh@aybabtu.com> wrote: > On Mon, Feb 18, 2008 at 03:07:54AM +0800, Bean wrote: > > Hi, > > > > This patch extends fshelp for general journal handling, it also > > implement journaling for ext2 file system. > > In which situations is this needed, reading writing or both? it's only used for reading. when ext2 is mounted, the journal file is checked, if it contains unflushed transaction, it's used to read data. This make sure that the file system can be accessed even after a crash. -- Bean ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Journal support for ext2 2008-02-18 6:15 ` Bean @ 2008-02-18 14:51 ` Robert Millan 0 siblings, 0 replies; 16+ messages in thread From: Robert Millan @ 2008-02-18 14:51 UTC (permalink / raw) To: The development of GRUB 2 On Mon, Feb 18, 2008 at 02:15:58PM +0800, Bean wrote: > On Feb 18, 2008 2:03 PM, Robert Millan <rmh@aybabtu.com> wrote: > > On Mon, Feb 18, 2008 at 03:07:54AM +0800, Bean wrote: > > > Hi, > > > > > > This patch extends fshelp for general journal handling, it also > > > implement journaling for ext2 file system. > > > > In which situations is this needed, reading writing or both? > > it's only used for reading. when ext2 is mounted, the journal file is > checked, if it contains unflushed transaction, it's used to read data. > This make sure that the file system can be accessed even after a > crash. Ah yes, now I remember about this problem. Nice work ;-) -- Robert Millan <GPLv2> I know my rights; I want my phone call! <DRM> What use is a phone call… if you are unable to speak? (as seen on /.) ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Journal support for ext2 @ 2008-03-20 0:12 Robert Millan 2008-03-20 6:03 ` Bean 0 siblings, 1 reply; 16+ messages in thread From: Robert Millan @ 2008-03-20 0:12 UTC (permalink / raw) To: grub-devel Hi! Is this patch supposed to fix > 32-bit disk addressing in filesystems? I just setup a ~4 TB hard disk for testing (in qemu), and added a (gpt) partition at the end of it, surely above the 2 TiB barrier. What I found puzzling is that grub-emu is capable of listing files in that partition _without_ this patch. Any idea why? This wasn't really supposed to work was it? Note: grub itself can't read it yet, but this must be due to disk io problems (asides from the lba32 limit in bochsbios). -- Robert Millan <GPLv2> I know my rights; I want my phone call! <DRM> What use is a phone call… if you are unable to speak? (as seen on /.) ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Journal support for ext2 2008-03-20 0:12 Robert Millan @ 2008-03-20 6:03 ` Bean 2008-03-20 13:13 ` Robert Millan 0 siblings, 1 reply; 16+ messages in thread From: Bean @ 2008-03-20 6:03 UTC (permalink / raw) To: The development of GRUB 2 On Thu, Mar 20, 2008 at 8:12 AM, Robert Millan <rmh@aybabtu.com> wrote: > > Hi! > > Is this patch supposed to fix > 32-bit disk addressing in filesystems? I > just setup a ~4 TB hard disk for testing (in qemu), and added a (gpt) partition > at the end of it, surely above the 2 TiB barrier. > > What I found puzzling is that grub-emu is capable of listing files in that > partition _without_ this patch. Any idea why? This wasn't really supposed > to work was it? > > Note: grub itself can't read it yet, but this must be due to disk io problems > (asides from the lba32 limit in bochsbios). Hi, the sector parameter in grub_disk_read is 64-bit, so it can read from disk larger than 4g.The fs interface is using 64-bit address as well, so if the implementation is all right, it can handle large partition. The problem is that fshelp function use int for offset and block number, which limit the maximum file size to 4g. You can verify this with loopback on a large file. -- Bean ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Journal support for ext2 2008-03-20 6:03 ` Bean @ 2008-03-20 13:13 ` Robert Millan 2008-05-15 12:18 ` Bean 0 siblings, 1 reply; 16+ messages in thread From: Robert Millan @ 2008-03-20 13:13 UTC (permalink / raw) To: The development of GRUB 2 On Thu, Mar 20, 2008 at 02:03:45PM +0800, Bean wrote: > On Thu, Mar 20, 2008 at 8:12 AM, Robert Millan <rmh@aybabtu.com> wrote: > > > > Hi! > > > > Is this patch supposed to fix > 32-bit disk addressing in filesystems? I > > just setup a ~4 TB hard disk for testing (in qemu), and added a (gpt) partition > > at the end of it, surely above the 2 TiB barrier. > > > > What I found puzzling is that grub-emu is capable of listing files in that > > partition _without_ this patch. Any idea why? This wasn't really supposed > > to work was it? > > > > Note: grub itself can't read it yet, but this must be due to disk io problems > > (asides from the lba32 limit in bochsbios). > > Hi, > > the sector parameter in grub_disk_read is 64-bit, so it can read from > disk larger than 4g.The fs interface is using 64-bit address as well, > so if the implementation is all right, it can handle large partition. Ah, that explains it. Note that the disk io part can't handle it yet, though. I'll have a look into that (bochsbios itself limits it, but ata.mod didn't work either). > The problem is that fshelp function use int for offset and block > number, which limit the maximum file size to 4g. You can verify this > with loopback on a large file. Ah ok. -- Robert Millan <GPLv2> I know my rights; I want my phone call! <DRM> What use is a phone call… if you are unable to speak? (as seen on /.) ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Journal support for ext2 2008-03-20 13:13 ` Robert Millan @ 2008-05-15 12:18 ` Bean 0 siblings, 0 replies; 16+ messages in thread From: Bean @ 2008-05-15 12:18 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 3076 bytes --] Hi, This new patch is synced with the current cvs head, also some minor changes. If nobody objects, I'd commit this in a few days. 2008-05-15 Bean <bean123ch@gmail.com> * fs/fshelp.c (grub_fshelp_map_block): New function. (grub_fshelp_find_file): Use 64-bit type for pos and block address. Use `>>' and `&' operator to avoid 64-bit divide and modulo. * include/grub/fshelp.h (grub_fshelp_journal_type): New enum. (GRUB_FSHELP_JOURNAL_UNUSED_MAPPING): New macro. (grub_fshelp_journal): New structure. (grub_fshelp_map_block): New function prototype. (grub_fshelp_read_file): Use grub_disk_addr_t as block type. (grub_fshelp_map_block): Likewise. * fs/ext2.c (EXT3_FEATURE_COMPAT_HAS_JOURNAL): New macro. (EXT3_JOURNAL_MAGIC_NUMBER): Likewise. (EXT3_JOURNAL_DESCRIPTOR_BLOCK): Likewise. (EXT3_JOURNAL_COMMIT_BLOCK): Likewise. (EXT3_JOURNAL_SUPERBLOCK_V1): Likewise. (EXT3_JOURNAL_SUPERBLOCK_V2): Likewise. (EXT3_JOURNAL_REVOKE_BLOCK): Likewise. (EXT3_JOURNAL_FLAG_ESCAPE): Likewise. (EXT3_JOURNAL_FLAG_SAME_UUID): Likewise. (EXT3_JOURNAL_FLAG_DELETED): Likewise. (EXT3_JOURNAL_FLAG_LAST_TAG): Likewise. (grub_ext2_sblock): New members for journal support. (grub_ext3_journal_header): New structure. (grub_ext3_journal_revoke_header): Likewise. (grub_ext3_journal_block_tag): Likewise. (grub_ext3_journal_sblock): Likewise. (grub_fshelp_node): New members logfile and journal. (grub_ext2_read_block): Change block type to grub_disk_addr_t. Use grub_fshelp_map_block to get real block number. (grub_ext2_blockgroup): Use grub_fshelp_map_block to get real block number. (grub_ext2_read_inode): Likewise. (grub_ext3_get_journal): New function. (grub_read_inode): Initialize journal using grub_ext3_get_journal. (grub_ext2_close): Release memory used by journal. * fs/reiserfs.c (REISERFS_MAGIC_STRING): Changed to "ReIsEr". (REISERFS_MAGIC_DESC_BLOCK): New macro. (grub_reiserfs_transaction_header): Renamed to grub_reiserfs_description_block, replace field data with real_blocks. (grub_reiserfs_commit_block): New structure. (grub_reiserfs_data): New member journal. (grub_reiserfs_get_item): Use grub_fshelp_map_block to get real block number. (grub_reiserfs_read_symlink): Likewise. (grub_reiserfs_iterate_dir): Likewise. (grub_reiserfs_open): Likewise. (grub_reiserfs_read): Likewise. (grub_reiserfs_get_journal): New function. (grub_reiserfs_mount): Use "ReIsEr" as super block magic, as there are three varieties ReIsErFs, ReIsEr2Fs and ReIsEr3Fs. Initialize journal using grub_reiserfs_get_journal. (grub_reiserfs_close): Release memory used by journal. * fs/affs.c (grub_affs_read_block): Change block type to grub_disk_addr_t. Use grub_divmod64 to do 64-bit division. * fs/afs.c (grub_afs_read_block): Change block type to grub_disk_addr_t. * fs/hfsplus.c (grub_hfsplus_read_block): Likewise. * fs/ntfs.c (grub_ntfs_read_block): Likewise. * fs/udf.c (grub_udf_read_block): Change block type to grub_disk_addr_t. Use type cast to avoid warning. * fs/xfs.c (grub_xfs_read_block): Likewise. -- Bean [-- Attachment #2: jour4.diff --] [-- Type: text/plain, Size: 35389 bytes --] diff --git a/fs/affs.c b/fs/affs.c index 8ebfa40..5418ffb 100644 --- a/fs/affs.c +++ b/fs/affs.c @@ -109,18 +109,19 @@ static grub_dl_t my_mod; #endif \f -static int -grub_affs_read_block (grub_fshelp_node_t node, int fileblock) +static grub_disk_addr_t +grub_affs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) { int links; grub_uint32_t pos; int block = node->block; struct grub_affs_file file; struct grub_affs_data *data = node->data; + grub_uint32_t mod; /* Find the block that points to the fileblock we are looking up by following the chain until the right table is reached. */ - for (links = fileblock / (data->htsize); links; links--) + for (links = grub_divmod64 (fileblock, data->htsize, &mod); links; links--) { grub_disk_read (data->disk, block + data->blocksize - 1, data->blocksize * (GRUB_DISK_SECTOR_SIZE @@ -133,7 +134,7 @@ grub_affs_read_block (grub_fshelp_node_t node, int fileblock) } /* Translate the fileblock to the block within the right table. */ - fileblock = fileblock % (data->htsize); + fileblock = mod; grub_disk_read (data->disk, block, GRUB_AFFS_BLOCKPTR_OFFSET + (data->htsize - fileblock - 1) * sizeof (pos), @@ -567,4 +568,3 @@ GRUB_MOD_FINI(affs) { grub_fs_unregister (&grub_affs_fs); } - diff --git a/fs/afs.c b/fs/afs.c index 7c61671..5b5eb68 100644 --- a/fs/afs.c +++ b/fs/afs.c @@ -199,12 +199,12 @@ grub_afs_read_inode (struct grub_afs_data *data, } static int -grub_afs_read_block (grub_fshelp_node_t node, int fileblock) +grub_afs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) { struct grub_afs_sblock *sb = &node->data->sblock; struct grub_afs_datastream *ds = &node->inode.stream; - if ((grub_uint32_t) fileblock < U64 (sb, ds->max_direct_range)) + if (fileblock < U64 (sb, ds->max_direct_range)) { int i; @@ -215,7 +215,7 @@ grub_afs_read_block (grub_fshelp_node_t node, int fileblock) fileblock -= U16 (sb, ds->direct[i].len); } } - else if ((grub_uint32_t) fileblock < U64 (sb, ds->max_indirect_range)) + else if (fileblock < U64 (sb, ds->max_indirect_range)) { int ptrs_per_blk = sb->block_size / sizeof (struct grub_afs_blockrun); struct grub_afs_blockrun indir[ptrs_per_blk]; diff --git a/fs/ext2.c b/fs/ext2.c index ec66582..ce7b2fa 100644 --- a/fs/ext2.c +++ b/fs/ext2.c @@ -71,6 +71,21 @@ ? EXT2_GOOD_OLD_INODE_SIZE \ : grub_le_to_cpu16 (data->sblock.inode_size)) +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 + +#define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U + +#define EXT3_JOURNAL_DESCRIPTOR_BLOCK 1 +#define EXT3_JOURNAL_COMMIT_BLOCK 2 +#define EXT3_JOURNAL_SUPERBLOCK_V1 3 +#define EXT3_JOURNAL_SUPERBLOCK_V2 4 +#define EXT3_JOURNAL_REVOKE_BLOCK 5 + +#define EXT3_JOURNAL_FLAG_ESCAPE 1 +#define EXT3_JOURNAL_FLAG_SAME_UUID 2 +#define EXT3_JOURNAL_FLAG_DELETED 4 +#define EXT3_JOURNAL_FLAG_LAST_TAG 8 + /* The ext2 superblock. */ struct grub_ext2_sblock { @@ -109,6 +124,21 @@ struct grub_ext2_sblock char volume_name[16]; char last_mounted_on[64]; grub_uint32_t compression_info; + grub_uint8_t prealloc_blocks; + grub_uint8_t prealloc_dir_blocks; + grub_uint16_t reserved_gdt_blocks; + grub_uint8_t journal_uuid[16]; + grub_uint32_t journal_inum; + grub_uint32_t journal_dev; + grub_uint32_t last_orphan; + grub_uint32_t hash_seed[4]; + grub_uint8_t def_hash_version; + grub_uint8_t jnl_backup_type; + grub_uint16_t reserved_word_pad; + grub_uint32_t default_mount_opts; + grub_uint32_t first_meta_bg; + grub_uint32_t mkfs_time; + grub_uint32_t jnl_blocks[17]; }; /* The ext2 blockgroup. */ @@ -166,6 +196,36 @@ struct ext2_dirent grub_uint8_t filetype; }; +struct grub_ext3_journal_header +{ + grub_uint32_t magic; + grub_uint32_t block_type; + grub_uint32_t sequence; +}; + +struct grub_ext3_journal_revoke_header +{ + struct grub_ext3_journal_header header; + grub_uint32_t count; + grub_uint32_t data[0]; +}; + +struct grub_ext3_journal_block_tag +{ + grub_uint32_t block; + grub_uint32_t flags; +}; + +struct grub_ext3_journal_sblock +{ + struct grub_ext3_journal_header header; + grub_uint32_t block_size; + grub_uint32_t maxlen; + grub_uint32_t first; + grub_uint32_t sequence; + grub_uint32_t start; +}; + struct grub_fshelp_node { struct grub_ext2_data *data; @@ -181,6 +241,8 @@ struct grub_ext2_data grub_disk_t disk; struct grub_ext2_inode *inode; struct grub_fshelp_node diropen; + struct grub_fshelp_node logfile; + grub_fshelp_journal_t journal; }; #ifndef GRUB_UTIL @@ -196,20 +258,21 @@ grub_ext2_blockgroup (struct grub_ext2_data *data, int group, struct grub_ext2_block_group *blkgrp) { return grub_disk_read (data->disk, - ((grub_le_to_cpu32 (data->sblock.first_data_block) + 1) + (grub_fshelp_map_block (data->journal, + grub_le_to_cpu32 (data->sblock.first_data_block) + 1) << LOG2_EXT2_BLOCK_SIZE (data)), group * sizeof (struct grub_ext2_block_group), sizeof (struct grub_ext2_block_group), (char *) blkgrp); } -static int -grub_ext2_read_block (grub_fshelp_node_t node, int fileblock) +static grub_disk_addr_t +grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) { struct grub_ext2_data *data = node->data; struct grub_ext2_inode *inode = &node->inode; int blknr; - int blksz = EXT2_BLOCK_SIZE (data); + unsigned int blksz = EXT2_BLOCK_SIZE (data); int log2_blksz = LOG2_EXT2_BLOCK_SIZE (data); /* Direct blocks. */ @@ -221,7 +284,8 @@ grub_ext2_read_block (grub_fshelp_node_t node, int fileblock) grub_uint32_t indir[blksz / 4]; if (grub_disk_read (data->disk, - grub_le_to_cpu32 (inode->blocks.indir_block) + grub_fshelp_map_block(data->journal, + grub_le_to_cpu32 (inode->blocks.indir_block)) << log2_blksz, 0, blksz, (char *) indir)) return grub_errno; @@ -237,13 +301,15 @@ grub_ext2_read_block (grub_fshelp_node_t node, int fileblock) grub_uint32_t indir[blksz / 4]; if (grub_disk_read (data->disk, - grub_le_to_cpu32 (inode->blocks.double_indir_block) + grub_fshelp_map_block(data->journal, + grub_le_to_cpu32 (inode->blocks.double_indir_block)) << log2_blksz, 0, blksz, (char *) indir)) return grub_errno; if (grub_disk_read (data->disk, - grub_le_to_cpu32 (indir[rblock / perblock]) + grub_fshelp_map_block(data->journal, + grub_le_to_cpu32 (indir[rblock / perblock])) << log2_blksz, 0, blksz, (char *) indir)) return grub_errno; @@ -259,10 +325,9 @@ grub_ext2_read_block (grub_fshelp_node_t node, int fileblock) blknr = -1; } - return blknr; + return grub_fshelp_map_block (data->journal, blknr); } - /* Read LEN bytes from the file described by DATA starting with byte POS. Return the amount of read bytes in READ. */ static grub_ssize_t @@ -308,8 +373,9 @@ grub_ext2_read_inode (struct grub_ext2_data *data, /* Read the inode. */ if (grub_disk_read (data->disk, - ((grub_le_to_cpu32 (blkgrp.inode_table_id) + blkno) - << LOG2_EXT2_BLOCK_SIZE (data)), + grub_fshelp_map_block(data->journal, + grub_le_to_cpu32 (blkgrp.inode_table_id) + blkno) + << LOG2_EXT2_BLOCK_SIZE (data), EXT2_INODE_SIZE (data) * blkoff, sizeof (struct grub_ext2_inode), (char *) inode)) return grub_errno; @@ -317,6 +383,169 @@ grub_ext2_read_inode (struct grub_ext2_data *data, return 0; } +static void +grub_ext3_get_journal (struct grub_ext2_data *data) +{ + char buf[1 << LOG2_BLOCK_SIZE (data)]; + struct grub_ext3_journal_sblock *jsb; + grub_fshelp_journal_t log; + int last_num, num, block, log2bs; + grub_uint32_t seq; + + auto void next_block (void); + void next_block (void) + { + block++; + if (block >= log->last_block) + block = log->first_block; + } + + data->journal = 0; + + if (! (data->sblock.feature_compatibility & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) + return; + + if (! data->sblock.journal_inum) + return; + + data->logfile.data = data; + data->logfile.ino = data->sblock.journal_inum; + data->logfile.inode_read = 1; + + if (grub_ext2_read_inode (data, data->logfile.ino, &data->logfile.inode)) + return; + + log2bs = LOG2_EXT2_BLOCK_SIZE (data); + if (grub_fshelp_read_file (data->disk, &data->logfile, 0, + 0, sizeof (struct grub_ext3_journal_sblock), + buf, grub_ext2_read_block, + sizeof (buf), log2bs) != + sizeof (struct grub_ext3_journal_sblock)) + return; + + jsb = (struct grub_ext3_journal_sblock *) &buf[0]; + if (grub_be_to_cpu32 (jsb->header.magic) != EXT3_JOURNAL_MAGIC_NUMBER) + return; + + /* Empty journal. */ + if (! jsb->start) + return; + + log = grub_malloc (sizeof (struct grub_fshelp_journal) + + grub_be_to_cpu32 (jsb->maxlen) * sizeof (grub_disk_addr_t)); + if (! log) + return; + + log->type = GRUB_FSHELP_JOURNAL_TYPE_FILE; + log->node = &data->logfile; + log->get_block = grub_ext2_read_block; + log->first_block = grub_be_to_cpu32 (jsb->first); + log->last_block = grub_be_to_cpu32 (jsb->maxlen); + log->start_block = grub_be_to_cpu32 (jsb->start); + + last_num = num = 0; + block = log->start_block; + seq = grub_be_to_cpu32 (jsb->sequence); + + while (1) + { + struct grub_ext3_journal_header *jh; + + if (grub_fshelp_read_file (data->disk, &data->logfile, 0, + block << (log2bs + 9), sizeof (buf), + buf, grub_ext2_read_block, + log->last_block << (log2bs + 9), + log2bs) != + (int) sizeof (buf)) + break; + + jh = (struct grub_ext3_journal_header *) &buf[0]; + if (grub_be_to_cpu32 (jh->magic) != EXT3_JOURNAL_MAGIC_NUMBER) + break; + + if (grub_be_to_cpu32 (jh->sequence) != seq) + break; + + log->mapping[num++] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING; + next_block(); + + switch (grub_be_to_cpu32 (jh->block_type)) + { + case EXT3_JOURNAL_DESCRIPTOR_BLOCK: + { + struct grub_ext3_journal_block_tag *tag; + int ofs, flags; + + ofs = sizeof (struct grub_ext3_journal_header); + + do + { + tag = (struct grub_ext3_journal_block_tag *) &buf[ofs]; + ofs += sizeof (struct grub_ext3_journal_block_tag); + + if (ofs > (int) sizeof (buf)) + break; + + flags = grub_be_to_cpu32 (tag->flags); + if (! (flags & EXT3_JOURNAL_FLAG_SAME_UUID)) + ofs += 16; + + log->mapping[num++] = grub_be_to_cpu32 (tag->block); + next_block(); + } + while (! (flags & EXT3_JOURNAL_FLAG_LAST_TAG)); + + continue; + } + + case EXT3_JOURNAL_COMMIT_BLOCK: + { + seq++; + last_num = num - 1; + continue; + } + + case EXT3_JOURNAL_REVOKE_BLOCK: + { + struct grub_ext3_journal_revoke_header *jrh; + grub_uint32_t i; + + jrh = (struct grub_ext3_journal_revoke_header *) jh; + + for (i = 0; i < grub_be_to_cpu32 (jrh->count); i++) + { + int j; + grub_uint32_t map; + + map = grub_be_to_cpu32 (jrh->data[i]); + for (j = 0; j < num; j++) + if (log->mapping[j] == map) + log->mapping[j] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING; + } + + continue; + } + default: + last_num = 0; + goto quit; + } + } + +quit: + if (! last_num) + grub_free (log); + else + { + int size; + + size = sizeof (struct grub_fshelp_journal) + + last_num * sizeof (grub_disk_addr_t); + + log->num_mappings = last_num; + data->journal = grub_realloc (log, size); + } +} + static struct grub_ext2_data * grub_ext2_mount (grub_disk_t disk) { @@ -336,12 +565,14 @@ grub_ext2_mount (grub_disk_t disk) if (grub_le_to_cpu16 (data->sblock.magic) != EXT2_MAGIC) goto fail; + data->disk = disk; + grub_ext3_get_journal (data); + data->diropen.data = data; data->diropen.ino = 2; data->diropen.inode_read = 1; data->inode = &data->diropen.inode; - data->disk = disk; grub_ext2_read_inode (data, 2, data->inode); if (grub_errno) @@ -540,7 +771,11 @@ grub_ext2_open (struct grub_file *file, const char *name) static grub_err_t grub_ext2_close (grub_file_t file) { - grub_free (file->data); + if (file->data) + { + grub_free (((struct grub_ext2_data *) file->data)->journal); + grub_free (file->data); + } #ifndef GRUB_UTIL grub_dl_unref (my_mod); diff --git a/fs/fshelp.c b/fs/fshelp.c index bbb58ac..13a81b6 100644 --- a/fs/fshelp.c +++ b/fs/fshelp.c @@ -72,7 +72,7 @@ grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode, void free_node (grub_fshelp_node_t node) { - if (node != rootnode && node != currroot) + if (node != rootnode && node != currroot) grub_free (node); } @@ -223,25 +223,26 @@ grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode, grub_ssize_t grub_fshelp_read_file (grub_disk_t disk, grub_fshelp_node_t node, void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector, - unsigned offset, unsigned length), - int pos, grub_size_t len, char *buf, - int (*get_block) (grub_fshelp_node_t node, int block), + unsigned offset, + unsigned length), + grub_off_t pos, grub_size_t len, char *buf, + grub_disk_addr_t (*get_block) (grub_fshelp_node_t node, + grub_disk_addr_t block), grub_off_t filesize, int log2blocksize) { - int i; - int blockcnt; + grub_disk_addr_t i, blockcnt; int blocksize = 1 << (log2blocksize + GRUB_DISK_SECTOR_BITS); /* Adjust LEN so it we can't read past the end of the file. */ - if (len > filesize) - len = filesize; + if (pos + len > filesize) + len = filesize - pos; - blockcnt = ((len + pos) + blocksize - 1) / blocksize; + blockcnt = ((len + pos) + blocksize - 1) >> (log2blocksize + GRUB_DISK_SECTOR_BITS); - for (i = pos / blocksize; i < blockcnt; i++) + for (i = pos >> (log2blocksize + GRUB_DISK_SECTOR_BITS); i < blockcnt; i++) { - int blknr; - int blockoff = pos % blocksize; + grub_disk_addr_t blknr; + int blockoff = pos & (blocksize - 1); int blockend = blocksize; int skipfirst = 0; @@ -255,7 +256,7 @@ grub_fshelp_read_file (grub_disk_t disk, grub_fshelp_node_t node, /* Last block. */ if (i == blockcnt - 1) { - blockend = (len + pos) % blocksize; + blockend = (len + pos) & (blocksize - 1); /* The last portion is exactly blocksize. */ if (! blockend) @@ -263,7 +264,7 @@ grub_fshelp_read_file (grub_disk_t disk, grub_fshelp_node_t node, } /* First block. */ - if (i == pos / blocksize) + if (i == (pos >> (log2blocksize + GRUB_DISK_SECTOR_BITS))) { skipfirst = blockoff; blockend -= skipfirst; @@ -310,3 +311,30 @@ grub_fshelp_log2blksize (unsigned int blksize, unsigned int *pow) return GRUB_ERR_NONE; } + +grub_disk_addr_t +grub_fshelp_map_block (grub_fshelp_journal_t log, grub_disk_addr_t block) +{ + int map_block; + + if (! log) + return block; + + for (map_block = log->num_mappings - 1; map_block >= 0; map_block--) + { + if (log->mapping[map_block] == block) + break; + } + + if (map_block < 0) + return block; + + map_block += log->start_block; + if (map_block >= log->last_block) + map_block -= log->last_block - log->first_block; + + if (log->type == GRUB_FSHELP_JOURNAL_TYPE_BLOCK) + return log->blkno + map_block; + else + return log->get_block (log->node, map_block); +} diff --git a/fs/hfsplus.c b/fs/hfsplus.c index fe72539..f4106f0 100644 --- a/fs/hfsplus.c +++ b/fs/hfsplus.c @@ -285,8 +285,8 @@ static int grub_hfsplus_cmp_extkey (struct grub_hfsplus_key *keya, /* Search for the block FILEBLOCK inside the file NODE. Return the blocknumber of this block on disk. */ -static int -grub_hfsplus_read_block (grub_fshelp_node_t node, int fileblock) +static grub_disk_addr_t +grub_hfsplus_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) { struct grub_hfsplus_btnode *nnode = 0; int blksleft = fileblock; diff --git a/fs/ntfs.c b/fs/ntfs.c index 2922ade..786f0e3 100644 --- a/fs/ntfs.c +++ b/fs/ntfs.c @@ -331,8 +331,8 @@ retry: return 0; } -static int -grub_ntfs_read_block (grub_fshelp_node_t node, int block) +static grub_disk_addr_t +grub_ntfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t block) { struct grub_ntfs_rlst *ctx; diff --git a/fs/reiserfs.c b/fs/reiserfs.c index b536b21..87a754c 100644 --- a/fs/reiserfs.c +++ b/fs/reiserfs.c @@ -52,7 +52,8 @@ #define REISERFS_SUPER_BLOCK_OFFSET 0x10000 #define REISERFS_MAGIC_LEN 12 -#define REISERFS_MAGIC_STRING "ReIsEr2Fs\0\0\0" +#define REISERFS_MAGIC_STRING "ReIsEr" +#define REISERFS_MAGIC_DESC_BLOCK "ReIsErLB" /* If the 3rd bit of an item state is set, then it's visible. */ #define GRUB_REISERFS_VISIBLE_MASK ((grub_uint16_t) 0x04) #define REISERFS_MAX_LABEL_LENGTH 16 @@ -109,8 +110,6 @@ struct grub_reiserfs_superblock grub_uint32_t inode_generation; } __attribute__ ((packed)); -#ifdef GRUB_REISERFS_JOURNALING -# error "Journaling not yet supported." struct grub_reiserfs_journal_header { grub_uint32_t last_flush_uid; @@ -118,15 +117,20 @@ struct grub_reiserfs_journal_header grub_uint32_t mount_id; } __attribute__ ((packed)); -struct grub_reiserfs_transaction_header +struct grub_reiserfs_description_block { grub_uint32_t id; grub_uint32_t len; grub_uint32_t mount_id; - char *data; - char checksum[12]; + grub_uint32_t real_blocks[0]; +} __attribute__ ((packed)); + +struct grub_reiserfs_commit_block +{ + grub_uint32_t id; + grub_uint32_t len; + grub_uint32_t real_blocks[0]; } __attribute__ ((packed)); -#endif struct grub_reiserfs_stat_item_v1 { @@ -228,6 +232,7 @@ struct grub_reiserfs_data { struct grub_reiserfs_superblock superblock; grub_disk_t disk; + grub_fshelp_journal_t journal; }; /* Internal-only functions. Not to be used outside of this file. */ @@ -504,8 +509,8 @@ grub_reiserfs_get_item (struct grub_reiserfs_data *data, do { grub_disk_read (data->disk, - (((grub_disk_addr_t) block_number * block_size) - >> GRUB_DISK_SECTOR_BITS), + grub_fshelp_map_block (data->journal, block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS), (((grub_off_t) block_number * block_size) & (GRUB_DISK_SECTOR_SIZE - 1)), block_size, (char *) block_header); @@ -655,8 +660,8 @@ grub_reiserfs_read_symlink (grub_fshelp_node_t node) block_size = grub_le_to_cpu16 (node->data->superblock.block_size); len = grub_le_to_cpu16 (found.header.item_size); - block = (((grub_disk_addr_t) found.block_number * block_size) - >> GRUB_DISK_SECTOR_BITS); + block = (grub_fshelp_map_block (node->data->journal, found.block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS)); offset = grub_le_to_cpu16 (found.header.item_location); symlink_buffer = grub_malloc (len + 1); @@ -675,6 +680,124 @@ grub_reiserfs_read_symlink (grub_fshelp_node_t node) return 0; } +static void +grub_reiserfs_get_journal (struct grub_reiserfs_data *data) +{ + int block_size = grub_le_to_cpu16 (data->superblock.block_size); + char buf[block_size]; + struct grub_reiserfs_journal_header *jh; + grub_fshelp_journal_t log; + grub_uint32_t seq_id, mount_id; + int num_blocks = grub_le_to_cpu32 (data->superblock.journal_original_size); + int base_block = grub_le_to_cpu32 (data->superblock.journal_block); + int last_num, num, block; + + data->journal = 0; + + if (! data->superblock.journal_block) + return; + + if (grub_disk_read (data->disk, + (base_block + num_blocks) + * (block_size >> GRUB_DISK_SECTOR_BITS), + 0, sizeof (struct grub_reiserfs_journal_header), + buf)) + return; + + log = grub_malloc (sizeof (struct grub_fshelp_journal) + + num_blocks * sizeof (grub_disk_addr_t)); + if (! log) + return; + + jh = (struct grub_reiserfs_journal_header *) &buf[0]; + + log->type = GRUB_FSHELP_JOURNAL_TYPE_BLOCK; + log->blkno = base_block; + log->first_block = 0; + log->last_block = num_blocks; + log->start_block = grub_le_to_cpu32 (jh->unflushed_offset); + + seq_id = grub_le_to_cpu32 (jh->last_flush_uid); + mount_id = grub_le_to_cpu32 (jh->mount_id); + + last_num = num = 0; + block = log->start_block; + + while (1) + { + struct grub_reiserfs_description_block *db; + struct grub_reiserfs_commit_block *cb; + grub_uint32_t i, len, half_len, id, mid; + + if (grub_disk_read (data->disk, + (base_block + block) + * (block_size >> GRUB_DISK_SECTOR_BITS), + 0, sizeof (buf), buf)) + break; + + if (grub_memcmp (&buf[block_size - REISERFS_MAGIC_LEN], + REISERFS_MAGIC_DESC_BLOCK, + sizeof (REISERFS_MAGIC_DESC_BLOCK) - 1)) + break; + + db = (struct grub_reiserfs_description_block *) &buf[0]; + id = grub_le_to_cpu32 (db->id); + len = grub_le_to_cpu32 (db->len); + mid = grub_le_to_cpu32 (db->mount_id); + if ((id <= seq_id) && (mid <= mount_id)) + break; + + log->mapping[num++] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING; + half_len = ((block_size - 24) >> 2); + if (half_len > len) + half_len = len; + + for (i = 0; i < half_len; i++) + log->mapping[num++] = db->real_blocks[i]; + + block += grub_le_to_cpu32 (db->len) + 1; + if (block >= log->last_block) + block -= log->last_block; + + if (grub_disk_read (data->disk, + (base_block + block) + * (block_size >> GRUB_DISK_SECTOR_BITS), + 0, sizeof (buf), buf)) + break; + + cb = (struct grub_reiserfs_commit_block *) &buf[0]; + if ((grub_le_to_cpu32 (cb->id) != id) || + (grub_le_to_cpu32 (cb->len) != len)) + break; + + for (i = 0; i < len - half_len; i++) + log->mapping[num++] = cb->real_blocks[i]; + + last_num = num; + log->mapping[num++] = GRUB_FSHELP_JOURNAL_UNUSED_MAPPING; + + block++; + if (block >= log->last_block) + block -= log->last_block; + + seq_id = id; + mount_id = mid; + }; + + if (! last_num) + grub_free (log); + else + { + int size; + + size = sizeof (struct grub_fshelp_journal) + + last_num * sizeof (grub_disk_addr_t); + + log->num_mappings = last_num; + data->journal = grub_realloc (log, size); + } +} + /* Fill the mounted filesystem structure and return it. */ static struct grub_reiserfs_data * grub_reiserfs_mount (grub_disk_t disk) @@ -688,12 +811,13 @@ grub_reiserfs_mount (grub_disk_t disk) if (grub_errno) goto fail; if (grub_memcmp (data->superblock.magic_string, - REISERFS_MAGIC_STRING, REISERFS_MAGIC_LEN)) + REISERFS_MAGIC_STRING, sizeof (REISERFS_MAGIC_STRING) - 1)) { grub_error (GRUB_ERR_BAD_FS, "not a reiserfs filesystem"); goto fail; } data->disk = disk; + grub_reiserfs_get_journal (data); return data; fail: @@ -741,8 +865,8 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item, struct grub_reiserfs_item_header *item_headers; grub_disk_read (data->disk, - (((grub_disk_addr_t) block_number * block_size) - >> GRUB_DISK_SECTOR_BITS), + grub_fshelp_map_block (data->journal, block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS), (((grub_off_t) block_number * block_size) & (GRUB_DISK_SECTOR_SIZE - 1)), block_size, (char *) block_header); @@ -836,7 +960,8 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item, { struct grub_reiserfs_stat_item_v1 entry_v1_stat; grub_disk_read (data->disk, - ((grub_disk_addr_t) entry_block_number * block_size) >> GRUB_DISK_SECTOR_BITS, + grub_fshelp_map_block (data->journal, entry_block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS), grub_le_to_cpu16 (entry_item->header.item_location), sizeof (entry_v1_stat), (char *) &entry_v1_stat); @@ -878,7 +1003,8 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item, { struct grub_reiserfs_stat_item_v2 entry_v2_stat; grub_disk_read (data->disk, - ((grub_disk_addr_t) entry_block_number * block_size) >> GRUB_DISK_SECTOR_BITS, + grub_fshelp_map_block (data->journal, entry_block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS), grub_le_to_cpu16 (entry_item->header.item_location), sizeof (entry_v2_stat), (char *) &entry_v2_stat); @@ -1026,8 +1152,8 @@ grub_reiserfs_open (struct grub_file *file, const char *name) { struct grub_reiserfs_stat_item_v1 entry_v1_stat; grub_disk_read (data->disk, - (((grub_disk_addr_t) block_number * block_size) - >> GRUB_DISK_SECTOR_BITS), + grub_fshelp_map_block (data->journal, block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS), entry_location + (((grub_off_t) block_number * block_size) & (GRUB_DISK_SECTOR_SIZE - 1)), @@ -1040,8 +1166,8 @@ grub_reiserfs_open (struct grub_file *file, const char *name) { struct grub_reiserfs_stat_item_v2 entry_v2_stat; grub_disk_read (data->disk, - (((grub_disk_addr_t) block_number * block_size) - >> GRUB_DISK_SECTOR_BITS), + grub_fshelp_map_block (data->journal, block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS), entry_location + (((grub_off_t) block_number * block_size) & (GRUB_DISK_SECTOR_SIZE - 1)), @@ -1109,8 +1235,8 @@ grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len) switch (found.type) { case GRUB_REISERFS_DIRECT: - block = (((grub_disk_addr_t) found.block_number * block_size) - >> GRUB_DISK_SECTOR_BITS); + block = (grub_fshelp_map_block (data->journal, found.block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS)); grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block); if (initial_position < current_position + item_size) { @@ -1142,8 +1268,8 @@ grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len) if (! indirect_block_ptr) goto fail; grub_disk_read (found.data->disk, - (((grub_disk_addr_t) found.block_number * block_size) - >> GRUB_DISK_SECTOR_BITS), + grub_fshelp_map_block (data->journal, found.block_number) * + (block_size >> GRUB_DISK_SECTOR_BITS), grub_le_to_cpu16 (found.header.item_location), item_size, (char *) indirect_block_ptr); if (grub_errno) @@ -1154,9 +1280,9 @@ grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len) && current_position < final_position; indirect_block++) { - block = ((grub_disk_addr_t) - grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) - * block_size) >> GRUB_DISK_SECTOR_BITS; + block = (grub_fshelp_map_block (data->journal, + grub_le_to_cpu32 (indirect_block_ptr[indirect_block])) * + (block_size >> GRUB_DISK_SECTOR_BITS)); grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block); if (current_position + block_size >= initial_position) { @@ -1255,6 +1381,7 @@ grub_reiserfs_close (grub_file_t file) struct grub_fshelp_node *node = file->data; struct grub_reiserfs_data *data = node->data; + grub_free (data->journal); grub_free (data); grub_free (node); #ifndef GRUB_UTIL diff --git a/fs/sfs.c b/fs/sfs.c index a453bc6..99081bd 100644 --- a/fs/sfs.c +++ b/fs/sfs.c @@ -219,8 +219,8 @@ grub_sfs_read_extent (struct grub_sfs_data *data, unsigned int block, return grub_error (GRUB_ERR_FILE_READ_ERROR, "SFS extent not found"); } -static int -grub_sfs_read_block (grub_fshelp_node_t node, int fileblock) +static grub_disk_addr_t +grub_sfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) { int blk = node->block; int size = 0; @@ -239,7 +239,7 @@ grub_sfs_read_block (grub_fshelp_node_t node, int fileblock) if (err) return 0; - if (fileblock < size) + if (fileblock < (unsigned int) size) return fileblock + blk; fileblock -= size; diff --git a/fs/udf.c b/fs/udf.c index 8f833eb..072e44f 100644 --- a/fs/udf.c +++ b/fs/udf.c @@ -404,8 +404,8 @@ grub_udf_read_icb (struct grub_udf_data *data, return 0; } -static int -grub_udf_read_block (grub_fshelp_node_t node, int fileblock) +static grub_disk_addr_t +grub_udf_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) { char *ptr; int len; @@ -429,7 +429,7 @@ grub_udf_read_block (grub_fshelp_node_t node, int fileblock) len /= sizeof (struct grub_udf_short_ad); while (len > 0) { - if (fileblock < (int) U32 (ad->length)) + if (fileblock < U32 (ad->length)) return ((U32 (ad->position) & GRUB_UDF_EXT_MASK) ? 0 : (grub_udf_get_block (node->data, node->part_ref, @@ -448,7 +448,7 @@ grub_udf_read_block (grub_fshelp_node_t node, int fileblock) len /= sizeof (struct grub_udf_long_ad); while (len > 0) { - if (fileblock < (int) U32 (ad->length)) + if (fileblock < U32 (ad->length)) return ((U32 (ad->block.block_num) & GRUB_UDF_EXT_MASK) ? 0 : (grub_udf_get_block (node->data, ad->block.part_ref, diff --git a/fs/xfs.c b/fs/xfs.c index 88d22be..b8ce3e9 100644 --- a/fs/xfs.c +++ b/fs/xfs.c @@ -220,8 +220,8 @@ grub_xfs_read_inode (struct grub_xfs_data *data, grub_uint64_t ino, } -static int -grub_xfs_read_block (grub_fshelp_node_t node, int fileblock) +static grub_disk_addr_t +grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) { struct grub_xfs_btree_node *leaf = 0; int ex, nrec; @@ -244,7 +244,7 @@ grub_xfs_read_block (grub_fshelp_node_t node, int fileblock) for (i = 0; i < nrec; i++) { - if ((grub_uint64_t) fileblock < grub_be_to_cpu64 (keys[i])) + if (fileblock < grub_be_to_cpu64 (keys[i])) break; } @@ -292,8 +292,8 @@ grub_xfs_read_block (grub_fshelp_node_t node, int fileblock) for (ex = 0; ex < nrec; ex++) { grub_uint64_t start = GRUB_XFS_EXTENT_BLOCK (exts, ex); - int offset = GRUB_XFS_EXTENT_OFFSET (exts, ex); - int size = GRUB_XFS_EXTENT_SIZE (exts, ex); + grub_uint64_t offset = GRUB_XFS_EXTENT_OFFSET (exts, ex); + grub_uint64_t size = GRUB_XFS_EXTENT_SIZE (exts, ex); /* Sparse block. */ if (fileblock < offset) diff --git a/include/grub/fshelp.h b/include/grub/fshelp.h index e25dd16..32d47a3 100644 --- a/include/grub/fshelp.h +++ b/include/grub/fshelp.h @@ -34,6 +34,34 @@ enum grub_fshelp_filetype GRUB_FSHELP_SYMLINK }; +enum grub_fshelp_journal_type + { + GRUB_FSHELP_JOURNAL_TYPE_BLOCK, + GRUB_FSHELP_JOURNAL_TYPE_FILE + }; + +#define GRUB_FSHELP_JOURNAL_UNUSED_MAPPING (grub_disk_addr_t) -1 + +struct grub_fshelp_journal +{ + int type; + union + { + struct + { + grub_fshelp_node_t node; + grub_disk_addr_t (*get_block) (grub_fshelp_node_t node, grub_disk_addr_t block); + }; + grub_disk_addr_t blkno; + }; + int first_block; + int last_block; + int start_block; + int num_mappings; + grub_disk_addr_t mapping[0]; +}; +typedef struct grub_fshelp_journal *grub_fshelp_journal_t; + /* Lookup the node PATH. The node ROOTNODE describes the root of the directory tree. The node found is returned in FOUNDNODE, which is either a ROOTNODE or a new malloc'ed node. ITERATE_DIR is used to @@ -64,15 +92,18 @@ EXPORT_FUNC(grub_fshelp_find_file) (const char *path, grub_ssize_t EXPORT_FUNC(grub_fshelp_read_file) (grub_disk_t disk, grub_fshelp_node_t node, void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector, - unsigned offset, - unsigned length), - int pos, grub_size_t len, char *buf, - int (*get_block) (grub_fshelp_node_t node, - int block), + unsigned offset, + unsigned length), + grub_off_t pos, grub_size_t len, char *buf, + grub_disk_addr_t (*get_block) (grub_fshelp_node_t node, + grub_disk_addr_t block), grub_off_t filesize, int log2blocksize); unsigned int EXPORT_FUNC(grub_fshelp_log2blksize) (unsigned int blksize, unsigned int *pow); +grub_disk_addr_t +EXPORT_FUNC(grub_fshelp_map_block) (grub_fshelp_journal_t log, grub_disk_addr_t block); + #endif /* ! GRUB_FSHELP_HEADER */ ^ permalink raw reply related [flat|nested] 16+ messages in thread
end of thread, other threads:[~2008-05-15 12:19 UTC | newest] Thread overview: 16+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-02-17 19:07 [PATCH] Journal support for ext2 Bean 2008-02-17 22:34 ` Bean 2008-02-17 23:25 ` Bean 2008-02-20 21:37 ` Yoshinori K. Okuji 2008-02-21 3:12 ` Bean 2008-02-21 21:16 ` Yoshinori K. Okuji 2008-03-05 17:24 ` Bean 2008-03-14 6:11 ` Bean 2008-03-14 6:45 ` Marco Gerards 2008-02-18 6:03 ` Robert Millan 2008-02-18 6:15 ` Bean 2008-02-18 14:51 ` Robert Millan -- strict thread matches above, loose matches on Subject: below -- 2008-03-20 0:12 Robert Millan 2008-03-20 6:03 ` Bean 2008-03-20 13:13 ` Robert Millan 2008-05-15 12:18 ` Bean
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.