Blame view

net/9p/trans_fd.c 23.9 KB
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
1
2
3
4
5
6
7
  /*
   * linux/fs/9p/trans_fd.c
   *
   * Fd transport layer.  Includes deprecated socket layer.
   *
   *  Copyright (C) 2006 by Russ Cox <rsc@swtch.com>
   *  Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
8
   *  Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com>
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
   *  Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com>
   *
   *  This program is free software; you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License version 2
   *  as published by the Free Software Foundation.
   *
   *  This program is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *  along with this program; if not, write to:
   *  Free Software Foundation
   *  51 Franklin Street, Fifth Floor
   *  Boston, MA  02111-1301  USA
   *
   */
5d3851530   Joe Perches   9p: Reduce object...
27
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
28
29
30
31
  #include <linux/in.h>
  #include <linux/module.h>
  #include <linux/net.h>
  #include <linux/ipv6.h>
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
32
  #include <linux/kthread.h>
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
33
34
35
36
37
38
39
  #include <linux/errno.h>
  #include <linux/kernel.h>
  #include <linux/un.h>
  #include <linux/uaccess.h>
  #include <linux/inet.h>
  #include <linux/idr.h>
  #include <linux/file.h>
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
40
  #include <linux/parser.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
41
  #include <linux/slab.h>
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
42
  #include <net/9p/9p.h>
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
43
  #include <net/9p/client.h>
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
44
  #include <net/9p/transport.h>
6b18662e2   Al Viro   9p connect fixes
45
  #include <linux/syscalls.h> /* killme */
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
46
  #define P9_PORT 564
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
47
  #define MAX_SOCK_BUF (64*1024)
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
48
  #define MAXPOLLWADDR	2
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
49

ee443996a   Eric Van Hensbergen   9p: Documentation...
50
51
52
53
54
55
56
  /**
   * struct p9_fd_opts - per-transport options
   * @rfd: file descriptor for reading (trans=fd)
   * @wfd: file descriptor for writing (trans=fd)
   * @port: port to connect to (trans=tcp)
   *
   */
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
57
58
59
60
61
  struct p9_fd_opts {
  	int rfd;
  	int wfd;
  	u16 port;
  };
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
62

ee443996a   Eric Van Hensbergen   9p: Documentation...
63
64
65
66
67
68
69
  /**
   * struct p9_trans_fd - transport state
   * @rd: reference to file to read from
   * @wr: reference of file to write to
   * @conn: connection state reference
   *
   */
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
70
71
72
  struct p9_trans_fd {
  	struct file *rd;
  	struct file *wr;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
73
  	struct p9_conn *conn;
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
74
  };
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
75
76
77
78
  /*
    * Option Parsing (code inspired by NFS code)
    *  - a little lazy - parse all fd-transport options
    */
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
79

a80d923e1   Eric Van Hensbergen   9p: Make transpor...
80
81
  enum {
  	/* Options that take integer arguments */
55762690e   Latchesar Ionkov   9p: add missing e...
82
  	Opt_port, Opt_rfdno, Opt_wfdno, Opt_err,
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
83
  };
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
84

a447c0932   Steven Whitehouse   vfs: Use const fo...
85
  static const match_table_t tokens = {
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
86
87
88
  	{Opt_port, "port=%u"},
  	{Opt_rfdno, "rfdno=%u"},
  	{Opt_wfdno, "wfdno=%u"},
55762690e   Latchesar Ionkov   9p: add missing e...
89
  	{Opt_err, NULL},
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
90
  };
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
91

8a0dc95fd   Eric Van Hensbergen   9p: transport API...
92
93
94
95
96
97
  enum {
  	Rworksched = 1,		/* read work scheduled or running */
  	Rpending = 2,		/* can read */
  	Wworksched = 4,		/* write work scheduled or running */
  	Wpending = 8,		/* can write */
  };
992b3f1db   Tejun Heo   9p-trans_fd: use ...
98
99
100
101
  struct p9_poll_wait {
  	struct p9_conn *conn;
  	wait_queue_t wait;
  	wait_queue_head_t *wait_addr;
ee443996a   Eric Van Hensbergen   9p: Documentation...
102
103
104
105
  };
  
  /**
   * struct p9_conn - fd mux connection state information
ee443996a   Eric Van Hensbergen   9p: Documentation...
106
   * @mux_list: list link for mux to manage multiple connections (?)
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
107
   * @client: reference to client instance for this connection
ee443996a   Eric Van Hensbergen   9p: Documentation...
108
   * @err: error state
ee443996a   Eric Van Hensbergen   9p: Documentation...
109
110
   * @req_list: accounting for requests which have been sent
   * @unsent_req_list: accounting for requests that haven't been sent
1b0a763bd   Eric Van Hensbergen   9p: use the rcall...
111
112
113
   * @req: current request being processed (if any)
   * @tmp_buf: temporary buffer to read in header
   * @rsize: amount to read for current frame
ee443996a   Eric Van Hensbergen   9p: Documentation...
114
115
116
117
118
   * @rpos: read position in current frame
   * @rbuf: current read buffer
   * @wpos: write position for current frame
   * @wsize: amount of data to write for current frame
   * @wbuf: current write buffer
0e15597eb   Abhishek Kulkarni   9p: minor comment...
119
   * @poll_pending_link: pending links to be polled per conn
ee443996a   Eric Van Hensbergen   9p: Documentation...
120
   * @poll_wait: array of wait_q's for various worker threads
ee443996a   Eric Van Hensbergen   9p: Documentation...
121
122
123
124
125
126
   * @pt: poll state
   * @rq: current read work
   * @wq: current write work
   * @wsched: ????
   *
   */
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
127
128
  
  struct p9_conn {
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
129
  	struct list_head mux_list;
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
130
  	struct p9_client *client;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
131
  	int err;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
132
133
  	struct list_head req_list;
  	struct list_head unsent_req_list;
1b0a763bd   Eric Van Hensbergen   9p: use the rcall...
134
135
136
  	struct p9_req_t *req;
  	char tmp_buf[7];
  	int rsize;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
137
138
139
140
141
  	int rpos;
  	char *rbuf;
  	int wpos;
  	int wsize;
  	char *wbuf;
992b3f1db   Tejun Heo   9p-trans_fd: use ...
142
143
  	struct list_head poll_pending_link;
  	struct p9_poll_wait poll_wait[MAXPOLLWADDR];
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
144
145
146
147
148
  	poll_table pt;
  	struct work_struct rq;
  	struct work_struct wq;
  	unsigned long wsched;
  };
aa70c585b   Tejun Heo   net/9p: replace p...
149
  static void p9_poll_workfn(struct work_struct *work);
992b3f1db   Tejun Heo   9p-trans_fd: use ...
150
151
  static DEFINE_SPINLOCK(p9_poll_lock);
  static LIST_HEAD(p9_poll_pending_list);
aa70c585b   Tejun Heo   net/9p: replace p...
152
  static DECLARE_WORK(p9_poll_work, p9_poll_workfn);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
153

