【问题标题】:touch timestamp accuracy on EXT4EXT4 上的触摸时间戳准确性
【发布时间】:2010-11-17 12:44:05
【问题描述】:

更新:原来我很愚蠢。当我应该检查访问时间时,我正在检查修改时间。无法重现的原因是测试文件是用dd if=/dev/urandom of="$target" bs='1K' count=1 || exit 1制作的,大部分时间太快了,以至于新文件的修改时间(dd结束)与访问时间(开始dd 的时间)。另一件需要注意的事情。

我正在编写一个脚本,将一个文件的访问时间加上两年时间应用于另一个文件。这使用stat -c %xdate --rfc-3339=nstouch -a --date="$result"statdate 都输出以纳秒为单位的日期字符串,比如

2012-11-17 10:22:15.390351800+01:00

info coreutils 'touch invocation' 表示它支持纳秒。但有时在应用触摸时,应用的时间戳与 stat 之后返回的时间戳之间存在微小差异。以下是实际运行的数据:

$ for i in {1..100}; do ./t_timecopy.sh 2>/dev/null| grep ASSERT; done
ASSERT:Expecting same access time expected:<2012-11-17 10:58:40.719320935+01:00> but was:<2012-11-17 10:58:40.723322203+01:00>
ASSERT:Expecting same access time expected:<2012-11-17 11:00:04.342346275+01:00> but was:<2012-11-17 11:00:04.346358718+01:00>
ASSERT:Expecting same access time expected:<2012-11-17 11:00:39.343348183+01:00> but was:<2012-11-17 11:00:39.347351686+01:00>
ASSERT:Expecting same access time expected:<2012-11-17 11:01:08.655348312+01:00> but was:<2012-11-17 11:01:08.659347625+01:00>
ASSERT:Expecting same access time expected:<2012-11-17 11:01:37.930346876+01:00> but was:<2012-11-17 11:01:37.934347311+01:00>
ASSERT:Expecting same access time expected:<2012-11-17 11:02:16.939319832+01:00> but was:<2012-11-17 11:02:16.943323061+01:00>
ASSERT:Expecting same access time expected:<2012-11-17 11:02:46.456443149+01:00> but was:<2012-11-17 11:02:46.458379114+01:00>
ASSERT:Expecting same access time expected:<2012-11-17 11:03:15.487339595+01:00> but was:<2012-11-17 11:03:15.491341426+01:00>
ASSERT:Expecting same access time expected:<2012-11-17 11:04:04.646335863+01:00> but was:<2012-11-17 11:04:04.650346634+01:00>
ASSERT:Expecting same access time expected:<2012-11-17 11:04:14.410326608+01:00> but was:<2012-11-17 11:04:14.414331233+01:00>
ASSERT:Expecting same access time expected:<2012-11-17 11:04:24.159367348+01:00> but was:<2012-11-17 11:04:24.163352418+01:00>
ASSERT:Expecting same access time expected:<2012-11-17 11:04:33.931387953+01:00> but was:<2012-11-17 11:04:33.935350115+01:00>
ASSERT:Expecting same access time expected:<2012-11-17 11:05:03.394361030+01:00> but was:<2012-11-17 11:05:03.398320957+01:00>
ASSERT:Expecting same access time expected:<2012-11-17 11:05:42.054317430+01:00> but was:<2012-11-17 11:05:42.059106497+01:00>
ASSERT:Expecting same access time expected:<2012-11-17 11:06:40.346320820+01:00> but was:<2012-11-17 11:06:40.350346956+01:00>
ASSERT:Expecting same access time expected:<2012-11-17 11:08:17.194346778+01:00> but was:<2012-11-17 11:08:17.198338832+01:00>
ASSERT:Expecting same access time expected:<2012-11-17 11:08:27.102347603+01:00> but was:<2012-11-17 11:08:27.106320380+01:00>
ASSERT:Expecting same access time expected:<2012-11-17 11:09:16.247322948+01:00> but was:<2012-11-17 11:09:16.251347966+01:00>
ASSERT:Expecting same access time expected:<2012-11-17 11:09:55.191325266+01:00> but was:<2012-11-17 11:09:55.195320672+01:00>
ASSERT:Expecting same access time expected:<2012-11-17 11:12:09.915318301+01:00> but was:<2012-11-17 11:12:09.919334099+01:00>
ASSERT:Expecting same access time expected:<2012-11-17 11:12:28.906346914+01:00> but was:<2012-11-17 11:12:28.910348186+01:00>

因此,100 次测试中有 21 次失败,平均为 3.938 毫秒,中位数为 4.001 毫秒。有什么想法会导致这种情况吗?

$ uname -a
Linux user 2.6.32-22-generic #33-Ubuntu SMP Wed Apr 28 13:27:30 UTC 2010 i686 GNU/Linux

