LWN: copy_file_range()应该处理哪些情况?

【信息科学与工程学】【产品体系】第三十三篇 DPU/smartinic芯片中的学科知识03 需求实现DMA 与流边界检测优化​分级超时状态机(短/中/长)+ 积压计数 + 批量触发DMA 控制器优化​描述符预取(深度 4)+ 中断合并(阈值 8)Fence 语义正确性验证​RTL 断言 + C 语言序列号检测 + 性能对比 + 硬件计数器所有代码均为可综合 Verilog,已在仿真器中通过基本功能测试。在 FPGA 原型上运行上述 RTL,配合 ChipScope 观察 fence 时序在 BlueField-3 上运行 DOCA DPA 测试程序,对比加/不加 fence 的结果。 阅读详情

关注了就能看到更多这么棒的文章哦~

How useful should copy_file_range() be?

By Jonathan Corbet
February 18, 2021
DeepL assisted translation
https://lwn.net/Articles/846403/

copy_file_range()系统调用看起来很容易理解:允许用户空间要求内核将一系列的数据从一个文件复制到另一个文件,希望在这一过程中能以比较优化的方式来完成。实际上,这个调用看起来会很常用,但实际上并不是,这还是在 5.3 版本时对可用性方面进行了一些改进之后的结果。Go 语言的开发者在使用 copy_file_range() 时就遇到了问题,随后进行了长时间的讨论,讨论这个系统调用应该如何应用、内核是否应该多做些工作来使它真正有用。

copy_file_range()的定义是:

ssize_t copy_file_range(int fd_in, loff_t *off_in,
                        int fd_out, loff_t *off_out,
                        size_t len, unsigned int flags);

ssize_t copy_file_range(int fd_in, loff_t *off_in,
int fd_out, loff_t *off_out,
size_t len, unsigned int flags)。

它的任务是将 fd_in 所代表的文件中的 len 长度的数据复制到 fd_out 中,监测两边的 offsett。flags 参数必须为 0。这个调用最早出现在 4.5 版本中。随着时间的推移,人们发现它有许多令人不快的问题,导致了很多长期修复工作,也引起了很多抱怨。

在 2019 年,Amir Goldstein 修复了许多问题,并在此过程中删除了一个重要的限制:在此之前,copy_file_range()不允许在不位于同一文件系统的文件之间进行数据复制。这个 patch 被合并之后(5.3),它可以在任何两个文件之间进行复制了。对于跨文件系统的情况,它会回退到使用 splice() 来完成。这样一来,似乎 copy_file_range() 终于成为了一个可靠而有用的系统调用。

它确实成功吸引到了人们的注意,Go 的开发者就决定将它用于他们标准库中的 io.Copy() 函数。然后他们遇到了一个问题:当使用内核生成的文件来作为 input 文件时,copy_file_range()会复制 0 byte 数据并返回成功。/proc、tracefs 和其他大量的虚拟文件系统中的文件都是这种情况,如果直接使用像 stat()这样的系统调用对其查询文件长度,一般都会显示长度为 0。copy_file_range()看到这个信息之后,就会认为没有数据需要复制,工作已经完成,就返回成功值。

但其实这种文件是有数据要读的,只是在文件长度上没有体现出来,原因也很简单在实际读取文件之前往往无法知道其真实长度。在内核 5.3 之前,因为禁止了对跨文件系统的 copy 操作,所以大多数这样的操作都会返回一个错误代码,但这种情况也被被干净地处理掉了。内核很高兴,但用户可能感到出乎意料,他们毕竟是真的想要复制他们所要求获取的数据,于是感到很不满意。

Marking virtual filesytems

于是 Nicolas Boichat 修改了 copy_file_range() 希望能让这些用户满意。patch 中为虚拟文件系统的 file_system_type 结构增加了一个 flag (FS_GENERATED_CONTENT),设置了这个 flag 就表示这个文件系统文件的长度是无法提前获取的。copy_file_range() 会根据这个标志来返回一个错误代码,这会进而导致 io.Copy() 退而求其次继续使用主动 copy 动作。这个改动似乎解决了眼前的问题,但它肯定无法被合入 mainline。

人们对这个 patch 有一些反对意见,首先,它要求对所有的虚拟文件系统进行特殊标记,这个 patch set 并未全部标记好,并且开发者在今后添加新文件系统时一定要将它们全部标记正确。正如 Greg Kroah-Hartman 所说,"这样就意味着不断的审查工作,我不认为有人愿意在接下来的 20 年内保持做这个工作"。

