如何避免内核中的页面缓存,应用程序可以直接从磁盘写入或读取数据?在内核中,如何设置?
问问题
4370 次
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_WCACHE
ioctl可以控制:
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 回答