First, convert page cache read to VOP. There are several negative side-effects of not calling into VOP layer at all for page cache reads. The biggest is the missed activation of EVFILT_READ knotes. Also, the conditions to do pgcache reads in vn layer were too rigid, they can be usefully weakened for tmpfs, which is too clumsy to do with new flags.
Then, tmpfs regular vnode object lifecycle is significantly different from the normal OBJT_VNODE: it is alive as far as ref_count > 0.
All the arguments convinced me that tmpfs is better served by separate code, not touching vn_read_from_obj().
I kept VIRF_PGREAD flag around, it is still useful for nullfs and for asserts.
Second, add tmpfs VOP_READ_PGCACHE that takes advantage of all tmpfs quirks. It is quite cheap in code size sense to support page-ins for read for tmpfs even if we do not own tmpfs vnode lock. Also, we can handle holes in tmpfs node without additional efforts, and do not have limitation of the transfer size.
Ensure liveness of the tmpfs VREG node and consequently v_object inside VOP_READ_PGCACHE by referencing tmpfs node in tmpfs_open(). Provide custom tmpfs fo_close() method on file, to ensure that close is paired with open.
Microoptimize tmpfs node ref/unref by using atomics and avoiding tmpfs mount and node locks when ref count is greater than zero, which is the case until node is being destroyed by unlink or unmount.
Do not copy vp into f_data for DTYPE_VNODE files. The pointer to vnode is already stored into f_vnode, so f_data can be reused. Fix all found users of f_data for DTYPE_VNODE.
Tested by: pho