From bc755553df9ab33f389c1a0a8bd0b4f4646e80ef Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:41 -0500 Subject: sysfs, kernfs: make inode number ida per kernfs_root 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 Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/dir.c | 47 +++++++++++++---------------------------------- 1 file changed, 13 insertions(+), 34 deletions(-) (limited to 'fs/kernfs/dir.c') diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 246740a741ef..eaffa83719d5 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 @@ -205,32 +202,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 @@ -276,7 +247,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; @@ -285,6 +256,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); } } @@ -360,10 +332,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); @@ -375,8 +349,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); @@ -628,8 +604,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); } @@ -674,7 +653,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); -- cgit v1.2.3