Skip to content

Commit

Permalink
Simplify/fix dnode_move() for dn_zfetch
Browse files Browse the repository at this point in the history
Previous code tried to keep prefetch streams while moving dnode.  But
it was at least not updating per-stream zs_fetchback pointers, causing
use-after-free on next access.  Instead of that I see much easier and
cleaner to just drop old prefetch state and start new from scratch.

Reviewed-by: Matthew Ahrens <[email protected]>
Reviewed-by: Igor Kozhukhov <[email protected]>
Signed-off-by: Alexander Motin <[email protected]>
Sponsored-By: iXsystems, Inc.
Closes openzfs#11936
Closes openzfs#11998
  • Loading branch information
amotin authored and RageLtMan committed May 31, 2021
1 parent 7362048 commit 6f7ac17
Showing 1 changed file with 1 addition and 7 deletions.
8 changes: 1 addition & 7 deletions module/zfs/dnode.c
Original file line number Diff line number Diff line change
Expand Up @@ -754,7 +754,6 @@ dnode_move_impl(dnode_t *odn, dnode_t *ndn)
ASSERT(!RW_LOCK_HELD(&odn->dn_struct_rwlock));
ASSERT(MUTEX_NOT_HELD(&odn->dn_mtx));
ASSERT(MUTEX_NOT_HELD(&odn->dn_dbufs_mtx));
ASSERT(!MUTEX_HELD(&odn->dn_zfetch.zf_lock));

/* Copy fields. */
ndn->dn_objset = odn->dn_objset;
Expand Down Expand Up @@ -822,19 +821,14 @@ dnode_move_impl(dnode_t *odn, dnode_t *ndn)
ndn->dn_newgid = odn->dn_newgid;
ndn->dn_newprojid = odn->dn_newprojid;
ndn->dn_id_flags = odn->dn_id_flags;
dmu_zfetch_init(&ndn->dn_zfetch, NULL);
list_move_tail(&ndn->dn_zfetch.zf_stream, &odn->dn_zfetch.zf_stream);
ndn->dn_zfetch.zf_dnode = odn->dn_zfetch.zf_dnode;
dmu_zfetch_init(&ndn->dn_zfetch, ndn);

/*
* Update back pointers. Updating the handle fixes the back pointer of
* every descendant dbuf as well as the bonus dbuf.
*/
ASSERT(ndn->dn_handle->dnh_dnode == odn);
ndn->dn_handle->dnh_dnode = ndn;
if (ndn->dn_zfetch.zf_dnode == odn) {
ndn->dn_zfetch.zf_dnode = ndn;
}

/*
* Invalidate the original dnode by clearing all of its back pointers.
Expand Down

0 comments on commit 6f7ac17

Please sign in to comment.