4

如何避免内核中的页面缓存,应用程序可以直接从磁盘写入或读取数据?在内核中,如何设置?

4

2 回答 2

5

您将需要应用程序调用 O_DIRECT。从手册页http://man7.org/linux/man-pages/man2/open.2.html

有了这个,你告诉内核在执行 I/O 时不要从页面缓存中写入/读取。

O_DIRECT(自 Linux 2.4.10 起) 尽量减少进出该文件的 I/O 的缓存影响。一般来说,这会降低性能,但在特殊情况下很有用,例如当应用程序进行自己的缓存时。文件 I/O 直接与用户空间缓冲区进行。O_DIRECT 标志自己努力同步传输数据,但不提供 O_SYNC 标志的保证,即传输数据和必要的元数据。为了保证同步 I/O,除了 O_DIRECT 之外,还必须使用 O_SYNC。有关进一步讨论,请参见下面的注释。

          A semantically similar (but deprecated) interface for block
          devices is described in raw(8).
于 2016-06-18T02:59:24.297 回答
0

更新

规范中的写缓存与page cache. 这里的缓存实际上是指集成在磁盘控制器中的 RAM/NVRAM,这种内存不要与页面缓存混淆!




AFAIK,这些仅保证 SATA 和 NVMe 设备的写入页面启用/禁用开关,

SATA

参考sata 3.0规范:

SET FEATURES (Write Cache Enable/Disable):由 SET FEATURES 命令建立的写缓存启用/禁用设置,子命令代码为 02h 或 82h。

在linux内核下,HDIO_SET_WCACHEioctl可以控制:

static DEFINE_MUTEX(ide_disk_ioctl_mutex);
static const struct ide_ioctl_devset ide_disk_ioctl_settings[] = {
{ HDIO_GET_ADDRESS, HDIO_SET_ADDRESS,   &ide_devset_address   },
{ HDIO_GET_MULTCOUNT,   HDIO_SET_MULTCOUNT, &ide_devset_multcount },
{ HDIO_GET_NOWERR,  HDIO_SET_NOWERR,    &ide_devset_nowerr    },
{ HDIO_GET_WCACHE,  HDIO_SET_WCACHE,    &ide_devset_wcache    },
{ HDIO_GET_ACOUSTIC,    HDIO_SET_ACOUSTIC,  &ide_devset_acoustic  },
{ 0 }
};

int ide_disk_ioctl(ide_drive_t *drive, struct block_device *bdev, fmode_t mode,
           unsigned int cmd, unsigned long arg)
{
    int err;

    mutex_lock(&ide_disk_ioctl_mutex);
    err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_disk_ioctl_settings);
    if (err != -EOPNOTSUPP)
        goto out;

    err = generic_ide_ioctl(drive, bdev, cmd, arg);
out:
    mutex_unlock(&ide_disk_ioctl_mutex);
    return err;
}

您还可以使用方便hdparm -W0/1 /dev/sdx地禁用/启用写入缓存,这也可以在HDIO_SET_WCACHE内部调用:

}
        if (!wcache)
            err = flush_wcache(fd);
        if (ioctl(fd, HDIO_SET_WCACHE, wcache)) {
            __u8 setcache[4] = {ATA_OP_SETFEATURES,0,0,0};
            setcache[2] = wcache ? 0x02 : 0x82;
            if (do_drive_cmd(fd, setcache, 0)) {
                err = errno;
                perror(" HDIO_DRIVE_CMD(setcache) failed");
            }
        }

NVME

内核源码:

static ssize_t queue_wc_show(struct request_queue *q, char *page)
{
    if (test_bit(QUEUE_FLAG_WC, &q->queue_flags))
        return sprintf(page, "write back\n");

    return sprintf(page, "write through\n");
}

static ssize_t queue_wc_store(struct request_queue *q, const char *page,
                  size_t count)
{
    int set = -1;

    if (!strncmp(page, "write back", 10))
        set = 1;
    else if (!strncmp(page, "write through", 13) ||
         !strncmp(page, "none", 4))
        set = 0;

    if (set == -1)
        return -EINVAL;

    if (set)
        blk_queue_flag_set(QUEUE_FLAG_WC, q);
    else
        blk_queue_flag_clear(QUEUE_FLAG_WC, q);

    return count;
}

nvme 规格:

在此处输入图像描述

于 2021-05-27T01:27:44.420 回答