为什么在读取文件时会翻转位置异常一致的位?

Laz*_*ble 6 memory windows-7 64-bit file-corruption

我正在尝试追踪在 Win7x64 中读取时发生的数据损坏问题,但我对接下来要尝试的方法一无所知。

这最初是在将大约 2TB 的数据迁移到新的家庭 NAS 时出现的;当我验证副本时,一小部分文件已损坏。那是在 12 月,从那以后我一直在追查这个问题。

每个“损坏”是在受影响文件的一个或多个位置中从 0 到 1 或从 1 到 0 翻转的单个位。当多个文件在一次“运行”中受到影响时,翻转的方向在每种情况下都是相同的。

它似乎不是 RAM 问题;我的系统不支持 ECC RAM,但我执行了多次内存测试,没有发现任何错误。该系统还可以连续运行数周而没有重新启动或任何意外崩溃(警告,因为我希望Firefox 会定期崩溃)但我有意避免任何涉及移动大量数据的事情,直到我能解决这个问题。没有 CD 翻录、视频转码等。

我见过的每一种情况下,翻转位都是 16 字节数据块的第七字节中的低位。在我见过的大多数情况下(如果不是全部),带有翻转位字节块的字节位于偏移量 …2x7 或 …5X7 处。大约一个月后,我才开始真正努力地跟踪该级别的问题。

以下是来自具有 121 位翻转的多 GB 视频文件的前几个示例:

                                     vv
000A46B2D0  1:  d2 04 29 dc d9 bf 15 01 f9 34 50 b6 08 11 63 d4
            2:  d2 04 29 dc d9 bf 15 00 f9 34 50 b6 08 11 63 d4
000EC6B2D0  1:  32 51 26 4f ae a0 42 29 93 5d 64 43 a6 e2 ee ba
            2:  32 51 26 4f ae a0 42 28 93 5d 64 43 a6 e2 ee ba
000F46B2D0  1:  e8 67 bd 18 08 00 62 59 21 37 94 00 d0 34 67 cf
            2:  e8 67 bd 18 08 00 62 58 21 37 94 00 d0 34 67 cf
0018C6B2D0  1:  b3 6e 0b 97 4e 7d 77 ab f9 74 38 6a 30 ee 9c 44
            2:  b3 6e 0b 97 4e 7d 77 aa f9 74 38 6a 30 ee 9c 44
001F46B2D0  1:  7e 87 0a c3 17 50 7c 55 39 b9 95 20 b8 6d 75 1a
            2:  7e 87 0a c3 17 50 7c 54 39 b9 95 20 b8 6d 75 1a
                                     ^^
Run Code Online (Sandbox Code Playgroud)

左边的十位十六进制值是被比较的两个文件中的字节位置,十六进制对是文件中从该位置开始的十六个字节。请注意每个十六进制对列的第八个字节中的值差异。相关性也发生在更高的水平上;请注意,每个 16 字节行的第一个字节位于以 46B2D0 或 C6B2D0 结尾的偏移量处。对于这个特定文件中的所有 121 个错误都是如此。

虽然这个问题首先在大文件复制期间出现,但我不认为它本身是“复制”问题,而是在读取文件时发生了一些事情,因为我实际上不必写回数据来查看问题:

  • 在比较两个已知相同的文件集时,第一次检查通过将返回错误,但在重新检查显示问题的特定文件时,它们将测试相同。
  • 在一种情况下,我进行了比较,其中位翻转发生在已知相同对的 SOURCE 文件中,并使用不同的工具多次重新读取同一文件(Beyond Compare、md5sum、我自己的字节级文件比较脚本给出了上面的输出)给出了相同的结果,但在重新启动后,文件位比较再次相同。根据这个结果,我假设所有重新读取都从缓存中提取相同的坏数据。

它似乎也没有绑定到特定的存储介质或我用来复制文件或之后比较它们的应用程序:

  • 我已经在所有可能的组合和方向上看到了文件复制只读比较的行为,涉及消费者 NAS、一个 USB3 连接的备份驱动器和两个不同的内部旋转盘驱动器。(所有文件系统都是 NTFS。)
  • 我在 Windows 资源管理器、Robocopy、Beyond Compare 和 Teracopy(后者在验证阶段报告校验和不匹配)中验证使用拖放制作的副本时,使用包括 Beyond Compare(十六进制视图)的比较工具时看到了这种行为),我自己的字节级比较脚本,以及与之前生成的 md5sum 值的比较。

我试图确定它是否与系统上任何特定进程的存在有关,但考虑到每次比较传递需要多长时间以及错误的罕见程度,这很困难。话虽如此,至少有一次我遇到了很多比较错误,我杀死了一个消耗大量内存的进程(CrashPlan 备份服务,这是一种疯狂的资源浪费),然后其余的比较通过没有错误。不过,无论该特定服务是否正在运行,我都能够重现该问题。

(从这个问题的这一点开始,事情变得更加棘手,因为我不太了解土地的位置。)

由于这看起来可能与 Windows 文件缓存有关,因此我使用 Sysinternals CacheSet 检查了使用情况。当我看到该问题时,典型值为 ~1Gb 的当前缓存大小和 1.5-1.7 GB 的峰值缓存大小。这对于 8GB 系统来说似乎是合理的;我运行了很多 RAM 贪婪的进程,但系统从来没有感到特别受内存限制。但是,工作集范围显示为 1MB - 1TB(!!),这绝对是不合理的。(我还使用 CacheSet 实验性地将最大工作集大小设置为 1Gb,但该设置在重新启动后无法生存——不确定这是否符合预期。)

在上面提到的缓存中存在明显的错误读取期间,我还使用了 CacheSet 来清除缓存工作集,但随后对“错误”文件的读取仍然显示问题,直到我重新启动。

读取错误时工作集的大小似乎无关紧要。虽然我最近才开始检查,但 Sysinternals RamMap 在发生时显示 Metafile Active/Total 值低至 200MB/250MB,远低于最大值。

可能此问题中看到的行为相同,假设 Windows 显示损坏的 XMP 日期字段的当前日期。

我认为这涵盖了到目前为止我对这个问题的了解。

Laz*_*ble 2

@Bob:看起来这绝对是一个坏内存条,尽管用 memtest86+ 进行了近 20 次传递来证明这一点。经验教训:1)在深入研究软件/配置兔子洞之前验证所有硬件,2)永远不要相信内置的自测试。感谢大家的帮助。