]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
2008-02-02 Bean <bean123ch@gmail.com>
authorbean <bean@localhost>
Sat, 2 Feb 2008 14:15:31 +0000 (14:15 +0000)
committerbean <bean@localhost>
Sat, 2 Feb 2008 14:15:31 +0000 (14:15 +0000)
        * fs/ufs.c (INODE_BLKSZ): Fix incorrect value.
        (grub_ufs_get_file_block): Fix indirect block calculation problem.

        * fs/xfs.c (grub_xfs_sblock): New member log2_dirblk.
        (grub_xfs_btree_node): New structure.
        (grub_xfs_btree_root): New structure.
        (grub_xfs_inode): New members nblocks, extsize, nextents and btree.
        (GRUB_XFS_EXTENT_OFFSET): Use exts instead of inode->data.extents.
        (GRUB_XFS_EXTENT_BLOCK): Likewise.
        (GRUB_XFS_EXTENT_SIZE): Likewise.
        (grub_xfs_read_block): Support btree format type.
        (grub_xfs_iterate_dir): Use NESTED_FUNC_ATTR in call_hook.
        Use directory block as basic unit.

        * fs/fshelp.c (grub_fshelp_read_file): Bug fix for sparse block.

        * aclocal.m4 (grub_i386_CHECK_REGPARM_BUG): Define NESTED_FUNC_ATTR as
        __attribute__ ((__regparm__ (1))).

ChangeLog
aclocal.m4
configure
fs/fshelp.c
fs/ufs.c
fs/xfs.c

index e386be57a63ebbef85d48cbc8eb20e1ba6748ce9..6e4177f0a8a8bf13e2a86cbb863b2ee2dcc671f7 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2008-02-02  Bean  <bean123ch@gmail.com>
+
+       * fs/ufs.c (INODE_BLKSZ): Fix incorrect value.
+       (grub_ufs_get_file_block): Fix indirect block calculation problem.
+
+       * fs/xfs.c (grub_xfs_sblock): New member log2_dirblk.
+       (grub_xfs_btree_node): New structure.
+       (grub_xfs_btree_root): New structure.
+       (grub_xfs_inode): New members nblocks, extsize, nextents and btree.
+       (GRUB_XFS_EXTENT_OFFSET): Use exts instead of inode->data.extents.
+       (GRUB_XFS_EXTENT_BLOCK): Likewise.
+       (GRUB_XFS_EXTENT_SIZE): Likewise.
+       (grub_xfs_read_block): Support btree format type.
+       (grub_xfs_iterate_dir): Use NESTED_FUNC_ATTR in call_hook.
+       Use directory block as basic unit.
+
+       * fs/fshelp.c (grub_fshelp_read_file): Bug fix for sparse block.
+
+       * aclocal.m4 (grub_i386_CHECK_REGPARM_BUG): Define NESTED_FUNC_ATTR as
+       __attribute__ ((__regparm__ (1))).
+
 2008-02-01  Robert Millan  <rmh@aybabtu.com>
 
        Correct a mistake in previous commit.
index 803d57b9147241cd1202c23ad0895a283fd564b6..a634253bb6c1fbc40c8fbd5fb68ca54cfbcc5d0d 100644 (file)
@@ -333,13 +333,13 @@ AC_MSG_RESULT([$grub_cv_i386_check_nested_functions])
 
 if test "x$grub_cv_i386_check_nested_functions" = xyes; then
   AC_DEFINE([NESTED_FUNC_ATTR], 
-       [__attribute__ ((__regparm__ (2)))],
+       [__attribute__ ((__regparm__ (1)))],
        [Catch gcc bug])
 else
 dnl Unfortunately, the above test does not detect a bug in gcc-4.0.
 dnl So use regparm 2 until a better test is found.
   AC_DEFINE([NESTED_FUNC_ATTR], 
-       [__attribute__ ((__regparm__ (2)))],
+       [__attribute__ ((__regparm__ (1)))],
        [Catch gcc bug])
 fi
 ])
index d272ea682ab862144a9c43689688d35f6ad55f7e..24b2f43ea487e2babedc5a7e665b45fc080d44f9 100644 (file)
--- a/configure
+++ b/configure
@@ -7512,13 +7512,13 @@ echo "${ECHO_T}$grub_cv_i386_check_nested_functions" >&6; }
 if test "x$grub_cv_i386_check_nested_functions" = xyes; then
 
 cat >>confdefs.h <<\_ACEOF
-#define NESTED_FUNC_ATTR __attribute__ ((__regparm__ (2)))
+#define NESTED_FUNC_ATTR __attribute__ ((__regparm__ (1)))
 _ACEOF
 
 else
 
 cat >>confdefs.h <<\_ACEOF