但更大的问题是,这种行为是否应该被看作是一个 bug。Boichat 认为这是一个质量倒退。在 5.3 之前代码逻辑会自动回到正常 copy,而在这个改动之后就会无法 copy 了,并且也不报错。不过 Kroah-Hartman 并不认为这是个质量回退,他继续说道:

首先,人们为什么要在简单的/proc 和/sys 文件上使用 copy_file_range 呢?这些文件无法进行 seek 操作(至少大多数是不行的),所以这种感觉就像 "快看,这有一个新的 syscall,我们可以把所有地方都改成用它了!" 的问题,user space 不应该这样改。

Dave Chinner 讲得就更加直接了:

这是一个针对性的解决方案,只针对那些存储 persistent data 的文件系统中的“常规文件”,用来加速数据复制(如 clone、server side offload、hardware offload)。这不是作为一种 copy 机制(也就是将数据从随便某个文件描述符复制到另一个文件描述符)。

在 Go system library 中把它当做普通的文件复制机制来用,这不对。这是一个 user space bug。用户空间做错了事,用户空间自己才需要修正。

Go 开发者 Ian Lance Taylor 认为,不是很容易搞清楚什么时候可以使用 copy_file_range()。他指出,在 copy_file_range()的 man 页面中没有提到这些限制,并且按这种做法的话,这个系统调用的实用性就大大降低了:

从我的角度来说,也就是作为内核的一个用户而不是内核的一个开发者,像这样的系统调用会对于某些文件直接无效并且没有提醒,而且也没有提供任何方法来帮助我们:1)要么能提前确定系统调用会失败,或者 2)在调用后确定系统调用确实失败。那么这种系统调用就没有用了。我永远不能使用那个系统调用,因为我不知道它是否会成功。

Chinner 说,可以看看是不是除了 read()以外没有办法判定这个文件是否有数据,如果没法判定,那就不要使用这个系统调用。但文件系统专家 Darrick Wong 也说:"我不知道怎么做到这一点,Dave:)" 还有一个有趣的转折,正如 Boichat 所说的:sysfs 中的文件,并没有报告自己长度为零,而是声称长度为 4,096 字节,而它们的真实长度可能比这个大,也可能比这个小。Chinner 的判定方法就算能实现,在这些文件上也是无效的。

Toward a real fix

Wong 继续说,他赞同 Go 开发者的观点:copy_file_range()要么能正常按照预期来完成任务,要么就返回一个错误,这样用户空间就可以知道应该回到老路上来进行普通的 copy。他还提出了几种可能解决这个问题的方法,其中第一种是回到以前的样子,也就是明确禁止跨文件系统 copy。如果做不到这一点,我们可以将这种 copy 限制在那些明确宣称支持这个操作的那种文件系统中。Luis Henriques 针对这一想法稍作修改之后实现了 patch,也就是如果两个文件系统的类型相同,并且所涉及的文件系统明确地实现了 copy_file_range() 操作,那么跨文件系统的 copy 仍然是被允许的。

不过,Trond Myklebust 指出内核的 NFS daemon 使用 copy_file_range()机制在不同类型的文件系统之间复制文件,这个 patch 也只好中止了,因为按这种实现的话会破坏这些基本功能。这种使用模式在其他文件系统中也存在,比如 Ceph 和 FUSE。对此,Henriques 添加了一个新的标志(COPY_FILE_SPLICE),可以在内核中使用这个标志来表示应该进行跨文件系统种类的 copy。有人提出,这个标志是否应该被提供给用户空间,这样用户空间能够有某种方式能知道操作会不会成功,但最终决定不会这么做。

在写这篇文章的时候,patch 的最终版本还没有发布,但修复的方式很清晰了。当从用户空间调用时,copy_file_range()只有在两个文件系统类型相同、并且该文件系统对这个系统调用显式地声明支持的情况下,才会尝试跨文件系统复制一个文件(这样写应该是考虑到了所有可能的情况了)。否则,调用将会显式地返回错误码报错,这样用户空间就知道必须以其他方式来 copy 数据。所以,copy_file_range() 永远不会是一个通用的文件复制机制,但至少可以在那些准备好面对出错情况的代码中可靠地使用。

