]>
Commit | Line | Data |
---|---|---|
ec71c73b GKH |
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 | |
5 | ||
6 | From: yangerkun <yangerkun@huawei.com> | |
7 | ||
8 | commit aa507b5faf38784defe49f5e64605ac3c4425e26 upstream. | |
9 | ||
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. | |
13 | ||
14 | Signed-off-by: yangerkun <yangerkun@huawei.com> | |
15 | Signed-off-by: Theodore Ts'o <tytso@mit.edu> | |
16 | Cc: stable@kernel.org | |
17 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
18 | ||
19 | --- | |
20 | fs/ext4/ioctl.c | 56 +++++++++++++++++++++++++++++++++++++++++++------------- | |
21 | 1 file changed, 43 insertions(+), 13 deletions(-) | |
22 | ||
23 | --- a/fs/ext4/ioctl.c | |
24 | +++ b/fs/ext4/ioctl.c | |
25 | @@ -68,8 +68,6 @@ static void swap_inode_data(struct inode | |
26 | ei2 = EXT4_I(inode2); | |
27 | ||
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); | |
33 | ||
34 | @@ -115,6 +113,9 @@ static long swap_inode_boot_loader(struc | |
35 | int err; | |
36 | struct inode *inode_bl; | |
37 | struct ext4_inode_info *ei_bl; | |
38 | + qsize_t size, size_bl, diff; | |
39 | + blkcnt_t blocks; | |
40 | + unsigned short bytes; | |
41 | ||
42 | inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO, EXT4_IGET_SPECIAL); | |
43 | if (IS_ERR(inode_bl)) | |
44 | @@ -180,6 +181,13 @@ static long swap_inode_boot_loader(struc | |
45 | memset(ei_bl->i_data, 0, sizeof(ei_bl->i_data)); | |
46 | } | |
47 | ||
48 | + err = dquot_initialize(inode); | |
49 | + if (err) | |
50 | + goto err_out1; | |
51 | + | |
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); | |
56 | ||
57 | inode->i_ctime = inode_bl->i_ctime = current_time(inode); | |
58 | @@ -193,24 +201,46 @@ static long swap_inode_boot_loader(struc | |
59 | ||
60 | err = ext4_mark_inode_dirty(handle, inode); | |
61 | if (err < 0) { | |
62 | + /* No need to update quota information. */ | |
63 | ext4_warning(inode->i_sb, | |
64 | "couldn't mark inode #%lu dirty (err %d)", | |
65 | inode->i_ino, err); | |
66 | /* Revert all changes: */ | |
67 | swap_inode_data(inode, inode_bl); | |
68 | ext4_mark_inode_dirty(handle, inode); | |
69 | - } else { | |
70 | - err = ext4_mark_inode_dirty(handle, inode_bl); | |
71 | - if (err < 0) { | |
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); | |
79 | - } | |
80 | + goto err_out1; | |
81 | + } | |
82 | + | |
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); | |
88 | + if (err < 0) { | |
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); | |
93 | + goto revert; | |
94 | + } | |
95 | + | |
96 | + /* Bootloader inode should not be counted into quota information. */ | |
97 | + if (diff > 0) | |
98 | + dquot_free_space(inode, diff); | |
99 | + else | |
100 | + err = dquot_alloc_space(inode, -1 * diff); | |
101 | + | |
102 | + if (err < 0) { | |
103 | +revert: | |
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); | |
110 | } | |
111 | + | |
112 | +err_out1: | |
113 | ext4_journal_stop(handle); | |
114 | ext4_double_up_write_data_sem(inode, inode_bl); | |
115 |