1 ext4: update quota information while swapping boot loader inode
3 From: yangerkun <yangerkun@huawei.com>
5 While do swap between two inode, they swap i_data without update
6 quota information. Also, swap_inode_boot_loader can do "revert"
7 somtimes, so update the quota while all operations has been finished.
9 Signed-off-by: yangerkun <yangerkun@huawei.com>
10 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
13 fs/ext4/ioctl.c | 56 +++++++++++++++++++++++++++++++++++++++++++-------------
14 1 file changed, 43 insertions(+), 13 deletions(-)
16 diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
17 index ea05e8d..eff6835 100644
20 @@ -68,8 +68,6 @@ static void swap_inode_data(struct inode *inode1, struct inode *inode2)
23 swap(inode1->i_version, inode2->i_version);
24 - swap(inode1->i_blocks, inode2->i_blocks);
25 - swap(inode1->i_bytes, inode2->i_bytes);
26 swap(inode1->i_atime, inode2->i_atime);
27 swap(inode1->i_mtime, inode2->i_mtime);
29 @@ -115,6 +113,9 @@ static long swap_inode_boot_loader(struct super_block *sb,
31 struct inode *inode_bl;
32 struct ext4_inode_info *ei_bl;
33 + qsize_t size, size_bl, diff;
35 + unsigned short bytes;
37 inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO, EXT4_IGET_SPECIAL);
39 @@ -180,6 +181,13 @@ static long swap_inode_boot_loader(struct super_block *sb,
40 memset(ei_bl->i_data, 0, sizeof(ei_bl->i_data));
43 + err = dquot_initialize(inode);
47 + size = (qsize_t)(inode->i_blocks) * (1 << 9) + inode->i_bytes;
48 + size_bl = (qsize_t)(inode_bl->i_blocks) * (1 << 9) + inode_bl->i_bytes;
49 + diff = size - size_bl;
50 swap_inode_data(inode, inode_bl);
52 inode->i_ctime = inode_bl->i_ctime = current_time(inode);
53 @@ -193,24 +201,46 @@ static long swap_inode_boot_loader(struct super_block *sb,
55 err = ext4_mark_inode_dirty(handle, inode);
57 + /* No need to update quota information. */
58 ext4_warning(inode->i_sb,
59 "couldn't mark inode #%lu dirty (err %d)",
61 /* Revert all changes: */
62 swap_inode_data(inode, inode_bl);
63 ext4_mark_inode_dirty(handle, inode);
65 - err = ext4_mark_inode_dirty(handle, inode_bl);
67 - ext4_warning(inode_bl->i_sb,
68 - "couldn't mark inode #%lu dirty (err %d)",
69 - inode_bl->i_ino, err);
70 - /* Revert all changes: */
71 - swap_inode_data(inode, inode_bl);
72 - ext4_mark_inode_dirty(handle, inode);
73 - ext4_mark_inode_dirty(handle, inode_bl);
78 + blocks = inode_bl->i_blocks;
79 + bytes = inode_bl->i_bytes;
80 + inode_bl->i_blocks = inode->i_blocks;
81 + inode_bl->i_bytes = inode->i_bytes;
82 + err = ext4_mark_inode_dirty(handle, inode_bl);
84 + /* No need to update quota information. */
85 + ext4_warning(inode_bl->i_sb,
86 + "couldn't mark inode #%lu dirty (err %d)",
87 + inode_bl->i_ino, err);
91 + /* Bootloader inode should not be counted into quota information. */
93 + dquot_free_space(inode, diff);
95 + err = dquot_alloc_space(inode, -1 * diff);
99 + /* Revert all changes: */
100 + inode_bl->i_blocks = blocks;
101 + inode_bl->i_bytes = bytes;
102 + swap_inode_data(inode, inode_bl);
103 + ext4_mark_inode_dirty(handle, inode);
104 + ext4_mark_inode_dirty(handle, inode_bl);
108 ext4_journal_stop(handle);
109 ext4_double_up_write_data_sem(inode, inode_bl);