[FreeBSD] zfs_znode_alloc: lock the vnode earlier

This is needed because of a possible error path where zfs_vnode_forget()
is called.  That function calls vgone() and vput(), the former requires
the vnode to be exclusively locked and the latter expects it to be
locked.

It should be safe to lock the vnode as early as possible because it is
not yet visible, so there is no interaction with other locks.

While here, remove a tautological assignment to 'vp'.

Reviewed-by: Alexander Motin <mav@FreeBSD.org>
Reviewed-by: Richard Yao <richard.yao@alumni.stonybrook.edu>
Signed-off-by: Andriy Gapon <avg@FreeBSD.org>
Closes #14565
This commit is contained in:
Andriy Gapon 2023-03-07 02:30:54 +02:00 committed by GitHub
parent ca9e32d3a7
commit 28bf26acb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -448,6 +448,13 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz,
zp->z_vnode = vp; zp->z_vnode = vp;
vp->v_data = zp; vp->v_data = zp;
/*
* Acquire the vnode lock before any possible interaction with the
* outside world. Specifically, there is an error path that calls
* zfs_vnode_forget() and the vnode should be exclusively locked.
*/
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
ASSERT(!POINTER_IS_VALID(zp->z_zfsvfs)); ASSERT(!POINTER_IS_VALID(zp->z_zfsvfs));
zp->z_sa_hdl = NULL; zp->z_sa_hdl = NULL;
@ -464,8 +471,6 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz,
atomic_store_ptr(&zp->z_cached_symlink, NULL); atomic_store_ptr(&zp->z_cached_symlink, NULL);
#endif #endif
vp = ZTOV(zp);
zfs_znode_sa_init(zfsvfs, zp, db, obj_type, hdl); zfs_znode_sa_init(zfsvfs, zp, db, obj_type, hdl);
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zfsvfs), NULL, &mode, 8); SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zfsvfs), NULL, &mode, 8);
@ -535,10 +540,6 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz,
zp->z_zfsvfs = zfsvfs; zp->z_zfsvfs = zfsvfs;
mutex_exit(&zfsvfs->z_znodes_lock); mutex_exit(&zfsvfs->z_znodes_lock);
/*
* Acquire vnode lock before making it available to the world.
*/
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
#if __FreeBSD_version >= 1400077 #if __FreeBSD_version >= 1400077
vn_set_state(vp, VSTATE_CONSTRUCTED); vn_set_state(vp, VSTATE_CONSTRUCTED);
#endif #endif