xref: /openbmc/linux/net/9p/trans_fd.c (revision 992b3f1d)
1bd238fb4SLatchesar Ionkov /*
2bd238fb4SLatchesar Ionkov  * linux/fs/9p/trans_fd.c
3bd238fb4SLatchesar Ionkov  *
4bd238fb4SLatchesar Ionkov  * Fd transport layer.  Includes deprecated socket layer.
5bd238fb4SLatchesar Ionkov  *
6bd238fb4SLatchesar Ionkov  *  Copyright (C) 2006 by Russ Cox <rsc@swtch.com>
7bd238fb4SLatchesar Ionkov  *  Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
88a0dc95fSEric Van Hensbergen  *  Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com>
9bd238fb4SLatchesar Ionkov  *  Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com>
10bd238fb4SLatchesar Ionkov  *
11bd238fb4SLatchesar Ionkov  *  This program is free software; you can redistribute it and/or modify
12bd238fb4SLatchesar Ionkov  *  it under the terms of the GNU General Public License version 2
13bd238fb4SLatchesar Ionkov  *  as published by the Free Software Foundation.
14bd238fb4SLatchesar Ionkov  *
15bd238fb4SLatchesar Ionkov  *  This program is distributed in the hope that it will be useful,
16bd238fb4SLatchesar Ionkov  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17bd238fb4SLatchesar Ionkov  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18bd238fb4SLatchesar Ionkov  *  GNU General Public License for more details.
19bd238fb4SLatchesar Ionkov  *
20bd238fb4SLatchesar Ionkov  *  You should have received a copy of the GNU General Public License
21bd238fb4SLatchesar Ionkov  *  along with this program; if not, write to:
22bd238fb4SLatchesar Ionkov  *  Free Software Foundation
23bd238fb4SLatchesar Ionkov  *  51 Franklin Street, Fifth Floor
24bd238fb4SLatchesar Ionkov  *  Boston, MA  02111-1301  USA
25bd238fb4SLatchesar Ionkov  *
26bd238fb4SLatchesar Ionkov  */
27bd238fb4SLatchesar Ionkov 
28bd238fb4SLatchesar Ionkov #include <linux/in.h>
29bd238fb4SLatchesar Ionkov #include <linux/module.h>
30bd238fb4SLatchesar Ionkov #include <linux/net.h>
31bd238fb4SLatchesar Ionkov #include <linux/ipv6.h>
328a0dc95fSEric Van Hensbergen #include <linux/kthread.h>
33bd238fb4SLatchesar Ionkov #include <linux/errno.h>
34bd238fb4SLatchesar Ionkov #include <linux/kernel.h>
35bd238fb4SLatchesar Ionkov #include <linux/un.h>
36bd238fb4SLatchesar Ionkov #include <linux/uaccess.h>
37bd238fb4SLatchesar Ionkov #include <linux/inet.h>
38bd238fb4SLatchesar Ionkov #include <linux/idr.h>
39bd238fb4SLatchesar Ionkov #include <linux/file.h>
40a80d923eSEric Van Hensbergen #include <linux/parser.h>
41bd238fb4SLatchesar Ionkov #include <net/9p/9p.h>
42bd238fb4SLatchesar Ionkov #include <net/9p/transport.h>
43bd238fb4SLatchesar Ionkov 
44bd238fb4SLatchesar Ionkov #define P9_PORT 564
45a80d923eSEric Van Hensbergen #define MAX_SOCK_BUF (64*1024)
468a0dc95fSEric Van Hensbergen #define ERREQFLUSH	1
478a0dc95fSEric Van Hensbergen #define MAXPOLLWADDR	2
48a80d923eSEric Van Hensbergen 
49ee443996SEric Van Hensbergen /**
50ee443996SEric Van Hensbergen  * struct p9_fd_opts - per-transport options
51ee443996SEric Van Hensbergen  * @rfd: file descriptor for reading (trans=fd)
52ee443996SEric Van Hensbergen  * @wfd: file descriptor for writing (trans=fd)
53ee443996SEric Van Hensbergen  * @port: port to connect to (trans=tcp)
54ee443996SEric Van Hensbergen  *
55ee443996SEric Van Hensbergen  */
56ee443996SEric Van Hensbergen 
57a80d923eSEric Van Hensbergen struct p9_fd_opts {
58a80d923eSEric Van Hensbergen 	int rfd;
59a80d923eSEric Van Hensbergen 	int wfd;
60a80d923eSEric Van Hensbergen 	u16 port;
61a80d923eSEric Van Hensbergen };
62bd238fb4SLatchesar Ionkov 
63ee443996SEric Van Hensbergen 
64ee443996SEric Van Hensbergen /**
65ee443996SEric Van Hensbergen  * struct p9_trans_fd - transport state
66ee443996SEric Van Hensbergen  * @rd: reference to file to read from
67ee443996SEric Van Hensbergen  * @wr: reference of file to write to
68ee443996SEric Van Hensbergen  * @conn: connection state reference
69ee443996SEric Van Hensbergen  *
70ee443996SEric Van Hensbergen  */
71ee443996SEric Van Hensbergen 
72bd238fb4SLatchesar Ionkov struct p9_trans_fd {
73bd238fb4SLatchesar Ionkov 	struct file *rd;
74bd238fb4SLatchesar Ionkov 	struct file *wr;
758a0dc95fSEric Van Hensbergen 	struct p9_conn *conn;
76bd238fb4SLatchesar Ionkov };
77bd238fb4SLatchesar Ionkov 
78a80d923eSEric Van Hensbergen /*
79a80d923eSEric Van Hensbergen   * Option Parsing (code inspired by NFS code)
80a80d923eSEric Van Hensbergen   *  - a little lazy - parse all fd-transport options
81a80d923eSEric Van Hensbergen   */
82bd238fb4SLatchesar Ionkov 
83a80d923eSEric Van Hensbergen enum {
84a80d923eSEric Van Hensbergen 	/* Options that take integer arguments */
8555762690SLatchesar Ionkov 	Opt_port, Opt_rfdno, Opt_wfdno, Opt_err,
86a80d923eSEric Van Hensbergen };
87a80d923eSEric Van Hensbergen 
88a447c093SSteven Whitehouse static const match_table_t tokens = {
89a80d923eSEric Van Hensbergen 	{Opt_port, "port=%u"},
90a80d923eSEric Van Hensbergen 	{Opt_rfdno, "rfdno=%u"},
91a80d923eSEric Van Hensbergen 	{Opt_wfdno, "wfdno=%u"},
9255762690SLatchesar Ionkov 	{Opt_err, NULL},
93a80d923eSEric Van Hensbergen };
94a80d923eSEric Van Hensbergen 
958a0dc95fSEric Van Hensbergen enum {
968a0dc95fSEric Van Hensbergen 	Rworksched = 1,		/* read work scheduled or running */
978a0dc95fSEric Van Hensbergen 	Rpending = 2,		/* can read */
988a0dc95fSEric Van Hensbergen 	Wworksched = 4,		/* write work scheduled or running */
998a0dc95fSEric Van Hensbergen 	Wpending = 8,		/* can write */
1008a0dc95fSEric Van Hensbergen };
1018a0dc95fSEric Van Hensbergen 
1028a0dc95fSEric Van Hensbergen enum {
1038a0dc95fSEric Van Hensbergen 	None,
1048a0dc95fSEric Van Hensbergen 	Flushing,
1058a0dc95fSEric Van Hensbergen 	Flushed,
1068a0dc95fSEric Van Hensbergen };
1078a0dc95fSEric Van Hensbergen 
1088a0dc95fSEric Van Hensbergen struct p9_req;
1098a0dc95fSEric Van Hensbergen typedef void (*p9_conn_req_callback)(struct p9_req *req, void *a);
110ee443996SEric Van Hensbergen 
111ee443996SEric Van Hensbergen /**
112ee443996SEric Van Hensbergen  * struct p9_req - fd mux encoding of an rpc transaction
113ee443996SEric Van Hensbergen  * @lock: protects req_list
114ee443996SEric Van Hensbergen  * @tag: numeric tag for rpc transaction
115ee443996SEric Van Hensbergen  * @tcall: request &p9_fcall structure
116ee443996SEric Van Hensbergen  * @rcall: response &p9_fcall structure
117ee443996SEric Van Hensbergen  * @err: error state
118ee443996SEric Van Hensbergen  * @cb: callback for when response is received
119ee443996SEric Van Hensbergen  * @cba: argument to pass to callback
120ee443996SEric Van Hensbergen  * @flush: flag to indicate RPC has been flushed
121ee443996SEric Van Hensbergen  * @req_list: list link for higher level objects to chain requests
122ee443996SEric Van Hensbergen  *
123ee443996SEric Van Hensbergen  */
124ee443996SEric Van Hensbergen 
1258a0dc95fSEric Van Hensbergen struct p9_req {
126ee443996SEric Van Hensbergen 	spinlock_t lock;
1278a0dc95fSEric Van Hensbergen 	int tag;
1288a0dc95fSEric Van Hensbergen 	struct p9_fcall *tcall;
1298a0dc95fSEric Van Hensbergen 	struct p9_fcall *rcall;
1308a0dc95fSEric Van Hensbergen 	int err;
1318a0dc95fSEric Van Hensbergen 	p9_conn_req_callback cb;
1328a0dc95fSEric Van Hensbergen 	void *cba;
1338a0dc95fSEric Van Hensbergen 	int flush;
1348a0dc95fSEric Van Hensbergen 	struct list_head req_list;
1358a0dc95fSEric Van Hensbergen };
1368a0dc95fSEric Van Hensbergen 
137992b3f1dSTejun Heo struct p9_poll_wait {
138992b3f1dSTejun Heo 	struct p9_conn *conn;
139992b3f1dSTejun Heo 	wait_queue_t wait;
140992b3f1dSTejun Heo 	wait_queue_head_t *wait_addr;
141ee443996SEric Van Hensbergen };
142ee443996SEric Van Hensbergen 
143ee443996SEric Van Hensbergen /**
144ee443996SEric Van Hensbergen  * struct p9_conn - fd mux connection state information
145ee443996SEric Van Hensbergen  * @lock: protects mux_list (?)
146ee443996SEric Van Hensbergen  * @mux_list: list link for mux to manage multiple connections (?)
147ee443996SEric Van Hensbergen  * @msize: maximum size for connection (dup)
148ee443996SEric Van Hensbergen  * @extended: 9p2000.u flag (dup)
149ee443996SEric Van Hensbergen  * @trans: reference to transport instance for this connection
150ee443996SEric Van Hensbergen  * @tagpool: id accounting for transactions
151ee443996SEric Van Hensbergen  * @err: error state
152ee443996SEric Van Hensbergen  * @req_list: accounting for requests which have been sent
153ee443996SEric Van Hensbergen  * @unsent_req_list: accounting for requests that haven't been sent
154ee443996SEric Van Hensbergen  * @rcall: current response &p9_fcall structure
155ee443996SEric Van Hensbergen  * @rpos: read position in current frame
156ee443996SEric Van Hensbergen  * @rbuf: current read buffer
157ee443996SEric Van Hensbergen  * @wpos: write position for current frame
158ee443996SEric Van Hensbergen  * @wsize: amount of data to write for current frame
159ee443996SEric Van Hensbergen  * @wbuf: current write buffer
160ee443996SEric Van Hensbergen  * @poll_wait: array of wait_q's for various worker threads
161ee443996SEric Van Hensbergen  * @poll_waddr: ????
162ee443996SEric Van Hensbergen  * @pt: poll state
163ee443996SEric Van Hensbergen  * @rq: current read work
164ee443996SEric Van Hensbergen  * @wq: current write work
165ee443996SEric Van Hensbergen  * @wsched: ????
166ee443996SEric Van Hensbergen  *
167ee443996SEric Van Hensbergen  */
1688a0dc95fSEric Van Hensbergen 
1698a0dc95fSEric Van Hensbergen struct p9_conn {
1708a0dc95fSEric Van Hensbergen 	spinlock_t lock; /* protect lock structure */
1718a0dc95fSEric Van Hensbergen 	struct list_head mux_list;
1728a0dc95fSEric Van Hensbergen 	int msize;
1738a0dc95fSEric Van Hensbergen 	unsigned char extended;
1748a0dc95fSEric Van Hensbergen 	struct p9_trans *trans;
1758a0dc95fSEric Van Hensbergen 	struct p9_idpool *tagpool;
1768a0dc95fSEric Van Hensbergen 	int err;
1778a0dc95fSEric Van Hensbergen 	struct list_head req_list;
1788a0dc95fSEric Van Hensbergen 	struct list_head unsent_req_list;
1798a0dc95fSEric Van Hensbergen 	struct p9_fcall *rcall;
1808a0dc95fSEric Van Hensbergen 	int rpos;
1818a0dc95fSEric Van Hensbergen 	char *rbuf;
1828a0dc95fSEric Van Hensbergen 	int wpos;
1838a0dc95fSEric Van Hensbergen 	int wsize;
1848a0dc95fSEric Van Hensbergen 	char *wbuf;
185992b3f1dSTejun Heo 	struct list_head poll_pending_link;
186992b3f1dSTejun Heo 	struct p9_poll_wait poll_wait[MAXPOLLWADDR];
1878a0dc95fSEric Van Hensbergen 	poll_table pt;
1888a0dc95fSEric Van Hensbergen 	struct work_struct rq;
1898a0dc95fSEric Van Hensbergen 	struct work_struct wq;
1908a0dc95fSEric Van Hensbergen 	unsigned long wsched;
1918a0dc95fSEric Van Hensbergen };
1928a0dc95fSEric Van Hensbergen 
193ee443996SEric Van Hensbergen /**
194ee443996SEric Van Hensbergen  * struct p9_mux_rpc - fd mux rpc accounting structure
195ee443996SEric Van Hensbergen  * @m: connection this request was issued on
196ee443996SEric Van Hensbergen  * @err: error state
197ee443996SEric Van Hensbergen  * @tcall: request &p9_fcall
198ee443996SEric Van Hensbergen  * @rcall: response &p9_fcall
199ee443996SEric Van Hensbergen  * @wqueue: wait queue that client is blocked on for this rpc
200ee443996SEric Van Hensbergen  *
201ee443996SEric Van Hensbergen  * Bug: isn't this information duplicated elsewhere like &p9_req
202ee443996SEric Van Hensbergen  */
2038a0dc95fSEric Van Hensbergen 
2048a0dc95fSEric Van Hensbergen struct p9_mux_rpc {
2058a0dc95fSEric Van Hensbergen 	struct p9_conn *m;
2068a0dc95fSEric Van Hensbergen 	int err;
2078a0dc95fSEric Van Hensbergen 	struct p9_fcall *tcall;
2088a0dc95fSEric Van Hensbergen 	struct p9_fcall *rcall;
2098a0dc95fSEric Van Hensbergen 	wait_queue_head_t wqueue;
2108a0dc95fSEric Van Hensbergen };
2118a0dc95fSEric Van Hensbergen 
2128a0dc95fSEric Van Hensbergen static int p9_poll_proc(void *);
2138a0dc95fSEric Van Hensbergen static void p9_read_work(struct work_struct *work);
2148a0dc95fSEric Van Hensbergen static void p9_write_work(struct work_struct *work);
2158a0dc95fSEric Van Hensbergen static void p9_pollwait(struct file *filp, wait_queue_head_t *wait_address,
2168a0dc95fSEric Van Hensbergen 								poll_table *p);
2178a0dc95fSEric Van Hensbergen static int p9_fd_write(struct p9_trans *trans, void *v, int len);
2188a0dc95fSEric Van Hensbergen static int p9_fd_read(struct p9_trans *trans, void *v, int len);
2198a0dc95fSEric Van Hensbergen 
220992b3f1dSTejun Heo static DEFINE_SPINLOCK(p9_poll_lock);
221992b3f1dSTejun Heo static LIST_HEAD(p9_poll_pending_list);
2228a0dc95fSEric Van Hensbergen static struct workqueue_struct *p9_mux_wq;
223992b3f1dSTejun Heo static struct task_struct *p9_poll_task;
2248a0dc95fSEric Van Hensbergen 
2258a0dc95fSEric Van Hensbergen static void p9_conn_destroy(struct p9_conn *);
2268a0dc95fSEric Van Hensbergen static unsigned int p9_fd_poll(struct p9_trans *trans,
2278a0dc95fSEric Van Hensbergen 						struct poll_table_struct *pt);
2288a0dc95fSEric Van Hensbergen 
2298a0dc95fSEric Van Hensbergen #ifdef P9_NONBLOCK
2308a0dc95fSEric Van Hensbergen static int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc,
2318a0dc95fSEric Van Hensbergen 	p9_conn_req_callback cb, void *a);
2328a0dc95fSEric Van Hensbergen #endif /* P9_NONBLOCK */
2338a0dc95fSEric Van Hensbergen 
2348a0dc95fSEric Van Hensbergen static void p9_conn_cancel(struct p9_conn *m, int err);
2358a0dc95fSEric Van Hensbergen 
2368a0dc95fSEric Van Hensbergen static u16 p9_mux_get_tag(struct p9_conn *m)
2378a0dc95fSEric Van Hensbergen {
2388a0dc95fSEric Van Hensbergen 	int tag;
2398a0dc95fSEric Van Hensbergen 
2408a0dc95fSEric Van Hensbergen 	tag = p9_idpool_get(m->tagpool);
2418a0dc95fSEric Van Hensbergen 	if (tag < 0)
2428a0dc95fSEric Van Hensbergen 		return P9_NOTAG;
2438a0dc95fSEric Van Hensbergen 	else
2448a0dc95fSEric Van Hensbergen 		return (u16) tag;
2458a0dc95fSEric Van Hensbergen }
2468a0dc95fSEric Van Hensbergen 
2478a0dc95fSEric Van Hensbergen static void p9_mux_put_tag(struct p9_conn *m, u16 tag)
2488a0dc95fSEric Van Hensbergen {
2498a0dc95fSEric Van Hensbergen 	if (tag != P9_NOTAG && p9_idpool_check(tag, m->tagpool))
2508a0dc95fSEric Van Hensbergen 		p9_idpool_put(tag, m->tagpool);
2518a0dc95fSEric Van Hensbergen }
2528a0dc95fSEric Van Hensbergen 
2538a0dc95fSEric Van Hensbergen static void p9_mux_poll_stop(struct p9_conn *m)
2548a0dc95fSEric Van Hensbergen {
255992b3f1dSTejun Heo 	unsigned long flags;
2568a0dc95fSEric Van Hensbergen 	int i;
2578a0dc95fSEric Van Hensbergen 
258992b3f1dSTejun Heo 	for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) {
259992b3f1dSTejun Heo 		struct p9_poll_wait *pwait = &m->poll_wait[i];
260992b3f1dSTejun Heo 
261992b3f1dSTejun Heo 		if (pwait->wait_addr) {
262992b3f1dSTejun Heo 			remove_wait_queue(pwait->wait_addr, &pwait->wait);
263992b3f1dSTejun Heo 			pwait->wait_addr = NULL;
2648a0dc95fSEric Van Hensbergen 		}
2658a0dc95fSEric Van Hensbergen 	}
266992b3f1dSTejun Heo 
267992b3f1dSTejun Heo 	spin_lock_irqsave(&p9_poll_lock, flags);
268992b3f1dSTejun Heo 	list_del_init(&m->poll_pending_link);
269992b3f1dSTejun Heo 	spin_unlock_irqrestore(&p9_poll_lock, flags);
2708a0dc95fSEric Van Hensbergen }
2718a0dc95fSEric Van Hensbergen 
2728a0dc95fSEric Van Hensbergen /**
2738a0dc95fSEric Van Hensbergen  * p9_conn_create - allocate and initialize the per-session mux data
274ee443996SEric Van Hensbergen  * @trans: transport structure
2758a0dc95fSEric Van Hensbergen  *
276ee443996SEric Van Hensbergen  * Note: Creates the polling task if this is the first session.
2778a0dc95fSEric Van Hensbergen  */
278ee443996SEric Van Hensbergen 
2798a0dc95fSEric Van Hensbergen static struct p9_conn *p9_conn_create(struct p9_trans *trans)
2808a0dc95fSEric Van Hensbergen {
2818a0dc95fSEric Van Hensbergen 	int i, n;
282571ffeafSTejun Heo 	struct p9_conn *m;
2838a0dc95fSEric Van Hensbergen 
2848a0dc95fSEric Van Hensbergen 	P9_DPRINTK(P9_DEBUG_MUX, "transport %p msize %d\n", trans,
2858a0dc95fSEric Van Hensbergen 								trans->msize);
286571ffeafSTejun Heo 	m = kzalloc(sizeof(struct p9_conn), GFP_KERNEL);
2878a0dc95fSEric Van Hensbergen 	if (!m)
2888a0dc95fSEric Van Hensbergen 		return ERR_PTR(-ENOMEM);
2898a0dc95fSEric Van Hensbergen 
2908a0dc95fSEric Van Hensbergen 	spin_lock_init(&m->lock);
2918a0dc95fSEric Van Hensbergen 	INIT_LIST_HEAD(&m->mux_list);
2928a0dc95fSEric Van Hensbergen 	m->msize = trans->msize;
2938a0dc95fSEric Van Hensbergen 	m->extended = trans->extended;
2948a0dc95fSEric Van Hensbergen 	m->trans = trans;
2958a0dc95fSEric Van Hensbergen 	m->tagpool = p9_idpool_create();
2968a0dc95fSEric Van Hensbergen 	if (IS_ERR(m->tagpool)) {
2978a0dc95fSEric Van Hensbergen 		kfree(m);
298571ffeafSTejun Heo 		return ERR_PTR(-ENOMEM);
2998a0dc95fSEric Van Hensbergen 	}
3008a0dc95fSEric Van Hensbergen 
3018a0dc95fSEric Van Hensbergen 	INIT_LIST_HEAD(&m->req_list);
3028a0dc95fSEric Van Hensbergen 	INIT_LIST_HEAD(&m->unsent_req_list);
3038a0dc95fSEric Van Hensbergen 	INIT_WORK(&m->rq, p9_read_work);
3048a0dc95fSEric Van Hensbergen 	INIT_WORK(&m->wq, p9_write_work);
305992b3f1dSTejun Heo 	INIT_LIST_HEAD(&m->poll_pending_link);
306992b3f1dSTejun Heo 	init_poll_funcptr(&m->pt, p9_pollwait);
3078a0dc95fSEric Van Hensbergen 
3088a0dc95fSEric Van Hensbergen 	n = p9_fd_poll(trans, &m->pt);
3098a0dc95fSEric Van Hensbergen 	if (n & POLLIN) {
3108a0dc95fSEric Van Hensbergen 		P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m);
3118a0dc95fSEric Van Hensbergen 		set_bit(Rpending, &m->wsched);
3128a0dc95fSEric Van Hensbergen 	}
3138a0dc95fSEric Van Hensbergen 
3148a0dc95fSEric Van Hensbergen 	if (n & POLLOUT) {
3158a0dc95fSEric Van Hensbergen 		P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m);
3168a0dc95fSEric Van Hensbergen 		set_bit(Wpending, &m->wsched);
3178a0dc95fSEric Van Hensbergen 	}
3188a0dc95fSEric Van Hensbergen 
319992b3f1dSTejun Heo 	for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) {
320992b3f1dSTejun Heo 		if (IS_ERR(m->poll_wait[i].wait_addr)) {
3218a0dc95fSEric Van Hensbergen 			p9_mux_poll_stop(m);
3228a0dc95fSEric Van Hensbergen 			kfree(m);
323992b3f1dSTejun Heo 			/* return the error code */
324992b3f1dSTejun Heo 			return (void *)m->poll_wait[i].wait_addr;
3258a0dc95fSEric Van Hensbergen 		}
3268a0dc95fSEric Van Hensbergen 	}
3278a0dc95fSEric Van Hensbergen 
3288a0dc95fSEric Van Hensbergen 	return m;
3298a0dc95fSEric Van Hensbergen }
3308a0dc95fSEric Van Hensbergen 
3318a0dc95fSEric Van Hensbergen /**
3328a0dc95fSEric Van Hensbergen  * p9_mux_destroy - cancels all pending requests and frees mux resources
333ee443996SEric Van Hensbergen  * @m: mux to destroy
334ee443996SEric Van Hensbergen  *
3358a0dc95fSEric Van Hensbergen  */
336ee443996SEric Van Hensbergen 
3378a0dc95fSEric Van Hensbergen static void p9_conn_destroy(struct p9_conn *m)
3388a0dc95fSEric Van Hensbergen {
3398a0dc95fSEric Van Hensbergen 	P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m,
3408a0dc95fSEric Van Hensbergen 		m->mux_list.prev, m->mux_list.next);
3418a0dc95fSEric Van Hensbergen 
3428a0dc95fSEric Van Hensbergen 	p9_mux_poll_stop(m);
3437dc5d24bSTejun Heo 	cancel_work_sync(&m->rq);
3447dc5d24bSTejun Heo 	cancel_work_sync(&m->wq);
3457dc5d24bSTejun Heo 
3467dc5d24bSTejun Heo 	p9_conn_cancel(m, -ECONNRESET);
3477dc5d24bSTejun Heo 
3488a0dc95fSEric Van Hensbergen 	m->trans = NULL;
3498a0dc95fSEric Van Hensbergen 	p9_idpool_destroy(m->tagpool);
3508a0dc95fSEric Van Hensbergen 	kfree(m);
3518a0dc95fSEric Van Hensbergen }
3528a0dc95fSEric Van Hensbergen 
353992b3f1dSTejun Heo static int p9_pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
354992b3f1dSTejun Heo {
355992b3f1dSTejun Heo 	struct p9_poll_wait *pwait =
356992b3f1dSTejun Heo 		container_of(wait, struct p9_poll_wait, wait);
357992b3f1dSTejun Heo 	struct p9_conn *m = pwait->conn;
358992b3f1dSTejun Heo 	unsigned long flags;
359992b3f1dSTejun Heo 	DECLARE_WAITQUEUE(dummy_wait, p9_poll_task);
360992b3f1dSTejun Heo 
361992b3f1dSTejun Heo 	spin_lock_irqsave(&p9_poll_lock, flags);
362992b3f1dSTejun Heo 	if (list_empty(&m->poll_pending_link))
363992b3f1dSTejun Heo 		list_add_tail(&m->poll_pending_link, &p9_poll_pending_list);
364992b3f1dSTejun Heo 	spin_unlock_irqrestore(&p9_poll_lock, flags);
365992b3f1dSTejun Heo 
366992b3f1dSTejun Heo 	/* perform the default wake up operation */
367992b3f1dSTejun Heo 	return default_wake_function(&dummy_wait, mode, sync, key);
368992b3f1dSTejun Heo }
369992b3f1dSTejun Heo 
3708a0dc95fSEric Van Hensbergen /**
371ee443996SEric Van Hensbergen  * p9_pollwait - add poll task to the wait queue
372ee443996SEric Van Hensbergen  * @filp: file pointer being polled
373ee443996SEric Van Hensbergen  * @wait_address: wait_q to block on
374ee443996SEric Van Hensbergen  * @p: poll state
375ee443996SEric Van Hensbergen  *
376ee443996SEric Van Hensbergen  * called by files poll operation to add v9fs-poll task to files wait queue
3778a0dc95fSEric Van Hensbergen  */
378ee443996SEric Van Hensbergen 
3798a0dc95fSEric Van Hensbergen static void
3808a0dc95fSEric Van Hensbergen p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p)
3818a0dc95fSEric Van Hensbergen {
382992b3f1dSTejun Heo 	struct p9_conn *m = container_of(p, struct p9_conn, pt);
383992b3f1dSTejun Heo 	struct p9_poll_wait *pwait = NULL;
3848a0dc95fSEric Van Hensbergen 	int i;
3858a0dc95fSEric Van Hensbergen 
386992b3f1dSTejun Heo 	for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) {
387992b3f1dSTejun Heo 		if (m->poll_wait[i].wait_addr == NULL) {
388992b3f1dSTejun Heo 			pwait = &m->poll_wait[i];
3898a0dc95fSEric Van Hensbergen 			break;
390992b3f1dSTejun Heo 		}
391992b3f1dSTejun Heo 	}
3928a0dc95fSEric Van Hensbergen 
393992b3f1dSTejun Heo 	if (!pwait) {
3948a0dc95fSEric Van Hensbergen 		P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n");
3958a0dc95fSEric Van Hensbergen 		return;
3968a0dc95fSEric Van Hensbergen 	}
3978a0dc95fSEric Van Hensbergen 
3988a0dc95fSEric Van Hensbergen 	if (!wait_address) {
3998a0dc95fSEric Van Hensbergen 		P9_DPRINTK(P9_DEBUG_ERROR, "no wait_address\n");
400992b3f1dSTejun Heo 		pwait->wait_addr = ERR_PTR(-EIO);
4018a0dc95fSEric Van Hensbergen 		return;
4028a0dc95fSEric Van Hensbergen 	}
4038a0dc95fSEric Van Hensbergen 
404992b3f1dSTejun Heo 	pwait->conn = m;
405992b3f1dSTejun Heo 	pwait->wait_addr = wait_address;
406992b3f1dSTejun Heo 	init_waitqueue_func_entry(&pwait->wait, p9_pollwake);
407992b3f1dSTejun Heo 	add_wait_queue(wait_address, &pwait->wait);
4088a0dc95fSEric Van Hensbergen }
4098a0dc95fSEric Van Hensbergen 
4108a0dc95fSEric Van Hensbergen /**
4118a0dc95fSEric Van Hensbergen  * p9_poll_mux - polls a mux and schedules read or write works if necessary
412ee443996SEric Van Hensbergen  * @m: connection to poll
413ee443996SEric Van Hensbergen  *
4148a0dc95fSEric Van Hensbergen  */
415ee443996SEric Van Hensbergen 
4168a0dc95fSEric Van Hensbergen static void p9_poll_mux(struct p9_conn *m)
4178a0dc95fSEric Van Hensbergen {
4188a0dc95fSEric Van Hensbergen 	int n;
4198a0dc95fSEric Van Hensbergen 
4208a0dc95fSEric Van Hensbergen 	if (m->err < 0)
4218a0dc95fSEric Van Hensbergen 		return;
4228a0dc95fSEric Van Hensbergen 
4238a0dc95fSEric Van Hensbergen 	n = p9_fd_poll(m->trans, NULL);
4248a0dc95fSEric Van Hensbergen 	if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) {
4258a0dc95fSEric Van Hensbergen 		P9_DPRINTK(P9_DEBUG_MUX, "error mux %p err %d\n", m, n);
4268a0dc95fSEric Van Hensbergen 		if (n >= 0)
4278a0dc95fSEric Van Hensbergen 			n = -ECONNRESET;
4288a0dc95fSEric Van Hensbergen 		p9_conn_cancel(m, n);
4298a0dc95fSEric Van Hensbergen 	}
4308a0dc95fSEric Van Hensbergen 
4318a0dc95fSEric Van Hensbergen 	if (n & POLLIN) {
4328a0dc95fSEric Van Hensbergen 		set_bit(Rpending, &m->wsched);
4338a0dc95fSEric Van Hensbergen 		P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m);
4348a0dc95fSEric Van Hensbergen 		if (!test_and_set_bit(Rworksched, &m->wsched)) {
4358a0dc95fSEric Van Hensbergen 			P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m);
4368a0dc95fSEric Van Hensbergen 			queue_work(p9_mux_wq, &m->rq);
4378a0dc95fSEric Van Hensbergen 		}
4388a0dc95fSEric Van Hensbergen 	}
4398a0dc95fSEric Van Hensbergen 
4408a0dc95fSEric Van Hensbergen 	if (n & POLLOUT) {
4418a0dc95fSEric Van Hensbergen 		set_bit(Wpending, &m->wsched);
4428a0dc95fSEric Van Hensbergen 		P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m);
4438a0dc95fSEric Van Hensbergen 		if ((m->wsize || !list_empty(&m->unsent_req_list))
4448a0dc95fSEric Van Hensbergen 		    && !test_and_set_bit(Wworksched, &m->wsched)) {
4458a0dc95fSEric Van Hensbergen 			P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m);
4468a0dc95fSEric Van Hensbergen 			queue_work(p9_mux_wq, &m->wq);
4478a0dc95fSEric Van Hensbergen 		}
4488a0dc95fSEric Van Hensbergen 	}
4498a0dc95fSEric Van Hensbergen }
4508a0dc95fSEric Van Hensbergen 
4518a0dc95fSEric Van Hensbergen /**
452ee443996SEric Van Hensbergen  * p9_poll_proc - poll worker thread
453ee443996SEric Van Hensbergen  * @a: thread state and arguments
454ee443996SEric Van Hensbergen  *
455ee443996SEric Van Hensbergen  * polls all v9fs transports for new events and queues the appropriate
456ee443996SEric Van Hensbergen  * work to the work queue
457ee443996SEric Van Hensbergen  *
4588a0dc95fSEric Van Hensbergen  */
459ee443996SEric Van Hensbergen 
4608a0dc95fSEric Van Hensbergen static int p9_poll_proc(void *a)
4618a0dc95fSEric Van Hensbergen {
462992b3f1dSTejun Heo 	unsigned long flags;
4638a0dc95fSEric Van Hensbergen 
464992b3f1dSTejun Heo 	P9_DPRINTK(P9_DEBUG_MUX, "start %p\n", current);
465992b3f1dSTejun Heo  repeat:
466992b3f1dSTejun Heo 	spin_lock_irqsave(&p9_poll_lock, flags);
467992b3f1dSTejun Heo 	while (!list_empty(&p9_poll_pending_list)) {
468992b3f1dSTejun Heo 		struct p9_conn *conn = list_first_entry(&p9_poll_pending_list,
469992b3f1dSTejun Heo 							struct p9_conn,
470992b3f1dSTejun Heo 							poll_pending_link);
471992b3f1dSTejun Heo 		list_del_init(&conn->poll_pending_link);
472992b3f1dSTejun Heo 		spin_unlock_irqrestore(&p9_poll_lock, flags);
473992b3f1dSTejun Heo 
474992b3f1dSTejun Heo 		p9_poll_mux(conn);
475992b3f1dSTejun Heo 
476992b3f1dSTejun Heo 		spin_lock_irqsave(&p9_poll_lock, flags);
477992b3f1dSTejun Heo 	}
478992b3f1dSTejun Heo 	spin_unlock_irqrestore(&p9_poll_lock, flags);
479992b3f1dSTejun Heo 
4808a0dc95fSEric Van Hensbergen 	set_current_state(TASK_INTERRUPTIBLE);
481992b3f1dSTejun Heo 	if (list_empty(&p9_poll_pending_list)) {
4828a0dc95fSEric Van Hensbergen 		P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n");
483992b3f1dSTejun Heo 		schedule();
4848a0dc95fSEric Van Hensbergen 	}
4858a0dc95fSEric Van Hensbergen 	__set_current_state(TASK_RUNNING);
486992b3f1dSTejun Heo 
487992b3f1dSTejun Heo 	if (!kthread_should_stop())
488992b3f1dSTejun Heo 		goto repeat;
489992b3f1dSTejun Heo 
4908a0dc95fSEric Van Hensbergen 	P9_DPRINTK(P9_DEBUG_MUX, "finish\n");
4918a0dc95fSEric Van Hensbergen 	return 0;
4928a0dc95fSEric Van Hensbergen }
4938a0dc95fSEric Van Hensbergen 
4948a0dc95fSEric Van Hensbergen /**
4958a0dc95fSEric Van Hensbergen  * p9_write_work - called when a transport can send some data
496ee443996SEric Van Hensbergen  * @work: container for work to be done
497ee443996SEric Van Hensbergen  *
4988a0dc95fSEric Van Hensbergen  */
499ee443996SEric Van Hensbergen 
5008a0dc95fSEric Van Hensbergen static void p9_write_work(struct work_struct *work)
5018a0dc95fSEric Van Hensbergen {
5028a0dc95fSEric Van Hensbergen 	int n, err;
5038a0dc95fSEric Van Hensbergen 	struct p9_conn *m;
5048a0dc95fSEric Van Hensbergen 	struct p9_req *req;
5058a0dc95fSEric Van Hensbergen 
5068a0dc95fSEric Van Hensbergen 	m = container_of(work, struct p9_conn, wq);
5078a0dc95fSEric Van Hensbergen 
5088a0dc95fSEric Van Hensbergen 	if (m->err < 0) {
5098a0dc95fSEric Van Hensbergen 		clear_bit(Wworksched, &m->wsched);
5108a0dc95fSEric Van Hensbergen 		return;
5118a0dc95fSEric Van Hensbergen 	}
5128a0dc95fSEric Van Hensbergen 
5138a0dc95fSEric Van Hensbergen 	if (!m->wsize) {
5148a0dc95fSEric Van Hensbergen 		if (list_empty(&m->unsent_req_list)) {
5158a0dc95fSEric Van Hensbergen 			clear_bit(Wworksched, &m->wsched);
5168a0dc95fSEric Van Hensbergen 			return;
5178a0dc95fSEric Van Hensbergen 		}
5188a0dc95fSEric Van Hensbergen 
5198a0dc95fSEric Van Hensbergen 		spin_lock(&m->lock);
5208a0dc95fSEric Van Hensbergen again:
5218a0dc95fSEric Van Hensbergen 		req = list_entry(m->unsent_req_list.next, struct p9_req,
5228a0dc95fSEric Van Hensbergen 			       req_list);
5238a0dc95fSEric Van Hensbergen 		list_move_tail(&req->req_list, &m->req_list);
5248a0dc95fSEric Van Hensbergen 		if (req->err == ERREQFLUSH)
5258a0dc95fSEric Van Hensbergen 			goto again;
5268a0dc95fSEric Van Hensbergen 
5278a0dc95fSEric Van Hensbergen 		m->wbuf = req->tcall->sdata;
5288a0dc95fSEric Van Hensbergen 		m->wsize = req->tcall->size;
5298a0dc95fSEric Van Hensbergen 		m->wpos = 0;
5308a0dc95fSEric Van Hensbergen 		spin_unlock(&m->lock);
5318a0dc95fSEric Van Hensbergen 	}
5328a0dc95fSEric Van Hensbergen 
5338a0dc95fSEric Van Hensbergen 	P9_DPRINTK(P9_DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos,
5348a0dc95fSEric Van Hensbergen 								m->wsize);
5358a0dc95fSEric Van Hensbergen 	clear_bit(Wpending, &m->wsched);
5368a0dc95fSEric Van Hensbergen 	err = p9_fd_write(m->trans, m->wbuf + m->wpos, m->wsize - m->wpos);
5378a0dc95fSEric Van Hensbergen 	P9_DPRINTK(P9_DEBUG_MUX, "mux %p sent %d bytes\n", m, err);
5388a0dc95fSEric Van Hensbergen 	if (err == -EAGAIN) {
5398a0dc95fSEric Van Hensbergen 		clear_bit(Wworksched, &m->wsched);
5408a0dc95fSEric Van Hensbergen 		return;
5418a0dc95fSEric Van Hensbergen 	}
5428a0dc95fSEric Van Hensbergen 
5438a0dc95fSEric Van Hensbergen 	if (err < 0)
5448a0dc95fSEric Van Hensbergen 		goto error;
5458a0dc95fSEric Van Hensbergen 	else if (err == 0) {
5468a0dc95fSEric Van Hensbergen 		err = -EREMOTEIO;
5478a0dc95fSEric Van Hensbergen 		goto error;
5488a0dc95fSEric Van Hensbergen 	}
5498a0dc95fSEric Van Hensbergen 
5508a0dc95fSEric Van Hensbergen 	m->wpos += err;
5518a0dc95fSEric Van Hensbergen 	if (m->wpos == m->wsize)
5528a0dc95fSEric Van Hensbergen 		m->wpos = m->wsize = 0;
5538a0dc95fSEric Van Hensbergen 
5548a0dc95fSEric Van Hensbergen 	if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) {
5558a0dc95fSEric Van Hensbergen 		if (test_and_clear_bit(Wpending, &m->wsched))
5568a0dc95fSEric Van Hensbergen 			n = POLLOUT;
5578a0dc95fSEric Van Hensbergen 		else
5588a0dc95fSEric Van Hensbergen 			n = p9_fd_poll(m->trans, NULL);
5598a0dc95fSEric Van Hensbergen 
5608a0dc95fSEric Van Hensbergen 		if (n & POLLOUT) {
5618a0dc95fSEric Van Hensbergen 			P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m);
5628a0dc95fSEric Van Hensbergen 			queue_work(p9_mux_wq, &m->wq);
5638a0dc95fSEric Van Hensbergen 		} else
5648a0dc95fSEric Van Hensbergen 			clear_bit(Wworksched, &m->wsched);
5658a0dc95fSEric Van Hensbergen 	} else
5668a0dc95fSEric Van Hensbergen 		clear_bit(Wworksched, &m->wsched);
5678a0dc95fSEric Van Hensbergen 
5688a0dc95fSEric Van Hensbergen 	return;
5698a0dc95fSEric Van Hensbergen 
5708a0dc95fSEric Van Hensbergen error:
5718a0dc95fSEric Van Hensbergen 	p9_conn_cancel(m, err);
5728a0dc95fSEric Van Hensbergen 	clear_bit(Wworksched, &m->wsched);
5738a0dc95fSEric Van Hensbergen }
5748a0dc95fSEric Van Hensbergen 
5758a0dc95fSEric Van Hensbergen static void process_request(struct p9_conn *m, struct p9_req *req)
5768a0dc95fSEric Van Hensbergen {
5778a0dc95fSEric Van Hensbergen 	int ecode;
5788a0dc95fSEric Van Hensbergen 	struct p9_str *ename;
5798a0dc95fSEric Van Hensbergen 
5808a0dc95fSEric Van Hensbergen 	if (!req->err && req->rcall->id == P9_RERROR) {
5818a0dc95fSEric Van Hensbergen 		ecode = req->rcall->params.rerror.errno;
5828a0dc95fSEric Van Hensbergen 		ename = &req->rcall->params.rerror.error;
5838a0dc95fSEric Van Hensbergen 
5848a0dc95fSEric Van Hensbergen 		P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len,
5858a0dc95fSEric Van Hensbergen 								ename->str);
5868a0dc95fSEric Van Hensbergen 
5878a0dc95fSEric Van Hensbergen 		if (m->extended)
5888a0dc95fSEric Van Hensbergen 			req->err = -ecode;
5898a0dc95fSEric Van Hensbergen 
5908a0dc95fSEric Van Hensbergen 		if (!req->err) {
5918a0dc95fSEric Van Hensbergen 			req->err = p9_errstr2errno(ename->str, ename->len);
5928a0dc95fSEric Van Hensbergen 
5938a0dc95fSEric Van Hensbergen 			/* string match failed */
5948a0dc95fSEric Van Hensbergen 			if (!req->err) {
5958a0dc95fSEric Van Hensbergen 				PRINT_FCALL_ERROR("unknown error", req->rcall);
5968a0dc95fSEric Van Hensbergen 				req->err = -ESERVERFAULT;
5978a0dc95fSEric Van Hensbergen 			}
5988a0dc95fSEric Van Hensbergen 		}
5998a0dc95fSEric Van Hensbergen 	} else if (req->tcall && req->rcall->id != req->tcall->id + 1) {
6008a0dc95fSEric Van Hensbergen 		P9_DPRINTK(P9_DEBUG_ERROR,
6018a0dc95fSEric Van Hensbergen 				"fcall mismatch: expected %d, got %d\n",
6028a0dc95fSEric Van Hensbergen 				req->tcall->id + 1, req->rcall->id);
6038a0dc95fSEric Van Hensbergen 		if (!req->err)
6048a0dc95fSEric Van Hensbergen 			req->err = -EIO;
6058a0dc95fSEric Van Hensbergen 	}
6068a0dc95fSEric Van Hensbergen }
6078a0dc95fSEric Van Hensbergen 
6088a0dc95fSEric Van Hensbergen /**
6098a0dc95fSEric Van Hensbergen  * p9_read_work - called when there is some data to be read from a transport
610ee443996SEric Van Hensbergen  * @work: container of work to be done
611ee443996SEric Van Hensbergen  *
6128a0dc95fSEric Van Hensbergen  */
613ee443996SEric Van Hensbergen 
6148a0dc95fSEric Van Hensbergen static void p9_read_work(struct work_struct *work)
6158a0dc95fSEric Van Hensbergen {
6168a0dc95fSEric Van Hensbergen 	int n, err;
6178a0dc95fSEric Van Hensbergen 	struct p9_conn *m;
6188a0dc95fSEric Van Hensbergen 	struct p9_req *req, *rptr, *rreq;
6198a0dc95fSEric Van Hensbergen 	struct p9_fcall *rcall;
6208a0dc95fSEric Van Hensbergen 	char *rbuf;
6218a0dc95fSEric Van Hensbergen 
6228a0dc95fSEric Van Hensbergen 	m = container_of(work, struct p9_conn, rq);
6238a0dc95fSEric Van Hensbergen 
6248a0dc95fSEric Van Hensbergen 	if (m->err < 0)
6258a0dc95fSEric Van Hensbergen 		return;
6268a0dc95fSEric Van Hensbergen 
6278a0dc95fSEric Van Hensbergen 	rcall = NULL;
6288a0dc95fSEric Van Hensbergen 	P9_DPRINTK(P9_DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos);
6298a0dc95fSEric Van Hensbergen 
6308a0dc95fSEric Van Hensbergen 	if (!m->rcall) {
6318a0dc95fSEric Van Hensbergen 		m->rcall =
6328a0dc95fSEric Van Hensbergen 		    kmalloc(sizeof(struct p9_fcall) + m->msize, GFP_KERNEL);
6338a0dc95fSEric Van Hensbergen 		if (!m->rcall) {
6348a0dc95fSEric Van Hensbergen 			err = -ENOMEM;
6358a0dc95fSEric Van Hensbergen 			goto error;
6368a0dc95fSEric Van Hensbergen 		}
6378a0dc95fSEric Van Hensbergen 
6388a0dc95fSEric Van Hensbergen 		m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall);
6398a0dc95fSEric Van Hensbergen 		m->rpos = 0;
6408a0dc95fSEric Van Hensbergen 	}
6418a0dc95fSEric Van Hensbergen 
6428a0dc95fSEric Van Hensbergen 	clear_bit(Rpending, &m->wsched);
6438a0dc95fSEric Van Hensbergen 	err = p9_fd_read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos);
6448a0dc95fSEric Van Hensbergen 	P9_DPRINTK(P9_DEBUG_MUX, "mux %p got %d bytes\n", m, err);
6458a0dc95fSEric Van Hensbergen 	if (err == -EAGAIN) {
6468a0dc95fSEric Van Hensbergen 		clear_bit(Rworksched, &m->wsched);
6478a0dc95fSEric Van Hensbergen 		return;
6488a0dc95fSEric Van Hensbergen 	}
6498a0dc95fSEric Van Hensbergen 
6508a0dc95fSEric Van Hensbergen 	if (err <= 0)
6518a0dc95fSEric Van Hensbergen 		goto error;
6528a0dc95fSEric Van Hensbergen 
6538a0dc95fSEric Van Hensbergen 	m->rpos += err;
6548a0dc95fSEric Van Hensbergen 	while (m->rpos > 4) {
6558a0dc95fSEric Van Hensbergen 		n = le32_to_cpu(*(__le32 *) m->rbuf);
6568a0dc95fSEric Van Hensbergen 		if (n >= m->msize) {
6578a0dc95fSEric Van Hensbergen 			P9_DPRINTK(P9_DEBUG_ERROR,
6588a0dc95fSEric Van Hensbergen 				"requested packet size too big: %d\n", n);
6598a0dc95fSEric Van Hensbergen 			err = -EIO;
6608a0dc95fSEric Van Hensbergen 			goto error;
6618a0dc95fSEric Van Hensbergen 		}
6628a0dc95fSEric Van Hensbergen 
6638a0dc95fSEric Van Hensbergen 		if (m->rpos < n)
6648a0dc95fSEric Van Hensbergen 			break;
6658a0dc95fSEric Van Hensbergen 
6668a0dc95fSEric Van Hensbergen 		err =
6678a0dc95fSEric Van Hensbergen 		    p9_deserialize_fcall(m->rbuf, n, m->rcall, m->extended);
6688a0dc95fSEric Van Hensbergen 		if (err < 0)
6698a0dc95fSEric Van Hensbergen 			goto error;
6708a0dc95fSEric Van Hensbergen 
6718a0dc95fSEric Van Hensbergen #ifdef CONFIG_NET_9P_DEBUG
6728a0dc95fSEric Van Hensbergen 		if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
6738a0dc95fSEric Van Hensbergen 			char buf[150];
6748a0dc95fSEric Van Hensbergen 
6758a0dc95fSEric Van Hensbergen 			p9_printfcall(buf, sizeof(buf), m->rcall,
6768a0dc95fSEric Van Hensbergen 				m->extended);
6778a0dc95fSEric Van Hensbergen 			printk(KERN_NOTICE ">>> %p %s\n", m, buf);
6788a0dc95fSEric Van Hensbergen 		}
6798a0dc95fSEric Van Hensbergen #endif
6808a0dc95fSEric Van Hensbergen 
6818a0dc95fSEric Van Hensbergen 		rcall = m->rcall;
6828a0dc95fSEric Van Hensbergen 		rbuf = m->rbuf;
6838a0dc95fSEric Van Hensbergen 		if (m->rpos > n) {
6848a0dc95fSEric Van Hensbergen 			m->rcall = kmalloc(sizeof(struct p9_fcall) + m->msize,
6858a0dc95fSEric Van Hensbergen 					   GFP_KERNEL);
6868a0dc95fSEric Van Hensbergen 			if (!m->rcall) {
6878a0dc95fSEric Van Hensbergen 				err = -ENOMEM;
6888a0dc95fSEric Van Hensbergen 				goto error;
6898a0dc95fSEric Van Hensbergen 			}
6908a0dc95fSEric Van Hensbergen 
6918a0dc95fSEric Van Hensbergen 			m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall);
6928a0dc95fSEric Van Hensbergen 			memmove(m->rbuf, rbuf + n, m->rpos - n);
6938a0dc95fSEric Van Hensbergen 			m->rpos -= n;
6948a0dc95fSEric Van Hensbergen 		} else {
6958a0dc95fSEric Van Hensbergen 			m->rcall = NULL;
6968a0dc95fSEric Van Hensbergen 			m->rbuf = NULL;
6978a0dc95fSEric Van Hensbergen 			m->rpos = 0;
6988a0dc95fSEric Van Hensbergen 		}
6998a0dc95fSEric Van Hensbergen 
7008a0dc95fSEric Van Hensbergen 		P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m,
7018a0dc95fSEric Van Hensbergen 							rcall->id, rcall->tag);
7028a0dc95fSEric Van Hensbergen 
7038a0dc95fSEric Van Hensbergen 		req = NULL;
7048a0dc95fSEric Van Hensbergen 		spin_lock(&m->lock);
7058a0dc95fSEric Van Hensbergen 		list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) {
7068a0dc95fSEric Van Hensbergen 			if (rreq->tag == rcall->tag) {
7078a0dc95fSEric Van Hensbergen 				req = rreq;
7088a0dc95fSEric Van Hensbergen 				if (req->flush != Flushing)
7098a0dc95fSEric Van Hensbergen 					list_del(&req->req_list);
7108a0dc95fSEric Van Hensbergen 				break;
7118a0dc95fSEric Van Hensbergen 			}
7128a0dc95fSEric Van Hensbergen 		}
7138a0dc95fSEric Van Hensbergen 		spin_unlock(&m->lock);
7148a0dc95fSEric Van Hensbergen 
7158a0dc95fSEric Van Hensbergen 		if (req) {
7168a0dc95fSEric Van Hensbergen 			req->rcall = rcall;
7178a0dc95fSEric Van Hensbergen 			process_request(m, req);
7188a0dc95fSEric Van Hensbergen 
7198a0dc95fSEric Van Hensbergen 			if (req->flush != Flushing) {
7208a0dc95fSEric Van Hensbergen 				if (req->cb)
7218a0dc95fSEric Van Hensbergen 					(*req->cb) (req, req->cba);
7228a0dc95fSEric Van Hensbergen 				else
7238a0dc95fSEric Van Hensbergen 					kfree(req->rcall);
7248a0dc95fSEric Van Hensbergen 			}
7258a0dc95fSEric Van Hensbergen 		} else {
7268a0dc95fSEric Van Hensbergen 			if (err >= 0 && rcall->id != P9_RFLUSH)
7278a0dc95fSEric Van Hensbergen 				P9_DPRINTK(P9_DEBUG_ERROR,
7288a0dc95fSEric Van Hensbergen 				  "unexpected response mux %p id %d tag %d\n",
7298a0dc95fSEric Van Hensbergen 				  m, rcall->id, rcall->tag);
7308a0dc95fSEric Van Hensbergen 			kfree(rcall);
7318a0dc95fSEric Van Hensbergen 		}
7328a0dc95fSEric Van Hensbergen 	}
7338a0dc95fSEric Van Hensbergen 
7348a0dc95fSEric Van Hensbergen 	if (!list_empty(&m->req_list)) {
7358a0dc95fSEric Van Hensbergen 		if (test_and_clear_bit(Rpending, &m->wsched))
7368a0dc95fSEric Van Hensbergen 			n = POLLIN;
7378a0dc95fSEric Van Hensbergen 		else
7388a0dc95fSEric Van Hensbergen 			n = p9_fd_poll(m->trans, NULL);
7398a0dc95fSEric Van Hensbergen 
7408a0dc95fSEric Van Hensbergen 		if (n & POLLIN) {
7418a0dc95fSEric Van Hensbergen 			P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m);
7428a0dc95fSEric Van Hensbergen 			queue_work(p9_mux_wq, &m->rq);
7438a0dc95fSEric Van Hensbergen 		} else
7448a0dc95fSEric Van Hensbergen 			clear_bit(Rworksched, &m->wsched);
7458a0dc95fSEric Van Hensbergen 	} else
7468a0dc95fSEric Van Hensbergen 		clear_bit(Rworksched, &m->wsched);
7478a0dc95fSEric Van Hensbergen 
7488a0dc95fSEric Van Hensbergen 	return;
7498a0dc95fSEric Van Hensbergen 
7508a0dc95fSEric Van Hensbergen error:
7518a0dc95fSEric Van Hensbergen 	p9_conn_cancel(m, err);
7528a0dc95fSEric Van Hensbergen 	clear_bit(Rworksched, &m->wsched);
7538a0dc95fSEric Van Hensbergen }
7548a0dc95fSEric Van Hensbergen 
7558a0dc95fSEric Van Hensbergen /**
7568a0dc95fSEric Van Hensbergen  * p9_send_request - send 9P request
7578a0dc95fSEric Van Hensbergen  * The function can sleep until the request is scheduled for sending.
7588a0dc95fSEric Van Hensbergen  * The function can be interrupted. Return from the function is not
7598a0dc95fSEric Van Hensbergen  * a guarantee that the request is sent successfully. Can return errors
7608a0dc95fSEric Van Hensbergen  * that can be retrieved by PTR_ERR macros.
7618a0dc95fSEric Van Hensbergen  *
7628a0dc95fSEric Van Hensbergen  * @m: mux data
7638a0dc95fSEric Van Hensbergen  * @tc: request to be sent
7648a0dc95fSEric Van Hensbergen  * @cb: callback function to call when response is received
7658a0dc95fSEric Van Hensbergen  * @cba: parameter to pass to the callback function
766ee443996SEric Van Hensbergen  *
7678a0dc95fSEric Van Hensbergen  */
768ee443996SEric Van Hensbergen 
7698a0dc95fSEric Van Hensbergen static struct p9_req *p9_send_request(struct p9_conn *m,
7708a0dc95fSEric Van Hensbergen 					  struct p9_fcall *tc,
7718a0dc95fSEric Van Hensbergen 					  p9_conn_req_callback cb, void *cba)
7728a0dc95fSEric Van Hensbergen {
7738a0dc95fSEric Van Hensbergen 	int n;
7748a0dc95fSEric Van Hensbergen 	struct p9_req *req;
7758a0dc95fSEric Van Hensbergen 
7768a0dc95fSEric Van Hensbergen 	P9_DPRINTK(P9_DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current,
7778a0dc95fSEric Van Hensbergen 		tc, tc->id);
7788a0dc95fSEric Van Hensbergen 	if (m->err < 0)
7798a0dc95fSEric Van Hensbergen 		return ERR_PTR(m->err);
7808a0dc95fSEric Van Hensbergen 
7818a0dc95fSEric Van Hensbergen 	req = kmalloc(sizeof(struct p9_req), GFP_KERNEL);
7828a0dc95fSEric Van Hensbergen 	if (!req)
7838a0dc95fSEric Van Hensbergen 		return ERR_PTR(-ENOMEM);
7848a0dc95fSEric Van Hensbergen 
7858a0dc95fSEric Van Hensbergen 	if (tc->id == P9_TVERSION)
7868a0dc95fSEric Van Hensbergen 		n = P9_NOTAG;
7878a0dc95fSEric Van Hensbergen 	else
7888a0dc95fSEric Van Hensbergen 		n = p9_mux_get_tag(m);
7898a0dc95fSEric Van Hensbergen 
79062067824SJulia Lawall 	if (n < 0) {
79162067824SJulia Lawall 		kfree(req);
7928a0dc95fSEric Van Hensbergen 		return ERR_PTR(-ENOMEM);
79362067824SJulia Lawall 	}
7948a0dc95fSEric Van Hensbergen 
7958a0dc95fSEric Van Hensbergen 	p9_set_tag(tc, n);
7968a0dc95fSEric Van Hensbergen 
7978a0dc95fSEric Van Hensbergen #ifdef CONFIG_NET_9P_DEBUG
7988a0dc95fSEric Van Hensbergen 	if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
7998a0dc95fSEric Van Hensbergen 		char buf[150];
8008a0dc95fSEric Van Hensbergen 
8018a0dc95fSEric Van Hensbergen 		p9_printfcall(buf, sizeof(buf), tc, m->extended);
8028a0dc95fSEric Van Hensbergen 		printk(KERN_NOTICE "<<< %p %s\n", m, buf);
8038a0dc95fSEric Van Hensbergen 	}
8048a0dc95fSEric Van Hensbergen #endif
8058a0dc95fSEric Van Hensbergen 
8068a0dc95fSEric Van Hensbergen 	spin_lock_init(&req->lock);
8078a0dc95fSEric Van Hensbergen 	req->tag = n;
8088a0dc95fSEric Van Hensbergen 	req->tcall = tc;
8098a0dc95fSEric Van Hensbergen 	req->rcall = NULL;
8108a0dc95fSEric Van Hensbergen 	req->err = 0;
8118a0dc95fSEric Van Hensbergen 	req->cb = cb;
8128a0dc95fSEric Van Hensbergen 	req->cba = cba;
8138a0dc95fSEric Van Hensbergen 	req->flush = None;
8148a0dc95fSEric Van Hensbergen 
8158a0dc95fSEric Van Hensbergen 	spin_lock(&m->lock);
8168a0dc95fSEric Van Hensbergen 	list_add_tail(&req->req_list, &m->unsent_req_list);
8178a0dc95fSEric Van Hensbergen 	spin_unlock(&m->lock);
8188a0dc95fSEric Van Hensbergen 
8198a0dc95fSEric Van Hensbergen 	if (test_and_clear_bit(Wpending, &m->wsched))
8208a0dc95fSEric Van Hensbergen 		n = POLLOUT;
8218a0dc95fSEric Van Hensbergen 	else
8228a0dc95fSEric Van Hensbergen 		n = p9_fd_poll(m->trans, NULL);
8238a0dc95fSEric Van Hensbergen 
8248a0dc95fSEric Van Hensbergen 	if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched))
8258a0dc95fSEric Van Hensbergen 		queue_work(p9_mux_wq, &m->wq);
8268a0dc95fSEric Van Hensbergen 
8278a0dc95fSEric Van Hensbergen 	return req;
8288a0dc95fSEric Van Hensbergen }
8298a0dc95fSEric Van Hensbergen 
8308a0dc95fSEric Van Hensbergen static void p9_mux_free_request(struct p9_conn *m, struct p9_req *req)
8318a0dc95fSEric Van Hensbergen {
8328a0dc95fSEric Van Hensbergen 	p9_mux_put_tag(m, req->tag);
8338a0dc95fSEric Van Hensbergen 	kfree(req);
8348a0dc95fSEric Van Hensbergen }
8358a0dc95fSEric Van Hensbergen 
8368a0dc95fSEric Van Hensbergen static void p9_mux_flush_cb(struct p9_req *freq, void *a)
8378a0dc95fSEric Van Hensbergen {
8388a0dc95fSEric Van Hensbergen 	int tag;
8398a0dc95fSEric Van Hensbergen 	struct p9_conn *m;
8408a0dc95fSEric Van Hensbergen 	struct p9_req *req, *rreq, *rptr;
8418a0dc95fSEric Van Hensbergen 
8428a0dc95fSEric Van Hensbergen 	m = a;
8438a0dc95fSEric Van Hensbergen 	P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m,
8448a0dc95fSEric Van Hensbergen 		freq->tcall, freq->rcall, freq->err,
8458a0dc95fSEric Van Hensbergen 		freq->tcall->params.tflush.oldtag);
8468a0dc95fSEric Van Hensbergen 
8478a0dc95fSEric Van Hensbergen 	spin_lock(&m->lock);
8488a0dc95fSEric Van Hensbergen 	tag = freq->tcall->params.tflush.oldtag;
8498a0dc95fSEric Van Hensbergen 	req = NULL;
8508a0dc95fSEric Van Hensbergen 	list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) {
8518a0dc95fSEric Van Hensbergen 		if (rreq->tag == tag) {
8528a0dc95fSEric Van Hensbergen 			req = rreq;
8538a0dc95fSEric Van Hensbergen 			list_del(&req->req_list);
8548a0dc95fSEric Van Hensbergen 			break;
8558a0dc95fSEric Van Hensbergen 		}
8568a0dc95fSEric Van Hensbergen 	}
8578a0dc95fSEric Van Hensbergen 	spin_unlock(&m->lock);
8588a0dc95fSEric Van Hensbergen 
8598a0dc95fSEric Van Hensbergen 	if (req) {
8608a0dc95fSEric Van Hensbergen 		spin_lock(&req->lock);
8618a0dc95fSEric Van Hensbergen 		req->flush = Flushed;
8628a0dc95fSEric Van Hensbergen 		spin_unlock(&req->lock);
8638a0dc95fSEric Van Hensbergen 
8648a0dc95fSEric Van Hensbergen 		if (req->cb)
8658a0dc95fSEric Van Hensbergen 			(*req->cb) (req, req->cba);
8668a0dc95fSEric Van Hensbergen 		else
8678a0dc95fSEric Van Hensbergen 			kfree(req->rcall);
8688a0dc95fSEric Van Hensbergen 	}
8698a0dc95fSEric Van Hensbergen 
8708a0dc95fSEric Van Hensbergen 	kfree(freq->tcall);
8718a0dc95fSEric Van Hensbergen 	kfree(freq->rcall);
8728a0dc95fSEric Van Hensbergen 	p9_mux_free_request(m, freq);
8738a0dc95fSEric Van Hensbergen }
8748a0dc95fSEric Van Hensbergen 
8758a0dc95fSEric Van Hensbergen static int
8768a0dc95fSEric Van Hensbergen p9_mux_flush_request(struct p9_conn *m, struct p9_req *req)
8778a0dc95fSEric Van Hensbergen {
8788a0dc95fSEric Van Hensbergen 	struct p9_fcall *fc;
8798a0dc95fSEric Van Hensbergen 	struct p9_req *rreq, *rptr;
8808a0dc95fSEric Van Hensbergen 
8818a0dc95fSEric Van Hensbergen 	P9_DPRINTK(P9_DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag);
8828a0dc95fSEric Van Hensbergen 
8838a0dc95fSEric Van Hensbergen 	/* if a response was received for a request, do nothing */
8848a0dc95fSEric Van Hensbergen 	spin_lock(&req->lock);
8858a0dc95fSEric Van Hensbergen 	if (req->rcall || req->err) {
8868a0dc95fSEric Van Hensbergen 		spin_unlock(&req->lock);
8878a0dc95fSEric Van Hensbergen 		P9_DPRINTK(P9_DEBUG_MUX,
8888a0dc95fSEric Van Hensbergen 			"mux %p req %p response already received\n", m, req);
8898a0dc95fSEric Van Hensbergen 		return 0;
8908a0dc95fSEric Van Hensbergen 	}
8918a0dc95fSEric Van Hensbergen 
8928a0dc95fSEric Van Hensbergen 	req->flush = Flushing;
8938a0dc95fSEric Van Hensbergen 	spin_unlock(&req->lock);
8948a0dc95fSEric Van Hensbergen 
8958a0dc95fSEric Van Hensbergen 	spin_lock(&m->lock);
8968a0dc95fSEric Van Hensbergen 	/* if the request is not sent yet, just remove it from the list */
8978a0dc95fSEric Van Hensbergen 	list_for_each_entry_safe(rreq, rptr, &m->unsent_req_list, req_list) {
8988a0dc95fSEric Van Hensbergen 		if (rreq->tag == req->tag) {
8998a0dc95fSEric Van Hensbergen 			P9_DPRINTK(P9_DEBUG_MUX,
9008a0dc95fSEric Van Hensbergen 			   "mux %p req %p request is not sent yet\n", m, req);
9018a0dc95fSEric Van Hensbergen 			list_del(&rreq->req_list);
9028a0dc95fSEric Van Hensbergen 			req->flush = Flushed;
9038a0dc95fSEric Van Hensbergen 			spin_unlock(&m->lock);
9048a0dc95fSEric Van Hensbergen 			if (req->cb)
9058a0dc95fSEric Van Hensbergen 				(*req->cb) (req, req->cba);
9068a0dc95fSEric Van Hensbergen 			return 0;
9078a0dc95fSEric Van Hensbergen 		}
9088a0dc95fSEric Van Hensbergen 	}
9098a0dc95fSEric Van Hensbergen 	spin_unlock(&m->lock);
9108a0dc95fSEric Van Hensbergen 
9118a0dc95fSEric Van Hensbergen 	clear_thread_flag(TIF_SIGPENDING);
9128a0dc95fSEric Van Hensbergen 	fc = p9_create_tflush(req->tag);
9138a0dc95fSEric Van Hensbergen 	p9_send_request(m, fc, p9_mux_flush_cb, m);
9148a0dc95fSEric Van Hensbergen 	return 1;
9158a0dc95fSEric Van Hensbergen }
9168a0dc95fSEric Van Hensbergen 
9178a0dc95fSEric Van Hensbergen static void
9188a0dc95fSEric Van Hensbergen p9_conn_rpc_cb(struct p9_req *req, void *a)
9198a0dc95fSEric Van Hensbergen {
9208a0dc95fSEric Van Hensbergen 	struct p9_mux_rpc *r;
9218a0dc95fSEric Van Hensbergen 
9228a0dc95fSEric Van Hensbergen 	P9_DPRINTK(P9_DEBUG_MUX, "req %p r %p\n", req, a);
9238a0dc95fSEric Van Hensbergen 	r = a;
9248a0dc95fSEric Van Hensbergen 	r->rcall = req->rcall;
9258a0dc95fSEric Van Hensbergen 	r->err = req->err;
9268a0dc95fSEric Van Hensbergen 
9278a0dc95fSEric Van Hensbergen 	if (req->flush != None && !req->err)
9288a0dc95fSEric Van Hensbergen 		r->err = -ERESTARTSYS;
9298a0dc95fSEric Van Hensbergen 
9308a0dc95fSEric Van Hensbergen 	wake_up(&r->wqueue);
9318a0dc95fSEric Van Hensbergen }
9328a0dc95fSEric Van Hensbergen 
9338a0dc95fSEric Van Hensbergen /**
9348a0dc95fSEric Van Hensbergen  * p9_fd_rpc- sends 9P request and waits until a response is available.
9358a0dc95fSEric Van Hensbergen  *	The function can be interrupted.
936ee443996SEric Van Hensbergen  * @t: transport data
9378a0dc95fSEric Van Hensbergen  * @tc: request to be sent
9388a0dc95fSEric Van Hensbergen  * @rc: pointer where a pointer to the response is stored
939ee443996SEric Van Hensbergen  *
9408a0dc95fSEric Van Hensbergen  */
941ee443996SEric Van Hensbergen 
9428a0dc95fSEric Van Hensbergen int
9438a0dc95fSEric Van Hensbergen p9_fd_rpc(struct p9_trans *t, struct p9_fcall *tc, struct p9_fcall **rc)
9448a0dc95fSEric Van Hensbergen {
9458a0dc95fSEric Van Hensbergen 	struct p9_trans_fd *p = t->priv;
9468a0dc95fSEric Van Hensbergen 	struct p9_conn *m = p->conn;
9478a0dc95fSEric Van Hensbergen 	int err, sigpending;
9488a0dc95fSEric Van Hensbergen 	unsigned long flags;
9498a0dc95fSEric Van Hensbergen 	struct p9_req *req;
9508a0dc95fSEric Van Hensbergen 	struct p9_mux_rpc r;
9518a0dc95fSEric Van Hensbergen 
9528a0dc95fSEric Van Hensbergen 	r.err = 0;
9538a0dc95fSEric Van Hensbergen 	r.tcall = tc;
9548a0dc95fSEric Van Hensbergen 	r.rcall = NULL;
9558a0dc95fSEric Van Hensbergen 	r.m = m;
9568a0dc95fSEric Van Hensbergen 	init_waitqueue_head(&r.wqueue);
9578a0dc95fSEric Van Hensbergen 
9588a0dc95fSEric Van Hensbergen 	if (rc)
9598a0dc95fSEric Van Hensbergen 		*rc = NULL;
9608a0dc95fSEric Van Hensbergen 
9618a0dc95fSEric Van Hensbergen 	sigpending = 0;
9628a0dc95fSEric Van Hensbergen 	if (signal_pending(current)) {
9638a0dc95fSEric Van Hensbergen 		sigpending = 1;
9648a0dc95fSEric Van Hensbergen 		clear_thread_flag(TIF_SIGPENDING);
9658a0dc95fSEric Van Hensbergen 	}
9668a0dc95fSEric Van Hensbergen 
9678a0dc95fSEric Van Hensbergen 	req = p9_send_request(m, tc, p9_conn_rpc_cb, &r);
9688a0dc95fSEric Van Hensbergen 	if (IS_ERR(req)) {
9698a0dc95fSEric Van Hensbergen 		err = PTR_ERR(req);
9708a0dc95fSEric Van Hensbergen 		P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err);
9718a0dc95fSEric Van Hensbergen 		return err;
9728a0dc95fSEric Van Hensbergen 	}
9738a0dc95fSEric Van Hensbergen 
9748a0dc95fSEric Van Hensbergen 	err = wait_event_interruptible(r.wqueue, r.rcall != NULL || r.err < 0);
9758a0dc95fSEric Van Hensbergen 	if (r.err < 0)
9768a0dc95fSEric Van Hensbergen 		err = r.err;
9778a0dc95fSEric Van Hensbergen 
9788a0dc95fSEric Van Hensbergen 	if (err == -ERESTARTSYS && m->trans->status == Connected
9798a0dc95fSEric Van Hensbergen 							&& m->err == 0) {
9808a0dc95fSEric Van Hensbergen 		if (p9_mux_flush_request(m, req)) {
9818a0dc95fSEric Van Hensbergen 			/* wait until we get response of the flush message */
9828a0dc95fSEric Van Hensbergen 			do {
9838a0dc95fSEric Van Hensbergen 				clear_thread_flag(TIF_SIGPENDING);
9848a0dc95fSEric Van Hensbergen 				err = wait_event_interruptible(r.wqueue,
9858a0dc95fSEric Van Hensbergen 					r.rcall || r.err);
9868a0dc95fSEric Van Hensbergen 			} while (!r.rcall && !r.err && err == -ERESTARTSYS &&
9878a0dc95fSEric Van Hensbergen 				m->trans->status == Connected && !m->err);
9888a0dc95fSEric Van Hensbergen 
9898a0dc95fSEric Van Hensbergen 			err = -ERESTARTSYS;
9908a0dc95fSEric Van Hensbergen 		}
9918a0dc95fSEric Van Hensbergen 		sigpending = 1;
9928a0dc95fSEric Van Hensbergen 	}
9938a0dc95fSEric Van Hensbergen 
9948a0dc95fSEric Van Hensbergen 	if (sigpending) {
9958a0dc95fSEric Van Hensbergen 		spin_lock_irqsave(&current->sighand->siglock, flags);
9968a0dc95fSEric Van Hensbergen 		recalc_sigpending();
9978a0dc95fSEric Van Hensbergen 		spin_unlock_irqrestore(&current->sighand->siglock, flags);
9988a0dc95fSEric Van Hensbergen 	}
9998a0dc95fSEric Van Hensbergen 
10008a0dc95fSEric Van Hensbergen 	if (rc)
10018a0dc95fSEric Van Hensbergen 		*rc = r.rcall;
10028a0dc95fSEric Van Hensbergen 	else
10038a0dc95fSEric Van Hensbergen 		kfree(r.rcall);
10048a0dc95fSEric Van Hensbergen 
10058a0dc95fSEric Van Hensbergen 	p9_mux_free_request(m, req);
10068a0dc95fSEric Van Hensbergen 	if (err > 0)
10078a0dc95fSEric Van Hensbergen 		err = -EIO;
10088a0dc95fSEric Van Hensbergen 
10098a0dc95fSEric Van Hensbergen 	return err;
10108a0dc95fSEric Van Hensbergen }
10118a0dc95fSEric Van Hensbergen 
10128a0dc95fSEric Van Hensbergen #ifdef P9_NONBLOCK
10138a0dc95fSEric Van Hensbergen /**
10148a0dc95fSEric Van Hensbergen  * p9_conn_rpcnb - sends 9P request without waiting for response.
10158a0dc95fSEric Van Hensbergen  * @m: mux data
10168a0dc95fSEric Van Hensbergen  * @tc: request to be sent
10178a0dc95fSEric Van Hensbergen  * @cb: callback function to be called when response arrives
1018ee443996SEric Van Hensbergen  * @a: value to pass to the callback function
1019ee443996SEric Van Hensbergen  *
10208a0dc95fSEric Van Hensbergen  */
1021ee443996SEric Van Hensbergen 
10228a0dc95fSEric Van Hensbergen int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc,
10238a0dc95fSEric Van Hensbergen 		   p9_conn_req_callback cb, void *a)
10248a0dc95fSEric Van Hensbergen {
10258a0dc95fSEric Van Hensbergen 	int err;
10268a0dc95fSEric Van Hensbergen 	struct p9_req *req;
10278a0dc95fSEric Van Hensbergen 
10288a0dc95fSEric Van Hensbergen 	req = p9_send_request(m, tc, cb, a);
10298a0dc95fSEric Van Hensbergen 	if (IS_ERR(req)) {
10308a0dc95fSEric Van Hensbergen 		err = PTR_ERR(req);
10318a0dc95fSEric Van Hensbergen 		P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err);
10328a0dc95fSEric Van Hensbergen 		return PTR_ERR(req);
10338a0dc95fSEric Van Hensbergen 	}
10348a0dc95fSEric Van Hensbergen 
10358a0dc95fSEric Van Hensbergen 	P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p tag %d\n", m, tc, req->tag);
10368a0dc95fSEric Van Hensbergen 	return 0;
10378a0dc95fSEric Van Hensbergen }
10388a0dc95fSEric Van Hensbergen #endif /* P9_NONBLOCK */
10398a0dc95fSEric Van Hensbergen 
10408a0dc95fSEric Van Hensbergen /**
10418a0dc95fSEric Van Hensbergen  * p9_conn_cancel - cancel all pending requests with error
10428a0dc95fSEric Van Hensbergen  * @m: mux data
10438a0dc95fSEric Van Hensbergen  * @err: error code
1044ee443996SEric Van Hensbergen  *
10458a0dc95fSEric Van Hensbergen  */
1046ee443996SEric Van Hensbergen 
10478a0dc95fSEric Van Hensbergen void p9_conn_cancel(struct p9_conn *m, int err)
10488a0dc95fSEric Van Hensbergen {
10498a0dc95fSEric Van Hensbergen 	struct p9_req *req, *rtmp;
10508a0dc95fSEric Van Hensbergen 	LIST_HEAD(cancel_list);
10518a0dc95fSEric Van Hensbergen 
10528a0dc95fSEric Van Hensbergen 	P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err);
10538a0dc95fSEric Van Hensbergen 	m->err = err;
10548a0dc95fSEric Van Hensbergen 	spin_lock(&m->lock);
10558a0dc95fSEric Van Hensbergen 	list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) {
10568a0dc95fSEric Van Hensbergen 		list_move(&req->req_list, &cancel_list);
10578a0dc95fSEric Van Hensbergen 	}
10588a0dc95fSEric Van Hensbergen 	list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) {
10598a0dc95fSEric Van Hensbergen 		list_move(&req->req_list, &cancel_list);
10608a0dc95fSEric Van Hensbergen 	}
10618a0dc95fSEric Van Hensbergen 	spin_unlock(&m->lock);
10628a0dc95fSEric Van Hensbergen 
10638a0dc95fSEric Van Hensbergen 	list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) {
10648a0dc95fSEric Van Hensbergen 		list_del(&req->req_list);
10658a0dc95fSEric Van Hensbergen 		if (!req->err)
10668a0dc95fSEric Van Hensbergen 			req->err = err;
10678a0dc95fSEric Van Hensbergen 
10688a0dc95fSEric Van Hensbergen 		if (req->cb)
10698a0dc95fSEric Van Hensbergen 			(*req->cb) (req, req->cba);
10708a0dc95fSEric Van Hensbergen 		else
10718a0dc95fSEric Van Hensbergen 			kfree(req->rcall);
10728a0dc95fSEric Van Hensbergen 	}
10738a0dc95fSEric Van Hensbergen }
10748a0dc95fSEric Van Hensbergen 
1075a80d923eSEric Van Hensbergen /**
1076bb8ffdfcSEric Van Hensbergen  * parse_options - parse mount options into session structure
1077a80d923eSEric Van Hensbergen  * @options: options string passed from mount
1078ee443996SEric Van Hensbergen  * @opts: transport-specific structure to parse options into
1079a80d923eSEric Van Hensbergen  *
1080bb8ffdfcSEric Van Hensbergen  * Returns 0 upon success, -ERRNO upon failure
1081a80d923eSEric Van Hensbergen  */
1082a80d923eSEric Van Hensbergen 
1083bb8ffdfcSEric Van Hensbergen static int parse_opts(char *params, struct p9_fd_opts *opts)
1084bd238fb4SLatchesar Ionkov {
1085a80d923eSEric Van Hensbergen 	char *p;
1086a80d923eSEric Van Hensbergen 	substring_t args[MAX_OPT_ARGS];
1087a80d923eSEric Van Hensbergen 	int option;
1088bb8ffdfcSEric Van Hensbergen 	char *options;
1089a80d923eSEric Van Hensbergen 	int ret;
1090bd238fb4SLatchesar Ionkov 
1091a80d923eSEric Van Hensbergen 	opts->port = P9_PORT;
1092a80d923eSEric Van Hensbergen 	opts->rfd = ~0;
1093a80d923eSEric Van Hensbergen 	opts->wfd = ~0;
1094bd238fb4SLatchesar Ionkov 
1095bb8ffdfcSEric Van Hensbergen 	if (!params)
1096bb8ffdfcSEric Van Hensbergen 		return 0;
1097bb8ffdfcSEric Van Hensbergen 
1098bb8ffdfcSEric Van Hensbergen 	options = kstrdup(params, GFP_KERNEL);
1099bb8ffdfcSEric Van Hensbergen 	if (!options) {
1100bb8ffdfcSEric Van Hensbergen 		P9_DPRINTK(P9_DEBUG_ERROR,
1101bb8ffdfcSEric Van Hensbergen 				"failed to allocate copy of option string\n");
1102bb8ffdfcSEric Van Hensbergen 		return -ENOMEM;
1103bb8ffdfcSEric Van Hensbergen 	}
1104bd238fb4SLatchesar Ionkov 
1105a80d923eSEric Van Hensbergen 	while ((p = strsep(&options, ",")) != NULL) {
1106a80d923eSEric Van Hensbergen 		int token;
1107bb8ffdfcSEric Van Hensbergen 		int r;
1108a80d923eSEric Van Hensbergen 		if (!*p)
1109a80d923eSEric Van Hensbergen 			continue;
1110a80d923eSEric Van Hensbergen 		token = match_token(p, tokens, args);
1111bb8ffdfcSEric Van Hensbergen 		r = match_int(&args[0], &option);
1112bb8ffdfcSEric Van Hensbergen 		if (r < 0) {
1113a80d923eSEric Van Hensbergen 			P9_DPRINTK(P9_DEBUG_ERROR,
1114a80d923eSEric Van Hensbergen 			 "integer field, but no integer?\n");
1115bb8ffdfcSEric Van Hensbergen 			ret = r;
1116a80d923eSEric Van Hensbergen 			continue;
1117a80d923eSEric Van Hensbergen 		}
1118a80d923eSEric Van Hensbergen 		switch (token) {
1119a80d923eSEric Van Hensbergen 		case Opt_port:
1120a80d923eSEric Van Hensbergen 			opts->port = option;
1121a80d923eSEric Van Hensbergen 			break;
1122a80d923eSEric Van Hensbergen 		case Opt_rfdno:
1123a80d923eSEric Van Hensbergen 			opts->rfd = option;
1124a80d923eSEric Van Hensbergen 			break;
1125a80d923eSEric Van Hensbergen 		case Opt_wfdno:
1126a80d923eSEric Van Hensbergen 			opts->wfd = option;
1127a80d923eSEric Van Hensbergen 			break;
1128a80d923eSEric Van Hensbergen 		default:
1129a80d923eSEric Van Hensbergen 			continue;
1130a80d923eSEric Van Hensbergen 		}
1131a80d923eSEric Van Hensbergen 	}
1132bb8ffdfcSEric Van Hensbergen 	kfree(options);
1133bb8ffdfcSEric Van Hensbergen 	return 0;
1134bd238fb4SLatchesar Ionkov }
1135bd238fb4SLatchesar Ionkov 
1136a80d923eSEric Van Hensbergen static int p9_fd_open(struct p9_trans *trans, int rfd, int wfd)
1137bd238fb4SLatchesar Ionkov {
1138bd238fb4SLatchesar Ionkov 	struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd),
1139bd238fb4SLatchesar Ionkov 					   GFP_KERNEL);
1140bd238fb4SLatchesar Ionkov 	if (!ts)
1141bd238fb4SLatchesar Ionkov 		return -ENOMEM;
1142bd238fb4SLatchesar Ionkov 
1143bd238fb4SLatchesar Ionkov 	ts->rd = fget(rfd);
1144bd238fb4SLatchesar Ionkov 	ts->wr = fget(wfd);
1145bd238fb4SLatchesar Ionkov 	if (!ts->rd || !ts->wr) {
1146bd238fb4SLatchesar Ionkov 		if (ts->rd)
1147bd238fb4SLatchesar Ionkov 			fput(ts->rd);
1148bd238fb4SLatchesar Ionkov 		if (ts->wr)
1149bd238fb4SLatchesar Ionkov 			fput(ts->wr);
1150bd238fb4SLatchesar Ionkov 		kfree(ts);
1151bd238fb4SLatchesar Ionkov 		return -EIO;
1152bd238fb4SLatchesar Ionkov 	}
1153bd238fb4SLatchesar Ionkov 
1154bd238fb4SLatchesar Ionkov 	trans->priv = ts;
1155bd238fb4SLatchesar Ionkov 	trans->status = Connected;
1156bd238fb4SLatchesar Ionkov 
1157bd238fb4SLatchesar Ionkov 	return 0;
1158bd238fb4SLatchesar Ionkov }
1159bd238fb4SLatchesar Ionkov 
1160a80d923eSEric Van Hensbergen static int p9_socket_open(struct p9_trans *trans, struct socket *csocket)
1161a80d923eSEric Van Hensbergen {
1162a80d923eSEric Van Hensbergen 	int fd, ret;
1163a80d923eSEric Van Hensbergen 
1164a80d923eSEric Van Hensbergen 	csocket->sk->sk_allocation = GFP_NOIO;
1165a677a039SUlrich Drepper 	fd = sock_map_fd(csocket, 0);
1166a80d923eSEric Van Hensbergen 	if (fd < 0) {
1167a80d923eSEric Van Hensbergen 		P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n");
1168a80d923eSEric Van Hensbergen 		return fd;
1169a80d923eSEric Van Hensbergen 	}
1170a80d923eSEric Van Hensbergen 
1171a80d923eSEric Van Hensbergen 	ret = p9_fd_open(trans, fd, fd);
1172a80d923eSEric Van Hensbergen 	if (ret < 0) {
1173a80d923eSEric Van Hensbergen 		P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to open fd\n");
1174a80d923eSEric Van Hensbergen 		sockfd_put(csocket);
1175a80d923eSEric Van Hensbergen 		return ret;
1176a80d923eSEric Van Hensbergen 	}
1177a80d923eSEric Van Hensbergen 
1178a80d923eSEric Van Hensbergen 	((struct p9_trans_fd *)trans->priv)->rd->f_flags |= O_NONBLOCK;
1179a80d923eSEric Van Hensbergen 
1180a80d923eSEric Van Hensbergen 	return 0;
1181a80d923eSEric Van Hensbergen }
1182a80d923eSEric Van Hensbergen 
1183bd238fb4SLatchesar Ionkov /**
1184bd238fb4SLatchesar Ionkov  * p9_fd_read- read from a fd
1185ee443996SEric Van Hensbergen  * @trans: transport instance state
1186bd238fb4SLatchesar Ionkov  * @v: buffer to receive data into
1187bd238fb4SLatchesar Ionkov  * @len: size of receive buffer
1188bd238fb4SLatchesar Ionkov  *
1189bd238fb4SLatchesar Ionkov  */
1190ee443996SEric Van Hensbergen 
1191a80d923eSEric Van Hensbergen static int p9_fd_read(struct p9_trans *trans, void *v, int len)
1192bd238fb4SLatchesar Ionkov {
1193bd238fb4SLatchesar Ionkov 	int ret;
1194bd238fb4SLatchesar Ionkov 	struct p9_trans_fd *ts = NULL;
1195bd238fb4SLatchesar Ionkov 
1196bd238fb4SLatchesar Ionkov 	if (trans && trans->status != Disconnected)
1197bd238fb4SLatchesar Ionkov 		ts = trans->priv;
1198bd238fb4SLatchesar Ionkov 
1199bd238fb4SLatchesar Ionkov 	if (!ts)
1200bd238fb4SLatchesar Ionkov 		return -EREMOTEIO;
1201bd238fb4SLatchesar Ionkov 
1202bd238fb4SLatchesar Ionkov 	if (!(ts->rd->f_flags & O_NONBLOCK))
1203bd238fb4SLatchesar Ionkov 		P9_DPRINTK(P9_DEBUG_ERROR, "blocking read ...\n");
1204bd238fb4SLatchesar Ionkov 
1205bd238fb4SLatchesar Ionkov 	ret = kernel_read(ts->rd, ts->rd->f_pos, v, len);
1206bd238fb4SLatchesar Ionkov 	if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
1207bd238fb4SLatchesar Ionkov 		trans->status = Disconnected;
1208bd238fb4SLatchesar Ionkov 	return ret;
1209bd238fb4SLatchesar Ionkov }
1210bd238fb4SLatchesar Ionkov 
1211bd238fb4SLatchesar Ionkov /**
1212bd238fb4SLatchesar Ionkov  * p9_fd_write - write to a socket
1213ee443996SEric Van Hensbergen  * @trans: transport instance state
1214bd238fb4SLatchesar Ionkov  * @v: buffer to send data from
1215bd238fb4SLatchesar Ionkov  * @len: size of send buffer
1216bd238fb4SLatchesar Ionkov  *
1217bd238fb4SLatchesar Ionkov  */
1218ee443996SEric Van Hensbergen 
1219a80d923eSEric Van Hensbergen static int p9_fd_write(struct p9_trans *trans, void *v, int len)
1220bd238fb4SLatchesar Ionkov {
1221bd238fb4SLatchesar Ionkov 	int ret;
1222bd238fb4SLatchesar Ionkov 	mm_segment_t oldfs;
1223bd238fb4SLatchesar Ionkov 	struct p9_trans_fd *ts = NULL;
1224bd238fb4SLatchesar Ionkov 
1225bd238fb4SLatchesar Ionkov 	if (trans && trans->status != Disconnected)
1226bd238fb4SLatchesar Ionkov 		ts = trans->priv;
1227bd238fb4SLatchesar Ionkov 
1228bd238fb4SLatchesar Ionkov 	if (!ts)
1229bd238fb4SLatchesar Ionkov 		return -EREMOTEIO;
1230bd238fb4SLatchesar Ionkov 
1231bd238fb4SLatchesar Ionkov 	if (!(ts->wr->f_flags & O_NONBLOCK))
1232bd238fb4SLatchesar Ionkov 		P9_DPRINTK(P9_DEBUG_ERROR, "blocking write ...\n");
1233bd238fb4SLatchesar Ionkov 
1234bd238fb4SLatchesar Ionkov 	oldfs = get_fs();
1235bd238fb4SLatchesar Ionkov 	set_fs(get_ds());
1236bd238fb4SLatchesar Ionkov 	/* The cast to a user pointer is valid due to the set_fs() */
1237bd238fb4SLatchesar Ionkov 	ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos);
1238bd238fb4SLatchesar Ionkov 	set_fs(oldfs);
1239bd238fb4SLatchesar Ionkov 
1240bd238fb4SLatchesar Ionkov 	if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
1241bd238fb4SLatchesar Ionkov 		trans->status = Disconnected;
1242bd238fb4SLatchesar Ionkov 	return ret;
1243bd238fb4SLatchesar Ionkov }
1244bd238fb4SLatchesar Ionkov 
1245bd238fb4SLatchesar Ionkov static unsigned int
1246a80d923eSEric Van Hensbergen p9_fd_poll(struct p9_trans *trans, struct poll_table_struct *pt)
1247bd238fb4SLatchesar Ionkov {
1248bd238fb4SLatchesar Ionkov 	int ret, n;
1249bd238fb4SLatchesar Ionkov 	struct p9_trans_fd *ts = NULL;
1250bd238fb4SLatchesar Ionkov 
1251bd238fb4SLatchesar Ionkov 	if (trans && trans->status == Connected)
1252bd238fb4SLatchesar Ionkov 		ts = trans->priv;
1253bd238fb4SLatchesar Ionkov 
1254bd238fb4SLatchesar Ionkov 	if (!ts)
1255bd238fb4SLatchesar Ionkov 		return -EREMOTEIO;
1256bd238fb4SLatchesar Ionkov 
1257bd238fb4SLatchesar Ionkov 	if (!ts->rd->f_op || !ts->rd->f_op->poll)
1258bd238fb4SLatchesar Ionkov 		return -EIO;
1259bd238fb4SLatchesar Ionkov 
1260bd238fb4SLatchesar Ionkov 	if (!ts->wr->f_op || !ts->wr->f_op->poll)
1261bd238fb4SLatchesar Ionkov 		return -EIO;
1262bd238fb4SLatchesar Ionkov 
1263bd238fb4SLatchesar Ionkov 	ret = ts->rd->f_op->poll(ts->rd, pt);
1264bd238fb4SLatchesar Ionkov 	if (ret < 0)
1265ec3c68f2STejun Heo 		return ret;
1266bd238fb4SLatchesar Ionkov 
1267bd238fb4SLatchesar Ionkov 	if (ts->rd != ts->wr) {
1268bd238fb4SLatchesar Ionkov 		n = ts->wr->f_op->poll(ts->wr, pt);
1269ec3c68f2STejun Heo 		if (n < 0)
1270ec3c68f2STejun Heo 			return n;
1271bd238fb4SLatchesar Ionkov 		ret = (ret & ~POLLOUT) | (n & ~POLLIN);
1272bd238fb4SLatchesar Ionkov 	}
1273bd238fb4SLatchesar Ionkov 
1274bd238fb4SLatchesar Ionkov 	return ret;
1275bd238fb4SLatchesar Ionkov }
1276bd238fb4SLatchesar Ionkov 
1277bd238fb4SLatchesar Ionkov /**
12788a0dc95fSEric Van Hensbergen  * p9_fd_close - shutdown socket
1279bd238fb4SLatchesar Ionkov  * @trans: private socket structure
1280bd238fb4SLatchesar Ionkov  *
1281bd238fb4SLatchesar Ionkov  */
1282ee443996SEric Van Hensbergen 
1283a80d923eSEric Van Hensbergen static void p9_fd_close(struct p9_trans *trans)
1284bd238fb4SLatchesar Ionkov {
1285bd238fb4SLatchesar Ionkov 	struct p9_trans_fd *ts;
1286bd238fb4SLatchesar Ionkov 
1287bd238fb4SLatchesar Ionkov 	if (!trans)
1288bd238fb4SLatchesar Ionkov 		return;
1289bd238fb4SLatchesar Ionkov 
1290bd238fb4SLatchesar Ionkov 	ts = xchg(&trans->priv, NULL);
1291bd238fb4SLatchesar Ionkov 
1292bd238fb4SLatchesar Ionkov 	if (!ts)
1293bd238fb4SLatchesar Ionkov 		return;
1294bd238fb4SLatchesar Ionkov 
12958a0dc95fSEric Van Hensbergen 	p9_conn_destroy(ts->conn);
12968a0dc95fSEric Van Hensbergen 
1297bd238fb4SLatchesar Ionkov 	trans->status = Disconnected;
1298bd238fb4SLatchesar Ionkov 	if (ts->rd)
1299bd238fb4SLatchesar Ionkov 		fput(ts->rd);
1300bd238fb4SLatchesar Ionkov 	if (ts->wr)
1301bd238fb4SLatchesar Ionkov 		fput(ts->wr);
1302bd238fb4SLatchesar Ionkov 	kfree(ts);
1303bd238fb4SLatchesar Ionkov }
1304bd238fb4SLatchesar Ionkov 
1305887b3eceSEric Van Hensbergen /*
1306887b3eceSEric Van Hensbergen  * stolen from NFS - maybe should be made a generic function?
1307887b3eceSEric Van Hensbergen  */
1308887b3eceSEric Van Hensbergen static inline int valid_ipaddr4(const char *buf)
1309887b3eceSEric Van Hensbergen {
1310887b3eceSEric Van Hensbergen 	int rc, count, in[4];
1311887b3eceSEric Van Hensbergen 
1312887b3eceSEric Van Hensbergen 	rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]);
1313887b3eceSEric Van Hensbergen 	if (rc != 4)
1314887b3eceSEric Van Hensbergen 		return -EINVAL;
1315887b3eceSEric Van Hensbergen 	for (count = 0; count < 4; count++) {
1316887b3eceSEric Van Hensbergen 		if (in[count] > 255)
1317887b3eceSEric Van Hensbergen 			return -EINVAL;
1318887b3eceSEric Van Hensbergen 	}
1319887b3eceSEric Van Hensbergen 	return 0;
1320887b3eceSEric Van Hensbergen }
1321887b3eceSEric Van Hensbergen 
13228a0dc95fSEric Van Hensbergen static struct p9_trans *
13238a0dc95fSEric Van Hensbergen p9_trans_create_tcp(const char *addr, char *args, int msize, unsigned char dotu)
1324a80d923eSEric Van Hensbergen {
1325a80d923eSEric Van Hensbergen 	int err;
1326a80d923eSEric Van Hensbergen 	struct p9_trans *trans;
1327a80d923eSEric Van Hensbergen 	struct socket *csocket;
1328a80d923eSEric Van Hensbergen 	struct sockaddr_in sin_server;
1329a80d923eSEric Van Hensbergen 	struct p9_fd_opts opts;
13308a0dc95fSEric Van Hensbergen 	struct p9_trans_fd *p;
1331a80d923eSEric Van Hensbergen 
1332bb8ffdfcSEric Van Hensbergen 	err = parse_opts(args, &opts);
1333bb8ffdfcSEric Van Hensbergen 	if (err < 0)
1334bb8ffdfcSEric Van Hensbergen 		return ERR_PTR(err);
1335a80d923eSEric Van Hensbergen 
1336887b3eceSEric Van Hensbergen 	if (valid_ipaddr4(addr) < 0)
1337887b3eceSEric Van Hensbergen 		return ERR_PTR(-EINVAL);
1338887b3eceSEric Van Hensbergen 
1339a80d923eSEric Van Hensbergen 	csocket = NULL;
1340a80d923eSEric Van Hensbergen 	trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
1341a80d923eSEric Van Hensbergen 	if (!trans)
1342a80d923eSEric Van Hensbergen 		return ERR_PTR(-ENOMEM);
13438a0dc95fSEric Van Hensbergen 	trans->msize = msize;
13448a0dc95fSEric Van Hensbergen 	trans->extended = dotu;
13458a0dc95fSEric Van Hensbergen 	trans->rpc = p9_fd_rpc;
1346a80d923eSEric Van Hensbergen 	trans->close = p9_fd_close;
1347a80d923eSEric Van Hensbergen 
1348a80d923eSEric Van Hensbergen 	sin_server.sin_family = AF_INET;
1349a80d923eSEric Van Hensbergen 	sin_server.sin_addr.s_addr = in_aton(addr);
1350a80d923eSEric Van Hensbergen 	sin_server.sin_port = htons(opts.port);
1351a80d923eSEric Van Hensbergen 	sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
1352a80d923eSEric Van Hensbergen 
1353a80d923eSEric Van Hensbergen 	if (!csocket) {
1354a80d923eSEric Van Hensbergen 		P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n");
1355a80d923eSEric Van Hensbergen 		err = -EIO;
1356a80d923eSEric Van Hensbergen 		goto error;
1357a80d923eSEric Van Hensbergen 	}
1358a80d923eSEric Van Hensbergen 
1359a80d923eSEric Van Hensbergen 	err = csocket->ops->connect(csocket,
1360a80d923eSEric Van Hensbergen 				    (struct sockaddr *)&sin_server,
1361a80d923eSEric Van Hensbergen 				    sizeof(struct sockaddr_in), 0);
1362a80d923eSEric Van Hensbergen 	if (err < 0) {
1363a80d923eSEric Van Hensbergen 		P9_EPRINTK(KERN_ERR,
1364a80d923eSEric Van Hensbergen 			"p9_trans_tcp: problem connecting socket to %s\n",
1365a80d923eSEric Van Hensbergen 			addr);
1366a80d923eSEric Van Hensbergen 		goto error;
1367a80d923eSEric Van Hensbergen 	}
1368a80d923eSEric Van Hensbergen 
1369a80d923eSEric Van Hensbergen 	err = p9_socket_open(trans, csocket);
1370a80d923eSEric Van Hensbergen 	if (err < 0)
1371a80d923eSEric Van Hensbergen 		goto error;
1372a80d923eSEric Van Hensbergen 
13738a0dc95fSEric Van Hensbergen 	p = (struct p9_trans_fd *) trans->priv;
13748a0dc95fSEric Van Hensbergen 	p->conn = p9_conn_create(trans);
13758a0dc95fSEric Van Hensbergen 	if (IS_ERR(p->conn)) {
13768a0dc95fSEric Van Hensbergen 		err = PTR_ERR(p->conn);
13778a0dc95fSEric Van Hensbergen 		p->conn = NULL;
13788a0dc95fSEric Van Hensbergen 		goto error;
13798a0dc95fSEric Van Hensbergen 	}
13808a0dc95fSEric Van Hensbergen 
1381a80d923eSEric Van Hensbergen 	return trans;
1382a80d923eSEric Van Hensbergen 
1383a80d923eSEric Van Hensbergen error:
1384a80d923eSEric Van Hensbergen 	if (csocket)
1385a80d923eSEric Van Hensbergen 		sock_release(csocket);
1386a80d923eSEric Van Hensbergen 
1387a80d923eSEric Van Hensbergen 	kfree(trans);
1388a80d923eSEric Van Hensbergen 	return ERR_PTR(err);
1389a80d923eSEric Van Hensbergen }
1390a80d923eSEric Van Hensbergen 
13918a0dc95fSEric Van Hensbergen static struct p9_trans *
13928a0dc95fSEric Van Hensbergen p9_trans_create_unix(const char *addr, char *args, int msize,
13938a0dc95fSEric Van Hensbergen 							unsigned char dotu)
1394a80d923eSEric Van Hensbergen {
1395a80d923eSEric Van Hensbergen 	int err;
1396a80d923eSEric Van Hensbergen 	struct socket *csocket;
1397a80d923eSEric Van Hensbergen 	struct sockaddr_un sun_server;
1398a80d923eSEric Van Hensbergen 	struct p9_trans *trans;
13998a0dc95fSEric Van Hensbergen 	struct p9_trans_fd *p;
1400a80d923eSEric Van Hensbergen 
1401a80d923eSEric Van Hensbergen 	csocket = NULL;
1402a80d923eSEric Van Hensbergen 	trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
1403a80d923eSEric Van Hensbergen 	if (!trans)
1404a80d923eSEric Van Hensbergen 		return ERR_PTR(-ENOMEM);
1405a80d923eSEric Van Hensbergen 
14068a0dc95fSEric Van Hensbergen 	trans->rpc = p9_fd_rpc;
1407a80d923eSEric Van Hensbergen 	trans->close = p9_fd_close;
1408a80d923eSEric Van Hensbergen 
1409a80d923eSEric Van Hensbergen 	if (strlen(addr) > UNIX_PATH_MAX) {
1410a80d923eSEric Van Hensbergen 		P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n",
1411a80d923eSEric Van Hensbergen 			addr);
1412a80d923eSEric Van Hensbergen 		err = -ENAMETOOLONG;
1413a80d923eSEric Van Hensbergen 		goto error;
1414a80d923eSEric Van Hensbergen 	}
1415a80d923eSEric Van Hensbergen 
1416a80d923eSEric Van Hensbergen 	sun_server.sun_family = PF_UNIX;
1417a80d923eSEric Van Hensbergen 	strcpy(sun_server.sun_path, addr);
1418a80d923eSEric Van Hensbergen 	sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket);
1419a80d923eSEric Van Hensbergen 	err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
1420a80d923eSEric Van Hensbergen 			sizeof(struct sockaddr_un) - 1, 0);
1421a80d923eSEric Van Hensbergen 	if (err < 0) {
1422a80d923eSEric Van Hensbergen 		P9_EPRINTK(KERN_ERR,
1423a80d923eSEric Van Hensbergen 			"p9_trans_unix: problem connecting socket: %s: %d\n",
1424a80d923eSEric Van Hensbergen 			addr, err);
1425a80d923eSEric Van Hensbergen 		goto error;
1426a80d923eSEric Van Hensbergen 	}
1427a80d923eSEric Van Hensbergen 
1428a80d923eSEric Van Hensbergen 	err = p9_socket_open(trans, csocket);
1429a80d923eSEric Van Hensbergen 	if (err < 0)
1430a80d923eSEric Van Hensbergen 		goto error;
1431a80d923eSEric Van Hensbergen 
14328a0dc95fSEric Van Hensbergen 	trans->msize = msize;
14338a0dc95fSEric Van Hensbergen 	trans->extended = dotu;
14348a0dc95fSEric Van Hensbergen 	p = (struct p9_trans_fd *) trans->priv;
14358a0dc95fSEric Van Hensbergen 	p->conn = p9_conn_create(trans);
14368a0dc95fSEric Van Hensbergen 	if (IS_ERR(p->conn)) {
14378a0dc95fSEric Van Hensbergen 		err = PTR_ERR(p->conn);
14388a0dc95fSEric Van Hensbergen 		p->conn = NULL;
14398a0dc95fSEric Van Hensbergen 		goto error;
14408a0dc95fSEric Van Hensbergen 	}
14418a0dc95fSEric Van Hensbergen 
1442a80d923eSEric Van Hensbergen 	return trans;
1443a80d923eSEric Van Hensbergen 
1444a80d923eSEric Van Hensbergen error:
1445a80d923eSEric Van Hensbergen 	if (csocket)
1446a80d923eSEric Van Hensbergen 		sock_release(csocket);
1447a80d923eSEric Van Hensbergen 
1448a80d923eSEric Van Hensbergen 	kfree(trans);
1449a80d923eSEric Van Hensbergen 	return ERR_PTR(err);
1450a80d923eSEric Van Hensbergen }
1451a80d923eSEric Van Hensbergen 
14528a0dc95fSEric Van Hensbergen static struct p9_trans *
14538a0dc95fSEric Van Hensbergen p9_trans_create_fd(const char *name, char *args, int msize,
14548a0dc95fSEric Van Hensbergen 							unsigned char extended)
1455a80d923eSEric Van Hensbergen {
1456a80d923eSEric Van Hensbergen 	int err;
1457a80d923eSEric Van Hensbergen 	struct p9_trans *trans;
1458a80d923eSEric Van Hensbergen 	struct p9_fd_opts opts;
14598a0dc95fSEric Van Hensbergen 	struct p9_trans_fd *p;
1460a80d923eSEric Van Hensbergen 
1461a80d923eSEric Van Hensbergen 	parse_opts(args, &opts);
1462a80d923eSEric Van Hensbergen 
1463a80d923eSEric Van Hensbergen 	if (opts.rfd == ~0 || opts.wfd == ~0) {
1464a80d923eSEric Van Hensbergen 		printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n");
1465a80d923eSEric Van Hensbergen 		return ERR_PTR(-ENOPROTOOPT);
1466a80d923eSEric Van Hensbergen 	}
1467a80d923eSEric Van Hensbergen 
1468a80d923eSEric Van Hensbergen 	trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
1469a80d923eSEric Van Hensbergen 	if (!trans)
1470a80d923eSEric Van Hensbergen 		return ERR_PTR(-ENOMEM);
1471a80d923eSEric Van Hensbergen 
14728a0dc95fSEric Van Hensbergen 	trans->rpc = p9_fd_rpc;
1473a80d923eSEric Van Hensbergen 	trans->close = p9_fd_close;
1474a80d923eSEric Van Hensbergen 
1475a80d923eSEric Van Hensbergen 	err = p9_fd_open(trans, opts.rfd, opts.wfd);
1476a80d923eSEric Van Hensbergen 	if (err < 0)
1477a80d923eSEric Van Hensbergen 		goto error;
1478a80d923eSEric Van Hensbergen 
14798a0dc95fSEric Van Hensbergen 	trans->msize = msize;
14808a0dc95fSEric Van Hensbergen 	trans->extended = extended;
14818a0dc95fSEric Van Hensbergen 	p = (struct p9_trans_fd *) trans->priv;
14828a0dc95fSEric Van Hensbergen 	p->conn = p9_conn_create(trans);
14838a0dc95fSEric Van Hensbergen 	if (IS_ERR(p->conn)) {
14848a0dc95fSEric Van Hensbergen 		err = PTR_ERR(p->conn);
14858a0dc95fSEric Van Hensbergen 		p->conn = NULL;
14868a0dc95fSEric Van Hensbergen 		goto error;
14878a0dc95fSEric Van Hensbergen 	}
14888a0dc95fSEric Van Hensbergen 
1489a80d923eSEric Van Hensbergen 	return trans;
1490a80d923eSEric Van Hensbergen 
1491a80d923eSEric Van Hensbergen error:
1492a80d923eSEric Van Hensbergen 	kfree(trans);
1493a80d923eSEric Van Hensbergen 	return ERR_PTR(err);
1494a80d923eSEric Van Hensbergen }
1495a80d923eSEric Van Hensbergen 
1496a80d923eSEric Van Hensbergen static struct p9_trans_module p9_tcp_trans = {
1497a80d923eSEric Van Hensbergen 	.name = "tcp",
1498a80d923eSEric Van Hensbergen 	.maxsize = MAX_SOCK_BUF,
1499a80d923eSEric Van Hensbergen 	.def = 1,
1500a80d923eSEric Van Hensbergen 	.create = p9_trans_create_tcp,
150172029fe8STejun Heo 	.owner = THIS_MODULE,
1502a80d923eSEric Van Hensbergen };
1503a80d923eSEric Van Hensbergen 
1504a80d923eSEric Van Hensbergen static struct p9_trans_module p9_unix_trans = {
1505a80d923eSEric Van Hensbergen 	.name = "unix",
1506a80d923eSEric Van Hensbergen 	.maxsize = MAX_SOCK_BUF,
1507a80d923eSEric Van Hensbergen 	.def = 0,
1508a80d923eSEric Van Hensbergen 	.create = p9_trans_create_unix,
150972029fe8STejun Heo 	.owner = THIS_MODULE,
1510a80d923eSEric Van Hensbergen };
1511a80d923eSEric Van Hensbergen 
1512a80d923eSEric Van Hensbergen static struct p9_trans_module p9_fd_trans = {
1513a80d923eSEric Van Hensbergen 	.name = "fd",
1514a80d923eSEric Van Hensbergen 	.maxsize = MAX_SOCK_BUF,
1515a80d923eSEric Van Hensbergen 	.def = 0,
1516a80d923eSEric Van Hensbergen 	.create = p9_trans_create_fd,
151772029fe8STejun Heo 	.owner = THIS_MODULE,
1518a80d923eSEric Van Hensbergen };
1519a80d923eSEric Van Hensbergen 
1520887b3eceSEric Van Hensbergen int p9_trans_fd_init(void)
1521a80d923eSEric Van Hensbergen {
1522206ca50dSTejun Heo 	p9_mux_wq = create_workqueue("v9fs");
1523206ca50dSTejun Heo 	if (!p9_mux_wq) {
1524206ca50dSTejun Heo 		printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n");
1525206ca50dSTejun Heo 		return -ENOMEM;
15268a0dc95fSEric Van Hensbergen 	}
15278a0dc95fSEric Van Hensbergen 
1528992b3f1dSTejun Heo 	p9_poll_task = kthread_run(p9_poll_proc, NULL, "v9fs-poll");
1529992b3f1dSTejun Heo 	if (IS_ERR(p9_poll_task)) {
1530992b3f1dSTejun Heo 		destroy_workqueue(p9_mux_wq);
1531992b3f1dSTejun Heo 		printk(KERN_WARNING "v9fs: mux: creating poll task failed\n");
1532992b3f1dSTejun Heo 		return PTR_ERR(p9_poll_task);
1533992b3f1dSTejun Heo 	}
1534992b3f1dSTejun Heo 
1535a80d923eSEric Van Hensbergen 	v9fs_register_trans(&p9_tcp_trans);
1536a80d923eSEric Van Hensbergen 	v9fs_register_trans(&p9_unix_trans);
1537a80d923eSEric Van Hensbergen 	v9fs_register_trans(&p9_fd_trans);
1538a80d923eSEric Van Hensbergen 
15393387b804SAndrew Morton 	return 0;
1540a80d923eSEric Van Hensbergen }
154172029fe8STejun Heo 
154272029fe8STejun Heo void p9_trans_fd_exit(void)
154372029fe8STejun Heo {
1544992b3f1dSTejun Heo 	kthread_stop(p9_poll_task);
154572029fe8STejun Heo 	v9fs_unregister_trans(&p9_tcp_trans);
154672029fe8STejun Heo 	v9fs_unregister_trans(&p9_unix_trans);
154772029fe8STejun Heo 	v9fs_unregister_trans(&p9_fd_trans);
1548206ca50dSTejun Heo 
1549206ca50dSTejun Heo 	destroy_workqueue(p9_mux_wq);
155072029fe8STejun Heo }
1551