LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH 1/5] lib: introduce call_once()
@ 2008-03-10 14:57 Akinobu Mita
  2008-03-10 15:00 ` [PATCH 2/5] idr: use call_once() Akinobu Mita
                   ` (3 more replies)
  0 siblings, 4 replies; 19+ messages in thread
From: Akinobu Mita @ 2008-03-10 14:57 UTC (permalink / raw)
  To: linux-kernel; +Cc: akpm

call_once() is an utility function which has similar functionality of
pthread_once().

Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
---
 include/linux/once.h |   42 ++++++++++++++++++++++++++++++++++++++++++
 lib/Makefile         |    2 +-
 lib/once.c           |   18 ++++++++++++++++++
 3 files changed, 61 insertions(+), 1 deletion(-)

Index: 2.6-rc/include/linux/once.h
===================================================================
--- /dev/null
+++ 2.6-rc/include/linux/once.h
@@ -0,0 +1,42 @@
+#ifndef __LINUX_ONCE_H
+#define __LINUX_ONCE_H
+
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+
+struct once_control {
+	struct mutex lock;
+	int done;
+};
+
+#define __ONCE_INITIALIZER(name) {					\
+		.lock		= __MUTEX_INITIALIZER(name.lock),	\
+		.done		= 0,					\
+	}
+
+#define DEFINE_ONCE(name) struct once_control name = __ONCE_INITIALIZER(name)
+
+extern int call_once_slow(struct once_control *once_control,
+			  int (*init_rouine)(void));
+
+/*
+ * call_once - call the initialization function only once
+ *
+ * @once_control: guarantee that the init_routine will be called only once
+ * @init_routine: initialization function
+ *
+ * The first call to call_once(), with a given once_control, shall call the
+ * init_routine with no arguments and return the value init_routine returned.
+ * If the init_routine returns zero which indicates the initialization
+ * succeeded, subsequent calls of call_once() with the same once_control shall
+ * not call the init_routine and return zero.
+ */
+
+static inline int call_once(struct once_control *once_control,
+			    int (*init_rouine)(void))
+{
+	return likely(once_control->done) ? 0
+			: call_once_slow(once_control, init_rouine);
+}
+
+#endif /* __LINUX_ONCE_H */
Index: 2.6-rc/lib/once.c
===================================================================
--- /dev/null
+++ 2.6-rc/lib/once.c
@@ -0,0 +1,18 @@
+#include <linux/module.h>
+#include <linux/once.h>
+
+int call_once_slow(struct once_control *once_control, int (*init_rouine)(void))
+{
+	int err = 0;
+
+	mutex_lock(&once_control->lock);
+	if (!once_control->done) {
+		err = init_rouine();
+		if (!err)
+			once_control->done = 1;
+	}
+	mutex_unlock(&once_control->lock);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(call_once_slow);
Index: 2.6-rc/lib/Makefile
===================================================================
--- 2.6-rc.orig/lib/Makefile
+++ 2.6-rc/lib/Makefile
@@ -14,7 +14,7 @@ lib-$(CONFIG_SMP) += cpumask.o
 lib-y	+= kobject.o kref.o klist.o
 
 obj-y += div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
-	 bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o
+	 bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o once.o
 
 ifeq ($(CONFIG_DEBUG_KOBJECT),y)
 CFLAGS_kobject.o += -DDEBUG

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 2/5] idr: use call_once()
  2008-03-10 14:57 [PATCH 1/5] lib: introduce call_once() Akinobu Mita
@ 2008-03-10 15:00 ` Akinobu Mita
  2008-03-10 15:01   ` [PATCH 3/5] hugetlbfs: " Akinobu Mita
  2008-03-10 15:29 ` [PATCH 1/5] lib: introduce call_once() Joe Perches
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 19+ messages in thread
From: Akinobu Mita @ 2008-03-10 15:00 UTC (permalink / raw)
  To: linux-kernel; +Cc: akpm

idr_layer_cache is created when idr_init() is called first time by someone.

This patch makes the idr_layer_cache initialization to use call_once().

This conversion prevents an unlikely race condition when two idr_init()
callers attempt to create idr_layer_cache simultaneously.

Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
---
 lib/idr.c |   13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

Index: 2.6-rc/lib/idr.c
===================================================================
--- 2.6-rc.orig/lib/idr.c
+++ 2.6-rc/lib/idr.c
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/once.h>
 #endif
 #include <linux/err.h>
 #include <linux/string.h>
@@ -585,12 +586,12 @@ static void idr_cache_ctor(struct kmem_c
 	memset(idr_layer, 0, sizeof(struct idr_layer));
 }
 
-static  int init_id_cache(void)
+static int init_id_cache(void)
 {
-	if (!idr_layer_cache)
-		idr_layer_cache = kmem_cache_create("idr_layer_cache",
+	idr_layer_cache = kmem_cache_create("idr_layer_cache",
 			sizeof(struct idr_layer), 0, 0, idr_cache_ctor);
-	return 0;
+
+	return !idr_layer_cache ? -ENOMEM : 0;
 }
 
 /**
@@ -602,7 +603,9 @@ static  int init_id_cache(void)
  */
 void idr_init(struct idr *idp)
 {
-	init_id_cache();
+	static DEFINE_ONCE(once);
+
+	call_once(&once, init_id_cache);
 	memset(idp, 0, sizeof(struct idr));
 	spin_lock_init(&idp->lock);
 }

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 3/5] hugetlbfs: use call_once()
  2008-03-10 15:00 ` [PATCH 2/5] idr: use call_once() Akinobu Mita
