[packages/grub2] - add fixes for XFS support (patches from openSUSE) - rel 4

baggins baggins at pld-linux.org
Mon Jan 19 22:11:30 CET 2015


commit 2c79d729d4cbf15ad7e20542b6e5a62184613fa2
Author: Jan Rękorajski <baggins at pld-linux.org>
Date:   Mon Jan 19 22:10:55 2015 +0100

    - add fixes for XFS support (patches from openSUSE)
    - rel 4

 grub2-xfs-Add-helper-for-inode-size.patch          |  76 ++++
 ...-inode-numbers-to-cpu-endianity-immediate.patch |  82 ++++
 ...-termination-loop-for-directory-iteration.patch |  32 ++
 grub2-xfs-V5-filesystem-format-support.patch       | 478 +++++++++++++++++++++
 grub2.spec                                         |  10 +-
 5 files changed, 677 insertions(+), 1 deletion(-)
---
diff --git a/grub2.spec b/grub2.spec
index 0f1fb0d..81f2d17 100644
--- a/grub2.spec
+++ b/grub2.spec
@@ -47,7 +47,7 @@ Summary(pt_BR.UTF-8):	Gerenciador de inicialização GRUB2
 %define	beta	beta2
 Name:		grub2
 Version:	2.02
-Release:	0.%{beta}.3
+Release:	0.%{beta}.4
 License:	GPL v2
 Group:		Base
 # git://git.savannah.gnu.org/grub.git
@@ -75,6 +75,10 @@ Patch10:	ignore-kernel-symlinks.patch
 Patch11:	choose-preferred-initrd.patch
 Patch12:	%{name}-cfg.patch
 Patch13:	efi-net-fix.patch
+Patch14:	grub2-xfs-Add-helper-for-inode-size.patch
+Patch15:	grub2-xfs-Convert-inode-numbers-to-cpu-endianity-immediate.patch
+Patch16:	grub2-xfs-Fix-termination-loop-for-directory-iteration.patch
+Patch17:	grub2-xfs-V5-filesystem-format-support.patch
 URL:		http://www.gnu.org/software/grub/
 BuildRequires:	autoconf >= 2.53
 BuildRequires:	automake >= 1:1.11.1-1
@@ -302,6 +306,10 @@ Motyw starfield dla GRUB-a.
 %patch11 -p1
 %patch12 -p0
 %patch13 -p1
+%patch14 -p1
+%patch15 -p1
+%patch16 -p1
+%patch17 -p1
 
 # we don't have C.utf-8 and need an UTF-8 locale for build
 sed -i -e 's/LC_ALL=C.UTF-8/LC_ALL=en_US.utf-8/g' po/Makefile* po/Rules*
