Fix a bunch of NFS races. These races existed in FreeBSD 4.x but are more
authorMatthew Dillon <dillon@dragonflybsd.org>
Sat, 13 Mar 2004 03:13:53 +0000 (03:13 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Sat, 13 Mar 2004 03:13:53 +0000 (03:13 +0000)
commit54938b9263a3dd2ff67bebfb900f5c1d35f3f68f
treefe1cd3551e7191245330b1980b56816837454d71
parent239b4df983d878d51e8fbbb875625e4423d89c33
Fix a bunch of NFS races.  These races existed in FreeBSD 4.x but are more
likely to occur now due to the additional thread switching that DragonFly
performs when doing things like sending UDP packets.  Three bugs are
being fixed:

* nfs_request() adds the request to the nfs_timer queue before doing initial
  processing (e.g. transmission) of the request.  The initial transmission of
  the request will race between nfs_request and nfs_timer, potentially causing
  the congestion window calculation (nm_sent) to be bumped twice instead of
  once.  This eventually closes the congestion window permanently and
  causes the NFS mount to freeze.  (Additionally the request could be
  transmitted twice unnecessarily, also fixed).

* Updates to rep->r_flags and nmp->nm_sent were not being properly protected
  against nfs_timer due to splsoftclock() being released too early.  All
  such accesses are now protected.

* nfs_reply() depends on nfs_rcvlock to do an interlock check to see if the
  request has already been replied, but nfs_rcvlock() only does this if it
  cannot immediately get the receiver lock.  The problem is that the NFS
  code in between request transmission and nfs_reply() can block, potentially
  allowing a reply to be returned to another nfsiod.  The NFS receiver winds
  up getting stuck waiting for a reply that has already been returned.
  nfs_rcvlock() now unconditionally checks to see if the reply has already
  occured before entering the loop.
sys/vfs/nfs/nfs.h
sys/vfs/nfs/nfs_socket.c