diff --git a/include/net/9p/client.h b/include/net/9p/client.h index 4fecaabd17bd..6a71d9067818 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -212,8 +212,7 @@ struct p9_stat *p9_client_stat(struct p9_fid *fid); int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst); struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset); -struct p9_req_t *p9_tag_alloc(struct p9_client *, u16); struct p9_req_t *p9_tag_lookup(struct p9_client *, u16); -void p9_free_req(struct p9_client *, struct p9_req_t *); +void p9_client_cb(struct p9_client *c, struct p9_req_t *req); #endif /* NET_9P_CLIENT_H */ diff --git a/include/net/9p/transport.h b/include/net/9p/transport.h index 3e0f2f6beba2..6d5886efb102 100644 --- a/include/net/9p/transport.h +++ b/include/net/9p/transport.h @@ -33,8 +33,8 @@ * @maxsize: transport provided maximum packet size * @def: set if this transport should be considered the default * @create: member function to create a new connection on this transport - * @close: member function to disconnect and close the transport - * @rpc: member function to issue a request to the transport + * @request: member function to issue a request to the transport + * @cancel: member function to cancel a request (if it hasn't been sent) * * This is the basic API for a transport module which is registered by the * transport module with the 9P core network module and used by the client @@ -51,8 +51,8 @@ struct p9_trans_module { struct module *owner; int (*create)(struct p9_client *, const char *, char *); void (*close) (struct p9_client *); - int (*rpc) (struct p9_client *t, struct p9_fcall *tc, - struct p9_fcall **rc); + int (*request) (struct p9_client *, struct p9_req_t *req); + int (*cancel) (struct p9_client *, struct p9_req_t *req); }; void v9fs_register_trans(struct p9_trans_module *m); diff --git a/net/9p/client.c b/net/9p/client.c index f2d07ef9e6a4..29934febecdb 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -55,6 +55,9 @@ static const match_table_t tokens = { {Opt_err, NULL}, }; +static int +p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc); + /** * v9fs_parse_options - parse mount options into session structure * @options: options string passed from mount @@ -268,6 +271,36 @@ static void p9_tag_cleanup(struct p9_client *c) c->max_tag = 0; } +/** + * p9_client_flush - flush (cancel) a request + * c: client state + * req: request to cancel + * + * This sents a flush for a particular requests and links + * the flush request to the original request. The current + * code only supports a single flush request although the protocol + * allows for multiple flush requests to be sent for a single request. + * + */ + +static int p9_client_flush(struct p9_client *c, struct p9_req_t *req) +{ + struct p9_fcall *tc, *rc = NULL; + int err; + + P9_DPRINTK(P9_DEBUG_9P, "client %p tag %d\n", c, req->tc->tag); + + tc = p9_create_tflush(req->tc->tag); + if (IS_ERR(tc)) + return PTR_ERR(tc); + + err = p9_client_rpc(c, tc, &rc); + + /* we don't free anything here because RPC isn't complete */ + + return err; +} + /** * p9_free_req - free a request and clean-up as necessary * c: client state @@ -289,6 +322,224 @@ void p9_free_req(struct p9_client *c, struct p9_req_t *r) } } +/** + * p9_client_cb - call back from transport to client + * c: client state + * req: request received + * + */ +void p9_client_cb(struct p9_client *c, struct p9_req_t *req) +{ + struct p9_req_t *other_req; + unsigned long flags; + + P9_DPRINTK(P9_DEBUG_MUX, ": %d\n", req->tc->tag); + + if (req->status == REQ_STATUS_ERROR) + wake_up(req->wq); + + if (req->tc->id == P9_TFLUSH) { /* flush receive path */ + P9_DPRINTK(P9_DEBUG_MUX, "flush: %d\n", req->tc->tag); + spin_lock_irqsave(&c->lock, flags); + other_req = p9_tag_lookup(c, req->tc->params.tflush.oldtag); + if (other_req->flush_tag != req->tc->tag) /* stale flush */ + spin_unlock_irqrestore(&c->lock, flags); + else { + BUG_ON(other_req->status != REQ_STATUS_FLSH); + other_req->status = REQ_STATUS_FLSHD; + spin_unlock_irqrestore(&c->lock, flags); + wake_up(other_req->wq); + } + p9_free_req(c, req); + } else { /* normal receive path */ + P9_DPRINTK(P9_DEBUG_MUX, "normal: %d\n", req->tc->tag); + spin_lock_irqsave(&c->lock, flags); + if (req->status != REQ_STATUS_FLSHD) + req->status = REQ_STATUS_RCVD; + req->flush_tag = P9_NOTAG; + spin_unlock_irqrestore(&c->lock, flags); + wake_up(req->wq); + P9_DPRINTK(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag); + } +} +EXPORT_SYMBOL(p9_client_cb); + +/** + * p9_client_rpc - issue a request and wait for a response + * @c: client session + * @tc: &p9_fcall request to transmit + * @rc: &p9_fcall to put reponse into + * + * Returns 0 on success, error code on failure + */ + +static int +p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc) +{ + int tag, err, size; + char *rdata; + struct p9_req_t *req; + unsigned long flags; + int sigpending; + int flushed = 0; + + P9_DPRINTK(P9_DEBUG_9P, "client %p tc %p rc %p\n", c, tc, rc); + + if (c->status != Connected) + return -EIO; + + if (signal_pending(current)) { + sigpending = 1; + clear_thread_flag(TIF_SIGPENDING); + } else + sigpending = 0; + + tag = P9_NOTAG; + if (tc->id != P9_TVERSION) { + tag = p9_idpool_get(c->tagpool); + if (tag < 0) + return -ENOMEM; + } + + req = p9_tag_alloc(c, tag); + + /* if this is a flush request, backlink flush request now to + * avoid race conditions later. */ + if (tc->id == P9_TFLUSH) { + struct p9_req_t *other_req = + p9_tag_lookup(c, tc->params.tflush.oldtag); + if (other_req->status == REQ_STATUS_FLSH) + other_req->flush_tag = tag; + } + + p9_set_tag(tc, tag); + + /* + * if client passed in a pre-allocated response fcall struct + * then we just use that, otherwise we allocate one. + */ + + if (rc == NULL) + req->rc = NULL; + else + req->rc = *rc; + if (req->rc == NULL) { + req->rc = kmalloc(sizeof(struct p9_fcall) + c->msize, + GFP_KERNEL); + if (!req->rc) { + err = -ENOMEM; + p9_idpool_put(tag, c->tagpool); + p9_free_req(c, req); + goto reterr; + } + *rc = req->rc; + } + + rdata = (char *)req->rc+sizeof(struct p9_fcall); + + req->tc = tc; + P9_DPRINTK(P9_DEBUG_9P, "request: tc: %p rc: %p\n", req->tc, req->rc); + + err = c->trans_mod->request(c, req); + if (err < 0) { + c->status = Disconnected; + goto reterr; + } + + /* if it was a flush we just transmitted, return our tag */ + if (tc->id == P9_TFLUSH) + return 0; +again: + P9_DPRINTK(P9_DEBUG_9P, "wait %p tag: %d\n", req->wq, tag); + err = wait_event_interruptible(*req->wq, + req->status >= REQ_STATUS_RCVD); + P9_DPRINTK(P9_DEBUG_9P, "wait %p tag: %d returned %d (flushed=%d)\n", + req->wq, tag, err, flushed); + + if (req->status == REQ_STATUS_ERROR) { + P9_DPRINTK(P9_DEBUG_9P, "req_status error %d\n", req->t_err); + err = req->t_err; + } else if (err == -ERESTARTSYS && flushed) { + P9_DPRINTK(P9_DEBUG_9P, "flushed - going again\n"); + goto again; + } else if (req->status == REQ_STATUS_FLSHD) { + P9_DPRINTK(P9_DEBUG_9P, "flushed - erestartsys\n"); + err = -ERESTARTSYS; + } + + if ((err == -ERESTARTSYS) && (c->status == Connected) && (!flushed)) { + P9_DPRINTK(P9_DEBUG_9P, "flushing\n"); + spin_lock_irqsave(&c->lock, flags); + if (req->status == REQ_STATUS_SENT) + req->status = REQ_STATUS_FLSH; + spin_unlock_irqrestore(&c->lock, flags); + sigpending = 1; + flushed = 1; + clear_thread_flag(TIF_SIGPENDING); + + if (c->trans_mod->cancel(c, req)) { + err = p9_client_flush(c, req); + if (err == 0) + goto again; + } + } + + if (sigpending) { + spin_lock_irqsave(¤t->sighand->siglock, flags); + recalc_sigpending(); + spin_unlock_irqrestore(¤t->sighand->siglock, flags); + } + + if (err < 0) + goto reterr; + + size = le32_to_cpu(*(__le32 *) rdata); + + err = p9_deserialize_fcall(rdata, size, req->rc, c->dotu); + if (err < 0) { + P9_DPRINTK(P9_DEBUG_9P, + "9p debug: client rpc deserialize returned %d\n", err); + goto reterr; + } + +#ifdef CONFIG_NET_9P_DEBUG + if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { + char buf[150]; + + p9_printfcall(buf, sizeof(buf), req->rc, c->dotu); + printk(KERN_NOTICE ">>> %p %s\n", c, buf); + } +#endif + + if (req->rc->id == P9_RERROR) { + int ecode = req->rc->params.rerror.errno; + struct p9_str *ename = &req->rc->params.rerror.error; + + P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len, + ename->str); + + if (c->dotu) + err = -ecode; + + if (!err) { + err = p9_errstr2errno(ename->str, ename->len); + + /* string match failed */ + if (!err) { + PRINT_FCALL_ERROR("unknown error", req->rc); + err = -ESERVERFAULT; + } + } + } else + err = 0; + +reterr: + p9_free_req(c, req); + + P9_DPRINTK(P9_DEBUG_9P, "returning %d\n", err); + return err; +} + static struct p9_fid *p9_fid_create(struct p9_client *clnt) { int err; @@ -339,20 +590,6 @@ static void p9_fid_destroy(struct p9_fid *fid) kfree(fid); } -/** - * p9_client_rpc - sends 9P request and waits until a response is available. - * The function can be interrupted. - * @c: client data - * @tc: request to be sent - * @rc: pointer where a pointer to the response is stored - */ -int -p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, - struct p9_fcall **rc) -{ - return c->trans_mod->rpc(c, tc, rc); -} - struct p9_client *p9_client_create(const char *dev_name, char *options) { int err, n; diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 627e3f097fc5..6bfc013f8b6f 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -174,44 +174,6 @@ static void p9_mux_poll_stop(struct p9_conn *m) spin_unlock_irqrestore(&p9_poll_lock, flags); } -static void p9_conn_rpc_cb(struct p9_client *, struct p9_req_t *); - -static void p9_mux_flush_cb(struct p9_client *client, struct p9_req_t *freq) -{ - struct p9_conn *m = client->trans; - struct p9_req_t *req; - - P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m, - freq->tc, freq->rc, freq->t_err, - freq->tc->params.tflush.oldtag); - - req = p9_tag_lookup(client, freq->tc->params.tflush.oldtag); - if (req) { - req->status = REQ_STATUS_FLSHD; - list_del(&req->req_list); - p9_conn_rpc_cb(client, req); - } - - p9_free_req(client, freq); -} - -static void p9_conn_rpc_cb(struct p9_client *client, struct p9_req_t *req) -{ - P9_DPRINTK(P9_DEBUG_MUX, "req %p\n", req); - - if (req->tc->id == P9_TFLUSH) { /* flush callback */ - P9_DPRINTK(P9_DEBUG_MUX, "flush req %p\n", req); - p9_mux_flush_cb(client, req); - } else { /* normal wakeup path */ - P9_DPRINTK(P9_DEBUG_MUX, "normal req %p\n", req); - if (!req->t_err && (req->status == REQ_STATUS_FLSHD || - req->status == REQ_STATUS_FLSH)) - req->t_err = -ERESTARTSYS; - - wake_up(req->wq); - } -} - /** * p9_conn_cancel - cancel all pending requests with error * @m: mux data @@ -222,11 +184,12 @@ static void p9_conn_rpc_cb(struct p9_client *client, struct p9_req_t *req) void p9_conn_cancel(struct p9_conn *m, int err) { struct p9_req_t *req, *rtmp; + unsigned long flags; LIST_HEAD(cancel_list); P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err); m->err = err; - spin_lock(&m->client->lock); + spin_lock_irqsave(&m->client->lock, flags); list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { req->status = REQ_STATUS_ERROR; if (!req->t_err) @@ -239,44 +202,12 @@ void p9_conn_cancel(struct p9_conn *m, int err) req->t_err = err; list_move(&req->req_list, &cancel_list); } - spin_unlock(&m->client->lock); + spin_unlock_irqrestore(&m->client->lock, flags); list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) { list_del(&req->req_list); - p9_conn_rpc_cb(m->client, req); - } -} - -static void process_request(struct p9_conn *m, struct p9_req_t *req) -{ - int ecode; - struct p9_str *ename; - - if (!req->t_err && req->rc->id == P9_RERROR) { - ecode = req->rc->params.rerror.errno; - ename = &req->rc->params.rerror.error; - - P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len, - ename->str); - - if (m->client->dotu) - req->t_err = -ecode; - - if (!req->t_err) { - req->t_err = p9_errstr2errno(ename->str, ename->len); - - /* string match failed */ - if (!req->t_err) { - PRINT_FCALL_ERROR("unknown error", req->rc); - req->t_err = -ESERVERFAULT; - } - } - } else if (req->tc && req->rc->id != req->tc->id + 1) { - P9_DPRINTK(P9_DEBUG_ERROR, - "fcall mismatch: expected %d, got %d\n", - req->tc->id + 1, req->rc->id); - if (!req->t_err) - req->t_err = -EIO; + P9_DPRINTK(P9_DEBUG_ERROR, "call back req %p\n", req); + p9_client_cb(m->client, req); } } @@ -421,41 +352,13 @@ static void p9_read_work(struct work_struct *work) /* not an else because some packets (like clunk) have no payload */ if ((m->req) && (m->rpos == m->rsize)) { /* packet is read in */ P9_DPRINTK(P9_DEBUG_MUX, "got new packet\n"); - m->rbuf = (char *)m->req->rc + sizeof(struct p9_fcall); - err = p9_deserialize_fcall(m->rbuf, m->rsize, m->req->rc, - m->client->dotu); - if (err < 0) { - m->req = NULL; - goto error; - } -#ifdef CONFIG_NET_9P_DEBUG - if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { - char buf[150]; - - p9_printfcall(buf, sizeof(buf), m->req->rc, - m->client->dotu); - printk(KERN_NOTICE ">>> %p %s\n", m, buf); - } -#endif - - P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, - m->req->rc->id, m->req->rc->tag); + list_del(&m->req->req_list); + p9_client_cb(m->client, m->req); m->rbuf = NULL; m->rpos = 0; m->rsize = 0; - - if (m->req->status != REQ_STATUS_FLSH) { - list_del(&m->req->req_list); - m->req->status = REQ_STATUS_RCVD; - } - - process_request(m, m->req); - - if (m->req->status != REQ_STATUS_FLSH) - p9_conn_rpc_cb(m->client, m->req); - m->req = NULL; } @@ -741,57 +644,41 @@ static void p9_poll_mux(struct p9_conn *m) } /** - * p9_send_request - send 9P request + * p9_fd_request - send 9P request * The function can sleep until the request is scheduled for sending. * The function can be interrupted. Return from the function is not - * a guarantee that the request is sent successfully. Can return errors - * that can be retrieved by PTR_ERR macros. + * a guarantee that the request is sent successfully. * - * @m: mux data - * @tc: request to be sent + * @client: client instance + * @req: request to be sent * */ -static struct p9_req_t *p9_send_request(struct p9_conn *m, struct p9_fcall *tc) +static int p9_fd_request(struct p9_client *client, struct p9_req_t *req) { - int tag; int n; - struct p9_req_t *req; + struct p9_trans_fd *ts = client->trans; + struct p9_conn *m = ts->conn; P9_DPRINTK(P9_DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current, - tc, tc->id); + req->tc, req->tc->id); if (m->err < 0) - return ERR_PTR(m->err); - - tag = P9_NOTAG; - if (tc->id != P9_TVERSION) { - tag = p9_idpool_get(m->client->tagpool); - if (tag < 0) - return ERR_PTR(-ENOMEM); - } - - p9_set_tag(tc, tag); - - req = p9_tag_alloc(m->client, tag); + return m->err; #ifdef CONFIG_NET_9P_DEBUG if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { char buf[150]; - p9_printfcall(buf, sizeof(buf), tc, m->client->dotu); + p9_printfcall(buf, sizeof(buf), req->tc, client->dotu); printk(KERN_NOTICE "<<< %p %s\n", m, buf); } #endif - req->tag = tag; - req->tc = tc; - req->rc = NULL; - req->t_err = 0; req->status = REQ_STATUS_UNSENT; - spin_lock(&m->client->lock); + spin_lock(&client->lock); list_add_tail(&req->req_list, &m->unsent_req_list); - spin_unlock(&m->client->lock); + spin_unlock(&client->lock); if (test_and_clear_bit(Wpending, &m->wsched)) n = POLLOUT; @@ -801,17 +688,20 @@ static struct p9_req_t *p9_send_request(struct p9_conn *m, struct p9_fcall *tc) if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched)) queue_work(p9_mux_wq, &m->wq); - return req; + return 0; } -static int -p9_mux_flush_request(struct p9_conn *m, struct p9_req_t *req) +static int p9_fd_cancel(struct p9_client *client, struct p9_req_t *req) { - struct p9_fcall *fc; - struct p9_req_t *rreq, *rptr; + struct p9_trans_fd *ts = client->trans; + struct p9_conn *m = ts->conn; P9_DPRINTK(P9_DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag); + spin_lock(&client->lock); + list_del(&req->req_list); + spin_unlock(&client->lock); + /* if a response was received for a request, do nothing */ if (req->rc || req->t_err) { P9_DPRINTK(P9_DEBUG_MUX, @@ -819,103 +709,14 @@ p9_mux_flush_request(struct p9_conn *m, struct p9_req_t *req) return 0; } - req->status = REQ_STATUS_FLSH; - - spin_lock(&m->client->lock); - /* if the request is not sent yet, just remove it from the list */ - list_for_each_entry_safe(rreq, rptr, &m->unsent_req_list, req_list) { - if (rreq->tag == req->tag) { - P9_DPRINTK(P9_DEBUG_MUX, - "mux %p req %p request is not sent yet\n", m, req); - list_del(&rreq->req_list); - req->status = REQ_STATUS_FLSHD; - spin_unlock(&m->client->lock); - p9_conn_rpc_cb(m->client, req); - return 0; - } + if (req->status == REQ_STATUS_UNSENT) { + req->status = REQ_STATUS_FLSHD; + return 0; } - spin_unlock(&m->client->lock); - clear_thread_flag(TIF_SIGPENDING); - fc = p9_create_tflush(req->tag); - p9_send_request(m, fc); return 1; } -/** - * p9_fd_rpc- sends 9P request and waits until a response is available. - * The function can be interrupted. - * @client: client instance - * @tc: request to be sent - * @rc: pointer where a pointer to the response is stored - * - */ - -int -p9_fd_rpc(struct p9_client *client, struct p9_fcall *tc, struct p9_fcall **rc) -{ - struct p9_trans_fd *p = client->trans; - struct p9_conn *m = p->conn; - int err, sigpending; - unsigned long flags; - struct p9_req_t *req; - - if (rc) - *rc = NULL; - - sigpending = 0; - if (signal_pending(current)) { - sigpending = 1; - clear_thread_flag(TIF_SIGPENDING); - } - - req = p9_send_request(m, tc); - if (IS_ERR(req)) { - err = PTR_ERR(req); - P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err); - return err; - } - - err = wait_event_interruptible(*req->wq, req->rc != NULL || - req->t_err < 0); - if (req->t_err < 0) - err = req->t_err; - - if (err == -ERESTARTSYS && client->status == Connected - && m->err == 0) { - if (p9_mux_flush_request(m, req)) { - /* wait until we get response of the flush message */ - do { - clear_thread_flag(TIF_SIGPENDING); - err = wait_event_interruptible(*req->wq, - req->rc || req->t_err); - } while (!req->rc && !req->t_err && - err == -ERESTARTSYS && - client->status == Connected && !m->err); - - err = -ERESTARTSYS; - } - sigpending = 1; - } - - if (sigpending) { - spin_lock_irqsave(¤t->sighand->siglock, flags); - recalc_sigpending(); - spin_unlock_irqrestore(¤t->sighand->siglock, flags); - } - - if (rc) - *rc = req->rc; - else - kfree(req->rc); - - p9_free_req(client, req); - if (err > 0) - err = -EIO; - - return err; -} - /** * parse_options - parse mount options into session structure * @options: options string passed from mount @@ -1243,7 +1044,8 @@ static struct p9_trans_module p9_tcp_trans = { .def = 1, .create = p9_fd_create_tcp, .close = p9_fd_close, - .rpc = p9_fd_rpc, + .request = p9_fd_request, + .cancel = p9_fd_cancel, .owner = THIS_MODULE, }; @@ -1253,7 +1055,8 @@ static struct p9_trans_module p9_unix_trans = { .def = 0, .create = p9_fd_create_unix, .close = p9_fd_close, - .rpc = p9_fd_rpc, + .request = p9_fd_request, + .cancel = p9_fd_cancel, .owner = THIS_MODULE, }; @@ -1263,7 +1066,8 @@ static struct p9_trans_module p9_fd_trans = { .def = 0, .create = p9_fd_create, .close = p9_fd_close, - .rpc = p9_fd_rpc, + .request = p9_fd_request, + .cancel = p9_fd_cancel, .owner = THIS_MODULE, }; diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index e18de14c30d5..2d7781ec663b 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -126,17 +126,16 @@ static void req_done(struct virtqueue *vq) struct virtio_chan *chan = vq->vdev->priv; struct p9_fcall *rc; unsigned int len; - unsigned long flags; struct p9_req_t *req; - spin_lock_irqsave(&chan->lock, flags); + P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n"); + while ((rc = chan->vq->vq_ops->get_buf(chan->vq, &len)) != NULL) { + P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc); + P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag); req = p9_tag_lookup(chan->client, rc->tag); - req->status = REQ_STATUS_RCVD; - wake_up(req->wq); + p9_client_cb(chan->client, req); } - /* In case queue is stopped waiting for more buffers. */ - spin_unlock_irqrestore(&chan->lock, flags); } /** @@ -173,8 +172,14 @@ pack_sg_list(struct scatterlist *sg, int start, int limit, char *data, return index-start; } +/* We don't currently allow canceling of virtio requests */ +static int p9_virtio_cancel(struct p9_client *client, struct p9_req_t *req) +{ + return 1; +} + /** - * p9_virtio_rpc - issue a request and wait for a response + * p9_virtio_request - issue a request * @t: transport state * @tc: &p9_fcall request to transmit * @rc: &p9_fcall to put reponse into @@ -182,44 +187,22 @@ pack_sg_list(struct scatterlist *sg, int start, int limit, char *data, */ static int -p9_virtio_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc) +p9_virtio_request(struct p9_client *client, struct p9_req_t *req) { int in, out; - int n, err, size; - struct virtio_chan *chan = c->trans; - char *rdata; - struct p9_req_t *req; - unsigned long flags; + struct virtio_chan *chan = client->trans; + char *rdata = (char *)req->rc+sizeof(struct p9_fcall); - if (*rc == NULL) { - *rc = kmalloc(sizeof(struct p9_fcall) + c->msize, GFP_KERNEL); - if (!*rc) - return -ENOMEM; - } + P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n"); - rdata = (char *)*rc+sizeof(struct p9_fcall); - - n = P9_NOTAG; - if (tc->id != P9_TVERSION) { - n = p9_idpool_get(c->tagpool); - if (n < 0) - return -ENOMEM; - } - - spin_lock_irqsave(&chan->lock, flags); - req = p9_tag_alloc(c, n); - spin_unlock_irqrestore(&chan->lock, flags); - - p9_set_tag(tc, n); - - P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio rpc tag %d\n", n); - - out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, tc->sdata, tc->size); - in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata, c->msize); + out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, req->tc->sdata, + req->tc->size); + in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata, + client->msize); req->status = REQ_STATUS_SENT; - if (chan->vq->vq_ops->add_buf(chan->vq, chan->sg, out, in, tc)) { + if (chan->vq->vq_ops->add_buf(chan->vq, chan->sg, out, in, req->tc)) { P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio rpc add_buf returned failure"); return -EIO; @@ -227,28 +210,7 @@ p9_virtio_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc) chan->vq->vq_ops->kick(chan->vq); - wait_event(*req->wq, req->status == REQ_STATUS_RCVD); - - size = le32_to_cpu(*(__le32 *) rdata); - - err = p9_deserialize_fcall(rdata, size, *rc, c->dotu); - if (err < 0) { - P9_DPRINTK(P9_DEBUG_TRANS, - "9p debug: virtio rpc deserialize returned %d\n", err); - return err; - } - -#ifdef CONFIG_NET_9P_DEBUG - if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { - char buf[150]; - - p9_printfcall(buf, sizeof(buf), *rc, c->dotu); - printk(KERN_NOTICE ">>> %p %s\n", c, buf); - } -#endif - - p9_free_req(c, req); - + P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n"); return 0; } @@ -394,7 +356,8 @@ static struct p9_trans_module p9_virtio_trans = { .name = "virtio", .create = p9_virtio_create, .close = p9_virtio_close, - .rpc = p9_virtio_rpc, + .request = p9_virtio_request, + .cancel = p9_virtio_cancel, .maxsize = PAGE_SIZE*16, .def = 0, .owner = THIS_MODULE,