avatar
signer has added 81d83e9c23
Merge pull request #1 from abondrov/grub2:rosa2014.1 Backport some p...

...atches from upstream for XFS V5 filesystem format support

view file @ 81d83e9c23
1
--- a/grub-core/fs/xfs.c
2
+++ b/grub-core/fs/xfs.c
3
@@ -603,8 +603,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
4
 		       - grub_be_to_cpu32 (tail->leaf_stale));
5
 
6
 	    /* Iterate over all entries within this block.  */
7
-	    while (pos < (dirblk_size
8
-			  - (int) sizeof (struct grub_xfs_dir2_entry)))
9
+	    while (pos < tail_start)
10
 	      {
11
 		struct grub_xfs_dir2_entry *direntry;
12
 		grub_uint8_t *freetag;
13
-- 
14
2.4.3
15
view file @ 81d83e9c23
... ... --- /dev/null
... ... +++ b/0002-xfs-Convert-inode-numbers-to-cpu-endianity-immediate.patch
... ... @@ -0,0 +1,77 @@
1
From 54a4f53f9ecae2378195e4e66a8410d3862a0be2 Mon Sep 17 00:00:00 2001
2
From: Jan Kara <jack@suse.cz>
3
Date: Mon, 14 Jul 2014 17:21:30 +0200
4
Subject: [PATCH 11/23] xfs: Convert inode numbers to cpu endianity immediately
5
 after reading
6
7
Currently XFS driver converted inode numbers to native endianity only
8
when using them to compute inode position. Although this works, it is
9
somewhat confusing. So convert inode numbers when reading them from disk
10
structures as every other field.
11
12
Signed-off-by: Jan Kara <jack@suse.cz>
13
---
14
 grub-core/fs/xfs.c | 13 ++++++-------
15
 1 file changed, 6 insertions(+), 7 deletions(-)
16
17
diff -urN grub-2.00/grub-core/fs/xfs.c grub-2.00-patched/grub-core/fs/xfs.c
18
--- grub-2.00/grub-core/fs/xfs.c	2016-07-08 13:26:00.240923100 +1000
19
+++ grub-2.00-patched/grub-core/fs/xfs.c	2016-07-08 13:24:54.758924819 +1000
20
@@ -180,14 +180,14 @@
21
 GRUB_XFS_INO_INOINAG (struct grub_xfs_data *data,
22
 		      grub_uint64_t ino)
23
 {
24
-  return (grub_be_to_cpu64 (ino) & ((1LL << GRUB_XFS_INO_AGBITS (data)) - 1));
25
+  return (ino & ((1LL << GRUB_XFS_INO_AGBITS (data)) - 1));
26
 }
27
 
28
 static inline grub_uint64_t
29
 GRUB_XFS_INO_AG (struct grub_xfs_data *data,
30
 		 grub_uint64_t ino)
31
 {
32
-  return (grub_be_to_cpu64 (ino) >> GRUB_XFS_INO_AGBITS (data));
33
+  return (ino >> GRUB_XFS_INO_AGBITS (data));
34
 }
35
 
36
 static inline grub_disk_addr_t
37
@@ -498,13 +498,12 @@
38
 	if (smallino)
39
 	  {
40
 	    parent = grub_be_to_cpu32 (diro->inode.data.dir.dirhead.parent.i4);
41
-	    parent = grub_cpu_to_be64 (parent);
42
 	    /* The header is a bit smaller than usual.  */
43
 	    de = (struct grub_xfs_dir_entry *) ((char *) de - 4);
44
 	  }
45
 	else
46
 	  {
47
-	    parent = diro->inode.data.dir.dirhead.parent.i8;
48
+	    parent = grub_be_to_cpu64(diro->inode.data.dir.dirhead.parent.i8);
49
 	  }
50
 
51
 	/* Synthesize the direntries for `.' and `..'.  */
52
@@ -537,7 +536,6 @@
53
 		| (((grub_uint64_t) inopos[5]) << 16)
54
 		| (((grub_uint64_t) inopos[6]) << 8)
55
 		| (((grub_uint64_t) inopos[7]) << 0);
56
-	    ino = grub_cpu_to_be64 (ino);
57
 
58
 	    grub_memcpy (name, de->name, de->len);
59
 	    name[de->len] = '\0';
60
@@ -618,7 +616,7 @@
61
 		   is not used by GRUB.  So it can be overwritten.  */
62
 		filename[direntry->len] = '\0';
63
 
64
-		if (call_hook (direntry->inode, filename))
65
+		if (call_hook (grub_be_to_cpu64(direntry->inode), filename))
66
 		  {
67
 		    grub_free (dirblock);
68
 		    return 1;
69
@@ -680,7 +678,7 @@
70
     goto fail;
71
 
72
   data->diropen.data = data;
73
-  data->diropen.ino = data->sblock.rootino;
74
+  data->diropen.ino = grub_be_to_cpu64(data->sblock.rootino);
75
   data->diropen.inode_read = 1;
76
   data->bsize = grub_be_to_cpu32 (data->sblock.bsize);
77
   data->agsize = grub_be_to_cpu32 (data->sblock.agsize);
view file @ 81d83e9c23
... ... --- /dev/null
... ... +++ b/0003-xfs-Add-helpers-for-inode-size.patch
... ... @@ -0,0 +1,93 @@
1
From bc7e3f1e508c91b9ad7d3459998c5cd31d1caca0 Mon Sep 17 00:00:00 2001
2
From: Jan Kara <jack@suse.cz>
3
Date: Mon, 1 Jun 2015 14:28:45 +0200
4
Subject: [PATCH 12/23] xfs: Add helpers for inode size
5
6
Add helpers to return size of XFS inode on disk and when loaded in
7
memory.
8
9
Signed-off-by: Jan Kara <jack@suse.cz>
10
---
11
 grub-core/fs/xfs.c | 35 ++++++++++++++++++++++++-----------
12
 1 file changed, 24 insertions(+), 11 deletions(-)
13
14
diff -urN grub-2.00/grub-core/fs/xfs.c grub-2.00-patched/grub-core/fs/xfs.c
15
--- grub-2.00/grub-core/fs/xfs.c	2016-07-08 21:48:15.419174902 +1000
16
+++ grub-2.00-patched/grub-core/fs/xfs.c	2016-07-08 21:53:35.185180891 +1000
17
@@ -255,6 +255,24 @@
18
 	  data->sblock.log2_inode);
19
 }
