5

在 Linux 的用户空间程序中,我通过从堆中分配获得一块内存,然后将指针分配给运行在其他线程中的许多其他组件以使用。我想在修改所述内存时收到通知。我当然可以为其他组件开发一个自定义用户空间解决方案,以便在他们尝试修改内存时使用。我的问题是这些是遗留组件,它们可以在很多情况下写入内存。所以我想知道是否有类似的API,如inotify(在文件更改时得到通知)或其他方法,以便在一块内存被更改时得到通知。

我考虑过使用 mmap 和 inotify,如果没有刷新更改,这显然是行不通的。任何建议表示赞赏:-)

4

3 回答 3

4

您可以添加一个inotify手表,该手表将在 mmap-ed 文件上的msync()上触发。

这需要修补 Linux 内核以启用对新 inotify watch 的支持。该补丁添加了一个新标志IN_SYNC - 一个新的 inotify 事件,每当对 mmap-ed 文件执行 msync() 时就会触发该事件。

补丁已经在 Linux Kernel v2.6.37 上测试过了。

From 83edf446e92c86c738337ca4a35eab48e2f4e0eb Mon Sep 17 00:00:00 2001
From: Chinmay V S <cvs268@gmail.com>
Date: Mon, 17 Jun 2013 13:53:57 +0800
Subject: [PATCH] Add mmap-ed file support to inotify

This patch adds a new flag IN_SYNC. This is a new inotify event that is
triggered whenever msync() is carried out on a mmap-ed file.

Signed-off-by: Chinmay V S <cvs268@gmail.com>
---
 fs/sync.c                             |  5 +++++
 include/linux/fsnotify.h              | 16 ++++++++++++++++
 include/linux/fsnotify_backend.h      |  1 +
 include/linux/inotify.h               |  3 ++-
 mm/msync.c                            |  4 ++++
 5 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/fs/sync.c b/fs/sync.c
index ba76b96..174c2af 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -16,6 +16,7 @@
 #include <linux/buffer_head.h>
 #include <linux/backing-dev.h>
 #include "internal.h"
+#include <linux/fsnotify.h>

 #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \
            SYNC_FILE_RANGE_WAIT_AFTER)
@@ -190,6 +191,10 @@ static int do_fsync(unsigned int fd, int datasync)
        ret = vfs_fsync(file, datasync);
        fput(file);
    }
+
+   if (!ret)
+       fsnotify_sync(file->f_path.dentry);
+
    return ret;
 }

diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index b10bcde..ef211fb 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -224,6 +224,22 @@ static inline void fsnotify_modify(struct file *file)
 }

 /*
+ * fsnotify_sync - file was synced
+ */
+static inline void fsnotify_sync(struct dentry *dentry)
+{
+   struct inode *inode = dentry->d_inode;
+   u32 mask = FS_SYNC;
+
+   if (S_ISDIR(inode->i_mode))
+       mask |= FS_ISDIR;
+
+   fsnotify_parent(NULL, dentry, mask);
+   fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
+
+}
+
+/*
  * fsnotify_open - file was opened
  */
 static inline void fsnotify_open(struct file *file)
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 7380763..35b5cb8 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -36,6 +36,7 @@
 #define FS_DELETE      0x00000200  /* Subfile was deleted */
 #define FS_DELETE_SELF     0x00000400  /* Self was deleted */
 #define FS_MOVE_SELF       0x00000800  /* Self was moved */
+#define FS_SYNC            0x00001000  /* File was synced */

 #define FS_UNMOUNT     0x00002000  /* inode on umount fs */
 #define FS_Q_OVERFLOW      0x00004000  /* Event queued overflowed */
diff --git a/include/linux/inotify.h b/include/linux/inotify.h
index d33041e..244a132 100644
--- a/include/linux/inotify.h
+++ b/include/linux/inotify.h
@@ -38,6 +38,7 @@ struct inotify_event {
 #define IN_DELETE      0x00000200  /* Subfile was deleted */
 #define IN_DELETE_SELF     0x00000400  /* Self was deleted */
 #define IN_MOVE_SELF       0x00000800  /* Self was moved */
+#define IN_SYNC            0x00001000  /* File was synced */

 /* the following are legal events.  they are sent as needed to any watch */
 #define IN_UNMOUNT     0x00002000  /* Backing fs was unmounted */
@@ -64,7 +65,7 @@ struct inotify_event {
 #define IN_ALL_EVENTS  (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | \
             IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | \
             IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF | \
-            IN_MOVE_SELF)
+            IN_MOVE_SELF | IN_SYNC)

 /* Flags for sys_inotify_init1.  */
 #define IN_CLOEXEC O_CLOEXEC
diff --git a/mm/msync.c b/mm/msync.c
index 632df45..b1665ac 100644
--- a/mm/msync.c
+++ b/mm/msync.c
@@ -13,6 +13,7 @@
 #include <linux/file.h>
 #include <linux/syscalls.h>
 #include <linux/sched.h>
+#include <linux/fsnotify.h>

 /*
  * MS_SYNC syncs the entire file - including mappings.
@@ -83,6 +84,9 @@ SYSCALL_DEFINE3(msync, unsigned long, start, size_t, len, int, flags)
            get_file(file);
            up_read(&mm->mmap_sem);
            error = vfs_fsync(file, 0);
+               if (!error)
+                   fsnotify_sync(file->f_path.dentry);
+
            fput(file);
            if (error || start >= end)
                goto out;
-- 
1.8.2

补丁已经在 Linux Kernel v2.6.37 上测试过了。

于 2013-06-27T08:05:05.720 回答
1

您可以 mprotect RAM 中的相应页面(将其设置为只读)并在写入失败时捕获 SIGSEGV 信号。在信号处理程序中,您需要设置 RAM 读写以允许写入成功(这基本上是对用户空间中的页面错误作出反应)。然后,您需要重新保护 RAM 以检测下一次写入。

这是特定于体系结构(不可移植)的硬核 C 代码,但我过去做过(2001 年在 Intel Pentium 服务器上)。这是特定于 x86 的,所以我不确定如何使用 x86_64 执行此操作。如果需要的话,我可以在我的档案中做一些考古来引导你朝着正确的方向前进(发表评论,我会深入研究我的旧代码)。

于 2017-10-25T15:14:27.587 回答
0

唯一可能这样工作的是调试硬件观察点。

但是,如果你沿着那条路线走,你就做错了。

为了在线程之间共享内存,您需要实现适当的锁定和同步代码。因为您应该能够在内存解锁时添加更改通知。

于 2012-06-07T10:37:32.740 回答