When a process is forked, all the buffers are shared with the forked
process too. Adds the functionality to add memtrack accounting for the
forked processes.

Forked process gets a copy of the mapped pages of the parent process.
This patch makes sure that the new mapped pages are attributed to the
child process instead of the parent.

Signed-off-by: Ruchi Kandoi <kandoiru...@google.com>
---
 drivers/misc/memtrack.c           | 45 +++++++++++++++++++++++++++++++++++----
 drivers/staging/android/ion/ion.c | 45 +++++++++++++++++++++++++++++++++++++--
 include/linux/memtrack.h          | 19 +++++++++++------
 include/linux/mm.h                |  3 +++
 kernel/fork.c                     | 19 +++++++++++++++--
 5 files changed, 117 insertions(+), 14 deletions(-)

diff --git a/drivers/misc/memtrack.c b/drivers/misc/memtrack.c
index 4b2d17f..fa2601a 100644
--- a/drivers/misc/memtrack.c
+++ b/drivers/misc/memtrack.c
@@ -204,12 +204,13 @@ EXPORT_SYMBOL(memtrack_buffer_uninstall);
  * @buffer: the buffer's memtrack entry
  *
  * @vma: vma being opened
+ * @task: task which mapped the pages
  */
 void memtrack_buffer_vm_open(struct memtrack_buffer *buffer,
-               const struct vm_area_struct *vma)
+               const struct vm_area_struct *vma, struct task_struct *task)
 {
        unsigned long flags;
-       struct task_struct *leader = current->group_leader;
+       struct task_struct *leader = task->group_leader;
        struct memtrack_vma_list *vma_list;
 
        vma_list = kmalloc(sizeof(*vma_list), GFP_KERNEL);
@@ -228,12 +229,13 @@ EXPORT_SYMBOL(memtrack_buffer_vm_open);
  *
  * @buffer: the buffer's memtrack entry
  * @vma: the vma being closed
+ * @task: task that mmaped the pages
  */
 void memtrack_buffer_vm_close(struct memtrack_buffer *buffer,
-               const struct vm_area_struct *vma)
+               const struct vm_area_struct *vma, struct task_struct *task)
 {
        unsigned long flags;
-       struct task_struct *leader = current->group_leader;
+       struct task_struct *leader = task->group_leader;
 
        write_lock_irqsave(&leader->memtrack_lock, flags);
        memtrack_buffer_vm_close_locked(&leader->memtrack_rb, buffer, vma);
@@ -241,6 +243,41 @@ void memtrack_buffer_vm_close(struct memtrack_buffer 
*buffer,
 }
 EXPORT_SYMBOL(memtrack_buffer_vm_close);
 
+/**
+ * memtrack_buffer_install_fork - Install all parent's handles into
+ *  child.
+ *
+ * @parent: parent task
+ * @child: child task
+ */
+void memtrack_buffer_install_fork(struct task_struct *parent,
+               struct task_struct *child)
+{
+       struct task_struct *leader, *leader_child;
+       struct rb_root *root;
+       struct rb_node *node;
+       unsigned long flags;
+
+       if (!child || !parent)
+               return;
+
+       leader = parent->group_leader;
+       leader_child = child->group_leader;
+       write_lock_irqsave(&leader->memtrack_lock, flags);
+       root = &leader->memtrack_rb;
+       node = rb_first(root);
+       while (node) {
+               struct memtrack_handle *handle;
+
+               handle = rb_entry(node, struct memtrack_handle, node);
+               memtrack_buffer_install_locked(&leader_child->memtrack_rb,
+                               handle->buffer);
+               node = rb_next(node);
+       }
+       write_unlock_irqrestore(&leader->memtrack_lock, flags);
+}
+EXPORT_SYMBOL(memtrack_buffer_install_fork);
+
 static int memtrack_id_alloc(struct memtrack_buffer *buffer)
 {
        int ret;
diff --git a/drivers/staging/android/ion/ion.c 
b/drivers/staging/android/ion/ion.c
index c32d520..451aa0f 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -906,7 +906,7 @@ static void ion_vm_open(struct vm_area_struct *vma)
        list_add(&vma_list->list, &buffer->vmas);
        mutex_unlock(&buffer->lock);
        pr_debug("%s: adding %p\n", __func__, vma);
-       memtrack_buffer_vm_open(&buffer->memtrack_buffer, vma);
+       memtrack_buffer_vm_open(&buffer->memtrack_buffer, vma, current);
 }
 
 static void ion_vm_close(struct vm_area_struct *vma)
@@ -925,13 +925,51 @@ static void ion_vm_close(struct vm_area_struct *vma)
                break;
        }
        mutex_unlock(&buffer->lock);