@ 2008-03-10 15:01   ` Akinobu Mita
  2008-03-10 15:03     ` [PATCH 4/5] shmem: " Akinobu Mita
  0 siblings, 1 reply; 19+ messages in thread
From: Akinobu Mita @ 2008-03-10 15:01 UTC (permalink / raw)
  To: linux-kernel; +Cc: akpm, William Irwin, linux-fsdevel

This patch defers mounting hugetlbfs till hugetlb_file_setup() is
called first time by using call_once().

Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Cc: William Irwin <wli@holomorphy.com>
---
 fs/hugetlbfs/inode.c |   30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

Index: 2.6-rc/fs/hugetlbfs/inode.c
===================================================================
--- 2.6-rc.orig/fs/hugetlbfs/inode.c
+++ 2.6-rc/fs/hugetlbfs/inode.c
@@ -31,6 +31,7 @@
 #include <linux/dnotify.h>
 #include <linux/statfs.h>
 #include <linux/security.h>
+#include <linux/once.h>
 
 #include <asm/uaccess.h>
 
@@ -903,6 +904,13 @@ static struct file_system_type hugetlbfs
 
 static struct vfsmount *hugetlbfs_vfsmount;
 
+static int init_hugetlbfs_vfsmount(void)
+{
+	hugetlbfs_vfsmount = kern_mount(&hugetlbfs_fs_type);
+
+	return IS_ERR(hugetlbfs_vfsmount) ? PTR_ERR(hugetlbfs_vfsmount) : 0;
+}
+
 static int can_do_hugetlb_shm(void)
 {
 	return likely(capable(CAP_IPC_LOCK) ||
@@ -912,14 +920,16 @@ static int can_do_hugetlb_shm(void)
 
 struct file *hugetlb_file_setup(const char *name, size_t size)
 {
-	int error = -ENOMEM;
+	int error;
 	struct file *file;
 	struct inode *inode;
 	struct dentry *dentry, *root;
 	struct qstr quick_string;
+	static DEFINE_ONCE(once);
 
-	if (!hugetlbfs_vfsmount)
-		return ERR_PTR(-ENOENT);
+	error = call_once(&once, init_hugetlbfs_vfsmount);
+	if (error)
+		return ERR_PTR(error);
 
 	if (!can_do_hugetlb_shm())
 		return ERR_PTR(-EPERM);
@@ -970,7 +980,6 @@ out_shm_unlock:
 static int __init init_hugetlbfs_fs(void)
 {
 	int error;
-	struct vfsmount *vfsmount;
 
 	error = bdi_init(&hugetlbfs_backing_dev_info);
 	if (error)
@@ -986,18 +995,9 @@ static int __init init_hugetlbfs_fs(void
 	if (error)
 		goto out;
 
-	vfsmount = kern_mount(&hugetlbfs_fs_type);
-
-	if (!IS_ERR(vfsmount)) {
-		hugetlbfs_vfsmount = vfsmount;
-		return 0;
-	}
-
-	error = PTR_ERR(vfsmount);
-
+	return 0;
  out:
-	if (error)
-		kmem_cache_destroy(hugetlbfs_inode_cachep);
+	kmem_cache_destroy(hugetlbfs_inode_cachep);
  out2:
 	bdi_destroy(&hugetlbfs_backing_dev_info);
 	return error;

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 4/5] shmem: use call_once()
  2008-03-10 15:01   ` [PATCH 3/5] hugetlbfs: " Akinobu Mita
@ 2008-03-10 15:03     ` Akinobu Mita
  2008-03-10 15:05       ` [PATCH 5/5] tiny-shmem: " Akinobu Mita
  2008-03-10 22:15       ` [PATCH 4/5] shmem: " Hugh Dickins
  0 siblings, 2 replies; 19+ messages in thread
From: Akinobu Mita @ 2008-03-10 15:03 UTC (permalink / raw)
  To: linux-kernel; +Cc: akpm, linux-fsdevel

This patch defers mounting tmpfs till shmem_file_setup() is
called first time by using call_once().

Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
---
 mm/shmem.c |   32 ++++++++++++++++++--------------
 1 file changed, 18 insertions(+), 14 deletions(-)

Index: 2.6-rc/mm/shmem.c
===================================================================
--- 2.6-rc.orig/mm/shmem.c
+++ 2.6-rc/mm/shmem.c
@@ -50,6 +50,7 @@
 #include <linux/migrate.h>
 #include <linux/highmem.h>
 #include <linux/seq_file.h>
+#include <linux/once.h>
 
 #include <asm/uaccess.h>
 #include <asm/div64.h>
@@ -2520,7 +2521,6 @@ static struct file_system_type tmpfs_fs_
 	.get_sb		= shmem_get_sb,
 	.kill_sb	= kill_litter_super,
 };
-static struct vfsmount *shm_mnt;
 
 static int __init init_tmpfs(void)
 {
@@ -2540,27 +2540,29 @@ static int __init init_tmpfs(void)
 		goto out2;
 	}
 
-	shm_mnt = vfs_kern_mount(&tmpfs_fs_type, MS_NOUSER,
-				tmpfs_fs_type.name, NULL);
-	if (IS_ERR(shm_mnt)) {
-		error = PTR_ERR(shm_mnt);
-		printk(KERN_ERR "Could not kern_mount tmpfs\n");
-		goto out1;
-	}
 	return 0;
-
-out1:
-	unregister_filesystem(&tmpfs_fs_type);
 out2:
 	destroy_inodecache();
 out3:
 	bdi_destroy(&shmem_backing_dev_info);
 out4:
-	shm_mnt = ERR_PTR(error);
 	return error;
 }
 module_init(init_tmpfs)
 
+static struct vfsmount *shm_mnt;
+
+static int init_shm_mnt(void)
+{
+	shm_mnt = vfs_kern_mount(&tmpfs_fs_type, MS_NOUSER,
+				tmpfs_fs_type.name, NULL);
+	if (IS_ERR(shm_mnt)) {
+		printk(KERN_ERR "Could not kern_mount tmpfs\n");
+		return PTR_ERR(shm_mnt);
+	}
+	return 0;
+}
+
 /*
  * shmem_file_setup - get an unlinked file living in tmpfs
  *
@@ -2575,9 +2577,11 @@ struct file *shmem_file_setup(char *name
 	struct inode *inode;
 	struct dentry *dentry, *root;
 	struct qstr this;
+	static DEFINE_ONCE(once);
 
-	if (IS_ERR(shm_mnt))
-		return (void *)shm_mnt;
+	error = call_once(&once, init_shm_mnt);
+	if (error)
+		return ERR_PTR(error);
 
 	if (size < 0 || size > SHMEM_MAX_BYTES)
 		return ERR_PTR(-EINVAL);

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 5/5] tiny-shmem: use call_once()
  2008-03-10 15:03     ` [PATCH 4/5] shmem: " Akinobu Mita
@ 2008-03-10 15:05       ` Akinobu Mita
  2008-03-10 22:15       ` [PATCH 4/5] shmem: " Hugh Dickins
  1 sibling, 0 replies; 19+ messages in thread
From: Akinobu Mita @ 2008-03-10 15:05 UTC (permalink / raw)
  To: linux-kernel; +Cc: akpm, linux-fsdevel

This patch defers mounting tmpfs till shmem_file_setup() is
called first time by using call_once().

Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
---
 mm/tiny-shmem.c |   21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

Index: 2.6-rc/mm/tiny-shmem.c
===================================================================
--- 2.6-rc.orig/mm/tiny-shmem.c
+++ 2.6-rc/mm/tiny-shmem.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/swap.h>
 #include <linux/ramfs.h>
+#include <linux/once.h>
 
 static struct file_system_type tmpfs_fs_type = {
 	.name		= "tmpfs",
@@ -26,19 +27,23 @@ static struct file_system_type tmpfs_fs_
 	.kill_sb	= kill_litter_super,
 };
 
-static struct vfsmount *shm_mnt;
-
 static int __init init_tmpfs(void)
 {
 	BUG_ON(register_filesystem(&tmpfs_fs_type) != 0);
 
-	shm_mnt = kern_mount(&tmpfs_fs_type);
-	BUG_ON(IS_ERR(shm_mnt));
-
 	return 0;
 }
 module_init(init_tmpfs)
 
+static struct vfsmount *shm_mnt;
+
+static int init_shm_mnt(void)
+{
+	shm_mnt = kern_mount(&tmpfs_fs_type);
+
+	return IS_ERR(shm_mnt) ? PTR_ERR(shm_mnt) : 0;
+}
+
 /*
  * shmem_file_setup - get an unlinked file living in tmpfs
  *
@@ -53,9 +58,11 @@ struct file *shmem_file_setup(char *name
 	struct inode *inode;
 	struct dentry *dentry, *root;
 	struct qstr this;
+	static DEFINE_ONCE(once);
 
-	if (IS_ERR(shm_mnt))
-		return (void *)shm_mnt;
+	error = call_once(&once, init_shm_mnt);
+	if (error)
+		return ERR_PTR(error);
 
 	error = -ENOMEM;
 	this.name = name;

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/5] lib: introduce call_once()
  2008-03-10 14:57 [PATCH 1/5] lib: introduce call_once() Akinobu Mita
  2008-03-10 15:00 ` [PATCH 2/5] idr: use call_once() Akinobu Mita
@ 2008-03-10 15:29 ` Joe Perches
  2008-03-11 12:17   ` Akinobu Mita
  2008-03-11  3:48 ` Andrew Morton
  2008-03-11 12:41 ` Nick Piggin
  3 siblings, 1 reply; 19+ messages in thread
From: Joe Perches @ 2008-03-10 15:29 UTC (permalink / raw)
  To: Akinobu Mita; +Cc: linux-kernel, akpm

On Mon, 2008-03-10 at 23:57 +0900, Akinobu Mita wrote:
> +++ 2.6-rc/include/linux/once.h
> +struct once_control {
> +	struct mutex lock;
> +	int done;

bool?

> +};
> +
> +#define __ONCE_INITIALIZER(name) {					\
> +		.lock		= __MUTEX_INITIALIZER(name.lock),	\
> +		.done		= 0,					\
> +	}
> +
> +#define DEFINE_ONCE(name) struct once_control name = __ONCE_INITIALIZER(name)

static?

> +
> +extern int call_once_slow(struct once_control *once_control,
> +			  int (*init_rouine)(void));

return bool?
spelling: s/rouine/routine/g



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 4/5] shmem: use call_once()
  2008-03-10 15:03     ` [PATCH 4/5] shmem: " Akinobu Mita
  2008-03-10 15:05       ` [PATCH 5/5] tiny-shmem: " Akinobu Mita
@ 2008-03-10 22:15       ` Hugh Dickins
  2008-03-11 12:29         ` Akinobu Mita
  1 sibling, 1 reply; 19+ messages in thread
From: Hugh Dickins @ 2008-03-10 22:15 UTC (permalink / raw)
  To: Akinobu Mita; +Cc: linux-kernel, akpm, linux-fsdevel

On Tue, 11 Mar 2008, Akinobu Mita wrote:
> This patch defers mounting tmpfs till shmem_file_setup() is
> called first time by using call_once().

Please explain why we might need this patch: is something changing
elsewhere?  Or are you misled by that "module_init(init_tmpfs)"
into thinking that mm/shmem.c is sometimes built modular?

Hugh

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/5] lib: introduce call_once()
  2008-03-10 14:57 [PATCH 1/5] lib: introduce call_once() Akinobu Mita
  2008-03-10 15:00 ` [PATCH 2/5] idr: use call_once() Akinobu Mita
  2008-03-10 15:29 ` [PATCH 1/5] lib: introduce call_once() Joe Perches
@ 2008-03-11  3:48 ` Andrew Morton
  2008-03-11  4:10   ` Nick Piggin
  2008-03-11 12:41 ` Nick Piggin
  3 siblings, 1 reply; 19+ messages in thread
From: Andrew Morton @ 2008-03-11  3:48 UTC (permalink / raw)
  To: Akinobu Mita; +Cc: linux-kernel

On Mon, 10 Mar 2008 23:57:05 +0900 Akinobu Mita <akinobu.mita@gmail.com> wrote:

> call_once() is an utility function which has similar functionality of
> pthread_once().
> 
> +/*
> + * call_once - call the initialization function only once
> + *
> + * @once_control: guarantee that the init_routine will be called only once
> + * @init_routine: initialization function
> + *
> + * The first call to call_once(), with a given once_control, shall call the
> + * init_routine with no arguments and return the value init_routine returned.
> + * If the init_routine returns zero which indicates the initialization
> + * succeeded, subsequent calls of call_once() with the same once_control shall
> + * not call the init_routine and return zero.
> + */
> +
> +static inline int call_once(struct once_control *once_control,
> +			    int (*init_rouine)(void))
> +{
> +	return likely(once_control->done) ? 0
> +			: call_once_slow(once_control, init_rouine);
> +}

I don't believe that this shold be described in terms of an "init_routine". 
This mechanism can be used for things other than initialisation routines.

It is spelled "routine", not "rouine".


Would it not be simpler and more general to do:

#define ONCE()						\
	({						\
		static long flag;			\
							\
		return !test_and_set_bit(0, flag);	\
	})

and then callers can do

	if (ONCE())
		do_something();

?

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/5] lib: introduce call_once()
  2008-03-11  3:48 ` Andrew Morton
@ 2008-03-11  4:10   ` Nick Piggin
  2008-03-11  4:21     ` Andrew Morton
  0 siblings, 1 reply; 19+ messages in thread
From: Nick Piggin @ 2008-03-11  4:10 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Akinobu Mita, linux-kernel

On Tuesday 11 March 2008 14:48, Andrew Morton wrote:
> On Mon, 10 Mar 2008 23:57:05 +0900 Akinobu Mita <akinobu.mita@gmail.com> 
wrote:
> > call_once() is an utility function which has similar functionality of
> > pthread_once().
> >
> > +/*
> > + * call_once - call the initialization function only once
> > + *
> > + * @once_control: guarantee that the init_routine will be called only
> > once + * @init_routine: initialization function
> > + *
> > + * The first call to call_once(), with a given once_control, shall call
> > the + * init_routine with no arguments and return the value init_routine
> > returned. + * If the init_routine returns zero which indicates the
> > initialization + * succeeded, subsequent calls of call_once() with the
> > same once_control shall + * not call the init_routine and return zero.
> > + */
> > +
> > +static inline int call_once(struct once_control *once_control,
> > +			    int (*init_rouine)(void))
> > +{
> > +	return likely(once_control->done) ? 0
> > +			: call_once_slow(once_control, init_rouine);
> > +}
>
> I don't believe that this shold be described in terms of an "init_routine".
> This mechanism can be used for things other than initialisation routines.
>
> It is spelled "routine", not "rouine".
>
>
> Would it not be simpler and more general to do:
>
> #define ONCE()						\
> 	({						\
> 		static long flag;			\
> 							\
> 		return !test_and_set_bit(0, flag);	\
> 	})
>
> and then callers can do
>
> 	if (ONCE())
> 		do_something();
>
> ?

Isn't this usually going to be buggy if you have concurrent access
here? I'd prefer to keep synchronisation details in the caller and
not have this call_once at all.


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/5] lib: introduce call_once()
  2008-03-11  4:10   ` Nick Piggin
@ 2008-03-11  4:21     ` Andrew Morton
  2008-03-11 12:27       ` Akinobu Mita
  0 siblings, 1 reply; 19+ messages in thread
From: Andrew Morton @ 2008-03-11  4:21 UTC (permalink / raw)
  To: Nick Piggin; +Cc: Akinobu Mita, linux-kernel

On Tue, 11 Mar 2008 15:10:52 +1100 Nick Piggin <nickpiggin@yahoo.com.au> wrote:

> On Tuesday 11 March 2008 14:48, Andrew Morton wrote:
> > On Mon, 10 Mar 2008 23:57:05 +0900 Akinobu Mita <akinobu.mita@gmail.com> 
> wrote:
> > > call_once() is an utility function which has similar functionality of
> > > pthread_once().
> > >
> > > +/*
> > > + * call_once - call the initialization function only once
> > > + *
> > > + * @once_control: guarantee that the init_routine will be called only
> > > once + * @init_routine: initialization function
> > > + *
> > > + * The first call to call_once(), with a given once_control, shall call
> > > the + * init_routine with no arguments and return the value init_routine
> > > returned. + * If the init_routine returns zero which indicates the
> > > initialization + * succeeded, subsequent calls of call_once() with the
> > > same once_control shall + * not call the init_routine and return zero.
> > > + */
> > > +
> > > +static inline int call_once(struct once_control *once_control,
> > > +			    int (*init_rouine)(void))
> > > +{
> > > +	return likely(once_control->done) ? 0
> > > +			: call_once_slow(once_control, init_rouine);
> > > +}
> >
> > I don't believe that this shold be described in terms of an "init_routine".
> > This mechanism can be used for things other than initialisation routines.
> >
> > It is spelled "routine", not "rouine".
> >
> >
> > Would it not be simpler and more general to do:
> >
> > #define ONCE()						\
> > 	({						\
> > 		static long flag;			\
> > 							\
> > 		return !test_and_set_bit(0, flag);	\
> > 	})
> >
> > and then callers can do
> >
> > 	if (ONCE())
> > 		do_something();
> >
> > ?
> 
> Isn't this usually going to be buggy if you have concurrent access
> here? I'd prefer to keep synchronisation details in the caller and
> not have this call_once at all.

Well, I'm a bit dubious about the calue of all of this (althoug I didn't
review the callers).