不过在 copy_file_range()中还潜伏着一个陷阱。同大多数与 I/O 相关的系统调用一样,copy_file_range()可以允许复制的字节数少于请求的字节数的情况。用户空间需要检查返回值,来看看实际复制了多少字节。目前没有办法区分是因为在被读的这一端被缩短的(比如是到了文件的末尾)还是在写端被停止(这很可能表明 write error)。目前还没有人想出能真正解决这个问题的方法。

上面这些内容应该让大家了解了一个看起来非常简单的接口是如何变得复杂的。copy_file_range() 存在的时间还不长,就已经暴露出了不少此前意想不到的问题。后续可能还会有新问题暴露出来。因此,难怪内核开发者在时不时被责备之后,会强烈希望要尽可能地保持 kernel 实现尽量简单了。

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

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

【信息科学与工程学】计算机科学与自动化——第二百三十三篇 信号量与进程调度、磁盘/SSD调用、内存管理及I/O工作方法的系统设计理论与方程式 第六章节01 设存储系统对外暴露逻辑对象标识集合 K,对内映射到物理资源集合 P。索引函数定义为文件系统:k=(inode,offset) 或 (path),P 为数据块/extent;对象存储:k=(bucket,key,version),P 为分片/EC chunk/副本节点;块存储:k=lba 或 lba 区间,P 为磁盘/SSD 物理页、RAID 成员、卷映射项。 阅读详情

相关推荐

Xilinx ZYNQ 7000学习笔记二(FSBL代码分析启动-汇编代码)

Xilinx ZYNQ 7000学习笔记

u011116085的博客 4246

copy_file_range系统调用及示例

copy_file_range是Linux内核4.5+引入的高效文件复制系统调用,允许在内核空间直接完成两个文件描述符间的数据传输,避免用户态和内核态间的数据拷贝开销。该函数通过指定源/目标文件偏移量和复制长度,支持跨文件系统复制(需支持),并可能利用copy-on-write等技术优化性能。相比传统read/write循环或mmap方案,特别适合大文件复制场景。函数原型包含6个参数,需注意文件描述符权限和偏移量指针的用法。典型应用场景包括文件备份、跨文件系统复制等,但需处理可能出现的EXDEV(跨挂载点不

悟空看八戒烤熟了没的专栏c)4Upqt4SeVk 1092

Source Insight 4.0舒适黑主题 仿心情看的舒服就行

Source Insight 4.0主题 仿心情看的舒服就行 source insight自带的主题怎么看怎么别扭,于是在试用全网各种主题配色后,在其中一个基础上自定义了c/c++的语法配色 截全图有点糊 函数定义 全局变量 局部变量 枚举变量引用 全局变量引用及结构体成员 宏定义引用 ----------------------后面会再把主题文件贴上来-------------- ...

weixin_43443402的博客 1303

零拷贝技术第一篇:综述

零拷贝(zero copy)在一些语境下指代的意思有所不同,本文讲的零拷贝就是大家常说的,通过这个技术让CPU释放出来不去执行内存中数据拷贝的功能,或者避免不必要的拷贝,所以说零拷贝不是没有数据的拷贝(复制),而是广义上讲的减少和避免不必要的数据拷贝,可以用来节省CPU使用和内带宽等,比如通过网络高速传输文件、实现网络proxy等等,零拷技术可以极大的提高程序的性能。本文总结零拷贝的各种技术,下一...

Go中国 1221

手把手教你用Boot-Repair快速修复Ubuntu启动分区缺失(附详细命令行步骤)

本文详细介绍了如何使用Boot-Repair工具快速修复Ubuntu启动分区缺失问题,包括诊断、应急准备、自动修复和手动命令操作。通过grub rescue模式下的关键命令和Boot-Repair的图形界面操作,帮助用户高效解决启动分区故障,确保系统恢复正常运行。

weixin_29229989的博客 562

Python画好看的雷达图,全网开源代码最好看的

【代码】Python画好看的雷达图,全网开源代码最好看的。

大模型天花板 2278

os模块篇(五)

需要注意的是,如果你使用 os.fdopen() 将文件描述符转换为了一个文件对象,那么你通常不需要调用 os.close(),因为当文件对象被垃圾回收或者显式调用其 close() 方法时,Python 会自动关闭与之关联的文件描述符。在这个例子中,我们首先使用 os.open() 打开(或创建)一个文件,并获取其文件描述符。此外,由于文件描述符是整数,并且是操作系统级别的资源,因此在使用 os.dup() 或其他文件描述符操作时,应小心确保不会耗尽文件描述符的可用范围或创建不必要的资源泄漏。

记录学习过程 728

纯C语言实现的Luhn算法(信用卡校验位):详解与示例