-#define NESTED_FUNC_ATTR __attribute__ ((__regparm__ (2)))
+#define NESTED_FUNC_ATTR __attribute__ ((__regparm__ (1)))
 _ACEOF
 
 fi
index ba97a2fdb77ed3402dab1b1fe85fa54e0945075f..bbb58ac9ff57de16a5ba9651cde53e423b919629 100644 (file)
@@ -282,7 +282,7 @@ grub_fshelp_read_file (grub_disk_t disk, grub_fshelp_node_t node,
            return -1;
        }
       else
-       grub_memset (buf, blocksize - skipfirst, 0);
+       grub_memset (buf, 0, blockend);
 
       buf += blocksize - skipfirst;
     }
index 25cd1fa34cc79644f4d95b4aa723249d21811b20..ebb71987868e964b5c1a0d599b11c603ca0adb54 100644 (file)
--- a/fs/ufs.c
+++ b/fs/ufs.c
@@ -52,7 +52,7 @@
                            grub_le_to_cpu##bits2 (data->inode2.field))
 #define INODE_SIZE(data) INODE_ENDIAN (data,size,32,64)
 #define INODE_MODE(data) INODE_ENDIAN (data,mode,16,16)
-#define INODE_BLKSZ(data) (data->ufs_type == UFS1 ? 32 : 64)
+#define INODE_BLKSZ(data) (data->ufs_type == UFS1 ? 4 : 8)
 #define INODE_DIRBLOCKS(data,blk) INODE_ENDIAN \
                                    (data,blocks.dir_blocks[blk],32,64)
 #define INODE_INDIRBLOCKS(data,blk) INODE_ENDIAN \