But the above code is guaranteed race-free ;)

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/5] lib: introduce call_once()
  2008-03-10 15:29 ` [PATCH 1/5] lib: introduce call_once() Joe Perches
@ 2008-03-11 12:17   ` Akinobu Mita
  0 siblings, 0 replies; 19+ messages in thread
From: Akinobu Mita @ 2008-03-11 12:17 UTC (permalink / raw)
  To: Joe Perches; +Cc: linux-kernel, akpm

2008/3/11, Joe Perches <joe@perches.com>:
> On Mon, 2008-03-10 at 23:57 +0900, Akinobu Mita wrote:
>  > +++ 2.6-rc/include/linux/once.h
>
> > +struct once_control {
>  > +     struct mutex lock;
>  > +     int done;
>
>
> bool?

Yes, this definetly should be bool.

>  > +};
>  > +
>  > +#define __ONCE_INITIALIZER(name) {                                   \
>  > +             .lock           = __MUTEX_INITIALIZER(name.lock),       \
>  > +             .done           = 0,                                    \
>  > +     }
>  > +
>  > +#define DEFINE_ONCE(name) struct once_control name = __ONCE_INITIALIZER(name)
>
>
> static?

no, static keyword should not be implicitly added in this macro.
DEFINE_ONCE is intended to be anologous to DEFINE_LOCK, DEFINE_WAIT,
and all other similar interfaces in kernel.

