[PATCH 34/39] sysfs, kernfs: make inode number ida per kernfs_root

From: Tejun Heo
Date: Sun Nov 03 2013 - 04:55:42 EST


kernfs is being updated to allow multiple sysfs_dirent hierarchies so
that it can also be used by other users. Currently, inode number is
allocated using a global ida, sysfs_ino_ida; however, inos for
different hierarchies should be handled separately.

This patch makes ino allocation per kernfs_root. sysfs_ino_ida is
replaced by kernfs_root->ino_ida and sysfs_new_dirent() is updated to
take @root and allocate ino from it. ida_simple_get/remove() are used
instead of sysfs_ino_lock and sysfs_alloc/free_ino().

Signed-off-by: Tejun Heo <tj@xxxxxxxxxx>
---
fs/kernfs/dir.c | 47 +++++++++++++--------------------------------
fs/kernfs/file.c | 4 ++--
fs/kernfs/kernfs-internal.h | 3 ++-
fs/kernfs/symlink.c | 3 ++-
include/linux/kernfs.h | 4 ++++
5 files changed, 23 insertions(+), 38 deletions(-)

diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 74eb4c4..6db5ed3 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -21,9 +21,6 @@ DEFINE_MUTEX(sysfs_mutex);

#define to_sysfs_dirent(X) rb_entry((X), struct sysfs_dirent, s_rb)

-static DEFINE_SPINLOCK(sysfs_ino_lock);
-static DEFINE_IDA(sysfs_ino_ida);
-
/**
* sysfs_name_hash
* @name: Null terminated string to hash
@@ -217,32 +214,6 @@ static void sysfs_deactivate(struct sysfs_dirent *sd)
rwsem_release(&sd->dep_map, 1, _RET_IP_);
}

-static int sysfs_alloc_ino(unsigned int *pino)
-{
- int ino, rc;
-
- retry:
- spin_lock(&sysfs_ino_lock);
- rc = ida_get_new_above(&sysfs_ino_ida, 1, &ino);
- spin_unlock(&sysfs_ino_lock);
-
- if (rc == -EAGAIN) {
- if (ida_pre_get(&sysfs_ino_ida, GFP_KERNEL))
- goto retry;
- rc = -ENOMEM;
- }
-
- *pino = ino;
- return rc;
-}
-
-static void sysfs_free_ino(unsigned int ino)
-{
- spin_lock(&sysfs_ino_lock);
- ida_remove(&sysfs_ino_ida, ino);
- spin_unlock(&sysfs_ino_lock);
-}
-
/**
* kernfs_get - get a reference count on a sysfs_dirent
* @sd: the target sysfs_dirent
@@ -288,7 +259,7 @@ void kernfs_put(struct sysfs_dirent *sd)
security_release_secctx(sd->s_iattr->ia_secdata,
sd->s_iattr->ia_secdata_len);
kfree(sd->s_iattr);
- sysfs_free_ino(sd->s_ino);
+ ida_simple_remove(&root->ino_ida, sd->s_ino);
kmem_cache_free(sysfs_dir_cachep, sd);

sd = parent_sd;
@@ -297,6 +268,7 @@ void kernfs_put(struct sysfs_dirent *sd)
goto repeat;
} else {
/* just released the root sd, free @root too */
+ ida_destroy(&root->ino_ida);
kfree(root);
}
}
@@ -371,10 +343,12 @@ const struct dentry_operations sysfs_dentry_ops = {
.d_release = sysfs_dentry_release,
};

-struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
+struct sysfs_dirent *sysfs_new_dirent(struct kernfs_root *root,
+ const char *name, umode_t mode, int type)
{
char *dup_name = NULL;
struct sysfs_dirent *sd;
+ int ret;

if (type & SYSFS_COPY_NAME) {
name = dup_name = kstrdup(name, GFP_KERNEL);
@@ -386,8 +360,10 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
if (!sd)
goto err_out1;

- if (sysfs_alloc_ino(&sd->s_ino))
+ ret = ida_simple_get(&root->ino_ida, 1, 0, GFP_KERNEL);
+ if (ret < 0)
goto err_out2;
+ sd->s_ino = ret;

atomic_set(&sd->s_count, 1);
atomic_set(&sd->s_active, 0);
@@ -623,8 +599,11 @@ struct kernfs_root *kernfs_create_root(void *priv)
if (!root)
return ERR_PTR(-ENOMEM);

- sd = sysfs_new_dirent("", S_IFDIR | S_IRUGO | S_IXUGO, SYSFS_DIR);
+ ida_init(&root->ino_ida);
+
+ sd = sysfs_new_dirent(root, "", S_IFDIR | S_IRUGO | S_IXUGO, SYSFS_DIR);
if (!sd) {
+ ida_destroy(&root->ino_ida);
kfree(root);
return ERR_PTR(-ENOMEM);
}
@@ -667,7 +646,7 @@ struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent,
int rc;

/* allocate */
- sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
+ sd = sysfs_new_dirent(kernfs_root(parent), name, mode, SYSFS_DIR);
if (!sd)
return ERR_PTR(-ENOMEM);

diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
index 3bf78a5..0b7e585 100644
--- a/fs/kernfs/file.c
+++ b/fs/kernfs/file.c
@@ -758,8 +758,8 @@ struct sysfs_dirent *kernfs_create_file_ns_key(struct sysfs_dirent *parent,
struct sysfs_dirent *sd;
int rc;

- sd = sysfs_new_dirent(name, (mode & S_IALLUGO) | S_IFREG,
- SYSFS_KOBJ_ATTR);
+ sd = sysfs_new_dirent(kernfs_root(parent), name,
+ (mode & S_IALLUGO) | S_IFREG, SYSFS_KOBJ_ATTR);
if (!sd)
return ERR_PTR(-ENOMEM);

diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h
index 3c830aa..584f169 100644
--- a/fs/kernfs/kernfs-internal.h
+++ b/fs/kernfs/kernfs-internal.h
@@ -160,7 +160,8 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt);
int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd,
struct sysfs_dirent *parent_sd);
void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt);
-struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type);
+struct sysfs_dirent *sysfs_new_dirent(struct kernfs_root *root,
+ const char *name, umode_t mode, int type);

/*
* file.c
diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c
index 00e4fdb..b65cd22 100644
--- a/fs/kernfs/symlink.c
+++ b/fs/kernfs/symlink.c
@@ -30,7 +30,8 @@ struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent,
struct sysfs_addrm_cxt acxt;
int error;

- sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK);
+ sd = sysfs_new_dirent(kernfs_root(parent), name, S_IFLNK|S_IRWXUGO,
+ SYSFS_KOBJ_LINK);
if (!sd)
return ERR_PTR(-ENOMEM);

diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index 8feaf48..b9ee397 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -11,6 +11,7 @@
#include <linux/err.h>
#include <linux/list.h>
#include <linux/mutex.h>
+#include <linux/idr.h>
#include <linux/lockdep.h>

struct file;
@@ -23,6 +24,9 @@ struct sysfs_dirent;
struct kernfs_root {
/* published fields */
struct sysfs_dirent *sd;
+
+ /* private fields, do not use outside kernfs proper */
+ struct ida ino_ida;
};

struct sysfs_open_file {
--
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/