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:
Konstantin Belousov 2017-10-09 16:07:27 +00:00
parent 354dc2dc84
commit 13a5d9112c
2 changed files with 33 additions and 30 deletions

View File

@ -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

View File

@ -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) {