mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 10:37:35 +03:00
Illumos 5095 - panic when adding a duplicate dbuf to dn_dbufs
5095 panic when adding a duplicate dbuf to dn_dbufs Author: Alex Reece <alex@delphix.com> Reviewed by: Adam Leventhal <adam.leventhal@delphix.com> Reviewed by: George Wilson <george.wilson@delphix.com> Reviewed by: Mattew Ahrens <mahrens@delphix.com> Reviewed by: Dan Kimmel <dan.kimmel@delphix.com> Reviewed by: Dan McDonald <danmcd@omniti.com> Reviewed by: Josef Sipek <jeffpc@josefsipek.net> Approved by: Robert Mustacchi <rm@joyent.com> References: https://www.illumos.org/issues/5095 https://github.com/illumos/illumos-gate/commit/86bb58a Ported-by: Chris Dunlop <chris@onthe.net.au> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
This commit is contained in:
committed by
Brian Behlendorf
parent
5aea3644d6
commit
9925c28cde
+1
-3
@@ -94,8 +94,6 @@ dbuf_cons(void *vdb, void *unused, int kmflag)
|
||||
cv_init(&db->db_changed, NULL, CV_DEFAULT, NULL);
|
||||
refcount_create(&db->db_holds);
|
||||
|
||||
db->db_creation = gethrtime();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -884,7 +882,7 @@ dbuf_free_range(dnode_t *dn, uint64_t start_blkid, uint64_t end_blkid,
|
||||
db_seach = kmem_alloc(sizeof (dmu_buf_impl_t), KM_SLEEP);
|
||||
db_search->db_level = 0;
|
||||
db_search->db_blkid = start_blkid;
|
||||
db_search->db_creation = 0;
|
||||
db_search->db_state = DB_SEARCH;
|
||||
|
||||
mutex_enter(&dn->dn_dbufs_mtx);
|
||||
if (start_blkid >= dn->dn_unlisted_l0_blkid && !freespill) {
|
||||
|
||||
+19
-17
@@ -70,33 +70,35 @@ dbuf_compare(const void *x1, const void *x2)
|
||||
|
||||
if (d1->db_level < d2->db_level) {
|
||||
return (-1);
|
||||
} else if (d1->db_level > d2->db_level) {
|
||||
}
|
||||
if (d1->db_level > d2->db_level) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (d1->db_blkid < d2->db_blkid) {
|
||||
return (-1);
|
||||
} else if (d1->db_blkid > d2->db_blkid) {
|
||||
}
|
||||
if (d1->db_blkid > d2->db_blkid) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* If a dbuf is being evicted while dn_dbufs_mutex is not held, we set
|
||||
* the db_state to DB_EVICTING but do not remove it from dn_dbufs. If
|
||||
* another thread creates a dbuf of the same blkid before the dbuf is
|
||||
* removed from dn_dbufs, we can reach a state where there are two
|
||||
* dbufs of the same blkid and level in db_dbufs. To maintain the avl
|
||||
* invariant that there cannot be duplicate items, we distinguish
|
||||
* between these two dbufs based on the time they were created.
|
||||
*/
|
||||
if (d1->db_creation < d2->db_creation) {
|
||||
if (d1->db_state < d2->db_state) {
|
||||
return (-1);
|
||||
} else if (d1->db_creation > d2->db_creation) {
|
||||
return (1);
|
||||
} else {
|
||||
ASSERT3P(d1, ==, d2);
|
||||
return (0);
|
||||
}
|
||||
if (d1->db_state > d2->db_state) {
|
||||
return (1);
|
||||
}
|
||||
|
||||
ASSERT3S(d1->db_state, !=, DB_SEARCH);
|
||||
ASSERT3S(d2->db_state, !=, DB_SEARCH);
|
||||
|
||||
if ((uintptr_t)d1 < (uintptr_t)d2) {
|
||||
return (-1);
|
||||
}
|
||||
if ((uintptr_t)d1 > (uintptr_t)d2) {
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
|
||||
Reference in New Issue
Block a user