20
 
21
+static inline grub_size_t
22
+grub_xfs_inode_size(struct grub_xfs_data *data)
23
+{
24
+  return 1 << data->sblock.log2_inode;
25
+}
26
+
27
+/*
28
+ * Returns size occupied by XFS inode stored in memory - we store struct
29
+ * grub_fshelp_node there but on disk inode size may be actually larger than
30
+ * struct grub_xfs_inode so we need to account for that so that we can read
31
+ * from disk directly into in-memory structure.
32
+ */
33
+static inline grub_size_t
34
+grub_xfs_fshelp_size(struct grub_xfs_data *data)
35
+{
36
+  return sizeof (struct grub_fshelp_node) - sizeof (struct grub_xfs_inode)
37
+	       + grub_xfs_inode_size(data);
38
+}
39
 
40
 static grub_err_t
41
 grub_xfs_read_inode (struct grub_xfs_data *data, grub_uint64_t ino,
42
@@ -264,8 +282,8 @@
43
   int offset = grub_xfs_inode_offset (data, ino);
44
 
45
   /* Read the inode.  */
46
-  if (grub_disk_read (data->disk, block, offset,
47
-		      1 << data->sblock.log2_inode, inode))
48
+  if (grub_disk_read (data->disk, block, offset, grub_xfs_inode_size(data),
49
+		      inode))
50
     return grub_errno;
51
 
52
   if (grub_strncmp ((char *) inode->magic, "IN", 2))
53
@@ -299,7 +317,7 @@
54
 		     - ((char *) &node->inode.data.btree.keys - (char *) &node->inode))
55
 	  / (2 * sizeof (grub_uint64_t));
56
       else
