LWN:写文件的时候不希望写入一半的时候掉电丢失,怎么办?

栏目: 后端 · 发布时间: 4年前

内容简介:全文完LWN文章遵循CC BY-SA 4.0许可协议。极度欢迎将文章分享到朋友圈

A way to do atomic writes

By Jake Edge

May 28, 2019

LSFMM

Christoph Hellwig在2019 Linux Storage, Filesystem, and Memory-Management Summit (LSFMM)会议上,分享了他关于文件系统原子操作的思考。如果application在写文件的时候出现了程序崩溃,人们肯定希望文件系统里的数据要么是旧数据,要么是新数据,肯定不希望看到新旧数据混杂在一起。这样就需要对文件有atomic write操作的能力。他介绍了在XFS里实现的atomic write,想看看其他文件系统开发者有什么想法。

目前,如果application希望对文件做atomic write,会有两种方法。一种是在user space加锁来保护,数据库方案里面通常会这样来做;另一种是重新写一个新文件,然后做“atomic rename"。可惜,应用程序开发者通常都没有正确使用fsync(),所以最终数据还是会有丢失。

LWN:写文件的时候不希望写入一半的时候掉电丢失,怎么办?

在现代存储系统里面,哪怕存储设备硬件本身,在写操作的时候都不是立刻写入存储单元的。例如闪存设备都有一个flash translation layer (FTL)抽象层,会把写操作分发到flash的各个地方去,避免某些存储单元被写入太多过早损坏(wear leveling),所以它们实际上从来不会在原地址更新数据。对NVMe设备来说,每次更新它的一个逻辑块地址(LBA)的数据的时候,都是能确保是atomic操作的,不过这个接口地位比较尴尬,估计很少人会用。SCSI的接口更加好一些,在做atomic write的时候能够有错误报告,不过他也没见过哪个厂商真的实现了这个接口。

有的文件系统可以在写操作的时候写在别的地址 ,例如XFS, Btrfs,等等。这样就能很容易在文件系统层实现aotmic write。在5年前,HP Research就有一篇有意思的论文,介绍了如何增加一个特殊的open() flag来专门指定要atomic write。这篇论文还只是学术论文,没有真正处理各种corner case,以及针对现实生活中的限制来实现,不过想法很合理。

在这个系统中,用户写入文件的时候无论写入多少数据都没用,在明确调用commit操作之前都不会真正生效。当commit操作结束后,所有的改动就真正生效了。这里比较简单的一种实现方式就是在fsync()里面来恰当地调用commit操作,这样就不需要再加一个新的系统调用了。

不久之前,他开始在XFS里面用这种方式实现atomic write。他向社区发布出了一组patch,不过当时还有不少问题,因此他后来继续修改了这组patch。目前论文的原作者一直在跟他紧密交流希望能拿到代码,然后就能跟他合作再写一篇论文出来。此外还有一些人也希望使用这个功能。

Chris Mason问他这里的粒度是多大,是针对每个单独的write(),还是更多?Hellwig回答,在commit操作之前的所有write,都会等commit的时候一次写入。文件系统会负责对最多能写多少数据来设一个上限。对XFS来说,会根据这些write所涉及到的不连续区域的数量,来决定这个上限。

不光是传统的write()系统调用,mmap()映射出来的区域也一样适用。例如,人们现在更改B-Tree的多个节点的时候,很难做atomic update,而这个功能合入后,application可以简单的在文件mmap出来的内存区域做这些更改,然后简单做一次commit即可。如果application崩溃了,文件系统里存储的数据仍然保证是旧版本或者是新版本,不会混杂起来。

Ted Ts'o提到他的Android领域的朋友也在提需求想要这么一个功能,不过是针对每个文件系统级别的。他们希望每次对Android做版本更新的时候,ext4或者F2FS文件系统都可以通过一个magic option来加载上来并且关闭所有日志记录真正触发写入操作。等文件更新完毕然后就发一个ioctl()来开始把所有那些日志都刷到存储设备里。这个方案有点不美观,不过能实现90%的功能。最后,Ts'o也认为ext4会需要有一个atomic write功能,不过每次commit之前究竟能更新多少数据,这里可能更加受限制一点。

Hellwig表示了一些担忧,因为他此前也做过类似的实现方案,都是在内存里面做数据更新,不过最终发现每一批次能缓存的数据非常有限。Ts'o介绍了Android的情况,这里数据块都是会写入存储设备的,而内存中缓存的只是metadata相关的更新,一般也就缓存几分钟,这是个非常特殊的应用场景,不具有普适性。不过这个新的实现方法替代了此前的利用device-mapper的机制(那个太慢了)。

Chris Mason提到,只要interface设计的好,他很愿意让Btrfs支持这个功能。Hellwig也说对Btrfs来说实现这个功能会很直接。对他来说一个比较大的阻碍是怎么支持O_DIRECT。如果某个application先做了atomic write,然后又把内容读回来,最好是能把刚刚写入的数据读回来。一般的application都不会这么做,不过NFS确实有这种行为。Linux I/O的代码里面没有完全支持好这部分功能,所以他还需要做一些修改。

还有一些讨论是关于为什么利用fsync()的,为什么不用一个专用的系统调用,或者其他什么接口。Hellwig觉得用fsync()没有什么不好,毕竟这也是它的本来含义,不应该只做一部分工作,而不做完。Amir Goldstein问到是否有可能其他进程同时也对这个文件做fsync()操作,相当于是某种类型的攻击。 Hellwig说他本来是使用了一个open()的flag,不过后来有人提醒没有用过的flag可能不会在open()里面检查,所以利用flag来保证数据一致性不是一个很好的主意。 在那种使用模式下,使用fsync()的接口仅仅会对那些被用这个flag打开的file descriptor才会做commit操作。后来他改成了使用inode的flag,这样更加合理一点,不过目前还没有处理好那些恶意的fsync()调用的问题。

全文完

LWN文章遵循CC BY-SA 4.0许可协议。

极度欢迎将文章分享到朋友圈 

长按下面二维码关注:Linux News搬运工,希望每周的深度文章以及开源社区的各种新近言论,能够让大家满意~

LWN:写文件的时候不希望写入一半的时候掉电丢失,怎么办?


以上所述就是小编给大家介绍的《LWN:写文件的时候不希望写入一半的时候掉电丢失,怎么办?》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Text Processing in Python

Text Processing in Python

David Mertz / Addison-Wesley Professional / 2003-6-12 / USD 54.99

Text Processing in Python describes techniques for manipulation of text using the Python programming language. At the broadest level, text processing is simply taking textual information and doing som......一起来看看 《Text Processing in Python》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具