symlink.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * fs/sysfs/symlink.c - sysfs symlink implementation
  4. *
  5. * Copyright (c) 2001-3 Patrick Mochel
  6. * Copyright (c) 2007 SUSE Linux Products GmbH
  7. * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
  8. *
  9. * Please see Documentation/filesystems/sysfs.txt for more information.
  10. */
  11. #include <linux/fs.h>
  12. #include <linux/module.h>
  13. #include <linux/kobject.h>
  14. #include <linux/mutex.h>
  15. #include <linux/security.h>
  16. #include "sysfs.h"
  17. static int sysfs_do_create_link_sd(struct kernfs_node *parent,
  18. struct kobject *target_kobj,
  19. const char *name, int warn)
  20. {
  21. struct kernfs_node *kn, *target = NULL;
  22. BUG_ON(!name || !parent);
  23. /*
  24. * We don't own @target_kobj and it may be removed at any time.
  25. * Synchronize using sysfs_symlink_target_lock. See
  26. * sysfs_remove_dir() for details.
  27. */
  28. spin_lock(&sysfs_symlink_target_lock);
  29. if (target_kobj->sd) {
  30. target = target_kobj->sd;
  31. kernfs_get(target);
  32. }
  33. spin_unlock(&sysfs_symlink_target_lock);
  34. if (!target)
  35. return -ENOENT;
  36. kn = kernfs_create_link(parent, name, target);
  37. kernfs_put(target);
  38. if (!IS_ERR(kn))
  39. return 0;
  40. if (warn && PTR_ERR(kn) == -EEXIST)
  41. sysfs_warn_dup(parent, name);
  42. return PTR_ERR(kn);
  43. }
  44. /**
  45. * sysfs_create_link_sd - create symlink to a given object.
  46. * @kn: directory we're creating the link in.
  47. * @target: object we're pointing to.
  48. * @name: name of the symlink.
  49. */
  50. int sysfs_create_link_sd(struct kernfs_node *kn, struct kobject *target,
  51. const char *name)
  52. {
  53. return sysfs_do_create_link_sd(kn, target, name, 1);
  54. }
  55. static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,
  56. const char *name, int warn)
  57. {
  58. struct kernfs_node *parent = NULL;
  59. if (!kobj)
  60. parent = sysfs_root_kn;
  61. else
  62. parent = kobj->sd;
  63. if (!parent)
  64. return -EFAULT;
  65. return sysfs_do_create_link_sd(parent, target, name, warn);
  66. }
  67. /**
  68. * sysfs_create_link - create symlink between two objects.
  69. * @kobj: object whose directory we're creating the link in.
  70. * @target: object we're pointing to.
  71. * @name: name of the symlink.
  72. */
  73. int sysfs_create_link(struct kobject *kobj, struct kobject *target,
  74. const char *name)
  75. {
  76. return sysfs_do_create_link(kobj, target, name, 1);
  77. }
  78. EXPORT_SYMBOL_GPL(sysfs_create_link);
  79. /**
  80. * sysfs_create_link_nowarn - create symlink between two objects.
  81. * @kobj: object whose directory we're creating the link in.
  82. * @target: object we're pointing to.
  83. * @name: name of the symlink.
  84. *
  85. * This function does the same as sysfs_create_link(), but it
  86. * doesn't warn if the link already exists.
  87. */
  88. int sysfs_create_link_nowarn(struct kobject *kobj, struct kobject *target,
  89. const char *name)
  90. {
  91. return sysfs_do_create_link(kobj, target, name, 0);
  92. }
  93. EXPORT_SYMBOL_GPL(sysfs_create_link_nowarn);
  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);