5ef95ecb65
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
168 lines
5.4 KiB
Diff
168 lines
5.4 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
From: Carlos Maiolino <cmaiolino@redhat.com>
|
||
Date: Wed, 14 Apr 2021 11:07:20 +0200
|
||
Subject: [PATCH] fs/xfs: Add bigtime support for xfs driver
|
||
|
||
XFS filesystem now supports bigtime feature, to overcome y2038 problem.
|
||
This patch makes grub able to support xfs filesystems with this feature
|
||
enabled.
|
||
|
||
xfs counter for bigtime enable timestamps starts on 0, which translates
|
||
to INT32_MIN (Dec 31 20:45:52 UTC 1901) in the legacy timestamps. The
|
||
conversion to unix timestamps is made before passing the value to
|
||
grub-core.
|
||
|
||
For this to work properly, grub requires to access flags2 field in the
|
||
xfs ondisk inode, so, the grub_xfs_inode structure has been updated to
|
||
the full ondisk inode size.
|
||
|
||
This patch is enough to make grub work properly with files with
|
||
timestamps up to INT32_MAX (y2038), any file with timestamps bigger than
|
||
this will overflow the counter, causing grub to show wrong timestamps
|
||
(not really much difference on current situation).
|
||
|
||
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
|
||
Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com>
|
||
---
|
||
grub-core/fs/xfs.c | 69 ++++++++++++++++++++++++++++++++++++++++++------------
|
||
1 file changed, 54 insertions(+), 15 deletions(-)
|
||
|
||
diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
|
||
index 43023e03fb3..2ce76ec70f9 100644
|
||
--- a/grub-core/fs/xfs.c
|
||
+++ b/grub-core/fs/xfs.c
|
||
@@ -75,10 +75,15 @@ GRUB_MOD_LICENSE ("GPLv3+");
|
||
XFS_SB_VERSION2_PROJID32BIT | \
|
||
XFS_SB_VERSION2_FTYPE)
|
||
|
||
+/* Inode flags2 flags */
|
||
+#define XFS_DIFLAG2_BIGTIME_BIT 3
|
||
+#define XFS_DIFLAG2_BIGTIME (1 << XFS_DIFLAG2_BIGTIME_BIT)
|
||
+
|
||
/* incompat feature flags */
|
||
-#define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0) /* filetype in dirent */
|
||
-#define XFS_SB_FEAT_INCOMPAT_SPINODES (1 << 1) /* sparse inode chunks */
|
||
-#define XFS_SB_FEAT_INCOMPAT_META_UUID (1 << 2) /* metadata UUID */
|
||
+#define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0) /* filetype in dirent */
|
||
+#define XFS_SB_FEAT_INCOMPAT_SPINODES (1 << 1) /* sparse inode chunks */
|
||
+#define XFS_SB_FEAT_INCOMPAT_META_UUID (1 << 2) /* metadata UUID */
|
||
+#define XFS_SB_FEAT_INCOMPAT_BIGTIME (1 << 3) /* large timestamps */
|
||
|
||
/*
|
||
* Directory entries with ftype are explicitly handled by GRUB code.
|
||
@@ -92,7 +97,8 @@ GRUB_MOD_LICENSE ("GPLv3+");
|
||
#define XFS_SB_FEAT_INCOMPAT_SUPPORTED \
|
||
(XFS_SB_FEAT_INCOMPAT_FTYPE | \
|
||
XFS_SB_FEAT_INCOMPAT_SPINODES | \
|
||
- XFS_SB_FEAT_INCOMPAT_META_UUID)
|
||
+ XFS_SB_FEAT_INCOMPAT_META_UUID | \
|
||
+ XFS_SB_FEAT_INCOMPAT_BIGTIME)
|
||
|
||
struct grub_xfs_sblock
|
||
{
|
||
@@ -177,7 +183,7 @@ struct grub_xfs_btree_root
|
||
grub_uint64_t keys[1];
|
||
} GRUB_PACKED;
|
||
|
||
-struct grub_xfs_time
|
||
+struct grub_xfs_time_legacy
|
||
{
|
||
grub_uint32_t sec;
|
||
grub_uint32_t nanosec;
|
||
@@ -190,20 +196,23 @@ struct grub_xfs_inode
|
||
grub_uint8_t version;
|
||
grub_uint8_t format;
|
||
grub_uint8_t unused2[26];
|
||
- struct grub_xfs_time atime;
|
||
- struct grub_xfs_time mtime;
|
||
- struct grub_xfs_time ctime;
|
||
+ grub_uint64_t atime;
|
||
+ grub_uint64_t mtime;
|
||
+ grub_uint64_t ctime;
|
||
grub_uint64_t size;
|
||
grub_uint64_t nblocks;
|
||
grub_uint32_t extsize;
|
||
grub_uint32_t nextents;
|
||
grub_uint16_t unused3;
|
||
grub_uint8_t fork_offset;
|
||
- grub_uint8_t unused4[17];
|
||
+ grub_uint8_t unused4[37];
|
||
+ grub_uint64_t flags2;
|
||
+ grub_uint8_t unused5[48];
|
||
} GRUB_PACKED;
|
||
|
||
-#define XFS_V2_INODE_SIZE sizeof(struct grub_xfs_inode)
|
||
-#define XFS_V3_INODE_SIZE (XFS_V2_INODE_SIZE + 76)
|
||
+#define XFS_V3_INODE_SIZE sizeof(struct grub_xfs_inode)
|
||
+/* Size of struct grub_xfs_inode until fork_offset (included)*/
|
||
+#define XFS_V2_INODE_SIZE (XFS_V3_INODE_SIZE - 92)
|
||
|
||
struct grub_xfs_dirblock_tail
|
||
{
|
||
@@ -233,8 +242,6 @@ struct grub_xfs_data
|
||
|
||
static grub_dl_t my_mod;
|
||
|
||
-
|
||
-
|
||
static int grub_xfs_sb_hascrc(struct grub_xfs_data *data)
|
||
{
|
||
return (data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_NUMBITS)) ==
|
||
@@ -950,7 +957,6 @@ grub_xfs_mount (grub_disk_t disk)
|
||
return 0;
|
||
}
|
||
|
||
-
|
||
/* Context for grub_xfs_dir. */
|
||
struct grub_xfs_dir_ctx
|
||
{
|
||
@@ -958,6 +964,39 @@ struct grub_xfs_dir_ctx
|
||
void *hook_data;
|
||
};
|
||
|
||
+/* Bigtime inodes helpers */
|
||
+
|
||
+#define NSEC_PER_SEC 1000000000L
|
||
+#define XFS_BIGTIME_EPOCH_OFFSET (-(grub_int64_t)GRUB_INT32_MIN)
|
||
+
|
||
+static int grub_xfs_inode_has_bigtime(const struct grub_xfs_inode *inode)
|
||
+{
|
||
+ return inode->version >= 3 &&
|
||
+ (inode->flags2 & grub_cpu_to_be64_compile_time(XFS_DIFLAG2_BIGTIME));
|
||
+}
|
||
+
|
||
+static grub_int64_t
|
||
+grub_xfs_bigtime_to_unix(grub_uint64_t time)
|
||
+{
|
||
+ grub_uint64_t rem;
|
||
+ grub_int64_t nsec = NSEC_PER_SEC;
|
||
+ grub_int64_t seconds = grub_divmod64((grub_int64_t)time, nsec, &rem);
|
||
+
|
||
+ return seconds - XFS_BIGTIME_EPOCH_OFFSET;
|
||
+}
|
||
+
|
||
+static grub_int64_t
|
||
+grub_xfs_get_inode_time(struct grub_xfs_inode *inode)
|
||
+{
|
||
+ struct grub_xfs_time_legacy *lts;
|
||
+
|
||
+ if (grub_xfs_inode_has_bigtime(inode))
|
||
+ return grub_xfs_bigtime_to_unix(grub_be_to_cpu64(inode->mtime));
|
||
+
|
||
+ lts = (struct grub_xfs_time_legacy *)&inode->mtime;
|
||
+ return grub_be_to_cpu32(lts->sec);
|
||
+}
|
||
+
|
||
/* Helper for grub_xfs_dir. */
|
||
static int
|
||
grub_xfs_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
|
||
@@ -970,7 +1009,7 @@ grub_xfs_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
|
||
if (node->inode_read)
|
||
{
|
||
info.mtimeset = 1;
|
||
- info.mtime = grub_be_to_cpu32 (node->inode.mtime.sec);
|
||
+ info.mtime = grub_xfs_get_inode_time(&node->inode);
|
||
}
|
||
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
|
||
grub_free (node);
|