992b3f1db   Tejun Heo   9p-trans_fd: use ...
154
  static void p9_mux_poll_stop(struct p9_conn *m)
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
155
  {
992b3f1db   Tejun Heo   9p-trans_fd: use ...
156
157
  	unsigned long flags;
  	int i;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
158

992b3f1db   Tejun Heo   9p-trans_fd: use ...
159
160
  	for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) {
  		struct p9_poll_wait *pwait = &m->poll_wait[i];
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
161

992b3f1db   Tejun Heo   9p-trans_fd: use ...
162
163
164
  		if (pwait->wait_addr) {
  			remove_wait_queue(pwait->wait_addr, &pwait->wait);
  			pwait->wait_addr = NULL;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
165
  		}
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
166
  	}
992b3f1db   Tejun Heo   9p-trans_fd: use ...
167
168
169
  	spin_lock_irqsave(&p9_poll_lock, flags);
  	list_del_init(&m->poll_pending_link);
  	spin_unlock_irqrestore(&p9_poll_lock, flags);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
170
171
172
  }
  
  /**
5503ac565   Eric Van Hensbergen   9p: remove unnece...
173
174
175
   * p9_conn_cancel - cancel all pending requests with error
   * @m: mux data
   * @err: error code
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
176
   *
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
177
   */
ee443996a   Eric Van Hensbergen   9p: Documentation...
178

51a87c552   Eric Van Hensbergen   9p: rework client...
179
  static void p9_conn_cancel(struct p9_conn *m, int err)
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
180
  {
673d62cda   Eric Van Hensbergen   9p: apply common ...
181
  	struct p9_req_t *req, *rtmp;
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
182
  	unsigned long flags;
5503ac565   Eric Van Hensbergen   9p: remove unnece...
183
  	LIST_HEAD(cancel_list);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
184

5d3851530   Joe Perches   9p: Reduce object...
185
186
  	p9_debug(P9_DEBUG_ERROR, "mux %p err %d
  ", m, err);
7eb923b80   Eric Van Hensbergen   9p: add more cons...
187

91b8534fa   Eric Van Hensbergen   9p: make rpc code...
188
  	spin_lock_irqsave(&m->client->lock, flags);
7eb923b80   Eric Van Hensbergen   9p: add more cons...
189
190
191
192
193
194
195
  
  	if (m->err) {
  		spin_unlock_irqrestore(&m->client->lock, flags);
  		return;
  	}
  
  	m->err = err;
5503ac565   Eric Van Hensbergen   9p: remove unnece...
196
  	list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) {
673d62cda   Eric Van Hensbergen   9p: apply common ...
197
198
199
  		req->status = REQ_STATUS_ERROR;
  		if (!req->t_err)
  			req->t_err = err;
5503ac565   Eric Van Hensbergen   9p: remove unnece...
200
201
202
  		list_move(&req->req_list, &cancel_list);
  	}
  	list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) {
673d62cda   Eric Van Hensbergen   9p: apply common ...
203
204
205
  		req->status = REQ_STATUS_ERROR;
  		if (!req->t_err)
  			req->t_err = err;
5503ac565   Eric Van Hensbergen   9p: remove unnece...
206
  		list_move(&req->req_list, &cancel_list);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
207
  	}
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
208
  	spin_unlock_irqrestore(&m->client->lock, flags);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
209

5503ac565   Eric Van Hensbergen   9p: remove unnece...
210
  	list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) {
5d3851530   Joe Perches   9p: Reduce object...
211
212
  		p9_debug(P9_DEBUG_ERROR, "call back req %p
  ", req);
1bab88b23   Latchesar Ionkov   net/9p: handle co...
213
  		list_del(&req->req_list);
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
214
  		p9_client_cb(m->client, req);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
215
  	}
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
216
  }
29af9309d   Julia Lawall   net/9p/trans_fd.c...
217
  static int
5503ac565   Eric Van Hensbergen   9p: remove unnece...
218
  p9_fd_poll(struct p9_client *client, struct poll_table_struct *pt)
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
219
  {
5503ac565   Eric Van Hensbergen   9p: remove unnece...
220
221
  	int ret, n;
  	struct p9_trans_fd *ts = NULL;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
222

5503ac565   Eric Van Hensbergen   9p: remove unnece...
223
224
  	if (client && client->status == Connected)
  		ts = client->trans;
7dc5d24be   Tejun Heo   9p-trans_fd: fix ...
225

5503ac565   Eric Van Hensbergen   9p: remove unnece...
226
227
  	if (!ts)
  		return -EREMOTEIO;
7dc5d24be   Tejun Heo   9p-trans_fd: fix ...
228

5503ac565   Eric Van Hensbergen   9p: remove unnece...
229
230
  	if (!ts->rd->f_op || !ts->rd->f_op->poll)
  		return -EIO;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
231

5503ac565   Eric Van Hensbergen   9p: remove unnece...
232
233
  	if (!ts->wr->f_op || !ts->wr->f_op->poll)
  		return -EIO;
992b3f1db   Tejun Heo   9p-trans_fd: use ...
234

5503ac565   Eric Van Hensbergen   9p: remove unnece...
235
236
237
  	ret = ts->rd->f_op->poll(ts->rd, pt);
  	if (ret < 0)
  		return ret;
992b3f1db   Tejun Heo   9p-trans_fd: use ...
238

5503ac565   Eric Van Hensbergen   9p: remove unnece...
239
240
241
242
243
244
245
246
  	if (ts->rd != ts->wr) {
  		n = ts->wr->f_op->poll(ts->wr, pt);
  		if (n < 0)
  			return n;
  		ret = (ret & ~POLLOUT) | (n & ~POLLIN);
  	}
  
  	return ret;
992b3f1db   Tejun Heo   9p-trans_fd: use ...
247
  }
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
248
  /**
5503ac565   Eric Van Hensbergen   9p: remove unnece...
249
250
251
252
   * p9_fd_read- read from a fd
   * @client: client instance
   * @v: buffer to receive data into
   * @len: size of receive buffer
ee443996a   Eric Van Hensbergen   9p: Documentation...
253
   *
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
254
   */
ee443996a   Eric Van Hensbergen   9p: Documentation...
255

