Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / fs / sysfs / inode.c
1 /*
2  * inode.c - basic inode and dentry operations.
3  *
4  * sysfs is Copyright (c) 2001-3 Patrick Mochel
5  *
6  * Please see Documentation/filesystems/sysfs.txt for more information.
7  */
8
9 #undef DEBUG 
10
11 #include <linux/pagemap.h>
12 #include <linux/namei.h>
13 #include <linux/backing-dev.h>
14 #include "sysfs.h"
15
16 extern struct super_block * sysfs_sb;
17
18 static struct address_space_operations sysfs_aops = {
19         .readpage       = simple_readpage,
20         .prepare_write  = simple_prepare_write,
21         .commit_write   = simple_commit_write
22 };
23
24 static struct backing_dev_info sysfs_backing_dev_info = {
25         .ra_pages       = 0,    /* No readahead */
26         .capabilities   = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
27 };
28
29 struct inode * sysfs_new_inode(mode_t mode)
30 {
31         struct inode * inode = new_inode(sysfs_sb);
32         if (inode) {
33                 inode->i_mode = mode;
34                 inode->i_uid = 0;
35                 inode->i_gid = 0;
36                 inode->i_blksize = PAGE_CACHE_SIZE;
37                 inode->i_blocks = 0;
38                 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
39                 inode->i_mapping->a_ops = &sysfs_aops;
40                 inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
41         }
42         return inode;
43 }
44
45 int sysfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *))
46 {
47         int error = 0;
48         struct inode * inode = NULL;
49         if (dentry) {
50                 if (!dentry->d_inode) {
51                         if ((inode = sysfs_new_inode(mode))) {
52                                 if (dentry->d_parent && dentry->d_parent->d_inode) {
53                                         struct inode *p_inode = dentry->d_parent->d_inode;
54                                         p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME;
55                                 }
56                                 goto Proceed;
57                         }
58                         else 
59                                 error = -ENOMEM;
60                 } else
61                         error = -EEXIST;
62         } else 
63                 error = -ENOENT;
64         goto Done;
65
66  Proceed:
67         if (init)
68                 error = init(inode);
69         if (!error) {
70                 d_instantiate(dentry, inode);
71                 if (S_ISDIR(mode))
72                         dget(dentry);  /* pin only directory dentry in core */
73         } else
74                 iput(inode);
75  Done:
76         return error;
77 }
78
79 struct dentry * sysfs_get_dentry(struct dentry * parent, const char * name)
80 {
81         struct qstr qstr;
82
83         qstr.name = name;
84         qstr.len = strlen(name);
85         qstr.hash = full_name_hash(name,qstr.len);
86         return lookup_hash(&qstr,parent);
87 }
88
89 /*
90  * Get the name for corresponding element represented by the given sysfs_dirent
91  */
92 const unsigned char * sysfs_get_name(struct sysfs_dirent *sd)
93 {
94         struct attribute * attr;
95         struct bin_attribute * bin_attr;
96         struct sysfs_symlink  * sl;
97
98         if (!sd || !sd->s_element)
99                 BUG();
100
101         switch (sd->s_type) {
102                 case SYSFS_DIR:
103                         /* Always have a dentry so use that */
104                         return sd->s_dentry->d_name.name;
105
106                 case SYSFS_KOBJ_ATTR:
107                         attr = sd->s_element;
108                         return attr->name;
109
110                 case SYSFS_KOBJ_BIN_ATTR:
111                         bin_attr = sd->s_element;
112                         return bin_attr->attr.name;
113
114                 case SYSFS_KOBJ_LINK:
115                         sl = sd->s_element;
116                         return sl->link_name;
117         }
118         return NULL;
119 }
120
121
122 /*
123  * Unhashes the dentry corresponding to given sysfs_dirent
124  * Called with parent inode's i_sem held.
125  */
126 void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent)
127 {
128         struct dentry * dentry = sd->s_dentry;
129
130         if (dentry) {
131                 spin_lock(&dcache_lock);
132                 spin_lock(&dentry->d_lock);
133                 if (!(d_unhashed(dentry) && dentry->d_inode)) {
134                         dget_locked(dentry);
135                         __d_drop(dentry);
136                         spin_unlock(&dentry->d_lock);
137                         spin_unlock(&dcache_lock);
138                         simple_unlink(parent->d_inode, dentry);
139                 } else {
140                         spin_unlock(&dentry->d_lock);
141                         spin_unlock(&dcache_lock);
142                 }
143         }
144 }
145
146 void sysfs_hash_and_remove(struct dentry * dir, const char * name)
147 {
148         struct sysfs_dirent * sd;
149         struct sysfs_dirent * parent_sd = dir->d_fsdata;
150
151         down(&dir->d_inode->i_sem);
152         list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
153                 if (!sd->s_element)
154                         continue;
155                 if (!strcmp(sysfs_get_name(sd), name)) {
156                         list_del_init(&sd->s_sibling);
157                         sysfs_drop_dentry(sd, dir);
158                         sysfs_put(sd);
159                         break;
160                 }
161         }
162         up(&dir->d_inode->i_sem);
163 }
164
165