>  > +
>  > +extern int call_once_slow(struct once_control *once_control,
>  > +                       int (*init_rouine)(void));
>
>
> return bool?

call_once() returns error-code when init_routine fails.

>  spelling: s/rouine/routine/g

Oops, thanks.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/5] lib: introduce call_once()
  2008-03-11  4:21     ` Andrew Morton
@ 2008-03-11 12:27       ` Akinobu Mita
  2008-03-11 17:35         ` Andrew Morton
  0 siblings, 1 reply; 19+ messages in thread
From: Akinobu Mita @ 2008-03-11 12:27 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Nick Piggin, linux-kernel

2008/3/11, Andrew Morton <akpm@linux-foundation.org>:
> On Tue, 11 Mar 2008 15:10:52 +1100 Nick Piggin <nickpiggin@yahoo.com.au> wrote:
>
>  > On Tuesday 11 March 2008 14:48, Andrew Morton wrote:
>  > > On Mon, 10 Mar 2008 23:57:05 +0900 Akinobu Mita <akinobu.mita@gmail.com>
>  > wrote:
>  > > > call_once() is an utility function which has similar functionality of
>  > > > pthread_once().
>  > > >
>  > > > +/*
>  > > > + * call_once - call the initialization function only once
>  > > > + *
>  > > > + * @once_control: guarantee that the init_routine will be called only
>  > > > once + * @init_routine: initialization function
>  > > > + *
>  > > > + * The first call to call_once(), with a given once_control, shall call
>  > > > the + * init_routine with no arguments and return the value init_routine
>  > > > returned. + * If the init_routine returns zero which indicates the
>  > > > initialization + * succeeded, subsequent calls of call_once() with the
>  > > > same once_control shall + * not call the init_routine and return zero.
>  > > > + */
>  > > > +
>  > > > +static inline int call_once(struct once_control *once_control,
>  > > > +                     int (*init_rouine)(void))
>  > > > +{
>  > > > + return likely(once_control->done) ? 0
>  > > > +                 : call_once_slow(once_control, init_rouine);
>  > > > +}
>  > >
>  > > I don't believe that this shold be described in terms of an "init_routine".
>  > > This mechanism can be used for things other than initialisation routines.
>  > >
>  > > It is spelled "routine", not "rouine".
>  > >
>  > >
>  > > Would it not be simpler and more general to do:
>  > >
>  > > #define ONCE()                                              \
>  > >     ({                                              \
>  > >             static long flag;                       \
>  > >                                                     \
>  > >             return !test_and_set_bit(0, flag);      \
>  > >     })
>  > >
>  > > and then callers can do
>  > >
>  > >     if (ONCE())
>  > >             do_something();
>  > >
>  > > ?

This cannot be used directly in the conversions of patch 2 - 5.
Because the callers of call_once() in patch 2 - 5 need to wait for the
complition of "init_routine". Some blocking mechanism is needed.

>  > Isn't this usually going to be buggy if you have concurrent access
>  > here? I'd prefer to keep synchronisation details in the caller and
>  > not have this call_once at all.
>
>
> Well, I'm a bit dubious about the calue of all of this (althoug I didn't
>  review the callers).
>

I'll try to find another conversions to back up the necessity...

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 4/5] shmem: use call_once()
  2008-03-10 22:15       ` [PATCH 4/5] shmem: " Hugh Dickins
