mux.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. /*
  2. * linux/fs/9p/mux.c
  3. *
  4. * Protocol Multiplexer
  5. *
  6. * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
  7. * Copyright (C) 2004 by Latchesar Ionkov <lucho@ionkov.net>
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to:
  21. * Free Software Foundation
  22. * 51 Franklin Street, Fifth Floor
  23. * Boston, MA 02111-1301 USA
  24. *
  25. */
  26. #include <linux/config.h>
  27. #include <linux/module.h>
  28. #include <linux/errno.h>
  29. #include <linux/fs.h>
  30. #include <linux/kthread.h>
  31. #include <linux/idr.h>
  32. #include "debug.h"
  33. #include "v9fs.h"
  34. #include "9p.h"
  35. #include "transport.h"
  36. #include "conv.h"
  37. #include "mux.h"
  38. /**
  39. * dprintcond - print condition of session info
  40. * @v9ses: session info structure
  41. * @req: RPC request structure
  42. *
  43. */
  44. static inline int
  45. dprintcond(struct v9fs_session_info *v9ses, struct v9fs_rpcreq *req)
  46. {
  47. dprintk(DEBUG_MUX, "condition: %d, %p\n", v9ses->transport->status,
  48. req->rcall);
  49. return 0;
  50. }
  51. /**
  52. * xread - force read of a certain number of bytes
  53. * @v9ses: session info structure
  54. * @ptr: pointer to buffer
  55. * @sz: number of bytes to read
  56. *
  57. * Chuck Cranor CS-533 project1
  58. */
  59. static int xread(struct v9fs_session_info *v9ses, void *ptr, unsigned long sz)
  60. {
  61. int rd = 0;
  62. int ret = 0;
  63. while (rd < sz) {
  64. ret = v9ses->transport->read(v9ses->transport, ptr, sz - rd);
  65. if (ret <= 0) {
  66. dprintk(DEBUG_ERROR, "xread errno %d\n", ret);
  67. return ret;
  68. }
  69. rd += ret;
  70. ptr += ret;
  71. }
  72. return (rd);
  73. }
  74. /**
  75. * read_message - read a full 9P2000 fcall packet
  76. * @v9ses: session info structure
  77. * @rcall: fcall structure to read into
  78. * @rcalllen: size of fcall buffer
  79. *
  80. */
  81. static int
  82. read_message(struct v9fs_session_info *v9ses,
  83. struct v9fs_fcall *rcall, int rcalllen)
  84. {
  85. unsigned char buf[4];
  86. void *data;
  87. int size = 0;
  88. int res = 0;
  89. res = xread(v9ses, buf, sizeof(buf));
  90. if (res < 0) {
  91. dprintk(DEBUG_ERROR,
  92. "Reading of count field failed returned: %d\n", res);
  93. return res;
  94. }
  95. if (res < 4) {
  96. dprintk(DEBUG_ERROR,
  97. "Reading of count field failed returned: %d\n", res);
  98. return -EIO;
  99. }
  100. size = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
  101. dprintk(DEBUG_MUX, "got a packet count: %d\n", size);
  102. /* adjust for the four bytes of size */
  103. size -= 4;
  104. if (size > v9ses->maxdata) {
  105. dprintk(DEBUG_ERROR, "packet too big: %d\n", size);
  106. return -E2BIG;
  107. }
  108. data = kmalloc(size, GFP_KERNEL);
  109. if (!data) {
  110. eprintk(KERN_WARNING, "out of memory\n");
  111. return -ENOMEM;
  112. }
  113. res = xread(v9ses, data, size);
  114. if (res < size) {
  115. dprintk(DEBUG_ERROR, "Reading of fcall failed returned: %d\n",
  116. res);
  117. kfree(data);
  118. return res;
  119. }
  120. /* we now have an in-memory string that is the reply.
  121. * deserialize it. There is very little to go wrong at this point
  122. * save for v9fs_alloc errors.
  123. */
  124. res = v9fs_deserialize_fcall(v9ses, size, data, v9ses->maxdata,
  125. rcall, rcalllen);
  126. kfree(data);
  127. if (res < 0)
  128. return res;
  129. return 0;
  130. }
  131. /**
  132. * v9fs_recv - receive an RPC response for a particular tag
  133. * @v9ses: session info structure
  134. * @req: RPC request structure
  135. *
  136. */
  137. static int v9fs_recv(struct v9fs_session_info *v9ses, struct v9fs_rpcreq *req)
  138. {
  139. int ret = 0;
  140. dprintk(DEBUG_MUX, "waiting for response: %d\n", req->tcall->tag);
  141. ret = wait_event_interruptible(v9ses->read_wait,
  142. ((v9ses->transport->status != Connected) ||
  143. (req->rcall != 0) || (req->err < 0) ||
  144. dprintcond(v9ses, req)));
  145. dprintk(DEBUG_MUX, "got it: rcall %p\n", req->rcall);
  146. spin_lock(&v9ses->muxlock);
  147. list_del(&req->next);
  148. spin_unlock(&v9ses->muxlock);
  149. if (req->err < 0)
  150. return req->err;
  151. if (v9ses->transport->status == Disconnected)
  152. return -ECONNRESET;
  153. return ret;
  154. }
  155. /**
  156. * v9fs_send - send a 9P request
  157. * @v9ses: session info structure
  158. * @req: RPC request to send
  159. *
  160. */
  161. static int v9fs_send(struct v9fs_session_info *v9ses, struct v9fs_rpcreq *req)
  162. {
  163. int ret = -1;
  164. void *data = NULL;
  165. struct v9fs_fcall *tcall = req->tcall;
  166. data = kmalloc(v9ses->maxdata + V9FS_IOHDRSZ, GFP_KERNEL);
  167. if (!data)
  168. return -ENOMEM;
  169. tcall->size = 0; /* enforce size recalculation */
  170. ret =
  171. v9fs_serialize_fcall(v9ses, tcall, data,
  172. v9ses->maxdata + V9FS_IOHDRSZ);
  173. if (ret < 0)
  174. goto free_data;
  175. spin_lock(&v9ses->muxlock);
  176. list_add(&req->next, &v9ses->mux_fcalls);
  177. spin_unlock(&v9ses->muxlock);
  178. dprintk(DEBUG_MUX, "sending message: tag %d size %d\n", tcall->tag,
  179. tcall->size);
  180. ret = v9ses->transport->write(v9ses->transport, data, tcall->size);
  181. if (ret != tcall->size) {
  182. spin_lock(&v9ses->muxlock);
  183. list_del(&req->next);
  184. kfree(req->rcall);
  185. spin_unlock(&v9ses->muxlock);
  186. if (ret >= 0)
  187. ret = -EREMOTEIO;
  188. } else
  189. ret = 0;
  190. free_data:
  191. kfree(data);
  192. return ret;
  193. }
  194. /**
  195. * v9fs_mux_rpc - send a request, receive a response
  196. * @v9ses: session info structure
  197. * @tcall: fcall to send
  198. * @rcall: buffer to place response into
  199. *
  200. */
  201. long
  202. v9fs_mux_rpc(struct v9fs_session_info *v9ses, struct v9fs_fcall *tcall,
  203. struct v9fs_fcall **rcall)
  204. {
  205. int tid = -1;
  206. struct v9fs_fcall *fcall = NULL;
  207. struct v9fs_rpcreq req;
  208. int ret = -1;
  209. if (!v9ses)
  210. return -EINVAL;
  211. if (!v9ses->transport || v9ses->transport->status != Connected)
  212. return -EIO;
  213. if (rcall)
  214. *rcall = NULL;
  215. if (tcall->id != TVERSION) {
  216. tid = v9fs_get_idpool(&v9ses->tidpool);
  217. if (tid < 0)
  218. return -ENOMEM;
  219. }
  220. tcall->tag = tid;
  221. req.tcall = tcall;
  222. req.err = 0;
  223. req.rcall = NULL;
  224. ret = v9fs_send(v9ses, &req);
  225. if (ret < 0) {
  226. if (tcall->id != TVERSION)
  227. v9fs_put_idpool(tid, &v9ses->tidpool);
  228. dprintk(DEBUG_MUX, "error %d\n", ret);
  229. return ret;
  230. }
  231. ret = v9fs_recv(v9ses, &req);
  232. fcall = req.rcall;
  233. dprintk(DEBUG_MUX, "received: tag=%x, ret=%d\n", tcall->tag, ret);
  234. if (ret == -ERESTARTSYS) {
  235. if (v9ses->transport->status != Disconnected
  236. && tcall->id != TFLUSH) {
  237. unsigned long flags;
  238. dprintk(DEBUG_MUX, "flushing the tag: %d\n",
  239. tcall->tag);
  240. clear_thread_flag(TIF_SIGPENDING);
  241. v9fs_t_flush(v9ses, tcall->tag);
  242. spin_lock_irqsave(&current->sighand->siglock, flags);
  243. recalc_sigpending();
  244. spin_unlock_irqrestore(&current->sighand->siglock,
  245. flags);
  246. dprintk(DEBUG_MUX, "flushing done\n");
  247. }
  248. goto release_req;
  249. } else if (ret < 0)
  250. goto release_req;
  251. if (!fcall)
  252. ret = -EIO;
  253. else {
  254. if (fcall->id == RERROR) {
  255. ret = v9fs_errstr2errno(fcall->params.rerror.error);
  256. if (ret == 0) { /* string match failed */
  257. if (fcall->params.rerror.errno)
  258. ret = -(fcall->params.rerror.errno);
  259. else
  260. ret = -ESERVERFAULT;
  261. }
  262. } else if (fcall->id != tcall->id + 1) {
  263. dprintk(DEBUG_ERROR,
  264. "fcall mismatch: expected %d, got %d\n",
  265. tcall->id + 1, fcall->id);
  266. ret = -EIO;
  267. }
  268. }
  269. release_req:
  270. if (tcall->id != TVERSION)
  271. v9fs_put_idpool(tid, &v9ses->tidpool);
  272. if (rcall)
  273. *rcall = fcall;
  274. else
  275. kfree(fcall);
  276. return ret;
  277. }
  278. /**
  279. * v9fs_mux_cancel_requests - cancels all pending requests
  280. *
  281. * @v9ses: session info structure
  282. * @err: error code to return to the requests
  283. */
  284. void v9fs_mux_cancel_requests(struct v9fs_session_info *v9ses, int err)
  285. {
  286. struct v9fs_rpcreq *rptr;
  287. struct v9fs_rpcreq *rreq;
  288. dprintk(DEBUG_MUX, " %d\n", err);
  289. spin_lock(&v9ses->muxlock);
  290. list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) {
  291. rreq->err = err;
  292. }
  293. spin_unlock(&v9ses->muxlock);
  294. wake_up_all(&v9ses->read_wait);
  295. }
  296. /**
  297. * v9fs_recvproc - kproc to handle demultiplexing responses
  298. * @data: session info structure
  299. *
  300. */
  301. static int v9fs_recvproc(void *data)
  302. {
  303. struct v9fs_session_info *v9ses = (struct v9fs_session_info *)data;
  304. struct v9fs_fcall *rcall = NULL;
  305. struct v9fs_rpcreq *rptr;
  306. struct v9fs_rpcreq *req;
  307. struct v9fs_rpcreq *rreq;
  308. int err = 0;
  309. allow_signal(SIGKILL);
  310. set_current_state(TASK_INTERRUPTIBLE);
  311. complete(&v9ses->proccmpl);
  312. while (!kthread_should_stop() && err >= 0) {
  313. req = rptr = rreq = NULL;
  314. rcall = kmalloc(v9ses->maxdata + V9FS_IOHDRSZ, GFP_KERNEL);
  315. if (!rcall) {
  316. eprintk(KERN_ERR, "no memory for buffers\n");
  317. break;
  318. }
  319. err = read_message(v9ses, rcall, v9ses->maxdata + V9FS_IOHDRSZ);
  320. spin_lock(&v9ses->muxlock);
  321. if (err < 0) {
  322. list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) {
  323. rreq->err = err;
  324. }
  325. if(err != -ERESTARTSYS)
  326. eprintk(KERN_ERR,
  327. "Transport error while reading message %d\n", err);
  328. } else {
  329. list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) {
  330. if (rreq->tcall->tag == rcall->tag) {
  331. req = rreq;
  332. req->rcall = rcall;
  333. break;
  334. }
  335. }
  336. }
  337. if (req && (req->tcall->id == TFLUSH)) {
  338. struct v9fs_rpcreq *treq = NULL;
  339. list_for_each_entry_safe(treq, rptr, &v9ses->mux_fcalls, next) {
  340. if (treq->tcall->tag ==
  341. req->tcall->params.tflush.oldtag) {
  342. list_del(&rptr->next);
  343. kfree(treq->rcall);
  344. break;
  345. }
  346. }
  347. }
  348. spin_unlock(&v9ses->muxlock);
  349. if (!req) {
  350. if (err >= 0)
  351. dprintk(DEBUG_ERROR,
  352. "unexpected response: id %d tag %d\n",
  353. rcall->id, rcall->tag);
  354. kfree(rcall);
  355. }
  356. wake_up_all(&v9ses->read_wait);
  357. set_current_state(TASK_INTERRUPTIBLE);
  358. }
  359. v9ses->transport->close(v9ses->transport);
  360. /* Inform all pending processes about the failure */
  361. wake_up_all(&v9ses->read_wait);
  362. if (signal_pending(current))
  363. complete(&v9ses->proccmpl);
  364. dprintk(DEBUG_MUX, "recvproc: end\n");
  365. v9ses->recvproc = NULL;
  366. return err >= 0;
  367. }
  368. /**
  369. * v9fs_mux_init - initialize multiplexer (spawn kproc)
  370. * @v9ses: session info structure
  371. * @dev_name: mount device information (to create unique kproc)
  372. *
  373. */
  374. int v9fs_mux_init(struct v9fs_session_info *v9ses, const char *dev_name)
  375. {
  376. char procname[60];
  377. strncpy(procname, dev_name, sizeof(procname));
  378. procname[sizeof(procname) - 1] = 0;
  379. init_waitqueue_head(&v9ses->read_wait);
  380. init_completion(&v9ses->fcread);
  381. init_completion(&v9ses->proccmpl);
  382. spin_lock_init(&v9ses->muxlock);
  383. INIT_LIST_HEAD(&v9ses->mux_fcalls);
  384. v9ses->recvproc = NULL;
  385. v9ses->curfcall = NULL;
  386. v9ses->recvproc = kthread_create(v9fs_recvproc, v9ses,
  387. "v9fs_recvproc %s", procname);
  388. if (IS_ERR(v9ses->recvproc)) {
  389. eprintk(KERN_ERR, "cannot create receiving thread\n");
  390. v9fs_session_close(v9ses);
  391. return -ECONNABORTED;
  392. }
  393. wake_up_process(v9ses->recvproc);
  394. wait_for_completion(&v9ses->proccmpl);
  395. return 0;
  396. }