磁盘扇区写入是原子操作吗?

73

澄清的问题:

当操作系统向磁盘发送写扇区的指令时,是否具有原子性?即在写入新数据时,如果立即断电,旧数据是否会完好无损,不关心多个扇区写入的情况 - 损坏的页面是可以接受的。

旧问题:

假设你在磁盘上有旧数据X,你用新数据Y覆盖它,在写入过程中,树木倒在了电线上。如果没有高级UPS或带电池的磁盘控制器,你可能会得到一个损毁的页面,其中磁盘上的数据部分是X,部分是Y。您是否曾经遇到过磁盘上的数据是X、Y和垃圾的混合物的情况?

我一直在努力理解像数据库这样的ACID系统的设计,对我来说,似乎火鸟(Firebird)并没有使用预写日志,而是依赖于给定的写操作不会破坏旧数据(X),只是未能完整地写入新数据(Y)。这意味着,如果正在覆盖X的一部分内容,那么只有被覆盖的部分的X才能被更改,而不能更改我们打算保留的X的部分。

澄清一下,这意味着如果您有一个页面大小的缓冲区,例如4096字节,其中一半是我们要保留的Y,另一半是X - 我们告诉操作系统将该缓冲区写入X时,除了磁盘严重损坏的情况外,我们要保留的那一半X不会在写入过程中被破坏。


我认为最糟糕的事情是头部因为树木撞击而微微颤动,导致头部向脆弱的陶瓷盘滑去,使其粉碎成无数碎片。这种情况以前发生过。 - BlueRaja - Danny Pflughoeft
是的,那将是非常糟糕的。这大概就是为什么你需要备份、镜像,甚至是复制。但这并不是软件,比如数据库,可以拯救你的东西。 - Eloff
你会遇到这样一种情况,即硬盘上的数据分为X部分、Y部分和垃圾部分吗?” — 在HDD的扇区级别上,答案是否定的。ECC保护每个扇区的完整性。重新计算的ECC必须与新的扇区数据一起写入,因此,如果扇区写入未能完成,则垃圾扇区数据与现有/旧ECC匹配的概率应该是非常小的,不必担心。 - sawdust
9个回答

72
传统(SCSI,ATA)磁盘协议规范不能保证在突然断电的情况下每个扇区的写入都是原子操作(但请参见下文关于NVMe规范的讨论)。然而,似乎默许地认为非古老的“真实”磁盘会尽力提供这种行为(例如,Linux内核开发者Christoph Hellwig在2017年的演示“Failure-Atomic file updates for Linux”中顺便提到了这一点)。

当涉及到合成磁盘(例如网络附加块设备、某些类型的RAID等)时,情况就不太清楚了,它们可能会或者可能不会在法律规定的规范下提供扇区原子性保证。想象一个RAID 1阵列(没有日志),由一个提供512字节大小扇区的磁盘和一个提供4KiB大小扇区的磁盘组成,从而强制RAID公开4KiB扇区大小。作为一种思想实验,你可以构建一个场景,其中每个单独的磁盘都提供了扇区原子性(相对于自己的扇区大小),但是在断电面前,RAID设备却没有提供这样的保证。这是因为它取决于RAID正在读取的是否是512字节扇区磁盘,并且在断电之前已经写入了多少个组成4KiB RAID扇区的8个512字节扇区。

有时规范只对特定的写命令提供原子性保证。SCSI磁盘规范就是一个例子,可选的WRITE ATOMIC(16)命令甚至可以在扇区以外提供保证,但是由于是可选的,很少被实现(因此很少被使用)。更常见的COMPARE AND WRITE命令也是原子性的(可能跨多个扇区),但对于SCSI设备来说也是可选的,并且具有与普通写入不同的语义...

有趣的是,由于Linux内核开发者Matthew Wilcox的贡献,NVMe规范被写得如此,以确保扇区原子性。符合该规范的设备必须提供扇区写入原子性的保证,并可以选择提供连续多扇区原子性,直到指定的限制(参见AWUPF字段)。然而,如果您目前无法发送原始的NVMe命令,那么如何发现和使用任何多扇区保证尚不清楚...

