All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] ipc, mqueue: lazy call kern_mount_data in new namespaces
@ 2017-11-30 18:38 Giuseppe Scrivano
  2017-12-03 18:42 ` kbuild test robot
  0 siblings, 1 reply; 2+ messages in thread
From: Giuseppe Scrivano @ 2017-11-30 18:38 UTC (permalink / raw)
  To: linux-kernel; +Cc: gscrivan, Andrew Morton

kern_mount_data is a relatively expensive operation when creating a
new IPC namespace, so delay the mount until its first usage when not
creating the the global namespace.

This is a net saving for new IPC namespaces that don't use mq_open().
In this case there won't be any kern_mount_data() cost at all.

On my machine, the time for creating 1000 new IPC namespaces dropped
from ~8s to ~2s.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
---

v1 here: https://lkml.org/lkml/2017/11/27/427

v1 -> v2:

Declare and use a mutex instead of a spinlock.

 include/linux/ipc_namespace.h |  2 +-
 ipc/mqueue.c                  | 48 ++++++++++++++++++++++++++++++++++---------
 ipc/namespace.c               |  2 +-
 3 files changed, 40 insertions(+), 12 deletions(-)

diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h
index b5630c8eb2f3..a06617c113f1 100644
--- a/include/linux/ipc_namespace.h
+++ b/include/linux/ipc_namespace.h
@@ -81,7 +81,7 @@ static inline void shm_destroy_orphaned(struct ipc_namespace *ns) {}
 #endif /* CONFIG_SYSVIPC */
 
 #ifdef CONFIG_POSIX_MQUEUE
-extern int mq_init_ns(struct ipc_namespace *ns);
+extern int mq_init_ns(struct ipc_namespace *ns, bool mount);
 /*
  * POSIX Message Queue default values:
  *
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index d24025626310..27a82a3fef50 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -87,6 +87,7 @@ struct mqueue_inode_info {
 	unsigned long qsize; /* size of queue in memory (sum of all msgs) */
 };
 
+static struct file_system_type mqueue_fs_type;
 static const struct inode_operations mqueue_dir_inode_operations;
 static const struct file_operations mqueue_file_operations;
 static const struct super_operations mqueue_super_ops;
@@ -776,9 +777,24 @@ static int do_mq_open(const char __user *u_name, int oflag, umode_t mode,
 	struct filename *name;
 	int fd, error;
 	struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
-	struct vfsmount *mnt = ipc_ns->mq_mnt;
-	struct dentry *root = mnt->mnt_root;
+	struct vfsmount *mnt;
+	struct dentry *root;
 	int ro;
+	static DEFINE_MUTEX(mnt_lock);
+
+	mutex_lock(&mnt_lock);
+	mnt = ipc_ns->mq_mnt;
+	if (unlikely(!mnt)) {
+		mnt = kern_mount_data(&mqueue_fs_type, ipc_ns);
+		if (IS_ERR(mnt)) {
+			mutex_unlock(&mnt_lock);
+			return PTR_ERR(mnt);
+		}
+		ipc_ns->mq_mnt = mnt;
+	}
+	mutex_unlock(&mnt_lock);
+
+	root = mnt->mnt_root;
 
 	audit_mq_open(oflag, mode, attr);
 
@@ -863,6 +879,9 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
 	struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
 	struct vfsmount *mnt = ipc_ns->mq_mnt;
 
+	if (!mnt)
+		return -ENOENT;
+
 	name = getname(u_name);
 	if (IS_ERR(name))
 		return PTR_ERR(name);
@@ -1581,7 +1600,8 @@ static struct file_system_type mqueue_fs_type = {
 	.fs_flags = FS_USERNS_MOUNT,
 };
 
-int mq_init_ns(struct ipc_namespace *ns)
+
+int mq_init_ns(struct ipc_namespace *ns, bool mount)
 {
 	ns->mq_queues_count  = 0;
 	ns->mq_queues_max    = DFLT_QUEUESMAX;
@@ -1590,23 +1610,31 @@ int mq_init_ns(struct ipc_namespace *ns)
 	ns->mq_msg_default   = DFLT_MSG;
 	ns->mq_msgsize_default  = DFLT_MSGSIZE;
 
-	ns->mq_mnt = kern_mount_data(&mqueue_fs_type, ns);
-	if (IS_ERR(ns->mq_mnt)) {
-		int err = PTR_ERR(ns->mq_mnt);
+	if (!mount)
 		ns->mq_mnt = NULL;
-		return err;
+	else {
+		int err;
+
+		ns->mq_mnt = kern_mount_data(&mqueue_fs_type, ns);
+		if (IS_ERR(ns->mq_mnt)) {
+			err = PTR_ERR(ns->mq_mnt);
+			ns->mq_mnt = NULL;
+			return err;
+		}
 	}
 	return 0;
 }
 
 void mq_clear_sbinfo(struct ipc_namespace *ns)
 {
-	ns->mq_mnt->mnt_sb->s_fs_info = NULL;
+	if (ns->mq_mnt)
+		ns->mq_mnt->mnt_sb->s_fs_info = NULL;
 }
 
 void mq_put_mnt(struct ipc_namespace *ns)
 {
-	kern_unmount(ns->mq_mnt);
+	if (ns->mq_mnt)
+		kern_unmount(ns->mq_mnt);
 }
 
 static int __init init_mqueue_fs(void)
@@ -1628,7 +1656,7 @@ static int __init init_mqueue_fs(void)
 
 	spin_lock_init(&mq_lock);
 
-	error = mq_init_ns(&init_ipc_ns);
+	error = mq_init_ns(&init_ipc_ns, true);
 	if (error)
 		goto out_filesystem;
 
diff --git a/ipc/namespace.c b/ipc/namespace.c
index f59a89966f92..9d3689577f66 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -65,7 +65,7 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
 	if (err)
 		goto fail_destroy_msg;
 
-	err = mq_init_ns(ns);
+	err = mq_init_ns(ns, false);
 	if (err)
 		goto fail_destroy_shm;
 
-- 
2.14.3

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

* Re: [PATCH v2] ipc, mqueue: lazy call kern_mount_data in new namespaces
  2017-11-30 18:38 [PATCH v2] ipc, mqueue: lazy call kern_mount_data in new namespaces Giuseppe Scrivano
@ 2017-12-03 18:42 ` kbuild test robot
  0 siblings, 0 replies; 2+ messages in thread