diff --git a/grub2-xfs-Add-helper-for-inode-size.patch b/grub2-xfs-Add-helper-for-inode-size.patch
new file mode 100644
index 0000000..47abde2
--- /dev/null
+++ b/grub2-xfs-Add-helper-for-inode-size.patch
@@ -0,0 +1,76 @@
+From 34231b28cbb6b2e10d7668c5b6d2432e8563bd1d Mon Sep 17 00:00:00 2001
+From: Jan Kara <jack at suse.cz>
+Date: Thu, 5 Jun 2014 20:56:21 +0200
+Subject: [PATCH 1/4] xfs: Add helper for inode size
+
+Signed-off-by: Jan Kara <jack at suse.cz>
+---
+ grub-core/fs/xfs.c | 17 +++++++++++------
+ 1 file changed, 11 insertions(+), 6 deletions(-)
+
+diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
+index 16ffd3f1ebd9..a2fc942707c1 100644
+--- a/grub-core/fs/xfs.c
++++ b/grub-core/fs/xfs.c
+@@ -255,6 +255,11 @@ grub_xfs_inode_offset (struct grub_xfs_data *data,
+ 	  data->sblock.log2_inode);
+ }
+ 
++static inline int
++grub_xfs_inode_size(struct grub_xfs_data *data)
++{
++	return 1 << data->sblock.log2_inode;
++}
+ 
+ static grub_err_t
+ grub_xfs_read_inode (struct grub_xfs_data *data, grub_uint64_t ino,
+@@ -264,8 +269,8 @@ grub_xfs_read_inode (struct grub_xfs_data *data, grub_uint64_t ino,
+   int offset = grub_xfs_inode_offset (data, ino);
+ 
+   /* Read the inode.  */
+-  if (grub_disk_read (data->disk, block, offset,
+-		      1 << data->sblock.log2_inode, inode))
++  if (grub_disk_read (data->disk, block, offset, grub_xfs_inode_size(data),
++		      inode))
+     return grub_errno;
+ 
+   if (grub_strncmp ((char *) inode->magic, "IN", 2))
+@@ -297,7 +302,7 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
+       if (node->inode.fork_offset)
+ 	recoffset = (node->inode.fork_offset - 1) / 2;
+       else
+-	recoffset = ((1 << node->data->sblock.log2_inode)
++	recoffset = (grub_xfs_inode_size(node->data)
+ 		     - ((char *) &node->inode.data.btree.keys
+ 			- (char *) &node->inode))
+ 	  / (2 * sizeof (grub_uint64_t));
+@@ -458,7 +463,7 @@ static int iterate_dir_call_hook (grub_uint64_t ino, const char *filename,
+ 
+   fdiro = grub_malloc (sizeof (struct grub_fshelp_node)
+ 		       - sizeof (struct grub_xfs_inode)
+-		       + (1 << ctx->diro->data->sblock.log2_inode) + 1);
++		       + grub_xfs_inode_size(ctx->diro->data) + 1);
+   if (!fdiro)
+     {
+       grub_print_error ();
+@@ -684,7 +689,7 @@ grub_xfs_mount (grub_disk_t disk)
+   data = grub_realloc (data,
+ 		       sizeof (struct grub_xfs_data)
+ 		       - sizeof (struct grub_xfs_inode)
+-		       + (1 << data->sblock.log2_inode) + 1);
++		       + grub_xfs_inode_size(data) + 1);
+ 
+   if (! data)
+     goto fail;
+@@ -802,7 +807,7 @@ grub_xfs_open (struct grub_file *file, const char *name)
+       grub_memcpy (&data->diropen, fdiro,
+ 		   sizeof (struct grub_fshelp_node)
+ 		   - sizeof (struct grub_xfs_inode)
+-		   + (1 << data->sblock.log2_inode));
++		   + grub_xfs_inode_size(data));
+       grub_free (fdiro);
+     }
+ 
+-- 
+1.8.1.4
+
diff --git a/grub2-xfs-Convert-inode-numbers-to-cpu-endianity-immediate.patch b/grub2-xfs-Convert-inode-numbers-to-cpu-endianity-immediate.patch
new file mode 100644
index 0000000..c5b6b0f
--- /dev/null
+++ b/grub2-xfs-Convert-inode-numbers-to-cpu-endianity-immediate.patch
@@ -0,0 +1,82 @@
+From 57ae4073cc28fa74014a62aca397a40ce1f73763 Mon Sep 17 00:00:00 2001
+From: Jan Kara <jack at suse.cz>
+Date: Thu, 12 Jun 2014 11:01:11 +0200
+Subject: [PATCH 3/4] xfs: Convert inode numbers to cpu endianity immediately
+ after reading
+
+Currently XFS driver converted inode numbers to native endianity only
+when using them to compute inode position. Although this works, it is
+somewhat confusing. So convert inode numbers when reading them from disk
+structures as every other field.
+
+Signed-off-by: Jan Kara <jack at suse.cz>
+---
+ grub-core/fs/xfs.c | 13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
+index ef3bc787e968..7e247a32df5c 100644
+--- a/grub-core/fs/xfs.c
++++ b/grub-core/fs/xfs.c
+@@ -180,14 +180,14 @@ static inline grub_uint64_t
+ GRUB_XFS_INO_INOINAG (struct grub_xfs_data *data,
+ 		      grub_uint64_t ino)
+ {
+-  return (grub_be_to_cpu64 (ino) & ((1LL << GRUB_XFS_INO_AGBITS (data)) - 1));
++  return (ino & ((1LL << GRUB_XFS_INO_AGBITS (data)) - 1));
+ }
+ 
+ static inline grub_uint64_t
+ GRUB_XFS_INO_AG (struct grub_xfs_data *data,
+ 		 grub_uint64_t ino)
+ {
+-  return (grub_be_to_cpu64 (ino) >> GRUB_XFS_INO_AGBITS (data));
++  return (ino >> GRUB_XFS_INO_AGBITS (data));
+ }
+ 
+ static inline grub_disk_addr_t
+@@ -511,13 +511,12 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
+ 	if (smallino)
+ 	  {
+ 	    parent = grub_be_to_cpu32 (diro->inode.data.dir.dirhead.parent.i4);
+-	    parent = grub_cpu_to_be64 (parent);
+ 	    /* The header is a bit smaller than usual.  */
+ 	    de = (struct grub_xfs_dir_entry *) ((char *) de - 4);
+ 	  }
+ 	else
+ 	  {
+-	    parent = diro->inode.data.dir.dirhead.parent.i8;
++	    parent = grub_be_to_cpu64(diro->inode.data.dir.dirhead.parent.i8);
+ 	  }
+ 
+ 	/* Synthesize the direntries for `.' and `..'.  */
+@@ -550,7 +549,6 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
+ 		| (((grub_uint64_t) inopos[5]) << 16)
+ 		| (((grub_uint64_t) inopos[6]) << 8)
+ 		| (((grub_uint64_t) inopos[7]) << 0);
+-	    ino = grub_cpu_to_be64 (ino);
+ 
+ 	    c = de->name[de->len];
+ 	    de->name[de->len] = '\0';
+@@ -632,7 +630,8 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
+ 		   is not used by GRUB.  So it can be overwritten.  */
+ 		filename[direntry->len] = '\0';
+ 
+-		if (iterate_dir_call_hook (direntry->inode, filename, &ctx))
++		if (iterate_dir_call_hook (grub_be_to_cpu64(direntry->inode), 
++					   filename, &ctx))
+ 		  {
+ 		    grub_free (dirblock);
+ 		    return 1;
+@@ -694,7 +693,7 @@ grub_xfs_mount (grub_disk_t disk)
+     goto fail;
+ 
+   data->diropen.data = data;
+-  data->diropen.ino = data->sblock.rootino;
++  data->diropen.ino = grub_be_to_cpu64(data->sblock.rootino);
+   data->diropen.inode_read = 1;
+   data->bsize = grub_be_to_cpu32 (data->sblock.bsize);
+   data->agsize = grub_be_to_cpu32 (data->sblock.agsize);
+-- 
+1.8.1.4
+
diff --git a/grub2-xfs-Fix-termination-loop-for-directory-iteration.patch b/grub2-xfs-Fix-termination-loop-for-directory-iteration.patch
new file mode 100644
index 0000000..a35fc93
--- /dev/null
+++ b/grub2-xfs-Fix-termination-loop-for-directory-iteration.patch
@@ -0,0 +1,32 @@
+From a7d584c005bde09bb86475a79d714215b3480821 Mon Sep 17 00:00:00 2001
+From: Jan Kara <jack at suse.cz>
+Date: Wed, 11 Jun 2014 18:36:59 +0200
+Subject: [PATCH 2/4] xfs: Fix termination loop for directory iteration
+
+Directory iteration used wrong position (sizeof wrong structure) for
+termination of iteration inside a directory block. Luckily the position
+ended up being wrong by just 1 byte and directory entries are larger so
+things worked out fine in practice. But fix the problem anyway.
+
+Signed-off-by: Jan Kara <jack at suse.cz>
+---
+ grub-core/fs/xfs.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
+index a2fc942707c1..ef3bc787e968 100644
+--- a/grub-core/fs/xfs.c
++++ b/grub-core/fs/xfs.c
+@@ -608,8 +608,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
+ 		       - grub_be_to_cpu32 (tail->leaf_stale));
+ 
+ 	    /* Iterate over all entries within this block.  */
+-	    while (pos < (dirblk_size
+-			  - (int) sizeof (struct grub_xfs_dir2_entry)))
++	    while (pos < tail_start)
+ 	      {
+ 		struct grub_xfs_dir2_entry *direntry;
+ 		grub_uint8_t *freetag;
+-- 
+1.8.1.4
+
diff --git a/grub2-xfs-V5-filesystem-format-support.patch b/grub2-xfs-V5-filesystem-format-support.patch
new file mode 100644
index 0000000..56318d4
--- /dev/null
+++ b/grub2-xfs-V5-filesystem-format-support.patch
@@ -0,0 +1,478 @@
+From 2f725e644d8ccf001a4dccddc8abb2c9479352a7 Mon Sep 17 00:00:00 2001
+From: Jan Kara <jack at suse.cz>
+Date: Wed, 11 Jun 2014 18:36:01 +0200
+Subject: [PATCH] xfs: V5 filesystem format support
+
+Signed-off-by: Jan Kara <jack at suse.cz>
+---
+ grub-core/fs/xfs.c | 245 +++++++++++++++++++++++++++++++++++++----------------
+ 1 file changed, 173 insertions(+), 72 deletions(-)
+
+Index: grub-2.02~beta2/grub-core/fs/xfs.c
+===================================================================
+--- grub-2.02~beta2.orig/grub-core/fs/xfs.c
++++ grub-2.02~beta2/grub-core/fs/xfs.c
+@@ -34,6 +34,15 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ #define XFS_INODE_FORMAT_EXT	2
+ #define XFS_INODE_FORMAT_BTREE	3
+ 
++/* Superblock version field flags */
++#define XFS_SB_VERSION_NUMBITS          0x000f
++#define XFS_SB_VERSION_MOREBITSBIT      0x8000
++
++/* features2 field flags */
++#define XFS_SB_VERSION2_FTYPE           0x00000200      /* inode type in dir */
++
++/* incompat feature flags */
++#define XFS_SB_FEAT_INCOMPAT_FTYPE      (1 << 0)        /* filetype in dirent */
+ 
+ struct grub_xfs_sblock
+ {
+@@ -45,7 +54,9 @@ struct grub_xfs_sblock
+   grub_uint64_t rootino;
+   grub_uint8_t unused3[20];
+   grub_uint32_t agsize;
+-  grub_uint8_t unused4[20];
++  grub_uint8_t unused4[12];
++  grub_uint16_t version;
++  grub_uint8_t unused5[6];
+   grub_uint8_t label[12];
+   grub_uint8_t log2_bsize;
+   grub_uint8_t log2_sect;
+@@ -54,12 +65,19 @@ struct grub_xfs_sblock
+   grub_uint8_t log2_agblk;
+   grub_uint8_t unused6[67];
+   grub_uint8_t log2_dirblk;
++  grub_uint8_t unused7[7];
++  grub_uint32_t features2;
++  grub_uint8_t unused8[4];
++  grub_uint32_t sb_features_compat;
++  grub_uint32_t sb_features_ro_compat;
++  grub_uint32_t sb_features_incompat;
++  grub_uint32_t sb_features_log_incompat;
+ } GRUB_PACKED;
+ 
+ struct grub_xfs_dir_header
+ {
+   grub_uint8_t count;
+-  grub_uint8_t smallino;
++  grub_uint8_t largeino;
+   union
+   {
+     grub_uint32_t i4;
+@@ -67,14 +85,16 @@ struct grub_xfs_dir_header
+   } GRUB_PACKED parent;
+ } GRUB_PACKED;
+ 
++/* Structure for directory entry inlined in the inode */
+ struct grub_xfs_dir_entry
+ {
+   grub_uint8_t len;
+   grub_uint16_t offset;
+   char name[1];
+-  /* Inode number follows, 32 bits.  */
++  /* Inode number follows, 32 / 64 bits.  */
+ } GRUB_PACKED;
+ 
++/* Structure for directory entry in a block */
+ struct grub_xfs_dir2_entry
+ {
+   grub_uint64_t inode;
+@@ -90,7 +110,8 @@ struct grub_xfs_btree_node
+   grub_uint16_t numrecs;
+   grub_uint64_t left;
+   grub_uint64_t right;
+-  grub_uint64_t keys[1];
++  /* In V5 here follow crc, uuid, etc. */
++  /* Then follow keys and block pointers */
+ }  GRUB_PACKED;
+ 
+ struct grub_xfs_btree_root
+@@ -123,17 +144,6 @@ struct grub_xfs_inode
+   grub_uint16_t unused3;
+   grub_uint8_t fork_offset;
+   grub_uint8_t unused4[17];
+-  union
+-  {
+-    char raw[156];
+-    struct dir
+-    {
+-      struct grub_xfs_dir_header dirhead;
+-      struct grub_xfs_dir_entry direntry[1];
+-    } dir;
+-    grub_xfs_extent extents[XFS_INODE_EXTENTS];
+-    struct grub_xfs_btree_root btree;
+-  } GRUB_PACKED data;
+ } GRUB_PACKED;
+ 
+ struct grub_xfs_dirblock_tail
+@@ -157,6 +167,8 @@ struct grub_xfs_data
+   int pos;
+   int bsize;
+   grub_uint32_t agsize;
++  unsigned int hasftype:1;
++  unsigned int hascrc:1;
+   struct grub_fshelp_node diropen;
+ };
+ 
+@@ -164,6 +176,24 @@ static grub_dl_t my_mod;
+ 
+ 

