sysfs: add sysfs_dirent->s_parent
[linux-2.6-block.git] / fs / sysfs / dir.c
CommitLineData
1da177e4
LT
1/*
2 * dir.c - Operations for sysfs directories.
3 */
4
5#undef DEBUG
6
7#include <linux/fs.h>
8#include <linux/mount.h>
9#include <linux/module.h>
10#include <linux/kobject.h>
5f45f1a7 11#include <linux/namei.h>
2b611bb7 12#include <linux/idr.h>
94bebf4d 13#include <asm/semaphore.h>
1da177e4
LT
14#include "sysfs.h"
15
16DECLARE_RWSEM(sysfs_rename_sem);
dd14cbc9 17spinlock_t sysfs_lock = SPIN_LOCK_UNLOCKED;
1da177e4 18
2b611bb7
TH
19static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED;
20static DEFINE_IDA(sysfs_ino_ida);
21
22int 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
41static 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
fa7f912a
TH
48void release_sysfs_dirent(struct sysfs_dirent * sd)
49{
13b3086d
TH
50 struct sysfs_dirent *parent_sd;
51
52 repeat:
53 parent_sd = sd->s_parent;
54
fa7f912a
TH
55 if (sd->s_type & SYSFS_KOBJ_LINK) {
56 struct sysfs_symlink * sl = sd->s_element;
57 kfree(sl->link_name);
58 kobject_put(sl->target_kobj);
59 kfree(sl);
60 }
61 kfree(sd->s_iattr);
2b611bb7 62 sysfs_free_ino(sd->s_ino);
fa7f912a 63 kmem_cache_free(sysfs_dir_cachep, sd);
13b3086d
TH
64
65 sd = parent_sd;
66 if (sd && atomic_dec_and_test(&sd->s_count))
67 goto repeat;
fa7f912a
TH
68}
69
1da177e4
LT
70static void sysfs_d_iput(struct dentry * dentry, struct inode * inode)
71{
72 struct sysfs_dirent * sd = dentry->d_fsdata;
73
74 if (sd) {
dd14cbc9
TH
75 /* sd->s_dentry is protected with sysfs_lock. This
76 * allows sysfs_drop_dentry() to dereference it.
77 */
78 spin_lock(&sysfs_lock);
79
80 /* The dentry might have been deleted or another
81 * lookup could have happened updating sd->s_dentry to
82 * point the new dentry. Ignore if it isn't pointing
83 * to this dentry.
84 */
85 if (sd->s_dentry == dentry)
86 sd->s_dentry = NULL;
87 spin_unlock(&sysfs_lock);
1da177e4
LT
88 sysfs_put(sd);
89 }
90 iput(inode);
91}
92
93static struct dentry_operations sysfs_dentry_ops = {
94 .d_iput = sysfs_d_iput,
95};
96
a26cd722 97struct sysfs_dirent *sysfs_new_dirent(void *element, umode_t mode, int type)
1da177e4
LT
98{
99 struct sysfs_dirent * sd;
100
c3762229 101 sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);
1da177e4
LT
102 if (!sd)
103 return NULL;
104
2b611bb7
TH
105 if (sysfs_alloc_ino(&sd->s_ino)) {
106 kmem_cache_free(sysfs_dir_cachep, sd);
107 return NULL;
108 }
109
1da177e4 110 atomic_set(&sd->s_count, 1);