@@ -205,35 +205,41 @@ grub_ufs_get_file_block (struct grub_ufs_data *data, unsigned int blk)
 {
   struct grub_ufs_sblock *sblock = &data->sblock;
   unsigned int indirsz;
+  int log2_blksz; 
   
   /* Direct.  */
   if (blk < GRUB_UFS_DIRBLKS)
     return INODE_DIRBLOCKS (data, blk);
   
+  log2_blksz = grub_le_to_cpu32 (data->sblock.log2_blksz);
+  
   blk -= GRUB_UFS_DIRBLKS;
   
   indirsz = UFS_BLKSZ (sblock) / INODE_BLKSZ (data);
   /* Single indirect block.  */
   if (blk < indirsz)
     {
-      grub_uint32_t indir[UFS_BLKSZ (sblock)];
-      grub_disk_read (data->disk, INODE_INDIRBLOCKS (data, 0),
+      grub_uint32_t indir[UFS_BLKSZ (sblock) >> 2];
+      grub_disk_read (data->disk, INODE_INDIRBLOCKS (data, 0) << log2_blksz,
                      0, sizeof (indir), (char *) indir);
-      return indir[blk];
+      return (data->ufs_type == UFS1) ? indir[blk] : indir[blk << 1];
     }
   blk -= indirsz;
   
   /* Double indirect block.  */
   if (blk < UFS_BLKSZ (sblock) / indirsz)
     {
-      grub_uint32_t indir[UFS_BLKSZ (sblock)];
+      grub_uint32_t indir[UFS_BLKSZ (sblock) >> 2];
       
-      grub_disk_read (data->disk, INODE_INDIRBLOCKS (data, 1),
+      grub_disk_read (data->disk, INODE_INDIRBLOCKS (data, 1) << log2_blksz,
                      0, sizeof (indir), (char *) indir);
-      grub_disk_read (data->disk,  indir[blk / indirsz],
+      grub_disk_read (data->disk,
+                     (data->ufs_type == UFS1) ?
+                     indir[blk / indirsz] : indir [(blk / indirsz) << 1],
                      0, sizeof (indir), (char *) indir);
       
-      return indir[blk % indirsz];
+      return (data->ufs_type == UFS1) ?
+            indir[blk % indirsz] : indir[(blk % indirsz) << 1];
     }
 
 
index b3154c7ceb48d1303d44f2df510927aabb712521..88d22be6d150cd98350b156e08e8a3289191fa8e 100644 (file)
--- a/fs/xfs.c
+++ b/fs/xfs.c
@@ -47,6 +47,8 @@ struct grub_xfs_sblock
   grub_uint8_t unused4[2];
   grub_uint8_t log2_inop;
   grub_uint8_t log2_agblk;
+  grub_uint8_t unused5[67];
+  grub_uint8_t log2_dirblk;
 } __attribute__ ((packed));
 
 struct grub_xfs_dir_header
@@ -72,6 +74,23 @@ struct grub_xfs_dir2_entry
 
 typedef grub_uint32_t grub_xfs_extent[4];
 
+struct grub_xfs_btree_node
+{
+  grub_uint8_t magic[4];
+  grub_uint16_t level;
+  grub_uint16_t numrecs;
+  grub_uint64_t left;
+  grub_uint64_t right;
+  grub_uint64_t keys[1];
+}  __attribute__ ((packed));
+
+struct grub_xfs_btree_root
+{
+  grub_uint16_t level;
+  grub_uint16_t numrecs;
+  grub_uint64_t keys[1];
+}  __attribute__ ((packed));
+
 struct grub_xfs_inode
 {
   grub_uint8_t magic[2];
@@ -80,7 +99,10 @@ struct grub_xfs_inode
   grub_uint8_t format;
   grub_uint8_t unused2[50];
   grub_uint64_t size;
-  grub_uint8_t unused3[36];
+  grub_uint64_t nblocks;
+  grub_uint32_t extsize;
+  grub_uint32_t nextents;
+  grub_uint8_t unused3[20];
   union
   {
     char raw[156];
@@ -90,6 +112,7 @@ struct grub_xfs_inode
       struct grub_xfs_dir_entry direntry[1];
     } dir;
     grub_xfs_extent extents[XFS_INODE_EXTENTS];
+    struct grub_xfs_btree_root btree;
   } data __attribute__ ((packed));
 } __attribute__ ((packed));
 
@@ -138,18 +161,18 @@ static grub_dl_t my_mod;
 #define GRUB_XFS_INO_AG(data,ino)              \
   (grub_be_to_cpu64 (ino) >> GRUB_XFS_INO_AGBITS (data))
 
-#define GRUB_XFS_EXTENT_OFFSET(inode,ex) \
-       ((grub_be_to_cpu32 ((inode)->data.extents[ex][0]) & ~(1 << 31)) << 23 \
-       | grub_be_to_cpu32 ((inode)->data.extents[ex][1]) >> 9)
+#define GRUB_XFS_EXTENT_OFFSET(exts,ex) \
+       ((grub_be_to_cpu32 (exts[ex][0]) & ~(1 << 31)) << 23 \
+       | grub_be_to_cpu32 (exts[ex][1]) >> 9)
 
-#define GRUB_XFS_EXTENT_BLOCK(inode,ex)                \
-  ((grub_uint64_t) (grub_be_to_cpu32 ((inode)->data.extents[ex][1]) \
-                 & (~255)) << 43 \
-   | (grub_uint64_t) grub_be_to_cpu32 ((inode)->data.extents[ex][2]) << 11 \
-   | grub_be_to_cpu32 ((inode)->data.extents[ex][3]) >> 21)
+#define GRUB_XFS_EXTENT_BLOCK(exts,ex)         \
+  ((grub_uint64_t) (grub_be_to_cpu32 (exts[ex][1]) \
+                 & (0x1ff)) << 43 \
+   | (grub_uint64_t) grub_be_to_cpu32 (exts[ex][2]) << 11 \
+   | grub_be_to_cpu32 (exts[ex][3]) >> 21)
 
-#define GRUB_XFS_EXTENT_SIZE(inode,ex)         \
-  (grub_be_to_cpu32 ((inode)->data.extents[ex][3]) & ((1 << 20) - 1))
+#define GRUB_XFS_EXTENT_SIZE(exts,ex)          \
+  (grub_be_to_cpu32 (exts[ex][3]) & ((1 << 20) - 1))
 
 #define GRUB_XFS_ROUND_TO_DIRENT(pos)  ((((pos) + 8 - 1) / 8) * 8)
 #define GRUB_XFS_NEXT_DIRENT(pos,len)          \
@@ -200,9 +223,63 @@ 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)
 {
-  int ex;
+  struct grub_xfs_btree_node *leaf = 0;
+  int ex, nrec;
+  grub_xfs_extent *exts;
+  grub_uint64_t ret = 0;
 
-  if (node->inode.format != XFS_INODE_FORMAT_EXT)
+  if (node->inode.format == XFS_INODE_FORMAT_BTREE)
+    {
+      grub_uint64_t *keys;
+
+      leaf = grub_malloc (node->data->sblock.bsize);
+      if (leaf == 0)
+        return 0;
+
+      nrec = grub_be_to_cpu16 (node->inode.data.btree.numrecs);
+      keys = &node->inode.data.btree.keys[0];
+      do
+        {
+          int i;
+
+          for (i = 0; i < nrec; i++)
+            {
+              if ((grub_uint64_t) fileblock < grub_be_to_cpu64 (keys[i]))
+                break;
+            }
+
+          /* Sparse block.  */
+          if (i == 0)
+            {
+              grub_free (leaf);
+              return 0;
+            }
+
+          if (grub_disk_read (node->data->disk,
+                              grub_be_to_cpu64 (keys[i - 1 + XFS_INODE_EXTENTS])
+                              << (node->data->sblock.log2_bsize
+                                  - GRUB_DISK_SECTOR_BITS),
+                              0, node->data->sblock.bsize, (char *) leaf))
+            return 0;
+
+          if (grub_strncmp ((char *) leaf->magic, "BMAP", 4))
+            {
+              grub_free (leaf);
+              grub_error (GRUB_ERR_BAD_FS, "not a correct XFS BMAP node.\n");
+              return 0;
+            }
+
+          nrec = grub_be_to_cpu16 (leaf->numrecs);
+          keys = &leaf->keys[0];
+        } while (leaf->level);
+      exts = (grub_xfs_extent *) keys;
+    }
+  else if (node->inode.format == XFS_INODE_FORMAT_EXT)
+    {
+      nrec = grub_be_to_cpu32 (node->inode.nextents);
+      exts = &node->inode.data.extents[0];
+    }
+  else
     {
       grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
                  "xfs does not support inode format %d yet",
@@ -212,23 +289,26 @@ grub_xfs_read_block (grub_fshelp_node_t node, int fileblock)
 
   /* Iterate over each extent to figure out which extent has
      the block we are looking for.  */
-  for (ex = 0; ex < XFS_INODE_EXTENTS; ex++)
+  for (ex = 0; ex < nrec; ex++)
     {
-      grub_uint64_t start = GRUB_XFS_EXTENT_BLOCK (&node->inode, ex);
-      int offset = GRUB_XFS_EXTENT_OFFSET (&node->inode, ex);
-      int size = GRUB_XFS_EXTENT_SIZE (&node->inode, ex);
-
-      unsigned int ag = start >> node->data->sblock.log2_agblk;
-      unsigned int block = start & ((1 << node->data->sblock.log2_agblk) - 1);
-
-      if (fileblock < offset + size)
-       return (fileblock - offset + block) + ag * node->data->agsize;
+      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);
+
+      /* Sparse block.  */
+      if (fileblock < offset)
+        break;
+      else if (fileblock < offset + size)
+        {
+          ret = (fileblock - offset + start);
+          break;
+        }
     }
 
-  grub_error (GRUB_ERR_FILE_READ_ERROR,
-             "xfs block %d for inode %d is not in an extent.\n",
-             fileblock, grub_be_to_cpu64 (node->ino));
-  return 0;
+  if (leaf)
+    grub_free (leaf);
+
+  return ret;
 }
 
 
@@ -306,9 +386,9 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
                                grub_fshelp_node_t node))
 {
   struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
-  auto int call_hook (grub_uint64_t ino, char *filename);
+  auto int NESTED_FUNC_ATTR call_hook (grub_uint64_t ino, char *filename);
     
-  int call_hook (grub_uint64_t ino, char *filename)
+  int NESTED_FUNC_ATTR call_hook (grub_uint64_t ino, char *filename)
     {
       struct grub_fshelp_node *fdiro;
 
@@ -393,38 +473,43 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
        grub_ssize_t numread;
        char *dirblock;
        grub_uint64_t blk;
+        int dirblk_size, dirblk_log2;
 
-       dirblock = grub_malloc (dir->data->bsize);
+        dirblk_log2 = (dir->data->sblock.log2_bsize
+                       + dir->data->sblock.log2_dirblk);
+        dirblk_size = 1 << dirblk_log2;
+
+       dirblock = grub_malloc (dirblk_size);
        if (! dirblock)
          return 0;
 
        /* Iterate over every block the directory has.  */
        for (blk = 0;
             blk < (grub_be_to_cpu64 (dir->inode.size) 
-                   >> dir->data->sblock.log2_bsize);
+                   >> dirblk_log2);
             blk++)
          {
            /* The header is skipped, the first direntry is stored
               from byte 16.  */
            int pos = 16;
            int entries;
-           int tail_start = (dir->data->bsize
+           int tail_start = (dirblk_size
                              - sizeof (struct grub_xfs_dirblock_tail));
 
            struct grub_xfs_dirblock_tail *tail;
            tail = (struct grub_xfs_dirblock_tail *) &dirblock[tail_start];
 
            numread = grub_xfs_read_file (dir, 0,
-                                         blk << dir->data->sblock.log2_bsize,
-                                         dir->data->bsize, dirblock);
-           if (numread != dir->data->bsize)
+                                         blk << dirblk_log2,
+                                         dirblk_size, dirblock);
+           if (numread != dirblk_size)
              return 0;
 
            entries = (grub_be_to_cpu32 (tail->leaf_count)
                       - grub_be_to_cpu32 (tail->leaf_stale));
 
            /* Iterate over all entries within this block.  */
-           while (pos < (dir->data->bsize
+           while (pos < (dirblk_size
                          - (int) sizeof (struct grub_xfs_dir2_entry)))
              {
                struct grub_xfs_dir2_entry *direntry;
@@ -703,4 +788,3 @@ GRUB_MOD_FINI(xfs)
 {
   grub_fs_unregister (&grub_xfs_fs);
 }
-