From: kbuild test robot @ 2017-12-03 18:42 UTC (permalink / raw)
  To: Giuseppe Scrivano; +Cc: kbuild-all, linux-kernel, gscrivan, Andrew Morton

[-- Attachment #1: Type: text/plain, Size: 7435 bytes --]

Hi Giuseppe,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v4.15-rc2 next-20171201]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Giuseppe-Scrivano/ipc-mqueue-lazy-call-kern_mount_data-in-new-namespaces/20171203-201041
config: i386-randconfig-c0-12032036 (attached as .config)
compiler: gcc-7 (Debian 7.2.0-12) 7.2.1 20171025
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

   ipc/namespace.c: In function 'create_ipc_ns':
>> ipc/namespace.c:68:8: error: too many arguments to function 'mq_init_ns'
     err = mq_init_ns(ns, false);
           ^~~~~~~~~~
   In file included from ipc/namespace.c:9:0:
   include/linux/ipc_namespace.h:119:19: note: declared here
    static inline int mq_init_ns(struct ipc_namespace *ns) { return 0; }
                      ^~~~~~~~~~
   In file included from include/linux/kernel.h:10:0,
                    from include/linux/list.h:9,
                    from include/linux/preempt.h:11,
                    from include/linux/spinlock.h:51,
                    from include/linux/ipc.h:5,
                    from ipc/namespace.c:7:
   ipc/namespace.c: At top level:
   include/linux/compiler.h:64:4: warning: '______f' is static but declared in inline function 'strcpy' which is not static
       ______f = {     \
       ^
   include/linux/compiler.h:56:23: note: in expansion of macro '__trace_if'
    #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
                          ^~~~~~~~~~
   include/linux/string.h:422:2: note: in expansion of macro 'if'
     if (p_size == (size_t)-1 && q_size == (size_t)-1)
     ^~
   include/linux/compiler.h:64:4: warning: '______f' is static but declared in inline function 'kmemdup' which is not static
       ______f = {     \
       ^
   include/linux/compiler.h:56:23: note: in expansion of macro '__trace_if'
    #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
                          ^~~~~~~~~~
   include/linux/string.h:412:2: note: in expansion of macro 'if'
     if (p_size < size)
     ^~
   include/linux/compiler.h:64:4: warning: '______f' is static but declared in inline function 'kmemdup' which is not static
       ______f = {     \
       ^
   include/linux/compiler.h:56:23: note: in expansion of macro '__trace_if'
    #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
                          ^~~~~~~~~~
   include/linux/string.h:410:2: note: in expansion of macro 'if'
     if (__builtin_constant_p(size) && p_size < size)
     ^~
   include/linux/compiler.h:64:4: warning: '______f' is static but declared in inline function 'memchr_inv' which is not static
       ______f = {     \
       ^
   include/linux/compiler.h:56:23: note: in expansion of macro '__trace_if'
    #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
                          ^~~~~~~~~~
   include/linux/string.h:401:2: note: in expansion of macro 'if'
     if (p_size < size)
     ^~
   include/linux/compiler.h:64:4: warning: '______f' is static but declared in inline function 'memchr_inv' which is not static
       ______f = {     \
       ^
   include/linux/compiler.h:56:23: note: in expansion of macro '__trace_if'
    #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
                          ^~~~~~~~~~
   include/linux/string.h:399:2: note: in expansion of macro 'if'
     if (__builtin_constant_p(size) && p_size < size)
     ^~
   include/linux/compiler.h:64:4: warning: '______f' is static but declared in inline function 'memchr' which is not static
       ______f = {     \
       ^
   include/linux/compiler.h:56:23: note: in expansion of macro '__trace_if'
    #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
                          ^~~~~~~~~~
   include/linux/string.h:390:2: note: in expansion of macro 'if'
     if (p_size < size)
     ^~
   include/linux/compiler.h:64:4: warning: '______f' is static but declared in inline function 'memchr' which is not static
       ______f = {     \
       ^
   include/linux/compiler.h:56:23: note: in expansion of macro '__trace_if'
    #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
                          ^~~~~~~~~~
   include/linux/string.h:388:2: note: in expansion of macro 'if'
     if (__builtin_constant_p(size) && p_size < size)
     ^~
   include/linux/compiler.h:64:4: warning: '______f' is static but declared in inline function 'memcmp' which is not static
       ______f = {     \
       ^
   include/linux/compiler.h:56:23: note: in expansion of macro '__trace_if'
    #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
                          ^~~~~~~~~~
   include/linux/string.h:380:2: note: in expansion of macro 'if'
     if (p_size < size || q_size < size)
     ^~
   include/linux/compiler.h:64:4: warning: '______f' is static but declared in inline function 'memcmp' which is not static
       ______f = {     \
       ^
   include/linux/compiler.h:56:23: note: in expansion of macro '__trace_if'
    #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
                          ^~~~~~~~~~
   include/linux/string.h:377:3: note: in expansion of macro 'if'
      if (q_size < size)
      ^~
   include/linux/compiler.h:64:4: warning: '______f' is static but declared in inline function 'memcmp' which is not static
       ______f = {     \
       ^
   include/linux/compiler.h:56:23: note: in expansion of macro '__trace_if'
    #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
                          ^~~~~~~~~~

vim +/mq_init_ns +68 ipc/namespace.c

    31	
    32	static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
    33						   struct ipc_namespace *old_ns)
    34	{
    35		struct ipc_namespace *ns;
    36		struct ucounts *ucounts;
    37		int err;
    38	
    39		err = -ENOSPC;
    40		ucounts = inc_ipc_namespaces(user_ns);
    41		if (!ucounts)
    42			goto fail;
    43	
    44		err = -ENOMEM;
    45		ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL);
    46		if (ns == NULL)
    47			goto fail_dec;
    48	
    49		err = ns_alloc_inum(&ns->ns);
    50		if (err)
    51			goto fail_free;
    52		ns->ns.ops = &ipcns_operations;
    53	
    54		refcount_set(&ns->count, 1);
    55		ns->user_ns = get_user_ns(user_ns);
    56		ns->ucounts = ucounts;
    57	
    58		err = sem_init_ns(ns);
    59		if (err)
    60			goto fail_put;
    61		err = msg_init_ns(ns);
    62		if (err)
    63			goto fail_destroy_sem;
    64		err = shm_init_ns(ns);
    65		if (err)
    66			goto fail_destroy_msg;
    67	
  > 68		err = mq_init_ns(ns, false);
    69		if (err)
    70			goto fail_destroy_shm;
    71	
    72		return ns;
    73	
    74	fail_destroy_shm:
    75		shm_exit_ns(ns);
    76	fail_destroy_msg:
    77		msg_exit_ns(ns);
    78	fail_destroy_sem:
    79		sem_exit_ns(ns);
    80	fail_put:
    81		put_user_ns(ns->user_ns);
    82		ns_free_inum(&ns->ns);
    83	fail_free:
    84		kfree(ns);
    85	fail_dec:
    86		dec_ipc_namespaces(ucounts);
    87	fail:
    88		return ERR_PTR(err);
    89	}
    90	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 26576 bytes --]

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

end of thread, other threads:[~2017-12-03 18:43 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-30 18:38 [PATCH v2] ipc, mqueue: lazy call kern_mount_data in new namespaces Giuseppe Scrivano
2017-12-03 18:42 ` kbuild test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.