git: kernel - Fix pmap placemarker timing race

Matthew Dillon dillon at crater.dragonflybsd.org
Sun Jun 23 08:56:54 PDT 2019


commit 92414ddf43087593c70a5b4011019fa8ec8cce80
Author: Matthew Dillon <dillon at apollo.backplane.com>
Date:   Sun Jun 23 08:24:24 2019 -0700

    kernel - Fix pmap placemarker timing race
    
    * Fix a timing race that could cause a thread to get stuck in
      "pvplw" indefinitely.  The timing window is very short and the
      race is fairly difficult to reproduce.
    
    * For this race to occur, more than one interaction must take
      place on other cpus against the placemarker being waited on
      by pv_placemarker_wait().  It takes multiple interactions for
      the WAKEUP bit to be lost.
    
      The first interaction can clear the WAKEUP bit and issue a
      wakeup() before we manage to interlock.  The second interaction
      can then reserve the placemarker so our conditional fails and
      we tsleep().  The result is that we block forever.
    
      pv_placemarker_wait(pmap_t pmap, vm_pindex_t *pmark)
      {
              if (*pmark != PM_NOPLACEMARK) {
                      atomic_set_long(pmark, PM_PLACEMARK_WAKEUP);
                      tsleep_interlock(pmark, 0);
                      if (*pmark != PM_NOPLACEMARK)
                              tsleep(pmark, PINTERLOCKED, "pvplw", 0);
              }
      }
    
      Just moving the interlock to before setting the flag is not
      sufficient due to cuteness on my part in overloading the WAKEUP
      bit on top of NOPLACEMARK (NOPLACEMARK is '-1').
    
    * The solution is to both properly order the interlock AND use
      a cmpset loop to prevent accidently setting the WAKEUP bit on
      a marker that has already been released.
    
    	mark = *pmark;
    	cpu_ccfence();
            while (mark != PM_NOPLACEMARK) {
                    tsleep_interlock(pmark, 0);
                    if (atomic_fcmpset_long(pmark, &mark,
                                           mark | PM_PLACEMARK_WAKEUP)) {
                            tsleep(pmark, PINTERLOCKED, "pvplw", 0);
                            break;
                    }
            }
    
    Reported-by: tuxillo

Summary of changes:
 sys/platform/pc64/x86_64/pmap.c | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff/92414ddf43087593c70a5b4011019fa8ec8cce80


-- 
DragonFly BSD source repository


More information about the Commits mailing list