Improvements to set_user_ldt().
Remove mtx_owned() checks from set_user_ldt(). Split the function into _locked() version which requires the dt_lock spinlock owned, and make set_user_ldt() a wrapper. Add a comment in swtch.s noting that the call to the new set_user_ldt() cannot recurse on dt_lock. Remove #ifdef SMP block, the addend is always zero on UP. Fix type of set_user_ldt_rv(), making it match the type used for smb_rendezvous() callback, and remove the cast. Use curproc. Reviewed by: bde Sponsored by: The FreeBSD Foundation MFC after: 1 week
This commit is contained in:
parent
354dc2dc84
commit
13a5d9112c
@ -279,6 +279,10 @@ sw1:
|
||||
pushl %edx /* Preserve pointer to pcb. */
|
||||
addl $P_MD,%eax /* Pointer to mdproc is arg. */
|
||||
pushl %eax
|
||||
/*
|
||||
* Holding dt_lock prevents context switches, so dt_lock cannot
|
||||
* be held now and set_user_ldt() will not deadlock acquiring it.
|
||||
*/
|
||||
call set_user_ldt
|
||||
addl $4,%esp
|
||||
popl %edx
|
||||
|
@ -69,10 +69,10 @@ __FBSDID("$FreeBSD$");
|
||||
#define NULL_LDT_BASE ((caddr_t)NULL)
|
||||
|
||||
#ifdef SMP
|
||||
static void set_user_ldt_rv(struct vmspace *vmsp);
|
||||
static void set_user_ldt_rv(void *arg);
|
||||
#endif
|
||||
static int i386_set_ldt_data(struct thread *, int start, int num,
|
||||
union descriptor *descs);
|
||||
union descriptor *descs);
|
||||
static int i386_ldt_grow(struct thread *td, int len);
|
||||
|
||||
void
|
||||
@ -405,41 +405,40 @@ i386_get_ioperm(td, uap)
|
||||
* Update the GDT entry pointing to the LDT to point to the LDT of the
|
||||
* current process. Manage dt_lock holding/unholding autonomously.
|
||||
*/
|
||||
static void
|
||||
set_user_ldt_locked(struct mdproc *mdp)
|
||||
{
|
||||
struct proc_ldt *pldt;
|
||||
int gdt_idx;
|
||||
|
||||
mtx_assert(&dt_lock, MA_OWNED);
|
||||
|
||||
pldt = mdp->md_ldt;
|
||||
gdt_idx = GUSERLDT_SEL;
|
||||
gdt_idx += PCPU_GET(cpuid) * NGDT; /* always 0 on UP */
|
||||
gdt[gdt_idx].sd = pldt->ldt_sd;
|
||||
lldt(GSEL(GUSERLDT_SEL, SEL_KPL));
|
||||
PCPU_SET(currentldt, GSEL(GUSERLDT_SEL, SEL_KPL));
|
||||
}
|
||||
|
||||
void
|
||||
set_user_ldt(struct mdproc *mdp)
|
||||
{
|
||||
struct proc_ldt *pldt;
|
||||
int dtlocked;
|
||||
|
||||
dtlocked = 0;
|
||||
if (!mtx_owned(&dt_lock)) {
|
||||
mtx_lock_spin(&dt_lock);
|
||||
dtlocked = 1;
|
||||
}
|
||||
|
||||
pldt = mdp->md_ldt;
|
||||
#ifdef SMP
|
||||
gdt[PCPU_GET(cpuid) * NGDT + GUSERLDT_SEL].sd = pldt->ldt_sd;
|
||||
#else
|
||||
gdt[GUSERLDT_SEL].sd = pldt->ldt_sd;
|
||||
#endif
|
||||
lldt(GSEL(GUSERLDT_SEL, SEL_KPL));
|
||||
PCPU_SET(currentldt, GSEL(GUSERLDT_SEL, SEL_KPL));
|
||||
if (dtlocked)
|
||||
mtx_unlock_spin(&dt_lock);
|
||||
mtx_lock_spin(&dt_lock);
|
||||
set_user_ldt_locked(mdp);
|
||||
mtx_unlock_spin(&dt_lock);
|
||||
}
|
||||
|
||||
#ifdef SMP
|
||||
static void
|
||||
set_user_ldt_rv(struct vmspace *vmsp)
|
||||
set_user_ldt_rv(void *arg)
|
||||
{
|
||||
struct thread *td;
|
||||
struct proc *p;
|
||||
|
||||
td = curthread;
|
||||
if (vmsp != td->td_proc->p_vmspace)
|
||||
return;
|
||||
|
||||
set_user_ldt(&td->td_proc->p_md);
|
||||
p = curproc;
|
||||
if (arg == p->p_vmspace)
|
||||
set_user_ldt(&p->p_md);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -796,10 +795,10 @@ i386_ldt_grow(struct thread *td, int len)
|
||||
* to acquire it.
|
||||
*/
|
||||
mtx_unlock_spin(&dt_lock);
|
||||
smp_rendezvous(NULL, (void (*)(void *))set_user_ldt_rv,
|
||||
NULL, td->td_proc->p_vmspace);
|
||||
smp_rendezvous(NULL, set_user_ldt_rv, NULL,
|
||||
td->td_proc->p_vmspace);
|
||||
#else
|
||||
set_user_ldt(&td->td_proc->p_md);
|
||||
set_user_ldt_locked(&td->td_proc->p_md);
|
||||
mtx_unlock_spin(&dt_lock);
|
||||
#endif
|
||||
if (old_ldt_base != NULL_LDT_BASE) {
|
||||
|
Loading…
Reference in New Issue
Block a user