57
-	recoffset = ((1 << node->data->sblock.log2_inode)
58
+	recoffset = (grub_xfs_inode_size(node->data)
59
 		     - ((char *) &node->inode.data.btree.keys
60
 			- (char *) &node->inode))
61
 	  / (2 * sizeof (grub_uint64_t));
62
@@ -458,9 +476,7 @@
63
       struct grub_fshelp_node *fdiro;
64
       grub_err_t err;
65
 
66
-      fdiro = grub_malloc (sizeof (struct grub_fshelp_node)
67
-			   - sizeof (struct grub_xfs_inode)
68
-			   + (1 << diro->data->sblock.log2_inode));
69
+      fdiro = grub_malloc (grub_xfs_fshelp_size(diro->data));
70
       if (!fdiro)
71
 	{
72
 	  grub_print_error ();
73
@@ -672,7 +688,7 @@
74
   data = grub_realloc (data,
75
 		       sizeof (struct grub_xfs_data)
76
 		       - sizeof (struct grub_xfs_inode)
77
-		       + (1 << data->sblock.log2_inode));
78
+                       + grub_xfs_inode_size(data));
79
 
80
   if (! data)
81
     goto fail;
82
@@ -781,10 +797,7 @@
83
 
84
   if (fdiro != &data->diropen)
85
     {
86
-      grub_memcpy (&data->diropen, fdiro,
87
-		   sizeof (struct grub_fshelp_node)
88
-		   - sizeof (struct grub_xfs_inode)
89
-		   + (1 << data->sblock.log2_inode));
90
+      grub_memcpy (&data->diropen, fdiro, grub_xfs_fshelp_size(data));
91
       grub_free (fdiro);
92
     }
93
 
view file @ 81d83e9c23
... ... --- /dev/null
... ... +++ b/0004-xfs-V5-filesystem-format-support.patch
... ... @@ -0,0 +1,580 @@
1
From f9187f5eef9776ba51dca88e347bfd6675787cb6 Mon Sep 17 00:00:00 2001
2
From: Jan Kara <jack@suse.cz>
3
Date: Mon, 1 Jun 2015 14:28:46 +0200
4
Subject: [PATCH 13/23] xfs: V5 filesystem format support
5
6
Add support for new XFS on disk format. We have to handle optional
7
filetype fields in directory entries, additional CRC, LSN, UUID entries
8
in some structures, etc.
9
10
Signed-off-by: Jan Kara <jack@suse.cz>
11
---
12
 grub-core/fs/xfs.c | 332 ++++++++++++++++++++++++++++++++++++++++-------------
13
 1 file changed, 252 insertions(+), 80 deletions(-)
14
15
diff -urN grub-2.00/grub-core/fs/xfs.c grub-2.00-patched/grub-core/fs/xfs.c
16
--- grub-2.00/grub-core/fs/xfs.c	2016-07-08 22:53:17.630247984 +1000
17
+++ grub-2.00-patched/grub-core/fs/xfs.c	2016-07-08 22:59:48.969255313 +1000
18
@@ -34,6 +34,50 @@
19
 #define XFS_INODE_FORMAT_EXT	2
20
 #define XFS_INODE_FORMAT_BTREE	3
21
 
22
+/* Superblock version field flags */
23
+#define XFS_SB_VERSION_NUMBITS		0x000f
24
+#define	XFS_SB_VERSION_ATTRBIT		0x0010
25
+#define	XFS_SB_VERSION_NLINKBIT		0x0020
26
+#define	XFS_SB_VERSION_QUOTABIT		0x0040
27
+#define	XFS_SB_VERSION_ALIGNBIT		0x0080
28
+#define	XFS_SB_VERSION_DALIGNBIT	0x0100
29
+#define	XFS_SB_VERSION_LOGV2BIT		0x0400
30
+#define	XFS_SB_VERSION_SECTORBIT	0x0800
31
+#define	XFS_SB_VERSION_EXTFLGBIT	0x1000
32
+#define	XFS_SB_VERSION_DIRV2BIT		0x2000
33
+#define XFS_SB_VERSION_MOREBITSBIT	0x8000
34
+#define XFS_SB_VERSION_BITS_SUPPORTED \
35
+	(XFS_SB_VERSION_NUMBITS | \
36
+	 XFS_SB_VERSION_ATTRBIT | \
37
+	 XFS_SB_VERSION_NLINKBIT | \
38
+	 XFS_SB_VERSION_QUOTABIT | \
39
+	 XFS_SB_VERSION_ALIGNBIT | \
40
+	 XFS_SB_VERSION_DALIGNBIT | \
41
+	 XFS_SB_VERSION_LOGV2BIT | \
42
+	 XFS_SB_VERSION_SECTORBIT | \
43
+	 XFS_SB_VERSION_EXTFLGBIT | \
44
+	 XFS_SB_VERSION_DIRV2BIT | \
45
+	 XFS_SB_VERSION_MOREBITSBIT)
46
+
47
+/* Recognized xfs format versions */
48
+#define XFS_SB_VERSION_4		4	/* Good old XFS filesystem */
49
+#define XFS_SB_VERSION_5		5	/* CRC enabled filesystem */
50
+
51
+/* features2 field flags */
52
+#define XFS_SB_VERSION2_LAZYSBCOUNTBIT	0x00000002	/* Superblk counters */
53
+#define XFS_SB_VERSION2_ATTR2BIT	0x00000008	/* Inline attr rework */
54
+#define XFS_SB_VERSION2_PROJID32BIT	0x00000080	/* 32-bit project ids */
55
+#define XFS_SB_VERSION2_FTYPE		0x00000200	/* inode type in dir */
56
+#define XFS_SB_VERSION2_BITS_SUPPORTED \
57
+	(XFS_SB_VERSION2_LAZYSBCOUNTBIT | \
58
+	 XFS_SB_VERSION2_ATTR2BIT | \
59
+	 XFS_SB_VERSION2_PROJID32BIT | \
60
+	 XFS_SB_VERSION2_FTYPE)
61
+
62
+/* incompat feature flags */
63
+#define XFS_SB_FEAT_INCOMPAT_FTYPE      (1 << 0)        /* filetype in dirent */
64
+#define XFS_SB_FEAT_INCOMPAT_SUPPORTED \
65
+	(XFS_SB_FEAT_INCOMPAT_FTYPE)
66
 
67
 struct grub_xfs_sblock
68
 {
69
@@ -45,7 +89,9 @@
70
   grub_uint64_t rootino;
71
   grub_uint8_t unused3[20];
72
   grub_uint32_t agsize;
73
-  grub_uint8_t unused4[20];
74
+  grub_uint8_t unused4[12];
75
+  grub_uint16_t version;
76
+  grub_uint8_t unused5[6];
77
   grub_uint8_t label[12];
78
   grub_uint8_t log2_bsize;
79
   grub_uint8_t log2_sect;
80
@@ -54,12 +100,19 @@
81
   grub_uint8_t log2_agblk;
82
   grub_uint8_t unused6[67];
83
   grub_uint8_t log2_dirblk;
84
+  grub_uint8_t unused7[7];
85
+  grub_uint32_t features2;
86
+  grub_uint8_t unused8[4];
87
+  grub_uint32_t sb_features_compat;
88
+  grub_uint32_t sb_features_ro_compat;
89
+  grub_uint32_t sb_features_incompat;
90
+  grub_uint32_t sb_features_log_incompat;
91
 } __attribute__ ((packed));
92
 
93
 struct grub_xfs_dir_header
94
 {
95
   grub_uint8_t count;
96
-  grub_uint8_t smallino;
97
+  grub_uint8_t largeino;
98
   union
99
   {
100
     grub_uint32_t i4;
101
@@ -67,14 +120,16 @@
102
   } parent __attribute__ ((packed));
103
 } __attribute__ ((packed));
104
 
105
+/* Structure for directory entry inlined in the inode */
106
 struct grub_xfs_dir_entry
107
 {
108
   grub_uint8_t len;
109
   grub_uint16_t offset;
110
   char name[1];
111
-  /* Inode number follows, 32 bits.  */
112
+  /* Inode number follows, 32 / 64 bits.  */
113
 } __attribute__ ((packed));
114
 
115
+/* Structure for directory entry in a block */
116
 struct grub_xfs_dir2_entry
117
 {
118
   grub_uint64_t inode;
119
@@ -90,7 +145,8 @@
120
   grub_uint16_t numrecs;
121
   grub_uint64_t left;
122
   grub_uint64_t right;
123
-  grub_uint64_t keys[1];
124
+  /* In V5 here follow crc, uuid, etc. */
125
+  /* Then follow keys and block pointers */
126
 }  __attribute__ ((packed));
127
 
128
 struct grub_xfs_btree_root
129
@@ -123,19 +179,11 @@
130
   grub_uint16_t unused3;
131
   grub_uint8_t fork_offset;
132
   grub_uint8_t unused4[17];
133
-  union
134
-  {
135
-    char raw[156];
136
-    struct dir
137
-    {
138
-      struct grub_xfs_dir_header dirhead;
139
-      struct grub_xfs_dir_entry direntry[1];
140
-    } dir;
141
-    grub_xfs_extent extents[XFS_INODE_EXTENTS];
142
-    struct grub_xfs_btree_root btree;
143
-  } data __attribute__ ((packed));
144
 } __attribute__ ((packed));
