diff options
-rw-r--r-- | arch/x86/kernel/ptrace.c | 45 | ||||
-rw-r--r-- | include/linux/mm.h | 2 | ||||
-rw-r--r-- | mm/mlock.c | 45 |
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 | ||
653 | static 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 | |||
664 | static 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 | |||
653 | static int ptrace_bts_config(struct task_struct *child, | 671 | static 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 | ||
793 | static void ptrace_bts_detach(struct task_struct *child) | 811 | static 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 |
798 | static inline void ptrace_bts_fork(struct task_struct *tsk) {} | 821 | static 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, | |||
1286 | int vmemmap_populate(struct page *start_page, unsigned long pages, int node); | 1286 | int vmemmap_populate(struct page *start_page, unsigned long pages, int node); |
1287 | void vmemmap_populate_print_last(void); | 1287 | void vmemmap_populate_print_last(void); |
1288 | 1288 | ||
1289 | extern void *alloc_locked_buffer(size_t size); | ||
1290 | extern 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 | |||
671 | void *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(¤t->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(¤t->mm->mmap_sem); | ||
699 | return buffer; | ||
700 | } | ||
701 | |||
702 | void free_locked_buffer(void *buffer, size_t size) | ||
703 | { | ||
704 | unsigned long pgsz = PAGE_ALIGN(size) >> PAGE_SHIFT; | ||
705 | |||
706 | down_write(¤t->mm->mmap_sem); | ||
707 | |||
708 | current->mm->total_vm -= pgsz; | ||
709 | current->mm->locked_vm -= pgsz; | ||
710 | |||
711 | up_write(¤t->mm->mmap_sem); | ||
712 | |||
713 | kfree(buffer); | ||
714 | } | ||