Commit e1b836f6 authored by David Howells's avatar David Howells Committed by Al Viro

ipc: Convert mqueue fs to fs_context

Convert the mqueue filesystem to use the filesystem context stuff.


 (1) The relevant ipc namespace is selected in when the context is
     initialised (and it defaults to the current task's ipc namespace).
     The caller can override this before calling vfs_get_tree().

 (2) Rather than simply calling kern_mount_data(), mq_init_ns() and
     mq_internal_mount() create a context, adjust it and then do the rest
     of the mount procedure.

 (3) The lazy mqueue mounting on creation of a new namespace is retained
     from a previous patch, but the avoidance of sget() if no superblock
     yet exists is reverted and the superblock is again keyed on the
     namespace pointer.

     Yes, there was a performance gain in not searching the superblock
     hash, but it's only paid once per ipc namespace - and only if someone
     uses mqueue within that namespace, so I'm not sure it's worth it,
     especially as calling sget() allows avoidance of recursion.
Signed-off-by: default avatarDavid Howells <>
Signed-off-by: default avatarAl Viro <>
parent 3eaa1435
......@@ -18,6 +18,7 @@
#include <linux/pagemap.h>
#include <linux/file.h>
#include <linux/mount.h>
#include <linux/fs_context.h>
#include <linux/namei.h>
#include <linux/sysctl.h>
#include <linux/poll.h>
......@@ -42,6 +43,10 @@
#include <net/sock.h>
#include "util.h"
struct mqueue_fs_context {
struct ipc_namespace *ipc_ns;
#define MQUEUE_MAGIC 0x19800202
#define DIRENT_SIZE 20
#define FILENT_SIZE 80
......@@ -87,9 +92,11 @@ 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;
static const struct fs_context_operations mqueue_fs_context_ops;
static void remove_notification(struct mqueue_inode_info *info);
static struct kmem_cache *mqueue_inode_cachep;
......@@ -322,7 +329,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
return ERR_PTR(ret);
static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
static int mqueue_fill_super(struct super_block *sb, struct fs_context *fc)
struct inode *inode;
struct ipc_namespace *ns = sb->s_fs_info;
......@@ -343,18 +350,56 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
return 0;
static struct dentry *mqueue_mount(struct file_system_type *fs_type,
int flags, const char *dev_name,
void *data)
static int mqueue_get_tree(struct fs_context *fc)
struct ipc_namespace *ns;
if (flags & SB_KERNMOUNT) {
ns = data;
data = NULL;
} else {
ns = current->nsproxy->ipc_ns;
return mount_ns(fs_type, flags, data, ns, ns->user_ns, mqueue_fill_super);
struct mqueue_fs_context *ctx = fc->fs_private;
fc->user_ns = get_user_ns(ctx->ipc_ns->user_ns);
fc->s_fs_info = ctx->ipc_ns;
return vfs_get_super(fc, vfs_get_keyed_super, mqueue_fill_super);
static void mqueue_fs_context_free(struct fs_context *fc)
struct mqueue_fs_context *ctx = fc->fs_private;
if (ctx->ipc_ns)
static int mqueue_init_fs_context(struct fs_context *fc)
struct mqueue_fs_context *ctx;
ctx = kzalloc(sizeof(struct mqueue_fs_context), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->ipc_ns = get_ipc_ns(current->nsproxy->ipc_ns);
fc->fs_private = ctx;
fc->ops = &mqueue_fs_context_ops;
return 0;
static struct vfsmount *mq_create_mount(struct ipc_namespace *ns)
struct mqueue_fs_context *ctx;
struct fs_context *fc;
struct vfsmount *mnt;
fc = fs_context_for_mount(&mqueue_fs_type, SB_KERNMOUNT);
if (IS_ERR(fc))
return ERR_CAST(fc);
ctx = fc->fs_private;
ctx->ipc_ns = get_ipc_ns(ns);
mnt = fc_mount(fc);
return mnt;
static void init_once(void *foo)
......@@ -1522,15 +1567,22 @@ static const struct super_operations mqueue_super_ops = {
.statfs = simple_statfs,
static const struct fs_context_operations mqueue_fs_context_ops = {
.free = mqueue_fs_context_free,
.get_tree = mqueue_get_tree,
static struct file_system_type mqueue_fs_type = {
.name = "mqueue",
.mount = mqueue_mount,
.kill_sb = kill_litter_super,
.fs_flags = FS_USERNS_MOUNT,
.name = "mqueue",
.init_fs_context = mqueue_init_fs_context,
.kill_sb = kill_litter_super,
.fs_flags = FS_USERNS_MOUNT,
int mq_init_ns(struct ipc_namespace *ns)
struct vfsmount *m;
ns->mq_queues_count = 0;
ns->mq_queues_max = DFLT_QUEUESMAX;
ns->mq_msg_max = DFLT_MSGMAX;
......@@ -1538,12 +1590,10 @@ 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);
ns->mq_mnt = NULL;
return err;
m = mq_create_mount(ns);
if (IS_ERR(m))
return PTR_ERR(m);
ns->mq_mnt = m;
return 0;
......@@ -42,7 +42,7 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
goto fail;
err = -ENOMEM;
ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL);
ns = kzalloc(sizeof(struct ipc_namespace), GFP_KERNEL);
if (ns == NULL)
goto fail_dec;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment