@@ -569,6 +569,23 @@ static int afs_get_tree(struct fs_context *fc)
return ret;
}
+static void afs_set_container(struct fs_context *fc)
+{
+ struct afs_fs_context *ctx = fc->fs_private;
+ struct afs_cell *cell;
+
+ afs_put_cell(ctx->net, ctx->cell);
+ do_set_container(fc);
+
+ /* Default to the workstation cell. */
+ rcu_read_lock();
+ cell = afs_lookup_cell_rcu(ctx->net, NULL, 0);
+ rcu_read_unlock();
+ if (IS_ERR(cell))
+ cell = NULL;
+ ctx->cell = cell;
+}
+
static void afs_free_fc(struct fs_context *fc)
{
struct afs_fs_context *ctx = fc->fs_private;
@@ -583,6 +600,7 @@ static void afs_free_fc(struct fs_context *fc)
static const struct fs_context_operations afs_context_ops = {
.free = afs_free_fc,
.parse_param = afs_parse_param,
+ .set_container = afs_set_container,
.get_tree = afs_get_tree,
};
@@ -170,18 +170,38 @@ int vfs_parse_fs_param(struct fs_context *fc, struct fs_parameter *param)
}
EXPORT_SYMBOL(vfs_parse_fs_param);
+/**
+ * do_set_container - Helper to set container
+ * @fc: The fs_context to adjust
+ *
+ * This is called to effect the change of namespaces associated with the
+ * container. The reason that this isn't rolled into vfs_set_container() is
+ * that the filesystem may need to do some cleanup on the old namespaces (which
+ * are currently pinned by the container) before calling this.
+ *
+ * The user namespace is not changed as that is used for security checks.
+ */
+void do_set_container(struct fs_context *fc)
+{
+ put_net(fc->net_ns);
+ fc->net_ns = get_net(fc->container->ns->net_ns);
+}
+EXPORT_SYMBOL(do_set_container);
+
/*
- * Specify a container in which a superblock will exist.
+ * Specify a container in which a superblock will exist. This should be called
+ * before calling vfs_parse_fs_param. If ->set_container() is supplied by the
+ * filesystem, it should call do_set_container().
*/
void vfs_set_container(struct fs_context *fc, struct container *container)
{
if (container) {
- put_user_ns(fc->user_ns);
- put_net(fc->net_ns);
-
+ put_container(fc->container);
fc->container = get_container(container);
- fc->user_ns = get_user_ns(container->cred->user_ns);
- fc->net_ns = get_net(container->ns->net_ns);
+ if (fc->ops->set_container)
+ fc->ops->set_container(fc);
+ else
+ do_set_container(fc);
}
}
@@ -164,6 +164,14 @@ static int proc_get_tree(struct fs_context *fc)
return vfs_get_super(fc, vfs_get_keyed_super, proc_fill_super);
}
+static void proc_set_container(struct fs_context *fc)
+{
+ struct proc_fs_context *ctx = fc->fs_private;
+
+ put_pid_ns(ctx->pid_ns);
+ ctx->pid_ns = get_pid_ns(fc->container->pid_ns);
+}
+
static void proc_fs_context_free(struct fs_context *fc)
{
struct proc_fs_context *ctx = fc->fs_private;
@@ -176,6 +184,7 @@ static void proc_fs_context_free(struct fs_context *fc)
static const struct fs_context_operations proc_fs_context_ops = {
.free = proc_fs_context_free,
.parse_param = proc_parse_param,
+ .set_container = proc_set_container,
.get_tree = proc_get_tree,
.reconfigure = proc_reconfigure,
};
@@ -118,6 +118,7 @@ struct fs_context_operations {
int (*dup)(struct fs_context *fc, struct fs_context *src_fc);
int (*parse_param)(struct fs_context *fc, struct fs_parameter *param);
int (*parse_monolithic)(struct fs_context *fc, void *data);
+ void (*set_container)(struct fs_context *fc);
int (*get_tree)(struct fs_context *fc);
int (*reconfigure)(struct fs_context *fc);
};
@@ -138,6 +139,7 @@ extern int vfs_parse_fs_param(struct fs_context *fc, struct fs_parameter *param)
extern int vfs_parse_fs_string(struct fs_context *fc, const char *key,
const char *value, size_t v_size);
extern int generic_parse_monolithic(struct fs_context *fc, void *data);
+extern void do_set_container(struct fs_context *fc);
extern void vfs_set_container(struct fs_context *fc, struct container *container);
extern int vfs_get_tree(struct fs_context *fc);
extern void put_fs_context(struct fs_context *fc);
@@ -33,6 +33,7 @@
#include <linux/mutex.h>
#include <linux/nsproxy.h>
#include <linux/pid.h>
+#include <linux/container.h>
#include <linux/ipc_namespace.h>
#include <linux/user_namespace.h>
#include <linux/slab.h>
@@ -329,6 +330,14 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
return ERR_PTR(ret);
}
+static void mqueue_set_container(struct fs_context *fc)
+{
+ struct mqueue_fs_context *ctx = fc->fs_private;
+
+ put_ipc_ns(ctx->ipc_ns);
+ ctx->ipc_ns = get_ipc_ns(fc->container->ns->ipc_ns);
+}
+
static int mqueue_fill_super(struct super_block *sb, struct fs_context *fc)
{
struct inode *inode;
@@ -1569,6 +1578,7 @@ static const struct super_operations mqueue_super_ops = {
static const struct fs_context_operations mqueue_fs_context_ops = {
.free = mqueue_fs_context_free,
+ .set_container = mqueue_set_container,
.get_tree = mqueue_get_tree,
};
Provide an fs_context op to notify a filesystem that a container has been set. The filesystem should do whatever cleanup it needs, then call do_set_container() and then re-set its container/namespace dependent stuff. This allows the following: (1) proc and mqueue mounts to set the correct pid and ipc namespaces respectively. (2) afs to discard the old default cell before the net namespace is changed (ie. while it is still pinned), after which it can get the new default cell. Signed-off-by: David Howells <dhowells@redhat.com> --- fs/afs/super.c | 18 ++++++++++++++++++ fs/fs_context.c | 32 ++++++++++++++++++++++++++------ fs/proc/root.c | 9 +++++++++ include/linux/fs_context.h | 2 ++ ipc/mqueue.c | 10 ++++++++++ 5 files changed, 65 insertions(+), 6 deletions(-)