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

Reply via email to