aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs/dir.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2013-11-28 14:54:30 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-11-29 20:55:10 -0500
commitccf73cf336dc55bc52748205dee998d2fd4a8808 (patch)
tree8e3a3b9891e6b9d4804299cd23110c91d8f8016e /fs/sysfs/dir.c
parent517e64f57883bd63c5a4ab8b3d0d3ed68c55d0cf (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.c117
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
243void 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 */
247void 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}
254EXPORT_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 */
262void 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}
293EXPORT_SYMBOL_GPL(kernfs_put);
272 294
273static int sysfs_dentry_delete(const struct dentry *dentry) 295static int sysfs_dentry_delete(const struct dentry *dentry)
274{ 296{
@@ -331,7 +353,7 @@ out_bad:
331 353
332static void sysfs_dentry_release(struct dentry *dentry) 354static 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
337const struct dentry_operations sysfs_dentry_ops = { 359const 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 */
574struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, 592static 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 */
621struct sysfs_dirent *sysfs_get_dirent_ns(struct sysfs_dirent *parent_sd, 636struct 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}
634EXPORT_SYMBOL_GPL(sysfs_get_dirent_ns); 648EXPORT_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
1001static int sysfs_dir_release(struct inode *inode, struct file *filp) 1016static 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))