145
 
146
+#define XFS_V2_INODE_SIZE sizeof(struct grub_xfs_inode)
147
+#define XFS_V3_INODE_SIZE (XFS_V2_INODE_SIZE + 76)
148
+
149
 struct grub_xfs_dirblock_tail
150
 {
151
   grub_uint32_t leaf_count;
152
@@ -157,6 +205,8 @@
153
   int pos;
154
   int bsize;
155
   grub_uint32_t agsize;
156
+  unsigned int hasftype:1;
157
+  unsigned int hascrc:1;
158
   struct grub_fshelp_node diropen;
159
 };
160
 
161
@@ -164,6 +214,71 @@
162
 
163
 
164
 
165
+static int grub_xfs_sb_hascrc(struct grub_xfs_data *data)
166
+{
167
+  return (data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_NUMBITS)) ==
168
+	  grub_cpu_to_be16_compile_time(XFS_SB_VERSION_5);
169
+}
170
+
171
+static int grub_xfs_sb_hasftype(struct grub_xfs_data *data)
172
+{
173
+  if ((data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_NUMBITS)) ==
174
+	grub_cpu_to_be16_compile_time(XFS_SB_VERSION_5) &&
175
+      data->sblock.sb_features_incompat & grub_cpu_to_be32_compile_time(XFS_SB_FEAT_INCOMPAT_FTYPE))
176
+    return 1;
177
+  if (data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_MOREBITSBIT) &&
178
+      data->sblock.features2 & grub_cpu_to_be32_compile_time(XFS_SB_VERSION2_FTYPE))
179
+    return 1;
180
+  return 0;
181
+}
182
+
183
+static int grub_xfs_sb_valid(struct grub_xfs_data *data)
184
+{
185
+  grub_dprintf("xfs", "Validating superblock\n");
186
+  if (grub_strncmp ((char *) (data->sblock.magic), "XFSB", 4)
187
+      || data->sblock.log2_bsize < GRUB_DISK_SECTOR_BITS
188
+      || ((int) data->sblock.log2_bsize
189
+	  + (int) data->sblock.log2_dirblk) >= 27)
190
+    {
191
+      grub_error (GRUB_ERR_BAD_FS, "not a XFS filesystem");
192
+      return 0;
193
+    }
194
+  if ((data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_NUMBITS)) ==
195
+       grub_cpu_to_be16_compile_time(XFS_SB_VERSION_5))
196
+    {
197
+      grub_dprintf("xfs", "XFS v5 superblock detected\n");
198
+      if (data->sblock.sb_features_incompat &
199
+          grub_cpu_to_be32_compile_time(~XFS_SB_FEAT_INCOMPAT_SUPPORTED))
200
+        {
201
+	  grub_error (GRUB_ERR_BAD_FS, "XFS filesystem has unsupported "
202
+		      "incompatible features");
203
+	  return 0;
204
+        }
205
+      return 1;
206
+    }
207
+  else if ((data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_NUMBITS)) ==
208
+	   grub_cpu_to_be16_compile_time(XFS_SB_VERSION_4))
209
+    {
210
+      grub_dprintf("xfs", "XFS v4 superblock detected\n");
211
+      if (!(data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_DIRV2BIT)))
212
+	{
213
+	  grub_error (GRUB_ERR_BAD_FS, "XFS filesystem without V2 directories "
214
+		      "is unsupported");
215
+	  return 0;
216
+	}
217
+      if (data->sblock.version & grub_cpu_to_be16_compile_time(~XFS_SB_VERSION_BITS_SUPPORTED) ||
218
+	  (data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_MOREBITSBIT) &&
219
+	   data->sblock.features2 & grub_cpu_to_be16_compile_time(~XFS_SB_VERSION2_BITS_SUPPORTED)))
220
+	{
221
+	  grub_error (GRUB_ERR_BAD_FS, "XFS filesystem has unsupported version "
222
+		      "bits");
223
+	  return 0;
224
+	}
225
+      return 1;
226
+    }
227
+  return 0;
228
+}
229
+
230
 /* Filetype information as used in inodes.  */
231
 #define FILETYPE_INO_MASK	0170000
232
 #define FILETYPE_INO_REG	0100000
233
@@ -219,18 +334,6 @@
234
   return (grub_be_to_cpu32 (exts[ex][3]) & ((1 << 21) - 1));
235
 }
236
 
237
-static inline int
238
-GRUB_XFS_ROUND_TO_DIRENT (int pos)
239
-{
240
-  return ((((pos) + 8 - 1) / 8) * 8);
241
-}
242
-
243
-static inline int
244
-GRUB_XFS_NEXT_DIRENT (int pos, int len)
245
-{
246
-  return (pos) + GRUB_XFS_ROUND_TO_DIRENT (8 + 1 + len + 2);
247
-}
248
-
249
 
