如何在linux中使用ioctl(原始分区)正确刷新磁盘缓存

我正在尝试使用ioctl来确保直接写入卷的更改正在访问磁盘.

fsync()显然在原始分区中不可用. sync()也是一个可怕的解决方案(为了冲洗64MB,我需要整个生命时间等待同步)

所以..这就是我想要做的事情 – 得到错误25.

/ dev / sda3是ssd驱动器上的原始卸载分区

open(_fd, "/dev/sda3", ...)
pwritev(_fd, ...)

ioctl(_fd, BLKFLSBUF, 0)   <== errno = 25. 

Ubuntu 14.04,c

注意:

hdparm -W 0 /dev/sda3

失败:对设备不适当的ioctl.

如何为我的ssd找到合适的冲洗方法?

最佳答案 我不能使用4.2.0-42泛型内核在x86_64上的Ubuntu 14.04.4 LTS中复制ioctl(fd,BLKFLSBUF)错误.

我测试了两个完整的块设备,以及它们上的各个分区.你能试试下面的最小测试程序吗?

保存以下内容,例如块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;
}

使用编译它

gcc -Wall -O2 block-flush.c -o block-flush

并运行它(以root身份),在命令行指定分区或块设备:

sudo ./block-flush /dev/sda3

对我来说,这输出/ dev / sdxN:刷新.对于未安装的分区,以及磁盘(/ dev / sdx)本身. (另外,在ioctl()之前添加fdatasync(描述符)不会改变任何东西,并且它也会成功而没有任何错误.)

此外,我碰巧使用外部USB SATA扩展坞和“响亮的”3.5“驱动器(这种扩展需要外部电源; USB电源不足以满足这些带有旋转盘片的大型驱动器)进行测试.我很容易听到ioctl ()确实访问物理设备,所以它不是无操作(并且,最小的测试程序再次没有报告我的测试中的任何失败).关闭描述符后,磁盘也是静止的,直到磁盘或分区是当然,这些观察仅适用于USB连接的硬盘驱动器,并且只适用于这种特定的内核和硬件架构,但在我看来,它确实表明ioctl(描述符,BLKFLSBUF);应该适用于未预装的分区和完整的块设备,以预期的方式.

点赞