+ 
++static int grub_xfs_sb_hascrc(struct grub_xfs_data *data)
++{
++  return (grub_be_to_cpu16(data->sblock.version) & XFS_SB_VERSION_NUMBITS) == 5;
++}
++
++static int grub_xfs_sb_hasftype(struct grub_xfs_data *data)
++{
++  grub_uint32_t version = grub_be_to_cpu16(data->sblock.version);
++
++  if ((version & XFS_SB_VERSION_NUMBITS) == 5 &&
++      grub_be_to_cpu32(data->sblock.sb_features_incompat) & XFS_SB_FEAT_INCOMPAT_FTYPE)
++    return 1;
++  if (version & XFS_SB_VERSION_MOREBITSBIT &&
++      grub_be_to_cpu32(data->sblock.features2) & XFS_SB_VERSION2_FTYPE)
++    return 1;
++  return 0;
++}
++
+ /* Filetype information as used in inodes.  */
+ #define FILETYPE_INO_MASK	0170000
+ #define FILETYPE_INO_REG	0100000
+@@ -219,18 +249,6 @@ GRUB_XFS_EXTENT_SIZE (grub_xfs_extent *e
+   return (grub_be_to_cpu32 (exts[ex][3]) & ((1 << 21) - 1));
+ }
+ 
+-static inline int
+-GRUB_XFS_ROUND_TO_DIRENT (int pos)
+-{
+-  return ((((pos) + 8 - 1) / 8) * 8);
+-}
+-
+-static inline int
+-GRUB_XFS_NEXT_DIRENT (int pos, int len)
+-{
+-  return (pos) + GRUB_XFS_ROUND_TO_DIRENT (8 + 1 + len + 2);
+-}
+-
+ 

