]> git.proxmox.com Git - grub2.git/commitdiff
* include/grub/disk.h (GRUB_DISK_SIZE_UNKNOWN): New macro.
authorJiro SEKIBA <jir@unicus.jp>
Mon, 31 May 2010 18:49:42 +0000 (20:49 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Mon, 31 May 2010 18:49:42 +0000 (20:49 +0200)
* fs/nilfs.c: Support 2nd super block in case 1st one is accidently
corrupted or not synced properly.

ChangeLog
fs/nilfs2.c
include/grub/disk.h

index 2d9015cfba1d23977e0cfa1b058903f343e1069d..a3584355469ed8d17fabac1201604ef310919079 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2010-05-31  Jiro SEKIBA <jir@unicus.jp>
+
+       * include/grub/disk.h (GRUB_DISK_SIZE_UNKNOWN): New macro.
+       * fs/nilfs.c: Support 2nd super block in case 1st one is accidently
+       corrupted or not synced properly.
+
 2010-05-31  Vladimir Serbinenko  <phcoder@gmail.com>
 
        * normal/main.c (grub_normal_add_menu_entry): Avoid going out of args.
index 7e0415d128f76a0b18e39e6f138e32155c9588be..5d32f5f88d6ae88e852e5200b91dbb78c8509f9f 100644 (file)
 #define NILFS_BTREE_LEVEL_NODE_MIN      (NILFS_BTREE_LEVEL_DATA + 1)
 #define NILFS_BTREE_LEVEL_MAX           14
 
+/* nilfs 1st super block posission from beginning of the partition
+   in 512 block size */
+#define NILFS_1ST_SUPER_BLOCK  2
+/* nilfs 2nd super block posission from end of the partition
+   in 512 block size */
+#define NILFS_2ND_SUPER_BLOCK  8
+
 struct grub_nilfs2_inode
 {
   grub_uint64_t i_blocks;
@@ -703,6 +710,52 @@ grub_nilfs2_valid_sb (struct grub_nilfs2_super_block *sbp)
   return 1;
 }
 
+static grub_err_t
+grub_nilfs2_load_sb (struct grub_nilfs2_data *data)
+{
+  grub_disk_t disk = data->disk;
+  struct grub_nilfs2_super_block sb2;
+  grub_uint64_t partition_size;
+  int valid[2];
+  int swp = 0;
+
+  /* Read first super block. */
+  grub_disk_read (disk, NILFS_1ST_SUPER_BLOCK, 0,
+                 sizeof (struct grub_nilfs2_super_block), &data->sblock);
+  /* Make sure if 1st super block is valid.  */
+  valid[0] = grub_nilfs2_valid_sb (&data->sblock);
+
+  partition_size = grub_disk_get_size (disk);
+  if (partition_size != GRUB_DISK_SIZE_UNKNOWN)
+    {
+      /* Read second super block. */
+      grub_disk_read (disk, partition_size - NILFS_2ND_SUPER_BLOCK, 0,
+                     sizeof (struct grub_nilfs2_super_block), &sb2);
+      /* Make sure if 2nd super block is valid.  */
+      valid[1] = grub_nilfs2_valid_sb (&sb2);
+    }
+  else
+    /* 2nd super block may not exist, so it's invalid. */
+    valid[1] = 0;
+
+
+
+  if (!valid[0] && !valid[1])
+    return grub_error (GRUB_ERR_BAD_FS, "not a nilfs2 filesystem");
+
+  swp = valid[1] && (!valid[0] ||
+                    grub_le_to_cpu64 (data->sblock.s_last_cno) <
+                    grub_le_to_cpu64 (sb2.s_last_cno));
+
+  /* swap if first super block is invalid or older than second one. */
+  if (swp)
+    grub_memcpy (&data->sblock, &sb2,
+                sizeof (struct grub_nilfs2_super_block));
+
+  grub_errno = GRUB_ERR_NONE;
+  return grub_errno;
+}
+
 static struct grub_nilfs2_data *
 grub_nilfs2_mount (grub_disk_t disk)
 {
@@ -717,19 +770,13 @@ grub_nilfs2_mount (grub_disk_t disk)
   if (!data)
     return 0;
 
+  data->disk = disk;
+
   /* Read the superblock.  */
-  grub_disk_read (disk, 1 * 2, 0, sizeof (struct grub_nilfs2_super_block),
-                 &data->sblock);
+  grub_nilfs2_load_sb (data);
   if (grub_errno)
     goto fail;
 
-  /* Make sure this is an nilfs2 filesystem.  */
-  if (!grub_nilfs2_valid_sb (&data->sblock))
-    {
-      grub_error (GRUB_ERR_BAD_FS, "not a nilfs2 filesystem");
-      goto fail;
-    }
-
   nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data));
 
   /* Read the last segment summary. */
@@ -748,8 +795,6 @@ grub_nilfs2_mount (grub_disk_t disk)
   if (grub_errno)
     goto fail;
 
-  data->disk = disk;
-
   grub_nilfs2_read_last_checkpoint (data, &last_checkpoint);
 
   if (grub_errno)
index e60b1f3de5a3a43b936c665f67f8caee5500d042..e7f807e0efbe0c10c2ef48cc140d6ad77238a24f 100644 (file)
@@ -138,6 +138,9 @@ typedef struct grub_disk_memberlist *grub_disk_memberlist_t;
 #define GRUB_DISK_CACHE_SIZE   8
 #define GRUB_DISK_CACHE_BITS   3
 
+/* Return value of grub_disk_get_size() in case disk size is unknown. */
+#define GRUB_DISK_SIZE_UNKNOWN  0xffffffffffffffffULL
+
 /* This is called from the memory manager.  */
 void grub_disk_cache_invalidate_all (void);