lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <55315ADD-4AE1-4EA4-8291-1B07F659BD99@linuxhacker.ru>
Date:	Wed, 15 Jun 2016 14:23:35 -0400
From:	Oleg Drokin <green@...uxhacker.ru>
To:	Mailing List <linux-kernel@...r.kernel.org>
Cc:	mingo@...hat.com, arjan@...ux.intel.com,
	"J . Bruce Fields" <bfields@...ldses.org>,
	Jeff Layton <jlayton@...chiereds.net>,
	Oleg Drokin <green@...uxhacker.ru>
Subject: initialize a mutex into locked state?

Hello!

  To my surprise I found out that it's not possible to initialise a mutex into
  a locked state.
  I discussed it with Arjan and apparently there's no fundamental reason
  not to allow this.

  A typical use would be when you have a structure that you need to init and then
  add to some list (under a spinlock), but with a possibility of a racing thread
  adding something there that you might want to reuse and not init your own copy
  of it to save cpu cycles. Yet you still want this structure to remain
  internally locked for other purposes before letting other threads do stuff
  with it (hence the mutex initialized to a locked state).

  There's just a case in nfsd that I met that would benefit from it that
  causes me to move mutex init + lock into the general "do always" area
  instead of doing it only when really necessary along with other init code
  (see the patch at http://marc.info/?l=linux-nfs&m=146596158830108&w=2 if
  interested).

  So I wonder if such a functionality should be considered?

Something like this (only compile-tested):

[PATCH] mutex: Add mutex_init_locked()

This is useful when you want to init it to this state under a spinlock.

Signed-off-by: Oleg Drokin <green@...uxhacker.ru>
---
drivers/base/bus.c                             |  2 +-
drivers/base/class.c                           |  2 +-
drivers/gpu/drm/nouveau/nvkm/core/subdev.c     |  2 +-
drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c |  2 +-
include/linux/mutex-debug.h                    | 11 ++++++++++-
include/linux/mutex.h                          | 22 +++++++++++++++++++---
include/linux/ww_mutex.h                       |  2 +-
kernel/locking/mutex.c                         | 10 +++++++---
net/netfilter/ipvs/ip_vs_sync.c                |  2 +-
9 files changed, 42 insertions(+), 13 deletions(-)