250
 static inline grub_uint64_t
251
 grub_xfs_inode_block (struct grub_xfs_data *data,
252
@@ -274,6 +377,85 @@
253
 	       + grub_xfs_inode_size(data);
254
 }
255
 
256
+static void *
257
+grub_xfs_inode_data(struct grub_xfs_inode *inode)
258
+{
259
+	if (inode->version <= 2)
260
+		return ((char *)inode) + XFS_V2_INODE_SIZE;
261
+	return ((char *)inode) + XFS_V3_INODE_SIZE;
262
+}
263
+
264
+static struct grub_xfs_dir_entry *
265
+grub_xfs_inline_de(struct grub_xfs_dir_header *head)
266
+{
267
+	/*
268
+	 * With small inode numbers the header is 4 bytes smaller because of
269
+	 * smaller parent pointer
270
+	 */
271
+	return (void *)(((char *)head) + sizeof(struct grub_xfs_dir_header) -
272
+		(head->largeino ? 0 : sizeof(grub_uint32_t)));
273
+}
274
+
275
+static grub_uint8_t *
276
+grub_xfs_inline_de_inopos(struct grub_xfs_data *data,
277
+			  struct grub_xfs_dir_entry *de)
278
+{
279
+	return ((grub_uint8_t *)(de + 1)) + de->len - 1 +
280
+		 (data->hasftype ? 1 : 0);
281
+}
282
+
283
+static struct grub_xfs_dir_entry *
284
+grub_xfs_inline_next_de(struct grub_xfs_data *data,
285
+			struct grub_xfs_dir_header *head,
286
+			struct grub_xfs_dir_entry *de)
287
+{
288
+  char *p = (char *)de + sizeof(struct grub_xfs_dir_entry) - 1 + de->len;
289
+
290
+  p += head->largeino ? sizeof(grub_uint64_t) : sizeof(grub_uint32_t);
291
+  if (data->hasftype)
292
+    p++;
293
+
294
+  return (struct grub_xfs_dir_entry *)p;
295
+}
296
+
297
+static struct grub_xfs_dirblock_tail *
298
+grub_xfs_dir_tail(struct grub_xfs_data *data, void *dirblock)
299
+{
300
+  int dirblksize = 1 << (data->sblock.log2_bsize + data->sblock.log2_dirblk);
301
+
302
+  return (struct grub_xfs_dirblock_tail *)
303
+    ((char *)dirblock + dirblksize - sizeof (struct grub_xfs_dirblock_tail));
304
+}
305
+
306
+static struct grub_xfs_dir2_entry *
307
+grub_xfs_first_de(struct grub_xfs_data *data, void *dirblock)
308
+{
309
+  if (data->hascrc)
310
+    return (struct grub_xfs_dir2_entry *)((char *)dirblock + 64);
311
+  return (struct grub_xfs_dir2_entry *)((char *)dirblock + 16);
312
+}
313
+
314
+static struct grub_xfs_dir2_entry *
315
+grub_xfs_next_de(struct grub_xfs_data *data, struct grub_xfs_dir2_entry *de)
316
+{
317
+  int size = sizeof (struct grub_xfs_dir2_entry) + de->len + 2 /* Tag */;
318
+
319
+  if (data->hasftype)
320
+    size++;		/* File type */
321
+  return (struct grub_xfs_dir2_entry *)(((char *)de) + ALIGN_UP(size, 8));
322
+}
323
+
324
+static grub_uint64_t *
325
+grub_xfs_btree_keys(struct grub_xfs_data *data,
326
+		    struct grub_xfs_btree_node *leaf)
327
+{
328
+  grub_uint64_t *keys = (grub_uint64_t *)(leaf + 1);
329
+
330
+  if (data->hascrc)
331
+    keys += 6;	/* skip crc, uuid, ... */
332
+  return keys;
333
+}
334
+
335
 static grub_err_t
336
 grub_xfs_read_inode (struct grub_xfs_data *data, grub_uint64_t ino,
337
 		     struct grub_xfs_inode *inode)
338
@@ -281,6 +463,8 @@
339
   grub_uint64_t block = grub_xfs_inode_block (data, ino);
340
   int offset = grub_xfs_inode_offset (data, ino);
341
 
342
+  grub_dprintf("xfs", "Reading inode (%"PRIuGRUB_UINT64_T") - %"PRIuGRUB_UINT64_T", %d\n",
343
+	       ino, block, offset);
344
   /* Read the inode.  */
345
   if (grub_disk_read (data->disk, block, offset, grub_xfs_inode_size(data),
346
 		      inode))
347
@@ -303,6 +487,7 @@
348
 
349
   if (node->inode.format == XFS_INODE_FORMAT_BTREE)
