diff options
Diffstat (limited to 'fs/sysfs')
-rw-r--r-- | fs/sysfs/dir.c | 45 |
1 files changed, 36 insertions, 9 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 2544aae6f583..f09626cc568a 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -9,12 +9,42 @@ | |||
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/kobject.h> | 10 | #include <linux/kobject.h> |
11 | #include <linux/namei.h> | 11 | #include <linux/namei.h> |
12 | #include <linux/idr.h> | ||
12 | #include <asm/semaphore.h> | 13 | #include <asm/semaphore.h> |
13 | #include "sysfs.h" | 14 | #include "sysfs.h" |
14 | 15 | ||
15 | DECLARE_RWSEM(sysfs_rename_sem); | 16 | DECLARE_RWSEM(sysfs_rename_sem); |
16 | spinlock_t sysfs_lock = SPIN_LOCK_UNLOCKED; | 17 | spinlock_t sysfs_lock = SPIN_LOCK_UNLOCKED; |
17 | 18 | ||
19 | static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED; | ||
20 | static DEFINE_IDA(sysfs_ino_ida); | ||
21 | |||
22 | int sysfs_alloc_ino(ino_t *pino) | ||
23 | { | ||
24 | int ino, rc; | ||
25 | |||
26 | retry: | ||
27 | spin_lock(&sysfs_ino_lock); | ||
28 | rc = ida_get_new_above(&sysfs_ino_ida, 2, &ino); | ||
29 | spin_unlock(&sysfs_ino_lock); | ||
30 | |||
31 | if (rc == -EAGAIN) { | ||
32 | if (ida_pre_get(&sysfs_ino_ida, GFP_KERNEL)) | ||
33 | goto retry; | ||
34 | rc = -ENOMEM; | ||
35 | } | ||
36 | |||
37 | *pino = ino; | ||
38 | return rc; | ||
39 | } | ||
40 | |||
41 | static void sysfs_free_ino(ino_t ino) | ||
42 | { | ||
43 | spin_lock(&sysfs_ino_lock); | ||
44 | ida_remove(&sysfs_ino_ida, ino); | ||
45 | spin_unlock(&sysfs_ino_lock); | ||
46 | } | ||
47 | |||
18 | void release_sysfs_dirent(struct sysfs_dirent * sd) | 48 | void release_sysfs_dirent(struct sysfs_dirent * sd) |
19 | { | 49 | { |
20 | if (sd->s_type & SYSFS_KOBJ_LINK) { | 50 | if (sd->s_type & SYSFS_KOBJ_LINK) { |
@@ -24,6 +54,7 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) | |||
24 | kfree(sl); | 54 | kfree(sl); |
25 | } | 55 | } |
26 | kfree(sd->s_iattr); | 56 | kfree(sd->s_iattr); |
57 | sysfs_free_ino(sd->s_ino); | ||
27 | kmem_cache_free(sysfs_dir_cachep, sd); | 58 | kmem_cache_free(sysfs_dir_cachep, sd); |
28 | } | 59 | } |
29 | 60 | ||
@@ -54,14 +85,6 @@ static struct dentry_operations sysfs_dentry_ops = { | |||
54 | .d_iput = sysfs_d_iput, | 85 | .d_iput = sysfs_d_iput, |
55 | }; | 86 | }; |
56 | 87 | ||
57 | static unsigned int sysfs_inode_counter; | ||
58 | ino_t sysfs_get_inum(void) | ||
59 | { | ||
60 | if (unlikely(sysfs_inode_counter < 3)) | ||
61 | sysfs_inode_counter = 3; | ||
62 | return sysfs_inode_counter++; | ||
63 | } | ||
64 | |||
65 | /* | 88 | /* |
66 | * Allocates a new sysfs_dirent and links it to the parent sysfs_dirent | 89 | * Allocates a new sysfs_dirent and links it to the parent sysfs_dirent |
67 | */ | 90 | */ |
@@ -73,7 +96,11 @@ static struct sysfs_dirent * __sysfs_new_dirent(void * element) | |||
73 | if (!sd) | 96 | if (!sd) |
74 | return NULL; | 97 | return NULL; |
75 | 98 | ||
76 | sd->s_ino = sysfs_get_inum(); | 99 | if (sysfs_alloc_ino(&sd->s_ino)) { |
100 | kmem_cache_free(sysfs_dir_cachep, sd); | ||
101 | return NULL; | ||
102 | } | ||
103 | |||
77 | atomic_set(&sd->s_count, 1); | 104 | atomic_set(&sd->s_count, 1); |
78 | atomic_set(&sd->s_event, 1); | 105 | atomic_set(&sd->s_event, 1); |
79 | INIT_LIST_HEAD(&sd->s_children); | 106 | INIT_LIST_HEAD(&sd->s_children); |