@ 2008-03-11 12:29         ` Akinobu Mita
  2008-03-11 13:41           ` Hugh Dickins
  0 siblings, 1 reply; 19+ messages in thread
From: Akinobu Mita @ 2008-03-11 12:29 UTC (permalink / raw)
  To: Hugh Dickins; +Cc: linux-kernel, akpm, linux-fsdevel

2008/3/11, Hugh Dickins <hugh@veritas.com>:
> On Tue, 11 Mar 2008, Akinobu Mita wrote:
>  > This patch defers mounting tmpfs till shmem_file_setup() is
>  > called first time by using call_once().
>
>
> Please explain why we might need this patch: is something changing
>  elsewhere?  Or are you misled by that "module_init(init_tmpfs)"
>  into thinking that mm/shmem.c is sometimes built modular?
>

If no processes call shmem_file_setup() (via shm_get(2)), it is unnecessary
to do vfs_kern_mount(&tmpfs_fs_type, ...) unconditionary in boot-time.
So I thought it is suitable example to demonstrate how to use "call_once()"
in this patch set.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/5] lib: introduce call_once()
  2008-03-10 14:57 [PATCH 1/5] lib: introduce call_once() Akinobu Mita
                   ` (2 preceding siblings ...)
  2008-03-11  3:48 ` Andrew Morton