350
     {
351
+      struct grub_xfs_btree_root *root;
352
       grub_uint64_t *keys;
353
       int recoffset;
354
 
355
@@ -310,17 +495,15 @@
356
       if (leaf == 0)
357
         return 0;
358
 
359
-      nrec = grub_be_to_cpu16 (node->inode.data.btree.numrecs);
360
-      keys = &node->inode.data.btree.keys[0];
361
+      root = grub_xfs_inode_data(&node->inode);
362
+      nrec = grub_be_to_cpu16 (root->numrecs);
363
+      keys = &root->keys[0];
364
       if (node->inode.fork_offset)
365
-	recoffset = (node->inode.fork_offset
366
-		     - ((char *) &node->inode.data.btree.keys - (char *) &node->inode))
367
-	  / (2 * sizeof (grub_uint64_t));
368
-      else
369
-	recoffset = (grub_xfs_inode_size(node->data)
370
-		     - ((char *) &node->inode.data.btree.keys
371
-			- (char *) &node->inode))
372
-	  / (2 * sizeof (grub_uint64_t));
373
+        recoffset = (node->inode.fork_offset - 1) / 2;
374
+       else
375
+        recoffset = (grub_xfs_inode_size(node->data)
376
+                    - ((char *) keys - (char *) &node->inode))
377
+                               / (2 * sizeof (grub_uint64_t));
378
       do
379
         {
380
           int i;
381
@@ -342,7 +525,10 @@
382
                               0, node->data->bsize, leaf))
383
             return 0;
384
 
385
-          if (grub_strncmp ((char *) leaf->magic, "BMAP", 4))
386
+	  if ((!node->data->hascrc &&
387
+	       grub_strncmp ((char *) leaf->magic, "BMAP", 4)) ||
388
+	      (node->data->hascrc &&
389
+	       grub_strncmp ((char *) leaf->magic, "BMA3", 4)))
390
             {
391
               grub_free (leaf);
392
               grub_error (GRUB_ERR_BAD_FS, "not a correct XFS BMAP node");
393
@@ -350,8 +536,8 @@
394
             }
395
 
396
           nrec = grub_be_to_cpu16 (leaf->numrecs);
