Beispiel #1
0
static void p9_xosclient_rerror(struct p9_req_t *req)
{
	struct p9_fcall *rcall;
	u16 tag;
	struct p9_xos_device *dev = (struct p9_xos_device *)req->aux;
	struct p9_xos_endpoint *ep = &dev->driver->ep[RD_EP];
	unsigned long flags;

	if (p9_parse_header(req->tc, &req->tc->size, &req->tc->id, &tag, 1))
		warning("Failed to decode header !");
	kfree(req->tc);
	spin_lock_irqsave(&dev->driver->ep_lock, flags);
	p9_xos_deque_push(ep->rqueue, a2n(req->tc->sdata - 8, ep), ep);
	nb_free_packets++;
	spin_unlock_irqrestore(&dev->driver->ep_lock, flags);

	rcall = kmalloc(sizeof(struct p9_fcall) + 32, GFP_KERNEL);
	p9pdu_reset(rcall);
	rcall->sdata = (u8 *) (rcall + sizeof(struct p9_fcall));
	p9pdu_writef(rcall, 0, "dbwT", 0, P9_RERROR, tag,
		     "9P destination service closed");
	p9pdu_finalize(rcall);

	req->rc = rcall;
	req->tc = NULL;

	spin_lock(&dev->lock);
	dev->ack_count += 1;
	spin_unlock(&dev->lock);

	p9_xos_add_write_request(req, 0);
}
Beispiel #2
0
static struct p9_req_t *
p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
{
	va_list ap;
	int tag, err;
	struct p9_req_t *req;
	unsigned long flags;
	int sigpending;
	int flushed = 0;

	P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type);

	if (c->status != Connected)
		return ERR_PTR(-EIO);

	if (signal_pending(current)) {
		sigpending = 1;
		clear_thread_flag(TIF_SIGPENDING);
	} else
		sigpending = 0;

	tag = P9_NOTAG;
	if (type != P9_TVERSION) {
		tag = p9_idpool_get(c->tagpool);
		if (tag < 0)
			return ERR_PTR(-ENOMEM);
	}

	req = p9_tag_alloc(c, tag);
	if (IS_ERR(req))
		return req;

	/* marshall the data */
	p9pdu_prepare(req->tc, tag, type);
	va_start(ap, fmt);
	err = p9pdu_vwritef(req->tc, c->dotu, fmt, ap);
	va_end(ap);
	p9pdu_finalize(req->tc);

	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 (type == P9_TFLUSH)
		return req;
again:
	P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d\n", req->wq, tag);
	err = wait_event_interruptible(*req->wq,
						req->status >= REQ_STATUS_RCVD);
	P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d returned %d (flushed=%d)\n",
						req->wq, tag, err, flushed);

	if (req->status == REQ_STATUS_ERROR) {
		P9_DPRINTK(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
		err = req->t_err;
	} else if (err == -ERESTARTSYS && flushed) {
		P9_DPRINTK(P9_DEBUG_MUX, "flushed - going again\n");
		goto again;
	} else if (req->status == REQ_STATUS_FLSHD) {
		P9_DPRINTK(P9_DEBUG_MUX, "flushed - erestartsys\n");
		err = -ERESTARTSYS;
	}

	if ((err == -ERESTARTSYS) && (c->status == Connected) && (!flushed)) {
		P9_DPRINTK(P9_DEBUG_MUX, "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(&current->sighand->siglock, flags);
		recalc_sigpending();
		spin_unlock_irqrestore(&current->sighand->siglock, flags);
	}

	if (err < 0)
		goto reterr;

	err = p9_check_errors(c, req);
	if (!err) {
		P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d\n", c, type);
		return req;
	}

reterr:
	P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d error: %d\n", c, type,
									err);
	p9_free_req(c, req);
	return ERR_PTR(err);
}