1 From aa507b5faf38784defe49f5e64605ac3c4425e26 Mon Sep 17 00:00:00 2001
2 From: yangerkun <yangerkun@huawei.com>
3 Date: Mon, 11 Feb 2019 00:14:02 -0500
4 Subject: ext4: update quota information while swapping boot loader inode
6 From: yangerkun <yangerkun@huawei.com>
8 commit aa507b5faf38784defe49f5e64605ac3c4425e26 upstream.
10 While do swap between two inode, they swap i_data without update
11 quota information. Also, swap_inode_boot_loader can do "revert"
12 somtimes, so update the quota while all operations has been finished.
14 Signed-off-by: yangerkun <yangerkun@huawei.com>
15 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
17 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
20 fs/ext4/ioctl.c | 56 +++++++++++++++++++++++++++++++++++++++++++-------------
21 1 file changed, 43 insertions(+), 13 deletions(-)
25 @@ -68,8 +68,6 @@ static void swap_inode_data(struct inode
28 swap(inode1->i_version, inode2->i_version);
29 - swap(inode1->i_blocks, inode2->i_blocks);
30 - swap(inode1->i_bytes, inode2->i_bytes);
31 swap(inode1->i_atime, inode2->i_atime);
32 swap(inode1->i_mtime, inode2->i_mtime);
34 @@ -115,6 +113,9 @@ static long swap_inode_boot_loader(struc
36 struct inode *inode_bl;
37 struct ext4_inode_info *ei_bl;
38 + qsize_t size, size_bl, diff;
40 + unsigned short bytes;
42 inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO, EXT4_IGET_SPECIAL);
44 @@ -180,6 +181,13 @@ static long swap_inode_boot_loader(struc
45 memset(ei_bl->i_data, 0, sizeof(ei_bl->i_data));
48 + err = dquot_initialize(inode);
52 + size = (qsize_t)(inode->i_blocks) * (1 << 9) + inode->i_bytes;
53 + size_bl = (qsize_t)(inode_bl->i_blocks) * (1 << 9) + inode_bl->i_bytes;
54 + diff = size - size_bl;
55 swap_inode_data(inode, inode_bl);
57 inode->i_ctime = inode_bl->i_ctime = current_time(inode);
58 @@ -193,24 +201,46 @@ static long swap_inode_boot_loader(struc
60 err = ext4_mark_inode_dirty(handle, inode);
62 + /* No need to update quota information. */
63 ext4_warning(inode->i_sb,
64 "couldn't mark inode #%lu dirty (err %d)",
66 /* Revert all changes: */
67 swap_inode_data(inode, inode_bl);
68 ext4_mark_inode_dirty(handle, inode);
70 - err = ext4_mark_inode_dirty(handle, inode_bl);
72 - ext4_warning(inode_bl->i_sb,
73 - "couldn't mark inode #%lu dirty (err %d)",
74 - inode_bl->i_ino, err);
75 - /* Revert all changes: */
76 - swap_inode_data(inode, inode_bl);
77 - ext4_mark_inode_dirty(handle, inode);
78 - ext4_mark_inode_dirty(handle, inode_bl);
83 + blocks = inode_bl->i_blocks;
84 + bytes = inode_bl->i_bytes;
85 + inode_bl->i_blocks = inode->i_blocks;
86 + inode_bl->i_bytes = inode->i_bytes;
87 + err = ext4_mark_inode_dirty(handle, inode_bl);
89 + /* No need to update quota information. */
90 + ext4_warning(inode_bl->i_sb,
91 + "couldn't mark inode #%lu dirty (err %d)",
92 + inode_bl->i_ino, err);
96 + /* Bootloader inode should not be counted into quota information. */
98 + dquot_free_space(inode, diff);
100 + err = dquot_alloc_space(inode, -1 * diff);
104 + /* Revert all changes: */
105 + inode_bl->i_blocks = blocks;
106 + inode_bl->i_bytes = bytes;
107 + swap_inode_data(inode, inode_bl);
108 + ext4_mark_inode_dirty(handle, inode);
109 + ext4_mark_inode_dirty(handle, inode_bl);
113 ext4_journal_stop(handle);
114 ext4_double_up_write_data_sem(inode, inode_bl);