Port http://review.whamcloud.com/17675 for RHEL7.2:
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.
Alexander Zarochentsev <alexander.zarochentsev@seagate.com>
Fix other code style issues and comments for upstream kernel.
Signed-off-by: Andreas Dilger <andreas.dilger@intel.com>
Change-Id: I7d402f000cde5ffb1ededf7a80276538e4465757
Reviewed-on: http://review.whamcloud.com/18436
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Bob Glossman <bob.glossman@intel.com>
Reviewed-by: Yang Sheng <yang.sheng@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
#define EXT4_MMP_MAX_CHECK_INTERVAL 300UL
/*
#define EXT4_MMP_MAX_CHECK_INTERVAL 300UL
/*
-+ * Maximum size of xattr attributes for FEATURE_INCOMPAT_EA_INODE 1Mb
++ * Maximum size of xattr attributes for FEATURE_INCOMPAT_EA_INODE 1MB
+ * This limit is arbitrary, but is reasonable for the xattr API.
+ */
+#define EXT4_XATTR_MAX_LARGE_EA_SIZE (1024 * 1024)
+ * This limit is arbitrary, but is reasonable for the xattr API.
+ */
+#define EXT4_XATTR_MAX_LARGE_EA_SIZE (1024 * 1024)
if (IS_ERR(handle)) {
ext4_std_error(inode->i_sb, PTR_ERR(handle));
/*
if (IS_ERR(handle)) {
ext4_std_error(inode->i_sb, PTR_ERR(handle));
/*
-@@ -249,9 +249,36 @@ void ext4_evict_inode(struct inode *inod
- sb_end_intwrite(inode->i_sb);
- goto no_delete;
- }
--
+@@ -252,6 +252,32 @@ void ext4_evict_inode(struct inode *inod
+
if (IS_SYNC(inode))
ext4_handle_sync(handle);
+
if (IS_SYNC(inode))
ext4_handle_sync(handle);
+
-+ /*
-+ * Delete xattr inode before deleting the main inode.
-+ */
++ /* Delete xattr inode before deleting the main inode. */
+ err = ext4_xattr_delete_inode(handle, inode, &lea_ino_array);
+ if (err) {
+ ext4_warning(inode->i_sb,
+ err = ext4_xattr_delete_inode(handle, inode, &lea_ino_array);
+ if (err) {
+ ext4_warning(inode->i_sb,
inode->i_size = 0;
err = ext4_mark_inode_dirty(handle, inode);
if (err) {
inode->i_size = 0;
err = ext4_mark_inode_dirty(handle, inode);
if (err) {
-@@ -306,8 +333,12 @@ void ext4_evict_inode(struct inode *inod
- ext4_clear_inode(inode);
- else
+@@ -308,6 +335,9 @@ void ext4_evict_inode(struct inode *inod
ext4_free_inode(handle, inode);
ext4_free_inode(handle, inode);
ext4_journal_stop(handle);
sb_end_intwrite(inode->i_sb);
+
ext4_journal_stop(handle);
sb_end_intwrite(inode->i_sb);
+
return;
no_delete:
ext4_clear_inode(inode); /* We must guarantee clearing of inode... */
return;
no_delete:
ext4_clear_inode(inode); /* We must guarantee clearing of inode... */
-@@ -4681,7 +4712,7 @@ static int ext4_index_trans_blocks(struc
+@@ -4681,7 +4711,7 @@ static int ext4_index_trans_blocks(struc
*
* Also account for superblock, inode, quota and xattr blocks
*/
*
* Also account for superblock, inode, quota and xattr blocks
*/
{
struct ext4_xattr_entry *entry;
size_t name_len;
{
struct ext4_xattr_entry *entry;
size_t name_len;
-@@ -265,11 +273,104 @@ ext4_xattr_find_entry(struct ext4_xattr_
+@@ -265,11 +273,109 @@ ext4_xattr_find_entry(struct ext4_xattr_
break;
}
*pentry = entry;
break;
}
*pentry = entry;
+/*
+ * Read the EA value from an inode.
+ */
+/*
+ * Read the EA value from an inode.
+ */
-+static int
-+ext4_xattr_inode_read(struct inode *ea_inode, void *buf, size_t *size)
++static int ext4_xattr_inode_read(struct inode *ea_inode, void *buf, size_t *size)
+{
+ unsigned long block = 0;
+ struct buffer_head *bh = NULL;
+{
+ unsigned long block = 0;
+ struct buffer_head *bh = NULL;
-+struct inode *ext4_xattr_inode_iget(struct inode *parent, unsigned long ea_ino, int *err)
++/*
++ * Fetch the xattr inode from disk.
++ *
++ * The xattr inode stores the parent inode number and generation so that
++ * the kernel and e2fsck can verify the xattr inode is valid upon access.
++ */
++struct inode *ext4_xattr_inode_iget(struct inode *parent,
++ unsigned long ea_ino, int *err)
+{
+ struct inode *ea_inode = NULL;
+
+{
+ struct inode *ea_inode = 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);
+ ea_inode->i_generation != parent->i_generation) {
+ ext4_error(parent->i_sb, "Backpointer from EA inode %lu "
+ "to parent invalid.", ea_ino);
+/*
+ * Read the value from the EA inode.
+ */
+/*
+ * Read the value from the EA inode.
+ */
-+static int
-+ext4_xattr_inode_get(struct inode *inode, unsigned long ea_ino, void *buffer,
-+ size_t *size)
++static int ext4_xattr_inode_get(struct inode *inode, unsigned long ea_ino,
++ void *buffer, size_t *size)
+{
+ struct inode *ea_inode = NULL;
+ int err;
+{
+ struct inode *ea_inode = NULL;
+ int err;
+ * A back-pointer from EA inode to parent inode will be useful
+ * for e2fsck.
+ */
+ * 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);
+ }
+
+ unlock_new_inode(ea_inode);
+ }
+
bs->s.here = bs->s.first;
error = ext4_xattr_find_entry(&bs->s.here, i->name_index,
- i->name, bs->bh->b_size, 1);
bs->s.here = bs->s.first;
error = ext4_xattr_find_entry(&bs->s.here, i->name_index,
- i->name, bs->bh->b_size, 1);
-+ i->name, bs->bh->b_size, 1, inode);
++ i->name, bs->bh->b_size, 1, inode);
if (error && error != -ENODATA)
goto cleanup;
bs->s.not_found = error;
if (error && error != -ENODATA)
goto cleanup;
bs->s.not_found = error;
__le32 e_value_size; /* size of attribute value */
__le32 e_hash; /* hash value of name and value */
char e_name[0]; /* attribute name */
__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))
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
+
+/*
+ * The minimum size of EA value when you start storing it in an external inode
#define EXT4_MMP_MAX_CHECK_INTERVAL 300UL
/*
#define EXT4_MMP_MAX_CHECK_INTERVAL 300UL
/*
-+ * Maximum size of xattr attributes for FEATURE_INCOMPAT_EA_INODE 1Mb
++ * Maximum size of xattr attributes for FEATURE_INCOMPAT_EA_INODE 1MB
+ * This limit is arbitrary, but is reasonable for the xattr API.
+ */
+#define EXT4_XATTR_MAX_LARGE_EA_SIZE (1024 * 1024)
+ * This limit is arbitrary, but is reasonable for the xattr API.
+ */
+#define EXT4_XATTR_MAX_LARGE_EA_SIZE (1024 * 1024)
if (IS_ERR(handle)) {
ext4_std_error(inode->i_sb, PTR_ERR(handle));
/*
if (IS_ERR(handle)) {
ext4_std_error(inode->i_sb, PTR_ERR(handle));
/*
-@@ -248,9 +248,36 @@ void ext4_evict_inode(struct inode *inod
- sb_end_intwrite(inode->i_sb);
- goto no_delete;
- }
--
+@@ -251,6 +251,32 @@ void ext4_evict_inode(struct inode *inod
+
if (IS_SYNC(inode))
ext4_handle_sync(handle);
+
if (IS_SYNC(inode))
ext4_handle_sync(handle);
+
-+ /*
-+ * Delete xattr inode before deleting the main inode.
-+ */
++ /* Delete xattr inode before deleting the main inode. */
+ err = ext4_xattr_delete_inode(handle, inode, &lea_ino_array);
+ if (err) {
+ ext4_warning(inode->i_sb,
+ err = ext4_xattr_delete_inode(handle, inode, &lea_ino_array);
+ if (err) {
+ ext4_warning(inode->i_sb,
inode->i_size = 0;
err = ext4_mark_inode_dirty(handle, inode);
if (err) {
inode->i_size = 0;
err = ext4_mark_inode_dirty(handle, inode);
if (err) {
-@@ -305,8 +332,12 @@ void ext4_evict_inode(struct inode *inod
- ext4_clear_inode(inode);
- else
+@@ -307,6 +334,9 @@ void ext4_evict_inode(struct inode *inod
ext4_free_inode(handle, inode);
ext4_free_inode(handle, inode);
ext4_journal_stop(handle);
sb_end_intwrite(inode->i_sb);
+
ext4_journal_stop(handle);
sb_end_intwrite(inode->i_sb);
+
return;
no_delete:
ext4_clear_inode(inode); /* We must guarantee clearing of inode... */
return;
no_delete:
ext4_clear_inode(inode); /* We must guarantee clearing of inode... */
-@@ -4777,7 +4808,7 @@ static int ext4_index_trans_blocks(struc
+@@ -4777,7 +4807,7 @@ static int ext4_index_trans_blocks(struc
*
* Also account for superblock, inode, quota and xattr blocks
*/
*
* Also account for superblock, inode, quota and xattr blocks
*/
{
struct ext4_xattr_entry *entry;
size_t name_len;
{
struct ext4_xattr_entry *entry;
size_t name_len;
-@@ -265,11 +272,104 @@ ext4_xattr_find_entry(struct ext4_xattr_
+@@ -265,11 +272,109 @@ ext4_xattr_find_entry(struct ext4_xattr_
break;
}
*pentry = entry;
break;
}
*pentry = entry;
+/*
+ * Read the EA value from an inode.
+ */
+/*
+ * Read the EA value from an inode.
+ */
-+static int
-+ext4_xattr_inode_read(struct inode *ea_inode, void *buf, size_t *size)
++static int ext4_xattr_inode_read(struct inode *ea_inode, void *buf, size_t *size)
+{
+ unsigned long block = 0;
+ struct buffer_head *bh = NULL;
+{
+ unsigned long block = 0;
+ struct buffer_head *bh = NULL;
-+struct inode *ext4_xattr_inode_iget(struct inode *parent, unsigned long ea_ino, int *err)
++/*
++ * Fetch the xattr inode from disk.
++ *
++ * The xattr inode stores the parent inode number and generation so that
++ * the kernel and e2fsck can verify the xattr inode is valid upon access.
++ */
++struct inode *ext4_xattr_inode_iget(struct inode *parent,
++ unsigned long ea_ino, int *err)
+{
+ struct inode *ea_inode = NULL;
+
+{
+ struct inode *ea_inode = NULL;
+
+/*
+ * Read the value from the EA inode.
+ */
+/*
+ * Read the value from the EA inode.
+ */
-+static int
-+ext4_xattr_inode_get(struct inode *inode, unsigned long ea_ino, void *buffer,
-+ size_t *size)
++static int ext4_xattr_inode_get(struct inode *inode, unsigned long ea_ino,
++ void *buffer, size_t *size)
+{
+ struct inode *ea_inode = NULL;
+ int err;
+{
+ struct inode *ea_inode = NULL;
+ int err;
bs->s.here = bs->s.first;
error = ext4_xattr_find_entry(&bs->s.here, i->name_index,
- i->name, bs->bh->b_size, 1);
bs->s.here = bs->s.first;
error = ext4_xattr_find_entry(&bs->s.here, i->name_index,
- i->name, bs->bh->b_size, 1);
-+ i->name, bs->bh->b_size, 1, inode);
++ i->name, bs->bh->b_size, 1, inode);
if (error && error != -ENODATA)
goto cleanup;
bs->s.not_found = error;
if (error && error != -ENODATA)
goto cleanup;
bs->s.not_found = error;
+ * Extra integer type conversion added to ignore higher
+ * bits in i_mtime.tv_sec which might be set by ext4_get()
+ */
+ * 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; \
++#define EXT4_XATTR_INODE_SET_PARENT(inode, inum) \
++do { \
++ (inode)->i_mtime.tv_sec = inum; \
-+#define EXT4_XATTR_INODE_GET_PARENT(inode) \
-+((__u32)(inode)->i_mtime.tv_sec)
++#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
+
+/*
+ * The minimum size of EA value when you start storing it in an external inode