scif_fd.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /*
  2. * Intel MIC Platform Software Stack (MPSS)
  3. *
  4. * Copyright(c) 2014 Intel Corporation.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License, version 2, as
  8. * published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * General Public License for more details.
  14. *
  15. * Intel SCIF driver.
  16. *
  17. */
  18. #include "scif_main.h"
  19. static int scif_fdopen(struct inode *inode, struct file *f)
  20. {
  21. struct scif_endpt *priv = scif_open();
  22. if (!priv)
  23. return -ENOMEM;
  24. f->private_data = priv;
  25. return 0;
  26. }
  27. static int scif_fdclose(struct inode *inode, struct file *f)
  28. {
  29. struct scif_endpt *priv = f->private_data;
  30. return scif_close(priv);
  31. }
  32. static int scif_fdflush(struct file *f, fl_owner_t id)
  33. {
  34. struct scif_endpt *ep = f->private_data;
  35. spin_lock(&ep->lock);
  36. /*
  37. * The listening endpoint stashes the open file information before
  38. * waiting for incoming connections. The release callback would never be
  39. * called if the application closed the endpoint, while waiting for
  40. * incoming connections from a separate thread since the file descriptor
  41. * reference count is bumped up in the accept IOCTL. Call the flush
  42. * routine if the id matches the endpoint open file information so that
  43. * the listening endpoint can be woken up and the fd released.
  44. */
  45. if (ep->files == id)
  46. __scif_flush(ep);
  47. spin_unlock(&ep->lock);
  48. return 0;
  49. }
  50. static __always_inline void scif_err_debug(int err, const char *str)
  51. {
  52. /*
  53. * ENOTCONN is a common uninteresting error which is
  54. * flooding debug messages to the console unnecessarily.
  55. */
  56. if (err < 0 && err != -ENOTCONN)
  57. dev_dbg(scif_info.mdev.this_device, "%s err %d\n", str, err);
  58. }
  59. static long scif_fdioctl(struct file *f, unsigned int cmd, unsigned long arg)
  60. {
  61. struct scif_endpt *priv = f->private_data;
  62. void __user *argp = (void __user *)arg;
  63. int err = 0;
  64. struct scifioctl_msg request;
  65. bool non_block = false;
  66. non_block = !!(f->f_flags & O_NONBLOCK);
  67. switch (cmd) {
  68. case SCIF_BIND:
  69. {
  70. int pn;
  71. if (copy_from_user(&pn, argp, sizeof(pn)))
  72. return -EFAULT;
  73. pn = scif_bind(priv, pn);
  74. if (pn < 0)
  75. return pn;
  76. if (copy_to_user(argp, &pn, sizeof(pn)))
  77. return -EFAULT;
  78. return 0;
  79. }
  80. case SCIF_LISTEN:
  81. return scif_listen(priv, arg);
  82. case SCIF_CONNECT:
  83. {
  84. struct scifioctl_connect req;
  85. struct scif_endpt *ep = (struct scif_endpt *)priv;
  86. if (copy_from_user(&req, argp, sizeof(req)))
  87. return -EFAULT;
  88. err = __scif_connect(priv, &req.peer, non_block);
  89. if (err < 0)
  90. return err;
  91. req.self.node = ep->port.node;
  92. req.self.port = ep->port.port;
  93. if (copy_to_user(argp, &req, sizeof(req)))
  94. return -EFAULT;
  95. return 0;
  96. }
  97. /*
  98. * Accept is done in two halves. The request ioctl does the basic
  99. * functionality of accepting the request and returning the information
  100. * about it including the internal ID of the end point. The register
  101. * is done with the internal ID on a new file descriptor opened by the
  102. * requesting process.
  103. */
  104. case SCIF_ACCEPTREQ:
  105. {
  106. struct scifioctl_accept request;
  107. scif_epd_t *ep = (scif_epd_t *)&request.endpt;
  108. if (copy_from_user(&request, argp, sizeof(request)))
  109. return -EFAULT;
  110. err = scif_accept(priv, &request.peer, ep, request.flags);
  111. if (err < 0)
  112. return err;
  113. if (copy_to_user(argp, &request, sizeof(request))) {
  114. scif_close(*ep);
  115. return -EFAULT;
  116. }
  117. /*
  118. * Add to the list of user mode eps where the second half
  119. * of the accept is not yet completed.
  120. */
  121. spin_lock(&scif_info.eplock);
  122. list_add_tail(&((*ep)->miacceptlist), &scif_info.uaccept);
  123. list_add_tail(&((*ep)->liacceptlist), &priv->li_accept);
  124. (*ep)->listenep = priv;
  125. priv->acceptcnt++;
  126. spin_unlock(&scif_info.eplock);
  127. return 0;
  128. }
  129. case SCIF_ACCEPTREG:
  130. {
  131. struct scif_endpt *priv = f->private_data;
  132. struct scif_endpt *newep;
  133. struct scif_endpt *lisep;
  134. struct scif_endpt *fep = NULL;
  135. struct scif_endpt *tmpep;
  136. struct list_head *pos, *tmpq;
  137. /* Finally replace the pointer to the accepted endpoint */
  138. if (copy_from_user(&newep, argp, sizeof(void *)))
  139. return -EFAULT;
  140. /* Remove form the user accept queue */
  141. spin_lock(&scif_info.eplock);
  142. list_for_each_safe(pos, tmpq, &scif_info.uaccept) {
  143. tmpep = list_entry(pos,
  144. struct scif_endpt, miacceptlist);
  145. if (tmpep == newep) {
  146. list_del(pos);
  147. fep = tmpep;
  148. break;
  149. }
  150. }
  151. if (!fep) {
  152. spin_unlock(&scif_info.eplock);
  153. return -ENOENT;
  154. }
  155. lisep = newep->listenep;
  156. list_for_each_safe(pos, tmpq, &lisep->li_accept) {
  157. tmpep = list_entry(pos,
  158. struct scif_endpt, liacceptlist);
  159. if (tmpep == newep) {
  160. list_del(pos);
  161. lisep->acceptcnt--;
  162. break;
  163. }
  164. }
  165. spin_unlock(&scif_info.eplock);
  166. /* Free the resources automatically created from the open. */
  167. scif_teardown_ep(priv);
  168. scif_add_epd_to_zombie_list(priv, !SCIF_EPLOCK_HELD);
  169. f->private_data = newep;
  170. return 0;
  171. }
  172. case SCIF_SEND:
  173. {
  174. struct scif_endpt *priv = f->private_data;
  175. if (copy_from_user(&request, argp,
  176. sizeof(struct scifioctl_msg))) {
  177. err = -EFAULT;
  178. goto send_err;
  179. }
  180. err = scif_user_send(priv, (void __user *)request.msg,
  181. request.len, request.flags);
  182. if (err < 0)
  183. goto send_err;
  184. if (copy_to_user(&
  185. ((struct scifioctl_msg __user *)argp)->out_len,
  186. &err, sizeof(err))) {
  187. err = -EFAULT;
  188. goto send_err;
  189. }
  190. err = 0;
  191. send_err:
  192. scif_err_debug(err, "scif_send");
  193. return err;
  194. }
  195. case SCIF_RECV:
  196. {
  197. struct scif_endpt *priv = f->private_data;
  198. if (copy_from_user(&request, argp,
  199. sizeof(struct scifioctl_msg))) {
  200. err = -EFAULT;
  201. goto recv_err;
  202. }
  203. err = scif_user_recv(priv, (void __user *)request.msg,
  204. request.len, request.flags);
  205. if (err < 0)
  206. goto recv_err;
  207. if (copy_to_user(&
  208. ((struct scifioctl_msg __user *)argp)->out_len,
  209. &err, sizeof(err))) {
  210. err = -EFAULT;
  211. goto recv_err;
  212. }
  213. err = 0;
  214. recv_err:
  215. scif_err_debug(err, "scif_recv");
  216. return err;
  217. }
  218. case SCIF_GET_NODEIDS:
  219. {
  220. struct scifioctl_node_ids node_ids;
  221. int entries;
  222. u16 *nodes;
  223. void __user *unodes, *uself;
  224. u16 self;
  225. if (copy_from_user(&node_ids, argp, sizeof(node_ids))) {
  226. err = -EFAULT;
  227. goto getnodes_err2;
  228. }
  229. entries = min_t(int, scif_info.maxid, node_ids.len);
  230. nodes = kmalloc_array(entries, sizeof(u16), GFP_KERNEL);
  231. if (entries && !nodes) {
  232. err = -ENOMEM;
  233. goto getnodes_err2;
  234. }
  235. node_ids.len = scif_get_node_ids(nodes, entries, &self);
  236. unodes = (void __user *)node_ids.nodes;
  237. if (copy_to_user(unodes, nodes, sizeof(u16) * entries)) {
  238. err = -EFAULT;
  239. goto getnodes_err1;
  240. }
  241. uself = (void __user *)node_ids.self;
  242. if (copy_to_user(uself, &self, sizeof(u16))) {
  243. err = -EFAULT;
  244. goto getnodes_err1;
  245. }
  246. if (copy_to_user(argp, &node_ids, sizeof(node_ids))) {
  247. err = -EFAULT;
  248. goto getnodes_err1;
  249. }
  250. getnodes_err1:
  251. kfree(nodes);
  252. getnodes_err2:
  253. return err;
  254. }
  255. }
  256. return -EINVAL;
  257. }
  258. const struct file_operations scif_fops = {
  259. .open = scif_fdopen,
  260. .release = scif_fdclose,
  261. .unlocked_ioctl = scif_fdioctl,
  262. .flush = scif_fdflush,
  263. .owner = THIS_MODULE,
  264. };