Joerg Goltermann
2014-04-04 13:07:00 UTC
Hi,
today i had to removed a cache device from a pool which caused a hang
of the complete pool for about 3 minutes.
I was too slow to debug the situation, but after looking at the code, I
think the function l2arc_evict() in arc.c is the problem.
The global mutex l2arc_buflist_mtx is entered at the beginning and if
there is no hash lock miss, it's hold until the complete list is evicted.
I did no further debugging or testing, but do you think something like
below can fix this?
default for zfs_free_max_blocks is UINT64_MAX, but I use a smaller
number like 100000.
- Joerg
--- a/usr/src/uts/common/fs/zfs/arc.c
+++ b/usr/src/uts/common/fs/zfs/arc.c
@@ -4416,7 +4416,7 @@ l2arc_evict(l2arc_dev_t *dev, uint64_t distance,
boolean_t all)
l2arc_buf_hdr_t *abl2;
arc_buf_hdr_t *ab, *ab_prev;
kmutex_t *hash_lock;
- uint64_t taddr;
+ uint64_t taddr, freed;
buflist = dev->l2ad_buflist;
@@ -4444,10 +4444,15 @@ l2arc_evict(l2arc_dev_t *dev, uint64_t distance,
boolean_t all)
uint64_t, taddr, boolean_t, all);
top:
+ freed = 0;
mutex_enter(&l2arc_buflist_mtx);
for (ab = list_tail(buflist); ab; ab = ab_prev) {
- ab_prev = list_prev(buflist, ab);
+ if (++freed >= zfs_free_max_blocks) {
+ mutex_exit(&l2arc_buflist_mtx);
+ goto top;
+ }
+ ab_prev = list_prev(buflist, ab);
hash_lock = HDR_LOCK(ab);
if (!mutex_tryenter(hash_lock)) {
/*
today i had to removed a cache device from a pool which caused a hang
of the complete pool for about 3 minutes.
I was too slow to debug the situation, but after looking at the code, I
think the function l2arc_evict() in arc.c is the problem.
The global mutex l2arc_buflist_mtx is entered at the beginning and if
there is no hash lock miss, it's hold until the complete list is evicted.
I did no further debugging or testing, but do you think something like
below can fix this?
default for zfs_free_max_blocks is UINT64_MAX, but I use a smaller
number like 100000.
- Joerg
--- a/usr/src/uts/common/fs/zfs/arc.c
+++ b/usr/src/uts/common/fs/zfs/arc.c
@@ -4416,7 +4416,7 @@ l2arc_evict(l2arc_dev_t *dev, uint64_t distance,
boolean_t all)
l2arc_buf_hdr_t *abl2;
arc_buf_hdr_t *ab, *ab_prev;
kmutex_t *hash_lock;
- uint64_t taddr;
+ uint64_t taddr, freed;
buflist = dev->l2ad_buflist;
@@ -4444,10 +4444,15 @@ l2arc_evict(l2arc_dev_t *dev, uint64_t distance,
boolean_t all)
uint64_t, taddr, boolean_t, all);
top:
+ freed = 0;
mutex_enter(&l2arc_buflist_mtx);
for (ab = list_tail(buflist); ab; ab = ab_prev) {
- ab_prev = list_prev(buflist, ab);
+ if (++freed >= zfs_free_max_blocks) {
+ mutex_exit(&l2arc_buflist_mtx);
+ goto top;
+ }
+ ab_prev = list_prev(buflist, ab);
hash_lock = HDR_LOCK(ab);
if (!mutex_tryenter(hash_lock)) {
/*