symlink.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. * fs/sysfs/symlink.c - sysfs symlink implementation
  3. *
  4. * Copyright (c) 2001-3 Patrick Mochel
  5. * Copyright (c) 2007 SUSE Linux Products GmbH
  6. * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
  7. *
  8. * This file is released under the GPLv2.
  9. *
  10. * Please see Documentation/filesystems/sysfs.txt for more information.
  11. */
  12. #include <linux/fs.h>
  13. #include <linux/module.h>
  14. #include <linux/kobject.h>
  15. #include <linux/mutex.h>
  16. #include <linux/security.h>
  17. #include "sysfs.h"
  18. static int sysfs_do_create_link_sd(struct kernfs_node *parent,
  19. struct kobject *target_kobj,
  20. const char *name, int warn)
  21. {
  22. struct kernfs_node *kn, *target = NULL;
  23. BUG_ON(!name || !parent);
  24. /*
  25. * We don't own @target_kobj and it may be removed at any time.
  26. * Synchronize using sysfs_symlink_target_lock. See
  27. * sysfs_remove_dir() for details.
  28. */
  29. spin_lock(&sysfs_symlink_target_lock);
  30. if (target_kobj->sd) {
  31. target = target_kobj->sd;
  32. kernfs_get(target);
  33. }
  34. spin_unlock(&sysfs_symlink_target_lock);
  35. if (!target)
  36. return -ENOENT;
  37. kn = kernfs_create_link(parent, name, target);
  38. kernfs_put(target);
  39. if (!IS_ERR(kn))
  40. return 0;
  41. if (warn && PTR_ERR(kn) == -EEXIST)
  42. sysfs_warn_dup(parent, name);
  43. return PTR_ERR(kn);
  44. }
  45. /**
  46. * sysfs_create_link_sd - create symlink to a given object.
  47. * @kn: directory we're creating the link in.
  48. * @target: object we're pointing to.
  49. * @name: name of the symlink.
  50. */
  51. int sysfs_create_link_sd(struct kernfs_node *kn, struct kobject *target,
  52. const char *name)
  53. {
  54. return sysfs_do_create_link_sd(kn, target, name, 1);
  55. }
  56. static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,
  57. const char *name, int warn)
  58. {
  59. struct kernfs_node *parent = NULL;
  60. if (!kobj)
  61. parent = sysfs_root_kn;
  62. else
  63. parent = kobj->sd;
  64. if (!parent)
  65. return -EFAULT;
  66. return sysfs_do_create_link_sd(parent, target, name, warn);
  67. }
  68. /**
  69. * sysfs_create_link - create symlink between two objects.
  70. * @kobj: object whose directory we're creating the link in.
  71. * @target: object we're pointing to.
  72. * @name: name of the symlink.
  73. */
  74. int sysfs_create_link(struct kobject *kobj, struct kobject *target,
  75. const char *name)
  76. {
  77. return sysfs_do_create_link(kobj, target, name, 1);
  78. }
  79. EXPORT_SYMBOL_GPL(sysfs_create_link);
  80. /**
  81. * sysfs_create_link_nowarn - create symlink between two objects.
  82. * @kobj: object whose directory we're creating the link in.
  83. * @target: object we're pointing to.
  84. * @name: name of the symlink.
  85. *
  86. * This function does the same as sysfs_create_link(), but it
  87. * doesn't warn if the link already exists.
  88. */
  89. int sysfs_create_link_nowarn(struct kobject *kobj, struct kobject *target,
  90. const char *name)
  91. {
  92. return sysfs_do_create_link(kobj, target, name, 0);
  93. }
  94. /**
  95. * sysfs_delete_link - remove symlink in object's directory.
  96. * @kobj: object we're acting for.
  97. * @targ: object we're pointing to.
  98. * @name: name of the symlink to remove.
  99. *
  100. * Unlike sysfs_remove_link sysfs_delete_link has enough information
  101. * to successfully delete symlinks in tagged directories.
  102. */
  103. void sysfs_delete_link(struct kobject *kobj, struct kobject *targ,
  104. const char *name)
  105. {
  106. const void *ns = NULL;
  107. /*
  108. * We don't own @target and it may be removed at any time.
  109. * Synchronize using sysfs_symlink_target_lock. See
  110. * sysfs_remove_dir() for details.
  111. */
  112. spin_lock(&sysfs_symlink_target_lock);
  113. if (targ->sd && kernfs_ns_enabled(kobj->sd))
  114. ns = targ->sd->ns;
  115. spin_unlock(&sysfs_symlink_target_lock);
  116. kernfs_remove_by_name_ns(kobj->sd, name, ns);
  117. }
  118. /**
  119. * sysfs_remove_link - remove symlink in object's directory.
  120. * @kobj: object we're acting for.
  121. * @name: name of the symlink to remove.
  122. */
  123. void sysfs_remove_link(struct kobject *kobj, const char *name)
  124. {
  125. struct kernfs_node *parent = NULL;
  126. if (!kobj)
  127. parent = sysfs_root_kn;
  128. else
  129. parent = kobj->sd;
  130. kernfs_remove_by_name(parent, name);
  131. }
  132. EXPORT_SYMBOL_GPL(sysfs_remove_link);
  133. /**
  134. * sysfs_rename_link_ns - rename symlink in object's directory.
  135. * @kobj: object we're acting for.
  136. * @targ: object we're pointing to.
  137. * @old: previous name of the symlink.
  138. * @new: new name of the symlink.
  139. * @new_ns: new namespace of the symlink.
  140. *
  141. * A helper function for the common rename symlink idiom.
  142. */
  143. int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *targ,
  144. const char *old, const char *new, const void *new_ns)
  145. {
  146. struct kernfs_node *parent, *kn = NULL;
  147. const void *old_ns = NULL;
  148. int result;
  149. if (!kobj)
  150. parent = sysfs_root_kn;
  151. else
  152. parent = kobj->sd;
  153. if (targ->sd)
  154. old_ns = targ->sd->ns;
  155. result = -ENOENT;
  156. kn = kernfs_find_and_get_ns(parent, old, old_ns);
  157. if (!kn)
  158. goto out;
  159. result = -EINVAL;
  160. if (kernfs_type(kn) != KERNFS_LINK)
  161. goto out;
  162. if (kn->symlink.target_kn->priv != targ)
  163. goto out;
  164. result = kernfs_rename_ns(kn, parent, new, new_ns);
  165. out:
  166. kernfs_put(kn);
  167. return result;
  168. }
  169. EXPORT_SYMBOL_GPL(sysfs_rename_link_ns);