【问题讨论】:

  • 如果您提供您正在使用的测试脚本的代码,这将对我们有所帮助。另外,您是否绝对确定在您执行此操作时没有任何内容读取(注意:atime)文件?
  • 这就解释了:-)。您还应该记住两件事: 1. 仅仅因为 FS 支持纳秒分辨率,并不意味着内核实际上使用这种分辨率对任何事情进行计时。 2. 时间是一件敏感的事情。您需要使用 strictatime 挂载选项显式打开它们,这将显着降低 FS(通常默认为 relatime)的性能。它们还容易受到任何可以访问您正在观看的文件的随机应用程序的攻击。

标签: linux ubuntu touch ext4


【解决方案1】:

我使用这群(诚然快速和肮脏的)oneliners 在我的系统上测试您的问题 - Mandriva Linux 2010.1 (x86-64):

seq 1 1000 | while read f; do sleep 0.01; touch test-$f-0; done

seq 1 1000 | while read f; do touch -a -d "$(stat -c %x test-$f-0 | sed 's|^2010|2012|')" test-$f-1; done

seq 1 1000 | while read f; do A="$(stat -c %x test-$f-0)"; B="$(stat -c %x test-$f-1)"; if [[ ! "${A#2010}" = "${B#2012}" ]]; then echo test-$f; fi; done

我什至一次都无法重现您的问题。听起来 touch 没有在 -d 参数处提供预期的时间戳,而是以其他方式计算的。

当然,问题可能是特定于系统的,在这种情况下,我们需要有关您系统的更多信息(CPU、操作系统是 32 位还是 64 位、内核/glibc/coreutils 版本等)。

更新:

我对 32 位版本的 stat 和 touch 进​​行了同样的尝试。没有出现任何问题。内核仍然是 64 位的。

更新2:

我也尝试了这组oneliners,更侧重于atime:

$ seq 1 1000 | while read f; do sleep 0.01; touch test-$f-0; done
$ seq 1 1000 | while read f; do sleep 0.01; touch test-$f-1; done
$ seq 1 1000 | while read f; do sleep 0.01; cat test-$f-0; done
$ seq 1 1000 | while read f; do touch -a -d "$(stat -c %x test-$f-0 | sed 's|^2010|2012|')" test-$f-1; done
$ seq 1 1000 | while read f; do A="$(stat -c %x test-$f-0)"; B="$(stat -c %x test-$f-1)"; if [[ ! "${A#2010}" = "${B#2012}" ]]; then echo test-$f; fi; done

再次没有检测到问题。我尝试使用 relatime 和 strictatime 挂载选项。

更新3:

我刚刚在我的 Mandriva i686 笔记本电脑上执行了上述测试。我似乎也没有纳秒精度的问题。我还在另一个 32 位系统上验证了如果不支持纳秒精度(例如在 ext3 上),则 stat 输出中的纳秒字段变为零。

【讨论】:

  • 即使文件系统计时,您的测试也不会捕捉到它,因为测试中唯一的时间来源是通过 stat(1) 获得的文件系统本身。
  • 根据 OP 想要“将一个文件的访问时间加上两年应用于另一个文件”的问题。他已经在使用 FS 作为参考。
  • @unbeli,OP 似乎遇到的问题是 touch -a -d "whenever" 并没有将 "whenever" 设置为文件的时间。 “无论何时”的时间从何而来实际上是无关紧要的。
  • 您使用的是 EXT4 吗?大多数文件系统仅以秒为单位保存时间戳,而不是纳秒。
  • @thkala,这是相关的。如果文件系统截断了时间,您无法通过提供已经截断的时间来检测它。来吧,让你的大脑运转起来!
【解决方案2】:

在 Windows 7 64 位上触摸会带来类似的问题。这是我的漏洞利用代码:

touch a && touch b && ls --full-time a b
touch -r a b && ls --full-time a b

还有输出:

-rw-rw-rw-  1 Jarek 0 0 2012-05-09 12:05:27.851839700 +0200 a
-rw-rw-rw-  1 Jarek 0 0 2012-05-09 12:05:27.874841000 +0200 b

-rw-rw-rw-  1 Jarek 0 0 2012-05-09 12:05:27.851839700 +0200 a
-rw-rw-rw-  1 Jarek 0 0 2012-05-09 12:05:27.851839000 +0200 b

lstouch 来自 gnuwin32。在前 2 个输出行中,时间戳差异为 20 毫秒。好的。但在第二次运行中,它们应该是相等的(ba 获得了印章)。没运气。有 0.7 us 的差异 :)。

svn status 看到了区别,因此很难用touch 来欺骗它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-22
    • 1970-01-01
    • 2017-05-27
    • 1970-01-01
    • 2022-01-16
    • 2012-09-01
    • 2014-12-18
    • 1970-01-01
    相关资源
    最近更新 更多