kernel - Major MPSAFE Infrastructure
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 27 Aug 2010 04:18:06 +0000 (21:18 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 27 Aug 2010 04:18:06 +0000 (21:18 -0700)
commit77912481ac5f5d886b07c9f7038b03eba09b2bca
treeefd5558886aa62db0c4e4e692b1c9b8899037905
parent4e4d3b292ed5a013ed4ff0e0516dbd744552104d
kernel - Major MPSAFE Infrastructure

* vm_page_lookup() now requires the vm_token to be held on call instead of
  the MP lock.  And fix the few places where the routine was being called
  without the vm_token.

  Various situations where a vm_page_lookup() is performed followed by
  vm_page_wire(), without busying the page, and other similar situations,
  require the vm_token to be held across the whole block of code.

* bio_done callbacks are now MPSAFE but some drivers (ata, ccd, vinum,
  aio, nfs) are not MPSAFE yet so get the mplock for those.   They will
  be converted to a generic driver-wide token later.

* Remove critical sections that used to protect VM system related
  interrupts, replace with the vm_token.

* Spinlocks now bump thread->td_critcount in addition to
  mycpu->gd_spinlock*.  Note the ordering is important.  Then remove
  gd_spinlock* checks elsewhere that are covered by td_critcount and
  replace with assertions.

  Also use td_critcount in the kern_mutex.c code instead of gd_spinlock*.

  This fixes situations where the last crit_exit() would call splx()
  without checking for spinlocks.  Adding the additional checks would
  have made the crit_*() inlines too complex so instead we just fold
  it into td_critcount.

* lwkt_yield() no longer guarantees that lwkt_switch() will be called
  so call lwkt_switch() instead in places where a switch is required.
  For example, to unwind a preemption.  Otherwise the kernel could end
  up live-locking trying to yield because the new switch code does not
  necessarily schedule a different kernel thread.

* Add the sysctl user_pri_sched (default 0).  Setting this will make
  the LWKT scheduler more aggressively schedule user threads when
  runnable kernel threads are unable to gain token/mplock resources.
  For debugging only.

* Change the bufspin spinlock to bufqspin and bufcspin, and generally
  rework vfs_bio.c to lock numerous fields with bufcspin.  Also use
  bufcspin to interlock waitrunningbufspace() and friends.

  Remove several mplocks in vfs_bio.c that are no longer needed.

  Protect the page manipulation code in vfs_bio.c with vm_token instead
  of the mplock.

* Fix a deadlock with the FINDBLK_TEST/BUF_LOCK sequence which can occur
  due to the fact that the buffer may change its (vp,loffset) during
  the BUF_LOCK call.  Even though the code checks for this after
  the lock succeeds there is still the problem of the locking operation
  itself potentially creating a deadlock betwen two threads by locking
  an unexpected buffer when the caller is already holding other buffers
  locked.

  We do this by adding an interlock refcounter, b_refs.  getnewbuf()
  will avoid reusing such buffers.

* The syncer_token was not protecting all accesses to the syncer list.
  Fix that.

* Make HAMMER MPSAFE.  All major entry points now use a per-mount token,
  hmp->fs_token.  Backend callbacks (bioops, bio_done) use hmp->io_token.
  The cache-case for the read and getattr paths require not tokens at
  all (as before).

  The bitfield flags had to be separated into two groups to deal with
  SMP cache coherency races.

  Certain flags in the hammer_record structure had to be separated for
  the same reason.

  Certain interactions between the frontend and the backend must use
  the hmp->io_token.

  It is important to note that for any given buffer there are two
  locking entities: (1) The hammer structure and (2) The buffer cache
  buffer.  These interactions are very fragile.

  Do not allow the kernel to flush a dirty buffer if we are unable
  to obtain a norefs-interlock on the buffer, which fixes numerous
  frontend/backend MP races on the io structure.

  Add a write interlock in one of the recover_flush_buffer cases.
35 files changed:
sys/dev/agp/agp.c
sys/dev/agp/agp_i810.c
sys/dev/disk/ata/ata-raid.c
sys/dev/disk/ccd/ccd.c
sys/dev/raid/vinum/vinumhdr.h
sys/dev/raid/vinum/vinuminterrupt.c
sys/kern/kern_exec.c
sys/kern/kern_mutex.c
sys/kern/kern_slaballoc.c
sys/kern/kern_spinlock.c
sys/kern/lwkt_thread.c
sys/kern/uipc_syscalls.c
sys/kern/usched_bsd4.c
sys/kern/vfs_aio.c
sys/kern/vfs_bio.c
sys/kern/vfs_cluster.c
sys/kern/vfs_subr.c
sys/kern/vfs_sync.c
sys/platform/pc32/isa/clock.c
sys/platform/pc64/isa/clock.c
sys/sys/bio.h
sys/sys/buf.h
sys/sys/spinlock2.h
sys/sys/vnode.h
sys/vfs/devfs/devfs_vnops.c
sys/vfs/hammer/hammer.h
sys/vfs/hammer/hammer_flusher.c
sys/vfs/hammer/hammer_io.c
sys/vfs/hammer/hammer_object.c
sys/vfs/hammer/hammer_ondisk.c
sys/vfs/hammer/hammer_recover.c
sys/vfs/hammer/hammer_volume.c
sys/vfs/nfs/nfs_bio.c
sys/vm/swap_pager.c
sys/vm/vm_page.c