@ 2008-03-11 12:41 ` Nick Piggin
  3 siblings, 0 replies; 19+ messages in thread
From: Nick Piggin @ 2008-03-11 12:41 UTC (permalink / raw)
  To: Akinobu Mita; +Cc: linux-kernel, akpm

On Tuesday 11 March 2008 01:57, Akinobu Mita wrote:

> +static inline int call_once(struct once_control *once_control,
> +			    int (*init_rouine)(void))
> +{
> +	return likely(once_control->done) ? 0
> +			: call_once_slow(once_control, init_rouine);
> +}
> +
> +#endif /* __LINUX_ONCE_H */
> Index: 2.6-rc/lib/once.c
> ===================================================================
> --- /dev/null
> +++ 2.6-rc/lib/once.c
> @@ -0,0 +1,18 @@
> +#include <linux/module.h>
> +#include <linux/once.h>
> +
> +int call_once_slow(struct once_control *once_control, int
> (*init_rouine)(void)) +{
> +	int err = 0;
> +
> +	mutex_lock(&once_control->lock);
> +	if (!once_control->done) {
> +		err = init_rouine();
> +		if (!err)
> +			once_control->done = 1;
> +	}
> +	mutex_unlock(&once_control->lock);
> +
> +	return err;
> +}
> +EXPORT_SYMBOL_GPL(call_once_slow);

The store "once_control->done = 1" can become visible before
init_routine has finished. The code after calling call_once may
also speculatively load some memory before the load of
once_control->done completes, so you can likewise have a data
race that way too.

To fix this, you need smp_wmb after init_rouine(), and probably
smp_mb() in the fastpath after the check but before returning.

Basically any time you have this situation where you're touching
a shared variable without using locks, then you're vastly
increasing the complexity of the code, and so you must have a
good reason for it.

So acquiring the mutex unconditionally would be the best way to
go, unless you're calling this a lot in fastpaths (in which case
I would say you should probably rework your code)

Thanks,
Nick


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 4/5] shmem: use call_once()
  2008-03-11 12:29         ` Akinobu Mita
@ 2008-03-11 13:41           ` Hugh Dickins
  0 siblings, 0 replies; 19+ messages in thread
From: Hugh Dickins @ 2008-03-11 13:41 UTC (permalink / raw)
  To: Akinobu Mita
  Cc: linux-kernel, akpm, linux-fsdevel, William Irwin, Matt Mackall

On Tue, 11 Mar 2008, Akinobu Mita wrote:
> 2008/3/11, Hugh Dickins <hugh@veritas.com>:
> > On Tue, 11 Mar 2008, Akinobu Mita wrote:
> >  > This patch defers mounting tmpfs till shmem_file_setup() is
> >  > called first time by using call_once().
> >
> > Please explain why we might need this patch: is something changing
> >  elsewhere?  Or are you misled by that "module_init(init_tmpfs)"
> >  into thinking that mm/shmem.c is sometimes built modular?
> 
> If no processes call shmem_file_setup() (via shm_get(2)), it is unnecessary
                                       or shmem_zero_setup, not very common
> to do vfs_kern_mount(&tmpfs_fs_type, ...) unconditionary in boot-time.
> So I thought it is suitable example to demonstrate how to use "call_once()"
> in this patch set.

Oh, I see, thanks.  Well, I don't feel all that strongly about it; but
on the whole I'd prefer we leave it as part of the __init, than change
it around to provide this example (and risk introducing some weird issue
e.g. related to its "dev"?).  I guess the same should go for the huge
and the tiny, whereas you have better justification in the idr case.
Call me over-cautious.

Hugh

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/5] lib: introduce call_once()
  2008-03-11 12:27       ` Akinobu Mita
