⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mux.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
			P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m);			queue_work(p9_mux_wq, &m->wq);		} else			clear_bit(Wworksched, &m->wsched);	} else		clear_bit(Wworksched, &m->wsched);	return;error:	p9_conn_cancel(m, err);	clear_bit(Wworksched, &m->wsched);}static void process_request(struct p9_conn *m, struct p9_req *req){	int ecode;	struct p9_str *ename;	if (!req->err && req->rcall->id == P9_RERROR) {		ecode = req->rcall->params.rerror.errno;		ename = &req->rcall->params.rerror.error;		P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len,								ename->str);		if (*m->extended)			req->err = -ecode;		if (!req->err) {			req->err = p9_errstr2errno(ename->str, ename->len);			if (!req->err) {	/* string match failed */				PRINT_FCALL_ERROR("unknown error", req->rcall);			}			if (!req->err)				req->err = -ESERVERFAULT;		}	} else if (req->tcall && req->rcall->id != req->tcall->id + 1) {		P9_DPRINTK(P9_DEBUG_ERROR,				"fcall mismatch: expected %d, got %d\n",				req->tcall->id + 1, req->rcall->id);		if (!req->err)			req->err = -EIO;	}}/** * p9_read_work - called when there is some data to be read from a transport */static void p9_read_work(struct work_struct *work){	int n, err;	struct p9_conn *m;	struct p9_req *req, *rptr, *rreq;	struct p9_fcall *rcall;	char *rbuf;	m = container_of(work, struct p9_conn, rq);	if (m->err < 0)		return;	rcall = NULL;	P9_DPRINTK(P9_DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos);	if (!m->rcall) {		m->rcall =		    kmalloc(sizeof(struct p9_fcall) + m->msize, GFP_KERNEL);		if (!m->rcall) {			err = -ENOMEM;			goto error;		}		m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall);		m->rpos = 0;	}	clear_bit(Rpending, &m->wsched);	err = m->trans->read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos);	P9_DPRINTK(P9_DEBUG_MUX, "mux %p got %d bytes\n", m, err);	if (err == -EAGAIN) {		clear_bit(Rworksched, &m->wsched);		return;	}	if (err <= 0)		goto error;	m->rpos += err;	while (m->rpos > 4) {		n = le32_to_cpu(*(__le32 *) m->rbuf);		if (n >= m->msize) {			P9_DPRINTK(P9_DEBUG_ERROR,				"requested packet size too big: %d\n", n);			err = -EIO;			goto error;		}		if (m->rpos < n)			break;		err =		    p9_deserialize_fcall(m->rbuf, n, m->rcall, *m->extended);		if (err < 0) {			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->rcall,				*m->extended);			printk(KERN_NOTICE ">>> %p %s\n", m, buf);		}#endif		rcall = m->rcall;		rbuf = m->rbuf;		if (m->rpos > n) {			m->rcall = kmalloc(sizeof(struct p9_fcall) + m->msize,					   GFP_KERNEL);			if (!m->rcall) {				err = -ENOMEM;				goto error;			}			m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall);			memmove(m->rbuf, rbuf + n, m->rpos - n);			m->rpos -= n;		} else {			m->rcall = NULL;			m->rbuf = NULL;			m->rpos = 0;		}		P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m,							rcall->id, rcall->tag);		req = NULL;		spin_lock(&m->lock);		list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) {			if (rreq->tag == rcall->tag) {				req = rreq;				if (req->flush != Flushing)					list_del(&req->req_list);				break;			}		}		spin_unlock(&m->lock);		if (req) {			req->rcall = rcall;			process_request(m, req);			if (req->flush != Flushing) {				if (req->cb)					(*req->cb) (req, req->cba);				else					kfree(req->rcall);				wake_up(&m->equeue);			}		} else {			if (err >= 0 && rcall->id != P9_RFLUSH)				P9_DPRINTK(P9_DEBUG_ERROR,				  "unexpected response mux %p id %d tag %d\n",				  m, rcall->id, rcall->tag);			kfree(rcall);		}	}	if (!list_empty(&m->req_list)) {		if (test_and_clear_bit(Rpending, &m->wsched))			n = POLLIN;		else			n = m->trans->poll(m->trans, NULL);		if (n & POLLIN) {			P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m);			queue_work(p9_mux_wq, &m->rq);		} else			clear_bit(Rworksched, &m->wsched);	} else		clear_bit(Rworksched, &m->wsched);	return;error:	p9_conn_cancel(m, err);	clear_bit(Rworksched, &m->wsched);}/** * p9_send_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. * * @m: mux data * @tc: request to be sent * @cb: callback function to call when response is received * @cba: parameter to pass to the callback function */static struct p9_req *p9_send_request(struct p9_conn *m,					  struct p9_fcall *tc,					  p9_conn_req_callback cb, void *cba){	int n;	struct p9_req *req;	P9_DPRINTK(P9_DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current,		tc, tc->id);	if (m->err < 0)		return ERR_PTR(m->err);	req = kmalloc(sizeof(struct p9_req), GFP_KERNEL);	if (!req)		return ERR_PTR(-ENOMEM);	if (tc->id == P9_TVERSION)		n = P9_NOTAG;	else		n = p9_mux_get_tag(m);	if (n < 0)		return ERR_PTR(-ENOMEM);	p9_set_tag(tc, n);#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->extended);		printk(KERN_NOTICE "<<< %p %s\n", m, buf);	}#endif	spin_lock_init(&req->lock);	req->tag = n;	req->tcall = tc;	req->rcall = NULL;	req->err = 0;	req->cb = cb;	req->cba = cba;	req->flush = None;	spin_lock(&m->lock);	list_add_tail(&req->req_list, &m->unsent_req_list);	spin_unlock(&m->lock);	if (test_and_clear_bit(Wpending, &m->wsched))		n = POLLOUT;	else		n = m->trans->poll(m->trans, NULL);	if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched))		queue_work(p9_mux_wq, &m->wq);	return req;}static void p9_mux_free_request(struct p9_conn *m, struct p9_req *req){	p9_mux_put_tag(m, req->tag);	kfree(req);}static void p9_mux_flush_cb(struct p9_req *freq, void *a){	p9_conn_req_callback cb;	int tag;	struct p9_conn *m;	struct p9_req *req, *rreq, *rptr;	m = a;	P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m,		freq->tcall, freq->rcall, freq->err,		freq->tcall->params.tflush.oldtag);	spin_lock(&m->lock);	cb = NULL;	tag = freq->tcall->params.tflush.oldtag;	req = NULL;	list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) {		if (rreq->tag == tag) {			req = rreq;			list_del(&req->req_list);			break;		}	}	spin_unlock(&m->lock);	if (req) {		spin_lock(&req->lock);		req->flush = Flushed;		spin_unlock(&req->lock);		if (req->cb)			(*req->cb) (req, req->cba);		else			kfree(req->rcall);		wake_up(&m->equeue);	}	kfree(freq->tcall);	kfree(freq->rcall);	p9_mux_free_request(m, freq);}static intp9_mux_flush_request(struct p9_conn *m, struct p9_req *req){	struct p9_fcall *fc;	struct p9_req *rreq, *rptr;	P9_DPRINTK(P9_DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag);	/* if a response was received for a request, do nothing */	spin_lock(&req->lock);	if (req->rcall || req->err) {		spin_unlock(&req->lock);		P9_DPRINTK(P9_DEBUG_MUX,			"mux %p req %p response already received\n", m, req);		return 0;	}	req->flush = Flushing;	spin_unlock(&req->lock);	spin_lock(&m->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->flush = Flushed;			spin_unlock(&m->lock);			if (req->cb)				(*req->cb) (req, req->cba);			return 0;		}	}	spin_unlock(&m->lock);	clear_thread_flag(TIF_SIGPENDING);	fc = p9_create_tflush(req->tag);	p9_send_request(m, fc, p9_mux_flush_cb, m);	return 1;}static voidp9_conn_rpc_cb(struct p9_req *req, void *a){	struct p9_mux_rpc *r;	P9_DPRINTK(P9_DEBUG_MUX, "req %p r %p\n", req, a);	r = a;	r->rcall = req->rcall;	r->err = req->err;	if (req->flush != None && !req->err)		r->err = -ERESTARTSYS;	wake_up(&r->wqueue);}/** * p9_mux_rpc - sends 9P request and waits until a response is available. *	The function can be interrupted. * @m: mux data * @tc: request to be sent * @rc: pointer where a pointer to the response is stored */intp9_conn_rpc(struct p9_conn *m, struct p9_fcall *tc,	     struct p9_fcall **rc){	int err, sigpending;	unsigned long flags;	struct p9_req *req;	struct p9_mux_rpc r;	r.err = 0;	r.tcall = tc;	r.rcall = NULL;	r.m = m;	init_waitqueue_head(&r.wqueue);	if (rc)		*rc = NULL;	sigpending = 0;	if (signal_pending(current)) {		sigpending = 1;		clear_thread_flag(TIF_SIGPENDING);	}	req = p9_send_request(m, tc, p9_conn_rpc_cb, &r);	if (IS_ERR(req)) {		err = PTR_ERR(req);		P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err);		return err;	}	err = wait_event_interruptible(r.wqueue, r.rcall != NULL || r.err < 0);	if (r.err < 0)		err = r.err;	if (err == -ERESTARTSYS && m->trans->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(r.wqueue,					r.rcall || r.err);			} while (!r.rcall && !r.err && err == -ERESTARTSYS &&				m->trans->status == Connected && !m->err);			err = -ERESTARTSYS;		}		sigpending = 1;	}	if (sigpending) {		spin_lock_irqsave(&current->sighand->siglock, flags);		recalc_sigpending();		spin_unlock_irqrestore(&current->sighand->siglock, flags);	}	if (rc)		*rc = r.rcall;	else		kfree(r.rcall);	p9_mux_free_request(m, req);	if (err > 0)		err = -EIO;	return err;}EXPORT_SYMBOL(p9_conn_rpc);#ifdef P9_NONBLOCK/** * p9_conn_rpcnb - sends 9P request without waiting for response. * @m: mux data * @tc: request to be sent * @cb: callback function to be called when response arrives * @cba: value to pass to the callback function */int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc,		   p9_conn_req_callback cb, void *a){	int err;	struct p9_req *req;	req = p9_send_request(m, tc, cb, a);	if (IS_ERR(req)) {		err = PTR_ERR(req);		P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err);		return PTR_ERR(req);	}	P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p tag %d\n", m, tc, req->tag);	return 0;}EXPORT_SYMBOL(p9_conn_rpcnb);#endif /* P9_NONBLOCK *//** * p9_conn_cancel - cancel all pending requests with error * @m: mux data * @err: error code */void p9_conn_cancel(struct p9_conn *m, int err){	struct p9_req *req, *rtmp;	LIST_HEAD(cancel_list);	P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err);	m->err = err;	spin_lock(&m->lock);	list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) {		list_move(&req->req_list, &cancel_list);	}	list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) {		list_move(&req->req_list, &cancel_list);	}	spin_unlock(&m->lock);	list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) {		list_del(&req->req_list);		if (!req->err)			req->err = err;		if (req->cb)			(*req->cb) (req, req->cba);		else			kfree(req->rcall);	}	wake_up(&m->equeue);}EXPORT_SYMBOL(p9_conn_cancel);static u16 p9_mux_get_tag(struct p9_conn *m){	int tag;	tag = p9_idpool_get(m->tagpool);	if (tag < 0)		return P9_NOTAG;	else		return (u16) tag;}static void p9_mux_put_tag(struct p9_conn *m, u16 tag){	if (tag != P9_NOTAG && p9_idpool_check(tag, m->tagpool))		p9_idpool_put(tag, m->tagpool);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -