6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2004 by Latchesar Ionkov <lucho@ionkov.net>
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.
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.
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
27 #include <linux/config.h>
28 #include <linux/module.h>
29 #include <linux/errno.h>
31 #include <linux/kthread.h>
32 #include <linux/idr.h>
37 #include "transport.h"
42 * dprintcond - print condition of session info
43 * @v9ses: session info structure
44 * @req: RPC request structure
49 dprintcond(struct v9fs_session_info
*v9ses
, struct v9fs_rpcreq
*req
)
51 dprintk(DEBUG_MUX
, "condition: %d, %p\n", v9ses
->transport
->status
,
57 * xread - force read of a certain number of bytes
58 * @v9ses: session info structure
59 * @ptr: pointer to buffer
60 * @sz: number of bytes to read
62 * Chuck Cranor CS-533 project1
65 static int xread(struct v9fs_session_info
*v9ses
, void *ptr
, unsigned long sz
)
70 ret
= v9ses
->transport
->read(v9ses
->transport
, ptr
, sz
- rd
);
72 dprintk(DEBUG_ERROR
, "xread errno %d\n", ret
);
82 * read_message - read a full 9P2000 fcall packet
83 * @v9ses: session info structure
84 * @rcall: fcall structure to read into
85 * @rcalllen: size of fcall buffer
90 read_message(struct v9fs_session_info
*v9ses
,
91 struct v9fs_fcall
*rcall
, int rcalllen
)
98 res
= xread(v9ses
, buf
, sizeof(buf
));
101 "Reading of count field failed returned: %d\n", res
);
107 "Reading of count field failed returned: %d\n", res
);
111 size
= buf
[0] | (buf
[1] << 8) | (buf
[2] << 16) | (buf
[3] << 24);
112 dprintk(DEBUG_MUX
, "got a packet count: %d\n", size
);
114 /* adjust for the four bytes of size */
117 if (size
> v9ses
->maxdata
) {
118 dprintk(DEBUG_ERROR
, "packet too big: %d\n", size
);
122 data
= kmalloc(size
, GFP_KERNEL
);
124 eprintk(KERN_WARNING
, "out of memory\n");
128 res
= xread(v9ses
, data
, size
);
130 dprintk(DEBUG_ERROR
, "Reading of fcall failed returned: %d\n",
136 /* we now have an in-memory string that is the reply.
137 * deserialize it. There is very little to go wrong at this point
138 * save for v9fs_alloc errors.
140 res
= v9fs_deserialize_fcall(v9ses
, size
, data
, v9ses
->maxdata
,
152 * v9fs_recv - receive an RPC response for a particular tag
153 * @v9ses: session info structure
154 * @req: RPC request structure
158 static int v9fs_recv(struct v9fs_session_info
*v9ses
, struct v9fs_rpcreq
*req
)
162 dprintk(DEBUG_MUX
, "waiting for response: %d\n", req
->tcall
->tag
);
163 ret
= wait_event_interruptible(v9ses
->read_wait
,
164 ((v9ses
->transport
->status
!= Connected
) ||
165 (req
->rcall
!= 0) || (req
->err
< 0) ||
166 dprintcond(v9ses
, req
)));
168 dprintk(DEBUG_MUX
, "got it: rcall %p\n", req
->rcall
);
170 spin_lock(&v9ses
->muxlock
);
171 list_del(&req
->next
);
172 spin_unlock(&v9ses
->muxlock
);
177 if (v9ses
->transport
->status
== Disconnected
)
184 * v9fs_send - send a 9P request
185 * @v9ses: session info structure
186 * @req: RPC request to send
190 static int v9fs_send(struct v9fs_session_info
*v9ses
, struct v9fs_rpcreq
*req
)
194 struct v9fs_fcall
*tcall
= req
->tcall
;
196 data
= kmalloc(v9ses
->maxdata
+ V9FS_IOHDRSZ
, GFP_KERNEL
);
200 tcall
->size
= 0; /* enforce size recalculation */
202 v9fs_serialize_fcall(v9ses
, tcall
, data
,
203 v9ses
->maxdata
+ V9FS_IOHDRSZ
);
207 spin_lock(&v9ses
->muxlock
);
208 list_add(&req
->next
, &v9ses
->mux_fcalls
);
209 spin_unlock(&v9ses
->muxlock
);
211 dprintk(DEBUG_MUX
, "sending message: tag %d size %d\n", tcall
->tag
,
213 ret
= v9ses
->transport
->write(v9ses
->transport
, data
, tcall
->size
);
215 if (ret
!= tcall
->size
) {
216 spin_lock(&v9ses
->muxlock
);
217 list_del(&req
->next
);
220 spin_unlock(&v9ses
->muxlock
);
232 * v9fs_mux_rpc - send a request, receive a response
233 * @v9ses: session info structure
234 * @tcall: fcall to send
235 * @rcall: buffer to place response into
240 v9fs_mux_rpc(struct v9fs_session_info
*v9ses
, struct v9fs_fcall
*tcall
,
241 struct v9fs_fcall
**rcall
)
244 struct v9fs_fcall
*fcall
= NULL
;
245 struct v9fs_rpcreq req
;
251 if (!v9ses
->transport
|| v9ses
->transport
->status
!= Connected
)
257 if (tcall
->id
!= TVERSION
) {
258 tid
= v9fs_get_idpool(&v9ses
->tidpool
);
269 ret
= v9fs_send(v9ses
, &req
);
272 if (tcall
->id
!= TVERSION
)
273 v9fs_put_idpool(tid
, &v9ses
->tidpool
);
274 dprintk(DEBUG_MUX
, "error %d\n", ret
);
278 ret
= v9fs_recv(v9ses
, &req
);
282 dprintk(DEBUG_MUX
, "received: tag=%x, ret=%d\n", tcall
->tag
, ret
);
283 if (ret
== -ERESTARTSYS
) {
284 if (v9ses
->transport
->status
!= Disconnected
285 && tcall
->id
!= TFLUSH
) {
288 dprintk(DEBUG_MUX
, "flushing the tag: %d\n",
290 clear_thread_flag(TIF_SIGPENDING
);
291 v9fs_t_flush(v9ses
, tcall
->tag
);
292 spin_lock_irqsave(¤t
->sighand
->siglock
, flags
);
294 spin_unlock_irqrestore(¤t
->sighand
->siglock
,
296 dprintk(DEBUG_MUX
, "flushing done\n");
306 if (fcall
->id
== RERROR
) {
307 ret
= v9fs_errstr2errno(fcall
->params
.rerror
.error
);
308 if (ret
== 0) { /* string match failed */
309 if (fcall
->params
.rerror
.errno
)
310 ret
= -(fcall
->params
.rerror
.errno
);
314 } else if (fcall
->id
!= tcall
->id
+ 1) {
316 "fcall mismatch: expected %d, got %d\n",
317 tcall
->id
+ 1, fcall
->id
);
323 if (tcall
->id
!= TVERSION
)
324 v9fs_put_idpool(tid
, &v9ses
->tidpool
);
334 * v9fs_mux_cancel_requests - cancels all pending requests
336 * @v9ses: session info structure
337 * @err: error code to return to the requests
339 void v9fs_mux_cancel_requests(struct v9fs_session_info
*v9ses
, int err
)
341 struct v9fs_rpcreq
*rptr
;
342 struct v9fs_rpcreq
*rreq
;
344 dprintk(DEBUG_MUX
, " %d\n", err
);
345 spin_lock(&v9ses
->muxlock
);
346 list_for_each_entry_safe(rreq
, rptr
, &v9ses
->mux_fcalls
, next
) {
349 spin_unlock(&v9ses
->muxlock
);
350 wake_up_all(&v9ses
->read_wait
);
354 * v9fs_recvproc - kproc to handle demultiplexing responses
355 * @data: session info structure
359 static int v9fs_recvproc(void *data
)
361 struct v9fs_session_info
*v9ses
= (struct v9fs_session_info
*)data
;
362 struct v9fs_fcall
*rcall
= NULL
;
363 struct v9fs_rpcreq
*rptr
;
364 struct v9fs_rpcreq
*req
;
365 struct v9fs_rpcreq
*rreq
;
368 allow_signal(SIGKILL
);
369 set_current_state(TASK_INTERRUPTIBLE
);
370 complete(&v9ses
->proccmpl
);
371 while (!kthread_should_stop() && err
>= 0) {
372 req
= rptr
= rreq
= NULL
;
374 rcall
= kmalloc(v9ses
->maxdata
+ V9FS_IOHDRSZ
, GFP_KERNEL
);
376 eprintk(KERN_ERR
, "no memory for buffers\n");
380 err
= read_message(v9ses
, rcall
, v9ses
->maxdata
+ V9FS_IOHDRSZ
);
381 spin_lock(&v9ses
->muxlock
);
383 list_for_each_entry_safe(rreq
, rptr
, &v9ses
->mux_fcalls
, next
) {
386 if(err
!= -ERESTARTSYS
)
388 "Transport error while reading message %d\n", err
);
390 list_for_each_entry_safe(rreq
, rptr
, &v9ses
->mux_fcalls
, next
) {
391 if (rreq
->tcall
->tag
== rcall
->tag
) {
399 if (req
&& (req
->tcall
->id
== TFLUSH
)) {
400 struct v9fs_rpcreq
*treq
= NULL
;
401 list_for_each_entry_safe(treq
, rptr
, &v9ses
->mux_fcalls
, next
) {
402 if (treq
->tcall
->tag
==
403 req
->tcall
->params
.tflush
.oldtag
) {
404 list_del(&rptr
->next
);
411 spin_unlock(&v9ses
->muxlock
);
416 "unexpected response: id %d tag %d\n",
417 rcall
->id
, rcall
->tag
);
422 wake_up_all(&v9ses
->read_wait
);
423 set_current_state(TASK_INTERRUPTIBLE
);
426 v9ses
->transport
->close(v9ses
->transport
);
428 /* Inform all pending processes about the failure */
429 wake_up_all(&v9ses
->read_wait
);
431 if (signal_pending(current
))
432 complete(&v9ses
->proccmpl
);
434 dprintk(DEBUG_MUX
, "recvproc: end\n");
435 v9ses
->recvproc
= NULL
;
441 * v9fs_mux_init - initialize multiplexer (spawn kproc)
442 * @v9ses: session info structure
443 * @dev_name: mount device information (to create unique kproc)
447 int v9fs_mux_init(struct v9fs_session_info
*v9ses
, const char *dev_name
)
451 strncpy(procname
, dev_name
, sizeof(procname
));
452 procname
[sizeof(procname
) - 1] = 0;
454 init_waitqueue_head(&v9ses
->read_wait
);
455 init_completion(&v9ses
->fcread
);
456 init_completion(&v9ses
->proccmpl
);
457 spin_lock_init(&v9ses
->muxlock
);
458 INIT_LIST_HEAD(&v9ses
->mux_fcalls
);
459 v9ses
->recvproc
= NULL
;
460 v9ses
->curfcall
= NULL
;
462 v9ses
->recvproc
= kthread_create(v9fs_recvproc
, v9ses
,
463 "v9fs_recvproc %s", procname
);
465 if (IS_ERR(v9ses
->recvproc
)) {
466 eprintk(KERN_ERR
, "cannot create receiving thread\n");
467 v9fs_session_close(v9ses
);
468 return -ECONNABORTED
;
471 wake_up_process(v9ses
->recvproc
);
472 wait_for_completion(&v9ses
->proccmpl
);