|
@@ -67,7 +67,6 @@ static void swap_inode_data(struct inode *inode1, struct inode *inode2)
|
|
|
ei1 = EXT4_I(inode1);
|
|
|
ei2 = EXT4_I(inode2);
|
|
|
|
|
|
- swap(inode1->i_flags, inode2->i_flags);
|
|
|
swap(inode1->i_version, inode2->i_version);
|
|
|
swap(inode1->i_blocks, inode2->i_blocks);
|
|
|
swap(inode1->i_bytes, inode2->i_bytes);
|
|
@@ -85,6 +84,21 @@ static void swap_inode_data(struct inode *inode1, struct inode *inode2)
|
|
|
i_size_write(inode2, isize);
|
|
|
}
|
|
|
|
|
|
+static void reset_inode_seed(struct inode *inode)
|
|
|
+{
|
|
|
+ struct ext4_inode_info *ei = EXT4_I(inode);
|
|
|
+ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
|
|
|
+ __le32 inum = cpu_to_le32(inode->i_ino);
|
|
|
+ __le32 gen = cpu_to_le32(inode->i_generation);
|
|
|
+ __u32 csum;
|
|
|
+
|
|
|
+ if (!ext4_has_metadata_csum(inode->i_sb))
|
|
|
+ return;
|
|
|
+
|
|
|
+ csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&inum, sizeof(inum));
|
|
|
+ ei->i_csum_seed = ext4_chksum(sbi, csum, (__u8 *)&gen, sizeof(gen));
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* Swap the information from the given @inode and the inode
|
|
|
* EXT4_BOOT_LOADER_INO. It will basically swap i_data and all other
|
|
@@ -102,10 +116,13 @@ static long swap_inode_boot_loader(struct super_block *sb,
|
|
|
struct inode *inode_bl;
|
|
|
struct ext4_inode_info *ei_bl;
|
|
|
|
|
|
- if (inode->i_nlink != 1 || !S_ISREG(inode->i_mode))
|
|
|
+ if (inode->i_nlink != 1 || !S_ISREG(inode->i_mode) ||
|
|
|
+ IS_SWAPFILE(inode) || IS_ENCRYPTED(inode) ||
|
|
|
+ ext4_has_inline_data(inode))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- if (!inode_owner_or_capable(inode) || !capable(CAP_SYS_ADMIN))
|
|
|
+ if (IS_RDONLY(inode) || IS_APPEND(inode) || IS_IMMUTABLE(inode) ||
|
|
|
+ !inode_owner_or_capable(inode) || !capable(CAP_SYS_ADMIN))
|
|
|
return -EPERM;
|
|
|
|
|
|
inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO);
|
|
@@ -120,13 +137,13 @@ static long swap_inode_boot_loader(struct super_block *sb,
|
|
|
* that only 1 swap_inode_boot_loader is running. */
|
|
|
lock_two_nondirectories(inode, inode_bl);
|
|
|
|
|
|
- truncate_inode_pages(&inode->i_data, 0);
|
|
|
- truncate_inode_pages(&inode_bl->i_data, 0);
|
|
|
-
|
|
|
/* Wait for all existing dio workers */
|
|
|
inode_dio_wait(inode);
|
|
|
inode_dio_wait(inode_bl);
|
|
|
|
|
|
+ truncate_inode_pages(&inode->i_data, 0);
|
|
|
+ truncate_inode_pages(&inode_bl->i_data, 0);
|
|
|
+
|
|
|
handle = ext4_journal_start(inode_bl, EXT4_HT_MOVE_EXTENTS, 2);
|
|
|
if (IS_ERR(handle)) {
|
|
|
err = -EINVAL;
|
|
@@ -159,6 +176,8 @@ static long swap_inode_boot_loader(struct super_block *sb,
|
|
|
|
|
|
inode->i_generation = prandom_u32();
|
|
|
inode_bl->i_generation = prandom_u32();
|
|
|
+ reset_inode_seed(inode);
|
|
|
+ reset_inode_seed(inode_bl);
|
|
|
|
|
|
ext4_discard_preallocations(inode);
|
|
|
|
|
@@ -169,6 +188,7 @@ static long swap_inode_boot_loader(struct super_block *sb,
|
|
|
inode->i_ino, err);
|
|
|
/* Revert all changes: */
|
|
|
swap_inode_data(inode, inode_bl);
|
|
|
+ ext4_mark_inode_dirty(handle, inode);
|
|
|
} else {
|
|
|
err = ext4_mark_inode_dirty(handle, inode_bl);
|
|
|
if (err < 0) {
|
|
@@ -178,6 +198,7 @@ static long swap_inode_boot_loader(struct super_block *sb,
|
|
|
/* Revert all changes: */
|
|
|
swap_inode_data(inode, inode_bl);
|
|
|
ext4_mark_inode_dirty(handle, inode);
|
|
|
+ ext4_mark_inode_dirty(handle, inode_bl);
|
|
|
}
|
|
|
}
|
|
|
ext4_journal_stop(handle);
|