From c405ccb5e248fed55da0590503782c26b4c0859b Mon Sep 17 00:00:00 2001 From: Alexander Zarochentsev Date: Fri, 18 Dec 2015 23:59:31 +0300 Subject: [PATCH] LU-7581 ldiskfs: wrong EA inode backpointer check EA inode is linked back to the parent inode using i_mtime.tv_sec filed. An inode number bigger 2G gets mangled due to sign bit extension over the high bits of tv_sec. It causes parent backpointer checks to fail. Add an explicit integer type conversion to ignore high bits of i_mtime.tv_sec. Change-Id: I4e086ca5bf13ec77ef0af73fa1f88846e278de23 Seagate-bug-id: MRP-3215 Signed-off-by: Alexander Zarochentsev Reviewed-on: http://review.whamcloud.com/17675 Tested-by: Maloo Reviewed-by: Andreas Dilger Reviewed-by: Niu Yawei Reviewed-by: Oleg Drokin --- .../patches/rhel6.3/ext4-large-eas.patch | 19 +++++++++++++++---- .../kernel_patches/patches/rhel7/ext4-large-eas.patch | 19 +++++++++++++++---- .../patches/sles11sp2/ext4-large-eas.patch | 19 +++++++++++++++---- .../patches/sles12/ext4-large-eas.patch | 19 +++++++++++++++---- 4 files changed, 60 insertions(+), 16 deletions(-) diff --git a/ldiskfs/kernel_patches/patches/rhel6.3/ext4-large-eas.patch b/ldiskfs/kernel_patches/patches/rhel6.3/ext4-large-eas.patch index a09bf18..ad656bf 100644 --- a/ldiskfs/kernel_patches/patches/rhel6.3/ext4-large-eas.patch +++ b/ldiskfs/kernel_patches/patches/rhel6.3/ext4-large-eas.patch @@ -136,7 +136,7 @@ Index: linux-stage/fs/ext4/xattr.c + return NULL; + } + -+ if (ea_inode->i_xattr_inode_parent != parent->i_ino || ++ if (EXT4_XATTR_INODE_GET_PARENT(ea_inode) != parent->i_ino || + ea_inode->i_generation != parent->i_generation) { + ext4_error(parent->i_sb, "Backpointer from EA inode %lu " + "to parent invalid.", ea_ino); @@ -347,7 +347,7 @@ Index: linux-stage/fs/ext4/xattr.c + * A back-pointer from EA inode to parent inode will be useful + * for e2fsck. + */ -+ ea_inode->i_xattr_inode_parent = inode->i_ino; ++ EXT4_XATTR_INODE_SET_PARENT(ea_inode, inode->i_ino); + unlock_new_inode(ea_inode); + } + @@ -881,11 +881,22 @@ Index: linux-stage/fs/ext4/xattr.h __le32 e_value_size; /* size of attribute value */ __le32 e_hash; /* hash value of name and value */ char e_name[0]; /* attribute name */ -@@ -63,6 +63,15 @@ struct ext4_xattr_entry { +@@ -63,6 +63,26 @@ struct ext4_xattr_entry { EXT4_I(inode)->i_extra_isize)) #define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1)) -+#define i_xattr_inode_parent i_mtime.tv_sec ++/* ++ * Link EA inode back to parent one using i_mtime field. ++ * Extra integer type conversion added to ignore higher ++ * bits in i_mtime.tv_sec which might be set by ext4_get() ++ */ ++#define EXT4_XATTR_INODE_SET_PARENT(inode, inum) \ ++do { \ ++ (inode)->i_mtime.tv_sec = inum; \ ++} while(0) ++ ++#define EXT4_XATTR_INODE_GET_PARENT(inode) \ ++((__u32)(inode)->i_mtime.tv_sec) + +/* + * The minimum size of EA value when you start storing it in an external inode diff --git a/ldiskfs/kernel_patches/patches/rhel7/ext4-large-eas.patch b/ldiskfs/kernel_patches/patches/rhel7/ext4-large-eas.patch index 24976ee..a461062 100644 --- a/ldiskfs/kernel_patches/patches/rhel7/ext4-large-eas.patch +++ b/ldiskfs/kernel_patches/patches/rhel7/ext4-large-eas.patch @@ -243,7 +243,7 @@ Index: linux-stage/fs/ext4/xattr.c + return NULL; + } + -+ if (ea_inode->i_xattr_inode_parent != parent->i_ino || ++ if (EXT4_XATTR_INODE_GET_PARENT(ea_inode) != parent->i_ino || + ea_inode->i_generation != parent->i_generation) { + ext4_error(parent->i_sb, "Backpointer from EA inode %lu " + "to parent invalid.", ea_ino); @@ -458,7 +458,7 @@ Index: linux-stage/fs/ext4/xattr.c + * A back-pointer from EA inode to parent inode will be useful + * for e2fsck. + */ -+ ea_inode->i_xattr_inode_parent = inode->i_ino; ++ EXT4_XATTR_INODE_SET_PARENT(ea_inode, inode->i_ino); + unlock_new_inode(ea_inode); + } + @@ -990,11 +990,22 @@ Index: linux-stage/fs/ext4/xattr.h __le32 e_value_size; /* size of attribute value */ __le32 e_hash; /* hash value of name and value */ char e_name[0]; /* attribute name */ -@@ -67,6 +67,15 @@ struct ext4_xattr_entry { +@@ -67,6 +67,26 @@ struct ext4_xattr_entry { EXT4_I(inode)->i_extra_isize)) #define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1)) -+#define i_xattr_inode_parent i_mtime.tv_sec ++/* ++ * Link EA inode back to parent one using i_mtime field. ++ * Extra integer type conversion added to ignore higher ++ * bits in i_mtime.tv_sec which might be set by ext4_get() ++ */ ++#define EXT4_XATTR_INODE_SET_PARENT(inode, inum) \ ++do { \ ++ (inode)->i_mtime.tv_sec = inum; \ ++} while(0) ++ ++#define EXT4_XATTR_INODE_GET_PARENT(inode) \ ++((__u32)(inode)->i_mtime.tv_sec) + +/* + * The minimum size of EA value when you start storing it in an external inode diff --git a/ldiskfs/kernel_patches/patches/sles11sp2/ext4-large-eas.patch b/ldiskfs/kernel_patches/patches/sles11sp2/ext4-large-eas.patch index f9f70a6..1c784d9 100644 --- a/ldiskfs/kernel_patches/patches/sles11sp2/ext4-large-eas.patch +++ b/ldiskfs/kernel_patches/patches/sles11sp2/ext4-large-eas.patch @@ -237,7 +237,7 @@ Index: linux-stage/fs/ext4/xattr.c + return NULL; + } + -+ if (ea_inode->i_xattr_inode_parent != parent->i_ino || ++ if (EXT4_XATTR_INODE_GET_PARENT(ea_inode) != parent->i_ino || + ea_inode->i_generation != parent->i_generation) { + ext4_error(parent->i_sb, "Backpointer from EA inode %lu " + "to parent invalid.", ea_ino); @@ -451,7 +451,7 @@ Index: linux-stage/fs/ext4/xattr.c + * A back-pointer from EA inode to parent inode will be useful + * for e2fsck. + */ -+ ea_inode->i_xattr_inode_parent = inode->i_ino; ++ EXT4_XATTR_INODE_SET_PARENT(ea_inode, inode->i_ino); + unlock_new_inode(ea_inode); + } + @@ -983,11 +983,22 @@ Index: linux-stage/fs/ext4/xattr.h __le32 e_value_size; /* size of attribute value */ __le32 e_hash; /* hash value of name and value */ char e_name[0]; /* attribute name */ -@@ -63,6 +63,15 @@ struct ext4_xattr_entry { +@@ -63,6 +63,26 @@ struct ext4_xattr_entry { EXT4_I(inode)->i_extra_isize)) #define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1)) -+#define i_xattr_inode_parent i_mtime.tv_sec ++/* ++ * Link EA inode back to parent one using i_mtime field. ++ * Extra integer type conversion added to ignore higher ++ * bits in i_mtime.tv_sec which might be set by ext4_get() ++ */ ++#define EXT4_XATTR_INODE_SET_PARENT(inode, inum) \ ++do { \ ++ (inode)->i_mtime.tv_sec = inum; \ ++} while(0) ++ ++#define EXT4_XATTR_INODE_GET_PARENT(inode) \ ++((__u32)(inode)->i_mtime.tv_sec) + +/* + * The minimum size of EA value when you start storing it in an external inode diff --git a/ldiskfs/kernel_patches/patches/sles12/ext4-large-eas.patch b/ldiskfs/kernel_patches/patches/sles12/ext4-large-eas.patch index 6a18661..baf0b57 100644 --- a/ldiskfs/kernel_patches/patches/sles12/ext4-large-eas.patch +++ b/ldiskfs/kernel_patches/patches/sles12/ext4-large-eas.patch @@ -235,7 +235,7 @@ Index: linux-stage/fs/ext4/xattr.c + return NULL; + } + -+ if (ea_inode->i_xattr_inode_parent != parent->i_ino || ++ if (EXT4_XATTR_INODE_GET_PARENT(ea_inode) != parent->i_ino || + ea_inode->i_generation != parent->i_generation) { + ext4_error(parent->i_sb, "Backpointer from EA inode %lu " + "to parent invalid.", ea_ino); @@ -448,7 +448,7 @@ Index: linux-stage/fs/ext4/xattr.c + * A back-pointer from EA inode to parent inode will be useful + * for e2fsck. + */ -+ ea_inode->i_xattr_inode_parent = inode->i_ino; ++ EXT4_XATTR_INODE_SET_PARENT(ea_inode, inode->i_ino); + unlock_new_inode(ea_inode); + } + @@ -980,11 +980,22 @@ Index: linux-stage/fs/ext4/xattr.h __le32 e_value_size; /* size of attribute value */ __le32 e_hash; /* hash value of name and value */ char e_name[0]; /* attribute name */ -@@ -67,6 +67,15 @@ struct ext4_xattr_entry { +@@ -67,6 +67,26 @@ struct ext4_xattr_entry { EXT4_I(inode)->i_extra_isize)) #define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1)) -+#define i_xattr_inode_parent i_mtime.tv_sec ++/* ++ * Link EA inode back to parent one using i_mtime field. ++ * Extra integer type conversion added to ignore higher ++ * bits in i_mtime.tv_sec which might be set by ext4_get() ++ */ ++#define EXT4_XATTR_INODE_SET_PARENT(inode, inum) \ ++do { \ ++ (inode)->i_mtime.tv_sec = inum; \ ++} while(0) ++ ++#define EXT4_XATTR_INODE_GET_PARENT(inode) \ ++((__u32)(inode)->i_mtime.tv_sec) + +/* + * The minimum size of EA value when you start storing it in an external inode -- 1.8.3.1