blob: 627e3f097fc5a355cf551a1cdff212a5e92b3e67 [file] [log] [blame]
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001/*
2 * linux/fs/9p/trans_fd.c
3 *
4 * Fd transport layer. Includes deprecated socket layer.
5 *
6 * Copyright (C) 2006 by Russ Cox <rsc@swtch.com>
7 * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -06008 * Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com>
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05009 * Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2
13 * as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to:
22 * Free Software Foundation
23 * 51 Franklin Street, Fifth Floor
24 * Boston, MA 02111-1301 USA
25 *
26 */
27
28#include <linux/in.h>
29#include <linux/module.h>
30#include <linux/net.h>
31#include <linux/ipv6.h>
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -060032#include <linux/kthread.h>
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -050033#include <linux/errno.h>
34#include <linux/kernel.h>
35#include <linux/un.h>
36#include <linux/uaccess.h>
37#include <linux/inet.h>
38#include <linux/idr.h>
39#include <linux/file.h>
Eric Van Hensbergena80d9232007-10-17 14:31:07 -050040#include <linux/parser.h>
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -050041#include <net/9p/9p.h>
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -050042#include <net/9p/client.h>
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -050043#include <net/9p/transport.h>
44
45#define P9_PORT 564
Eric Van Hensbergena80d9232007-10-17 14:31:07 -050046#define MAX_SOCK_BUF (64*1024)
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -060047#define MAXPOLLWADDR 2
Eric Van Hensbergena80d9232007-10-17 14:31:07 -050048
Eric Van Hensbergenee443992008-03-05 07:08:09 -060049/**
50 * struct p9_fd_opts - per-transport options
51 * @rfd: file descriptor for reading (trans=fd)
52 * @wfd: file descriptor for writing (trans=fd)
53 * @port: port to connect to (trans=tcp)
54 *
55 */
56
Eric Van Hensbergena80d9232007-10-17 14:31:07 -050057struct p9_fd_opts {
58 int rfd;
59 int wfd;
60 u16 port;
61};
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -050062
Eric Van Hensbergenee443992008-03-05 07:08:09 -060063/**
64 * struct p9_trans_fd - transport state
65 * @rd: reference to file to read from
66 * @wr: reference of file to write to
67 * @conn: connection state reference
68 *
69 */
70
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -050071struct p9_trans_fd {
72 struct file *rd;
73 struct file *wr;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -060074 struct p9_conn *conn;
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -050075};
76
Eric Van Hensbergena80d9232007-10-17 14:31:07 -050077/*
78 * Option Parsing (code inspired by NFS code)
79 * - a little lazy - parse all fd-transport options
80 */
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -050081
Eric Van Hensbergena80d9232007-10-17 14:31:07 -050082enum {
83 /* Options that take integer arguments */
Latchesar Ionkov55762692007-11-06 08:02:53 -060084 Opt_port, Opt_rfdno, Opt_wfdno, Opt_err,
Eric Van Hensbergena80d9232007-10-17 14:31:07 -050085};
86
Steven Whitehousea447c092008-10-13 10:46:57 +010087static const match_table_t tokens = {
Eric Van Hensbergena80d9232007-10-17 14:31:07 -050088 {Opt_port, "port=%u"},
89 {Opt_rfdno, "rfdno=%u"},
90 {Opt_wfdno, "wfdno=%u"},
Latchesar Ionkov55762692007-11-06 08:02:53 -060091 {Opt_err, NULL},
Eric Van Hensbergena80d9232007-10-17 14:31:07 -050092};
93
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -060094enum {
95 Rworksched = 1, /* read work scheduled or running */
96 Rpending = 2, /* can read */
97 Wworksched = 4, /* write work scheduled or running */
98 Wpending = 8, /* can write */
99};
100
Tejun Heo992b3f12008-10-13 18:45:25 -0500101struct p9_poll_wait {
102 struct p9_conn *conn;
103 wait_queue_t wait;
104 wait_queue_head_t *wait_addr;
Eric Van Hensbergenee443992008-03-05 07:08:09 -0600105};
106
107/**
108 * struct p9_conn - fd mux connection state information
Eric Van Hensbergenee443992008-03-05 07:08:09 -0600109 * @mux_list: list link for mux to manage multiple connections (?)
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -0500110 * @client: reference to client instance for this connection
Eric Van Hensbergenee443992008-03-05 07:08:09 -0600111 * @err: error state
Eric Van Hensbergenee443992008-03-05 07:08:09 -0600112 * @req_list: accounting for requests which have been sent
113 * @unsent_req_list: accounting for requests that haven't been sent
Eric Van Hensbergen1b0a7632008-10-13 18:45:22 -0500114 * @req: current request being processed (if any)
115 * @tmp_buf: temporary buffer to read in header
116 * @rsize: amount to read for current frame
Eric Van Hensbergenee443992008-03-05 07:08:09 -0600117 * @rpos: read position in current frame
118 * @rbuf: current read buffer
119 * @wpos: write position for current frame
120 * @wsize: amount of data to write for current frame
121 * @wbuf: current write buffer
122 * @poll_wait: array of wait_q's for various worker threads
123 * @poll_waddr: ????
124 * @pt: poll state
125 * @rq: current read work
126 * @wq: current write work
127 * @wsched: ????
128 *
129 */
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600130
131struct p9_conn {
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600132 struct list_head mux_list;
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -0500133 struct p9_client *client;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600134 int err;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600135 struct list_head req_list;
136 struct list_head unsent_req_list;
Eric Van Hensbergen1b0a7632008-10-13 18:45:22 -0500137 struct p9_req_t *req;
138 char tmp_buf[7];
139 int rsize;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600140 int rpos;
141 char *rbuf;
142 int wpos;
143 int wsize;
144 char *wbuf;
Tejun Heo992b3f12008-10-13 18:45:25 -0500145 struct list_head poll_pending_link;
146 struct p9_poll_wait poll_wait[MAXPOLLWADDR];
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600147 poll_table pt;
148 struct work_struct rq;
149 struct work_struct wq;
150 unsigned long wsched;
151};
152
Tejun Heo992b3f12008-10-13 18:45:25 -0500153static DEFINE_SPINLOCK(p9_poll_lock);
154static LIST_HEAD(p9_poll_pending_list);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600155static struct workqueue_struct *p9_mux_wq;
Tejun Heo992b3f12008-10-13 18:45:25 -0500156static struct task_struct *p9_poll_task;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600157
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600158static void p9_mux_poll_stop(struct p9_conn *m)
159{
Tejun Heo992b3f12008-10-13 18:45:25 -0500160 unsigned long flags;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600161 int i;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600162
Tejun Heo992b3f12008-10-13 18:45:25 -0500163 for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) {
164 struct p9_poll_wait *pwait = &m->poll_wait[i];
165
166 if (pwait->wait_addr) {
167 remove_wait_queue(pwait->wait_addr, &pwait->wait);
168 pwait->wait_addr = NULL;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600169 }
170 }
Tejun Heo992b3f12008-10-13 18:45:25 -0500171
172 spin_lock_irqsave(&p9_poll_lock, flags);
173 list_del_init(&m->poll_pending_link);
174 spin_unlock_irqrestore(&p9_poll_lock, flags);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600175}
176
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500177static void p9_conn_rpc_cb(struct p9_client *, struct p9_req_t *);
Eric Van Hensbergen044c7762008-10-13 18:45:23 -0500178
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500179static void p9_mux_flush_cb(struct p9_client *client, struct p9_req_t *freq)
Eric Van Hensbergen044c7762008-10-13 18:45:23 -0500180{
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500181 struct p9_conn *m = client->trans;
182 struct p9_req_t *req;
Eric Van Hensbergen044c7762008-10-13 18:45:23 -0500183
184 P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m,
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500185 freq->tc, freq->rc, freq->t_err,
186 freq->tc->params.tflush.oldtag);
Eric Van Hensbergen044c7762008-10-13 18:45:23 -0500187
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500188 req = p9_tag_lookup(client, freq->tc->params.tflush.oldtag);
Eric Van Hensbergen044c7762008-10-13 18:45:23 -0500189 if (req) {
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500190 req->status = REQ_STATUS_FLSHD;
191 list_del(&req->req_list);
192 p9_conn_rpc_cb(client, req);
Eric Van Hensbergen044c7762008-10-13 18:45:23 -0500193 }
194
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500195 p9_free_req(client, freq);
Eric Van Hensbergen044c7762008-10-13 18:45:23 -0500196}
197
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500198static void p9_conn_rpc_cb(struct p9_client *client, struct p9_req_t *req)
Eric Van Hensbergen044c7762008-10-13 18:45:23 -0500199{
200 P9_DPRINTK(P9_DEBUG_MUX, "req %p\n", req);
201
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500202 if (req->tc->id == P9_TFLUSH) { /* flush callback */
Eric Van Hensbergen044c7762008-10-13 18:45:23 -0500203 P9_DPRINTK(P9_DEBUG_MUX, "flush req %p\n", req);
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500204 p9_mux_flush_cb(client, req);
Eric Van Hensbergen044c7762008-10-13 18:45:23 -0500205 } else { /* normal wakeup path */
206 P9_DPRINTK(P9_DEBUG_MUX, "normal req %p\n", req);
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500207 if (!req->t_err && (req->status == REQ_STATUS_FLSHD ||
208 req->status == REQ_STATUS_FLSH))
209 req->t_err = -ERESTARTSYS;
Eric Van Hensbergen044c7762008-10-13 18:45:23 -0500210
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500211 wake_up(req->wq);
Eric Van Hensbergen044c7762008-10-13 18:45:23 -0500212 }
213}
214
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600215/**
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -0500216 * p9_conn_cancel - cancel all pending requests with error
217 * @m: mux data
218 * @err: error code
Eric Van Hensbergenee443992008-03-05 07:08:09 -0600219 *
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600220 */
Eric Van Hensbergenee443992008-03-05 07:08:09 -0600221
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -0500222void p9_conn_cancel(struct p9_conn *m, int err)
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600223{
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500224 struct p9_req_t *req, *rtmp;
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -0500225 LIST_HEAD(cancel_list);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600226
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -0500227 P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err);
228 m->err = err;
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500229 spin_lock(&m->client->lock);
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -0500230 list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) {
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500231 req->status = REQ_STATUS_ERROR;
232 if (!req->t_err)
233 req->t_err = err;
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -0500234 list_move(&req->req_list, &cancel_list);
Tejun Heo992b3f12008-10-13 18:45:25 -0500235 }
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -0500236 list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) {
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500237 req->status = REQ_STATUS_ERROR;
238 if (!req->t_err)
239 req->t_err = err;
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -0500240 list_move(&req->req_list, &cancel_list);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600241 }
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500242 spin_unlock(&m->client->lock);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600243
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -0500244 list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) {
245 list_del(&req->req_list);
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500246 p9_conn_rpc_cb(m->client, req);
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -0500247 }
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600248}
249
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500250static void process_request(struct p9_conn *m, struct p9_req_t *req)
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600251{
252 int ecode;
253 struct p9_str *ename;
254
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500255 if (!req->t_err && req->rc->id == P9_RERROR) {
256 ecode = req->rc->params.rerror.errno;
257 ename = &req->rc->params.rerror.error;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600258
259 P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len,
260 ename->str);
261
Eric Van Hensbergenbead27f2008-10-13 18:45:24 -0500262 if (m->client->dotu)
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500263 req->t_err = -ecode;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600264
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500265 if (!req->t_err) {
266 req->t_err = p9_errstr2errno(ename->str, ename->len);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600267
268 /* string match failed */
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500269 if (!req->t_err) {
270 PRINT_FCALL_ERROR("unknown error", req->rc);
271 req->t_err = -ESERVERFAULT;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600272 }
273 }
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500274 } else if (req->tc && req->rc->id != req->tc->id + 1) {
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600275 P9_DPRINTK(P9_DEBUG_ERROR,
276 "fcall mismatch: expected %d, got %d\n",
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500277 req->tc->id + 1, req->rc->id);
278 if (!req->t_err)
279 req->t_err = -EIO;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600280 }
281}
282
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -0500283static unsigned int
284p9_fd_poll(struct p9_client *client, struct poll_table_struct *pt)
285{
286 int ret, n;
287 struct p9_trans_fd *ts = NULL;
288
289 if (client && client->status == Connected)
290 ts = client->trans;
291
292 if (!ts)
293 return -EREMOTEIO;
294
295 if (!ts->rd->f_op || !ts->rd->f_op->poll)
296 return -EIO;
297
298 if (!ts->wr->f_op || !ts->wr->f_op->poll)
299 return -EIO;
300
301 ret = ts->rd->f_op->poll(ts->rd, pt);
302 if (ret < 0)
303 return ret;
304
305 if (ts->rd != ts->wr) {
306 n = ts->wr->f_op->poll(ts->wr, pt);
307 if (n < 0)
308 return n;
309 ret = (ret & ~POLLOUT) | (n & ~POLLIN);
310 }
311
312 return ret;
313}
314
315/**
316 * p9_fd_read- read from a fd
317 * @client: client instance
318 * @v: buffer to receive data into
319 * @len: size of receive buffer
320 *
321 */
322
323static int p9_fd_read(struct p9_client *client, void *v, int len)
324{
325 int ret;
326 struct p9_trans_fd *ts = NULL;
327
328 if (client && client->status != Disconnected)
329 ts = client->trans;
330
331 if (!ts)
332 return -EREMOTEIO;
333
334 if (!(ts->rd->f_flags & O_NONBLOCK))
335 P9_DPRINTK(P9_DEBUG_ERROR, "blocking read ...\n");
336
337 ret = kernel_read(ts->rd, ts->rd->f_pos, v, len);
338 if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
339 client->status = Disconnected;
340 return ret;
341}
342
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600343/**
344 * p9_read_work - called when there is some data to be read from a transport
Eric Van Hensbergenee443992008-03-05 07:08:09 -0600345 * @work: container of work to be done
346 *
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600347 */
Eric Van Hensbergenee443992008-03-05 07:08:09 -0600348
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600349static void p9_read_work(struct work_struct *work)
350{
351 int n, err;
352 struct p9_conn *m;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600353
354 m = container_of(work, struct p9_conn, rq);
355
356 if (m->err < 0)
357 return;
358
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600359 P9_DPRINTK(P9_DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos);
360
Eric Van Hensbergen1b0a7632008-10-13 18:45:22 -0500361 if (!m->rbuf) {
362 m->rbuf = m->tmp_buf;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600363 m->rpos = 0;
Eric Van Hensbergen1b0a7632008-10-13 18:45:22 -0500364 m->rsize = 7; /* start by reading header */
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600365 }
366
367 clear_bit(Rpending, &m->wsched);
Eric Van Hensbergen1b0a7632008-10-13 18:45:22 -0500368 P9_DPRINTK(P9_DEBUG_MUX, "read mux %p pos %d size: %d = %d\n", m,
369 m->rpos, m->rsize, m->rsize-m->rpos);
Eric Van Hensbergenbead27f2008-10-13 18:45:24 -0500370 err = p9_fd_read(m->client, m->rbuf + m->rpos,
Eric Van Hensbergen1b0a7632008-10-13 18:45:22 -0500371 m->rsize - m->rpos);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600372 P9_DPRINTK(P9_DEBUG_MUX, "mux %p got %d bytes\n", m, err);
373 if (err == -EAGAIN) {
374 clear_bit(Rworksched, &m->wsched);
375 return;
376 }
377
378 if (err <= 0)
379 goto error;
380
381 m->rpos += err;
Eric Van Hensbergen1b0a7632008-10-13 18:45:22 -0500382
383 if ((!m->req) && (m->rpos == m->rsize)) { /* header read in */
384 u16 tag;
385 P9_DPRINTK(P9_DEBUG_MUX, "got new header\n");
386
387 n = le32_to_cpu(*(__le32 *) m->rbuf); /* read packet size */
Eric Van Hensbergenbead27f2008-10-13 18:45:24 -0500388 if (n >= m->client->msize) {
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600389 P9_DPRINTK(P9_DEBUG_ERROR,
390 "requested packet size too big: %d\n", n);
391 err = -EIO;
392 goto error;
393 }
394
Eric Van Hensbergen1b0a7632008-10-13 18:45:22 -0500395 tag = le16_to_cpu(*(__le16 *) (m->rbuf+5)); /* read tag */
396 P9_DPRINTK(P9_DEBUG_MUX, "mux %p pkt: size: %d bytes tag: %d\n",
397 m, n, tag);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600398
Eric Van Hensbergen1b0a7632008-10-13 18:45:22 -0500399 m->req = p9_tag_lookup(m->client, tag);
400 if (!m->req) {
401 P9_DPRINTK(P9_DEBUG_ERROR, "Unexpected packet tag %d\n",
402 tag);
403 err = -EIO;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600404 goto error;
Eric Van Hensbergen1b0a7632008-10-13 18:45:22 -0500405 }
406
407 if (m->req->rc == NULL) {
408 m->req->rc = kmalloc(sizeof(struct p9_fcall) +
409 m->client->msize, GFP_KERNEL);
410 if (!m->req->rc) {
411 m->req = NULL;
412 err = -ENOMEM;
413 goto error;
414 }
415 }
416 m->rbuf = (char *)m->req->rc + sizeof(struct p9_fcall);
417 memcpy(m->rbuf, m->tmp_buf, m->rsize);
418 m->rsize = n;
419 }
420
421 /* not an else because some packets (like clunk) have no payload */
422 if ((m->req) && (m->rpos == m->rsize)) { /* packet is read in */
423 P9_DPRINTK(P9_DEBUG_MUX, "got new packet\n");
424 m->rbuf = (char *)m->req->rc + sizeof(struct p9_fcall);
425 err = p9_deserialize_fcall(m->rbuf, m->rsize, m->req->rc,
426 m->client->dotu);
427 if (err < 0) {
428 m->req = NULL;
429 goto error;
430 }
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600431
432#ifdef CONFIG_NET_9P_DEBUG
433 if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
434 char buf[150];
435
Eric Van Hensbergen1b0a7632008-10-13 18:45:22 -0500436 p9_printfcall(buf, sizeof(buf), m->req->rc,
Eric Van Hensbergenbead27f2008-10-13 18:45:24 -0500437 m->client->dotu);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600438 printk(KERN_NOTICE ">>> %p %s\n", m, buf);
439 }
440#endif
441
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600442 P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m,
Eric Van Hensbergen1b0a7632008-10-13 18:45:22 -0500443 m->req->rc->id, m->req->rc->tag);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600444
Eric Van Hensbergen1b0a7632008-10-13 18:45:22 -0500445 m->rbuf = NULL;
446 m->rpos = 0;
447 m->rsize = 0;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600448
Eric Van Hensbergen1b0a7632008-10-13 18:45:22 -0500449 if (m->req->status != REQ_STATUS_FLSH) {
450 list_del(&m->req->req_list);
451 m->req->status = REQ_STATUS_RCVD;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600452 }
Eric Van Hensbergen1b0a7632008-10-13 18:45:22 -0500453
454 process_request(m, m->req);
455
456 if (m->req->status != REQ_STATUS_FLSH)
457 p9_conn_rpc_cb(m->client, m->req);
458
459 m->req = NULL;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600460 }
461
462 if (!list_empty(&m->req_list)) {
463 if (test_and_clear_bit(Rpending, &m->wsched))
464 n = POLLIN;
465 else
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -0500466 n = p9_fd_poll(m->client, NULL);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600467
468 if (n & POLLIN) {
469 P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m);
470 queue_work(p9_mux_wq, &m->rq);
471 } else
472 clear_bit(Rworksched, &m->wsched);
473 } else
474 clear_bit(Rworksched, &m->wsched);
475
476 return;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600477error:
478 p9_conn_cancel(m, err);
479 clear_bit(Rworksched, &m->wsched);
480}
481
482/**
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -0500483 * p9_fd_write - write to a socket
484 * @client: client instance
485 * @v: buffer to send data from
486 * @len: size of send buffer
487 *
488 */
489
490static int p9_fd_write(struct p9_client *client, void *v, int len)
491{
492 int ret;
493 mm_segment_t oldfs;
494 struct p9_trans_fd *ts = NULL;
495
496 if (client && client->status != Disconnected)
497 ts = client->trans;
498
499 if (!ts)
500 return -EREMOTEIO;
501
502 if (!(ts->wr->f_flags & O_NONBLOCK))
503 P9_DPRINTK(P9_DEBUG_ERROR, "blocking write ...\n");
504
505 oldfs = get_fs();
506 set_fs(get_ds());
507 /* The cast to a user pointer is valid due to the set_fs() */
508 ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos);
509 set_fs(oldfs);
510
511 if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
512 client->status = Disconnected;
513 return ret;
514}
515
516/**
517 * p9_write_work - called when a transport can send some data
518 * @work: container for work to be done
519 *
520 */
521
522static void p9_write_work(struct work_struct *work)
523{
524 int n, err;
525 struct p9_conn *m;
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500526 struct p9_req_t *req;
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -0500527
528 m = container_of(work, struct p9_conn, wq);
529
530 if (m->err < 0) {
531 clear_bit(Wworksched, &m->wsched);
532 return;
533 }
534
535 if (!m->wsize) {
536 if (list_empty(&m->unsent_req_list)) {
537 clear_bit(Wworksched, &m->wsched);
538 return;
539 }
540
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500541 spin_lock(&m->client->lock);
542 req = list_entry(m->unsent_req_list.next, struct p9_req_t,
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -0500543 req_list);
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500544 req->status = REQ_STATUS_SENT;
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -0500545 list_move_tail(&req->req_list, &m->req_list);
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -0500546
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500547 m->wbuf = req->tc->sdata;
548 m->wsize = req->tc->size;
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -0500549 m->wpos = 0;
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500550 spin_unlock(&m->client->lock);
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -0500551 }
552
553 P9_DPRINTK(P9_DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos,
554 m->wsize);
555 clear_bit(Wpending, &m->wsched);
556 err = p9_fd_write(m->client, m->wbuf + m->wpos, m->wsize - m->wpos);
557 P9_DPRINTK(P9_DEBUG_MUX, "mux %p sent %d bytes\n", m, err);
558 if (err == -EAGAIN) {
559 clear_bit(Wworksched, &m->wsched);
560 return;
561 }
562
563 if (err < 0)
564 goto error;
565 else if (err == 0) {
566 err = -EREMOTEIO;
567 goto error;
568 }
569
570 m->wpos += err;
571 if (m->wpos == m->wsize)
572 m->wpos = m->wsize = 0;
573
574 if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) {
575 if (test_and_clear_bit(Wpending, &m->wsched))
576 n = POLLOUT;
577 else
578 n = p9_fd_poll(m->client, NULL);
579
580 if (n & POLLOUT) {
581 P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m);
582 queue_work(p9_mux_wq, &m->wq);
583 } else
584 clear_bit(Wworksched, &m->wsched);
585 } else
586 clear_bit(Wworksched, &m->wsched);
587
588 return;
589
590error:
591 p9_conn_cancel(m, err);
592 clear_bit(Wworksched, &m->wsched);
593}
594
595static int p9_pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
596{
597 struct p9_poll_wait *pwait =
598 container_of(wait, struct p9_poll_wait, wait);
599 struct p9_conn *m = pwait->conn;
600 unsigned long flags;
601 DECLARE_WAITQUEUE(dummy_wait, p9_poll_task);
602
603 spin_lock_irqsave(&p9_poll_lock, flags);
604 if (list_empty(&m->poll_pending_link))
605 list_add_tail(&m->poll_pending_link, &p9_poll_pending_list);
606 spin_unlock_irqrestore(&p9_poll_lock, flags);
607
608 /* perform the default wake up operation */
609 return default_wake_function(&dummy_wait, mode, sync, key);
610}
611
612/**
613 * p9_pollwait - add poll task to the wait queue
614 * @filp: file pointer being polled
615 * @wait_address: wait_q to block on
616 * @p: poll state
617 *
618 * called by files poll operation to add v9fs-poll task to files wait queue
619 */
620
621static void
622p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p)
623{
624 struct p9_conn *m = container_of(p, struct p9_conn, pt);
625 struct p9_poll_wait *pwait = NULL;
626 int i;
627
628 for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) {
629 if (m->poll_wait[i].wait_addr == NULL) {
630 pwait = &m->poll_wait[i];
631 break;
632 }
633 }
634
635 if (!pwait) {
636 P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n");
637 return;
638 }
639
640 if (!wait_address) {
641 P9_DPRINTK(P9_DEBUG_ERROR, "no wait_address\n");
642 pwait->wait_addr = ERR_PTR(-EIO);
643 return;
644 }
645
646 pwait->conn = m;
647 pwait->wait_addr = wait_address;
648 init_waitqueue_func_entry(&pwait->wait, p9_pollwake);
649 add_wait_queue(wait_address, &pwait->wait);
650}
651
652/**
653 * p9_conn_create - allocate and initialize the per-session mux data
654 * @client: client instance
655 *
656 * Note: Creates the polling task if this is the first session.
657 */
658
659static struct p9_conn *p9_conn_create(struct p9_client *client)
660{
661 int i, n;
662 struct p9_conn *m;
663
664 P9_DPRINTK(P9_DEBUG_MUX, "client %p msize %d\n", client, client->msize);
665 m = kzalloc(sizeof(struct p9_conn), GFP_KERNEL);
666 if (!m)
667 return ERR_PTR(-ENOMEM);
668
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -0500669 INIT_LIST_HEAD(&m->mux_list);
670 m->client = client;
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -0500671
672 INIT_LIST_HEAD(&m->req_list);
673 INIT_LIST_HEAD(&m->unsent_req_list);
674 INIT_WORK(&m->rq, p9_read_work);
675 INIT_WORK(&m->wq, p9_write_work);
676 INIT_LIST_HEAD(&m->poll_pending_link);
677 init_poll_funcptr(&m->pt, p9_pollwait);
678
679 n = p9_fd_poll(client, &m->pt);
680 if (n & POLLIN) {
681 P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m);
682 set_bit(Rpending, &m->wsched);
683 }
684
685 if (n & POLLOUT) {
686 P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m);
687 set_bit(Wpending, &m->wsched);
688 }
689
690 for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) {
691 if (IS_ERR(m->poll_wait[i].wait_addr)) {
692 p9_mux_poll_stop(m);
693 kfree(m);
694 /* return the error code */
695 return (void *)m->poll_wait[i].wait_addr;
696 }
697 }
698
699 return m;
700}
701
702/**
703 * p9_poll_mux - polls a mux and schedules read or write works if necessary
704 * @m: connection to poll
705 *
706 */
707
708static void p9_poll_mux(struct p9_conn *m)
709{
710 int n;
711
712 if (m->err < 0)
713 return;
714
715 n = p9_fd_poll(m->client, NULL);
716 if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) {
717 P9_DPRINTK(P9_DEBUG_MUX, "error mux %p err %d\n", m, n);
718 if (n >= 0)
719 n = -ECONNRESET;
720 p9_conn_cancel(m, n);
721 }
722
723 if (n & POLLIN) {
724 set_bit(Rpending, &m->wsched);
725 P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m);
726 if (!test_and_set_bit(Rworksched, &m->wsched)) {
727 P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m);
728 queue_work(p9_mux_wq, &m->rq);
729 }
730 }
731
732 if (n & POLLOUT) {
733 set_bit(Wpending, &m->wsched);
734 P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m);
735 if ((m->wsize || !list_empty(&m->unsent_req_list))
736 && !test_and_set_bit(Wworksched, &m->wsched)) {
737 P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m);
738 queue_work(p9_mux_wq, &m->wq);
739 }
740 }
741}
742
743/**
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600744 * p9_send_request - send 9P request
745 * The function can sleep until the request is scheduled for sending.
746 * The function can be interrupted. Return from the function is not
747 * a guarantee that the request is sent successfully. Can return errors
748 * that can be retrieved by PTR_ERR macros.
749 *
750 * @m: mux data
751 * @tc: request to be sent
Eric Van Hensbergenee443992008-03-05 07:08:09 -0600752 *
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600753 */
Eric Van Hensbergenee443992008-03-05 07:08:09 -0600754
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500755static struct p9_req_t *p9_send_request(struct p9_conn *m, struct p9_fcall *tc)
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600756{
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500757 int tag;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600758 int n;
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500759 struct p9_req_t *req;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600760
761 P9_DPRINTK(P9_DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current,
762 tc, tc->id);
763 if (m->err < 0)
764 return ERR_PTR(m->err);
765
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500766 tag = P9_NOTAG;
Eric Van Hensbergenff683452008-10-13 18:45:22 -0500767 if (tc->id != P9_TVERSION) {
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500768 tag = p9_idpool_get(m->client->tagpool);
769 if (tag < 0)
Eric Van Hensbergenff683452008-10-13 18:45:22 -0500770 return ERR_PTR(-ENOMEM);
Julia Lawall62067822008-09-24 16:22:22 -0500771 }
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600772
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500773 p9_set_tag(tc, tag);
774
775 req = p9_tag_alloc(m->client, tag);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600776
777#ifdef CONFIG_NET_9P_DEBUG
778 if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
779 char buf[150];
780
Eric Van Hensbergenbead27f2008-10-13 18:45:24 -0500781 p9_printfcall(buf, sizeof(buf), tc, m->client->dotu);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600782 printk(KERN_NOTICE "<<< %p %s\n", m, buf);
783 }
784#endif
785
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500786 req->tag = tag;
787 req->tc = tc;
788 req->rc = NULL;
789 req->t_err = 0;
790 req->status = REQ_STATUS_UNSENT;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600791
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500792 spin_lock(&m->client->lock);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600793 list_add_tail(&req->req_list, &m->unsent_req_list);
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500794 spin_unlock(&m->client->lock);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600795
796 if (test_and_clear_bit(Wpending, &m->wsched))
797 n = POLLOUT;
798 else
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -0500799 n = p9_fd_poll(m->client, NULL);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600800
801 if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched))
802 queue_work(p9_mux_wq, &m->wq);
803
804 return req;
805}
806
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600807static int
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500808p9_mux_flush_request(struct p9_conn *m, struct p9_req_t *req)
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600809{
810 struct p9_fcall *fc;
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500811 struct p9_req_t *rreq, *rptr;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600812
813 P9_DPRINTK(P9_DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag);
814
815 /* if a response was received for a request, do nothing */
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500816 if (req->rc || req->t_err) {
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600817 P9_DPRINTK(P9_DEBUG_MUX,
818 "mux %p req %p response already received\n", m, req);
819 return 0;
820 }
821
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500822 req->status = REQ_STATUS_FLSH;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600823
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500824 spin_lock(&m->client->lock);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600825 /* if the request is not sent yet, just remove it from the list */
826 list_for_each_entry_safe(rreq, rptr, &m->unsent_req_list, req_list) {
827 if (rreq->tag == req->tag) {
828 P9_DPRINTK(P9_DEBUG_MUX,
829 "mux %p req %p request is not sent yet\n", m, req);
830 list_del(&rreq->req_list);
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500831 req->status = REQ_STATUS_FLSHD;
832 spin_unlock(&m->client->lock);
833 p9_conn_rpc_cb(m->client, req);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600834 return 0;
835 }
836 }
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500837 spin_unlock(&m->client->lock);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600838
839 clear_thread_flag(TIF_SIGPENDING);
840 fc = p9_create_tflush(req->tag);
Eric Van Hensbergen044c7762008-10-13 18:45:23 -0500841 p9_send_request(m, fc);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600842 return 1;
843}
844
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600845/**
846 * p9_fd_rpc- sends 9P request and waits until a response is available.
847 * The function can be interrupted.
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -0500848 * @client: client instance
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600849 * @tc: request to be sent
850 * @rc: pointer where a pointer to the response is stored
Eric Van Hensbergenee443992008-03-05 07:08:09 -0600851 *
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600852 */
Eric Van Hensbergenee443992008-03-05 07:08:09 -0600853
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600854int
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -0500855p9_fd_rpc(struct p9_client *client, struct p9_fcall *tc, struct p9_fcall **rc)
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600856{
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -0500857 struct p9_trans_fd *p = client->trans;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600858 struct p9_conn *m = p->conn;
859 int err, sigpending;
860 unsigned long flags;
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500861 struct p9_req_t *req;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600862
863 if (rc)
864 *rc = NULL;
865
866 sigpending = 0;
867 if (signal_pending(current)) {
868 sigpending = 1;
869 clear_thread_flag(TIF_SIGPENDING);
870 }
871
Eric Van Hensbergen044c7762008-10-13 18:45:23 -0500872 req = p9_send_request(m, tc);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600873 if (IS_ERR(req)) {
874 err = PTR_ERR(req);
875 P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err);
876 return err;
877 }
878
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500879 err = wait_event_interruptible(*req->wq, req->rc != NULL ||
880 req->t_err < 0);
881 if (req->t_err < 0)
882 err = req->t_err;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600883
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -0500884 if (err == -ERESTARTSYS && client->status == Connected
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600885 && m->err == 0) {
886 if (p9_mux_flush_request(m, req)) {
887 /* wait until we get response of the flush message */
888 do {
889 clear_thread_flag(TIF_SIGPENDING);
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500890 err = wait_event_interruptible(*req->wq,
891 req->rc || req->t_err);
892 } while (!req->rc && !req->t_err &&
Eric Van Hensbergen21c00362008-10-13 18:45:24 -0500893 err == -ERESTARTSYS &&
894 client->status == Connected && !m->err);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600895
896 err = -ERESTARTSYS;
897 }
898 sigpending = 1;
899 }
900
901 if (sigpending) {
902 spin_lock_irqsave(&current->sighand->siglock, flags);
903 recalc_sigpending();
904 spin_unlock_irqrestore(&current->sighand->siglock, flags);
905 }
906
907 if (rc)
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500908 *rc = req->rc;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600909 else
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500910 kfree(req->rc);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600911
Eric Van Hensbergen673d62cd2008-10-13 18:45:22 -0500912 p9_free_req(client, req);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600913 if (err > 0)
914 err = -EIO;
915
916 return err;
917}
918
Eric Van Hensbergena80d9232007-10-17 14:31:07 -0500919/**
Eric Van Hensbergenbb8ffdf2008-03-07 10:53:53 -0600920 * parse_options - parse mount options into session structure
Eric Van Hensbergena80d9232007-10-17 14:31:07 -0500921 * @options: options string passed from mount
Eric Van Hensbergenee443992008-03-05 07:08:09 -0600922 * @opts: transport-specific structure to parse options into
Eric Van Hensbergena80d9232007-10-17 14:31:07 -0500923 *
Eric Van Hensbergenbb8ffdf2008-03-07 10:53:53 -0600924 * Returns 0 upon success, -ERRNO upon failure
Eric Van Hensbergena80d9232007-10-17 14:31:07 -0500925 */
926
Eric Van Hensbergenbb8ffdf2008-03-07 10:53:53 -0600927static int parse_opts(char *params, struct p9_fd_opts *opts)
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500928{
Eric Van Hensbergena80d9232007-10-17 14:31:07 -0500929 char *p;
930 substring_t args[MAX_OPT_ARGS];
931 int option;
Eric Van Hensbergenbb8ffdf2008-03-07 10:53:53 -0600932 char *options;
Eric Van Hensbergena80d9232007-10-17 14:31:07 -0500933 int ret;
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500934
Eric Van Hensbergena80d9232007-10-17 14:31:07 -0500935 opts->port = P9_PORT;
936 opts->rfd = ~0;
937 opts->wfd = ~0;
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500938
Eric Van Hensbergenbb8ffdf2008-03-07 10:53:53 -0600939 if (!params)
940 return 0;
941
942 options = kstrdup(params, GFP_KERNEL);
943 if (!options) {
944 P9_DPRINTK(P9_DEBUG_ERROR,
945 "failed to allocate copy of option string\n");
946 return -ENOMEM;
947 }
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500948
Eric Van Hensbergena80d9232007-10-17 14:31:07 -0500949 while ((p = strsep(&options, ",")) != NULL) {
950 int token;
Eric Van Hensbergenbb8ffdf2008-03-07 10:53:53 -0600951 int r;
Eric Van Hensbergena80d9232007-10-17 14:31:07 -0500952 if (!*p)
953 continue;
954 token = match_token(p, tokens, args);
Eric Van Hensbergenbb8ffdf2008-03-07 10:53:53 -0600955 r = match_int(&args[0], &option);
956 if (r < 0) {
Eric Van Hensbergena80d9232007-10-17 14:31:07 -0500957 P9_DPRINTK(P9_DEBUG_ERROR,
958 "integer field, but no integer?\n");
Eric Van Hensbergenbb8ffdf2008-03-07 10:53:53 -0600959 ret = r;
Eric Van Hensbergena80d9232007-10-17 14:31:07 -0500960 continue;
961 }
962 switch (token) {
963 case Opt_port:
964 opts->port = option;
965 break;
966 case Opt_rfdno:
967 opts->rfd = option;
968 break;
969 case Opt_wfdno:
970 opts->wfd = option;
971 break;
972 default:
973 continue;
974 }
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500975 }
Eric Van Hensbergenbb8ffdf2008-03-07 10:53:53 -0600976 kfree(options);
977 return 0;
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500978}
979
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -0500980static int p9_fd_open(struct p9_client *client, int rfd, int wfd)
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500981{
982 struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd),
983 GFP_KERNEL);
984 if (!ts)
985 return -ENOMEM;
986
987 ts->rd = fget(rfd);
988 ts->wr = fget(wfd);
989 if (!ts->rd || !ts->wr) {
990 if (ts->rd)
991 fput(ts->rd);
992 if (ts->wr)
993 fput(ts->wr);
994 kfree(ts);
995 return -EIO;
996 }
997
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -0500998 client->trans = ts;
999 client->status = Connected;
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001000
1001 return 0;
1002}
1003
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001004static int p9_socket_open(struct p9_client *client, struct socket *csocket)
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001005{
1006 int fd, ret;
1007
1008 csocket->sk->sk_allocation = GFP_NOIO;
Ulrich Dreppera677a032008-07-23 21:29:17 -07001009 fd = sock_map_fd(csocket, 0);
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001010 if (fd < 0) {
1011 P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n");
1012 return fd;
1013 }
1014
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001015 ret = p9_fd_open(client, fd, fd);
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001016 if (ret < 0) {
1017 P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to open fd\n");
1018 sockfd_put(csocket);
1019 return ret;
1020 }
1021
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001022 ((struct p9_trans_fd *)client->trans)->rd->f_flags |= O_NONBLOCK;
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001023
1024 return 0;
1025}
1026
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001027/**
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -05001028 * p9_mux_destroy - cancels all pending requests and frees mux resources
1029 * @m: mux to destroy
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001030 *
1031 */
Eric Van Hensbergenee443992008-03-05 07:08:09 -06001032
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -05001033static void p9_conn_destroy(struct p9_conn *m)
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001034{
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -05001035 P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m,
1036 m->mux_list.prev, m->mux_list.next);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001037
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -05001038 p9_mux_poll_stop(m);
1039 cancel_work_sync(&m->rq);
1040 cancel_work_sync(&m->wq);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001041
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -05001042 p9_conn_cancel(m, -ECONNRESET);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001043
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -05001044 m->client = NULL;
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -05001045 kfree(m);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001046}
1047
1048/**
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001049 * p9_fd_close - shutdown file descriptor transport
1050 * @client: client instance
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001051 *
1052 */
Eric Van Hensbergenee443992008-03-05 07:08:09 -06001053
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001054static void p9_fd_close(struct p9_client *client)
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001055{
1056 struct p9_trans_fd *ts;
1057
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001058 if (!client)
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001059 return;
1060
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001061 ts = client->trans;
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001062 if (!ts)
1063 return;
1064
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001065 client->status = Disconnected;
1066
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -06001067 p9_conn_destroy(ts->conn);
1068
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001069 if (ts->rd)
1070 fput(ts->rd);
1071 if (ts->wr)
1072 fput(ts->wr);
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001073
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001074 kfree(ts);
1075}
1076
Eric Van Hensbergen887b3ec2008-05-08 20:26:37 -05001077/*
1078 * stolen from NFS - maybe should be made a generic function?
1079 */
1080static inline int valid_ipaddr4(const char *buf)
1081{
1082 int rc, count, in[4];
1083
1084 rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]);
1085 if (rc != 4)
1086 return -EINVAL;
1087 for (count = 0; count < 4; count++) {
1088 if (in[count] > 255)
1089 return -EINVAL;
1090 }
1091 return 0;
1092}
1093
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001094static int
1095p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001096{
1097 int err;
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001098 struct socket *csocket;
1099 struct sockaddr_in sin_server;
1100 struct p9_fd_opts opts;
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001101 struct p9_trans_fd *p = NULL; /* this gets allocated in p9_fd_open */
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001102
Eric Van Hensbergenbb8ffdf2008-03-07 10:53:53 -06001103 err = parse_opts(args, &opts);
1104 if (err < 0)
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001105 return err;
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001106
Eric Van Hensbergen887b3ec2008-05-08 20:26:37 -05001107 if (valid_ipaddr4(addr) < 0)
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001108 return -EINVAL;
Eric Van Hensbergen887b3ec2008-05-08 20:26:37 -05001109
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001110 csocket = NULL;
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001111
1112 sin_server.sin_family = AF_INET;
1113 sin_server.sin_addr.s_addr = in_aton(addr);
1114 sin_server.sin_port = htons(opts.port);
1115 sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
1116
1117 if (!csocket) {
1118 P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n");
1119 err = -EIO;
1120 goto error;
1121 }
1122
1123 err = csocket->ops->connect(csocket,
1124 (struct sockaddr *)&sin_server,
1125 sizeof(struct sockaddr_in), 0);
1126 if (err < 0) {
1127 P9_EPRINTK(KERN_ERR,
1128 "p9_trans_tcp: problem connecting socket to %s\n",
1129 addr);
1130 goto error;
1131 }
1132
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001133 err = p9_socket_open(client, csocket);
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001134 if (err < 0)
1135 goto error;
1136
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001137 p = (struct p9_trans_fd *) client->trans;
1138 p->conn = p9_conn_create(client);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -06001139 if (IS_ERR(p->conn)) {
1140 err = PTR_ERR(p->conn);
1141 p->conn = NULL;
1142 goto error;
1143 }
1144
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001145 return 0;
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001146
1147error:
1148 if (csocket)
1149 sock_release(csocket);
1150
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001151 kfree(p);
1152
1153 return err;
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001154}
1155
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001156static int
1157p9_fd_create_unix(struct p9_client *client, const char *addr, char *args)
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001158{
1159 int err;
1160 struct socket *csocket;
1161 struct sockaddr_un sun_server;
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001162 struct p9_trans_fd *p = NULL; /* this gets allocated in p9_fd_open */
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001163
1164 csocket = NULL;
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001165
1166 if (strlen(addr) > UNIX_PATH_MAX) {
1167 P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n",
1168 addr);
1169 err = -ENAMETOOLONG;
1170 goto error;
1171 }
1172
1173 sun_server.sun_family = PF_UNIX;
1174 strcpy(sun_server.sun_path, addr);
1175 sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket);
1176 err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
1177 sizeof(struct sockaddr_un) - 1, 0);
1178 if (err < 0) {
1179 P9_EPRINTK(KERN_ERR,
1180 "p9_trans_unix: problem connecting socket: %s: %d\n",
1181 addr, err);
1182 goto error;
1183 }
1184
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001185 err = p9_socket_open(client, csocket);
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001186 if (err < 0)
1187 goto error;
1188
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001189 p = (struct p9_trans_fd *) client->trans;
1190 p->conn = p9_conn_create(client);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -06001191 if (IS_ERR(p->conn)) {
1192 err = PTR_ERR(p->conn);
1193 p->conn = NULL;
1194 goto error;
1195 }
1196
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001197 return 0;
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001198
1199error:
1200 if (csocket)
1201 sock_release(csocket);
1202
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001203 kfree(p);
1204 return err;
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001205}
1206
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001207static int
1208p9_fd_create(struct p9_client *client, const char *addr, char *args)
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001209{
1210 int err;
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001211 struct p9_fd_opts opts;
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001212 struct p9_trans_fd *p = NULL; /* this get allocated in p9_fd_open */
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001213
1214 parse_opts(args, &opts);
1215
1216 if (opts.rfd == ~0 || opts.wfd == ~0) {
1217 printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n");
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001218 return -ENOPROTOOPT;
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001219 }
1220
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001221 err = p9_fd_open(client, opts.rfd, opts.wfd);
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001222 if (err < 0)
1223 goto error;
1224
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001225 p = (struct p9_trans_fd *) client->trans;
1226 p->conn = p9_conn_create(client);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -06001227 if (IS_ERR(p->conn)) {
1228 err = PTR_ERR(p->conn);
1229 p->conn = NULL;
1230 goto error;
1231 }
1232
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001233 return 0;
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001234
1235error:
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001236 kfree(p);
1237 return err;
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001238}
1239
1240static struct p9_trans_module p9_tcp_trans = {
1241 .name = "tcp",
1242 .maxsize = MAX_SOCK_BUF,
1243 .def = 1,
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001244 .create = p9_fd_create_tcp,
1245 .close = p9_fd_close,
1246 .rpc = p9_fd_rpc,
Tejun Heo72029fe2008-09-24 16:22:23 -05001247 .owner = THIS_MODULE,
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001248};
1249
1250static struct p9_trans_module p9_unix_trans = {
1251 .name = "unix",
1252 .maxsize = MAX_SOCK_BUF,
1253 .def = 0,
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001254 .create = p9_fd_create_unix,
1255 .close = p9_fd_close,
1256 .rpc = p9_fd_rpc,
Tejun Heo72029fe2008-09-24 16:22:23 -05001257 .owner = THIS_MODULE,
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001258};
1259
1260static struct p9_trans_module p9_fd_trans = {
1261 .name = "fd",
1262 .maxsize = MAX_SOCK_BUF,
1263 .def = 0,
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -05001264 .create = p9_fd_create,
1265 .close = p9_fd_close,
1266 .rpc = p9_fd_rpc,
Tejun Heo72029fe2008-09-24 16:22:23 -05001267 .owner = THIS_MODULE,
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001268};
1269
Eric Van Hensbergen5503ac52008-10-13 18:45:24 -05001270/**
1271 * p9_poll_proc - poll worker thread
1272 * @a: thread state and arguments
1273 *
1274 * polls all v9fs transports for new events and queues the appropriate
1275 * work to the work queue
1276 *
1277 */
1278
1279static int p9_poll_proc(void *a)
1280{
1281 unsigned long flags;
1282
1283 P9_DPRINTK(P9_DEBUG_MUX, "start %p\n", current);
1284 repeat:
1285 spin_lock_irqsave(&p9_poll_lock, flags);
1286 while (!list_empty(&p9_poll_pending_list)) {
1287 struct p9_conn *conn = list_first_entry(&p9_poll_pending_list,
1288 struct p9_conn,
1289 poll_pending_link);
1290 list_del_init(&conn->poll_pending_link);
1291 spin_unlock_irqrestore(&p9_poll_lock, flags);
1292
1293 p9_poll_mux(conn);
1294
1295 spin_lock_irqsave(&p9_poll_lock, flags);
1296 }
1297 spin_unlock_irqrestore(&p9_poll_lock, flags);
1298
1299 set_current_state(TASK_INTERRUPTIBLE);
1300 if (list_empty(&p9_poll_pending_list)) {
1301 P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n");
1302 schedule();
1303 }
1304 __set_current_state(TASK_RUNNING);
1305
1306 if (!kthread_should_stop())
1307 goto repeat;
1308
1309 P9_DPRINTK(P9_DEBUG_MUX, "finish\n");
1310 return 0;
1311}
1312
Eric Van Hensbergen887b3ec2008-05-08 20:26:37 -05001313int p9_trans_fd_init(void)
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001314{
Tejun Heo206ca502008-09-24 16:22:23 -05001315 p9_mux_wq = create_workqueue("v9fs");
1316 if (!p9_mux_wq) {
1317 printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n");
1318 return -ENOMEM;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -06001319 }
1320
Tejun Heo992b3f12008-10-13 18:45:25 -05001321 p9_poll_task = kthread_run(p9_poll_proc, NULL, "v9fs-poll");
1322 if (IS_ERR(p9_poll_task)) {
1323 destroy_workqueue(p9_mux_wq);
1324 printk(KERN_WARNING "v9fs: mux: creating poll task failed\n");
1325 return PTR_ERR(p9_poll_task);
1326 }
1327
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001328 v9fs_register_trans(&p9_tcp_trans);
1329 v9fs_register_trans(&p9_unix_trans);
1330 v9fs_register_trans(&p9_fd_trans);
1331
Andrew Morton3387b802008-03-28 14:15:57 -07001332 return 0;
Eric Van Hensbergena80d9232007-10-17 14:31:07 -05001333}
Tejun Heo72029fe2008-09-24 16:22:23 -05001334
1335void p9_trans_fd_exit(void)
1336{
Tejun Heo992b3f12008-10-13 18:45:25 -05001337 kthread_stop(p9_poll_task);
Tejun Heo72029fe2008-09-24 16:22:23 -05001338 v9fs_unregister_trans(&p9_tcp_trans);
1339 v9fs_unregister_trans(&p9_unix_trans);
1340 v9fs_unregister_trans(&p9_fd_trans);
Tejun Heo206ca502008-09-24 16:22:23 -05001341
1342 destroy_workqueue(p9_mux_wq);
Tejun Heo72029fe2008-09-24 16:22:23 -05001343}