+ static inline grub_uint64_t
+ grub_xfs_inode_block (struct grub_xfs_data *data,
+@@ -261,6 +279,92 @@ grub_xfs_inode_size(struct grub_xfs_data
+ 	return 1 << data->sblock.log2_inode;
+ }
+ 
++static void *
++grub_xfs_inode_data(struct grub_xfs_inode *inode)
++{
++	if (inode->version <= 2)
++		return ((char *)inode) + 100;
++	return ((char *)inode) + 176;
++}
++
++static struct grub_xfs_dir_entry *
++grub_xfs_inline_de(struct grub_xfs_dir_header *head)
++{
++	/*
++	 * With small inode numbers the header is 4 bytes smaller because of
++	 * smaller parent pointer
++	 */
++	return (void *)(((char *)head) + sizeof(struct grub_xfs_dir_header) -
++		(head->largeino ? 0 : sizeof(grub_uint32_t)));
++}
++
++static grub_uint8_t *
++grub_xfs_inline_de_inopos(struct grub_xfs_data *data,
++			  struct grub_xfs_dir_entry *de)
++{
++	return ((grub_uint8_t *)(de + 1)) + de->len - 1 +
++		 (data->hasftype ? 1 : 0);
++}
++
++static struct grub_xfs_dir_entry *
++grub_xfs_inline_next_de(struct grub_xfs_data *data,
++			struct grub_xfs_dir_header *head,
++			struct grub_xfs_dir_entry *de)
++{
++  char *p = (char *)de + sizeof(struct grub_xfs_dir_entry) - 1 + de->len;
++
++  p += head->largeino ? sizeof(grub_uint64_t) : sizeof(grub_uint32_t);
++  if (data->hasftype)
++    p++;
++
++  return (struct grub_xfs_dir_entry *)p;
++}
++
++static struct grub_xfs_dirblock_tail *
++grub_xfs_dir_tail(struct grub_xfs_data *data, void *dirblock)
++{
++  int dirblksize = 1 << (data->sblock.log2_bsize + data->sblock.log2_dirblk);
++
++  return (struct grub_xfs_dirblock_tail *)
++    ((char *)dirblock + dirblksize - sizeof (struct grub_xfs_dirblock_tail));
++}
++
++static struct grub_xfs_dir2_entry *
++grub_xfs_first_de(struct grub_xfs_data *data, void *dirblock)
++{
++  if (data->hascrc)
++    return (struct grub_xfs_dir2_entry *)((char *)dirblock + 64);
++  return (struct grub_xfs_dir2_entry *)((char *)dirblock + 16);
++}
++
++static inline int
++grub_xfs_round_dirent_size (int len)
++{
++  return (len + 7) & ~7;
++}
++
++static struct grub_xfs_dir2_entry *
++grub_xfs_next_de(struct grub_xfs_data *data, struct grub_xfs_dir2_entry *de)
++{
++  int size = sizeof (struct grub_xfs_dir2_entry) + de->len + 2 /* Tag */;
++
++  if (data->hasftype)
++    size++;		/* File type */
++  return (struct grub_xfs_dir2_entry *)
++			(((char *)de) + grub_xfs_round_dirent_size (size));
++}
++
++static grub_uint64_t *
++grub_xfs_btree_keys(struct grub_xfs_data *data,
++		    struct grub_xfs_btree_node *leaf)
++{
++  char *p = (char *)(leaf + 1);
++
++  if (data->hascrc)
++    p += 48;	/* crc, uuid, ... */
++  return (grub_uint64_t *)(void*)p;
++}
++
+ static grub_err_t
+ grub_xfs_read_inode (struct grub_xfs_data *data, grub_uint64_t ino,
+ 		     struct grub_xfs_inode *inode)
+@@ -268,6 +372,9 @@ grub_xfs_read_inode (struct grub_xfs_dat
+   grub_uint64_t block = grub_xfs_inode_block (data, ino);
+   int offset = grub_xfs_inode_offset (data, ino);
+ 
++  grub_dprintf("xfs", "Reading inode (%llu) - %llu, %d\n",
++	       (unsigned long long) ino,
++	       (unsigned long long) block, offset);
+   /* Read the inode.  */
+   if (grub_disk_read (data->disk, block, offset, grub_xfs_inode_size(data),
+ 		      inode))
+@@ -290,6 +397,7 @@ grub_xfs_read_block (grub_fshelp_node_t
+ 
+   if (node->inode.format == XFS_INODE_FORMAT_BTREE)
+     {
++      struct grub_xfs_btree_root *root;
+       const grub_uint64_t *keys;
+       int recoffset;
+ 
+@@ -297,15 +405,15 @@ grub_xfs_read_block (grub_fshelp_node_t
+       if (leaf == 0)
+         return 0;
+ 
+-      nrec = grub_be_to_cpu16 (node->inode.data.btree.numrecs);
+-      keys = &node->inode.data.btree.keys[0];
++      root = grub_xfs_inode_data(&node->inode);
++      nrec = grub_be_to_cpu16 (root->numrecs);
++      keys = &root->keys[0];
+       if (node->inode.fork_offset)
+ 	recoffset = (node->inode.fork_offset - 1) / 2;
+       else
+ 	recoffset = (grub_xfs_inode_size(node->data)
+-		     - ((char *) &node->inode.data.btree.keys
+-			- (char *) &node->inode))
+-	  / (2 * sizeof (grub_uint64_t));
++		     - ((char *) keys - (char *) &node->inode))
++				/ (2 * sizeof (grub_uint64_t));
+       do
+         {
+           int i;
+@@ -327,7 +435,10 @@ grub_xfs_read_block (grub_fshelp_node_t
+                               0, node->data->bsize, leaf))
+             return 0;
+ 
+-          if (grub_strncmp ((char *) leaf->magic, "BMAP", 4))
++	  if ((!node->data->hascrc &&
++	       grub_strncmp ((char *) leaf->magic, "BMAP", 4)) ||
++	      (node->data->hascrc &&
++	       grub_strncmp ((char *) leaf->magic, "BMA3", 4)))
+             {
+               grub_free (leaf);
+               grub_error (GRUB_ERR_BAD_FS, "not a correct XFS BMAP node");
+@@ -335,8 +446,8 @@ grub_xfs_read_block (grub_fshelp_node_t
+             }
+ 
+           nrec = grub_be_to_cpu16 (leaf->numrecs);
+-          keys = &leaf->keys[0];
+-	  recoffset = ((node->data->bsize - ((char *) &leaf->keys
++          keys = grub_xfs_btree_keys(node->data, leaf);
++	  recoffset = ((node->data->bsize - ((char *) keys
+ 					     - (char *) leaf))
+ 		       / (2 * sizeof (grub_uint64_t)));
+ 	}
+@@ -346,7 +457,7 @@ grub_xfs_read_block (grub_fshelp_node_t
+   else if (node->inode.format == XFS_INODE_FORMAT_EXT)
+     {
+       nrec = grub_be_to_cpu32 (node->inode.nextents);
+-      exts = &node->inode.data.extents[0];
++      exts = grub_xfs_inode_data(&node->inode);
+     }
+   else
+     {
+@@ -404,7 +515,7 @@ grub_xfs_read_symlink (grub_fshelp_node_
+   switch (node->inode.format)
+     {
+     case XFS_INODE_FORMAT_INO:
+-      return grub_strndup (node->inode.data.raw, size);
++      return grub_strndup (grub_xfs_inode_data(&node->inode), size);
+ 
+     case XFS_INODE_FORMAT_EXT:
+       {
+@@ -501,23 +612,18 @@ grub_xfs_iterate_dir (grub_fshelp_node_t
+     {
+     case XFS_INODE_FORMAT_INO:
+       {
+-	struct grub_xfs_dir_entry *de = &diro->inode.data.dir.direntry[0];
+-	int smallino = !diro->inode.data.dir.dirhead.smallino;
++	struct grub_xfs_dir_header *head = grub_xfs_inode_data(&diro->inode);
++	struct grub_xfs_dir_entry *de = grub_xfs_inline_de(head);
++	int smallino = !head->largeino;
+ 	int i;
+ 	grub_uint64_t parent;
+ 
+ 	/* If small inode numbers are used to pack the direntry, the
+ 	   parent inode number is small too.  */
+ 	if (smallino)
+-	  {
+-	    parent = grub_be_to_cpu32 (diro->inode.data.dir.dirhead.parent.i4);
+-	    /* The header is a bit smaller than usual.  */
+-	    de = (struct grub_xfs_dir_entry *) ((char *) de - 4);
+-	  }
++	  parent = grub_be_to_cpu32 (head->parent.i4);
+ 	else
+-	  {
+-	    parent = grub_be_to_cpu64(diro->inode.data.dir.dirhead.parent.i8);
+-	  }
++	  parent = grub_be_to_cpu64 (head->parent.i8);
+ 
+ 	/* Synthesize the direntries for `.' and `..'.  */
+ 	if (iterate_dir_call_hook (diro->ino, ".", &ctx))
+@@ -526,12 +632,10 @@ grub_xfs_iterate_dir (grub_fshelp_node_t
+ 	if (iterate_dir_call_hook (parent, "..", &ctx))
+ 	  return 1;
+ 
+-	for (i = 0; i < diro->inode.data.dir.dirhead.count; i++)
++	for (i = 0; i < head->count; i++)
+ 	  {
+ 	    grub_uint64_t ino;
+-	    grub_uint8_t *inopos = (((grub_uint8_t *) de)
+-			    + sizeof (struct grub_xfs_dir_entry)
+-			    + de->len - 1);
++	    grub_uint8_t *inopos = grub_xfs_inline_de_inopos(dir->data, de);
+ 	    grub_uint8_t c;
+ 
+ 	    /* inopos might be unaligned.  */
+@@ -556,10 +660,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t
+ 	      return 1;
+ 	    de->name[de->len] = c;
+ 
+-	    de = ((struct grub_xfs_dir_entry *)
+-		  (((char *) de)+ sizeof (struct grub_xfs_dir_entry) + de->len
+-		   + ((smallino ? sizeof (grub_uint32_t)
+-		       : sizeof (grub_uint64_t))) - 1));
++	    de = grub_xfs_inline_next_de(dir->data, head, de);
+ 	  }
+ 	break;
+       }
+@@ -586,15 +687,11 @@ grub_xfs_iterate_dir (grub_fshelp_node_t
+ 		    >> dirblk_log2);
+ 	     blk++)
+ 	  {
+-	    /* The header is skipped, the first direntry is stored
+-	       from byte 16.  */
+-	    int pos = 16;
++	    struct grub_xfs_dir2_entry *direntry =
++					grub_xfs_first_de(dir->data, dirblock);
+ 	    int entries;
+-	    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];
++	    struct grub_xfs_dirblock_tail *tail =
++					grub_xfs_dir_tail(dir->data, dirblock);
+ 
+ 	    numread = grub_xfs_read_file (dir, 0, 0,
+ 					  blk << dirblk_log2,
+@@ -606,13 +703,11 @@ grub_xfs_iterate_dir (grub_fshelp_node_t
+ 		       - grub_be_to_cpu32 (tail->leaf_stale));
+ 
+ 	    /* Iterate over all entries within this block.  */
+-	    while (pos < tail_start)
++	    while ((char *)direntry < (char *)tail)
+ 	      {
+-		struct grub_xfs_dir2_entry *direntry;
+ 		grub_uint8_t *freetag;
+ 		char *filename;
+ 
+-		direntry = (struct grub_xfs_dir2_entry *) &dirblock[pos];
+ 		freetag = (grub_uint8_t *) direntry;
+ 
+ 		if (grub_get_unaligned16 (freetag) == 0XFFFF)
+@@ -620,14 +715,16 @@ grub_xfs_iterate_dir (grub_fshelp_node_t
+ 		    grub_uint8_t *skip = (freetag + sizeof (grub_uint16_t));
+ 
+ 		    /* This entry is not used, go to the next one.  */
+-		    pos += grub_be_to_cpu16 (grub_get_unaligned16 (skip));
++		    direntry = (struct grub_xfs_dir2_entry *)
++				(((char *)direntry) +
++				grub_be_to_cpu16 (grub_get_unaligned16 (skip)));
+ 
+ 		    continue;
+ 		  }
+ 
+-		filename = &dirblock[pos + sizeof (*direntry)];
+-		/* The byte after the filename is for the tag, which
+-		   is not used by GRUB.  So it can be overwritten.  */
++		filename = (char *)(direntry + 1);
++		/* The byte after the filename is for the filetype, padding, or
++		   tag, which is not used by GRUB.  So it can be overwritten. */
+ 		filename[direntry->len] = '\0';
+ 
+ 		if (iterate_dir_call_hook (grub_be_to_cpu64(direntry->inode), 
+@@ -644,8 +741,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t
+ 		  break;
+ 
+ 		/* Select the next directory entry.  */
+-		pos = GRUB_XFS_NEXT_DIRENT (pos, direntry->len);
+-		pos = GRUB_XFS_ROUND_TO_DIRENT (pos);
++		direntry = grub_xfs_next_de(dir->data, direntry);
+ 	      }
+ 	  }
+ 	grub_free (dirblock);
+@@ -670,6 +766,7 @@ grub_xfs_mount (grub_disk_t disk)
+   if (!data)
+     return 0;
+ 
++  grub_dprintf("xfs", "Reading sb\n");
+   /* Read the superblock.  */
+   if (grub_disk_read (disk, 0, 0,
+ 		      sizeof (struct grub_xfs_sblock), &data->sblock))
+@@ -697,9 +794,13 @@ grub_xfs_mount (grub_disk_t disk)
+   data->diropen.inode_read = 1;
+   data->bsize = grub_be_to_cpu32 (data->sblock.bsize);
+   data->agsize = grub_be_to_cpu32 (data->sblock.agsize);
++  data->hasftype = grub_xfs_sb_hasftype(data);
++  data->hascrc = grub_xfs_sb_hascrc(data);
+ 
+   data->disk = disk;
+   data->pos = 0;
++  grub_dprintf("xfs", "Reading root ino %llu\n",
++	       (unsigned long long) grub_cpu_to_be64(data->sblock.rootino));
+ 
+   grub_xfs_read_inode (data, data->diropen.ino, &data->diropen.inode);
+ 
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/grub2.git/commitdiff/2c79d729d4cbf15ad7e20542b6e5a62184613fa2



More information about the pld-cvs-commit mailing list