To deal with the problem of calling vnode_pager_setsize() with a mutex held, I first tried...
- Locking/upgrading the vnode lock to an exclusive lock. This deadlocked between the attempt to LK_EXCLUSIVE lock the vnode in nfscl_loadattrcache() and the acquisition of a buffer cache block (sleeping on bo_wwait). There was also the issue that many calls to nfscl_loadattrcache() are done with the vnode LK_SHARED locked, but this would have required an LK_EXCLUSIVE lock to serialize use of n_size with vnode_pager_setsize().
Then I considered replacing the NFS node mutex with a sleep lock. However, there are many
places in the code where the NFS node mutex was used to protect fields of the NFS node other
than n_size and most of these are just a few lines of code. It seemed like overkill to make all of
these use a sleep lock.
So, I added a sleep lock to the NFS node and changed the code so that it is used to protect
the n_size field (the one that vnode_pager_setsize() cares about).
For cases where only n_size was being manipulated, I replaced mtx_lock()/mtx_unlock() with
sx_xlock()/sx_xunlock().
For cases where use of n_size was mixed with use of other fields, I wrapped the sx_xlock()/sx_xunlock()
around the mtx_lock()/mtx_unlock(), so that both locks were held for these code blocks.
For the cases where vnode_pager_setsize() was being called, I did the mtx_unlock() just before the
vnode_pager_setsize() call and sx_xunlock() just after the call, so only the sx lock is held for the call.
The patch no longer delays calls to vnode_pager_setsize().