397
-          keys = &leaf->keys[0];
398
-	  recoffset = ((node->data->bsize - ((char *) &leaf->keys
399
+          keys = grub_xfs_btree_keys(node->data, leaf);
400
+	  recoffset = ((node->data->bsize - ((char *) keys
401
 					     - (char *) leaf))
402
 		       / (2 * sizeof (grub_uint64_t)));
403
 	}
404
@@ -361,7 +547,7 @@
405
   else if (node->inode.format == XFS_INODE_FORMAT_EXT)
406
     {
407
       nrec = grub_be_to_cpu32 (node->inode.nextents);
408
-      exts = &node->inode.data.extents[0];
409
+      exts = grub_xfs_inode_data(&node->inode);
410
     }
411
   else
412
     {
413
@@ -419,7 +605,7 @@
414
   switch (node->inode.format)
415
     {
416
     case XFS_INODE_FORMAT_INO:
417
-      return grub_strndup (node->inode.data.raw, size);
418
+      return grub_strndup (grub_xfs_inode_data(&node->inode), size);
419
 
420
     case XFS_INODE_FORMAT_EXT:
421
       {
422
@@ -504,23 +690,18 @@
423
     {
424
     case XFS_INODE_FORMAT_INO:
425
       {
426
-	struct grub_xfs_dir_entry *de = &diro->inode.data.dir.direntry[0];
427
-	int smallino = !diro->inode.data.dir.dirhead.smallino;
428
+	struct grub_xfs_dir_header *head = grub_xfs_inode_data(&diro->inode);
429
+	struct grub_xfs_dir_entry *de = grub_xfs_inline_de(head);
430
+	int smallino = !head->largeino;
431
 	int i;
432
 	grub_uint64_t parent;
433
 
434
 	/* If small inode numbers are used to pack the direntry, the
435
 	   parent inode number is small too.  */
436
 	if (smallino)
437
-	  {
438
-	    parent = grub_be_to_cpu32 (diro->inode.data.dir.dirhead.parent.i4);
439
-	    /* The header is a bit smaller than usual.  */
440
-	    de = (struct grub_xfs_dir_entry *) ((char *) de - 4);
441
-	  }
442
+	  parent = grub_be_to_cpu32 (head->parent.i4);
443
 	else
444
-	  {
445
-	    parent = grub_be_to_cpu64(diro->inode.data.dir.dirhead.parent.i8);
446
-	  }
447
+	  parent = grub_be_to_cpu64 (head->parent.i8);
448
 
449
 	/* Synthesize the direntries for `.' and `..'.  */
450
 	if (call_hook (diro->ino, "."))
451
@@ -529,12 +710,10 @@
452
 	if (call_hook (parent, ".."))
453
 	  return 1;
454
 
455
-	for (i = 0; i < diro->inode.data.dir.dirhead.count; i++)
456
+	for (i = 0; i < head->count; i++)
457
 	  {
458
 	    grub_uint64_t ino;
459
-	    grub_uint8_t *inopos = (((grub_uint8_t *) de)
460
-			    + sizeof (struct grub_xfs_dir_entry)
461
-			    + de->len - 1);
462
+	    grub_uint8_t *inopos = grub_xfs_inline_de_inopos(dir->data, de);
463
 	    char name[de->len + 1];
464
 
465
 	    /* inopos might be unaligned.  */
466
@@ -558,10 +737,7 @@
467
 	    if (call_hook (ino, name))
468
 	      return 1;
469
 
470
-	    de = ((struct grub_xfs_dir_entry *)
471
-		  (((char *) de)+ sizeof (struct grub_xfs_dir_entry) + de->len
472
-		   + ((smallino ? sizeof (grub_uint32_t)
473
-		       : sizeof (grub_uint64_t))) - 1));
474
+	    de = grub_xfs_inline_next_de(dir->data, head, de);
475
 	  }
476
 	break;
477
       }
478
@@ -588,15 +764,11 @@
479
 		    >> dirblk_log2);
480
 	     blk++)
481
 	  {
482
-	    /* The header is skipped, the first direntry is stored
483
-	       from byte 16.  */
484
-	    int pos = 16;
485
+	    struct grub_xfs_dir2_entry *direntry =
486
+					grub_xfs_first_de(dir->data, dirblock);
487
 	    int entries;
488
-	    int tail_start = (dirblk_size
489
-			      - sizeof (struct grub_xfs_dirblock_tail));
490
-
491
-	    struct grub_xfs_dirblock_tail *tail;
492
-	    tail = (struct grub_xfs_dirblock_tail *) &dirblock[tail_start];
493
+	    struct grub_xfs_dirblock_tail *tail =
494
+					grub_xfs_dir_tail(dir->data, dirblock);
495
 
496
 	    numread = grub_xfs_read_file (dir, 0,
497
 					  blk << dirblk_log2,
498
@@ -608,13 +780,11 @@
499
 		       - grub_be_to_cpu32 (tail->leaf_stale));
500
 
501
 	    /* Iterate over all entries within this block.  */
502
-	    while (pos < tail_start)
503
+	    while ((char *)direntry < (char *)tail)
504
 	      {
505
-		struct grub_xfs_dir2_entry *direntry;
506
 		grub_uint8_t *freetag;
507
 		char *filename;
508
 
509
-		direntry = (struct grub_xfs_dir2_entry *) &dirblock[pos];
510
 		freetag = (grub_uint8_t *) direntry;
511
 
512
 		if (grub_get_unaligned16 (freetag) == 0XFFFF)
513
@@ -622,14 +792,16 @@
514
 		    grub_uint8_t *skip = (freetag + sizeof (grub_uint16_t));
515
 
516
 		    /* This entry is not used, go to the next one.  */
517
-		    pos += grub_be_to_cpu16 (grub_get_unaligned16 (skip));
518
+		    direntry = (struct grub_xfs_dir2_entry *)
519
+				(((char *)direntry) +
520
+				grub_be_to_cpu16 (grub_get_unaligned16 (skip)));
521
 
522
 		    continue;
523
 		  }
524
 
525
-		filename = &dirblock[pos + sizeof (*direntry)];
526
-		/* The byte after the filename is for the tag, which
527
-		   is not used by GRUB.  So it can be overwritten.  */
528
+		filename = (char *)(direntry + 1);
529
+		/* The byte after the filename is for the filetype, padding, or
530
+		   tag, which is not used by GRUB.  So it can be overwritten. */
531
 		filename[direntry->len] = '\0';
532
 
533
 		if (call_hook (grub_be_to_cpu64(direntry->inode), filename))
534
@@ -645,8 +817,7 @@
535
 		  break;
536
 
537
 		/* Select the next directory entry.  */
538
-		pos = GRUB_XFS_NEXT_DIRENT (pos, direntry->len);
539
-		pos = GRUB_XFS_ROUND_TO_DIRENT (pos);
540
+		direntry = grub_xfs_next_de(dir->data, direntry);
541
 	      }
542
 	  }
543
 	grub_free (dirblock);
544
@@ -671,19 +842,14 @@
545
   if (!data)
546
     return 0;
547
 
548
+  grub_dprintf("xfs", "Reading sb\n");
549
   /* Read the superblock.  */
550
   if (grub_disk_read (disk, 0, 0,
551
 		      sizeof (struct grub_xfs_sblock), &data->sblock))
552
     goto fail;
553
 
554
-  if (grub_strncmp ((char *) (data->sblock.magic), "XFSB", 4)
555
-      || data->sblock.log2_bsize < GRUB_DISK_SECTOR_BITS
556
-      || ((int) data->sblock.log2_bsize
557
-	  + (int) data->sblock.log2_dirblk) >= 27)
558
-    {
559
-      grub_error (GRUB_ERR_BAD_FS, "not a XFS filesystem");
560
-      goto fail;
561
-    }
562
+  if (!grub_xfs_sb_valid(data))
563
+    goto fail;
564
 
565
   data = grub_realloc (data,
566
 		       sizeof (struct grub_xfs_data)
567
@@ -698,9 +864,13 @@
568
   data->diropen.inode_read = 1;
569
   data->bsize = grub_be_to_cpu32 (data->sblock.bsize);
570
   data->agsize = grub_be_to_cpu32 (data->sblock.agsize);
571
+  data->hasftype = grub_xfs_sb_hasftype(data);
572
+  data->hascrc = grub_xfs_sb_hascrc(data);
573
 
574
   data->disk = disk;
575
   data->pos = 0;
576
+  grub_dprintf("xfs", "Reading root ino %"PRIuGRUB_UINT64_T"\n",
577
+	       grub_cpu_to_be64(data->sblock.rootino));
578
 
579
   grub_xfs_read_inode (data, data->diropen.ino, &data->diropen.inode);
580
 
view file @ 81d83e9c23
... ... --- /dev/null
... ... +++ b/0005-xfs-silence-Coverity-overflow-warning.patch
... ... @@ -0,0 +1,27 @@
1
From 4ac2b84fea9a90d68970c0729a02895d47a8b40c Mon Sep 17 00:00:00 2001
2
From: Andrei Borzenkov <arvidjaar@gmail.com>
3
Date: Fri, 19 Jun 2015 18:38:25 +0300
4
Subject: [PATCH 14/23] xfs: silence Coverity overflow warning
5
6
inode size cannot really overflow integer, but Coverity does not know it.
7
CID: 96602
8
---
9
 grub-core/fs/xfs.c | 2 +-
10
 1 file changed, 1 insertion(+), 1 deletion(-)
11
12
diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
13
index f00e43e..7249291 100644
14
--- a/grub-core/fs/xfs.c
15
+++ b/grub-core/fs/xfs.c
16
@@ -361,7 +361,7 @@ grub_xfs_inode_offset (struct grub_xfs_data *data,
17
 static inline grub_size_t
18
 grub_xfs_inode_size(struct grub_xfs_data *data)
19
 {
20
-  return 1 << data->sblock.log2_inode;
21
+  return (grub_size_t)1 << data->sblock.log2_inode;
22
 }
23
 
24
 /*
25
-- 
26
2.4.3
27
view file @ 81d83e9c23
... ... --- /dev/null
... ... +++ b/0006-fix-handling-of-symlink.patch
... ... @@ -0,0 +1,77 @@
1
From 049dcfa03c2217f3af9f108d3f41229b8155c534 Mon Sep 17 00:00:00 2001
2
From: Vladimir Serbinenko <phcoder@gmail.com>
3
Date: Thu, 23 Jul 2015 23:15:32 +0000
4
Subject: xfs: Fix handling of symlink with crc-enabled filesystem.
5
6
---
7
(limited to 'grub-core/fs/xfs.c')
8
9
diff -urN grub-2.00/grub-core/fs/xfs.c grub-2.00-patched/grub-core/fs/xfs.c
10
--- grub-2.00/grub-core/fs/xfs.c	2016-07-08 23:11:22.127268295 +1000
11
+++ grub-2.00-patched/grub-core/fs/xfs.c	2016-07-08 23:15:17.424272702 +1000
12
@@ -587,11 +587,11 @@
13
 grub_xfs_read_file (grub_fshelp_node_t node,
14
 		     void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
15
 					unsigned offset, unsigned length),
16
-		     grub_off_t pos, grub_size_t len, char *buf)
17
+		     grub_off_t pos, grub_size_t len, char *buf, grub_uint32_t header_size)
18
 {
19
   return grub_fshelp_read_file (node->data->disk, node, read_hook,
20
 				pos, len, buf, grub_xfs_read_block,
21
-				grub_be_to_cpu64 (node->inode.size),
22
+				grub_be_to_cpu64 (node->inode.size) + header_size,
23
 				node->data->sblock.log2_bsize
24
 				- GRUB_DISK_SECTOR_BITS, 0);
25
 }
26
@@ -600,7 +600,13 @@
27
 static char *
28
 grub_xfs_read_symlink (grub_fshelp_node_t node)
29
 {
30
-  int size = grub_be_to_cpu64 (node->inode.size);
31
+  grub_ssize_t size = grub_be_to_cpu64 (node->inode.size);
32
+
33
+  if (size < 0)
34
+    {
35
+      grub_error (GRUB_ERR_BAD_FS, "invalid symlink");
36
+      return 0;
37
+    }
38
 
39
   switch (node->inode.format)
40
     {
41
@@ -611,12 +617,17 @@
42
       {
43
 	char *symlink;
44
 	grub_ssize_t numread;
45
+	int off = 0;
46
+
47
+	if (node->data->hascrc)
48
+	  off = 56;
49
 
50
 	symlink = grub_malloc (size + 1);
51
 	if (!symlink)
52
 	  return 0;
53
 
54
-	numread = grub_xfs_read_file (node, 0, 0, size, symlink);
55
+	node->inode.size = grub_be_to_cpu64 (size + off);
56
+	numread = grub_xfs_read_file (node, 0, 0, size, symlink, off);
57
 	if (numread != size)
58
 	  {
59
 	    grub_free (symlink);
60
@@ -772,7 +783,7 @@
61
 
62
 	    numread = grub_xfs_read_file (dir, 0,
63
 					  blk << dirblk_log2,
64
-					  dirblk_size, dirblock);
65
+					  dirblk_size, dirblock, 0);
66
 	    if (numread != dirblk_size)
67
 	      return 0;
68
 
69
@@ -996,7 +1007,7 @@
70
     (struct grub_xfs_data *) file->data;
71
 
72
   return grub_xfs_read_file (&data->diropen, file->read_hook,
73
-			      file->offset, len, buf);
74
+			      file->offset, len, buf, 0);
75
 }
76
 
77
 
... ... --- a/grub2.spec
... ... +++ b/grub2.spec
... ... @@ -13,7 +13,7 @@
13 13
Summary:	GNU GRUB is a Multiboot boot loader
14 14
Name:		grub2
15 15
Version:	2.00
16
Release:	78
16
Release:	79
17 17
License:	GPLv3+
18 18
Group:		System/Kernel and hardware
19 19
Url:		http://www.gnu.org/software/grub/
... ... @@ -98,6 +98,14 @@ Patch514: grub2-2.00-secureboot-chainloader.patch
98 98
Patch515:	grub2-2.00-efi-install-grub-cfg.patch
99 99
Patch516:	0516-Fix-security-issue-when-reading-username-and-passwor.patch
100 100
101
# Backported from upstream and re-worked for 2.00
102
Patch600:	0001-xfs-Fix-termination-loop-for-directory-iteration.patch
103
Patch601:	0002-xfs-Convert-inode-numbers-to-cpu-endianity-immediate.patch
104
Patch602:	0003-xfs-Add-helpers-for-inode-size.patch
105
Patch603:	0004-xfs-V5-filesystem-format-support.patch
106
Patch604:	0005-xfs-silence-Coverity-overflow-warning.patch
107
Patch605:	0006-fix-handling-of-symlink.patch
108
101 109
# For updating Makefile template after patch 12
102 110
BuildRequires:	autogen
103 111
BuildRequires:	bison

Comments