aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/ptrace.c45
-rw-r--r--include/linux/mm.h2
-rw-r--r--mm/mlock.c45
3 files changed, 81 insertions, 11 deletions
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 6ad2bb607650..0a5df5f82fb9 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -650,6 +650,24 @@ static int ptrace_bts_drain(struct task_struct *child,
650 return drained; 650 return drained;
651} 651}
652 652
653static int ptrace_bts_allocate_buffer(struct task_struct *child, size_t size)
654{
655 child->bts_buffer = alloc_locked_buffer(size);
656 if (!child->bts_buffer)
657 return -ENOMEM;
658
659 child->bts_size = size;
660
661 return 0;
662}
663
664static void ptrace_bts_free_buffer(struct task_struct *child)
665{
666 free_locked_buffer(child->bts_buffer, child->bts_size);
667 child->bts_buffer = NULL;
668 child->bts_size = 0;
669}
670
653static int ptrace_bts_config(struct task_struct *child, 671static int ptrace_bts_config(struct task_struct *child,
654 long cfg_size, 672 long cfg_size,
655 const struct ptrace_bts_config __user *ucfg) 673 const struct ptrace_bts_config __user *ucfg)
@@ -679,14 +697,13 @@ static int ptrace_bts_config(struct task_struct *child,
679 697
680 if ((cfg.flags & PTRACE_BTS_O_ALLOC) && 698 if ((cfg.flags & PTRACE_BTS_O_ALLOC) &&
681 (cfg.size != child->bts_size)) { 699 (cfg.size != child->bts_size)) {
682 kfree(child->bts_buffer); 700 int error;
683 701
684 child->bts_size = cfg.size; 702 ptrace_bts_free_buffer(child);
685 child->bts_buffer = kzalloc(cfg.size, GFP_KERNEL); 703
686 if (!child->bts_buffer) { 704 error = ptrace_bts_allocate_buffer(child, cfg.size);
687 child->bts_size = 0; 705 if (error < 0)
688 return -ENOMEM; 706 return error;
689 }
690 } 707 }
691 708
692 if (cfg.flags & PTRACE_BTS_O_TRACE) 709 if (cfg.flags & PTRACE_BTS_O_TRACE)
@@ -701,10 +718,8 @@ static int ptrace_bts_config(struct task_struct *child,
701 if (IS_ERR(child->bts)) { 718 if (IS_ERR(child->bts)) {
702 int error = PTR_ERR(child->bts); 719 int error = PTR_ERR(child->bts);
703 720
704 kfree(child->bts_buffer); 721 ptrace_bts_free_buffer(child);
705 child->bts = NULL; 722 child->bts = NULL;
706 child->bts_buffer = NULL;
707 child->bts_size = 0;
708 723
709 return error; 724 return error;
710 } 725 }
@@ -784,6 +799,9 @@ static void ptrace_bts_untrace(struct task_struct *child)
784 ds_release_bts(child->bts); 799 ds_release_bts(child->bts);
785 child->bts = NULL; 800 child->bts = NULL;
786 801
802 /* We cannot update total_vm and locked_vm since
803 child's mm is already gone. But we can reclaim the
804 memory. */
787 kfree(child->bts_buffer); 805 kfree(child->bts_buffer);
788 child->bts_buffer = NULL; 806 child->bts_buffer = NULL;
789 child->bts_size = 0; 807 child->bts_size = 0;
@@ -792,7 +810,12 @@ static void ptrace_bts_untrace(struct task_struct *child)
792 810
793static void ptrace_bts_detach(struct task_struct *child) 811static void ptrace_bts_detach(struct task_struct *child)
794{ 812{
795 ptrace_bts_untrace(child); 813 if (unlikely(child->bts)) {
814 ds_release_bts(child->bts);
815 child->bts = NULL;
816
817 ptrace_bts_free_buffer(child);
818 }
796} 819}
797#else 820#else
798static inline void ptrace_bts_fork(struct task_struct *tsk) {} 821static inline void ptrace_bts_fork(struct task_struct *tsk) {}
diff --git a/include/linux/mm.h b/include/linux/mm.h
index ffee2f743418..9979d3fab6e7 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1286,5 +1286,7 @@ int vmemmap_populate_basepages(struct page *start_page,
1286int vmemmap_populate(struct page *start_page, unsigned long pages, int node); 1286int vmemmap_populate(struct page *start_page, unsigned long pages, int node);
1287void vmemmap_populate_print_last(void); 1287void vmemmap_populate_print_last(void);
1288 1288
1289extern void *alloc_locked_buffer(size_t size);
1290extern void free_locked_buffer(void *buffer, size_t size);
1289#endif /* __KERNEL__ */ 1291#endif /* __KERNEL__ */
1290#endif /* _LINUX_MM_H */ 1292#endif /* _LINUX_MM_H */
diff --git a/mm/mlock.c b/mm/mlock.c
index 1ada366570cb..3035a56e7616 100644
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -667,3 +667,48 @@ void user_shm_unlock(size_t size, struct user_struct *user)
667 spin_unlock(&shmlock_user_lock); 667 spin_unlock(&shmlock_user_lock);
668 free_uid(user); 668 free_uid(user);
669} 669}
670
671void *alloc_locked_buffer(size_t size)
672{
673 unsigned long rlim, vm, pgsz;
674 void *buffer = NULL;
675
676 pgsz = PAGE_ALIGN(size) >> PAGE_SHIFT;
677
678 down_write(&current->mm->mmap_sem);
679
680 rlim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT;
681 vm = current->mm->total_vm + pgsz;
682 if (rlim < vm)
683 goto out;
684
685 rlim = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
686 vm = current->mm->locked_vm + pgsz;
687 if (rlim < vm)
688 goto out;
689
690 buffer = kzalloc(size, GFP_KERNEL);
691 if (!buffer)
692 goto out;
693
694 current->mm->total_vm += pgsz;
695 current->mm->locked_vm += pgsz;
696
697 out:
698 up_write(&current->mm->mmap_sem);
699 return buffer;
700}
701
702void free_locked_buffer(void *buffer, size_t size)
703{
704 unsigned long pgsz = PAGE_ALIGN(size) >> PAGE_SHIFT;
705
706 down_write(&current->mm->mmap_sem);
707
708 current->mm->total_vm -= pgsz;
709 current->mm->locked_vm -= pgsz;
710
711 up_write(&current->mm->mmap_sem);
712
713 kfree(buffer);
714}