diff options
author | Tejun Heo <htejun@gmail.com> | 2007-06-13 14:45:17 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-07-11 19:09:07 -0400 |
commit | fc9f54b9982e14e6dbe023425c87ffbfd6992c45 (patch) | |
tree | 61b828ac694d9e8decb02022a1056a5367bb1bef | |
parent | 7f7cfffe60ed6271c4028ec79ae1c297b44bcb14 (diff) |
sysfs: reorganize sysfs_new_indoe() and sysfs_create()
Reorganize/clean up sysfs_new_inode() and sysfs_create().
* sysfs_init_inode() is separated out from sysfs_new_inode() and is
responsible for basic initialization.
* sysfs_instantiate() replaces the last step of sysfs_create() and is
responsible for dentry instantitaion.
* type-specific initialization is moved out to the callers.
* mode is specified only once when creating a sysfs_dirent.
* spurious list_del_init(&sd->s_sibling) dropped from create_dir()
This change is to
* prepare for inode allocation fix.
* separate alloc and init code for synchronization update.
* make dentry/inode initialization more flexible for later changes.
This patch doesn't introduce visible behavior change.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | fs/sysfs/dir.c | 130 | ||||
-rw-r--r-- | fs/sysfs/inode.c | 108 | ||||
-rw-r--r-- | fs/sysfs/mount.c | 18 | ||||
-rw-r--r-- | fs/sysfs/sysfs.h | 6 |
4 files changed, 118 insertions, 144 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index a26e3db89432..bbf3525fd222 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -191,39 +191,18 @@ int sysfs_dirent_exist(struct sysfs_dirent *parent_sd, | |||
191 | return 0; | 191 | return 0; |
192 | } | 192 | } |
193 | 193 | ||
194 | static int init_dir(struct inode * inode) | ||
195 | { | ||
196 | inode->i_op = &sysfs_dir_inode_operations; | ||
197 | inode->i_fop = &sysfs_dir_operations; | ||
198 | |||
199 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ | ||
200 | inc_nlink(inode); | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static int init_file(struct inode * inode) | ||
205 | { | ||
206 | inode->i_size = PAGE_SIZE; | ||
207 | inode->i_fop = &sysfs_file_operations; | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static int init_symlink(struct inode * inode) | ||
212 | { | ||
213 | inode->i_op = &sysfs_symlink_inode_operations; | ||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | static int create_dir(struct kobject *kobj, struct dentry *parent, | 194 | static int create_dir(struct kobject *kobj, struct dentry *parent, |
218 | const char *name, struct dentry **p_dentry) | 195 | const char *name, struct dentry **p_dentry) |
219 | { | 196 | { |
220 | int error; | 197 | int error; |
221 | umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; | 198 | umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; |
222 | struct dentry *dentry; | 199 | struct dentry *dentry; |
200 | struct inode *inode; | ||
223 | struct sysfs_dirent *sd; | 201 | struct sysfs_dirent *sd; |
224 | 202 | ||
225 | mutex_lock(&parent->d_inode->i_mutex); | 203 | mutex_lock(&parent->d_inode->i_mutex); |
226 | 204 | ||
205 | /* allocate */ | ||
227 | dentry = lookup_one_len(name, parent, strlen(name)); | 206 | dentry = lookup_one_len(name, parent, strlen(name)); |
228 | if (IS_ERR(dentry)) { | 207 | if (IS_ERR(dentry)) { |
229 | error = PTR_ERR(dentry); | 208 | error = PTR_ERR(dentry); |
@@ -231,7 +210,7 @@ static int create_dir(struct kobject *kobj, struct dentry *parent, | |||
231 | } | 210 | } |
232 | 211 | ||
233 | error = -EEXIST; | 212 | error = -EEXIST; |
234 | if (sysfs_dirent_exist(parent->d_fsdata, name)) | 213 | if (dentry->d_inode) |
235 | goto out_dput; | 214 | goto out_dput; |
236 | 215 | ||
237 | error = -ENOMEM; | 216 | error = -ENOMEM; |
@@ -240,19 +219,31 @@ static int create_dir(struct kobject *kobj, struct dentry *parent, | |||
240 | goto out_drop; | 219 | goto out_drop; |
241 | sd->s_elem.dir.kobj = kobj; | 220 | sd->s_elem.dir.kobj = kobj; |
242 | 221 | ||
243 | error = sysfs_create(sd, dentry, mode, init_dir); | 222 | inode = sysfs_new_inode(sd); |
244 | if (error) | 223 | if (!inode) |
245 | goto out_sput; | 224 | goto out_sput; |
246 | 225 | ||
226 | inode->i_op = &sysfs_dir_inode_operations; | ||
227 | inode->i_fop = &sysfs_dir_operations; | ||
228 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ | ||
229 | inc_nlink(inode); | ||
230 | |||
231 | /* link in */ | ||
232 | error = -EEXIST; | ||
233 | if (sysfs_dirent_exist(parent->d_fsdata, name)) | ||
234 | goto out_iput; | ||
235 | |||
236 | sysfs_instantiate(dentry, inode); | ||
247 | inc_nlink(parent->d_inode); | 237 | inc_nlink(parent->d_inode); |
248 | sysfs_attach_dirent(sd, parent->d_fsdata, dentry); | 238 | sysfs_attach_dirent(sd, parent->d_fsdata, dentry); |
249 | 239 | ||
250 | *p_dentry = dentry; | 240 | *p_dentry = dentry; |
251 | error = 0; | 241 | error = 0; |
252 | goto out_dput; | 242 | goto out_unlock; /* pin directory dentry in core */ |
253 | 243 | ||
244 | out_iput: | ||
245 | iput(inode); | ||
254 | out_sput: | 246 | out_sput: |
255 | list_del_init(&sd->s_sibling); | ||
256 | sysfs_put(sd); | 247 | sysfs_put(sd); |
257 | out_drop: | 248 | out_drop: |
258 | d_drop(dentry); | 249 | d_drop(dentry); |
@@ -298,71 +289,46 @@ int sysfs_create_dir(struct kobject * kobj, struct dentry *shadow_parent) | |||
298 | return error; | 289 | return error; |
299 | } | 290 | } |
300 | 291 | ||
301 | /* attaches attribute's sysfs_dirent to the dentry corresponding to the | ||
302 | * attribute file | ||
303 | */ | ||
304 | static int sysfs_attach_attr(struct sysfs_dirent * sd, struct dentry * dentry) | ||
305 | { | ||
306 | struct attribute * attr = NULL; | ||
307 | struct bin_attribute * bin_attr = NULL; | ||
308 | int (* init) (struct inode *) = NULL; | ||
309 | int error = 0; | ||
310 | |||
311 | if (sd->s_type & SYSFS_KOBJ_BIN_ATTR) { | ||
312 | bin_attr = sd->s_elem.bin_attr.bin_attr; | ||
313 | attr = &bin_attr->attr; | ||
314 | } else { | ||
315 | attr = sd->s_elem.attr.attr; | ||
316 | init = init_file; | ||
317 | } | ||
318 | |||
319 | error = sysfs_create(sd, dentry, | ||
320 | (attr->mode & S_IALLUGO) | S_IFREG, init); | ||
321 | if (error) | ||
322 | return error; | ||
323 | |||
324 | if (bin_attr) { | ||
325 | dentry->d_inode->i_size = bin_attr->size; | ||
326 | dentry->d_inode->i_fop = &bin_fops; | ||
327 | } | ||
328 | |||
329 | sysfs_attach_dentry(sd, dentry); | ||
330 | |||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static int sysfs_attach_link(struct sysfs_dirent * sd, struct dentry * dentry) | ||
335 | { | ||
336 | int err; | ||
337 | |||
338 | err = sysfs_create(sd, dentry, S_IFLNK|S_IRWXUGO, init_symlink); | ||
339 | if (!err) | ||
340 | sysfs_attach_dentry(sd, dentry); | ||
341 | |||
342 | return err; | ||
343 | } | ||
344 | |||
345 | static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | 292 | static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, |
346 | struct nameidata *nd) | 293 | struct nameidata *nd) |
347 | { | 294 | { |
348 | struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata; | 295 | struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata; |
349 | struct sysfs_dirent * sd; | 296 | struct sysfs_dirent * sd; |
350 | int err = 0; | 297 | struct inode *inode; |
298 | int found = 0; | ||
351 | 299 | ||
352 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { | 300 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { |
353 | if (sd->s_type & SYSFS_NOT_PINNED) { | 301 | if ((sd->s_type & SYSFS_NOT_PINNED) && |
354 | if (strcmp(sd->s_name, dentry->d_name.name)) | 302 | !strcmp(sd->s_name, dentry->d_name.name)) { |
355 | continue; | 303 | found = 1; |
356 | |||
357 | if (sd->s_type & SYSFS_KOBJ_LINK) | ||
358 | err = sysfs_attach_link(sd, dentry); | ||
359 | else | ||
360 | err = sysfs_attach_attr(sd, dentry); | ||
361 | break; | 304 | break; |
362 | } | 305 | } |
363 | } | 306 | } |
364 | 307 | ||
365 | return ERR_PTR(err); | 308 | /* no such entry */ |
309 | if (!found) | ||
310 | return NULL; | ||
311 | |||
312 | /* attach dentry and inode */ | ||
313 | inode = sysfs_new_inode(sd); | ||
314 | if (!inode) | ||
315 | return ERR_PTR(-ENOMEM); | ||
316 | |||
317 | /* initialize inode according to type */ | ||
318 | if (sd->s_type & SYSFS_KOBJ_ATTR) { | ||
319 | inode->i_size = PAGE_SIZE; | ||
320 | inode->i_fop = &sysfs_file_operations; | ||
321 | } else if (sd->s_type & SYSFS_KOBJ_BIN_ATTR) { | ||
322 | struct bin_attribute *bin_attr = sd->s_elem.bin_attr.bin_attr; | ||
323 | inode->i_size = bin_attr->size; | ||
324 | inode->i_fop = &bin_fops; | ||
325 | } else if (sd->s_type & SYSFS_KOBJ_LINK) | ||
326 | inode->i_op = &sysfs_symlink_inode_operations; | ||
327 | |||
328 | sysfs_instantiate(dentry, inode); | ||
329 | sysfs_attach_dentry(sd, dentry); | ||
330 | |||
331 | return NULL; | ||
366 | } | 332 | } |
367 | 333 | ||
368 | const struct inode_operations sysfs_dir_inode_operations = { | 334 | const struct inode_operations sysfs_dir_inode_operations = { |
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 6ad47c13b94d..26d8503c8997 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
@@ -133,62 +133,68 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) | |||
133 | */ | 133 | */ |
134 | static struct lock_class_key sysfs_inode_imutex_key; | 134 | static struct lock_class_key sysfs_inode_imutex_key; |
135 | 135 | ||
136 | struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent * sd) | 136 | void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) |
137 | { | 137 | { |
138 | struct inode * inode = new_inode(sysfs_sb); | 138 | inode->i_blocks = 0; |
139 | if (inode) { | 139 | inode->i_mapping->a_ops = &sysfs_aops; |
140 | inode->i_blocks = 0; | 140 | inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; |
141 | inode->i_mapping->a_ops = &sysfs_aops; | 141 | inode->i_op = &sysfs_inode_operations; |
142 | inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; | 142 | inode->i_ino = sd->s_ino; |
143 | inode->i_op = &sysfs_inode_operations; | 143 | lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key); |
144 | inode->i_ino = sd->s_ino; | 144 | |
145 | lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key); | 145 | if (sd->s_iattr) { |
146 | 146 | /* sysfs_dirent has non-default attributes | |
147 | if (sd->s_iattr) { | 147 | * get them for the new inode from persistent copy |
148 | /* sysfs_dirent has non-default attributes | 148 | * in sysfs_dirent |
149 | * get them for the new inode from persistent copy | 149 | */ |
150 | * in sysfs_dirent | 150 | set_inode_attr(inode, sd->s_iattr); |
151 | */ | 151 | } else |
152 | set_inode_attr(inode, sd->s_iattr); | 152 | set_default_inode_attr(inode, sd->s_mode); |
153 | } else | 153 | } |
154 | set_default_inode_attr(inode, mode); | 154 | |
155 | } | 155 | /** |
156 | * sysfs_new_inode - allocate new inode for sysfs_dirent | ||
157 | * @sd: sysfs_dirent to allocate inode for | ||
158 | * | ||
159 | * Allocate inode for @sd and initialize basics. | ||
160 | * | ||
161 | * LOCKING: | ||
162 | * Kernel thread context (may sleep). | ||
163 | * | ||
164 | * RETURNS: | ||
165 | * Pointer to allocated inode on success, NULL on failure. | ||
166 | */ | ||
167 | struct inode * sysfs_new_inode(struct sysfs_dirent *sd) | ||
168 | { | ||
169 | struct inode *inode; | ||
170 | |||
171 | inode = new_inode(sysfs_sb); | ||
172 | if (inode) | ||
173 | sysfs_init_inode(sd, inode); | ||
174 | |||
156 | return inode; | 175 | return inode; |
157 | } | 176 | } |
158 | 177 | ||
159 | int sysfs_create(struct sysfs_dirent *sd, struct dentry *dentry, int mode, | 178 | /** |
160 | int (*init)(struct inode *)) | 179 | * sysfs_instantiate - instantiate dentry |
180 | * @dentry: dentry to be instantiated | ||
181 | * @inode: inode associated with @sd | ||
182 | * | ||
183 | * Instantiate @dentry with @inode. | ||
184 | * | ||
185 | * LOCKING: | ||
186 | * None. | ||
187 | */ | ||
188 | void sysfs_instantiate(struct dentry *dentry, struct inode *inode) | ||
161 | { | 189 | { |
162 | int error = 0; | 190 | BUG_ON(!dentry || dentry->d_inode); |
163 | struct inode * inode = NULL; | 191 | |
164 | if (dentry) { | 192 | if (dentry->d_parent && dentry->d_parent->d_inode) { |
165 | if (!dentry->d_inode) { | 193 | struct inode *p_inode = dentry->d_parent->d_inode; |
166 | if ((inode = sysfs_new_inode(mode, sd))) { | 194 | p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME; |
167 | if (dentry->d_parent && dentry->d_parent->d_inode) { | 195 | } |
168 | struct inode *p_inode = dentry->d_parent->d_inode; | 196 | |
169 | p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME; | 197 | d_instantiate(dentry, inode); |
170 | } | ||
171 | goto Proceed; | ||
172 | } | ||
173 | else | ||
174 | error = -ENOMEM; | ||
175 | } else | ||
176 | error = -EEXIST; | ||
177 | } else | ||
178 | error = -ENOENT; | ||
179 | goto Done; | ||
180 | |||
181 | Proceed: | ||
182 | if (init) | ||
183 | error = init(inode); | ||
184 | if (!error) { | ||
185 | d_instantiate(dentry, inode); | ||
186 | if (S_ISDIR(mode)) | ||
187 | dget(dentry); /* pin only directory dentry in core */ | ||
188 | } else | ||
189 | iput(inode); | ||
190 | Done: | ||
191 | return error; | ||
192 | } | 198 | } |
193 | 199 | ||
194 | /** | 200 | /** |
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 37ff9ffc55f0..6d3a6249d21c 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c | |||
@@ -29,6 +29,7 @@ static struct sysfs_dirent sysfs_root = { | |||
29 | .s_sibling = LIST_HEAD_INIT(sysfs_root.s_sibling), | 29 | .s_sibling = LIST_HEAD_INIT(sysfs_root.s_sibling), |
30 | .s_children = LIST_HEAD_INIT(sysfs_root.s_children), | 30 | .s_children = LIST_HEAD_INIT(sysfs_root.s_children), |
31 | .s_type = SYSFS_ROOT, | 31 | .s_type = SYSFS_ROOT, |
32 | .s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, | ||
32 | .s_iattr = NULL, | 33 | .s_iattr = NULL, |
33 | .s_ino = 1, | 34 | .s_ino = 1, |
34 | }; | 35 | }; |
@@ -45,18 +46,19 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) | |||
45 | sb->s_time_gran = 1; | 46 | sb->s_time_gran = 1; |
46 | sysfs_sb = sb; | 47 | sysfs_sb = sb; |
47 | 48 | ||
48 | inode = sysfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, | 49 | inode = new_inode(sysfs_sb); |
49 | &sysfs_root); | 50 | if (!inode) { |
50 | if (inode) { | ||
51 | inode->i_op = &sysfs_dir_inode_operations; | ||
52 | inode->i_fop = &sysfs_dir_operations; | ||
53 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ | ||
54 | inc_nlink(inode); | ||
55 | } else { | ||
56 | pr_debug("sysfs: could not get root inode\n"); | 51 | pr_debug("sysfs: could not get root inode\n"); |
57 | return -ENOMEM; | 52 | return -ENOMEM; |
58 | } | 53 | } |
59 | 54 | ||
55 | sysfs_init_inode(&sysfs_root, inode); | ||
56 | |||
57 | inode->i_op = &sysfs_dir_inode_operations; | ||
58 | inode->i_fop = &sysfs_dir_operations; | ||
59 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ | ||
60 | inc_nlink(inode); | ||
61 | |||
60 | root = d_alloc_root(inode); | 62 | root = d_alloc_root(inode); |
61 | if (!root) { | 63 | if (!root) { |
62 | pr_debug("%s: could not get root dentry!\n",__FUNCTION__); | 64 | pr_debug("%s: could not get root dentry!\n",__FUNCTION__); |
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index fc6aa863b947..143fdbe56c14 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
@@ -57,9 +57,9 @@ extern struct vfsmount * sysfs_mount; | |||
57 | extern struct kmem_cache *sysfs_dir_cachep; | 57 | extern struct kmem_cache *sysfs_dir_cachep; |
58 | 58 | ||
59 | extern void sysfs_delete_inode(struct inode *inode); | 59 | extern void sysfs_delete_inode(struct inode *inode); |
60 | extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *); | 60 | extern void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode); |
61 | extern int sysfs_create(struct sysfs_dirent *sd, struct dentry *dentry, | 61 | extern struct inode * sysfs_new_inode(struct sysfs_dirent *sd); |
62 | int mode, int (*init)(struct inode *)); | 62 | extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode); |
63 | 63 | ||
64 | extern void release_sysfs_dirent(struct sysfs_dirent * sd); | 64 | extern void release_sysfs_dirent(struct sysfs_dirent * sd); |
65 | extern int sysfs_dirent_exist(struct sysfs_dirent *, const unsigned char *); | 65 | extern int sysfs_dirent_exist(struct sysfs_dirent *, const unsigned char *); |