From: Josh Poimboeuf <jpoim...@kernel.org>

Associate an sframe section with its mm by adding it to a per-mm maple
tree which is indexed by the corresponding text address range.  A single
sframe section can be associated with multiple text ranges.

Cc: linux...@kvack.org
Signed-off-by: Josh Poimboeuf <jpoim...@kernel.org>
Signed-off-by: Steven Rostedt (Google) <rost...@goodmis.org>
---
 arch/x86/include/asm/mmu.h |  2 +-
 include/linux/mm_types.h   |  3 +++
 include/linux/sframe.h     | 13 +++++++++
 kernel/fork.c              | 10 +++++++
 kernel/unwind/sframe.c     | 55 +++++++++++++++++++++++++++++++++++---
 mm/init-mm.c               |  2 ++
 6 files changed, 81 insertions(+), 4 deletions(-)

diff --git a/arch/x86/include/asm/mmu.h b/arch/x86/include/asm/mmu.h
index 0fe9c569d171..227a32899a59 100644
--- a/arch/x86/include/asm/mmu.h
+++ b/arch/x86/include/asm/mmu.h
@@ -87,7 +87,7 @@ typedef struct {
        .context = {                                                    \
                .ctx_id = 1,                                            \
                .lock = __MUTEX_INITIALIZER(mm.context.lock),           \
-       }
+       },
 
 void leave_mm(void);
 #define leave_mm leave_mm
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index d6b91e8a66d6..4296cabf4afa 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -1206,6 +1206,9 @@ struct mm_struct {
 #ifdef CONFIG_MM_ID
                mm_id_t mm_id;
 #endif /* CONFIG_MM_ID */
+#ifdef CONFIG_HAVE_UNWIND_USER_SFRAME
+               struct maple_tree sframe_mt;
+#endif
        } __randomize_layout;
 
        /*
diff --git a/include/linux/sframe.h b/include/linux/sframe.h
index 0584f661f698..73bf6f0b30c2 100644
--- a/include/linux/sframe.h
+++ b/include/linux/sframe.h
@@ -22,18 +22,31 @@ struct sframe_section {
        signed char     fp_off;
 };
 
+#define INIT_MM_SFRAME .sframe_mt = MTREE_INIT(sframe_mt, 0),
+extern void sframe_free_mm(struct mm_struct *mm);
+
 extern int sframe_add_section(unsigned long sframe_start, unsigned long 
sframe_end,
                              unsigned long text_start, unsigned long text_end);
 extern int sframe_remove_section(unsigned long sframe_addr);
 
+static inline bool current_has_sframe(void)
+{
+       struct mm_struct *mm = current->mm;
+
+       return mm && !mtree_empty(&mm->sframe_mt);
+}
+
 #else /* !CONFIG_HAVE_UNWIND_USER_SFRAME */
 
+#define INIT_MM_SFRAME
+static inline void sframe_free_mm(struct mm_struct *mm) {}
 static inline int sframe_add_section(unsigned long sframe_start, unsigned long 
sframe_end,
                                     unsigned long text_start, unsigned long 
text_end)
 {
        return -ENOSYS;
 }
 static inline int sframe_remove_section(unsigned long sframe_addr) { return 
-ENOSYS; }
+static inline bool current_has_sframe(void) { return false; }
 
 #endif /* CONFIG_HAVE_UNWIND_USER_SFRAME */
 
diff --git a/kernel/fork.c b/kernel/fork.c
index 3341d50c61f2..e56daf4e546f 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -106,6 +106,7 @@
 #include <linux/pidfs.h>
 #include <linux/tick.h>
 #include <linux/unwind_deferred.h>
+#include <linux/sframe.h>
 
 #include <asm/pgalloc.h>
 #include <linux/uaccess.h>
@@ -687,6 +688,7 @@ void __mmdrop(struct mm_struct *mm)
        mm_pasid_drop(mm);
        mm_destroy_cid(mm);
        percpu_counter_destroy_many(mm->rss_stat, NR_MM_COUNTERS);
