mdev_sysfs.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /*
  2. * File attributes for Mediated devices
  3. *
  4. * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
  5. * Author: Neo Jia <cjia@nvidia.com>
  6. * Kirti Wankhede <kwankhede@nvidia.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. */
  12. #include <linux/sysfs.h>
  13. #include <linux/ctype.h>
  14. #include <linux/device.h>
  15. #include <linux/slab.h>
  16. #include <linux/uuid.h>
  17. #include <linux/mdev.h>
  18. #include "mdev_private.h"
  19. /* Static functions */
  20. static ssize_t mdev_type_attr_show(struct kobject *kobj,
  21. struct attribute *__attr, char *buf)
  22. {
  23. struct mdev_type_attribute *attr = to_mdev_type_attr(__attr);
  24. struct mdev_type *type = to_mdev_type(kobj);
  25. ssize_t ret = -EIO;
  26. if (attr->show)
  27. ret = attr->show(kobj, type->parent->dev, buf);
  28. return ret;
  29. }
  30. static ssize_t mdev_type_attr_store(struct kobject *kobj,
  31. struct attribute *__attr,
  32. const char *buf, size_t count)
  33. {
  34. struct mdev_type_attribute *attr = to_mdev_type_attr(__attr);
  35. struct mdev_type *type = to_mdev_type(kobj);
  36. ssize_t ret = -EIO;
  37. if (attr->store)
  38. ret = attr->store(&type->kobj, type->parent->dev, buf, count);
  39. return ret;
  40. }
  41. static const struct sysfs_ops mdev_type_sysfs_ops = {
  42. .show = mdev_type_attr_show,
  43. .store = mdev_type_attr_store,
  44. };
  45. static ssize_t create_store(struct kobject *kobj, struct device *dev,
  46. const char *buf, size_t count)
  47. {
  48. char *str;
  49. uuid_le uuid;
  50. int ret;
  51. if ((count < UUID_STRING_LEN) || (count > UUID_STRING_LEN + 1))
  52. return -EINVAL;
  53. str = kstrndup(buf, count, GFP_KERNEL);
  54. if (!str)
  55. return -ENOMEM;
  56. ret = uuid_le_to_bin(str, &uuid);
  57. kfree(str);
  58. if (ret)
  59. return ret;
  60. ret = mdev_device_create(kobj, dev, uuid);
  61. if (ret)
  62. return ret;
  63. return count;
  64. }
  65. MDEV_TYPE_ATTR_WO(create);
  66. static void mdev_type_release(struct kobject *kobj)
  67. {
  68. struct mdev_type *type = to_mdev_type(kobj);
  69. pr_debug("Releasing group %s\n", kobj->name);
  70. kfree(type);
  71. }
  72. static struct kobj_type mdev_type_ktype = {
  73. .sysfs_ops = &mdev_type_sysfs_ops,
  74. .release = mdev_type_release,
  75. };
  76. struct mdev_type *add_mdev_supported_type(struct mdev_parent *parent,
  77. struct attribute_group *group)
  78. {
  79. struct mdev_type *type;
  80. int ret;
  81. if (!group->name) {
  82. pr_err("%s: Type name empty!\n", __func__);
  83. return ERR_PTR(-EINVAL);
  84. }
  85. type = kzalloc(sizeof(*type), GFP_KERNEL);
  86. if (!type)
  87. return ERR_PTR(-ENOMEM);
  88. type->kobj.kset = parent->mdev_types_kset;
  89. type->parent = parent;
  90. ret = kobject_init_and_add(&type->kobj, &mdev_type_ktype, NULL,
  91. "%s-%s", dev_driver_string(parent->dev),
  92. group->name);
  93. if (ret) {
  94. kobject_put(&type->kobj);
  95. return ERR_PTR(ret);
  96. }
  97. ret = sysfs_create_file(&type->kobj, &mdev_type_attr_create.attr);
  98. if (ret)
  99. goto attr_create_failed;
  100. type->devices_kobj = kobject_create_and_add("devices", &type->kobj);
  101. if (!type->devices_kobj) {
  102. ret = -ENOMEM;
  103. goto attr_devices_failed;
  104. }
  105. ret = sysfs_create_files(&type->kobj,
  106. (const struct attribute **)group->attrs);
  107. if (ret) {
  108. ret = -ENOMEM;
  109. goto attrs_failed;
  110. }
  111. type->group = group;
  112. return type;
  113. attrs_failed:
  114. kobject_put(type->devices_kobj);
  115. attr_devices_failed:
  116. sysfs_remove_file(&type->kobj, &mdev_type_attr_create.attr);
  117. attr_create_failed:
  118. kobject_del(&type->kobj);
  119. kobject_put(&type->kobj);
  120. return ERR_PTR(ret);
  121. }
  122. static void remove_mdev_supported_type(struct mdev_type *type)
  123. {
  124. sysfs_remove_files(&type->kobj,
  125. (const struct attribute **)type->group->attrs);
  126. kobject_put(type->devices_kobj);
  127. sysfs_remove_file(&type->kobj, &mdev_type_attr_create.attr);
  128. kobject_del(&type->kobj);
  129. kobject_put(&type->kobj);
  130. }
  131. static int add_mdev_supported_type_groups(struct mdev_parent *parent)
  132. {
  133. int i;
  134. for (i = 0; parent->ops->supported_type_groups[i]; i++) {
  135. struct mdev_type *type;
  136. type = add_mdev_supported_type(parent,
  137. parent->ops->supported_type_groups[i]);
  138. if (IS_ERR(type)) {
  139. struct mdev_type *ltype, *tmp;
  140. list_for_each_entry_safe(ltype, tmp, &parent->type_list,
  141. next) {
  142. list_del(&ltype->next);
  143. remove_mdev_supported_type(ltype);
  144. }
  145. return PTR_ERR(type);
  146. }
  147. list_add(&type->next, &parent->type_list);
  148. }
  149. return 0;
  150. }
  151. /* mdev sysfs functions */
  152. void parent_remove_sysfs_files(struct mdev_parent *parent)
  153. {
  154. struct mdev_type *type, *tmp;
  155. list_for_each_entry_safe(type, tmp, &parent->type_list, next) {
  156. list_del(&type->next);
  157. remove_mdev_supported_type(type);
  158. }
  159. sysfs_remove_groups(&parent->dev->kobj, parent->ops->dev_attr_groups);
  160. kset_unregister(parent->mdev_types_kset);
  161. }
  162. int parent_create_sysfs_files(struct mdev_parent *parent)
  163. {
  164. int ret;
  165. parent->mdev_types_kset = kset_create_and_add("mdev_supported_types",
  166. NULL, &parent->dev->kobj);
  167. if (!parent->mdev_types_kset)
  168. return -ENOMEM;
  169. INIT_LIST_HEAD(&parent->type_list);
  170. ret = sysfs_create_groups(&parent->dev->kobj,
  171. parent->ops->dev_attr_groups);
  172. if (ret)
  173. goto create_err;
  174. ret = add_mdev_supported_type_groups(parent);
  175. if (ret)
  176. sysfs_remove_groups(&parent->dev->kobj,
  177. parent->ops->dev_attr_groups);
  178. else
  179. return ret;
  180. create_err:
  181. kset_unregister(parent->mdev_types_kset);
  182. return ret;
  183. }
  184. static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
  185. const char *buf, size_t count)
  186. {
  187. unsigned long val;
  188. if (kstrtoul(buf, 0, &val) < 0)
  189. return -EINVAL;
  190. if (val && device_remove_file_self(dev, attr)) {
  191. int ret;
  192. ret = mdev_device_remove(dev, false);
  193. if (ret) {
  194. device_create_file(dev, attr);
  195. return ret;
  196. }
  197. }
  198. return count;
  199. }
  200. static DEVICE_ATTR_WO(remove);
  201. static const struct attribute *mdev_device_attrs[] = {
  202. &dev_attr_remove.attr,
  203. NULL,
  204. };
  205. int mdev_create_sysfs_files(struct device *dev, struct mdev_type *type)
  206. {
  207. int ret;
  208. ret = sysfs_create_link(type->devices_kobj, &dev->kobj, dev_name(dev));
  209. if (ret)
  210. return ret;
  211. ret = sysfs_create_link(&dev->kobj, &type->kobj, "mdev_type");
  212. if (ret)
  213. goto type_link_failed;
  214. ret = sysfs_create_files(&dev->kobj, mdev_device_attrs);
  215. if (ret)
  216. goto create_files_failed;
  217. return ret;
  218. create_files_failed:
  219. sysfs_remove_link(&dev->kobj, "mdev_type");
  220. type_link_failed:
  221. sysfs_remove_link(type->devices_kobj, dev_name(dev));
  222. return ret;
  223. }
  224. void mdev_remove_sysfs_files(struct device *dev, struct mdev_type *type)
  225. {
  226. sysfs_remove_files(&dev->kobj, mdev_device_attrs);
  227. sysfs_remove_link(&dev->kobj, "mdev_type");
  228. sysfs_remove_link(type->devices_kobj, dev_name(dev));
  229. }