如何实现或模拟MADV_ZERO?

时间:2015-08-31 23:56:11

标签: c linux shared-memory mmap fallocate

我希望能够在不调用任何io的情况下将一系列文件内存映射归零(为了有效地顺序覆盖大型文件而不会产生任何磁盘读取io)。

执行std::memset(ptr, 0, length)会导致页面从磁盘读取,即使整个页面都被覆盖也不在内存中,因此完全破坏了磁盘性能。

我希望能够执行类似madvise(ptr, length, MADV_ZERO)的操作,这会使范围归零(类似于FALLOC_FL_ZERO_RANGE),以便在访问时导致零填充页面错误而不是常规io页面错误指定范围。

不幸的是MADV_ZERO不存在。即使相应的标记FALLOC_FL_ZERO_RANGE确实存在于fallocate中,并且可以与fwrite一起使用以实现类似的效果,但没有即时的跨进程一致性。

我猜测一种可能的选择是使用MADV_REMOVE。但是,根据我的理解,这可能导致文件碎片并在完成时阻止其他操作,这使我不确定其长期性能影响。我使用Windows的经验是类似的FSCTL_SET_ZERO_DATA命令在调用时会引起显着的性能峰值。

我的问题是如何为共享映射实现或模拟MADV_ZERO,最好是在用户模式下?

1。的 /dev/zero/

我已将suggested视为只需将/dev/zero读入所选范围即可。虽然我不太清楚什么"阅读范围"手段和方法。是fread/dev/zero进入记忆范围吗?不确定如何避免访问时出现常规页面错误?

  

对于Linux,只需将/dev/zero读入所选范围即可。该   内核已经为匿名映射优化了这种情况。

     

如果一般来说这样做太难实现,我会   建议MADV_ZERO应该有这样的效果:就像读书一样   / dev / zero进入范围,但始终有效。

编辑:在线程further之后,事实证明它实际上不起作用。

  

在处理共享映射时,它不会做任何技巧。

2。的 MADV_REMOVE

在Linux中实现它的一个猜测(即不在我喜欢的用户应用程序中)可以通过简单地复制和修改MADV_REMOVE,即madvise_remove来代替使用FALLOC_FL_ZERO_RANGE FALLOC_FL_PUNCH_HOLE。虽然我在猜测这一点时有点头脑,特别是因为我不太了解vfs_allocate周围的代码是做什么的:

// madvice.c
static long madvise_remove(...)
  ...
  /*
   * Filesystem's fallocate may need to take i_mutex.  We need to
   * explicitly grab a reference because the vma (and hence the
   * vma's reference to the file) can go away as soon as we drop
   * mmap_sem.
   */
  get_file(f); // Increment ref count.
  up_read(&current->mm->mmap_sem); // Release a read lock? Why?
  error = vfs_fallocate(f,
            FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, // FALLOC_FL_ZERO_RANGE?
            offset, end - start);
  fput(f); // Decrement ref count.
  down_read(&current->mm->mmap_sem); // Acquire read lock. Why?
  return error;
}

1 个答案:

答案 0 :(得分:1)

你可能无法做到你想要的(在用户空间,不破坏内核)。请注意,由于page cache,写入零页可能不会产生物理磁盘IO。

您可能希望在sparse file中用文件孔替换文件段(但这不是您想要的),但某些文件系统(例如VFAT)没有漏洞或稀疏文件。请参阅lseek(2) SEEK_HOLEftruncate(2)