Seninha Asked: 2018-09-02 05:45:00 +0800 CST2018-09-02 05:45:00 +0800 CST 2018-09-02 05:45:00 +0800 CST 当我杀死'cp'时会发生什么?它安全吗?它有什么后果吗? 772 当我在运行时键入+终止复制cp命令时,对 ext4 文件系统有什么影响?CtrlC 文件系统是否损坏?不完整的复制文件所占用的分区空间在删除后是否还能使用? 而且,最重要的是,终止cp进程是否安全? files filesystems 3 个回答 Voted Best Answer forest 2018-09-02T11:59:15+08:002018-09-02T11:59:15+08:00 这样做是安全的,但自然你可能还没有完成副本。 当cp命令运行时,它会进行系统调用,指示内核制作文件的副本。系统调用或系统调用是应用程序可以用来向内核请求服务的函数,例如向磁盘读取或写入数据。用户空间进程只是等待系统调用完成。如果您要跟踪来自 的调用cp ~/hello.txt /mnt,它将如下所示: open("/home/user/hello.txt", O_RDONLY) = 3 open("/mnt/hello.txt", O_CREAT|O_WRONLY, 0644) = 4 read(3, "Hello, world!\n", 131072) = 14 write(4, "Hello, world!\n", 14) = 14 close(3) = 0 close(4) = 0 这对要复制的每个文件重复。由于这些系统调用的工作方式,不会发生损坏。当输入这样的系统调用时,致命信号只会在系统调用完成后生效,而不是在它运行时生效(实际上,信号仅在内核空间到用户空间上下文切换期间到达)。请注意,某些信号,例如read(),可以提前终止。 因此,强制终止进程只会导致它在当前运行的系统调用返回后终止。这意味着文件系统驱动程序所在的内核可以自由地完成将文件系统置于正常状态所需完成的操作。任何此类 I/O 都不会在操作过程中终止,因此不存在文件系统损坏的风险。 schily 2018-09-02T05:52:17+08:002018-09-02T05:52:17+08:00 由于cp是用户空间命令,因此不会影响文件系统的完整性。 你当然需要做好准备,如果你杀死一个正在运行的程序,至少有一个文件不会被完全复制cp。 Marcus Müller 2021-11-02T10:54:43+08:002021-11-02T10:54:43+08:00 森林的答案,虽然很漂亮(在许多情况下是正确的),但不是您在现代系统上看到的⁰。他们是对的——在任何情况下都不会损坏您的文件系统。但在实际情况下,这些天你不会得到半份! 假设我这样做(只是为了生成一个大文件yesfile,并将其复制到一个文件copy中(不必在同一个文件系统上),同时记录所有系统调用 mady by cp): cd /tmp yes | head -n$((10**7)) > yesfile strace -o strace.output cp yesfile copy 我得到了不同的画面:用户态进程实际上cp并没有读取文件的内容,也没有将其写入另一个文件;这在性能方面会很糟糕:它至少需要两个上下文切换!用户态程序调用read、切换、获取数据、调用write、切换;如果文件大于单个读取缓冲区,则冲洗并重复。现在这种精确的重复模型,只读取有限大小的缓冲区,可能会导致文件中断时复制一半。 相反,它使用copy_file_range系统调用(参见下面的跟踪¹);man copy_file_range告诉我们: 系统 copy_file_range() 调用在两个文件描述符之间执行内核内复制,而无需将数据从内核传输到用户空间然后再返回内核的额外成本。len它将源文件描述符中最多字节的数据复制到fd_in目标文件描述符fd_out,覆盖目标文件请求范围内存在的任何数据。 所以,有一个原子的copy-this-file系统调用,通常会用到,所以中断cp不能中断复制。 如果您的源文件系统和目标文件系统相同,以及 Btrfs、CIFS、NFS 4.2、OCFS2、overlayfs 或 XFS源(在撰写本文时,仅针对这些 Linux 具有 reflink 功能),情况会变得更好:如果 ioctl(4, BTRFS_IOC_CLONE or FICLONE, 3) 成功后,系统根本不需要复制文件内容——相反,只需将属于源文件的块列表复制到目标文件;每个块都有一个增加的引用计数器,因此当任何进程写入这些文件中的任何一个时,文件系统都会透明地对其进行写时复制。所以,这些东西更加原子! ⁰ 至少,如果我的 GNU coreutils 8.32 和 fedora 34 的反向移植copy_file_range 补丁/Linux 5.13.5 被认为是现代的。 ¹ 相关的 strace 输出 156 │ newfstatat(AT_FDCWD, "yesfile", {st_mode=S_IFREG|0644, st_size=20000000, ...}, 0) = 0 157 │ newfstatat(AT_FDCWD, "copy", 0x7fff982d5e70, 0) = -1 ENOENT (No such file or directory) 158 │ openat(AT_FDCWD, "yesfile", O_RDONLY) = 3 159 │ newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=20000000, ...}, AT_EMPTY_PATH) = 0 160 │ openat(AT_FDCWD, "copy", O_WRONLY|O_CREAT|O_EXCL, 0644) = 4 161 │ newfstatat(4, "", {st_mode=S_IFREG|0644, st_size=0, ...}, AT_EMPTY_PATH) = 0 162 │ ioctl(4, BTRFS_IOC_CLONE or FICLONE, 3) = -1 EOPNOTSUPP (Operation not supported) 163 │ fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0 164 │ mmap(NULL, 139264, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0be58ca000 165 │ uname({sysname="Linux", nodename="workhorse", ...}) = 0 166 │ copy_file_range(3, NULL, 4, NULL, 9223372035781033984, 0) = 20000000 167 │ copy_file_range(3, NULL, 4, NULL, 9223372035781033984, 0) = 0 168 │ close(4) = 0 169 │ close(3) = 0 170 │ munmap(0x7f0be58ca000, 139264) = 0
这样做是安全的,但自然你可能还没有完成副本。
当
cp
命令运行时,它会进行系统调用,指示内核制作文件的副本。系统调用或系统调用是应用程序可以用来向内核请求服务的函数,例如向磁盘读取或写入数据。用户空间进程只是等待系统调用完成。如果您要跟踪来自 的调用cp ~/hello.txt /mnt
,它将如下所示:这对要复制的每个文件重复。由于这些系统调用的工作方式,不会发生损坏。当输入这样的系统调用时,致命信号只会在系统调用完成后生效,而不是在它运行时生效(实际上,信号仅在内核空间到用户空间上下文切换期间到达)。请注意,某些信号,例如
read()
,可以提前终止。因此,强制终止进程只会导致它在当前运行的系统调用返回后终止。这意味着文件系统驱动程序所在的内核可以自由地完成将文件系统置于正常状态所需完成的操作。任何此类 I/O 都不会在操作过程中终止,因此不存在文件系统损坏的风险。
由于
cp
是用户空间命令,因此不会影响文件系统的完整性。你当然需要做好准备,如果你杀死一个正在运行的程序,至少有一个文件不会被完全复制
cp
。森林的答案,虽然很漂亮(在许多情况下是正确的),但不是您在现代系统上看到的⁰。他们是对的——在任何情况下都不会损坏您的文件系统。但在实际情况下,这些天你不会得到半份!
假设我这样做(只是为了生成一个大文件
yesfile
,并将其复制到一个文件copy
中(不必在同一个文件系统上),同时记录所有系统调用 mady bycp
):我得到了不同的画面:用户态进程实际上
cp
并没有读取文件的内容,也没有将其写入另一个文件;这在性能方面会很糟糕:它至少需要两个上下文切换!用户态程序调用read
、切换、获取数据、调用write
、切换;如果文件大于单个读取缓冲区,则冲洗并重复。现在这种精确的重复模型,只读取有限大小的缓冲区,可能会导致文件中断时复制一半。相反,它使用
copy_file_range
系统调用(参见下面的跟踪¹);man copy_file_range
告诉我们:所以,有一个原子的copy-this-file系统调用,通常会用到,所以中断
cp
不能中断复制。如果您的源文件系统和目标文件系统相同,以及 Btrfs、CIFS、NFS 4.2、OCFS2、overlayfs 或 XFS源(在撰写本文时,仅针对这些 Linux 具有 reflink 功能),情况会变得更好:如果
成功后,系统根本不需要复制文件内容——相反,只需将属于源文件的块列表复制到目标文件;每个块都有一个增加的引用计数器,因此当任何进程写入这些文件中的任何一个时,文件系统都会透明地对其进行写时复制。所以,这些东西更加原子!
⁰ 至少,如果我的 GNU coreutils 8.32 和 fedora 34 的反向移植
copy_file_range
补丁/Linux 5.13.5 被认为是现代的。¹ 相关的 strace 输出