+       sframe_free_mm(mm);
 
        free_mm(mm);
 }
@@ -1024,6 +1026,13 @@ static void mmap_init_lock(struct mm_struct *mm)
 #endif
 }
 
+static void mm_init_sframe(struct mm_struct *mm)
+{
+#ifdef CONFIG_HAVE_UNWIND_USER_SFRAME
+       mt_init(&mm->sframe_mt);
+#endif
+}
+
 static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
        struct user_namespace *user_ns)
 {
@@ -1053,6 +1062,7 @@ static struct mm_struct *mm_init(struct mm_struct *mm, 
struct task_struct *p,
        mm->pmd_huge_pte = NULL;
 #endif
        mm_init_uprobes_state(mm);
+       mm_init_sframe(mm);
        hugetlb_count_init(mm);
 
        if (current->mm) {
diff --git a/kernel/unwind/sframe.c b/kernel/unwind/sframe.c
index 20287f795b36..fa7d87ffd00a 100644
--- a/kernel/unwind/sframe.c
+++ b/kernel/unwind/sframe.c
@@ -122,15 +122,64 @@ int sframe_add_section(unsigned long sframe_start, 
unsigned long sframe_end,
        if (ret)
                goto err_free;
 
-       /* TODO nowhere to store it yet - just free it and return an error */
-       ret = -ENOSYS;
+       ret = mtree_insert_range(sframe_mt, sec->text_start, sec->text_end, 
sec, GFP_KERNEL);
+       if (ret) {
+               dbg("mtree_insert_range failed: text=%lx-%lx\n",
+                   sec->text_start, sec->text_end);
+               goto err_free;
+       }
+
+       return 0;
 
 err_free:
        free_section(sec);
        return ret;
 }
 
+static int __sframe_remove_section(struct mm_struct *mm,
+                                  struct sframe_section *sec)
+{
+       if (!mtree_erase(&mm->sframe_mt, sec->text_start)) {
+               dbg("mtree_erase failed: text=%lx\n", sec->text_start);
+               return -EINVAL;
+       }
+
+       free_section(sec);
+
+       return 0;
+}
+
 int sframe_remove_section(unsigned long sframe_start)
 {
-       return -ENOSYS;
+       struct mm_struct *mm = current->mm;
+       struct sframe_section *sec;
+       unsigned long index = 0;
+       bool found = false;
+       int ret = 0;
+
+       mt_for_each(&mm->sframe_mt, sec, index, ULONG_MAX) {
+               if (sec->sframe_start == sframe_start) {
+                       found = true;
+                       ret |= __sframe_remove_section(mm, sec);
+               }
+       }
+
+       if (!found || ret)
+               return -EINVAL;
+
+       return 0;
+}
+
+void sframe_free_mm(struct mm_struct *mm)
+{
+       struct sframe_section *sec;
+       unsigned long index = 0;
+
+       if (!mm)
+               return;
+
+       mt_for_each(&mm->sframe_mt, sec, index, ULONG_MAX)
+               free_section(sec);
+
+       mtree_destroy(&mm->sframe_mt);
 }
diff --git a/mm/init-mm.c b/mm/init-mm.c
index 4600e7605cab..b32fcf167cc2 100644
--- a/mm/init-mm.c
+++ b/mm/init-mm.c
@@ -11,6 +11,7 @@
 #include <linux/atomic.h>
 #include <linux/user_namespace.h>
 #include <linux/iommu.h>
+#include <linux/sframe.h>
 #include <asm/mmu.h>
 
 #ifndef INIT_MM_CONTEXT
@@ -46,6 +47,7 @@ struct mm_struct init_mm = {
        .user_ns        = &init_user_ns,
        .cpu_bitmap     = CPU_BITS_NONE,
        INIT_MM_CONTEXT(init_mm)
+       INIT_MM_SFRAME
 };
 
 void setup_initial_init_mm(void *start_code, void *end_code,
-- 
2.47.2



Reply via email to