104
104
* with the buffer may be evicted prior to the callback. The callback
105
105
* must be made with *no locks held* (to prevent deadlock). Additionally,
106
106
* the users of callbacks must ensure that their private data is
107
- * protected from simultaneous callbacks from arc_buf_evict ()
107
+ * protected from simultaneous callbacks from arc_clear_callback ()
108
108
* and arc_do_user_evicts().
109
109
*
110
110
* It as also possible to register a callback which is run when the
@@ -1604,8 +1604,12 @@ arc_buf_data_free(arc_buf_t *buf, void (*free_func)(void *, size_t))
1604
1604
}
1605
1605
}
1606
1606
1607
+ /*
1608
+ * Free up buf->b_data and if 'remove' is set, then pull the
1609
+ * arc_buf_t off of the the arc_buf_hdr_t's list and free it.
1610
+ */
1607
1611
static void
1608
- arc_buf_destroy (arc_buf_t * buf , boolean_t recycle , boolean_t all )
1612
+ arc_buf_destroy (arc_buf_t * buf , boolean_t recycle , boolean_t remove )
1609
1613
{
1610
1614
arc_buf_t * * bufp ;
1611
1615
@@ -1655,7 +1659,7 @@ arc_buf_destroy(arc_buf_t *buf, boolean_t recycle, boolean_t all)
1655
1659
}
1656
1660
1657
1661
/* only remove the buf if requested */
1658
- if (!all )
1662
+ if (!remove )
1659
1663
return ;
1660
1664
1661
1665
/* remove the buf from the hdr list */
@@ -2265,7 +2269,7 @@ arc_do_user_evicts(void)
2265
2269
mutex_exit (& arc_eviction_mtx );
2266
2270
2267
2271
if (buf -> b_efunc != NULL )
2268
- VERIFY (buf -> b_efunc (buf ) == 0 );
2272
+ VERIFY0 (buf -> b_efunc (buf -> b_private ) );
2269
2273
2270
2274
buf -> b_efunc = NULL ;
2271
2275
buf -> b_private = NULL ;
@@ -3576,16 +3580,25 @@ arc_freed(spa_t *spa, const blkptr_t *bp)
3576
3580
}
3577
3581
3578
3582
/*
3579
- * This is used by the DMU to let the ARC know that a buffer is
3580
- * being evicted, so the ARC should clean up. If this arc buf
3581
- * is not yet in the evicted state, it will be put there.
3583
+ * Clear the user eviction callback set by arc_set_callback(), first calling
3584
+ * it if it exists. Because the presence of a callback keeps an arc_buf cached
3585
+ * clearing the callback may result in the arc_buf being destroyed. However,
3586
+ * it will not result in the *last* arc_buf being destroyed, hence the data
3587
+ * will remain cached in the ARC. We make a copy of the arc buffer here so
3588
+ * that we can process the callback without holding any locks.
3589
+ *
3590
+ * It's possible that the callback is already in the process of being cleared
3591
+ * by another thread. In this case we can not clear the callback.
3592
+ *
3593
+ * Returns B_TRUE if the callback was successfully called and cleared.
3582
3594
*/
3583
- int
3584
- arc_buf_evict (arc_buf_t * buf )
3595
+ boolean_t
3596
+ arc_clear_callback (arc_buf_t * buf )
3585
3597
{
3586
3598
arc_buf_hdr_t * hdr ;
3587
3599
kmutex_t * hash_lock ;
3588
- arc_buf_t * * bufp ;
3600
+ arc_evict_func_t * efunc = buf -> b_efunc ;
3601
+ void * private = buf -> b_private ;
3589
3602
3590
3603
mutex_enter (& buf -> b_evict_lock );
3591
3604
hdr = buf -> b_hdr ;
@@ -3595,17 +3608,16 @@ arc_buf_evict(arc_buf_t *buf)
3595
3608
*/
3596
3609
ASSERT (buf -> b_data == NULL );
3597
3610
mutex_exit (& buf -> b_evict_lock );
3598
- return (0 );
3611
+ return (B_FALSE );
3599
3612
} else if (buf -> b_data == NULL ) {
3600
- arc_buf_t copy = * buf ; /* structure assignment */
3601
3613
/*
3602
3614
* We are on the eviction list; process this buffer now
3603
3615
* but let arc_do_user_evicts() do the reaping.
3604
3616
*/
3605
3617
buf -> b_efunc = NULL ;
3606
3618
mutex_exit (& buf -> b_evict_lock );
3607
- VERIFY ( copy . b_efunc ( & copy ) == 0 );
3608
- return (1 );
3619
+ VERIFY0 ( efunc ( private ) );
3620
+ return (B_TRUE );
3609
3621
}
3610
3622
hash_lock = HDR_LOCK (hdr );
3611
3623
mutex_enter (hash_lock );
@@ -3615,48 +3627,21 @@ arc_buf_evict(arc_buf_t *buf)
3615
3627
ASSERT3U (refcount_count (& hdr -> b_refcnt ), < , hdr -> b_datacnt );
3616
3628
ASSERT (hdr -> b_state == arc_mru || hdr -> b_state == arc_mfu );
3617
3629
3618
- /*
3619
- * Pull this buffer off of the hdr
3620
- */
3621
- bufp = & hdr -> b_buf ;
3622
- while (* bufp != buf )
3623
- bufp = & (* bufp )-> b_next ;
3624
- * bufp = buf -> b_next ;
3625
-
3626
- ASSERT (buf -> b_data != NULL );
3627
- arc_buf_destroy (buf , FALSE, FALSE);
3628
-
3629
- if (hdr -> b_datacnt == 0 ) {
3630
- arc_state_t * old_state = hdr -> b_state ;
3631
- arc_state_t * evicted_state ;
3632
-
3633
- ASSERT (hdr -> b_buf == NULL );
3634
- ASSERT (refcount_is_zero (& hdr -> b_refcnt ));
3635
-
3636
- evicted_state =
3637
- (old_state == arc_mru ) ? arc_mru_ghost : arc_mfu_ghost ;
3638
-
3639
- mutex_enter (& old_state -> arcs_mtx );
3640
- mutex_enter (& evicted_state -> arcs_mtx );
3641
-
3642
- arc_change_state (evicted_state , hdr , hash_lock );
3643
- ASSERT (HDR_IN_HASH_TABLE (hdr ));
3644
- hdr -> b_flags |= ARC_IN_HASH_TABLE ;
3645
- hdr -> b_flags &= ~ARC_BUF_AVAILABLE ;
3630
+ buf -> b_efunc = NULL ;
3631
+ buf -> b_private = NULL ;
3646
3632
3647
- mutex_exit (& evicted_state -> arcs_mtx );
3648
- mutex_exit (& old_state -> arcs_mtx );
3633
+ if (hdr -> b_datacnt > 1 ) {
3634
+ mutex_exit (& buf -> b_evict_lock );
3635
+ arc_buf_destroy (buf , FALSE, TRUE);
3636
+ } else {
3637
+ ASSERT (buf == hdr -> b_buf );
3638
+ hdr -> b_flags |= ARC_BUF_AVAILABLE ;
3639
+ mutex_exit (& buf -> b_evict_lock );
3649
3640
}
3650
- mutex_exit (hash_lock );
3651
- mutex_exit (& buf -> b_evict_lock );
3652
3641
3653
- VERIFY (buf -> b_efunc (buf ) == 0 );
3654
- buf -> b_efunc = NULL ;
3655
- buf -> b_private = NULL ;
3656
- buf -> b_hdr = NULL ;
3657
- buf -> b_next = NULL ;
3658
- kmem_cache_free (buf_cache , buf );
3659
- return (1 );
3642
+ mutex_exit (hash_lock );
3643
+ VERIFY0 (efunc (private ));
3644
+ return (B_TRUE );
3660
3645
}
3661
3646
3662
3647
/*
@@ -3813,17 +3798,6 @@ arc_released(arc_buf_t *buf)
3813
3798
return (released );
3814
3799
}
3815
3800
3816
- int
3817
- arc_has_callback (arc_buf_t * buf )
3818
- {
3819
- int callback ;
3820
-
3821
- mutex_enter (& buf -> b_evict_lock );
3822
- callback = (buf -> b_efunc != NULL );
3823
- mutex_exit (& buf -> b_evict_lock );
3824
- return (callback );
3825
- }
3826
-
3827
3801
#ifdef ZFS_DEBUG
3828
3802
int
3829
3803
arc_referenced (arc_buf_t * buf )
0 commit comments