On 24/09/20(Thu) 16:35, Mark Kettenis wrote:
> This avoids taking the kernel lock when ci_inatomic is set.  This
> might speed up inteldrm(4) a bit.  Since uvm_grow() still needs the
> kernel lock, some reorganization of the code is necessary.
> 
> I'm not sure this actaully has an impact.  If we end up here with
> ci_inatomic set we're going to return EFAULT and take a slow path
> anyway.  So maybe it is better to leave this until we make uvm_grow()
> mpsafe?

I think it's valuable in itself.  Some questions below:

> Index: arch/amd64/amd64/trap.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/amd64/amd64/trap.c,v
> retrieving revision 1.81
> diff -u -p -r1.81 trap.c
> --- arch/amd64/amd64/trap.c   14 Sep 2020 12:51:28 -0000      1.81
> +++ arch/amd64/amd64/trap.c   24 Sep 2020 14:21:24 -0000
> @@ -173,11 +173,10 @@ pageflttrap(struct trapframe *frame, uin
>       pcb = &p->p_addr->u_pcb;
>       va = trunc_page((vaddr_t)cr2);
>  
> -     KERNEL_LOCK();
> -
>       if (!usermode) {
>               /* This will only trigger if SMEP is enabled */
>               if (cr2 <= VM_MAXUSER_ADDRESS && frame->tf_err & PGEX_I) {
> +                     KERNEL_LOCK();

This is necessary to prevent another thread from corrupting the global
array `faultbuf' if another fault occur, right?

That opens a question about how to protect `faultstr'.  Maybe we could
even grab the KERNEL_LOCK() inside fault().

>                       fault("attempt to execute user address %p "
>                           "in supervisor mode", (void *)cr2);
>                       /* retain kernel lock */
> @@ -186,6 +185,7 @@ pageflttrap(struct trapframe *frame, uin
>               /* This will only trigger if SMAP is enabled */
>               if (pcb->pcb_onfault == NULL && cr2 <= VM_MAXUSER_ADDRESS &&
>                   frame->tf_err & PGEX_P) {
> +                     KERNEL_LOCK();
>                       fault("attempt to access user address %p "
>                           "in supervisor mode", (void *)cr2);
>                       /* retain kernel lock */
> @@ -216,28 +216,29 @@ pageflttrap(struct trapframe *frame, uin
>               caddr_t onfault = pcb->pcb_onfault;
>  
>               pcb->pcb_onfault = NULL;

`pcb_onfault' is no longer modified under KERNEL_LOCK().  Is it safe
because this member is "owned" by the current thread?  Maybe we should
start documenting this, the "struct proc" has some examples.

> +             KERNEL_LOCK();
>               error = uvm_fault(map, va, frame->tf_err & PGEX_P ?
>                   VM_FAULT_PROTECT : VM_FAULT_INVALID, ftype);
> +             if (error == 0 && map != kernel_map)
> +                     uvm_grow(p, va);

Is there anything preventing us from having such idiom inside
uvm_fault()?  Not now, but maybe in the future.

> +             KERNEL_UNLOCK();
>               pcb->pcb_onfault = onfault;
>       } else
>               error = EFAULT;
>  
> -     if (error == 0) {
> -             if (map != kernel_map)
> -                     uvm_grow(p, va);
> -     } else if (!usermode) {
> +     if (error && !usermode) {
>               if (pcb->pcb_onfault != 0) {
> -                     KERNEL_UNLOCK();
>                       frame->tf_rip = (u_int64_t)pcb->pcb_onfault;
>                       return 1;
>               } else {
>                       /* bad memory access in the kernel */
> +                     KERNEL_LOCK();
>                       fault("uvm_fault(%p, 0x%llx, 0, %d) -> %x",
>                           map, cr2, ftype, error);
>                       /* retain kernel lock */
>                       return 0;
>               }
> -     } else {
> +     } else if (error) {
>               union sigval sv;
>               int signal, sicode;
>  
> @@ -260,8 +261,6 @@ pageflttrap(struct trapframe *frame, uin
>               sv.sival_ptr = (void *)cr2;
>               trapsignal(p, signal, T_PAGEFLT, sicode, sv);
>       }
> -
> -     KERNEL_UNLOCK();
>  
>       return 1;
>  }
> 

Reply via email to