在本文中,我们详细介绍了如何使用纯C语言实现Luhn算法,并提供了一些示例代码。用于检查任意长度的数字字符串的有效性,用于计算给定数字字符串的校验位字符。我们还提供了一个简单的“main”C程序,用于在命令行上接受一个或多个数字字符串,并计算它们的校验位字符。通过阅读本文和理解示例代码,我们希望读者能够更好地理解Luhn算法的工作原理,并能够在自己的项目中应用这种算法。

qq_38334677的博客 1220

python的os模块

一、官方文档 os --- 多种操作系统接口 — Python 3.10.2 文档https://docs.python.org/zh-cn/3/library/os.html本模块提供了一种使用与操作系统相关的功能的便捷式途径。如果你只是想读写一个文件,请参阅open(),如果你想操作文件路径,请参阅os.path模块,如果你想读取通过命令行给出的所有文件中的所有行,请参阅fileinput模块。 为了创建临时文件和目录,请参阅tempfile模块,对于高级文件和目录处理,请参阅shut...

weixin_43431593的博客 1274

【JTAG】1149.6协议详解

JTAG1149.6协议是1149.1协议中Boundary-Scan结构的扩展,1149.1对交流耦合、差分或两者兼有的情况并没有得到充分的处理。该协议支持新的I/O测试结构。需要时变(AC)信号的高级I/O引脚允许测试它们之间的连接,这包括所有差分信号引脚或单端信号引脚,通过设计支持交流耦合。..................

xuhe0206的博客 4573

YOLO26涨点改进| TGRS 2026 | 独家创新首发、注意力改进篇| 引入LCGA局部曲率引导注意力,保持局部稳定性的同时突出关键几何区域,含多种创新改进,促进YOLO26所有任务高效涨点

🔥本文提出LCGA(局部曲率引导注意力)模块,通过引入曲率信息改进YOLO26网络模型。LCGA在局部窗口内利用深度卷积构造曲率代理,调制标准窗口注意力,使模型更关注道路、边界等曲线型结构,提升遥感图像超分辨率中的几何保真度。相比普通注意力,LCGA能精准聚焦关键几何区域,减少边缘断裂和轮廓偏移,同时保持较低计算开销。实验表明LCGA显著提升性能,在UCMerced数据集上PSNR提升0.2148dB。文章提供了三种改进方案。

Ai缝合怪、助力小伙伴高效发论文 226

Linux下Go的安装、配置 、升级和卸载

目录 1. 手动安装 Go 2. 设置 Go 开发环境 2.1 创建工作空间 2.2 配置环境变量 3. 测试 Go 源码实例 4. 卸载 Go 5. 升级 Go 版本 1. 手动安装 Go 由于大家使用的 Linux 版本不尽相同,也不见得是最新版本或需要版本的 Go 语言包,所以我们说一下如何手动安装指定版本。 1.下载Go发行版 从官方地址:https://go...

光年遐想 2万+

黑猫带你学UFS协议第2篇:UFS相关名词释义

本文依据UFSJEDEC3.1、个人工作经验整理而成,如有错误请留言。文章为个人辛苦整理,付费内容,已加入原创保护,禁止私自转载。文章所在专栏《黑猫带你学UFS协议详解》

黑猫奥利奥的博客 5302

The GPU Memory Subsystem as a Mirror of CPU Memory Management: A Structural Analogy

Abstract: The Linux GPU memory management subsystem (TTM/GEM/GPUVM) is a domain-specific reimplementation of classical CPU virtual memory principles, adapted for accelerator hardware.

图形/计算GPU的驱动与虚拟化技术分享园地 698

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

OSTEP实战作战地图:从虚拟化、并发到持久性的三维穿透式学习

操作系统是软硬件协同的精密系统,其核心围绕虚拟化、并发和持久性三大原理展开。虚拟化通过页表与TLB实现资源抽象与隔离,直接影响内存访问性能与上下文切换开销;并发机制依赖内核调度、锁原语与信号处理,在多线程/多进程场景中决定响应延迟与数据一致性;持久性则贯穿I/O栈设计,涉及Page Cache、缓冲区管理与设备调度策略。这些基础原理不仅构成Linux内核行为的底层逻辑,更直接映射到Redis单线程优势、MySQL主从延迟、K8s容器内存限制等高频工程问题。本文以《操作系统导论》(OSTEP)为纲,聚焦虚拟化

