summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/spl/sys/rwlock.h2
-rw-r--r--module/spl/spl-rwlock.c10
-rw-r--r--module/zfs/dmu_zfetch.c13
3 files changed, 20 insertions, 5 deletions
diff --git a/include/spl/sys/rwlock.h b/include/spl/sys/rwlock.h
index a1c1fd469..408defac2 100644
--- a/include/spl/sys/rwlock.h
+++ b/include/spl/sys/rwlock.h
@@ -36,7 +36,7 @@
#elif defined(CONFIG_RWSEM_GENERIC_SPINLOCK)
#define SPL_RWSEM_SINGLE_READER_VALUE (1)
#define SPL_RWSEM_SINGLE_WRITER_VALUE (-1)
-#else
+#elif defined(RWSEM_ACTIVE_MASK)
#define SPL_RWSEM_SINGLE_READER_VALUE (RWSEM_ACTIVE_READ_BIAS)
#define SPL_RWSEM_SINGLE_WRITER_VALUE (RWSEM_ACTIVE_WRITE_BIAS)
#endif
diff --git a/module/spl/spl-rwlock.c b/module/spl/spl-rwlock.c
index 4ffebc8ea..86727ed19 100644
--- a/module/spl/spl-rwlock.c
+++ b/module/spl/spl-rwlock.c
@@ -85,7 +85,8 @@ __rwsem_tryupgrade(struct rw_semaphore *rwsem)
spl_rwsem_unlock_irqrestore(&rwsem->wait_lock, flags);
return (ret);
}
-#elif defined(HAVE_RWSEM_ATOMIC_LONG_COUNT)
+#elif defined(RWSEM_ACTIVE_MASK)
+#if defined(HAVE_RWSEM_ATOMIC_LONG_COUNT)
static int
__rwsem_tryupgrade(struct rw_semaphore *rwsem)
{
@@ -104,6 +105,13 @@ __rwsem_tryupgrade(struct rw_semaphore *rwsem)
return (val == SPL_RWSEM_SINGLE_READER_VALUE);
}
#endif
+#else
+static int
+__rwsem_tryupgrade(struct rw_semaphore *rwsem)
+{
+ return (0);
+}
+#endif
int
rwsem_tryupgrade(struct rw_semaphore *rwsem)
diff --git a/module/zfs/dmu_zfetch.c b/module/zfs/dmu_zfetch.c
index 2133518ff..364e4d7aa 100644
--- a/module/zfs/dmu_zfetch.c
+++ b/module/zfs/dmu_zfetch.c
@@ -214,6 +214,7 @@ dmu_zfetch(zfetch_t *zf, uint64_t blkid, uint64_t nblks, boolean_t fetch_data)
uint64_t end_of_access_blkid;
end_of_access_blkid = blkid + nblks;
spa_t *spa = zf->zf_dnode->dn_objset->os_spa;
+ krw_t rw = RW_READER;
if (zfs_prefetch_disable)
return;
@@ -234,7 +235,8 @@ dmu_zfetch(zfetch_t *zf, uint64_t blkid, uint64_t nblks, boolean_t fetch_data)
if (blkid == 0)
return;
- rw_enter(&zf->zf_rwlock, RW_READER);
+retry:
+ rw_enter(&zf->zf_rwlock, rw);
/*
* Find matching prefetch stream. Depending on whether the accesses
@@ -272,8 +274,13 @@ dmu_zfetch(zfetch_t *zf, uint64_t blkid, uint64_t nblks, boolean_t fetch_data)
* a new stream for it.
*/
ZFETCHSTAT_BUMP(zfetchstat_misses);
- if (rw_tryupgrade(&zf->zf_rwlock))
- dmu_zfetch_stream_create(zf, end_of_access_blkid);
+ if (rw == RW_READER && !rw_tryupgrade(&zf->zf_rwlock)) {
+ rw_exit(&zf->zf_rwlock);
+ rw = RW_WRITER;
+ goto retry;
+ }
+
+ dmu_zfetch_stream_create(zf, end_of_access_blkid);
rw_exit(&zf->zf_rwlock);
return;
}