Distribution: Gentoo Hardware Environment: 64 bit machine Problem Description: A user at gentoo buzilla(1) reported that some files that he change the date to 1 Jan 1970 for archiving purposes, after umount and re-mounting the partition, the files would have the date changed to 7 Feb 2106. On the report, he only test this on ext3 filesystem but i also reproduce it in ext2 filesystems. If any mor info is needed just ask. Steps to reproduce: 1. Compile and install a kernel with ext2/3 support 2. mount <ext2/3_partition> 3. cd <ext2/3_partition> 4. touch -d 01/01/1907 test_file 5. cd .. 6. umount <ext2/3_partition> 7. mount <ext2/3_partition> 8. ls -l <ext2/3_partition>/test_file The file will report 7 Feb 2106. (1) http://bugs.gentoo.org/show_bug.cgi?id=101723
This was also confirmed in plain vanilla kernel 2.6.13-rc6.
btw, forgot to mention that this was only reproduced on 64bit machines (intel and amd) and that this bug doesn't happen on reiserfs nor xfs, just ext2/3. Also this is not new to the 2.6.13 kernel since it is reproducible on 2.6.12 kernel's.
Downstream bug report: http://bugs.gentoo.org/show_bug.cgi?id=101723
I cannot reproduce this with 2.6.16-rc1. I tried setting localtime to Japan too. Can you guys please retest? If it still happens, then we need to work out what's different between your setups and mine. Also, use /usr/bin/stat to read the inode timestamps - that'll help us separate kernel problems from userspace ones.
I am now on x86_64 and interestingly enough I was looking into this just a little earlier. I can reproduce the bug on my x86_64 but *not* on my x86. Note that the partition must be remounted before the "future" date appears. I didn't get much time to work on this, but I ended up confusing myself how it can possibly work on x86. In ext2_update_inode(), the inode->i_mtime.tv_sec value seems to be represented as 64 bits, but the raw_inode->i_mtime as 32. The inode value was reading something like 0xffffff831212 (made up number, it was similar to that though: first 32 bits as ff), and the raw_inode value was being truncated to 0x831212. You can probably discount these results as they were quite rushed. However I can definately confirm the bug, and I'll come up with a detailed description of the problem (and maybe even fix it :) when I next have some time (maybe this weekend).
Found the numbers I was testing with in my logs. When inode->i_mtime.tv_sec read 0xffffffff89808d00, 0x89808d00 was being written into raw_inode->i_mtime.
Ok I just gave it some thought and the bug is obvious. The function I've been talking about is ext2_update_inode() by the way, which deals with copying values from an inode struct (inode) to an ext2_inode struct (raw_inode). inode->i_mtime.tv_sec is a time_t which is a "long" for both x86 and x86_64. On x86 this is 32 bits and on x86_64 it is 64 bits. raw_inode->i_mtime is __le32. This explains why it works on x86: cpu_to_le32() on a 32 bit value isn't gonna hurt it However, cpu_to_le32() on a 64 bit signed number (apparently) doesn't consider its numerical value (in this case, negative, since we are talking about dates before the epoch), it just chops off the upper bits which it doesn't care about.
Yes, something like that. Or the bug's in ext2_read_inode(): sign-extending a 32-bit field to 64. But how are you setting an inode's time to before-epoch anyway? If I try that, /bin/date complains.
Using touch: touch -d 01/01/1907 somefile
oh, I thought 1907 was a typo in the bug report. ext2 and ext3 cannot represent dates prior to epoch, and FC1's `touch' command refuses to let you try. But a newer version of `date' _does_ permit it. As one would expect, a negative time like this will turn into a large positive time after it's been written to a 32-bit inode field and read back. I guess the filesystem should be returning error on this, but it cannot distinguish a negative time from a large positive one. That being said, 2106 is the wrong year. Setting the time to epoch-63 years _should_ result in epoch+73, but that's 2043. I think the 2106 is epoch+0xffffffff, which is odd.
Oh, it probably was a typo, as the description talks about 1 Jan 1970. I'll retest for 1970 later, since that shouldn't suffer from this weird pre-epoch crazyness, right?
With the advent of large inodes, we gain the ability to have more space for the inode timestamps. This has repeatedly been considered only for adding nanosecond timestamps (consuming 30 bits per), but little consideration has been given to also increasing the maximum values using some of those bits. I also thought that unix timestamps are considered signed values, which is why there is a unix "y2k" problem in 2038 (68 years = 2^31 seconds), so in theory negative timestamps should get us to 1902 or so. Whether we care about the signedness for ext3 files is a completely different issue.
Has anyone looked into this problem? I am interested in the timestamp bug. Where in the kernel source should I look into to fix the bug? Are there documents about ext3 filesystem for developers?
Created attachment 10317 [details] signed/unsigned inode fix
The previous attachment is an approach to fix the date problem. I tested this fix on an amd64 machine: unsigned long ranges from -2.147.483.648 2.147.483.647 10000011110110100100111110111101 .. -2.082.844.739 10000011110110100100111110111101 .. 2.212.122.557 <- this would be stored in long(64bit) which overflows the 32bit range/date
errata: signed long ranges from -2.147.483.648 to 2.147.483.647 on x86 32bit 10000011110110100100111110111101 .. -2.082.844.739 10000011110110100100111110111101 .. 2.212.122.557 <- this currently gets stored on the disk but when converting it to a 64bit signed long value it loses its sign and becomes positive.
merged Markus's fix into -mm.
Btw: after time val becomes interpreted as signed value we have to make according changes in e2fsprogs.
*** Bug 8643 has been marked as a duplicate of this bug. ***
Committed into mainline as commit: 4d7bf11d649c72621ca31b8ea12b9c94af380e63