This new patch add journal support for reiserfs file system.
--
Bean
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
_______________________________________________
Grub-devel mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/grub-devel