@ 2008-03-11 17:35         ` Andrew Morton
  2008-03-11 18:56           ` Joe Perches
  2008-03-15  4:01           ` Akinobu Mita
  0 siblings, 2 replies; 19+ messages in thread
From: Andrew Morton @ 2008-03-11 17:35 UTC (permalink / raw)
  To: Akinobu Mita; +Cc: nickpiggin, linux-kernel

On Tue, 11 Mar 2008 21:27:30 +0900
"Akinobu Mita" <akinobu.mita@gmail.com> wrote:

> 2008/3/11, Andrew Morton <akpm@linux-foundation.org>:
> > On Tue, 11 Mar 2008 15:10:52 +1100 Nick Piggin <nickpiggin@yahoo.com.au> wrote:
> >
> >  > > #define ONCE()                                              \
> >  > >     ({                                              \
> >  > >             static long flag;                       \
> >  > >                                                     \
> >  > >             return !test_and_set_bit(0, flag);      \
> >  > >     })
> >  > >
> >  > > and then callers can do
> >  > >
> >  > >     if (ONCE())
> >  > >             do_something();
> >  > >
> >  > > ?
> 
> This cannot be used directly in the conversions of patch 2 - 5.
> Because the callers of call_once() in patch 2 - 5 need to wait for the
> complition of "init_routine". Some blocking mechanism is needed.

Of course it can be used in those places.  Here's the idr.c conversion:

--- a/lib/idr.c~a
+++ a/lib/idr.c
@@ -585,14 +585,6 @@ static void idr_cache_ctor(struct kmem_c
 	memset(idr_layer, 0, sizeof(struct idr_layer));
 }
 
-static  int init_id_cache(void)
-{
-	if (!idr_layer_cache)
-		idr_layer_cache = kmem_cache_create("idr_layer_cache",
-			sizeof(struct idr_layer), 0, 0, idr_cache_ctor);
-	return 0;
-}
-
 /**
  * idr_init - initialize idr handle
  * @idp:	idr handle
@@ -602,7 +594,9 @@ static  int init_id_cache(void)
  */
 void idr_init(struct idr *idp)
 {
-	init_id_cache();
+	if (ONCE())
+		idr_layer_cache = kmem_cache_create("idr_layer_cache",
+			sizeof(struct idr_layer), 0, 0, idr_cache_ctor);
 	memset(idp, 0, sizeof(struct idr));
 	spin_lock_init(&idp->lock);
 }



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/5] lib: introduce call_once()
  2008-03-11 17:35         ` Andrew Morton
@ 2008-03-11 18:56           ` Joe Perches
  2008-03-11 19:11             ` Andrew Morton
  2008-03-15  4:01           ` Akinobu Mita
  1 sibling, 1 reply; 19+ messages in thread
From: Joe Perches @ 2008-03-11 18:56 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Akinobu Mita, nickpiggin, linux-kernel

On Tue, 2008-03-11 at 10:35 -0700, Andrew Morton wrote:
> #define ONCE()                                              \
>     ({                                              \
>             static long flag;                       \
>                                                     \
>             return !test_and_set_bit(0, flag);      \
>     })

test_and_set_bit takes an address

Perhaps:

#define DO_ONCE(x) \
	({ static long flag; if (test_and_set_bit(0, &flag)) x; 1; })

DO_ONCE(foo);


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/5] lib: introduce call_once()
  2008-03-11 18:56           ` Joe Perches
@ 2008-03-11 19:11             ` Andrew Morton
  0 siblings, 0 replies; 19+ messages in thread
From: Andrew Morton @ 2008-03-11 19:11 UTC (permalink / raw)
  To: Joe Perches; +Cc: akinobu.mita, nickpiggin, linux-kernel

On Tue, 11 Mar 2008 11:56:55 -0700
Joe Perches <joe@perches.com> wrote:

> On Tue, 2008-03-11 at 10:35 -0700, Andrew Morton wrote:
> > #define ONCE()                                              \
> >     ({                                              \
> >             static long flag;                       \
> >                                                     \
> >             return !test_and_set_bit(0, flag);      \
> >     })
> 
> test_and_set_bit takes an address

duh.

> Perhaps:
> 
> #define DO_ONCE(x) \
> 	({ static long flag; if (test_and_set_bit(0, &flag)) x; 1; })
> 
> DO_ONCE(foo);

No, that's completely unnecessary and would produce nasty-looking code. 
Take a look at some of the wait_event monstrosities we have.


I'm not sure that we need any of this once() stuff really.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/5] lib: introduce call_once()
  2008-03-11 17:35         ` Andrew Morton
  2008-03-11 18:56           ` Joe Perches
@ 2008-03-15  4:01           ` Akinobu Mita
  1 sibling, 0 replies; 19+ messages in thread