-       memtrack_buffer_vm_close(&buffer->memtrack_buffer, vma);
+       memtrack_buffer_vm_close(&buffer->memtrack_buffer, vma, current);
+}
+
+void vm_track(struct vm_area_struct *vma, struct task_struct *task)
+{
+       struct ion_buffer *buffer = vma->vm_private_data;
+
+       memtrack_buffer_vm_open(&buffer->memtrack_buffer, vma, task);
+}
+
+void vm_untrack(struct vm_area_struct *vma, struct task_struct *task)
+{
+       struct ion_buffer *buffer = vma->vm_private_data;
+
+       memtrack_buffer_vm_close(&buffer->memtrack_buffer, vma, task);
 }
 
 static const struct vm_operations_struct ion_vma_ops = {
        .open = ion_vm_open,
        .close = ion_vm_close,
        .fault = ion_vm_fault,
+       .track = vm_track,
+       .untrack = vm_untrack,
+};
+
+static void memtrack_vm_close(struct vm_area_struct *vma)
+{
+       struct ion_buffer *buffer = vma->vm_private_data;
+
+       memtrack_buffer_vm_close(&buffer->memtrack_buffer, vma, current);
+}
+
+static void memtrack_vm_open(struct vm_area_struct *vma)
+{
+       struct ion_buffer *buffer = vma->vm_private_data;
+
+       memtrack_buffer_vm_open(&buffer->memtrack_buffer, vma, current);
+}
+
+static struct vm_operations_struct memtrack_vma_ops = {
+       .open = memtrack_vm_open,
+       .close = memtrack_vm_close,
+       .fault = NULL,
+       .track = vm_track,
+       .untrack = vm_untrack,
 };
 
 static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
@@ -952,6 +990,9 @@ static int ion_mmap(struct dma_buf *dmabuf, struct 
vm_area_struct *vma)
                vma->vm_ops = &ion_vma_ops;
                ion_vm_open(vma);
                return 0;
+       } else {
+               vma->vm_private_data = buffer;
+               vma->vm_ops = &memtrack_vma_ops;
        }
 
        if (!(buffer->flags & ION_FLAG_CACHED))
diff --git a/include/linux/memtrack.h b/include/linux/memtrack.h
index 5a4c7ea..4595fb0 100644
--- a/include/linux/memtrack.h
+++ b/include/linux/memtrack.h
@@ -41,10 +41,12 @@ void memtrack_buffer_install(struct memtrack_buffer *buffer,
                struct task_struct *tsk);
 void memtrack_buffer_uninstall(struct memtrack_buffer *buffer,
                struct task_struct *tsk);
+void memtrack_buffer_install_fork(struct task_struct *parent,
+               struct task_struct *child);
 void memtrack_buffer_vm_open(struct memtrack_buffer *buffer,
-               const struct vm_area_struct *vma);
+               const struct vm_area_struct *vma, struct task_struct *task);
 void memtrack_buffer_vm_close(struct memtrack_buffer *buffer,
-               const struct vm_area_struct *vma);
+               const struct vm_area_struct *vma, struct task_struct *task);
 
 /**
  * memtrack_buffer_set_tag - add a descriptive tag to a memtrack entry
@@ -90,6 +92,11 @@ static inline void memtrack_buffer_uninstall(struct 
memtrack_buffer *buffer,
 {
 }
 
+static inline void memtrack_buffer_install_fork(struct task_struct *parent,
+               struct task_struct *child)
+{
+}
+
 static inline int memtrack_buffer_set_tag(struct memtrack_buffer *buffer,
                const char *tag)
 {
@@ -97,12 +104,12 @@ static inline int memtrack_buffer_set_tag(struct 
memtrack_buffer *buffer,
 }
 
 static inline void memtrack_buffer_vm_open(struct memtrack_buffer *buffer,
-               const struct vm_area_struct *vma)
+               const struct vm_area_struct *vma, struct task_struct *task)
 {
 }
 
 static inline void memtrack_buffer_vm_close(struct memtrack_buffer *buffer,
-               const struct vm_area_struct *vma)
+               const struct vm_area_struct *vma, struct task_struct *task)
 {
 }
 #endif /* CONFIG_MEMTRACK */
