From bff2361aeb32a83c26e2992733864ca99cced257 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Thu, 23 May 2019 13:46:33 -0700 Subject: [PATCH] Linux 5.2 compat: rw_tryupgrade() Commit torvalds/linux@46ad0840b has removed the architecture specific rwsem source and headers leaving only the generic version. As part of this change the RWSEM_ACTIVE_READ_BIAS and RWSEM_ACTIVE_WRITE_BIAS macros were moved to the private kernel/locking/rwsem.h header. This results in a build failure because these macros were required to implement the rw_tryupgrade() compatibility function. In practice, this isn't a major problem because there are only a few consumers of rw_tryupgrade() and because consumers of rw_tryupgrade should be written to retry using rw_enter(RW_WRITER). After auditing all of the callers only dmu_zfetch() was determined not to perform a retry. It has been updated in this commit to resolve this issue. That said, the rw_tryupgrade() functionality should be considered for possible removal in a future release due to the difficultly in supporting the interface. Reviewed-by: Tomohiro Kusumi Reviewed-by: Chunwei Chen Signed-off-by: Brian Behlendorf Closes #8730 --- include/spl/sys/rwlock.h | 2 +- module/spl/spl-rwlock.c | 10 +++++++++- module/zfs/dmu_zfetch.c | 13 ++++++++++--- 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; } -- 2.40.0