From: Akinobu Mita @ 2008-03-15  4:01 UTC (permalink / raw)
  To: Andrew Morton; +Cc: nickpiggin, linux-kernel

> Of course it can be used in those places.  Here's the idr.c conversion:
> 
> --- a/lib/idr.c~a
> +++ a/lib/idr.c
> @@ -585,14 +585,6 @@ static void idr_cache_ctor(struct kmem_c
>  	memset(idr_layer, 0, sizeof(struct idr_layer));
>  }
>  
> -static  int init_id_cache(void)
> -{
> -	if (!idr_layer_cache)
> -		idr_layer_cache = kmem_cache_create("idr_layer_cache",
> -			sizeof(struct idr_layer), 0, 0, idr_cache_ctor);
> -	return 0;
> -}
> -
>  /**
>   * idr_init - initialize idr handle
>   * @idp:	idr handle
> @@ -602,7 +594,9 @@ static  int init_id_cache(void)
>   */
>  void idr_init(struct idr *idp)
>  {
> -	init_id_cache();
> +	if (ONCE())
> +		idr_layer_cache = kmem_cache_create("idr_layer_cache",
> +			sizeof(struct idr_layer), 0, 0, idr_cache_ctor);
>  	memset(idp, 0, sizeof(struct idr));
>  	spin_lock_init(&idp->lock);
>  }
> 
> 

Maybe this doesn't handle kmem_cache_create() failure.

Anyhow this is the alternative patch to fix what the patch 1/5 was
trying to fix.

Subject: idr: create idr_layer_cache at boot time

This patch checks kmem_cache_create() failure by SLAB_PANIC
by creating idr_layer_cache unconditionary at boot time rather than
creates when idr_init() is called first time by someone.

This change also enables to eliminate unnecessary check every time
idr_init() is called.

Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
---
 include/linux/idr.h |    2 ++
 init/main.c         |    2 ++
 lib/idr.c           |   10 ++++------
 3 files changed, 8 insertions(+), 6 deletions(-)

Index: 2.6-rc/lib/idr.c
===================================================================
--- 2.6-rc.orig/lib/idr.c
+++ 2.6-rc/lib/idr.c
@@ -585,12 +585,11 @@ static void idr_cache_ctor(struct kmem_c
 	memset(idr_layer, 0, sizeof(struct idr_layer));
 }
 
-static  int init_id_cache(void)
+void __init init_id_cache(void)
 {
-	if (!idr_layer_cache)
-		idr_layer_cache = kmem_cache_create("idr_layer_cache",
-			sizeof(struct idr_layer), 0, 0, idr_cache_ctor);
-	return 0;
+	idr_layer_cache = kmem_cache_create("idr_layer_cache",
+				sizeof(struct idr_layer), 0, SLAB_PANIC,
+				idr_cache_ctor);
 }
 
 /**
@@ -602,7 +601,6 @@ static  int init_id_cache(void)
  */
 void idr_init(struct idr *idp)
 {
-	init_id_cache();
 	memset(idp, 0, sizeof(struct idr));
 	spin_lock_init(&idp->lock);
 }
Index: 2.6-rc/include/linux/idr.h
===================================================================
--- 2.6-rc.orig/include/linux/idr.h
+++ 2.6-rc/include/linux/idr.h
@@ -115,4 +115,6 @@ void ida_remove(struct ida *ida, int id)
 void ida_destroy(struct ida *ida);
 void ida_init(struct ida *ida);
 
+void __init init_id_cache(void);
+
 #endif /* __IDR_H__ */
Index: 2.6-rc/init/main.c
===================================================================
--- 2.6-rc.orig/init/main.c
+++ 2.6-rc/init/main.c
@@ -58,6 +58,7 @@
 #include <linux/kthread.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
+#include <linux/idr.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -616,6 +617,7 @@ asmlinkage void __init start_kernel(void
 	enable_debug_pagealloc();
 	cpu_hotplug_init();
 	kmem_cache_init();
+	init_id_cache();
 	setup_per_cpu_pageset();
 	numa_policy_init();
 	if (late_time_init)

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2008-03-15  4:09 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-03-10 14:57 [PATCH 1/5] lib: introduce call_once() Akinobu Mita
2008-03-10 15:00 ` [PATCH 2/5] idr: use call_once() Akinobu Mita
2008-03-10 15:01   ` [PATCH 3/5] hugetlbfs: " Akinobu Mita
2008-03-10 15:03     ` [PATCH 4/5] shmem: " Akinobu Mita
2008-03-10 15:05       ` [PATCH 5/5] tiny-shmem: " Akinobu Mita
2008-03-10 22:15       ` [PATCH 4/5] shmem: " Hugh Dickins
2008-03-11 12:29         ` Akinobu Mita
2008-03-11 13:41           ` Hugh Dickins
2008-03-10 15:29 ` [PATCH 1/5] lib: introduce call_once() Joe Perches
2008-03-11 12:17   ` Akinobu Mita
2008-03-11  3:48 ` Andrew Morton
2008-03-11  4:10   ` Nick Piggin
2008-03-11  4:21     ` Andrew Morton
2008-03-11 12:27       ` Akinobu Mita
2008-03-11 17:35         ` Andrew Morton
2008-03-11 18:56           ` Joe Perches
2008-03-11 19:11             ` Andrew Morton
2008-03-15  4:01           ` Akinobu Mita
2008-03-11 12:41 ` Nick Piggin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).