@@ -115,9 +122,9 @@ static inline void memtrack_buffer_vm_close(struct 
memtrack_buffer *buffer,
  * @vma: the vma passed to mmap()
  */
 static inline void memtrack_buffer_mmap(struct memtrack_buffer *buffer,
-               const struct vm_area_struct *vma)
+               struct vm_area_struct *vma)
 {
-       memtrack_buffer_vm_open(buffer, vma);
+       memtrack_buffer_vm_open(buffer, vma, current);
 }
 
 #endif /* _MEMTRACK_ */
diff --git a/include/linux/mm.h b/include/linux/mm.h
index e9caec6..619ea7f 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -402,6 +402,9 @@ struct vm_operations_struct {
         */
        struct page *(*find_special_page)(struct vm_area_struct *vma,
                                          unsigned long addr);
+
+       void (*track)(struct vm_area_struct *vma, struct task_struct *task);
+       void (*untrack)(struct vm_area_struct *vma, struct task_struct *task);
 };
 
 struct mmu_gather;
diff --git a/kernel/fork.c b/kernel/fork.c
index da8537a..43a2e73 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -76,6 +76,7 @@
 #include <linux/compiler.h>
 #include <linux/sysctl.h>
 #include <linux/kcov.h>
+#include <linux/memtrack.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -547,7 +548,8 @@ static struct task_struct *dup_task_struct(struct 
task_struct *orig, int node)
 }
 
 #ifdef CONFIG_MMU
-static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
+static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm,
+               struct task_struct *tsk)
 {
        struct vm_area_struct *mpnt, *tmp, *prev, **pprev;
        struct rb_node **rb_link, *rb_parent;
@@ -660,6 +662,11 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct 
*oldmm)
                if (tmp->vm_ops && tmp->vm_ops->open)
                        tmp->vm_ops->open(tmp);
 
+               if (tmp->vm_ops && tmp->vm_ops->track && tmp->vm_ops->untrack) {
+                       tmp->vm_ops->untrack(tmp, current);
+                       tmp->vm_ops->track(tmp, tsk);
+               }
+
                if (retval)
                        goto out;
        }
@@ -1125,7 +1132,7 @@ static struct mm_struct *dup_mm(struct task_struct *tsk)
        if (!mm_init(mm, tsk))
                goto fail_nomem;
 
-       err = dup_mmap(mm, oldmm);
+       err = dup_mmap(mm, oldmm, tsk);
        if (err)
                goto free_pt;
 
@@ -1235,6 +1242,12 @@ static int copy_files(unsigned long clone_flags, struct 
task_struct *tsk)
 
        tsk->files = newf;
        error = 0;
+#ifdef CONFIG_MEMTRACK
+       if (!(clone_flags & CLONE_THREAD)) {
+               tsk->group_leader = tsk;
+               memtrack_buffer_install_fork(current, tsk);
+       }
+#endif
 out:
        return error;
 }
@@ -2153,6 +2166,8 @@ static int unshare_fd(unsigned long unshare_flags, struct 
files_struct **new_fdp
                *new_fdp = dup_fd(fd, &error);
                if (!*new_fdp)
                        return error;
+
+               memtrack_buffer_install_fork(current->parent, current);
        }
 
        return 0;
-- 
2.8.0.rc3.226.g39d4020

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to