Hi,

This patch extends fshelp for general journal handling, it also
implement journaling for ext2 file system.

2008-02-18  Bean  <[EMAIL PROTECTED]>

        * 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
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
 
 
-
-/* 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 */
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to