@@ -576,7 +576,7 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags)
/* The kernfs node has been moved to a different namespace */
if (kn->parent && kernfs_ns_enabled(kn->parent) &&
- kernfs_info(dentry->d_sb)->ns != kn->ns)
+ kernfs_info(dentry->d_sb)->ns[kn->ns_type] != kn->ns)
goto out_bad;
mutex_unlock(&kernfs_mutex);
@@ -1087,7 +1087,7 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir,
mutex_lock(&kernfs_mutex);
if (kernfs_ns_enabled(parent))
- ns = kernfs_info(dir->i_sb)->ns;
+ ns = kernfs_info(dir->i_sb)->ns[parent->ns_type];
kn = kernfs_find_ns(parent, dentry->d_name.name, ns);
@@ -1673,7 +1673,7 @@ static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx)
mutex_lock(&kernfs_mutex);
if (kernfs_ns_enabled(parent))
- ns = kernfs_info(dentry->d_sb)->ns;
+ ns = kernfs_info(dentry->d_sb)->ns[parent->ns_type];
for (pos = kernfs_dir_pos(ns, parent, ctx->pos, pos);
pos;
@@ -16,6 +16,7 @@
#include <linux/xattr.h>
#include <linux/kernfs.h>
+#include <linux/kobject_ns.h>
#include <linux/fs_context.h>
struct kernfs_iattrs {
@@ -62,12 +63,10 @@ struct kernfs_super_info {
struct kernfs_root *root;
/*
- * Each sb is associated with one namespace tag, currently the
- * network namespace of the task which mounted this kernfs
- * instance. If multiple tags become necessary, make the following
- * an array and compare kernfs_node tag against every entry.
+ * Each sb can be associated with namespace tags. They will be used
+ * to compare kernfs_node tags against relevant entries.
*/
- const void *ns;
+ const void *ns[KOBJ_NS_TYPES];
/* anchored at kernfs_root->supers, protected by kernfs_mutex */
struct list_head node;
@@ -279,14 +279,15 @@ static int kernfs_test_super(struct super_block *sb, struct fs_context *fc)
struct kernfs_super_info *sb_info = kernfs_info(sb);
struct kernfs_super_info *info = fc->s_fs_info;
- return sb_info->root == info->root && sb_info->ns == info->ns;
+ return sb_info->root == info->root &&
+ memcmp(sb_info->ns, info->ns, sizeof(sb_info->ns)) == 0;
}
static int kernfs_set_super(struct super_block *sb, struct fs_context *fc)
{
struct kernfs_fs_context *kfc = fc->fs_private;
- kfc->ns_tag = NULL;
+ memset(kfc->ns_tag, 0, sizeof(kfc->ns_tag));
return set_anon_super_fc(sb, fc);
}
@@ -296,7 +297,7 @@ static int kernfs_set_super(struct super_block *sb, struct fs_context *fc)
*
* Return the namespace tag associated with kernfs super_block @sb.
*/
-const void *kernfs_super_ns(struct super_block *sb)
+const void **kernfs_super_ns(struct super_block *sb)
{
struct kernfs_super_info *info = kernfs_info(sb);
@@ -324,7 +325,9 @@ int kernfs_get_tree(struct fs_context *fc)
return -ENOMEM;
info->root = kfc->root;
- info->ns = kfc->ns_tag;
+ BUILD_BUG_ON(sizeof(info->ns) != sizeof(kfc->ns_tag));
+ memcpy(info->ns, kfc->ns_tag, sizeof(info->ns));
+
INIT_LIST_HEAD(&info->node);
fc->s_fs_info = info;
@@ -41,8 +41,8 @@ static void sysfs_fs_context_free(struct fs_context *fc)
{
struct kernfs_fs_context *kfc = fc->fs_private;
- if (kfc->ns_tag)
- kobj_ns_drop(KOBJ_NS_TYPE_NET, kfc->ns_tag);
+ if (kfc->ns_tag[KOBJ_NS_TYPE_NET])
+ kobj_ns_drop(KOBJ_NS_TYPE_NET, kfc->ns_tag[KOBJ_NS_TYPE_NET]);
kernfs_free_fs_context(fc);
kfree(kfc);
}
@@ -66,7 +66,7 @@ static int sysfs_init_fs_context(struct fs_context *fc)
if (!kfc)
return -ENOMEM;
- kfc->ns_tag = netns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET);
+ kfc->ns_tag[KOBJ_NS_TYPE_NET] = netns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET);
kfc->root = sysfs_root;
kfc->magic = SYSFS_MAGIC;
fc->fs_private = kfc;
@@ -81,10 +81,10 @@ static int sysfs_init_fs_context(struct fs_context *fc)
static void sysfs_kill_sb(struct super_block *sb)
{
- void *ns = (void *)kernfs_super_ns(sb);
+ void **ns = (void **)kernfs_super_ns(sb);
+ kobj_ns_drop(KOBJ_NS_TYPE_NET, ns[KOBJ_NS_TYPE_NET]);
kernfs_kill_sb(sb);
- kobj_ns_drop(KOBJ_NS_TYPE_NET, ns);
}
static struct file_system_type sysfs_fs_type = {
@@ -16,6 +16,7 @@
#include <linux/atomic.h>
#include <linux/uidgid.h>
#include <linux/wait.h>
+#include <linux/kobject_ns.h>
struct file;
struct dentry;
@@ -137,8 +138,9 @@ struct kernfs_node {
struct rb_node rb;
- const void *ns; /* namespace tag */
- unsigned int hash; /* ns + name hash */
+ const void *ns; /* namespace tag */
+ enum kobj_ns_type ns_type; /* type of namespace tag */
+ unsigned int hash; /* ns + name hash */
union {
struct kernfs_elem_dir dir;
struct kernfs_elem_symlink symlink;
@@ -275,7 +277,7 @@ struct kernfs_ops {
*/
struct kernfs_fs_context {
struct kernfs_root *root; /* Root of the hierarchy being mounted */
- void *ns_tag; /* Namespace tag of the mount (or NULL) */
+ void *ns_tag[KOBJ_NS_TYPES]; /* Namespace tags of the mount (or empty) */
unsigned long magic; /* File system specific magic number */
/* The following are set/used by kernfs_mount() */
@@ -319,17 +321,20 @@ static inline ino_t kernfs_gen(struct kernfs_node *kn)
/**
* kernfs_enable_ns - enable namespace under a directory
- * @kn: directory of interest, should be empty
+ * @kn: directory of interest, should be empty
+ * @ns_type: type of namespace that should be enabled for this directory
*
* This is to be called right after @kn is created to enable namespace
* under it. All children of @kn must have non-NULL namespace tags and
* only the ones which match the super_block's tag will be visible.
*/
-static inline void kernfs_enable_ns(struct kernfs_node *kn)
+static inline void kernfs_enable_ns(struct kernfs_node *kn,
+ enum kobj_ns_type ns_type)
{
WARN_ON_ONCE(kernfs_type(kn) != KERNFS_DIR);
WARN_ON_ONCE(!RB_EMPTY_ROOT(&kn->dir.children));
kn->flags |= KERNFS_NS;
+ kn->ns_type = ns_type;
}
/**
@@ -401,7 +406,7 @@ int kernfs_xattr_get(struct kernfs_node *kn, const char *name,
int kernfs_xattr_set(struct kernfs_node *kn, const char *name,
const void *value, size_t size, int flags);
-const void *kernfs_super_ns(struct super_block *sb);
+const void **kernfs_super_ns(struct super_block *sb);
int kernfs_get_tree(struct fs_context *fc);
void kernfs_free_fs_context(struct fs_context *fc);
void kernfs_kill_sb(struct super_block *sb);
@@ -415,7 +420,8 @@ struct kernfs_node *kernfs_find_and_get_node_by_id(struct kernfs_root *root,
static inline enum kernfs_node_type kernfs_type(struct kernfs_node *kn)
{ return 0; } /* whatever */
-static inline void kernfs_enable_ns(struct kernfs_node *kn) { }
+static inline void kernfs_enable_ns(struct kernfs_node *kn,
+ enum kobj_ns_type ns_type) { }
static inline bool kernfs_ns_enabled(struct kernfs_node *kn)
{ return false; }
@@ -511,7 +517,7 @@ static inline int kernfs_xattr_set(struct kernfs_node *kn, const char *name,
const void *value, size_t size, int flags)
{ return -ENOSYS; }
-static inline const void *kernfs_super_ns(struct super_block *sb)
+static inline const void **kernfs_super_ns(struct super_block *sb)
{ return NULL; }
static inline int kernfs_get_tree(struct fs_context *fc)
@@ -306,9 +306,10 @@ void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr);
int __must_check sysfs_init(void);
-static inline void sysfs_enable_ns(struct kernfs_node *kn)
+static inline void sysfs_enable_ns(struct kernfs_node *kn,
+ enum kobj_ns_type ns_type)
{
- return kernfs_enable_ns(kn);
+ return kernfs_enable_ns(kn, ns_type);
}
int sysfs_file_change_owner(struct kobject *kobj, const char *name, kuid_t kuid,
@@ -531,7 +532,8 @@ static inline int __must_check sysfs_init(void)
return 0;
}
-static inline void sysfs_enable_ns(struct kernfs_node *kn)
+static inline void sysfs_enable_ns(struct kernfs_node *kn,
+ enum kobj_ns_type ns_type)
{
}
@@ -120,7 +120,7 @@ static int create_dir(struct kobject *kobj)
BUG_ON(ops->type >= KOBJ_NS_TYPES);
BUG_ON(!kobj_ns_type_registered(ops->type));
- sysfs_enable_ns(kobj->sd);
+ sysfs_enable_ns(kobj->sd, ops->type);
}
return 0;