5503ac565   Eric Van Hensbergen   9p: remove unnece...
256
  static int p9_fd_read(struct p9_client *client, void *v, int len)
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
257
  {
5503ac565   Eric Van Hensbergen   9p: remove unnece...
258
259
  	int ret;
  	struct p9_trans_fd *ts = NULL;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
260

5503ac565   Eric Van Hensbergen   9p: remove unnece...
261
262
  	if (client && client->status != Disconnected)
  		ts = client->trans;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
263

5503ac565   Eric Van Hensbergen   9p: remove unnece...
264
265
  	if (!ts)
  		return -EREMOTEIO;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
266

5503ac565   Eric Van Hensbergen   9p: remove unnece...
267
  	if (!(ts->rd->f_flags & O_NONBLOCK))
5d3851530   Joe Perches   9p: Reduce object...
268
269
  		p9_debug(P9_DEBUG_ERROR, "blocking read ...
  ");
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
270

5503ac565   Eric Van Hensbergen   9p: remove unnece...
271
272
273
274
  	ret = kernel_read(ts->rd, ts->rd->f_pos, v, len);
  	if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
  		client->status = Disconnected;
  	return ret;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
275
276
277
  }
  
  /**
5503ac565   Eric Van Hensbergen   9p: remove unnece...
278
279
   * p9_read_work - called when there is some data to be read from a transport
   * @work: container of work to be done
ee443996a   Eric Van Hensbergen   9p: Documentation...
280
   *
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
281
   */
ee443996a   Eric Van Hensbergen   9p: Documentation...
282

5503ac565   Eric Van Hensbergen   9p: remove unnece...
283
  static void p9_read_work(struct work_struct *work)
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
284
  {
5503ac565   Eric Van Hensbergen   9p: remove unnece...
285
286
  	int n, err;
  	struct p9_conn *m;
5503ac565   Eric Van Hensbergen   9p: remove unnece...
287
288
  
  	m = container_of(work, struct p9_conn, rq);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
289
290
291
  
  	if (m->err < 0)
  		return;
5d3851530   Joe Perches   9p: Reduce object...
292
293
  	p9_debug(P9_DEBUG_TRANS, "start mux %p pos %d
  ", m, m->rpos);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
294

1b0a763bd   Eric Van Hensbergen   9p: use the rcall...
295
296
  	if (!m->rbuf) {
  		m->rbuf = m->tmp_buf;
5503ac565   Eric Van Hensbergen   9p: remove unnece...
297
  		m->rpos = 0;
1b0a763bd   Eric Van Hensbergen   9p: use the rcall...
298
  		m->rsize = 7; /* start by reading header */
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
299
  	}
5503ac565   Eric Van Hensbergen   9p: remove unnece...
300
  	clear_bit(Rpending, &m->wsched);
5d3851530   Joe Perches   9p: Reduce object...
301
302
303
  	p9_debug(P9_DEBUG_TRANS, "read mux %p pos %d size: %d = %d
  ",
  		 m, m->rpos, m->rsize, m->rsize-m->rpos);
5503ac565   Eric Van Hensbergen   9p: remove unnece...
304
  	err = p9_fd_read(m->client, m->rbuf + m->rpos,
1b0a763bd   Eric Van Hensbergen   9p: use the rcall...
305
  						m->rsize - m->rpos);
5d3851530   Joe Perches   9p: Reduce object...
306
307
  	p9_debug(P9_DEBUG_TRANS, "mux %p got %d bytes
  ", m, err);
5503ac565   Eric Van Hensbergen   9p: remove unnece...
308
309
310
  	if (err == -EAGAIN) {
  		clear_bit(Rworksched, &m->wsched);
  		return;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
311
  	}
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
312

5503ac565   Eric Van Hensbergen   9p: remove unnece...
313
314
315
316
  	if (err <= 0)
  		goto error;
  
  	m->rpos += err;
1b0a763bd   Eric Van Hensbergen   9p: use the rcall...
317
318
319
  
  	if ((!m->req) && (m->rpos == m->rsize)) { /* header read in */
  		u16 tag;
5d3851530   Joe Perches   9p: Reduce object...
320
321
  		p9_debug(P9_DEBUG_TRANS, "got new header
  ");
1b0a763bd   Eric Van Hensbergen   9p: use the rcall...
322
323
  
  		n = le32_to_cpu(*(__le32 *) m->rbuf); /* read packet size */
5503ac565   Eric Van Hensbergen   9p: remove unnece...
324
  		if (n >= m->client->msize) {
5d3851530   Joe Perches   9p: Reduce object...
325
326
327
  			p9_debug(P9_DEBUG_ERROR,
  				 "requested packet size too big: %d
  ", n);
5503ac565   Eric Van Hensbergen   9p: remove unnece...
328
329
330
  			err = -EIO;
  			goto error;
  		}
1b0a763bd   Eric Van Hensbergen   9p: use the rcall...
331
  		tag = le16_to_cpu(*(__le16 *) (m->rbuf+5)); /* read tag */
5d3851530   Joe Perches   9p: Reduce object...
332
333
334
  		p9_debug(P9_DEBUG_TRANS,
  			 "mux %p pkt: size: %d bytes tag: %d
  ", m, n, tag);
1b0a763bd   Eric Van Hensbergen   9p: use the rcall...
335
336
  
  		m->req = p9_tag_lookup(m->client, tag);
1bab88b23   Latchesar Ionkov   net/9p: handle co...
337
338
  		if (!m->req || (m->req->status != REQ_STATUS_SENT &&
  					m->req->status != REQ_STATUS_FLSH)) {
5d3851530   Joe Perches   9p: Reduce object...
339
340
341
  			p9_debug(P9_DEBUG_ERROR, "Unexpected packet tag %d
  ",
  				 tag);
1b0a763bd   Eric Van Hensbergen   9p: use the rcall...
342
343
344
345
346
347
  			err = -EIO;
  			goto error;
  		}
  
  		if (m->req->rc == NULL) {
  			m->req->rc = kmalloc(sizeof(struct p9_fcall) +
eeff66ef6   Aneesh Kumar K.V   net/9p: Convert t...
348
  						m->client->msize, GFP_NOFS);
1b0a763bd   Eric Van Hensbergen   9p: use the rcall...
349
350
351
352
353
354
355
356
357
358
  			if (!m->req->rc) {
  				m->req = NULL;
  				err = -ENOMEM;
  				goto error;
  			}
  		}
  		m->rbuf = (char *)m->req->rc + sizeof(struct p9_fcall);
  		memcpy(m->rbuf, m->tmp_buf, m->rsize);
  		m->rsize = n;
  	}
5503ac565   Eric Van Hensbergen   9p: remove unnece...
359

1b0a763bd   Eric Van Hensbergen   9p: use the rcall...
360
361
  	/* not an else because some packets (like clunk) have no payload */
  	if ((m->req) && (m->rpos == m->rsize)) { /* packet is read in */
5d3851530   Joe Perches   9p: Reduce object...
362
363
  		p9_debug(P9_DEBUG_TRANS, "got new packet
  ");
7eb923b80   Eric Van Hensbergen   9p: add more cons...
364
  		spin_lock(&m->client->lock);
1bab88b23   Latchesar Ionkov   net/9p: handle co...
365
366
  		if (m->req->status != REQ_STATUS_ERROR)
  			m->req->status = REQ_STATUS_RCVD;
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
367
  		list_del(&m->req->req_list);
7eb923b80   Eric Van Hensbergen   9p: add more cons...
368
  		spin_unlock(&m->client->lock);
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
369
  		p9_client_cb(m->client, m->req);
1b0a763bd   Eric Van Hensbergen   9p: use the rcall...
370
371
372
  		m->rbuf = NULL;
  		m->rpos = 0;
  		m->rsize = 0;
1b0a763bd   Eric Van Hensbergen   9p: use the rcall...
373
  		m->req = NULL;
5503ac565   Eric Van Hensbergen   9p: remove unnece...
374
375
376
377
378
379
380
381
382
  	}
  
  	if (!list_empty(&m->req_list)) {
  		if (test_and_clear_bit(Rpending, &m->wsched))
  			n = POLLIN;
  		else
  			n = p9_fd_poll(m->client, NULL);
  
  		if (n & POLLIN) {
5d3851530   Joe Perches   9p: Reduce object...
383
384
  			p9_debug(P9_DEBUG_TRANS, "sched read work %p
  ", m);
61edeeed9   Tejun Heo   net/9p: use syste...
385
  			schedule_work(&m->rq);
5503ac565   Eric Van Hensbergen   9p: remove unnece...
386
387
388
389
390
391
  		} else
  			clear_bit(Rworksched, &m->wsched);
  	} else
  		clear_bit(Rworksched, &m->wsched);
  
  	return;
5503ac565   Eric Van Hensbergen   9p: remove unnece...
392
393
394
395
396
397
398
399
400
401
  error:
  	p9_conn_cancel(m, err);
  	clear_bit(Rworksched, &m->wsched);
  }
  
  /**
   * p9_fd_write - write to a socket
   * @client: client instance
   * @v: buffer to send data from
   * @len: size of send buffer
ee443996a   Eric Van Hensbergen   9p: Documentation...
402
   *
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
403
   */
ee443996a   Eric Van Hensbergen   9p: Documentation...
404

5503ac565   Eric Van Hensbergen   9p: remove unnece...
405
  static int p9_fd_write(struct p9_client *client, void *v, int len)
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
406
  {
5503ac565   Eric Van Hensbergen   9p: remove unnece...
407
408
409
  	int ret;
  	mm_segment_t oldfs;
  	struct p9_trans_fd *ts = NULL;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
410

5503ac565   Eric Van Hensbergen   9p: remove unnece...
411
412
  	if (client && client->status != Disconnected)
  		ts = client->trans;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
413

5503ac565   Eric Van Hensbergen   9p: remove unnece...
414
415
  	if (!ts)
  		return -EREMOTEIO;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
416

5503ac565   Eric Van Hensbergen   9p: remove unnece...
417
  	if (!(ts->wr->f_flags & O_NONBLOCK))
5d3851530   Joe Perches   9p: Reduce object...
418
419
  		p9_debug(P9_DEBUG_ERROR, "blocking write ...
  ");
992b3f1db   Tejun Heo   9p-trans_fd: use ...
420

5503ac565   Eric Van Hensbergen   9p: remove unnece...
421
422
423
  	oldfs = get_fs();
  	set_fs(get_ds());
  	/* The cast to a user pointer is valid due to the set_fs() */
e3db6cb42   Hannes Eder   9p: fix sparse wa...
424
  	ret = vfs_write(ts->wr, (__force void __user *)v, len, &ts->wr->f_pos);
5503ac565   Eric Van Hensbergen   9p: remove unnece...
425
  	set_fs(oldfs);
992b3f1db   Tejun Heo   9p-trans_fd: use ...
426

5503ac565   Eric Van Hensbergen   9p: remove unnece...
427
428
429
  	if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
  		client->status = Disconnected;
  	return ret;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
430
431
432
433
  }
  
  /**
   * p9_write_work - called when a transport can send some data
ee443996a   Eric Van Hensbergen   9p: Documentation...
434
435
   * @work: container for work to be done
   *
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
436
   */
ee443996a   Eric Van Hensbergen   9p: Documentation...
437

8a0dc95fd   Eric Van Hensbergen   9p: transport API...
438
439
440
441
  static void p9_write_work(struct work_struct *work)
  {
  	int n, err;
  	struct p9_conn *m;
673d62cda   Eric Van Hensbergen   9p: apply common ...
442
  	struct p9_req_t *req;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
443
444
445
446
447
448
449
450
451
452
453
454
455
  
  	m = container_of(work, struct p9_conn, wq);
  
  	if (m->err < 0) {
  		clear_bit(Wworksched, &m->wsched);
  		return;
  	}
  
  	if (!m->wsize) {
  		if (list_empty(&m->unsent_req_list)) {
  			clear_bit(Wworksched, &m->wsched);
  			return;
  		}
673d62cda   Eric Van Hensbergen   9p: apply common ...
456
457
  		spin_lock(&m->client->lock);
  		req = list_entry(m->unsent_req_list.next, struct p9_req_t,
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
458
  			       req_list);
673d62cda   Eric Van Hensbergen   9p: apply common ...
459
  		req->status = REQ_STATUS_SENT;
5d3851530   Joe Perches   9p: Reduce object...
460
461
  		p9_debug(P9_DEBUG_TRANS, "move req %p
  ", req);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
462
  		list_move_tail(&req->req_list, &m->req_list);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
463

673d62cda   Eric Van Hensbergen   9p: apply common ...
464
465
  		m->wbuf = req->tc->sdata;
  		m->wsize = req->tc->size;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
466
  		m->wpos = 0;
673d62cda   Eric Van Hensbergen   9p: apply common ...
467
  		spin_unlock(&m->client->lock);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
468
  	}
5d3851530   Joe Perches   9p: Reduce object...
469
470
471
  	p9_debug(P9_DEBUG_TRANS, "mux %p pos %d size %d
  ",
  		 m, m->wpos, m->wsize);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
472
  	clear_bit(Wpending, &m->wsched);
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
473
  	err = p9_fd_write(m->client, m->wbuf + m->wpos, m->wsize - m->wpos);
5d3851530   Joe Perches   9p: Reduce object...
474
475
  	p9_debug(P9_DEBUG_TRANS, "mux %p sent %d bytes
  ", m, err);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
  	if (err == -EAGAIN) {
  		clear_bit(Wworksched, &m->wsched);
  		return;
  	}
  
  	if (err < 0)
  		goto error;
  	else if (err == 0) {
  		err = -EREMOTEIO;
  		goto error;
  	}
  
  	m->wpos += err;
  	if (m->wpos == m->wsize)
  		m->wpos = m->wsize = 0;
  
  	if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) {
  		if (test_and_clear_bit(Wpending, &m->wsched))
  			n = POLLOUT;
  		else
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
496
  			n = p9_fd_poll(m->client, NULL);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
497
498
  
  		if (n & POLLOUT) {
5d3851530   Joe Perches   9p: Reduce object...
499
500
  			p9_debug(P9_DEBUG_TRANS, "sched write work %p
  ", m);
61edeeed9   Tejun Heo   net/9p: use syste...
501
  			schedule_work(&m->wq);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
502
503
504
505
506
507
508
509
510
511
512
  		} else
  			clear_bit(Wworksched, &m->wsched);
  	} else
  		clear_bit(Wworksched, &m->wsched);
  
  	return;
  
  error:
  	p9_conn_cancel(m, err);
  	clear_bit(Wworksched, &m->wsched);
  }
5503ac565   Eric Van Hensbergen   9p: remove unnece...
513
  static int p9_pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
514
  {
5503ac565   Eric Van Hensbergen   9p: remove unnece...
515
516
517
518
  	struct p9_poll_wait *pwait =
  		container_of(wait, struct p9_poll_wait, wait);
  	struct p9_conn *m = pwait->conn;
  	unsigned long flags;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
519

5503ac565   Eric Van Hensbergen   9p: remove unnece...
520
521
522
523
  	spin_lock_irqsave(&p9_poll_lock, flags);
  	if (list_empty(&m->poll_pending_link))
  		list_add_tail(&m->poll_pending_link, &p9_poll_pending_list);
  	spin_unlock_irqrestore(&p9_poll_lock, flags);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
524

aa70c585b   Tejun Heo   net/9p: replace p...
525
526
  	schedule_work(&p9_poll_work);
  	return 1;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
527
528
529
  }
  
  /**
5503ac565   Eric Van Hensbergen   9p: remove unnece...
530
531
532
533
   * p9_pollwait - add poll task to the wait queue
   * @filp: file pointer being polled
   * @wait_address: wait_q to block on
   * @p: poll state
ee443996a   Eric Van Hensbergen   9p: Documentation...
534
   *
5503ac565   Eric Van Hensbergen   9p: remove unnece...
535
   * called by files poll operation to add v9fs-poll task to files wait queue
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
536
   */
ee443996a   Eric Van Hensbergen   9p: Documentation...
537

5503ac565   Eric Van Hensbergen   9p: remove unnece...
538
539
  static void
  p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p)
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
540
  {
5503ac565   Eric Van Hensbergen   9p: remove unnece...
541
542
543
  	struct p9_conn *m = container_of(p, struct p9_conn, pt);
  	struct p9_poll_wait *pwait = NULL;
  	int i;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
544

5503ac565   Eric Van Hensbergen   9p: remove unnece...
545
546
547
548
  	for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) {
  		if (m->poll_wait[i].wait_addr == NULL) {
  			pwait = &m->poll_wait[i];
  			break;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
549
  		}
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
550
  	}
5503ac565   Eric Van Hensbergen   9p: remove unnece...
551
  	if (!pwait) {
5d3851530   Joe Perches   9p: Reduce object...
552
553
  		p9_debug(P9_DEBUG_ERROR, "not enough wait_address slots
  ");
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
554
555
  		return;
  	}
5503ac565   Eric Van Hensbergen   9p: remove unnece...
556
557
558
559
560
  	pwait->conn = m;
  	pwait->wait_addr = wait_address;
  	init_waitqueue_func_entry(&pwait->wait, p9_pollwake);
  	add_wait_queue(wait_address, &pwait->wait);
  }
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
561

5503ac565   Eric Van Hensbergen   9p: remove unnece...
562
563
564
565
566
567
  /**
   * p9_conn_create - allocate and initialize the per-session mux data
   * @client: client instance
   *
   * Note: Creates the polling task if this is the first session.
   */
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
568

5503ac565   Eric Van Hensbergen   9p: remove unnece...
569
570
  static struct p9_conn *p9_conn_create(struct p9_client *client)
  {
95820a365   Tejun Heo   9p: drop broken u...
571
  	int n;
5503ac565   Eric Van Hensbergen   9p: remove unnece...
572
  	struct p9_conn *m;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
573

5d3851530   Joe Perches   9p: Reduce object...
574
575
  	p9_debug(P9_DEBUG_TRANS, "client %p msize %d
  ", client, client->msize);
5503ac565   Eric Van Hensbergen   9p: remove unnece...
576
577
578
  	m = kzalloc(sizeof(struct p9_conn), GFP_KERNEL);
  	if (!m)
  		return ERR_PTR(-ENOMEM);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
579

5503ac565   Eric Van Hensbergen   9p: remove unnece...
580
581
  	INIT_LIST_HEAD(&m->mux_list);
  	m->client = client;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
582

5503ac565   Eric Van Hensbergen   9p: remove unnece...
583
584
585
586
587
588
  	INIT_LIST_HEAD(&m->req_list);
  	INIT_LIST_HEAD(&m->unsent_req_list);
  	INIT_WORK(&m->rq, p9_read_work);
  	INIT_WORK(&m->wq, p9_write_work);
  	INIT_LIST_HEAD(&m->poll_pending_link);
  	init_poll_funcptr(&m->pt, p9_pollwait);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
589

5503ac565   Eric Van Hensbergen   9p: remove unnece...
590
591
  	n = p9_fd_poll(client, &m->pt);
  	if (n & POLLIN) {
5d3851530   Joe Perches   9p: Reduce object...
592
593
  		p9_debug(P9_DEBUG_TRANS, "mux %p can read
  ", m);
5503ac565   Eric Van Hensbergen   9p: remove unnece...
594
595
  		set_bit(Rpending, &m->wsched);
  	}
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
596

5503ac565   Eric Van Hensbergen   9p: remove unnece...
597
  	if (n & POLLOUT) {
5d3851530   Joe Perches   9p: Reduce object...
598
599
  		p9_debug(P9_DEBUG_TRANS, "mux %p can write
  ", m);
5503ac565   Eric Van Hensbergen   9p: remove unnece...
600
601
  		set_bit(Wpending, &m->wsched);
  	}
5503ac565   Eric Van Hensbergen   9p: remove unnece...
602
603
  	return m;
  }
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
604

5503ac565   Eric Van Hensbergen   9p: remove unnece...
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
  /**
   * p9_poll_mux - polls a mux and schedules read or write works if necessary
   * @m: connection to poll
   *
   */
  
  static void p9_poll_mux(struct p9_conn *m)
  {
  	int n;
  
  	if (m->err < 0)
  		return;
  
  	n = p9_fd_poll(m->client, NULL);
  	if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) {
5d3851530   Joe Perches   9p: Reduce object...
620
621
  		p9_debug(P9_DEBUG_TRANS, "error mux %p err %d
  ", m, n);
5503ac565   Eric Van Hensbergen   9p: remove unnece...
622
623
624
625
626
627
628
  		if (n >= 0)
  			n = -ECONNRESET;
  		p9_conn_cancel(m, n);
  	}
  
  	if (n & POLLIN) {
  		set_bit(Rpending, &m->wsched);
5d3851530   Joe Perches   9p: Reduce object...
629
630
  		p9_debug(P9_DEBUG_TRANS, "mux %p can read
  ", m);
5503ac565   Eric Van Hensbergen   9p: remove unnece...
631
  		if (!test_and_set_bit(Rworksched, &m->wsched)) {
5d3851530   Joe Perches   9p: Reduce object...
632
633
  			p9_debug(P9_DEBUG_TRANS, "sched read work %p
  ", m);
61edeeed9   Tejun Heo   net/9p: use syste...
634
  			schedule_work(&m->rq);
5503ac565   Eric Van Hensbergen   9p: remove unnece...
635
636
  		}
  	}
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
637

5503ac565   Eric Van Hensbergen   9p: remove unnece...
638
639
  	if (n & POLLOUT) {
  		set_bit(Wpending, &m->wsched);
5d3851530   Joe Perches   9p: Reduce object...
640
641
  		p9_debug(P9_DEBUG_TRANS, "mux %p can write
  ", m);
f64f9e719   Joe Perches   net: Move && and ...
642
643
  		if ((m->wsize || !list_empty(&m->unsent_req_list)) &&
  		    !test_and_set_bit(Wworksched, &m->wsched)) {
5d3851530   Joe Perches   9p: Reduce object...
644
645
  			p9_debug(P9_DEBUG_TRANS, "sched write work %p
  ", m);
61edeeed9   Tejun Heo   net/9p: use syste...
646
  			schedule_work(&m->wq);
5503ac565   Eric Van Hensbergen   9p: remove unnece...
647
648
  		}
  	}
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
649
650
651
  }
  
  /**
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
652
   * p9_fd_request - send 9P request
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
653
654
   * The function can sleep until the request is scheduled for sending.
   * The function can be interrupted. Return from the function is not
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
655
   * a guarantee that the request is sent successfully.
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
656
   *
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
657
658
   * @client: client instance
   * @req: request to be sent
ee443996a   Eric Van Hensbergen   9p: Documentation...
659
   *
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
660
   */
ee443996a   Eric Van Hensbergen   9p: Documentation...
661

91b8534fa   Eric Van Hensbergen   9p: make rpc code...
662
  static int p9_fd_request(struct p9_client *client, struct p9_req_t *req)
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
663
664
  {
  	int n;
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
665
666
  	struct p9_trans_fd *ts = client->trans;
  	struct p9_conn *m = ts->conn;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
667

5d3851530   Joe Perches   9p: Reduce object...
668
669
670
  	p9_debug(P9_DEBUG_TRANS, "mux %p task %p tcall %p id %d
  ",
  		 m, current, req->tc, req->tc->id);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
671
  	if (m->err < 0)
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
672
  		return m->err;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
673

91b8534fa   Eric Van Hensbergen   9p: make rpc code...
674
  	spin_lock(&client->lock);
7eb923b80   Eric Van Hensbergen   9p: add more cons...
675
  	req->status = REQ_STATUS_UNSENT;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
676
  	list_add_tail(&req->req_list, &m->unsent_req_list);
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
677
  	spin_unlock(&client->lock);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
678
679
680
681
  
  	if (test_and_clear_bit(Wpending, &m->wsched))
  		n = POLLOUT;
  	else
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
682
  		n = p9_fd_poll(m->client, NULL);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
683
684
  
  	if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched))
61edeeed9   Tejun Heo   net/9p: use syste...
685
  		schedule_work(&m->wq);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
686

91b8534fa   Eric Van Hensbergen   9p: make rpc code...
687
  	return 0;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
688
  }
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
689
  static int p9_fd_cancel(struct p9_client *client, struct p9_req_t *req)
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
690
  {
7eb923b80   Eric Van Hensbergen   9p: add more cons...
691
  	int ret = 1;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
692

5d3851530   Joe Perches   9p: Reduce object...
693
694
  	p9_debug(P9_DEBUG_TRANS, "client %p req %p
  ", client, req);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
695

91b8534fa   Eric Van Hensbergen   9p: make rpc code...
696
  	spin_lock(&client->lock);
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
697

91b8534fa   Eric Van Hensbergen   9p: make rpc code...
698
  	if (req->status == REQ_STATUS_UNSENT) {
1bab88b23   Latchesar Ionkov   net/9p: handle co...
699
  		list_del(&req->req_list);
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
700
  		req->status = REQ_STATUS_FLSHD;
7eb923b80   Eric Van Hensbergen   9p: add more cons...
701
  		ret = 0;
1bab88b23   Latchesar Ionkov   net/9p: handle co...
702
703
  	} else if (req->status == REQ_STATUS_SENT)
  		req->status = REQ_STATUS_FLSH;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
704

7eb923b80   Eric Van Hensbergen   9p: add more cons...
705
706
707
  	spin_unlock(&client->lock);
  
  	return ret;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
708
  }
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
709
  /**
0e15597eb   Abhishek Kulkarni   9p: minor comment...
710
711
712
   * parse_opts - parse mount options into p9_fd_opts structure
   * @params: options string passed from mount
   * @opts: fd transport-specific structure to parse options into
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
713
   *
bb8ffdfc3   Eric Van Hensbergen   9p: propagate par...
714
   * Returns 0 upon success, -ERRNO upon failure
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
715
   */
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
716

bb8ffdfc3   Eric Van Hensbergen   9p: propagate par...
717
  static int parse_opts(char *params, struct p9_fd_opts *opts)
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
718
  {
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
719
720
721
  	char *p;
  	substring_t args[MAX_OPT_ARGS];
  	int option;
d8c8a9e36   Eric Van Hensbergen   9p: fix option pa...
722
  	char *options, *tmp_options;
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
723

a80d923e1   Eric Van Hensbergen   9p: Make transpor...
724
725
726
  	opts->port = P9_PORT;
  	opts->rfd = ~0;
  	opts->wfd = ~0;
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
727

bb8ffdfc3   Eric Van Hensbergen   9p: propagate par...
728
729
  	if (!params)
  		return 0;
d8c8a9e36   Eric Van Hensbergen   9p: fix option pa...
730
731
  	tmp_options = kstrdup(params, GFP_KERNEL);
  	if (!tmp_options) {
5d3851530   Joe Perches   9p: Reduce object...
732
733
734
  		p9_debug(P9_DEBUG_ERROR,
  			 "failed to allocate copy of option string
  ");
bb8ffdfc3   Eric Van Hensbergen   9p: propagate par...
735
736
  		return -ENOMEM;
  	}
d8c8a9e36   Eric Van Hensbergen   9p: fix option pa...
737
  	options = tmp_options;
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
738

a80d923e1   Eric Van Hensbergen   9p: Make transpor...
739
740
  	while ((p = strsep(&options, ",")) != NULL) {
  		int token;
bb8ffdfc3   Eric Van Hensbergen   9p: propagate par...
741
  		int r;
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
742
743
744
  		if (!*p)
  			continue;
  		token = match_token(p, tokens, args);
15da4b161   Abhishek Kulkarni   net/9p: Fix crash...
745
746
747
  		if (token != Opt_err) {
  			r = match_int(&args[0], &option);
  			if (r < 0) {
5d3851530   Joe Perches   9p: Reduce object...
748
749
750
  				p9_debug(P9_DEBUG_ERROR,
  					 "integer field, but no integer?
  ");
15da4b161   Abhishek Kulkarni   net/9p: Fix crash...
751
752
  				continue;
  			}
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
753
754
755
756
757
758
759
760
761
762
763
764
765
766
  		}
  		switch (token) {
  		case Opt_port:
  			opts->port = option;
  			break;
  		case Opt_rfdno:
  			opts->rfd = option;
  			break;
  		case Opt_wfdno:
  			opts->wfd = option;
  			break;
  		default:
  			continue;
  		}
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
767
  	}
d8c8a9e36   Eric Van Hensbergen   9p: fix option pa...
768
769
  
  	kfree(tmp_options);
bb8ffdfc3   Eric Van Hensbergen   9p: propagate par...
770
  	return 0;
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
771
  }
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
772

8b81ef589   Eric Van Hensbergen   9p: consolidate t...
773
  static int p9_fd_open(struct p9_client *client, int rfd, int wfd)
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
774
  {
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
775
776
777
778
  	struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd),
  					   GFP_KERNEL);
  	if (!ts)
  		return -ENOMEM;
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
779

a80d923e1   Eric Van Hensbergen   9p: Make transpor...
780
781
782
783
784
785
786
787
788
  	ts->rd = fget(rfd);
  	ts->wr = fget(wfd);
  	if (!ts->rd || !ts->wr) {
  		if (ts->rd)
  			fput(ts->rd);
  		if (ts->wr)
  			fput(ts->wr);
  		kfree(ts);
  		return -EIO;
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
789
  	}
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
790
791
  	client->trans = ts;
  	client->status = Connected;
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
792

a80d923e1   Eric Van Hensbergen   9p: Make transpor...
793
  	return 0;
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
794
  }
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
795

8b81ef589   Eric Van Hensbergen   9p: consolidate t...
796
  static int p9_socket_open(struct p9_client *client, struct socket *csocket)
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
797
  {
6b18662e2   Al Viro   9p connect fixes
798
799
800
801
802
803
  	struct p9_trans_fd *p;
  	int ret, fd;
  
  	p = kmalloc(sizeof(struct p9_trans_fd), GFP_KERNEL);
  	if (!p)
  		return -ENOMEM;
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
804
805
  
  	csocket->sk->sk_allocation = GFP_NOIO;
a677a039b   Ulrich Drepper   flag parameters: ...
806
  	fd = sock_map_fd(csocket, 0);
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
807
  	if (fd < 0) {
5d3851530   Joe Perches   9p: Reduce object...
808
809
810
  		pr_err("%s (%d): failed to map fd
  ",
  		       __func__, task_pid_nr(current));
6b18662e2   Al Viro   9p connect fixes
811
812
  		sock_release(csocket);
  		kfree(p);
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
813
814
  		return fd;
  	}
6b18662e2   Al Viro   9p connect fixes
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
  	get_file(csocket->file);
  	get_file(csocket->file);
  	p->wr = p->rd = csocket->file;
  	client->trans = p;
  	client->status = Connected;
  
  	sys_close(fd);	/* still racy */
  
  	p->rd->f_flags |= O_NONBLOCK;
  
  	p->conn = p9_conn_create(client);
  	if (IS_ERR(p->conn)) {
  		ret = PTR_ERR(p->conn);
  		p->conn = NULL;
  		kfree(p);
  		sockfd_put(csocket);
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
831
832
833
  		sockfd_put(csocket);
  		return ret;
  	}
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
834
835
  	return 0;
  }
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
836
  /**
5503ac565   Eric Van Hensbergen   9p: remove unnece...
837
838
   * p9_mux_destroy - cancels all pending requests and frees mux resources
   * @m: mux to destroy
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
839
840
   *
   */
ee443996a   Eric Van Hensbergen   9p: Documentation...
841

5503ac565   Eric Van Hensbergen   9p: remove unnece...
842
  static void p9_conn_destroy(struct p9_conn *m)
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
843
  {
5d3851530   Joe Perches   9p: Reduce object...
844
845
846
  	p9_debug(P9_DEBUG_TRANS, "mux %p prev %p next %p
  ",
  		 m, m->mux_list.prev, m->mux_list.next);
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
847

5503ac565   Eric Van Hensbergen   9p: remove unnece...
848
849
850
  	p9_mux_poll_stop(m);
  	cancel_work_sync(&m->rq);
  	cancel_work_sync(&m->wq);
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
851

5503ac565   Eric Van Hensbergen   9p: remove unnece...
852
  	p9_conn_cancel(m, -ECONNRESET);
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
853

5503ac565   Eric Van Hensbergen   9p: remove unnece...
854
  	m->client = NULL;
5503ac565   Eric Van Hensbergen   9p: remove unnece...
855
  	kfree(m);
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
856
857
858
  }
  
  /**
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
859
860
   * p9_fd_close - shutdown file descriptor transport
   * @client: client instance
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
861
862
   *
   */
ee443996a   Eric Van Hensbergen   9p: Documentation...
863

8b81ef589   Eric Van Hensbergen   9p: consolidate t...
864
  static void p9_fd_close(struct p9_client *client)
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
865
866
  {
  	struct p9_trans_fd *ts;
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
867
  	if (!client)
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
868
  		return;
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
869
  	ts = client->trans;
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
870
871
  	if (!ts)
  		return;
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
872
  	client->status = Disconnected;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
873
  	p9_conn_destroy(ts->conn);
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
874
875
876
877
  	if (ts->rd)
  		fput(ts->rd);
  	if (ts->wr)
  		fput(ts->wr);
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
878

bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
879
880
  	kfree(ts);
  }
887b3ece6   Eric Van Hensbergen   9p: fix error pat...
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
  /*
   * stolen from NFS - maybe should be made a generic function?
   */
  static inline int valid_ipaddr4(const char *buf)
  {
  	int rc, count, in[4];
  
  	rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]);
  	if (rc != 4)
  		return -EINVAL;
  	for (count = 0; count < 4; count++) {
  		if (in[count] > 255)
  			return -EINVAL;
  	}
  	return 0;
  }
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
897
898
  static int
  p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
899
900
  {
  	int err;
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
901
902
903
  	struct socket *csocket;
  	struct sockaddr_in sin_server;
  	struct p9_fd_opts opts;
bb8ffdfc3   Eric Van Hensbergen   9p: propagate par...
904
905
  	err = parse_opts(args, &opts);
  	if (err < 0)
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
906
  		return err;
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
907

887b3ece6   Eric Van Hensbergen   9p: fix error pat...
908
  	if (valid_ipaddr4(addr) < 0)
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
909
  		return -EINVAL;
887b3ece6   Eric Van Hensbergen   9p: fix error pat...
910

a80d923e1   Eric Van Hensbergen   9p: Make transpor...
911
  	csocket = NULL;
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
912
913
914
915
  
  	sin_server.sin_family = AF_INET;
  	sin_server.sin_addr.s_addr = in_aton(addr);
  	sin_server.sin_port = htons(opts.port);
e75762fdc   Rob Landley   net/9p: enable 9p...
916
917
  	err = __sock_create(read_pnet(&current->nsproxy->net_ns), PF_INET,
  			    SOCK_STREAM, IPPROTO_TCP, &csocket, 1);
6b18662e2   Al Viro   9p connect fixes
918
  	if (err) {
5d3851530   Joe Perches   9p: Reduce object...
919
920
921
  		pr_err("%s (%d): problem creating socket
  ",
  		       __func__, task_pid_nr(current));
6b18662e2   Al Viro   9p connect fixes
922
  		return err;
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
923
924
925
926
927
928
  	}
  
  	err = csocket->ops->connect(csocket,
  				    (struct sockaddr *)&sin_server,
  				    sizeof(struct sockaddr_in), 0);
  	if (err < 0) {
5d3851530   Joe Perches   9p: Reduce object...
929
930
931
  		pr_err("%s (%d): problem connecting socket to %s
  ",
  		       __func__, task_pid_nr(current), addr);
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
932
  		sock_release(csocket);
6b18662e2   Al Viro   9p connect fixes
933
934
  		return err;
  	}
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
935

6b18662e2   Al Viro   9p connect fixes
936
  	return p9_socket_open(client, csocket);
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
937
  }
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
938
939
  static int
  p9_fd_create_unix(struct p9_client *client, const char *addr, char *args)
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
940
941
942
943
  {
  	int err;
  	struct socket *csocket;
  	struct sockaddr_un sun_server;
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
944
945
  
  	csocket = NULL;
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
946

cff6b8a9b   Dan Carpenter   9p: strlen() does...
947
  	if (strlen(addr) >= UNIX_PATH_MAX) {
5d3851530   Joe Perches   9p: Reduce object...
948
949
950
  		pr_err("%s (%d): address too long: %s
  ",
  		       __func__, task_pid_nr(current), addr);
6b18662e2   Al Viro   9p connect fixes
951
  		return -ENAMETOOLONG;
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
952
953
954
955
  	}
  
  	sun_server.sun_family = PF_UNIX;
  	strcpy(sun_server.sun_path, addr);
e75762fdc   Rob Landley   net/9p: enable 9p...
956
957
  	err = __sock_create(read_pnet(&current->nsproxy->net_ns), PF_UNIX,
  			    SOCK_STREAM, 0, &csocket, 1);
6b18662e2   Al Viro   9p connect fixes
958
  	if (err < 0) {
5d3851530   Joe Perches   9p: Reduce object...
959
960
961
  		pr_err("%s (%d): problem creating socket
  ",
  		       __func__, task_pid_nr(current));
6b18662e2   Al Viro   9p connect fixes
962
963
  		return err;
  	}
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
964
965
966
  	err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
  			sizeof(struct sockaddr_un) - 1, 0);
  	if (err < 0) {
5d3851530   Joe Perches   9p: Reduce object...
967
968
969
  		pr_err("%s (%d): problem connecting socket: %s: %d
  ",
  		       __func__, task_pid_nr(current), addr, err);
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
970
  		sock_release(csocket);
6b18662e2   Al Viro   9p connect fixes
971
972
  		return err;
  	}
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
973

6b18662e2   Al Viro   9p connect fixes
974
  	return p9_socket_open(client, csocket);
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
975
  }
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
976
977
  static int
  p9_fd_create(struct p9_client *client, const char *addr, char *args)
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
978
979
  {
  	int err;
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
980
  	struct p9_fd_opts opts;
6b18662e2   Al Viro   9p connect fixes
981
  	struct p9_trans_fd *p;
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
982
983
984
985
  
  	parse_opts(args, &opts);
  
  	if (opts.rfd == ~0 || opts.wfd == ~0) {
5d3851530   Joe Perches   9p: Reduce object...
986
987
  		pr_err("Insufficient options for proto=fd
  ");
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
988
  		return -ENOPROTOOPT;
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
989
  	}
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
990
  	err = p9_fd_open(client, opts.rfd, opts.wfd);
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
991
  	if (err < 0)
6b18662e2   Al Viro   9p connect fixes
992
  		return err;
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
993

8b81ef589   Eric Van Hensbergen   9p: consolidate t...
994
995
  	p = (struct p9_trans_fd *) client->trans;
  	p->conn = p9_conn_create(client);
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
996
997
998
  	if (IS_ERR(p->conn)) {
  		err = PTR_ERR(p->conn);
  		p->conn = NULL;
6b18662e2   Al Viro   9p connect fixes
999
1000
1001
  		fput(p->rd);
  		fput(p->wr);
  		return err;
8a0dc95fd   Eric Van Hensbergen   9p: transport API...
1002
  	}
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
1003
  	return 0;
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
1004
1005
1006
1007
1008
1009
  }
  
  static struct p9_trans_module p9_tcp_trans = {
  	.name = "tcp",
  	.maxsize = MAX_SOCK_BUF,
  	.def = 1,
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
1010
1011
  	.create = p9_fd_create_tcp,
  	.close = p9_fd_close,
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
1012
1013
  	.request = p9_fd_request,
  	.cancel = p9_fd_cancel,
72029fe85   Tejun Heo   9p: implement pro...
1014
  	.owner = THIS_MODULE,
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
1015
1016
1017
1018
1019
1020
  };
  
  static struct p9_trans_module p9_unix_trans = {
  	.name = "unix",
  	.maxsize = MAX_SOCK_BUF,
  	.def = 0,
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
1021
1022
  	.create = p9_fd_create_unix,
  	.close = p9_fd_close,
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
1023
1024
  	.request = p9_fd_request,
  	.cancel = p9_fd_cancel,
72029fe85   Tejun Heo   9p: implement pro...
1025
  	.owner = THIS_MODULE,
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
1026
1027
1028
1029
1030
1031
  };
  
  static struct p9_trans_module p9_fd_trans = {
  	.name = "fd",
  	.maxsize = MAX_SOCK_BUF,
  	.def = 0,
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
1032
1033
  	.create = p9_fd_create,
  	.close = p9_fd_close,
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
1034
1035
  	.request = p9_fd_request,
  	.cancel = p9_fd_cancel,
72029fe85   Tejun Heo   9p: implement pro...
1036
  	.owner = THIS_MODULE,
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
1037
  };
5503ac565   Eric Van Hensbergen   9p: remove unnece...
1038
1039
1040
1041
1042
1043
1044
1045
  /**
   * p9_poll_proc - poll worker thread
   * @a: thread state and arguments
   *
   * polls all v9fs transports for new events and queues the appropriate
   * work to the work queue
   *
   */
aa70c585b   Tejun Heo   net/9p: replace p...
1046
  static void p9_poll_workfn(struct work_struct *work)
5503ac565   Eric Van Hensbergen   9p: remove unnece...
1047
1048
  {
  	unsigned long flags;
5d3851530   Joe Perches   9p: Reduce object...
1049
1050
  	p9_debug(P9_DEBUG_TRANS, "start %p
  ", current);
aa70c585b   Tejun Heo   net/9p: replace p...
1051

5503ac565   Eric Van Hensbergen   9p: remove unnece...
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
  	spin_lock_irqsave(&p9_poll_lock, flags);
  	while (!list_empty(&p9_poll_pending_list)) {
  		struct p9_conn *conn = list_first_entry(&p9_poll_pending_list,
  							struct p9_conn,
  							poll_pending_link);
  		list_del_init(&conn->poll_pending_link);
  		spin_unlock_irqrestore(&p9_poll_lock, flags);
  
  		p9_poll_mux(conn);
  
  		spin_lock_irqsave(&p9_poll_lock, flags);
  	}
  	spin_unlock_irqrestore(&p9_poll_lock, flags);
5d3851530   Joe Perches   9p: Reduce object...
1065
1066
  	p9_debug(P9_DEBUG_TRANS, "finish
  ");
5503ac565   Eric Van Hensbergen   9p: remove unnece...
1067
  }
887b3ece6   Eric Van Hensbergen   9p: fix error pat...
1068
  int p9_trans_fd_init(void)
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
1069
1070
1071
1072
  {
  	v9fs_register_trans(&p9_tcp_trans);
  	v9fs_register_trans(&p9_unix_trans);
  	v9fs_register_trans(&p9_fd_trans);
3387b804d   Andrew Morton   net/9p/trans_fd.c...
1073
  	return 0;
a80d923e1   Eric Van Hensbergen   9p: Make transpor...
1074
  }
72029fe85   Tejun Heo   9p: implement pro...
1075
1076
1077
  
  void p9_trans_fd_exit(void)
  {
aa70c585b   Tejun Heo   net/9p: replace p...
1078
  	flush_work_sync(&p9_poll_work);
72029fe85   Tejun Heo   9p: implement pro...
1079
1080
1081
1082
  	v9fs_unregister_trans(&p9_tcp_trans);
  	v9fs_unregister_trans(&p9_unix_trans);
  	v9fs_unregister_trans(&p9_fd_trans);
  }