Andy Rudoff是一位工程师,他谈论了他在写原子性方面所做的调查。他的演讲“保护软件免受自身影响:块写入的断电原子性”(幻灯片)中有一个部分是视频,在其中他谈到了断电对传统存储中正在进行的写入的影响。他描述了他如何联系硬盘制造商询问关于“磁盘的旋转能量用于确保在断电情况下完成写入}”这一说法,但回复都不明确是否该制造商实际上执行了这样的操作。此外,没有任何制造商会说撕裂写入从不发生,而当他在Sun公司时,ZFS在测试过程中添加了块校验和,从而揭示了撕裂写入的情况。然而,并非一切都黯淡无光-Andy谈到了扇区撕裂很少见,如果写入被中断,通常只会得到旧扇区、新扇区或错误(至少损坏不是无声的)。Andy还有一份较早的{{link4:幻灯片集 写原子性和NVM驱动器设计,其中收集了流行的声明,并警告说很多软件(包括多个操作系统上的各种流行文件系统)实际上在不知情的情况下依赖于扇区写入的原子性...
(以下以Linux为中心视角,但其中许多概念适用于不在严格受控硬件环境中部署的通用操作系统)
回到2013年,BtrFS的首席开发人员Chris Mason谈到了(现已关闭的)Fusion-io是如何创建了一个实现原子操作的存储产品(当时Chris正在为Fusion-io工作)。Fusion-io还创建了一个专有文件系统"DirectFS"(由Chris编写),以公开这个特性。MariaDB开发人员实现了一种模式,可以利用这种行为,不再进行双缓冲,从而使事务每秒增加了"43%,存储设备的磨损减少了一半"。Chris提出了一个补丁,使通用文件系统(如BtrFS)能够通过新的标志O_ATOMIC来宣传它们提供的原子性保证,但是块层面的更改也是必需的。Chris在后来的一系列补丁中还提出了块层面的更改,添加了一个函数blk_queue_set_atomic_write()。然而,这两个补丁系列都没有进入主线Linux内核,(截至2020年)主线5.7 Linux内核中没有O_ATOMIC标志
在我们进一步讨论之前,值得注意的是,即使较低级别不提供原子性保证,较高级别仍然可以为其用户提供原子性(尽管会带来性能开销),只要它知道何时写入已达到稳定存储。如果`fsync()`可以告诉您写入是否在稳定存储上(在技术上POSIX没有保证,但在现代Linux上是这样的情况),那么因为POSIX重命名是原子的,您可以使用创建新文件/ fsync /重命名操作来进行原子文件更新,从而允许应用程序自行执行双缓冲/预写式日志记录。堆栈中较低层次的另一个示例是Copy On Write文件系统,如BtrFS和ZFS。这些文件系统通过其语义为用户空间程序提供了“所有旧数据”或“所有新数据”的保证,即使磁盘可能不提供原子写入。您甚至可以将这个想法推广到磁盘本身,其中NAND基于SSD不会覆盖现有LBA当前使用的区域,而是将数据写入新区域并保留映射以指示LBA数据的当前位置。
继续我们的简化时间线,在2015年,惠普的研究人员撰写了一篇论文《在Linux文件系统中实现应用数据的故障原子更新》(PDF)(media),介绍了将一个新功能引入AdvFS的Linux端(AdvFS最初是DEC的Tru64的一部分):

如果使用新的O_ATOMIC标志打开文件,则其应用数据的状态将始终反映最近成功的msync、fsync或fdatasync操作。此外,AdvFS还包括一个新的syncv操作,将多个文件的更新合并为一个故障原子束[...]

2017年,Christoph Hellwig撰写了实验性的XFS补丁,以提供O_ATOMIC功能。在"Linux中的故障原子文件更新"演讲幻灯片)中,他解释了自己如何从2015年的论文中获得灵感(但没有多文件支持),并且该补丁集扩展了已经存在的XFS reflink工作。然而,尽管有最初的邮件列表帖子,但截至撰写本文时(2020年中),这个补丁集尚未进入主线内核。

在2019年Linux Plumbers Conference的数据库讨论中,MySQL开发者Dimitri Kravtchuk问是否有计划支持O_ATOMIC(链接指向录制讨论的开始)。与会人员提到了上面的XFS工作,Intel声称他们可以在Optane上实现原子性,但Linux没有提供公开接口来使用,Google声称在GCE存储上提供16KiB的原子性1。另一个关键点是许多数据库开发人员需要比4KiB更大的原子性以避免进行双重写入-PostgreSQL需要8KiB,MySQL需要16KiB,而Oracle数据库显然需要64KiB。此外,SQLite数据库作者Dr Richard Hipp询问是否有标准接口用于请求原子性,因为目前SQLite利用F2FS文件系统通过自定义ioctl()进行原子更新,但ioctl绑定在一个文件系统上。Chris回答说目前没有标准,也没有提供O_ATOMIC接口。

在2021年的Linux Plumbers Conference上,Darrick Wong重新提出了原子写入的话题(链接指向讨论录像的开头)。他指出当人们说他们想要原子写入时,有两种不同的意思:
1. 硬件提供了一些原子性API,并且这种能力以某种方式通过软件堆栈暴露出来。 2. 让文件系统完成所有工作,无论硬件如何,都要暴露出某种原子写入的API。
Darrick提到Christoph过去有关于1.的想法,但是Christoph没有回到这个话题上,并且还有一些未解答的问题(如何使用户空间意识到限制,如果该功能被公开,将仅限于直接I/O,这对许多程序可能会有问题)。相反,Darrick建议解决2.的方法是提出他的FIEXCHANGE_RANGE ioctl,它可以交换两个文件的内容(如果在中途失败,交换可以重新开始)。这种方法没有硬件解决方案所具有的限制(例如较小的连续大小、散射聚集向量的最大数量、仅支持直接I/O),并且理论上可以在VFS中实现,从而与文件系统无关...
在2023年的Linux存储、文件系统、内存管理和BPF峰会上,讨论了一种可以被应用程序使用的暴露设备原子性的方式。在演讲之前,已经发布了一个名为“block atomic writes”的RFC补丁系列,其中包括以下内容:
- 允许查询原子写支持 - 添加了一个新的fallocate2()调用,可用于确保文件的后备对齐以进行后续的原子写操作 - 在pwritev2()中添加了一个RWF_ATOMIC标志 - 利用了SCSI WRITE ATOMIC(16) / NVMe写入
该补丁系列仅支持直接I/O和XFS。
该工作的好处如下所述:
有了这个新的界面,应用程序块将永远不会被撕裂或破碎。对于每个单独的应用程序块,在电源故障时,要么全部写入数据,要么全部不写入数据。快速的原子写入和读取意味着读取可以看到所有旧数据或所有新数据,但绝不会混合旧数据和新数据。
简而言之,如果您对整个堆栈从应用程序一直到物理磁盘都有严格控制(因此可以控制和验证整个过程),您可以安排所需的内容以利用磁盘的原子性。如果您不处于这种情况或者您正在讨论一般情况,您不应该依赖于扇区写入的原子性。
操作系统发送写入扇区到磁盘的命令时是否是原子的?
截至2020年中:
- 当使用主线4.14+的Linux内核 - 如果您正在处理真实的磁盘

一个由内核发送的扇区写入很可能是原子性的(假设扇区大小不超过4KiB)。在受控情况下(具有电池备份的控制器、声称支持原子写入的NVMe磁盘、厂商向您提供保证的SCSI磁盘等),用户空间程序可能能够使用O_DIRECT,只要O_DIRECT没有回退到缓冲模式,I/O操作没有在块层被拆分/合并,且您正在发送设备特定命令并绕过块层。然而,在一般情况下,无论是内核还是用户空间程序都不能安全地假设扇区写入是原子性的。

是否可能出现磁盘上的数据部分为X、部分为Y、以及部分为垃圾的情况?

从规范的角度来看,如果你正在讨论一个 SCSI 磁盘执行常规的 SCSI WRITE(16) 操作,在写入过程中发生了停电,那么答案是肯定的:一个扇区可能包含部分 X、部分 Y 和部分垃圾数据。在进行中的写入过程中崩溃意味着从正在写入的区域读取的数据是不确定的,并且磁盘可以自由选择从该区域返回哪些数据。这意味着所有旧数据、所有新数据、一些旧数据和新数据、全零、全一、随机数据等都是该扇区可能返回的"合法"值。根据 SBC-3 规范的一个旧草案

4.9 写入失败
如果在任务集中有一个或多个执行写操作的命令正在处理时断电(例如,导致应用程序客户端发生供应商特定的命令超时)或发生介质错误或硬件错误(例如,由于错误卸载可移动介质),那些命令正在写入的逻辑块中的数据是不确定的。当被执行读取或验证操作的命令访问这些逻辑块时(例如,在通电后或在安装可移动介质后),设备服务器可能会返回旧数据、新数据或供应商特定的数据。
在读取遇到此类故障的逻辑块之前,应用程序客户端应重新发出任何未完成的执行写操作的命令。

1 2018年,Google宣布已经调整了其云SQL堆栈,并且这使得他们能够使用16k原子写入MySQL的innodb_doublewrite=0通过O_DIRECT... Google进行的底层定制被描述为在虚拟化存储、内核、virtio和ext4文件系统层面上。此外,一个不再可用的测试版文档标题为16 KB持久磁盘和MySQL的最佳实践(存档副本)描述了终端用户如何安全地使用该功能。更改包括:使用适当的Google提供的虚拟机,使用专门的存储,更改块设备参数,并仔细创建具有特定布局的ext4文件系统。然而,在2020年的某个时候,这个文档从GCE的在线指南中消失了,这表明不支持这样的终端用户调优。


1
我认为大多数人在更高的抽象层面上工作,但如果你正在编写文件系统或数据库,那么你可能需要依赖于从磁盘进行原子操作 - 并且不支持不提供该保证的硬件。 - Eloff
1
正如@Eloff所述,原子扇区写入可能是一种优化,但您需要保证不提供设置。单个扇区写入可能是原子的,但如果存在任何类型的易失性缓冲,则没有其他工作可以阻止它相对于其他“正在进行中”的写入重新排序 - 在这种情况下,仍然需要某些东西作为障碍,当I/O被下层接受时。FWIW SQLite默认依赖于扇区写入线性而不是扇区写入原子性,但这可以更改。 - Anon
1
我同意这个观点,但基本上如果你正在编写一个使用原始块设备的文件系统或数据库,你需要像原子写和屏障这样的基本操作。如果磁盘没有提供这两个操作中的任何一个,或者以一种奇怪的方式提供它们,那么你基本上无法支持该硬件 - 它从根本上就是有缺陷的。似乎原子扇区写是原子性的几乎普遍保证。对于屏障,根据你正在使用的磁盘类型(SCSI、SATA、NVM等),有特殊的排序操作。 - Eloff
1
@Eloff 我基本上同意你的说法。我认为我们都在说需要一种方法来知道何时整个写入已经传输到非易失介质。您拥有哪些原语和保证可以控制您的最佳操作方式。例如,如果我只知道磁盘高速缓存已被清除,则可以模拟屏障(以某种代价)。我还可以采用日志方法来模拟原子性。我认为这不是错误,但可能会慢(更慢)。有趣的是Linux曾经在块层中公开了屏障,但由于复杂性和错误而将其删除 - Anon
“这意味着所有旧数据、所有新数据、一些旧的和新的、所有零、所有一以及随机数据等都是该扇区返回的“合法”值。”-- 问题并不像它看起来那么丑陋。引用的草案文档指的是“设备服务器”,不管那是什么。但在驱动器级别,未完成的扇区写入(特别是在HDD上)有望在任何已写入数据与(未更新的)ECC之间创建不匹配。当ECC在扇区写入完成时未被正确更新时,任何随后的读取都应能够检测到无效的扇区数据。这就是它应该运作的方式。 - sawdust

22

我认为撕毁的页面并不是问题。据我所知,所有驱动器都有足够的电能来完成当前扇区的写入工作,即使电源中断。

问题在于每个人都撒谎。

至少在数据库知道事务已提交到磁盘时,每个人都在说谎。数据库发出fsync命令,当操作系统将所有未完成的写入提交到磁盘后才返回,对吧?也许不是这样。特别是使用RAID卡和/或SATA驱动器时,你的程序可能被告知所有数据都已提交(即fsync命令返回),但实际上还有未存储到驱动器上的数据。

你可以尝试使用Brad's diskchecker 来检测你要用于数据库的平台是否能够在断电情况下保留数据。结论是:如果diskchecker检测失败,则该平台不适合运行数据库。具有ACID特性的数据库依赖于知道何时将事务提交到后备存储器以及何时没有提交。无论数据库是否使用预写式日志记录,这都是真实的(如果数据库在没有执行fsync的情况下立即返回给用户,则在发生故障时可能会丢失事务,因此不应声称提供ACID语义)。

关于持久性问题,Postgresql邮件列表上有一篇长篇讨论。它起初是关于SSD的讨论,但随后也涉及到SATA驱动器、SCSI驱动器和文件系统。你可能会惊讶地发现你的数据可以容易丢失。这对于任何需要持久性的数据库用户都是一个很好的线索,而不仅仅是那些运行Postgresql的用户。


1
你是正确的,必须使用能够在数据进行fsync时正确向操作系统报告的存储设备来部署数据库,否则ACID中的D就无法实现。当页面大小(写入大小)是扇区大小的倍数时,需要处理撕裂的页面问题,但只要驱动器完成当前扇区的写入,并正确向操作系统报告fsync,撕裂的页面可能是你通常会遇到的最糟糕的情况。 - Eloff
1
我希望在未来的CPU和磁盘硬件设计中能够实现不需要绝对栅栏的顺序执行。例如,计算机可以告诉驱动器“在任何时候写入X和Y;相对于其他事物进行排序,但是绝对不要在X之前写入Y”。同样,CPU应了解有关对象引用的足够信息,以保证在所有挂起的写入操作完成之前不会更新对象引用,而无需强制执行与其他内容的相对顺序。是否有人正在追求这些想法呢? - supercat

18

这个问题似乎没有一个统一的答案。所以我花了很多时间尝试不同的谷歌查询,直到最终找到了答案。

来自RedHat员工、Linux内核文件系统和虚拟内存开发人员Dr. Stephen Tweedie在他关于ext3的演讲中(他是其开发者)转录在这里提到:“仅将事物写入日志是不够的,因为必须在日志中标记某些内容:这个日志记录是否实际上代表磁盘上的完全一致性呢?而你采取的方式是进行一些原子操作,将该事务标记为在磁盘上已经完成。”[23分14秒]

"现在,现代硬盘确实会做出这些保证。如果你开始向硬盘写入数据,即使在这个扇区正在处于写入过程中电源突然断电,硬盘也有足够的能量,并且可以从主轴的旋转能量中获得能量;它有足够的能量来完成正在写入的那个扇区的写入。在所有情况下,硬盘都作出了这个保证。”[23分41秒]


http://www.qnx.com/developers/docs/6.4.0/neutrino/sys_arch/fsys.html#QNX6_filesystem - Zan Lynx
看起来非常古老,因为它只提到了ext2。COW文件系统只是解决与日志文件系统相同问题的一种效率较低的方式 - 所以即使是所提出的想法也很陈旧。我仍然要说Stephen Tweedie可能是正确的人。 - Eloff
我尊重地不同意Tweedi博士的观点。尽管硬盘制造商会尽力防止,但分裂扇区确实可能发生。分裂扇区是一半新的,一半旧的。这会导致扇区出现ECC错误,并最终作为读取错误报告给主机。使用电机的反电动势(窃取转动动量)来驱动硬盘存在问题,因为在电子设备供电时会减慢旋转速度,而且由于旋转速度在写入数据时变慢,因此数据频率似乎从开始到结束发生了变化,使得读取电路难以锁定信号。 - dboals
制造商通常会使用小型字母和专门的功耗检测电路来防止分裂扇区,但并非所有驱动器都受到同等对待。然而,如果向带有FUA(强制单元访问)的驱动器发送命令,则据说数据在从驱动器获得命令完成后被保证写入。如果未设置FUA,则数据可能会在写缓存中停留一段时间。 - dboals
1
作为 https://dev59.com/GI_ea4cB1Zd3GeqPQZvn#33383028 的一部分,Arek 在2015年与 Stephen 就原子写入的问题进行了联系 - Anon

10
不,它们并不是。更糟糕的是,在默认设置下,磁盘可能会报告数据已写入,但实际上数据在磁盘缓存中。出于性能原因,这可能是可取的(实际耐久性慢了一个数量级),但这意味着如果您失去电源,而磁盘缓存没有被物理写入,则数据将丢失。
真正的耐久性非常困难缓慢,因为您需要每次写入至少进行一次完整的旋转,或者在记录/撤消时进行2次或更多次旋转。 这将限制您每秒仅能进行数百个数据库事务,并要求在相当低的级别禁用写入缓存。
然而,实际上,在大多数情况下,差异并不是很重要。
参见:
- 如何(不)实现耐久性。
- FSync()可能不会刷新到磁盘

1
如果你在使用SSD,那么上述内容都可以直接忽略。实际IOPS应该在千级以上,并且通过flush-to-disk技术,真正的耐久性也是可能实现的。 - BobMcGee
@ArekBulski 你读了这些链接吗?当你尝试写一个块时,从旋转的硬盘到底层会发生什么事情?我保证如果你仔细看,你会发现一些不好的惊喜。 - BobMcGee

8

人们似乎对于在电源故障期间进行扇区写入时会发生什么并不一致。可能是因为这取决于所使用的硬件,甚至取决于文件系统。

根据维基百科(http://en.wikipedia.org/wiki/Journaling_file_system):

某些磁盘驱动器在电源故障期间保证了写入原子性。然而,其他磁盘驱动器在电源故障后在扇区的一半停止写入,导致扇区与其纠错码不匹配。因此扇区已损坏且内容丢失。物理日志可以防止这种情况的发生,因为它保存了扇区的完整副本,可以在下次挂载时通过重放覆盖来修复。

看起来表明一些硬盘驱动器将无法完成扇区的写入,但是日志文件系统可以像xlog保护数据库那样保护您免受数据损失。

从关于ext3日志文件系统的Linux内核邮件列表中:

总之,坏扇区校验和是硬件错误。扇区写入应该是原子性的,它要么发生了,要么没有发生。

我倾向于相信这个评论而不是维基百科上的评论。实际上,没有xlog的数据库(firebird)的存在意味着扇区写入是原子性的,它不能破坏您没有意图更改的数据。
关于扇区写入的原子性有很多讨论在这里,但是没有达成一致意见。但是,持不同意见的人似乎在谈论多扇区写入(在许多现代硬盘上不是原子性的)。那些说扇区写入是原子性的人似乎更了解他们所说的内容。

5
你的第一个问题的答案取决于涉及的硬件。至少在一些旧硬件上,答案是肯定的——断电可能导致垃圾被写入磁盘。然而,大多数当前的磁盘都内置了一种“UPS”——一个电容器,足够长时间供电以将缓存中的数据写入磁盘盘片。它们还有检测电源是否正常的电路,因此当电源变得不稳定时,它们会将缓存中的数据写入盘片,并忽略可能接收到的垃圾。
至于“撕裂的页面”,典型的磁盘只接受按扇区为单位写入整个扇区的命令,因此你通常会得到正确写入的整数个扇区,其他扇区保持不变。但是,如果你使用的逻辑页面大小大于单个扇区,你确实可能会得到部分写入的页面。
然而,这主要适用于直接连接到普通移动盘式硬盘的情况。对于几乎任何其他情况,规则可能会有所不同。举个明显的例子,如果你通过网络传输数据,你大多数情况下要受网络协议的限制。如果你通过TCP传输数据,与CRC不匹配的数据将被拒绝,但是相同的数据通过UDP传输,即使存在相同的损坏,也可能被接受。

@Jerry:在我看来,这个问题涉及到磁盘收到写入单个扇区的命令,但没有足够的能量来完成。我相信并不是所有现代磁盘都能始终完成扇区的写入。 - EFraim
@EFraim:这正是我所考虑的情况,如果现代磁盘无法完成当前扇区的写入,它必须将其留下作为旧数据和新数据的混合体,如果任何垃圾数据进入该扇区,则需要从其他副本中恢复。 - Eloff
你可以使用带有电池(或电容器)支持的磁盘或RAID控制器,在系统故障时将缓存写出,这通常意味着fsync只需要等待数据到达写入缓存(非常快)。在此类硬件上运行,可能仍会发生页损坏,但一个扇区应该具有原子性,要么被写入,要么不被写入。我考虑的是比那更便宜的磁盘,但不便宜到向操作系统关于fsync撒谎,因为您不能在那种硬件上安全地运行ACID数据库。 - Eloff

2
我怀疑这个假设是错误的。
现代硬盘驱动器将数据编码为扇区,并使用ECC进行保护。因此,您可能会结束所有扇区内容 - 它只是不符合所使用的编码。
对于越来越流行的固态硬盘,情况更加严重 - 在覆盖之前会清除块,因此,取决于使用的固件和可用空间量,可能会损坏完全不相关的扇区。
顺便说一句,操作系统崩溃不会导致单个扇区内的数据受损。

我怀疑 OP 更多地是指数据库(及其数据完整性机制),而不是实际的磁盘本身。数据库包含诸如事务、序列化和日志记录等机制,以防止您所描述的情况对数据造成损害。 - Robert Harvey
1
我认为磁盘上数据的表示方式并不重要。重要的是操作系统对你所使用的系统调用提供的数据完整性保证。这种保证因操作系统而异,甚至在同一操作系统上的多个文件系统之间也有所不同,或者取决于特定文件系统的配置(例如ext3 data={data,ordered,writeback}选项)。 - daf
@EFraim:那就回答了我的问题。扇区写入是原子性的,它们要么完全成功,要么根本不会发生。这使得在操作系统崩溃时,你可以合理地期望最坏的情况是页撕裂。 - Eloff
他说扇区受ECC保护是正确的,但他关于读取垃圾数据的说法是错误的 - 硬盘驱动器的微控制器将检测到ECC不匹配并报告该扇区无法读取。您将无法从该扇区获取任何数据,无论是垃圾数据还是其他数据。他对SSD的描述也有些夸张 - 块覆盖仅在块满时发生。部分填充的块会逐步写入,每次512字节。 - hyc
@hyc:这不是重点——你不知道磨损平衡算法如何在擦除扇区之间分配扇区,因此不知道擦除扇区什么时候会被填满。当你写入操作系统看来完全不相关的磁盘区域时,这种情况可能会发生。 - EFraim
显示剩余6条评论

0

我期望一张损坏的页面包含部分X、部分Y和部分无法读取的扇区。如果在电源故障时磁头正在写入一个扇区,驱动器应立即将磁头停放,以便除了那个扇区之外的整个驱动器都不会受到损坏。

在某些情况下,我期望有几张损坏的页面包含部分X和部分Y,但只有一张损坏的页面包括一个无法读取的扇区。造成多张损坏的页面的原因是驱动器可以在内部缓冲大量写入,并且写入顺序可能交错各种页面的各种扇区。

我已经阅读了关于新写入无法读取扇区是否会使其再次可读的相互矛盾的说法。即使答案是肯定的,那也将是新数据Z,既不是X也不是Y。


-1

当更新磁盘时,驱动器制造商唯一保证的是单个512字节写入是原子性的(即,它要么完全完成,要么根本不完成);因此,如果发生意外断电,则只可能会完成更大写入的一部分(有时称为断裂写入)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接