* [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 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 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 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-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 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-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-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 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
* 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
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