如何在linux中使用ioctl(原始分区)正确刷新磁盘缓存
我正在尝试使用ioctl来确保直接写入卷的更改会影响磁盘。 fsync()显然在原始分区中不可用。sync()也是一个可怕的解决方案(为了刷新64MB,我需要整个生命周期来同步等待) 所以。。以下是我正在尝试做的事情——犯25号错误 /dev/sda3是ssd驱动器上未安装的原始分区如何在linux中使用ioctl(原始分区)正确刷新磁盘缓存,c,linux,flush,ioctl,C,Linux,Flush,Ioctl,我正在尝试使用ioctl来确保直接写入卷的更改会影响磁盘。 fsync()显然在原始分区中不可用。sync()也是一个可怕的解决方案(为了刷新64MB,我需要整个生命周期来同步等待) 所以。。以下是我正在尝试做的事情——犯25号错误 /dev/sda3是ssd驱动器上未安装的原始分区 open(_fd, "/dev/sda3", ...) pwritev(_fd, ...) ioctl(_fd, BLKFLSBUF, 0) <== errno = 25. 开启失败:设备的ioct
open(_fd, "/dev/sda3", ...)
pwritev(_fd, ...)
ioctl(_fd, BLKFLSBUF, 0) <== errno = 25.
开启失败:设备的ioctl不正确
如何为我的ssd找到合适的刷新方法?我无法使用4.2.0-42-generic内核在x86\u 64上复制Ubuntu 14.04.4 LTS中的
ioctl(fd,BLKFLSBUF)
错误
我测试了全块设备和它们上的各个分区。你能试试下面的最小测试程序吗
将以下内容另存为例如block flush.c:
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
int arg, descriptor, result;
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s BLOCK-DEVICE-OR-PARTITION ...\n", argv[0]);
fprintf(stderr, "\n");
return EXIT_FAILURE;
}
for (arg = 1; arg < argc; arg++) {
do {
descriptor = open(argv[arg], O_RDWR);
} while (descriptor == -1 && errno == EINTR);
if (descriptor == -1) {
const int cause = errno;
fprintf(stderr, "%s: Cannot open device: %s [%d].\n", argv[arg], strerror(cause), cause);
return EXIT_FAILURE;
}
errno = 0;
result = ioctl(descriptor, BLKFLSBUF);
if (result && errno) {
const int cause = errno;
fprintf(stderr, "%s: Cannot flush device: %s [%d].\n", argv[arg], strerror(cause), cause);
return EXIT_FAILURE;
} else
if (result)
fprintf(stderr, "%s: Flush returned %d.\n", argv[arg], result);
else
if (errno) {
const int cause = errno;
fprintf(stderr, "%s: Flush returned zero, but with error: %s [%d]. Ignored.\n", argv[arg], strerror(cause), cause);
}
result = close(descriptor);
if (result == -1) {
const int cause = errno;
fprintf(stderr, "%s: Error closing device: %s [%d].\n", argv[arg], strerror(cause), cause);
return EXIT_FAILURE;
}
fprintf(stderr, "%s: Flushed.\n", argv[arg]);
}
return EXIT_SUCCESS;
}
并以root用户身份运行它,在命令行中指定分区或块设备:
sudo ./block-flush /dev/sda3
对我来说,这会为未安装的分区以及磁盘(/dev/sdx
)本身输出/dev/sdxN:Flushed.
)。(另外,在ioctl()之前添加fdatasync(descriptor)
不会改变任何内容,它也会成功,不会出现任何错误。)
此外,我碰巧使用一个外部USB SATA扩展底座和一个“响亮的”3.5“驱动器(此类扩展底座需要外部电源;USB电源不足以支持这些带有旋转盘片的大型驱动器)对此进行了测试。我可以很容易地听到ioctl()确实访问了物理设备,因此它不是一个禁止操作的选项(同样,最小测试程序在我的测试中从未报告任何失败)。关闭描述符后,磁盘也会处于静止状态,直到磁盘或分区被打开以供进一步访问。当然,这些观察结果仅适用于USB连接的硬盘驱动器,并且仅适用于此特定的内核和硬件体系结构,但在我看来,它确实表明
ioctl(描述符,BLKFLSBUF)
应该以预期的方式适用于未安装的分区和全块设备。使用直接I/O或/dev/raw是一个选项吗?什么意思,“fsync()显然在原始分区中不可用”?fsync(\u fd)
和fdatasync(\u fd)
应将内容刷新到底层设备,即使\u fd
指的是块设备。实际刷新由(通过→ do_fsync()→ vfs_fsync()→ vfs_fsync_range(),然后通过文件操作结构执行blkdev_fsync()@MarkPlotnick-我正在打开/dev/sda3。不是/dev/raw。我使用了另一台运行hdparam-W 0的机器。仍然ioctl失败,errno=25。所以我的问题是-我可以在/dev/sdxN上使用ioctl-BLKFLSHBUF吗?@NominalAnimal-fsync给我提供内存速率,而不是磁盘。它似乎什么都不起作用。我的场景:1)创建未安装的分区2)fd=open(“/dev/sdaxN“,…权限..)3)写入..现在fsync什么都不做,ioctl(fd,BLKFLSBUF)失败。我缺少什么?我想确保数据是以物理方式写入的
gcc -Wall -O2 block-flush.c -o block-flush
sudo ./block-flush /dev/sda3