diff options
author | Tejun Heo <tj@kernel.org> | 2013-11-28 14:54:30 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-11-29 20:55:10 -0500 |
commit | ccf73cf336dc55bc52748205dee998d2fd4a8808 (patch) | |
tree | 8e3a3b9891e6b9d4804299cd23110c91d8f8016e /fs/sysfs/dir.c | |
parent | 517e64f57883bd63c5a4ab8b3d0d3ed68c55d0cf (diff) |
sysfs, kernfs: introduce kernfs[_find_and]_get() and kernfs_put()
Introduce kernfs interface for finding, getting and putting
sysfs_dirents.
* sysfs_find_dirent() is renamed to kernfs_find_ns() and lockdep
assertion for sysfs_mutex is added.
* sysfs_get_dirent_ns() is renamed to kernfs_find_and_get().
* Macro inline dancing around __sysfs_get/put() are removed and
kernfs_get/put() are made proper functions implemented in
fs/sysfs/dir.c.
While the conversions are mostly equivalent, there's one difference -
kernfs_get() doesn't return the input param as its return value. This
change is intentional. While passing through the input increases
writability in some areas, it is unnecessary and has been shown to
cause confusion regarding how the last ref is handled.
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/sysfs/dir.c')
-rw-r--r-- | fs/sysfs/dir.c | 117 |
1 files changed, 67 insertions, 50 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 8f2d577b5f64..0d806efcc9a6 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -240,10 +240,31 @@ static void sysfs_free_ino(unsigned int ino) | |||
240 | spin_unlock(&sysfs_ino_lock); | 240 | spin_unlock(&sysfs_ino_lock); |
241 | } | 241 | } |
242 | 242 | ||
243 | void release_sysfs_dirent(struct sysfs_dirent *sd) | 243 | /** |
244 | * kernfs_get - get a reference count on a sysfs_dirent | ||
245 | * @sd: the target sysfs_dirent | ||
246 | */ | ||
247 | void kernfs_get(struct sysfs_dirent *sd) | ||
248 | { | ||
249 | if (sd) { | ||
250 | WARN_ON(!atomic_read(&sd->s_count)); | ||
251 | atomic_inc(&sd->s_count); | ||
252 | } | ||
253 | } | ||
254 | EXPORT_SYMBOL_GPL(kernfs_get); | ||
255 | |||
256 | /** | ||
257 | * kernfs_put - put a reference count on a sysfs_dirent | ||
258 | * @sd: the target sysfs_dirent | ||
259 | * | ||
260 | * Put a reference count of @sd and destroy it if it reached zero. | ||
261 | */ | ||
262 | void kernfs_put(struct sysfs_dirent *sd) | ||
244 | { | 263 | { |
245 | struct sysfs_dirent *parent_sd; | 264 | struct sysfs_dirent *parent_sd; |
246 | 265 | ||
266 | if (!sd || !atomic_dec_and_test(&sd->s_count)) | ||
267 | return; | ||
247 | repeat: | 268 | repeat: |
248 | /* Moving/renaming is always done while holding reference. | 269 | /* Moving/renaming is always done while holding reference. |
249 | * sd->s_parent won't change beneath us. | 270 | * sd->s_parent won't change beneath us. |
@@ -255,7 +276,7 @@ void release_sysfs_dirent(struct sysfs_dirent *sd) | |||
255 | parent_sd ? parent_sd->s_name : "", sd->s_name); | 276 | parent_sd ? parent_sd->s_name : "", sd->s_name); |
256 | 277 | ||
257 | if (sysfs_type(sd) == SYSFS_KOBJ_LINK) | 278 | if (sysfs_type(sd) == SYSFS_KOBJ_LINK) |
258 | sysfs_put(sd->s_symlink.target_sd); | 279 | kernfs_put(sd->s_symlink.target_sd); |
259 | if (sysfs_type(sd) & SYSFS_COPY_NAME) | 280 | if (sysfs_type(sd) & SYSFS_COPY_NAME) |
260 | kfree(sd->s_name); | 281 | kfree(sd->s_name); |
261 | if (sd->s_iattr && sd->s_iattr->ia_secdata) | 282 | if (sd->s_iattr && sd->s_iattr->ia_secdata) |
@@ -269,6 +290,7 @@ void release_sysfs_dirent(struct sysfs_dirent *sd) | |||
269 | if (sd && atomic_dec_and_test(&sd->s_count)) | 290 | if (sd && atomic_dec_and_test(&sd->s_count)) |
270 | goto repeat; | 291 | goto repeat; |
271 | } | 292 | } |
293 | EXPORT_SYMBOL_GPL(kernfs_put); | ||
272 | 294 | ||
273 | static int sysfs_dentry_delete(const struct dentry *dentry) | 295 | static int sysfs_dentry_delete(const struct dentry *dentry) |
274 | { | 296 | { |
@@ -331,7 +353,7 @@ out_bad: | |||
331 | 353 | ||
332 | static void sysfs_dentry_release(struct dentry *dentry) | 354 | static void sysfs_dentry_release(struct dentry *dentry) |
333 | { | 355 | { |
334 | sysfs_put(dentry->d_fsdata); | 356 | kernfs_put(dentry->d_fsdata); |
335 | } | 357 | } |
336 | 358 | ||
337 | const struct dentry_operations sysfs_dentry_ops = { | 359 | const struct dentry_operations sysfs_dentry_ops = { |
@@ -433,7 +455,8 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd, | |||
433 | return -EINVAL; | 455 | return -EINVAL; |
434 | 456 | ||
435 | sd->s_hash = sysfs_name_hash(sd->s_name, sd->s_ns); | 457 | sd->s_hash = sysfs_name_hash(sd->s_name, sd->s_ns); |
436 | sd->s_parent = sysfs_get(parent_sd); | 458 | sd->s_parent = parent_sd; |
459 | kernfs_get(parent_sd); | ||
437 | 460 | ||
438 | ret = sysfs_link_sibling(sd); | 461 | ret = sysfs_link_sibling(sd); |
439 | if (ret) | 462 | if (ret) |
@@ -553,36 +576,33 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | |||
553 | 576 | ||
554 | sysfs_deactivate(sd); | 577 | sysfs_deactivate(sd); |
555 | sysfs_unmap_bin_file(sd); | 578 | sysfs_unmap_bin_file(sd); |
556 | sysfs_put(sd); | 579 | kernfs_put(sd); |
557 | } | 580 | } |
558 | } | 581 | } |
559 | 582 | ||
560 | /** | 583 | /** |
561 | * sysfs_find_dirent - find sysfs_dirent with the given name | 584 | * kernfs_find_ns - find sysfs_dirent with the given name |
562 | * @parent_sd: sysfs_dirent to search under | 585 | * @parent: sysfs_dirent to search under |
563 | * @name: name to look for | 586 | * @name: name to look for |
564 | * @ns: the namespace tag to use | 587 | * @ns: the namespace tag to use |
565 | * | ||
566 | * Look for sysfs_dirent with name @name under @parent_sd. | ||
567 | * | ||
568 | * LOCKING: | ||
569 | * mutex_lock(sysfs_mutex) | ||
570 | * | 588 | * |
571 | * RETURNS: | 589 | * Look for sysfs_dirent with name @name under @parent. Returns pointer to |
572 | * Pointer to sysfs_dirent if found, NULL if not. | 590 | * the found sysfs_dirent on success, %NULL on failure. |
573 | */ | 591 | */ |
574 | struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | 592 | static struct sysfs_dirent *kernfs_find_ns(struct sysfs_dirent *parent, |
575 | const unsigned char *name, | 593 | const unsigned char *name, |
576 | const void *ns) | 594 | const void *ns) |
577 | { | 595 | { |
578 | struct rb_node *node = parent_sd->s_dir.children.rb_node; | 596 | struct rb_node *node = parent->s_dir.children.rb_node; |
579 | bool has_ns = parent_sd->s_flags & SYSFS_FLAG_NS; | 597 | bool has_ns = parent->s_flags & SYSFS_FLAG_NS; |
580 | unsigned int hash; | 598 | unsigned int hash; |
581 | 599 | ||
600 | lockdep_assert_held(&sysfs_mutex); | ||
601 | |||
582 | if (has_ns != (bool)ns) { | 602 | if (has_ns != (bool)ns) { |
583 | WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", | 603 | WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", |
584 | has_ns ? "required" : "invalid", | 604 | has_ns ? "required" : "invalid", |
585 | parent_sd->s_name, name); | 605 | parent->s_name, name); |
586 | return NULL; | 606 | return NULL; |
587 | } | 607 | } |
588 | 608 | ||
@@ -604,34 +624,28 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | |||
604 | } | 624 | } |
605 | 625 | ||
606 | /** | 626 | /** |
607 | * sysfs_get_dirent_ns - find and get sysfs_dirent with the given name | 627 | * kernfs_find_and_get_ns - find and get sysfs_dirent with the given name |
608 | * @parent_sd: sysfs_dirent to search under | 628 | * @parent: sysfs_dirent to search under |
609 | * @name: name to look for | 629 | * @name: name to look for |
610 | * @ns: the namespace tag to use | 630 | * @ns: the namespace tag to use |
611 | * | ||
612 | * Look for sysfs_dirent with name @name under @parent_sd and get | ||
613 | * it if found. | ||
614 | * | ||
615 | * LOCKING: | ||
616 | * Kernel thread context (may sleep). Grabs sysfs_mutex. | ||
617 | * | 631 | * |
618 | * RETURNS: | 632 | * Look for sysfs_dirent with name @name under @parent and get a reference |
619 | * Pointer to sysfs_dirent if found, NULL if not. | 633 | * if found. This function may sleep and returns pointer to the found |
634 | * sysfs_dirent on success, %NULL on failure. | ||
620 | */ | 635 | */ |
621 | struct sysfs_dirent *sysfs_get_dirent_ns(struct sysfs_dirent *parent_sd, | 636 | struct sysfs_dirent *kernfs_find_and_get_ns(struct sysfs_dirent *parent, |
622 | const unsigned char *name, | 637 | const char *name, const void *ns) |
623 | const void *ns) | ||
624 | { | 638 | { |
625 | struct sysfs_dirent *sd; | 639 | struct sysfs_dirent *sd; |
626 | 640 | ||
627 | mutex_lock(&sysfs_mutex); | 641 | mutex_lock(&sysfs_mutex); |
628 | sd = sysfs_find_dirent(parent_sd, name, ns); | 642 | sd = kernfs_find_ns(parent, name, ns); |
629 | sysfs_get(sd); | 643 | kernfs_get(sd); |
630 | mutex_unlock(&sysfs_mutex); | 644 | mutex_unlock(&sysfs_mutex); |
631 | 645 | ||
632 | return sd; | 646 | return sd; |
633 | } | 647 | } |
634 | EXPORT_SYMBOL_GPL(sysfs_get_dirent_ns); | 648 | EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns); |
635 | 649 | ||
636 | /** | 650 | /** |
637 | * kernfs_create_dir_ns - create a directory | 651 | * kernfs_create_dir_ns - create a directory |
@@ -667,7 +681,7 @@ struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, | |||
667 | if (!rc) | 681 | if (!rc) |
668 | return sd; | 682 | return sd; |
669 | 683 | ||
670 | sysfs_put(sd); | 684 | kernfs_put(sd); |
671 | return ERR_PTR(rc); | 685 | return ERR_PTR(rc); |
672 | } | 686 | } |
673 | 687 | ||
@@ -716,14 +730,15 @@ static struct dentry *sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
716 | if (parent_sd->s_flags & SYSFS_FLAG_NS) | 730 | if (parent_sd->s_flags & SYSFS_FLAG_NS) |
717 | ns = sysfs_info(dir->i_sb)->ns; | 731 | ns = sysfs_info(dir->i_sb)->ns; |
718 | 732 | ||
719 | sd = sysfs_find_dirent(parent_sd, dentry->d_name.name, ns); | 733 | sd = kernfs_find_ns(parent_sd, dentry->d_name.name, ns); |
720 | 734 | ||
721 | /* no such entry */ | 735 | /* no such entry */ |
722 | if (!sd) { | 736 | if (!sd) { |
723 | ret = ERR_PTR(-ENOENT); | 737 | ret = ERR_PTR(-ENOENT); |
724 | goto out_unlock; | 738 | goto out_unlock; |
725 | } | 739 | } |
726 | dentry->d_fsdata = sysfs_get(sd); | 740 | kernfs_get(sd); |
741 | dentry->d_fsdata = sd; | ||
727 | 742 | ||
728 | /* attach dentry and inode */ | 743 | /* attach dentry and inode */ |
729 | inode = sysfs_get_inode(dir->i_sb, sd); | 744 | inode = sysfs_get_inode(dir->i_sb, sd); |
@@ -859,7 +874,7 @@ int kernfs_remove_by_name_ns(struct sysfs_dirent *dir_sd, const char *name, | |||
859 | 874 | ||
860 | sysfs_addrm_start(&acxt); | 875 | sysfs_addrm_start(&acxt); |
861 | 876 | ||
862 | sd = sysfs_find_dirent(dir_sd, name, ns); | 877 | sd = kernfs_find_ns(dir_sd, name, ns); |
863 | if (sd) | 878 | if (sd) |
864 | __kernfs_remove(&acxt, sd); | 879 | __kernfs_remove(&acxt, sd); |
865 | 880 | ||
@@ -925,7 +940,7 @@ int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, | |||
925 | goto out; /* nothing to rename */ | 940 | goto out; /* nothing to rename */ |
926 | 941 | ||
927 | error = -EEXIST; | 942 | error = -EEXIST; |
928 | if (sysfs_find_dirent(new_parent, new_name, new_ns)) | 943 | if (kernfs_find_ns(new_parent, new_name, new_ns)) |
929 | goto out; | 944 | goto out; |
930 | 945 | ||
931 | /* rename sysfs_dirent */ | 946 | /* rename sysfs_dirent */ |
@@ -943,8 +958,8 @@ int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, | |||
943 | * Move to the appropriate place in the appropriate directories rbtree. | 958 | * Move to the appropriate place in the appropriate directories rbtree. |
944 | */ | 959 | */ |
945 | sysfs_unlink_sibling(sd); | 960 | sysfs_unlink_sibling(sd); |
946 | sysfs_get(new_parent); | 961 | kernfs_get(new_parent); |
947 | sysfs_put(sd->s_parent); | 962 | kernfs_put(sd->s_parent); |
948 | sd->s_ns = new_ns; | 963 | sd->s_ns = new_ns; |
949 | sd->s_hash = sysfs_name_hash(sd->s_name, sd->s_ns); | 964 | sd->s_hash = sysfs_name_hash(sd->s_name, sd->s_ns); |
950 | sd->s_parent = new_parent; | 965 | sd->s_parent = new_parent; |
@@ -1000,7 +1015,7 @@ static inline unsigned char dt_type(struct sysfs_dirent *sd) | |||
1000 | 1015 | ||
1001 | static int sysfs_dir_release(struct inode *inode, struct file *filp) | 1016 | static int sysfs_dir_release(struct inode *inode, struct file *filp) |
1002 | { | 1017 | { |
1003 | sysfs_put(filp->private_data); | 1018 | kernfs_put(filp->private_data); |
1004 | return 0; | 1019 | return 0; |
1005 | } | 1020 | } |
1006 | 1021 | ||
@@ -1011,7 +1026,7 @@ static struct sysfs_dirent *sysfs_dir_pos(const void *ns, | |||
1011 | int valid = !(pos->s_flags & SYSFS_FLAG_REMOVED) && | 1026 | int valid = !(pos->s_flags & SYSFS_FLAG_REMOVED) && |
1012 | pos->s_parent == parent_sd && | 1027 | pos->s_parent == parent_sd && |
1013 | hash == pos->s_hash; | 1028 | hash == pos->s_hash; |
1014 | sysfs_put(pos); | 1029 | kernfs_put(pos); |
1015 | if (!valid) | 1030 | if (!valid) |
1016 | pos = NULL; | 1031 | pos = NULL; |
1017 | } | 1032 | } |
@@ -1075,8 +1090,10 @@ static int sysfs_readdir(struct file *file, struct dir_context *ctx) | |||
1075 | unsigned int type = dt_type(pos); | 1090 | unsigned int type = dt_type(pos); |
1076 | int len = strlen(name); | 1091 | int len = strlen(name); |
1077 | ino_t ino = pos->s_ino; | 1092 | ino_t ino = pos->s_ino; |
1093 | |||
1078 | ctx->pos = pos->s_hash; | 1094 | ctx->pos = pos->s_hash; |
1079 | file->private_data = sysfs_get(pos); | 1095 | file->private_data = pos; |
1096 | kernfs_get(pos); | ||
1080 | 1097 | ||
1081 | mutex_unlock(&sysfs_mutex); | 1098 | mutex_unlock(&sysfs_mutex); |
1082 | if (!dir_emit(ctx, name, len, ino, type)) | 1099 | if (!dir_emit(ctx, name, len, ino, type)) |