svn commit: r367341 - in head/sys: kern sys

Mateusz Guzik mjg at FreeBSD.org
Wed Nov 4 21:18:09 UTC 2020


Author: mjg
Date: Wed Nov  4 21:18:08 2020
New Revision: 367341
URL: https://svnweb.freebsd.org/changeset/base/367341

Log:
  rms: fixup concurrent writer handling and add more features
  
  Previously the code had one wait channel for all pending writers.
  This could result in a buggy scenario where after a writer switches
  the lock mode form readers to writers goes off CPU, another writer
  queues itself and then the last reader wakes up the latter instead
  of the former.
  
  Use a separate channel.
  
  While here add features to reliably detect whether curthread has
  the lock write-owned. This will be used by ZFS.

Modified:
  head/sys/kern/kern_rmlock.c
  head/sys/sys/_rmlock.h
  head/sys/sys/rmlock.h

Modified: head/sys/kern/kern_rmlock.c
==============================================================================
--- head/sys/kern/kern_rmlock.c	Wed Nov  4 20:15:14 2020	(r367340)
+++ head/sys/kern/kern_rmlock.c	Wed Nov  4 21:18:08 2020	(r367341)
@@ -878,10 +878,15 @@ db_show_rm(const struct lock_object *lock)
  * problem at some point. The easiest way to lessen it is to provide a bitmap.
  */
 
+#define	RMS_NOOWNER	((void *)0x1)
+#define	RMS_TRANSIENT	((void *)0x2)
+#define	RMS_FLAGMASK	0xf
+
 void
 rms_init(struct rmslock *rms, const char *name)
 {
 
+	rms->owner = RMS_NOOWNER;
 	rms->writers = 0;
 	rms->readers = 0;
 	mtx_init(&rms->mtx, name, NULL, MTX_DEF | MTX_NEW);
@@ -922,6 +927,7 @@ rms_rlock(struct rmslock *rms)
 {
 
 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, __func__);
+	MPASS(atomic_load_ptr(&rms->owner) != curthread);
 
 	critical_enter();
 	zpcpu_set_protected(rms->readers_influx, 1);
@@ -941,6 +947,8 @@ int
 rms_try_rlock(struct rmslock *rms)
 {
 
+	MPASS(atomic_load_ptr(&rms->owner) != curthread);
+
 	critical_enter();
 	zpcpu_set_protected(rms->readers_influx, 1);
 	__compiler_membar();
@@ -1054,23 +1062,33 @@ rms_wlock(struct rmslock *rms)
 {
 
 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, __func__);
+	MPASS(atomic_load_ptr(&rms->owner) != curthread);
 
 	mtx_lock(&rms->mtx);
 	rms->writers++;
 	if (rms->writers > 1) {
-		msleep(&rms->writers, &rms->mtx, (PUSER - 1) | PDROP,
+		msleep(&rms->owner, &rms->mtx, (PUSER - 1),
 		    mtx_name(&rms->mtx), 0);
 		MPASS(rms->readers == 0);
-		return;
+		KASSERT(rms->owner == RMS_TRANSIENT,
+		    ("%s: unexpected owner value %p\n", __func__,
+		    rms->owner));
+		goto out_grab;
 	}
 
+	KASSERT(rms->owner == RMS_NOOWNER,
+	    ("%s: unexpected owner value %p\n", __func__, rms->owner));
+
 	rms_wlock_switch(rms);
 
-	if (rms->readers > 0)
-		msleep(&rms->writers, &rms->mtx, (PUSER - 1) | PDROP,
+	if (rms->readers > 0) {
+		msleep(&rms->writers, &rms->mtx, (PUSER - 1),
 		    mtx_name(&rms->mtx), 0);
-	else
-		mtx_unlock(&rms->mtx);
+	}
+
+out_grab:
+	rms->owner = curthread;
+	mtx_unlock(&rms->mtx);
 	MPASS(rms->readers == 0);
 }
 
@@ -1079,12 +1097,27 @@ rms_wunlock(struct rmslock *rms)
 {
 
 	mtx_lock(&rms->mtx);
+	KASSERT(rms->owner == curthread,
+	    ("%s: unexpected owner value %p\n", __func__, rms->owner));
 	MPASS(rms->writers >= 1);
 	MPASS(rms->readers == 0);
 	rms->writers--;
-	if (rms->writers > 0)
-		wakeup_one(&rms->writers);
-	else
+	if (rms->writers > 0) {
+		wakeup_one(&rms->owner);
+		rms->owner = RMS_TRANSIENT;
+	} else {
 		wakeup(&rms->readers);
+		rms->owner = RMS_NOOWNER;
+	}
 	mtx_unlock(&rms->mtx);
+}
+
+void
+rms_unlock(struct rmslock *rms)
+{
+
+	if (rms_wowned(rms))
+		rms_wunlock(rms);
+	else
+		rms_runlock(rms);
 }

Modified: head/sys/sys/_rmlock.h
==============================================================================
--- head/sys/sys/_rmlock.h	Wed Nov  4 20:15:14 2020	(r367340)
+++ head/sys/sys/_rmlock.h	Wed Nov  4 21:18:08 2020	(r367341)
@@ -72,6 +72,7 @@ struct rm_priotracker {
 
 struct rmslock {
 	struct mtx mtx;
+	struct thread *owner;
 	int	writers;
 	int	readers;
 	int	*readers_pcpu;

Modified: head/sys/sys/rmlock.h
==============================================================================
--- head/sys/sys/rmlock.h	Wed Nov  4 20:15:14 2020	(r367340)
+++ head/sys/sys/rmlock.h	Wed Nov  4 21:18:08 2020	(r367341)
@@ -140,16 +140,33 @@ int	rms_try_rlock(struct rmslock *rms);
 void	rms_runlock(struct rmslock *rms);
 void	rms_wlock(struct rmslock *rms);
 void	rms_wunlock(struct rmslock *rms);
+void	rms_unlock(struct rmslock *rms);
 
+static inline int
+rms_wowned(struct rmslock *rms)
+{
+
+	return (rms->owner == curthread);
+}
+
 /*
- * Writers are not explicitly tracked, thus until that changes the best we can
- * do is indicate the lock is taken for writing by *someone*.
+ * Only valid to call if you hold the lock in some manner.
  */
 static inline int
-rms_wowned(struct rmslock *rms)
+rms_rowned(struct rmslock *rms)
 {
 
-	return (rms->writers > 0);
+	return (rms->readers > 0);
+}
+
+static inline int
+rms_owned_any(struct rmslock *rms)
+{
+
+	if (rms_wowned(rms))
+		return (1);
+
+	return (rms_rowned(rms));
 }
 
 #endif /* _KERNEL */


More information about the svn-src-all mailing list