weixin_33805743的博客 1076

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Linux DMA-BUF 软件框架分析

DMA-BUF 是 Linux 内核中跨设备、跨子系统共享缓冲区的通用框架。它解决的问题不是“如何分配一块内存”,而是“当一块内存已经由某个子系统拥有时,如何把它安全地交给其他设备或驱动访问”。在多媒体、显示、GPU、摄像头、视频编解码等场景中,同一帧图像或同一块数据经常需要在多个硬件模块之间流转。如果每个模块都复制一份,性能和内存占用都会很差。DMA-BUF 通过 fd 作为用户态句柄,通过作为内核对象,把 buffer 的所有权、映射、同步和生命周期统一起来。避免跨设备数据复制。

非专业业余程序员 535

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

全志编译过程问题与解决方法汇总

全志编译过程问题与解决方法汇总 一、copy_file_range ./../misc/create_inode.c:395:18: error: conflicting types for 'copy_file_range' static errcode_t copy_file_range(ext2_filsys fs, int fd, ext2_file_t e2_file, 修改文件:./out/sun8iw11p1/linux/common/buildroot/build/hos..

小小的生活,大大的世界 5429

linux java 归来_零拷贝Zero copy-linux and java

什么是零拷贝传统零拷贝背景-几种拷贝方式方式1:Copying in Two Sample System Callsread(file, tmp_buf, len);write(socket, tmp_buf, len);首先,调用read时,文件A copy到了kernel模式;之后,CPU控制将kernel模式数据copy到user模式下;调用write时,先将user模式下的内容copy到k...

weixin_39814369的博客 136

python系统模块os

文章目录成员变量和无参函数常用单参函数与复制移动重命名相关的函数os.path文件描述符操作进程管理stat_result os,即操作系统,os模块提供一些与操作系统交互的接口,是一个非常强大的内置包。由于其内容过多,很大一部分功能我也没用过,如有纰漏之处还望指出,在此谢过。 成员变量和无参函数 (返回)类型 成员变量 os.name 字符串 操作系统名称,取值为posix, nt, java分别代表当前系统为Linux, Windows, java虚拟机 os.environ 字典

微小冷的学习笔记 3702

conflicting types for ‘copy_file_range’

编译 QIHUA-X40I 报错如下: ./…/misc/create_inode.c:395:18: error: conflicting types for ‘copy_file_range’ static errcode_t copy_file_range(ext2_filsys fs, int fd, ext2_file_t e2_file, ^ In file included from ./…/misc/create_inode.c:19:0: /usr/include/unistd.h:11

DawnChing 2108

python操作系统接口错误_os --- 多种操作系统接口 — Python 3.10.0a2 文档

文件描述符操作¶这些函数对文件描述符所引用的 I/O 流进行操作。文件描述符是一些小的整数,对应于当前进程所打开的文件。例如,标准输入的文件描述符通常是0,标准输出是1,标准错误是2。之后被进程打开的文件的文件描述符会被依次指定为3,4,5等。“文件描述符”这个词有点误导性,在 Unix 平台中套接字和管道也被文件描述符所引用。当需要时,可以用 fileno() 可以获得 file object ...

weixin_39944074的博客 413

Python模块百科_操作系统接口_os[四]

用自己的方式来理解Python的常用模块;os 模块是最常用的模块之一,提供了与操作系统交互的多种功能。可以使用 os 模块来执行文件或目录操作,如读取或修改环境变量、访问命令行参数、处理文件路径、执行系统命令等

长孤秋落的札记 1746

Python文件复制

#!/usr/bin/python # -*- coding: UTF-8 -*- import os import shutil # 创建的目录 root_path = "D:\paper\\5derain\CIR\CIR_delete\pairimages" copy_path = "D:\paper\\5derain\CIR\CIR_delete\pairimages\\train" for i in range(2965): source_file = root_path + "\\" .

weixin_36670529的博客 366

linux添加一个系统调用(syscall)

添加系统调用函数头文件 在include/linux/syscalls.h文件中的#endif前添加自己的系统调用函数声明,内容如下: asmlinkage long sys_test(void); 添加系统调用实现源码 随便找一个文件,我们在这个文件中添加系统调用的源码SYSCALL_DEFINE0(test) ,内容如下: SYSCALL_DEFINE0(test) { ...

小小城御园的博客 5151
上一篇: LWN: 5.12 合并窗口,第一部分!
下一篇: LWN:介绍lockless算法!
LinuxNews搬运工
博客等级 码龄7年 438粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值