1*0e32b8c5SMatthew Dillon /* 2*0e32b8c5SMatthew Dillon * Copyright (c) 2019 The DragonFly Project. All rights reserved. 3*0e32b8c5SMatthew Dillon * 4*0e32b8c5SMatthew Dillon * This code is derived from software contributed to The DragonFly Project 5*0e32b8c5SMatthew Dillon * by Matthew Dillon <dillon@backplane.com> 6*0e32b8c5SMatthew Dillon * 7*0e32b8c5SMatthew Dillon * Redistribution and use in source and binary forms, with or without 8*0e32b8c5SMatthew Dillon * modification, are permitted provided that the following conditions 9*0e32b8c5SMatthew Dillon * are met: 10*0e32b8c5SMatthew Dillon * 11*0e32b8c5SMatthew Dillon * 1. Redistributions of source code must retain the above copyright 12*0e32b8c5SMatthew Dillon * notice, this list of conditions and the following disclaimer. 13*0e32b8c5SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright 14*0e32b8c5SMatthew Dillon * notice, this list of conditions and the following disclaimer in 15*0e32b8c5SMatthew Dillon * the documentation and/or other materials provided with the 16*0e32b8c5SMatthew Dillon * distribution. 17*0e32b8c5SMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its 18*0e32b8c5SMatthew Dillon * contributors may be used to endorse or promote products derived 19*0e32b8c5SMatthew Dillon * from this software without specific, prior written permission. 20*0e32b8c5SMatthew Dillon * 21*0e32b8c5SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22*0e32b8c5SMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23*0e32b8c5SMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24*0e32b8c5SMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25*0e32b8c5SMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26*0e32b8c5SMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27*0e32b8c5SMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28*0e32b8c5SMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29*0e32b8c5SMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30*0e32b8c5SMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31*0e32b8c5SMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32*0e32b8c5SMatthew Dillon * SUCH DAMAGE. 33*0e32b8c5SMatthew Dillon */ 34*0e32b8c5SMatthew Dillon #include <sys/cdefs.h> 35*0e32b8c5SMatthew Dillon 36*0e32b8c5SMatthew Dillon #include <sys/condvar.h> 37*0e32b8c5SMatthew Dillon #include <sys/queue.h> 38*0e32b8c5SMatthew Dillon #include <sys/lock.h> 39*0e32b8c5SMatthew Dillon 40*0e32b8c5SMatthew Dillon #include <linux/compiler.h> 41*0e32b8c5SMatthew Dillon 42*0e32b8c5SMatthew Dillon #include <linux/atomic.h> 43*0e32b8c5SMatthew Dillon #include <linux/errno.h> 44*0e32b8c5SMatthew Dillon #include <linux/kref.h> 45*0e32b8c5SMatthew Dillon #include <linux/fence.h> 46*0e32b8c5SMatthew Dillon #include <linux/sched.h> 47*0e32b8c5SMatthew Dillon #include <linux/slab.h> 48*0e32b8c5SMatthew Dillon #include <linux/spinlock.h> 49*0e32b8c5SMatthew Dillon 50*0e32b8c5SMatthew Dillon /* 51*0e32b8c5SMatthew Dillon * Called when curthread->td_linux_task is NULL. We must allocated, initialize, 52*0e32b8c5SMatthew Dillon * and install a task_struct in td (the current thread). 53*0e32b8c5SMatthew Dillon * 54*0e32b8c5SMatthew Dillon * All threads belonging to the same process have a common mm_struct which 55*0e32b8c5SMatthew Dillon * is stored as p->p_linux_mm. This must be allocated, initialized, and 56*0e32b8c5SMatthew Dillon * and installed if necessary. 57*0e32b8c5SMatthew Dillon */ 58*0e32b8c5SMatthew Dillon struct task_struct * 59*0e32b8c5SMatthew Dillon linux_task_alloc(struct thread *td) 60*0e32b8c5SMatthew Dillon { 61*0e32b8c5SMatthew Dillon struct task_struct *task; 62*0e32b8c5SMatthew Dillon struct mm_struct *mm; 63*0e32b8c5SMatthew Dillon struct proc *p; 64*0e32b8c5SMatthew Dillon 65*0e32b8c5SMatthew Dillon task = kzalloc(sizeof(*task), GFP_KERNEL); 66*0e32b8c5SMatthew Dillon task->dfly_td = td; 67*0e32b8c5SMatthew Dillon 68*0e32b8c5SMatthew Dillon if ((p = td->td_proc) != NULL) { 69*0e32b8c5SMatthew Dillon if ((mm = p->p_linux_mm) == NULL) { 70*0e32b8c5SMatthew Dillon mm = kzalloc(sizeof(*mm), GFP_KERNEL); 71*0e32b8c5SMatthew Dillon mm->refs = 1; 72*0e32b8c5SMatthew Dillon lockinit(&mm->mmap_sem, "drmmms", 0, LK_CANRECURSE); 73*0e32b8c5SMatthew Dillon lwkt_gettoken(&p->p_token); 74*0e32b8c5SMatthew Dillon if (p->p_linux_mm == NULL) { 75*0e32b8c5SMatthew Dillon p->p_linux_mm = mm; 76*0e32b8c5SMatthew Dillon } else { 77*0e32b8c5SMatthew Dillon linux_mm_drop(mm); 78*0e32b8c5SMatthew Dillon mm = p->p_linux_mm; 79*0e32b8c5SMatthew Dillon } 80*0e32b8c5SMatthew Dillon lwkt_reltoken(&p->p_token); 81*0e32b8c5SMatthew Dillon } 82*0e32b8c5SMatthew Dillon task->mm = mm; 83*0e32b8c5SMatthew Dillon atomic_add_long(&mm->refs, 1); 84*0e32b8c5SMatthew Dillon } 85*0e32b8c5SMatthew Dillon td->td_linux_task = task; 86*0e32b8c5SMatthew Dillon 87*0e32b8c5SMatthew Dillon return task; 88*0e32b8c5SMatthew Dillon } 89*0e32b8c5SMatthew Dillon 90*0e32b8c5SMatthew Dillon /* 91*0e32b8c5SMatthew Dillon * Called at thread exit 92*0e32b8c5SMatthew Dillon */ 93*0e32b8c5SMatthew Dillon void 94*0e32b8c5SMatthew Dillon linux_task_drop(struct thread *td) 95*0e32b8c5SMatthew Dillon { 96*0e32b8c5SMatthew Dillon struct task_struct *task; 97*0e32b8c5SMatthew Dillon struct mm_struct *mm; 98*0e32b8c5SMatthew Dillon 99*0e32b8c5SMatthew Dillon task = td->td_linux_task; 100*0e32b8c5SMatthew Dillon td->td_linux_task = NULL; 101*0e32b8c5SMatthew Dillon if ((mm = task->mm) != NULL) { 102*0e32b8c5SMatthew Dillon atomic_add_long(&mm->refs, -1); /* proc ref always remains */ 103*0e32b8c5SMatthew Dillon task->mm = NULL; 104*0e32b8c5SMatthew Dillon } 105*0e32b8c5SMatthew Dillon kprintf("FREE TASK %p\n", task); 106*0e32b8c5SMatthew Dillon kfree(task); 107*0e32b8c5SMatthew Dillon } 108*0e32b8c5SMatthew Dillon 109*0e32b8c5SMatthew Dillon void 110*0e32b8c5SMatthew Dillon linux_proc_drop(struct proc *p) 111*0e32b8c5SMatthew Dillon { 112*0e32b8c5SMatthew Dillon struct mm_struct *mm; 113*0e32b8c5SMatthew Dillon 114*0e32b8c5SMatthew Dillon if ((mm = p->p_linux_mm) != NULL) { 115*0e32b8c5SMatthew Dillon p->p_linux_mm = NULL; 116*0e32b8c5SMatthew Dillon linux_mm_drop(mm); 117*0e32b8c5SMatthew Dillon } 118*0e32b8c5SMatthew Dillon } 119*0e32b8c5SMatthew Dillon 120*0e32b8c5SMatthew Dillon void 121*0e32b8c5SMatthew Dillon linux_mm_drop(struct mm_struct *mm) 122*0e32b8c5SMatthew Dillon { 123*0e32b8c5SMatthew Dillon long refs; 124*0e32b8c5SMatthew Dillon 125*0e32b8c5SMatthew Dillon refs = atomic_fetchadd_long(&mm->refs, -1); 126*0e32b8c5SMatthew Dillon KKASSERT(refs > 0); 127*0e32b8c5SMatthew Dillon if (refs == 1) { 128*0e32b8c5SMatthew Dillon lockuninit(&mm->mmap_sem); 129*0e32b8c5SMatthew Dillon kfree(mm); 130*0e32b8c5SMatthew Dillon kprintf("FREE MM %p\n", mm); 131*0e32b8c5SMatthew Dillon } 132*0e32b8c5SMatthew Dillon } 133