diff options
-rw-r--r-- | fs/sysfs/dir.c | 250 | ||||
-rw-r--r-- | fs/sysfs/file.c | 17 | ||||
-rw-r--r-- | fs/sysfs/inode.c | 46 | ||||
-rw-r--r-- | fs/sysfs/symlink.c | 20 | ||||
-rw-r--r-- | fs/sysfs/sysfs.h | 20 |
5 files changed, 229 insertions, 124 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 9fc8558fd86c..edb30621b82f 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -30,7 +30,7 @@ static DEFINE_IDA(sysfs_ino_ida); | |||
30 | * Locking: | 30 | * Locking: |
31 | * mutex_lock(sysfs_mutex) | 31 | * mutex_lock(sysfs_mutex) |
32 | */ | 32 | */ |
33 | static void sysfs_link_sibling(struct sysfs_dirent *sd) | 33 | void sysfs_link_sibling(struct sysfs_dirent *sd) |
34 | { | 34 | { |
35 | struct sysfs_dirent *parent_sd = sd->s_parent; | 35 | struct sysfs_dirent *parent_sd = sd->s_parent; |
36 | 36 | ||
@@ -49,7 +49,7 @@ static void sysfs_link_sibling(struct sysfs_dirent *sd) | |||
49 | * Locking: | 49 | * Locking: |
50 | * mutex_lock(sysfs_mutex) | 50 | * mutex_lock(sysfs_mutex) |
51 | */ | 51 | */ |
52 | static void sysfs_unlink_sibling(struct sysfs_dirent *sd) | 52 | void sysfs_unlink_sibling(struct sysfs_dirent *sd) |
53 | { | 53 | { |
54 | struct sysfs_dirent **pos; | 54 | struct sysfs_dirent **pos; |
55 | 55 | ||
@@ -165,7 +165,7 @@ void sysfs_put_active_two(struct sysfs_dirent *sd) | |||
165 | * | 165 | * |
166 | * Deny new active references and drain existing ones. | 166 | * Deny new active references and drain existing ones. |
167 | */ | 167 | */ |
168 | void sysfs_deactivate(struct sysfs_dirent *sd) | 168 | static void sysfs_deactivate(struct sysfs_dirent *sd) |
169 | { | 169 | { |
170 | DECLARE_COMPLETION_ONSTACK(wait); | 170 | DECLARE_COMPLETION_ONSTACK(wait); |
171 | int v; | 171 | int v; |
@@ -318,27 +318,164 @@ static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry) | |||
318 | d_rehash(dentry); | 318 | d_rehash(dentry); |
319 | } | 319 | } |
320 | 320 | ||
321 | static int sysfs_ilookup_test(struct inode *inode, void *arg) | ||
322 | { | ||
323 | struct sysfs_dirent *sd = arg; | ||
324 | return inode->i_ino == sd->s_ino; | ||
325 | } | ||
326 | |||
321 | /** | 327 | /** |
322 | * sysfs_attach_dirent - attach sysfs_dirent to its parent and dentry | 328 | * sysfs_addrm_start - prepare for sysfs_dirent add/remove |
323 | * @sd: sysfs_dirent to attach | 329 | * @acxt: pointer to sysfs_addrm_cxt to be used |
324 | * @parent_sd: parent to attach to (optional) | 330 | * @parent_sd: parent sysfs_dirent |
325 | * @dentry: dentry to be associated to @sd (optional) | ||
326 | * | 331 | * |
327 | * Attach @sd to @parent_sd and/or @dentry. Both are optional. | 332 | * This function is called when the caller is about to add or |
333 | * remove sysfs_dirent under @parent_sd. This function acquires | ||
334 | * sysfs_mutex, grabs inode for @parent_sd if available and lock | ||
335 | * i_mutex of it. @acxt is used to keep and pass context to | ||
336 | * other addrm functions. | ||
328 | * | 337 | * |
329 | * LOCKING: | 338 | * LOCKING: |
330 | * mutex_lock(sysfs_mutex) | 339 | * Kernel thread context (may sleep). sysfs_mutex is locked on |
340 | * return. i_mutex of parent inode is locked on return if | ||
341 | * available. | ||
331 | */ | 342 | */ |
332 | void sysfs_attach_dirent(struct sysfs_dirent *sd, | 343 | void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, |
333 | struct sysfs_dirent *parent_sd, struct dentry *dentry) | 344 | struct sysfs_dirent *parent_sd) |
334 | { | 345 | { |
335 | if (dentry) | 346 | struct inode *inode; |
336 | sysfs_attach_dentry(sd, dentry); | ||
337 | 347 | ||
338 | if (parent_sd) { | 348 | memset(acxt, 0, sizeof(*acxt)); |
339 | sd->s_parent = sysfs_get(parent_sd); | 349 | acxt->parent_sd = parent_sd; |
340 | sysfs_link_sibling(sd); | 350 | |
351 | /* Lookup parent inode. inode initialization and I_NEW | ||
352 | * clearing are protected by sysfs_mutex. By grabbing it and | ||
353 | * looking up with _nowait variant, inode state can be | ||
354 | * determined reliably. | ||
355 | */ | ||
356 | mutex_lock(&sysfs_mutex); | ||
357 | |||
358 | inode = ilookup5_nowait(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test, | ||
359 | parent_sd); | ||
360 | |||
361 | if (inode && !(inode->i_state & I_NEW)) { | ||
362 | /* parent inode available */ | ||
363 | acxt->parent_inode = inode; | ||
364 | |||
365 | /* sysfs_mutex is below i_mutex in lock hierarchy. | ||
366 | * First, trylock i_mutex. If fails, unlock | ||
367 | * sysfs_mutex and lock them in order. | ||
368 | */ | ||
369 | if (!mutex_trylock(&inode->i_mutex)) { | ||
370 | mutex_unlock(&sysfs_mutex); | ||
371 | mutex_lock(&inode->i_mutex); | ||
372 | mutex_lock(&sysfs_mutex); | ||
373 | } | ||
374 | } else | ||
375 | iput(inode); | ||
376 | } | ||
377 | |||
378 | /** | ||
379 | * sysfs_add_one - add sysfs_dirent to parent | ||
380 | * @acxt: addrm context to use | ||
381 | * @sd: sysfs_dirent to be added | ||
382 | * | ||
383 | * Get @acxt->parent_sd and set sd->s_parent to it and increment | ||
384 | * nlink of parent inode if @sd is a directory. @sd is NOT | ||
385 | * linked into the children list of the parent. The caller | ||
386 | * should invoke sysfs_link_sibling() after this function | ||
387 | * completes if @sd needs to be on the children list. | ||
388 | * | ||
389 | * This function should be called between calls to | ||
390 | * sysfs_addrm_start() and sysfs_addrm_finish() and should be | ||
391 | * passed the same @acxt as passed to sysfs_addrm_start(). | ||
392 | * | ||
393 | * LOCKING: | ||
394 | * Determined by sysfs_addrm_start(). | ||
395 | */ | ||
396 | void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | ||
397 | { | ||
398 | sd->s_parent = sysfs_get(acxt->parent_sd); | ||
399 | |||
400 | if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode) | ||
401 | inc_nlink(acxt->parent_inode); | ||
402 | |||
403 | acxt->cnt++; | ||
404 | } | ||
405 | |||
406 | /** | ||
407 | * sysfs_remove_one - remove sysfs_dirent from parent | ||
408 | * @acxt: addrm context to use | ||
409 | * @sd: sysfs_dirent to be added | ||
410 | * | ||
411 | * Mark @sd removed and drop nlink of parent inode if @sd is a | ||
412 | * directory. @sd is NOT unlinked from the children list of the | ||
413 | * parent. The caller is repsonsible for removing @sd from the | ||
414 | * children list before calling this function. | ||
415 | * | ||
416 | * This function should be called between calls to | ||
417 | * sysfs_addrm_start() and sysfs_addrm_finish() and should be | ||
418 | * passed the same @acxt as passed to sysfs_addrm_start(). | ||
419 | * | ||
420 | * LOCKING: | ||
421 | * Determined by sysfs_addrm_start(). | ||
422 | */ | ||
423 | void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | ||
424 | { | ||
425 | BUG_ON(sd->s_sibling || (sd->s_flags & SYSFS_FLAG_REMOVED)); | ||
426 | |||
427 | sd->s_flags |= SYSFS_FLAG_REMOVED; | ||
428 | sd->s_sibling = acxt->removed; | ||
429 | acxt->removed = sd; | ||
430 | |||
431 | if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode) | ||
432 | drop_nlink(acxt->parent_inode); | ||
433 | |||
434 | acxt->cnt++; | ||
435 | } | ||
436 | |||
437 | /** | ||
438 | * sysfs_addrm_finish - finish up sysfs_dirent add/remove | ||
439 | * @acxt: addrm context to finish up | ||
440 | * | ||
441 | * Finish up sysfs_dirent add/remove. Resources acquired by | ||
442 | * sysfs_addrm_start() are released and removed sysfs_dirents are | ||
443 | * cleaned up. Timestamps on the parent inode are updated. | ||
444 | * | ||
445 | * LOCKING: | ||
446 | * All mutexes acquired by sysfs_addrm_start() are released. | ||
447 | * | ||
448 | * RETURNS: | ||
449 | * Number of added/removed sysfs_dirents since sysfs_addrm_start(). | ||
450 | */ | ||
451 | int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | ||
452 | { | ||
453 | /* release resources acquired by sysfs_addrm_start() */ | ||
454 | mutex_unlock(&sysfs_mutex); | ||
455 | if (acxt->parent_inode) { | ||
456 | struct inode *inode = acxt->parent_inode; | ||
457 | |||
458 | /* if added/removed, update timestamps on the parent */ | ||
459 | if (acxt->cnt) | ||
460 | inode->i_ctime = inode->i_mtime = CURRENT_TIME; | ||
461 | |||
462 | mutex_unlock(&inode->i_mutex); | ||
463 | iput(inode); | ||
464 | } | ||
465 | |||
466 | /* kill removed sysfs_dirents */ | ||
467 | while (acxt->removed) { | ||
468 | struct sysfs_dirent *sd = acxt->removed; | ||
469 | |||
470 | acxt->removed = sd->s_sibling; | ||
471 | sd->s_sibling = NULL; | ||
472 | |||
473 | sysfs_drop_dentry(sd); | ||
474 | sysfs_deactivate(sd); | ||
475 | sysfs_put(sd); | ||
341 | } | 476 | } |
477 | |||
478 | return acxt->cnt; | ||
342 | } | 479 | } |
343 | 480 | ||
344 | /** | 481 | /** |
@@ -396,19 +533,20 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, | |||
396 | const char *name, struct sysfs_dirent **p_sd) | 533 | const char *name, struct sysfs_dirent **p_sd) |
397 | { | 534 | { |
398 | struct dentry *parent = parent_sd->s_dentry; | 535 | struct dentry *parent = parent_sd->s_dentry; |
536 | struct sysfs_addrm_cxt acxt; | ||
399 | int error; | 537 | int error; |
400 | umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; | 538 | umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; |
401 | struct dentry *dentry; | 539 | struct dentry *dentry; |
402 | struct inode *inode; | 540 | struct inode *inode; |
403 | struct sysfs_dirent *sd; | 541 | struct sysfs_dirent *sd; |
404 | 542 | ||
405 | mutex_lock(&parent->d_inode->i_mutex); | 543 | sysfs_addrm_start(&acxt, parent_sd); |
406 | 544 | ||
407 | /* allocate */ | 545 | /* allocate */ |
408 | dentry = lookup_one_len(name, parent, strlen(name)); | 546 | dentry = lookup_one_len(name, parent, strlen(name)); |
409 | if (IS_ERR(dentry)) { | 547 | if (IS_ERR(dentry)) { |
410 | error = PTR_ERR(dentry); | 548 | error = PTR_ERR(dentry); |
411 | goto out_unlock; | 549 | goto out_finish; |
412 | } | 550 | } |
413 | 551 | ||
414 | error = -EEXIST; | 552 | error = -EEXIST; |
@@ -433,23 +571,18 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, | |||
433 | } | 571 | } |
434 | 572 | ||
435 | /* link in */ | 573 | /* link in */ |
436 | mutex_lock(&sysfs_mutex); | ||
437 | |||
438 | error = -EEXIST; | 574 | error = -EEXIST; |
439 | if (sysfs_find_dirent(parent_sd, name)) { | 575 | if (sysfs_find_dirent(parent_sd, name)) |
440 | mutex_unlock(&sysfs_mutex); | ||
441 | goto out_iput; | 576 | goto out_iput; |
442 | } | ||
443 | 577 | ||
578 | sysfs_add_one(&acxt, sd); | ||
579 | sysfs_link_sibling(sd); | ||
444 | sysfs_instantiate(dentry, inode); | 580 | sysfs_instantiate(dentry, inode); |
445 | inc_nlink(parent->d_inode); | 581 | sysfs_attach_dentry(sd, dentry); |
446 | sysfs_attach_dirent(sd, parent_sd, dentry); | ||
447 | |||
448 | mutex_unlock(&sysfs_mutex); | ||
449 | 582 | ||
450 | *p_sd = sd; | 583 | *p_sd = sd; |
451 | error = 0; | 584 | error = 0; |
452 | goto out_unlock; /* pin directory dentry in core */ | 585 | goto out_finish; /* pin directory dentry in core */ |
453 | 586 | ||
454 | out_iput: | 587 | out_iput: |
455 | iput(inode); | 588 | iput(inode); |
@@ -459,8 +592,8 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, | |||
459 | d_drop(dentry); | 592 | d_drop(dentry); |
460 | out_dput: | 593 | out_dput: |
461 | dput(dentry); | 594 | dput(dentry); |
462 | out_unlock: | 595 | out_finish: |
463 | mutex_unlock(&parent->d_inode->i_mutex); | 596 | sysfs_addrm_finish(&acxt); |
464 | return error; | 597 | return error; |
465 | } | 598 | } |
466 | 599 | ||
@@ -561,16 +694,12 @@ const struct inode_operations sysfs_dir_inode_operations = { | |||
561 | 694 | ||
562 | static void remove_dir(struct sysfs_dirent *sd) | 695 | static void remove_dir(struct sysfs_dirent *sd) |
563 | { | 696 | { |
564 | mutex_lock(&sysfs_mutex); | 697 | struct sysfs_addrm_cxt acxt; |
565 | sysfs_unlink_sibling(sd); | ||
566 | sd->s_flags |= SYSFS_FLAG_REMOVED; | ||
567 | mutex_unlock(&sysfs_mutex); | ||
568 | 698 | ||
569 | pr_debug(" o %s removing done\n", sd->s_name); | 699 | sysfs_addrm_start(&acxt, sd->s_parent); |
570 | 700 | sysfs_unlink_sibling(sd); | |
571 | sysfs_drop_dentry(sd); | 701 | sysfs_remove_one(&acxt, sd); |
572 | sysfs_deactivate(sd); | 702 | sysfs_addrm_finish(&acxt); |
573 | sysfs_put(sd); | ||
574 | } | 703 | } |
575 | 704 | ||
576 | void sysfs_remove_subdir(struct sysfs_dirent *sd) | 705 | void sysfs_remove_subdir(struct sysfs_dirent *sd) |
@@ -581,38 +710,26 @@ void sysfs_remove_subdir(struct sysfs_dirent *sd) | |||
581 | 710 | ||
582 | static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) | 711 | static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) |
583 | { | 712 | { |
584 | struct sysfs_dirent *removed = NULL; | 713 | struct sysfs_addrm_cxt acxt; |
585 | struct sysfs_dirent **pos; | 714 | struct sysfs_dirent **pos; |
586 | 715 | ||
587 | if (!dir_sd) | 716 | if (!dir_sd) |
588 | return; | 717 | return; |
589 | 718 | ||
590 | pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); | 719 | pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); |
591 | mutex_lock(&sysfs_mutex); | 720 | sysfs_addrm_start(&acxt, dir_sd); |
592 | pos = &dir_sd->s_children; | 721 | pos = &dir_sd->s_children; |
593 | while (*pos) { | 722 | while (*pos) { |
594 | struct sysfs_dirent *sd = *pos; | 723 | struct sysfs_dirent *sd = *pos; |
595 | 724 | ||
596 | if (sysfs_type(sd) && (sysfs_type(sd) & SYSFS_NOT_PINNED)) { | 725 | if (sysfs_type(sd) && (sysfs_type(sd) & SYSFS_NOT_PINNED)) { |
597 | sd->s_flags |= SYSFS_FLAG_REMOVED; | ||
598 | *pos = sd->s_sibling; | 726 | *pos = sd->s_sibling; |
599 | sd->s_sibling = removed; | 727 | sd->s_sibling = NULL; |
600 | removed = sd; | 728 | sysfs_remove_one(&acxt, sd); |
601 | } else | 729 | } else |
602 | pos = &(*pos)->s_sibling; | 730 | pos = &(*pos)->s_sibling; |
603 | } | 731 | } |
604 | mutex_unlock(&sysfs_mutex); | 732 | sysfs_addrm_finish(&acxt); |
605 | |||
606 | while (removed) { | ||
607 | struct sysfs_dirent *sd = removed; | ||
608 | |||
609 | removed = sd->s_sibling; | ||
610 | sd->s_sibling = NULL; | ||
611 | |||
612 | sysfs_drop_dentry(sd); | ||
613 | sysfs_deactivate(sd); | ||
614 | sysfs_put(sd); | ||
615 | } | ||
616 | 733 | ||
617 | remove_dir(dir_sd); | 734 | remove_dir(dir_sd); |
618 | } | 735 | } |
@@ -772,7 +889,8 @@ static int sysfs_dir_open(struct inode *inode, struct file *file) | |||
772 | sd = sysfs_new_dirent("_DIR_", 0, 0); | 889 | sd = sysfs_new_dirent("_DIR_", 0, 0); |
773 | if (sd) { | 890 | if (sd) { |
774 | mutex_lock(&sysfs_mutex); | 891 | mutex_lock(&sysfs_mutex); |
775 | sysfs_attach_dirent(sd, parent_sd, NULL); | 892 | sd->s_parent = sysfs_get(parent_sd); |
893 | sysfs_link_sibling(sd); | ||
776 | mutex_unlock(&sysfs_mutex); | 894 | mutex_unlock(&sysfs_mutex); |
777 | } | 895 | } |
778 | 896 | ||
@@ -957,6 +1075,7 @@ struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj) | |||
957 | struct sysfs_dirent *parent_sd = parent->d_fsdata; | 1075 | struct sysfs_dirent *parent_sd = parent->d_fsdata; |
958 | struct dentry *shadow; | 1076 | struct dentry *shadow; |
959 | struct sysfs_dirent *sd; | 1077 | struct sysfs_dirent *sd; |
1078 | struct sysfs_addrm_cxt acxt; | ||
960 | 1079 | ||
961 | sd = ERR_PTR(-EINVAL); | 1080 | sd = ERR_PTR(-EINVAL); |
962 | if (!sysfs_is_shadowed_inode(inode)) | 1081 | if (!sysfs_is_shadowed_inode(inode)) |
@@ -970,15 +1089,18 @@ struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj) | |||
970 | if (!sd) | 1089 | if (!sd) |
971 | goto nomem; | 1090 | goto nomem; |
972 | sd->s_elem.dir.kobj = kobj; | 1091 | sd->s_elem.dir.kobj = kobj; |
973 | /* point to parent_sd but don't attach to it */ | ||
974 | sd->s_parent = sysfs_get(parent_sd); | ||
975 | mutex_lock(&sysfs_mutex); | ||
976 | sysfs_attach_dirent(sd, NULL, shadow); | ||
977 | mutex_unlock(&sysfs_mutex); | ||
978 | 1092 | ||
1093 | sysfs_addrm_start(&acxt, parent_sd); | ||
1094 | |||
1095 | /* add but don't link into children list */ | ||
1096 | sysfs_add_one(&acxt, sd); | ||
1097 | |||
1098 | /* attach and instantiate dentry */ | ||
1099 | sysfs_attach_dentry(sd, shadow); | ||
979 | d_instantiate(shadow, igrab(inode)); | 1100 | d_instantiate(shadow, igrab(inode)); |
980 | inc_nlink(inode); | 1101 | inc_nlink(inode); /* tj: synchronization? */ |
981 | inc_nlink(parent->d_inode); | 1102 | |
1103 | sysfs_addrm_finish(&acxt); | ||
982 | 1104 | ||
983 | dget(shadow); /* Extra count - pin the dentry in core */ | 1105 | dget(shadow); /* Extra count - pin the dentry in core */ |
984 | 1106 | ||
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index d0deed3e60b5..69bacf1db596 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
@@ -416,6 +416,7 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, | |||
416 | int type) | 416 | int type) |
417 | { | 417 | { |
418 | umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; | 418 | umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; |
419 | struct sysfs_addrm_cxt acxt; | ||
419 | struct sysfs_dirent *sd; | 420 | struct sysfs_dirent *sd; |
420 | 421 | ||
421 | sd = sysfs_new_dirent(attr->name, mode, type); | 422 | sd = sysfs_new_dirent(attr->name, mode, type); |
@@ -423,20 +424,18 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, | |||
423 | return -ENOMEM; | 424 | return -ENOMEM; |
424 | sd->s_elem.attr.attr = (void *)attr; | 425 | sd->s_elem.attr.attr = (void *)attr; |
425 | 426 | ||
426 | mutex_lock(&sysfs_mutex); | 427 | sysfs_addrm_start(&acxt, dir_sd); |
427 | 428 | ||
428 | if (!sysfs_find_dirent(dir_sd, attr->name)) { | 429 | if (!sysfs_find_dirent(dir_sd, attr->name)) { |
429 | sysfs_attach_dirent(sd, dir_sd, NULL); | 430 | sysfs_add_one(&acxt, sd); |
430 | sd = NULL; | 431 | sysfs_link_sibling(sd); |
431 | } | 432 | } |
432 | 433 | ||
433 | mutex_unlock(&sysfs_mutex); | 434 | if (sysfs_addrm_finish(&acxt)) |
435 | return 0; | ||
434 | 436 | ||
435 | if (sd) { | 437 | sysfs_put(sd); |
436 | sysfs_put(sd); | 438 | return -EEXIST; |
437 | return -EEXIST; | ||
438 | } | ||
439 | return 0; | ||
440 | } | 439 | } |
441 | 440 | ||
442 | 441 | ||
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index d439c0b4bfce..f95966847a81 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
@@ -191,15 +191,9 @@ void sysfs_instantiate(struct dentry *dentry, struct inode *inode) | |||
191 | { | 191 | { |
192 | BUG_ON(!dentry || dentry->d_inode); | 192 | BUG_ON(!dentry || dentry->d_inode); |
193 | 193 | ||
194 | if (inode->i_state & I_NEW) { | 194 | if (inode->i_state & I_NEW) |
195 | unlock_new_inode(inode); | 195 | unlock_new_inode(inode); |
196 | 196 | ||
197 | if (dentry->d_parent && dentry->d_parent->d_inode) { | ||
198 | struct inode *p_inode = dentry->d_parent->d_inode; | ||
199 | p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | d_instantiate(dentry, inode); | 197 | d_instantiate(dentry, inode); |
204 | } | 198 | } |
205 | 199 | ||
@@ -220,7 +214,6 @@ void sysfs_instantiate(struct dentry *dentry, struct inode *inode) | |||
220 | void sysfs_drop_dentry(struct sysfs_dirent *sd) | 214 | void sysfs_drop_dentry(struct sysfs_dirent *sd) |
221 | { | 215 | { |
222 | struct dentry *dentry = NULL; | 216 | struct dentry *dentry = NULL; |
223 | struct timespec curtime; | ||
224 | struct inode *inode; | 217 | struct inode *inode; |
225 | 218 | ||
226 | /* We're not holding a reference to ->s_dentry dentry but the | 219 | /* We're not holding a reference to ->s_dentry dentry but the |
@@ -246,13 +239,11 @@ void sysfs_drop_dentry(struct sysfs_dirent *sd) | |||
246 | dput(dentry); | 239 | dput(dentry); |
247 | 240 | ||
248 | /* adjust nlink and update timestamp */ | 241 | /* adjust nlink and update timestamp */ |
249 | curtime = CURRENT_TIME; | ||
250 | |||
251 | inode = ilookup(sysfs_sb, sd->s_ino); | 242 | inode = ilookup(sysfs_sb, sd->s_ino); |
252 | if (inode) { | 243 | if (inode) { |
253 | mutex_lock(&inode->i_mutex); | 244 | mutex_lock(&inode->i_mutex); |
254 | 245 | ||
255 | inode->i_ctime = curtime; | 246 | inode->i_ctime = CURRENT_TIME; |
256 | drop_nlink(inode); | 247 | drop_nlink(inode); |
257 | if (sysfs_type(sd) == SYSFS_DIR) | 248 | if (sysfs_type(sd) == SYSFS_DIR) |
258 | drop_nlink(inode); | 249 | drop_nlink(inode); |
@@ -260,30 +251,17 @@ void sysfs_drop_dentry(struct sysfs_dirent *sd) | |||
260 | mutex_unlock(&inode->i_mutex); | 251 | mutex_unlock(&inode->i_mutex); |
261 | iput(inode); | 252 | iput(inode); |
262 | } | 253 | } |
263 | |||
264 | /* adjust nlink and udpate timestamp of the parent */ | ||
265 | inode = ilookup(sysfs_sb, sd->s_parent->s_ino); | ||
266 | if (inode) { | ||
267 | mutex_lock(&inode->i_mutex); | ||
268 | |||
269 | inode->i_ctime = inode->i_mtime = curtime; | ||
270 | if (sysfs_type(sd) == SYSFS_DIR) | ||
271 | drop_nlink(inode); | ||
272 | |||
273 | mutex_unlock(&inode->i_mutex); | ||
274 | iput(inode); | ||
275 | } | ||
276 | } | 254 | } |
277 | 255 | ||
278 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) | 256 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) |
279 | { | 257 | { |
258 | struct sysfs_addrm_cxt acxt; | ||
280 | struct sysfs_dirent **pos, *sd; | 259 | struct sysfs_dirent **pos, *sd; |
281 | int found = 0; | ||
282 | 260 | ||
283 | if (!dir_sd) | 261 | if (!dir_sd) |
284 | return -ENOENT; | 262 | return -ENOENT; |
285 | 263 | ||
286 | mutex_lock(&sysfs_mutex); | 264 | sysfs_addrm_start(&acxt, dir_sd); |
287 | 265 | ||
288 | for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) { | 266 | for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) { |
289 | sd = *pos; | 267 | sd = *pos; |
@@ -291,22 +269,14 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) | |||
291 | if (!sysfs_type(sd)) | 269 | if (!sysfs_type(sd)) |
292 | continue; | 270 | continue; |
293 | if (!strcmp(sd->s_name, name)) { | 271 | if (!strcmp(sd->s_name, name)) { |
294 | sd->s_flags |= SYSFS_FLAG_REMOVED; | ||
295 | *pos = sd->s_sibling; | 272 | *pos = sd->s_sibling; |
296 | sd->s_sibling = NULL; | 273 | sd->s_sibling = NULL; |
297 | found = 1; | 274 | sysfs_remove_one(&acxt, sd); |
298 | break; | 275 | break; |
299 | } | 276 | } |
300 | } | 277 | } |
301 | 278 | ||
302 | mutex_unlock(&sysfs_mutex); | 279 | if (sysfs_addrm_finish(&acxt)) |
303 | 280 | return 0; | |
304 | if (!found) | 281 | return -ENOENT; |
305 | return -ENOENT; | ||
306 | |||
307 | sysfs_drop_dentry(sd); | ||
308 | sysfs_deactivate(sd); | ||
309 | sysfs_put(sd); | ||
310 | |||
311 | return 0; | ||
312 | } | 282 | } |
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 683316f0aa96..2f86e0422290 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
@@ -55,6 +55,7 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char | |||
55 | struct sysfs_dirent *parent_sd = NULL; | 55 | struct sysfs_dirent *parent_sd = NULL; |
56 | struct sysfs_dirent *target_sd = NULL; | 56 | struct sysfs_dirent *target_sd = NULL; |
57 | struct sysfs_dirent *sd = NULL; | 57 | struct sysfs_dirent *sd = NULL; |
58 | struct sysfs_addrm_cxt acxt; | ||
58 | int error; | 59 | int error; |
59 | 60 | ||
60 | BUG_ON(!name); | 61 | BUG_ON(!name); |
@@ -87,17 +88,18 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char | |||
87 | goto out_put; | 88 | goto out_put; |
88 | sd->s_elem.symlink.target_sd = target_sd; | 89 | sd->s_elem.symlink.target_sd = target_sd; |
89 | 90 | ||
90 | mutex_lock(&sysfs_mutex); | 91 | sysfs_addrm_start(&acxt, parent_sd); |
91 | error = -EEXIST; | ||
92 | if (sysfs_find_dirent(parent_sd, name)) | ||
93 | goto out_unlock; | ||
94 | sysfs_attach_dirent(sd, parent_sd, NULL); | ||
95 | mutex_unlock(&sysfs_mutex); | ||
96 | 92 | ||
97 | return 0; | 93 | if (!sysfs_find_dirent(parent_sd, name)) { |
94 | sysfs_add_one(&acxt, sd); | ||
95 | sysfs_link_sibling(sd); | ||
96 | } | ||
98 | 97 | ||
99 | out_unlock: | 98 | if (sysfs_addrm_finish(&acxt)) |
100 | mutex_unlock(&sysfs_mutex); | 99 | return 0; |
100 | |||
101 | error = -EEXIST; | ||
102 | /* fall through */ | ||
101 | out_put: | 103 | out_put: |
102 | sysfs_put(target_sd); | 104 | sysfs_put(target_sd); |
103 | sysfs_put(sd); | 105 | sysfs_put(sd); |
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 26051616ed11..3e9a5ee38233 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
@@ -44,14 +44,29 @@ struct sysfs_dirent { | |||
44 | 44 | ||
45 | #define SD_DEACTIVATED_BIAS INT_MIN | 45 | #define SD_DEACTIVATED_BIAS INT_MIN |
46 | 46 | ||
47 | struct sysfs_addrm_cxt { | ||
48 | struct sysfs_dirent *parent_sd; | ||
49 | struct inode *parent_inode; | ||
50 | struct sysfs_dirent *removed; | ||
51 | int cnt; | ||
52 | }; | ||
53 | |||
47 | extern struct vfsmount * sysfs_mount; | 54 | extern struct vfsmount * sysfs_mount; |
48 | extern struct kmem_cache *sysfs_dir_cachep; | 55 | extern struct kmem_cache *sysfs_dir_cachep; |
49 | 56 | ||
57 | extern void sysfs_link_sibling(struct sysfs_dirent *sd); | ||
58 | extern void sysfs_unlink_sibling(struct sysfs_dirent *sd); | ||
50 | extern struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd); | 59 | extern struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd); |
51 | extern void sysfs_put_active(struct sysfs_dirent *sd); | 60 | extern void sysfs_put_active(struct sysfs_dirent *sd); |
52 | extern struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd); | 61 | extern struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd); |
53 | extern void sysfs_put_active_two(struct sysfs_dirent *sd); | 62 | extern void sysfs_put_active_two(struct sysfs_dirent *sd); |
54 | extern void sysfs_deactivate(struct sysfs_dirent *sd); | 63 | extern void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, |
64 | struct sysfs_dirent *parent_sd); | ||
65 | extern void sysfs_add_one(struct sysfs_addrm_cxt *acxt, | ||
66 | struct sysfs_dirent *sd); | ||
67 | extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, | ||
68 | struct sysfs_dirent *sd); | ||
69 | extern int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); | ||
55 | 70 | ||
56 | extern void sysfs_delete_inode(struct inode *inode); | 71 | extern void sysfs_delete_inode(struct inode *inode); |
57 | extern void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode); | 72 | extern void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode); |
@@ -65,9 +80,6 @@ extern struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, | |||
65 | const unsigned char *name); | 80 | const unsigned char *name); |
66 | extern struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, | 81 | extern struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, |
67 | int type); | 82 | int type); |
68 | extern void sysfs_attach_dirent(struct sysfs_dirent *sd, | ||
69 | struct sysfs_dirent *parent_sd, | ||
70 | struct dentry *dentry); | ||
71 | 83 | ||
72 | extern int sysfs_add_file(struct sysfs_dirent *dir_sd, | 84 | extern int sysfs_add_file(struct sysfs_dirent *dir_sd, |
73 | const struct attribute *attr, int type); | 85 | const struct attribute *attr, int type); |