> Date: Wed, 18 Mar 2020 11:34:59 +0100
> From: Martin Pieuchot <m...@openbsd.org>
> 
> On 17/03/20(Tue) 20:08, Mark Kettenis wrote:
> > While playing with dt(4)/btrace(4) flamegraphs on a 32-core arm64
> > machine, I noticed that the kernel was spending a lot of time (6.84%)
> > in uvm_map_inentry().  This is caused by kernel lock contention.
> > Pushing baack the kernel lock further into the slow path reduces the
> > time to 0.05%.
> > 
> > Now mpi@ tried this before in sys/uvm/uvm_map.c rev 1.249.  That was
> > backed out because it caused issues with golang.  So I had a look
> > again and identified a potential issue.  When we "fix" the cached
> > entry, we use the serial number that has been passed down to us.  But
> > since that serial number was recorded before we grapped the vm_map
> > lock, it may be stale.  Instead we should be using the current map
> > serial number.
> > 
> > This makes me wonder whether having two serial numbers is a case of
> > premature optimization.  But that is a different discussion.
> > 
> > I'd like to see this tested, especially by people running/building
> > golang.  Does anybody remember specific details of the issue?  If it
> > manifests itself, it should be pretty obvious as it results in a
> > kernel printf and a killed process.
> 
> Sadly this isn't the bug we're looking for.  golang still segfaults
> with this diff.

How do you reproduce the golang segfault?

> That said it is still a bug, so please commit it without moving the
> KERNEL_LOCK(),  ok mpi@.
> 
> > Index: uvm/uvm_map.c
> > ===================================================================
> > RCS file: /cvs/src/sys/uvm/uvm_map.c,v
> > retrieving revision 1.263
> > diff -u -p -r1.263 uvm_map.c
> > --- uvm/uvm_map.c   4 Mar 2020 21:15:38 -0000       1.263
> > +++ uvm/uvm_map.c   17 Mar 2020 18:57:19 -0000
> > @@ -161,7 +161,7 @@ void                     uvm_map_addr_augment(struct 
> > vm_m
> >  int                         uvm_map_inentry_recheck(u_long, vaddr_t,
> >                          struct p_inentry *);
> >  boolean_t           uvm_map_inentry_fix(struct proc *, struct p_inentry *,
> > -                        vaddr_t, int (*)(vm_map_entry_t), u_long);
> > +                        vaddr_t, int (*)(vm_map_entry_t));
> >  /*
> >   * Tree management functions.
> >   */
> > @@ -1848,10 +1848,11 @@ uvm_map_inentry_recheck(u_long serial, v
> >   */
> >  boolean_t
> >  uvm_map_inentry_fix(struct proc *p, struct p_inentry *ie, vaddr_t addr,
> > -    int (*fn)(vm_map_entry_t), u_long serial)
> > +    int (*fn)(vm_map_entry_t))
> >  {
> >     vm_map_t map = &p->p_vmspace->vm_map;
> >     vm_map_entry_t entry;
> > +   u_long serial;
> >     int ret;
> >  
> >     if (addr < map->min_offset || addr >= map->max_offset)
> > @@ -1866,6 +1867,11 @@ uvm_map_inentry_fix(struct proc *p, stru
> >             return (FALSE);
> >     }
> >  
> > +   if (ie == &p->p_spinentry)
> > +           serial = map->sserial;
> > +   else
> > +           serial = map->wserial;
> > +
> >     ret = (*fn)(entry);
> >     if (ret == 0) {
> >             vm_map_unlock_read(map);
> > @@ -1889,16 +1895,16 @@ uvm_map_inentry(struct proc *p, struct p
> >     boolean_t ok = TRUE;
> >  
> >     if (uvm_map_inentry_recheck(serial, addr, ie)) {
> > -           KERNEL_LOCK();
> > -           ok = uvm_map_inentry_fix(p, ie, addr, fn, serial);
> > +           ok = uvm_map_inentry_fix(p, ie, addr, fn);
> >             if (!ok) {
> >                     printf(fmt, p->p_p->ps_comm, p->p_p->ps_pid, p->p_tid,
> >                         addr, ie->ie_start, ie->ie_end);
> > +                   KERNEL_LOCK();
> >                     p->p_p->ps_acflag |= AMAP;
> >                     sv.sival_ptr = (void *)PROC_PC(p);
> >                     trapsignal(p, SIGSEGV, 0, SEGV_ACCERR, sv);
> > +                   KERNEL_UNLOCK();
> >             }
> > -           KERNEL_UNLOCK();
> >     }
> >     return (ok);
> >  }
> > 
> 

Reply via email to