diff options
Diffstat (limited to 'fs/sysfs/dir.c')
-rw-r--r-- | fs/sysfs/dir.c | 130 |
1 files changed, 48 insertions, 82 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 = { |