Add stable@vger.kernel.org annotations
[ext4-patch-queue.git] / reinforce-check-of-i_dtime-when-clearing-high-uid-gid-fields
blobf0563f71e2e4dccd06b18aa681054888680a1c6c
1 ext4: reinforce check of i_dtime when clearing high fields of uid and gid
3 From: Daeho Jeong <daeho.jeong@samsung.com>
5 Now, ext4_do_update_inode() clears high 16-bit fields of uid/gid
6 of deleted and evicted inode to fix up interoperability with old
7 kernels. However, it checks only i_dtime of an inode to determine
8 whether the inode was deleted and evicted, and this is very risky,
9 because i_dtime can be used for the pointer maintaining orphan inode
10 list, too. We need to further check whether the i_dtime is being
11 used for the orphan inode list even if the i_dtime is not NULL.
13 We found that high 16-bit fields of uid/gid of inode are unintentionally
14 and permanently cleared when the inode truncation is just triggered,
15 but not finished, and the inode metadata, whose high uid/gid bits are
16 cleared, is written on disk, and the sudden power-off follows that
17 in order.
19 Cc: stable@vger.kernel.org
20 Signed-off-by: Daeho Jeong <daeho.jeong@samsung.com>
21 Signed-off-by: Hobin Woo <hobin.woo@samsung.com>
22 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
23 ---
24  fs/ext4/inode.c |    8 ++++----
25  1 file changed, 4 insertions(+), 4 deletions(-)
27 diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
28 index f7140ca..bb5aede 100644
29 --- a/fs/ext4/inode.c
30 +++ b/fs/ext4/inode.c
31 @@ -4785,14 +4785,14 @@ static int ext4_do_update_inode(handle_t *handle,
32   * Fix up interoperability with old kernels. Otherwise, old inodes get
33   * re-used with the upper 16 bits of the uid/gid intact
34   */
35 -               if (!ei->i_dtime) {
36 +               if (ei->i_dtime && list_empty(&ei->i_orphan)) {
37 +                       raw_inode->i_uid_high = 0;
38 +                       raw_inode->i_gid_high = 0;
39 +               } else {
40                         raw_inode->i_uid_high =
41                                 cpu_to_le16(high_16_bits(i_uid));
42                         raw_inode->i_gid_high =
43                                 cpu_to_le16(high_16_bits(i_gid));
44 -               } else {
45 -                       raw_inode->i_uid_high = 0;
46 -                       raw_inode->i_gid_high = 0;
47                 }
48         } else {
49                 raw_inode->i_uid_low = cpu_to_le16(fs_high2lowuid(i_uid));
50 -- 
51 1.7.9.5