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..7f214ea --- /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 +Date: Thu, 5 Jun 2014 20:56:21 +0200 +Subject: [PATCH 1/4] xfs: Add helper for inode size + +Signed-off-by: Jan Kara +--- + 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..dd3eb83 --- /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 +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 +--- + 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..23fcf89 --- /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 +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 +--- + 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..6359d64 --- /dev/null +++ b/grub2-xfs-V5-filesystem-format-support.patch @@ -0,0 +1,481 @@ +From 2f725e644d8ccf001a4dccddc8abb2c9479352a7 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Wed, 11 Jun 2014 18:36:01 +0200 +Subject: [PATCH] xfs: V5 filesystem format support + +Signed-off-by: Jan Kara +--- + grub-core/fs/xfs.c | 245 +++++++++++++++++++++++++++++++++++++---------------- + 1 file changed, 173 insertions(+), 72 deletions(-) + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index 7e247a32df5c..3b1d8994067f 100644 +--- a/grub-core/fs/xfs.c ++++ b/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 *exts, int ex) + 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 *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 *)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_data *data, grub_uint64_t ino, + 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 node, grub_disk_addr_t fileblock) + + 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 node, grub_disk_addr_t fileblock) + 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 node, grub_disk_addr_t fileblock) + 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 node, grub_disk_addr_t fileblock) + } + + 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 node, grub_disk_addr_t fileblock) + 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_t 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 dir, + { + 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 dir, + 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 dir, + 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 dir, + >> 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 dir, + - 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 dir, + 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 dir, + 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); + +-- +1.8.1.4 + diff --git a/grub2.changes b/grub2.changes index a9661ab..f02668f 100644 --- a/grub2.changes +++ b/grub2.changes @@ -1,3 +1,14 @@ +------------------------------------------------------------------- +Wed Jun 25 09:20:16 UTC 2014 - jack@suse.cz + +- xfs V5 superblock support (bnc#880166 bnc#883392) + +- added patches: + * grub2-xfs-Add-helper-for-inode-size.patch + * grub2-xfs-Fix-termination-loop-for-directory-iteration.patch + * grub2-xfs-Convert-inode-numbers-to-cpu-endianity-immediate.patch + * grub2-xfs-V5-filesystem-format-support.patch + ------------------------------------------------------------------- Fri Jun 20 19:50:28 UTC 2014 - jeffm@suse.com diff --git a/grub2.spec b/grub2.spec index ea9a18c..b141efa 100644 --- a/grub2.spec +++ b/grub2.spec @@ -174,6 +174,10 @@ Patch224: grub2-ppc64-build-ppc64-32bit.patch Patch225: grub2-ppc64-qemu.patch Patch226: grub2-ppc64le-timeout.patch Patch227: grub2-use-stat-instead-of-udevadm-for-partition-lookup.patch +Patch228: grub2-xfs-Add-helper-for-inode-size.patch +Patch229: grub2-xfs-Fix-termination-loop-for-directory-iteration.patch +Patch230: grub2-xfs-Convert-inode-numbers-to-cpu-endianity-immediate.patch +Patch231: grub2-xfs-V5-filesystem-format-support.patch Requires: gettext-runtime %if 0%{?suse_version} >= 1140 @@ -364,6 +368,10 @@ mv po/grub.pot po/%{name}.pot %patch225 -p1 %patch226 -p1 %patch227 -p1 +%patch228 -p1 +%patch229 -p1 +%patch230 -p1 +%patch231 -p1 # Generate po/LINGUAS for message catalogs ... ./linguas.sh