diff --git a/include/linux/mutex-debug.h b/include/linux/mutex-debug.h
index 4ac8b19..ee54a3d 100644
--- a/include/linux/mutex-debug.h
+++ b/include/linux/mutex-debug.h
@@ -16,9 +16,18 @@
do {									\
	static struct lock_class_key __key;				\
									\
-	__mutex_init((mutex), #mutex, &__key);				\
+	__mutex_init((mutex), #mutex, &__key, 0);			\
} while (0)

+#define mutex_init_locked(mutex)					\
+do {									\
+	static struct lock_class_key __key;				\
+									\
+	__mutex_init((mutex), #mutex, &__key, 1);			\
+} while (0)
+
+
+
extern void mutex_destroy(struct mutex *lock);

#endif
diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index 2cb7531..43faca4 100644
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -88,14 +88,30 @@ struct mutex_waiter {
 *
 * Initialize the mutex to unlocked state.
 *
- * It is not allowed to initialize an already locked mutex.
+ * It is not allowed to re-initialize an already locked mutex.
 */
# define mutex_init(mutex) \
do {							\
	static struct lock_class_key __key;		\
							\
-	__mutex_init((mutex), #mutex, &__key);		\
+	__mutex_init((mutex), #mutex, &__key, 0);	\
} while (0)
+
+/**
+ * mutex_init_locked - initialize the mutex
+ * @mutex: the mutex to be initialized
+ *
+ * Initialize the mutex to locked state.
+ *
+ * It is not allowed to re-initialize an already locked mutex.
+ */
+# define mutex_init_locked(mutex) \
+do {							\
+	static struct lock_class_key __key;		\
+							\
+	__mutex_init((mutex), #mutex, &__key, 1);	\
+} while (0)
+
static inline void mutex_destroy(struct mutex *lock) {}
#endif

@@ -117,7 +133,7 @@ static inline void mutex_destroy(struct mutex *lock) {}
	struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)

extern void __mutex_init(struct mutex *lock, const char *name,
-			 struct lock_class_key *key);
+			 struct lock_class_key *key, int locked);

/**
 * mutex_is_locked - is the mutex locked
diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
index e364b42..a9cc497 100644
--- a/kernel/locking/mutex.c
+++ b/kernel/locking/mutex.c
@@ -47,12 +47,16 @@
#endif

void
-__mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
+__mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key,
+	     int locked)
{
-	atomic_set(&lock->count, 1);
+	atomic_set(&lock->count, !lock);
	spin_lock_init(&lock->wait_lock);
	INIT_LIST_HEAD(&lock->wait_list);
-	mutex_clear_owner(lock);
+	if (locked)
+		mutex_set_owner(lock);
+	else
+		mutex_clear_owner(lock);
#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
	osq_lock_init(&lock->osq);
#endif
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 6470eb8..6df6bb3 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -930,7 +930,7 @@ int bus_register(struct bus_type *bus)
	}

	INIT_LIST_HEAD(&priv->interfaces);
-	__mutex_init(&priv->mutex, "subsys mutex", key);
+	__mutex_init(&priv->mutex, "subsys mutex", key, 0);
	klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
	klist_init(&priv->klist_drivers, NULL, NULL);

diff --git a/drivers/base/class.c b/drivers/base/class.c
index 71059e3..a7e8031 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -176,7 +176,7 @@ int __class_register(struct class *cls, struct lock_class_key *key)
	klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put);
	INIT_LIST_HEAD(&cp->interfaces);
	kset_init(&cp->glue_dirs);
-	__mutex_init(&cp->mutex, "subsys mutex", key);
+	__mutex_init(&cp->mutex, "subsys mutex", key, 0);
	error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name);
	if (error) {
		kfree(cp);
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c
index b185578..7b0b022 100644
--- a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c
+++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c
@@ -198,6 +198,6 @@ nvkm_subdev_ctor(const struct nvkm_subdev_func *func,
	subdev->device = device;
	subdev->index = index;

-	__mutex_init(&subdev->mutex, name, &nvkm_subdev_lock_class[index]);
+	__mutex_init(&subdev->mutex, name, &nvkm_subdev_lock_class[index], 0);
	subdev->debug = nvkm_dbgopt(device->dbgopt, name);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c
index 5df9669..57fa64e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c
@@ -372,7 +372,7 @@ nvkm_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset,
	if (!vm)
		return -ENOMEM;

-	__mutex_init(&vm->mutex, "&vm->mutex", key ? key : &_key);
+	__mutex_init(&vm->mutex, "&vm->mutex", key ? key : &_key, 0);
	INIT_LIST_HEAD(&vm->pgd_list);
	vm->mmu = mmu;
	kref_init(&vm->refcount);
diff --git a/include/linux/ww_mutex.h b/include/linux/ww_mutex.h
index 760399a..22bc051 100644
--- a/include/linux/ww_mutex.h
+++ b/include/linux/ww_mutex.h
@@ -85,7 +85,7 @@ struct ww_mutex {
static inline void ww_mutex_init(struct ww_mutex *lock,
				 struct ww_class *ww_class)
{
-	__mutex_init(&lock->base, ww_class->mutex_name, &ww_class->mutex_key);
+	__mutex_init(&lock->base, ww_class->mutex_name, &ww_class->mutex_key, 0);
	lock->ctx = NULL;
#ifdef CONFIG_DEBUG_MUTEXES
	lock->ww_class = ww_class;
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
index 803001a..b9f87a3 100644
--- a/net/netfilter/ipvs/ip_vs_sync.c
+++ b/net/netfilter/ipvs/ip_vs_sync.c
@@ -2009,7 +2009,7 @@ int stop_sync_thread(struct netns_ipvs *ipvs, int state)
 */
int __net_init ip_vs_sync_net_init(struct netns_ipvs *ipvs)
{
-	__mutex_init(&ipvs->sync_mutex, "ipvs->sync_mutex", &__ipvs_sync_key);
+	__mutex_init(&ipvs->sync_mutex, "ipvs->sync_mutex", &__ipvs_sync_key, 0);
	spin_lock_init(&ipvs->sync_lock);
	spin_lock_init(&ipvs->sync_buff_lock);
	return 0;
-- 
2.7.4

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