```
Read or write to the snapshot inode first locks the snap lock, which is
equal to the vnode lock, then locks a buffer from the operational range.
On the other hand, copy on write path starts with the buffer locked, and
needs to lock the snap lock. If the same buffer is simultaneously read
and written, it gets into LoR.
Break the reversal by locking buffers of the snapshot inode in ffs VOPs
with LK_NOWAIT, and temporary unlock the snap lock if possible deadlock
is detected. This is similar to how ffs_update() handles the situation.
```
Also
```
ufs: be more persistent with finishing some operations
when the vnode is doomed after relock. The mere fact that the vnode is
doomed does not prevent us from doing UFS operations on it while it is
still belongs to UFS, which is determined by non-NULL v_data. Not
finishing some operations, e.g. not syncing the inode block only because
the vnode started reclamation, is not correct.
Add macro IS_UFS() which incapsulates the v_data != NULL, and use it
instead of VN_IS_DOOMED() for places where the operation completion is
important.
```
Also
```
buf_alloc(): lock the buffer with LK_NOWAIT
The buffer must not be accessed by any other thread, it is freshly
allocated. As such, LK_NOWAIT should be nop but also it prevents
recording the order between the buffer lock and any other locks we might
own in the call to getnewbuf(). In particular, if we own FFS snap lock,
it should avoid triggering false positive warning.
```