userfaultfd: non-cooperative: add event for exit() notification
authorMike Rapoport <rppt@linux.vnet.ibm.com>
Fri, 24 Feb 2017 22:58:25 +0000 (14:58 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 25 Feb 2017 01:46:55 +0000 (17:46 -0800)
Allow userfaultfd monitor track termination of the processes that have
memory backed by the uffd.

[rppt@linux.vnet.ibm.com: add comment]
Link: http://lkml.kernel.org/r/20170202135448.GB19804@rapoport-lnxLink:
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Acked-by: Hillf Danton <hillf.zj@alibaba-inc.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
Cc: Mike Kravetz <mike.kravetz@oracle.com>
Cc: Pavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
fs/userfaultfd.c
include/linux/userfaultfd_k.h
include/uapi/linux/userfaultfd.h
kernel/exit.c

index 4c78458ea78df4567c0910af343f1a0a9499eae8..b676575f226884342e72a7bfe4e2099f3efb8003 100644 (file)
@@ -774,6 +774,34 @@ void userfaultfd_unmap_complete(struct mm_struct *mm, struct list_head *uf)
        }
 }
 
+void userfaultfd_exit(struct mm_struct *mm)
+{
+       struct vm_area_struct *vma = mm->mmap;
+
+       /*
+        * We can do the vma walk without locking because the caller
+        * (exit_mm) knows it now has exclusive access
+        */
+       while (vma) {
+               struct userfaultfd_ctx *ctx = vma->vm_userfaultfd_ctx.ctx;
+
+               if (ctx && (ctx->features & UFFD_FEATURE_EVENT_EXIT)) {
+                       struct userfaultfd_wait_queue ewq;
+
+                       userfaultfd_ctx_get(ctx);
+
+                       msg_init(&ewq.msg);
+                       ewq.msg.event = UFFD_EVENT_EXIT;
+
+                       userfaultfd_event_wait_completion(ctx, &ewq);
+
+                       ctx->features &= ~UFFD_FEATURE_EVENT_EXIT;
+               }
+
+               vma = vma->vm_next;
+       }
+}
+
 static int userfaultfd_release(struct inode *inode, struct file *file)
 {
        struct userfaultfd_ctx *ctx = file->private_data;
index a40be5d0661b210ac6b0360ddfa0896aa03a97da..0468548acebfef5431ea7bfd6f565cfdfb73f348 100644 (file)
@@ -72,6 +72,8 @@ extern int userfaultfd_unmap_prep(struct vm_area_struct *vma,
 extern void userfaultfd_unmap_complete(struct mm_struct *mm,
                                       struct list_head *uf);
 
+extern void userfaultfd_exit(struct mm_struct *mm);
+
 #else /* CONFIG_USERFAULTFD */
 
 /* mm helpers */
@@ -136,6 +138,11 @@ static inline void userfaultfd_unmap_complete(struct mm_struct *mm,
                                              struct list_head *uf)
 {
 }
+
+static inline void userfaultfd_exit(struct mm_struct *mm)
+{
+}
+
 #endif /* CONFIG_USERFAULTFD */
 
 #endif /* _LINUX_USERFAULTFD_K_H */
index 3b059530dac95fa6e5dcf736e95a84fe80eb5f35..c055947c5c989fa7e399a7b0dcaba8640014b548 100644 (file)
@@ -18,7 +18,8 @@
  * means the userland is reading).
  */
 #define UFFD_API ((__u64)0xAA)
-#define UFFD_API_FEATURES (UFFD_FEATURE_EVENT_FORK |           \
+#define UFFD_API_FEATURES (UFFD_FEATURE_EVENT_EXIT |           \
+                          UFFD_FEATURE_EVENT_FORK |            \
                           UFFD_FEATURE_EVENT_REMAP |           \
                           UFFD_FEATURE_EVENT_REMOVE |  \
                           UFFD_FEATURE_EVENT_UNMAP |           \
@@ -112,6 +113,7 @@ struct uffd_msg {
 #define UFFD_EVENT_REMAP       0x14
 #define UFFD_EVENT_REMOVE      0x15
 #define UFFD_EVENT_UNMAP       0x16
+#define UFFD_EVENT_EXIT                0x17
 
 /* flags for UFFD_EVENT_PAGEFAULT */
 #define UFFD_PAGEFAULT_FLAG_WRITE      (1<<0)  /* If this was a write fault */
@@ -161,6 +163,7 @@ struct uffdio_api {
 #define UFFD_FEATURE_MISSING_HUGETLBFS         (1<<4)
 #define UFFD_FEATURE_MISSING_SHMEM             (1<<5)
 #define UFFD_FEATURE_EVENT_UNMAP               (1<<6)
+#define UFFD_FEATURE_EVENT_EXIT                        (1<<7)
        __u64 features;
 
        __u64 ioctls;
index 9960accbf2ab0863643a5ee38b0040043f424d20..90b09ca35c849b2a6421dd2dc717d7f58dc3a71b 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/task_io_accounting_ops.h>
 #include <linux/tracehook.h>
 #include <linux/fs_struct.h>
+#include <linux/userfaultfd_k.h>
 #include <linux/init_task.h>
 #include <linux/perf_event.h>
 #include <trace/events/sched.h>
@@ -547,6 +548,7 @@ static void exit_mm(void)
        enter_lazy_tlb(mm, current);
        task_unlock(current);
        mm_update_next_owner(mm);
+       userfaultfd_exit(mm);
        mmput(mm);
        if (test_thread_flag(TIF_MEMDIE))
                exit_oom_victim();