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.rst 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. if (WARN_ON(!name || !parent))
  23. return -EINVAL;
  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. EXPORT_SYMBOL_GPL(sysfs_create_link_nowarn);
  95. /**
  96. * sysfs_delete_link - remove symlink in object's directory.
  97. * @kobj: object we're acting for.
  98. * @targ: object we're pointing to.
  99. * @name: name of the symlink to remove.
  100. *
  101. * Unlike sysfs_remove_link sysfs_delete_link has enough information
  102. * to successfully delete symlinks in tagged directories.
  103. */
  104. void sysfs_delete_link(struct kobject *kobj, struct kobject *targ,
  105. const char *name)
  106. {
  107. const void *ns = NULL;
  108. /*
  109. * We don't own @target and it may be removed at any time.
  110. * Synchronize using sysfs_symlink_target_lock. See
  111. * sysfs_remove_dir() for details.
  112. */
  113. spin_lock(&sysfs_symlink_target_lock);
  114. if (targ->sd && kernfs_ns_enabled(kobj->sd))
  115. ns = targ->sd->ns;
  116. spin_unlock(&sysfs_symlink_target_lock);
  117. kernfs_remove_by_name_ns(kobj->sd, name, ns);
  118. }
  119. /**
  120. * sysfs_remove_link - remove symlink in object's directory.
  121. * @kobj: object we're acting for.
  122. * @name: name of the symlink to remove.
  123. */
  124. void sysfs_remove_link(struct kobject *kobj, const char *name)
  125. {
  126. struct kernfs_node *parent = NULL;
  127. if (!kobj)
  128. parent = sysfs_root_kn;
  129. else
  130. parent = kobj->sd;
  131. kernfs_remove_by_name(parent, name);
  132. }
  133. EXPORT_SYMBOL_GPL(sysfs_remove_link);
  134. /**
  135. * sysfs_rename_link_ns - rename symlink in object's directory.
  136. * @kobj: object we're acting for.
  137. * @targ: object we're pointing to.
  138. * @old: previous name of the symlink.
  139. * @new: new name of the symlink.
  140. * @new_ns: new namespace of the symlink.
  141. *
  142. * A helper function for the common rename symlink idiom.
  143. */
  144. int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *targ,
  145. const char *old, const char *new, const void *new_ns)
  146. {
  147. struct kernfs_node *parent, *kn = NULL;
  148. const void *old_ns = NULL;
  149. int result;
  150. if (!kobj)
  151. parent = sysfs_root_kn;
  152. else
  153. parent = kobj->sd;
  154. if (targ->sd)
  155. old_ns = targ->sd->ns;
  156. result = -ENOENT;
  157. kn = kernfs_find_and_get_ns(parent, old, old_ns);
  158. if (!kn)
  159. goto out;
  160. result = -EINVAL;
  161. if (kernfs_type(kn) != KERNFS_LINK)
  162. goto out;
  163. if (kn->symlink.target_kn->priv != targ)
  164. goto out;
  165. result = kernfs_rename_ns(kn, parent, new, new_ns);
  166. out:
  167. kernfs_put(kn);
  168. return result;
  169. }
  170. EXPORT_SYMBOL_GPL(sysfs_rename_link_ns);