1bd238fb4SLatchesar Ionkov /* 2bd238fb4SLatchesar Ionkov * linux/fs/9p/trans_fd.c 3bd238fb4SLatchesar Ionkov * 4bd238fb4SLatchesar Ionkov * Fd transport layer. Includes deprecated socket layer. 5bd238fb4SLatchesar Ionkov * 6bd238fb4SLatchesar Ionkov * Copyright (C) 2006 by Russ Cox <rsc@swtch.com> 7bd238fb4SLatchesar Ionkov * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net> 88a0dc95fSEric Van Hensbergen * Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com> 9bd238fb4SLatchesar Ionkov * Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com> 10bd238fb4SLatchesar Ionkov * 11bd238fb4SLatchesar Ionkov * This program is free software; you can redistribute it and/or modify 12bd238fb4SLatchesar Ionkov * it under the terms of the GNU General Public License version 2 13bd238fb4SLatchesar Ionkov * as published by the Free Software Foundation. 14bd238fb4SLatchesar Ionkov * 15bd238fb4SLatchesar Ionkov * This program is distributed in the hope that it will be useful, 16bd238fb4SLatchesar Ionkov * but WITHOUT ANY WARRANTY; without even the implied warranty of 17bd238fb4SLatchesar Ionkov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18bd238fb4SLatchesar Ionkov * GNU General Public License for more details. 19bd238fb4SLatchesar Ionkov * 20bd238fb4SLatchesar Ionkov * You should have received a copy of the GNU General Public License 21bd238fb4SLatchesar Ionkov * along with this program; if not, write to: 22bd238fb4SLatchesar Ionkov * Free Software Foundation 23bd238fb4SLatchesar Ionkov * 51 Franklin Street, Fifth Floor 24bd238fb4SLatchesar Ionkov * Boston, MA 02111-1301 USA 25bd238fb4SLatchesar Ionkov * 26bd238fb4SLatchesar Ionkov */ 27bd238fb4SLatchesar Ionkov 285d385153SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 295d385153SJoe Perches 30bd238fb4SLatchesar Ionkov #include <linux/in.h> 31bd238fb4SLatchesar Ionkov #include <linux/module.h> 32bd238fb4SLatchesar Ionkov #include <linux/net.h> 33bd238fb4SLatchesar Ionkov #include <linux/ipv6.h> 348a0dc95fSEric Van Hensbergen #include <linux/kthread.h> 35bd238fb4SLatchesar Ionkov #include <linux/errno.h> 36bd238fb4SLatchesar Ionkov #include <linux/kernel.h> 37bd238fb4SLatchesar Ionkov #include <linux/un.h> 38bd238fb4SLatchesar Ionkov #include <linux/uaccess.h> 39bd238fb4SLatchesar Ionkov #include <linux/inet.h> 40bd238fb4SLatchesar Ionkov #include <linux/idr.h> 41bd238fb4SLatchesar Ionkov #include <linux/file.h> 42a80d923eSEric Van Hensbergen #include <linux/parser.h> 435a0e3ad6STejun Heo #include <linux/slab.h> 44bd238fb4SLatchesar Ionkov #include <net/9p/9p.h> 458b81ef58SEric Van Hensbergen #include <net/9p/client.h> 46bd238fb4SLatchesar Ionkov #include <net/9p/transport.h> 47bd238fb4SLatchesar Ionkov 486b18662eSAl Viro #include <linux/syscalls.h> /* killme */ 496b18662eSAl Viro 50bd238fb4SLatchesar Ionkov #define P9_PORT 564 51a80d923eSEric Van Hensbergen #define MAX_SOCK_BUF (64*1024) 528a0dc95fSEric Van Hensbergen #define MAXPOLLWADDR 2 53a80d923eSEric Van Hensbergen 54ee443996SEric Van Hensbergen /** 55ee443996SEric Van Hensbergen * struct p9_fd_opts - per-transport options 56ee443996SEric Van Hensbergen * @rfd: file descriptor for reading (trans=fd) 57ee443996SEric Van Hensbergen * @wfd: file descriptor for writing (trans=fd) 58ee443996SEric Van Hensbergen * @port: port to connect to (trans=tcp) 59ee443996SEric Van Hensbergen * 60ee443996SEric Van Hensbergen */ 61ee443996SEric Van Hensbergen 62a80d923eSEric Van Hensbergen struct p9_fd_opts { 63a80d923eSEric Van Hensbergen int rfd; 64a80d923eSEric Van Hensbergen int wfd; 65a80d923eSEric Van Hensbergen u16 port; 66a80d923eSEric Van Hensbergen }; 67bd238fb4SLatchesar Ionkov 68ee443996SEric Van Hensbergen /** 69ee443996SEric Van Hensbergen * struct p9_trans_fd - transport state 70ee443996SEric Van Hensbergen * @rd: reference to file to read from 71ee443996SEric Van Hensbergen * @wr: reference of file to write to 72ee443996SEric Van Hensbergen * @conn: connection state reference 73ee443996SEric Van Hensbergen * 74ee443996SEric Van Hensbergen */ 75ee443996SEric Van Hensbergen 76bd238fb4SLatchesar Ionkov struct p9_trans_fd { 77bd238fb4SLatchesar Ionkov struct file *rd; 78bd238fb4SLatchesar Ionkov struct file *wr; 798a0dc95fSEric Van Hensbergen struct p9_conn *conn; 80bd238fb4SLatchesar Ionkov }; 81bd238fb4SLatchesar Ionkov 82a80d923eSEric Van Hensbergen /* 83a80d923eSEric Van Hensbergen * Option Parsing (code inspired by NFS code) 84a80d923eSEric Van Hensbergen * - a little lazy - parse all fd-transport options 85a80d923eSEric Van Hensbergen */ 86bd238fb4SLatchesar Ionkov 87a80d923eSEric Van Hensbergen enum { 88a80d923eSEric Van Hensbergen /* Options that take integer arguments */ 8955762690SLatchesar Ionkov Opt_port, Opt_rfdno, Opt_wfdno, Opt_err, 90a80d923eSEric Van Hensbergen }; 91a80d923eSEric Van Hensbergen 92a447c093SSteven Whitehouse static const match_table_t tokens = { 93a80d923eSEric Van Hensbergen {Opt_port, "port=%u"}, 94a80d923eSEric Van Hensbergen {Opt_rfdno, "rfdno=%u"}, 95a80d923eSEric Van Hensbergen {Opt_wfdno, "wfdno=%u"}, 9655762690SLatchesar Ionkov {Opt_err, NULL}, 97a80d923eSEric Van Hensbergen }; 98a80d923eSEric Van Hensbergen 998a0dc95fSEric Van Hensbergen enum { 1008a0dc95fSEric Van Hensbergen Rworksched = 1, /* read work scheduled or running */ 1018a0dc95fSEric Van Hensbergen Rpending = 2, /* can read */ 1028a0dc95fSEric Van Hensbergen Wworksched = 4, /* write work scheduled or running */ 1038a0dc95fSEric Van Hensbergen Wpending = 8, /* can write */ 1048a0dc95fSEric Van Hensbergen }; 1058a0dc95fSEric Van Hensbergen 106992b3f1dSTejun Heo struct p9_poll_wait { 107992b3f1dSTejun Heo struct p9_conn *conn; 108992b3f1dSTejun Heo wait_queue_t wait; 109992b3f1dSTejun Heo wait_queue_head_t *wait_addr; 110ee443996SEric Van Hensbergen }; 111ee443996SEric Van Hensbergen 112ee443996SEric Van Hensbergen /** 113ee443996SEric Van Hensbergen * struct p9_conn - fd mux connection state information 114ee443996SEric Van Hensbergen * @mux_list: list link for mux to manage multiple connections (?) 1158b81ef58SEric Van Hensbergen * @client: reference to client instance for this connection 116ee443996SEric Van Hensbergen * @err: error state 117ee443996SEric Van Hensbergen * @req_list: accounting for requests which have been sent 118ee443996SEric Van Hensbergen * @unsent_req_list: accounting for requests that haven't been sent 1191b0a763bSEric Van Hensbergen * @req: current request being processed (if any) 1201b0a763bSEric Van Hensbergen * @tmp_buf: temporary buffer to read in header 1211b0a763bSEric Van Hensbergen * @rsize: amount to read for current frame 122ee443996SEric Van Hensbergen * @rpos: read position in current frame 123ee443996SEric Van Hensbergen * @rbuf: current read buffer 124ee443996SEric Van Hensbergen * @wpos: write position for current frame 125ee443996SEric Van Hensbergen * @wsize: amount of data to write for current frame 126ee443996SEric Van Hensbergen * @wbuf: current write buffer 1270e15597eSAbhishek Kulkarni * @poll_pending_link: pending links to be polled per conn 128ee443996SEric Van Hensbergen * @poll_wait: array of wait_q's for various worker threads 129ee443996SEric Van Hensbergen * @pt: poll state 130ee443996SEric Van Hensbergen * @rq: current read work 131ee443996SEric Van Hensbergen * @wq: current write work 132ee443996SEric Van Hensbergen * @wsched: ???? 133ee443996SEric Van Hensbergen * 134ee443996SEric Van Hensbergen */ 1358a0dc95fSEric Van Hensbergen 1368a0dc95fSEric Van Hensbergen struct p9_conn { 1378a0dc95fSEric Van Hensbergen struct list_head mux_list; 1388b81ef58SEric Van Hensbergen struct p9_client *client; 1398a0dc95fSEric Van Hensbergen int err; 1408a0dc95fSEric Van Hensbergen struct list_head req_list; 1418a0dc95fSEric Van Hensbergen struct list_head unsent_req_list; 1421b0a763bSEric Van Hensbergen struct p9_req_t *req; 1431b0a763bSEric Van Hensbergen char tmp_buf[7]; 1441b0a763bSEric Van Hensbergen int rsize; 1458a0dc95fSEric Van Hensbergen int rpos; 1468a0dc95fSEric Van Hensbergen char *rbuf; 1478a0dc95fSEric Van Hensbergen int wpos; 1488a0dc95fSEric Van Hensbergen int wsize; 1498a0dc95fSEric Van Hensbergen char *wbuf; 150992b3f1dSTejun Heo struct list_head poll_pending_link; 151992b3f1dSTejun Heo struct p9_poll_wait poll_wait[MAXPOLLWADDR]; 1528a0dc95fSEric Van Hensbergen poll_table pt; 1538a0dc95fSEric Van Hensbergen struct work_struct rq; 1548a0dc95fSEric Van Hensbergen struct work_struct wq; 1558a0dc95fSEric Van Hensbergen unsigned long wsched; 1568a0dc95fSEric Van Hensbergen }; 1578a0dc95fSEric Van Hensbergen 158aa70c585STejun Heo static void p9_poll_workfn(struct work_struct *work); 159aa70c585STejun Heo 160992b3f1dSTejun Heo static DEFINE_SPINLOCK(p9_poll_lock); 161992b3f1dSTejun Heo static LIST_HEAD(p9_poll_pending_list); 162aa70c585STejun Heo static DECLARE_WORK(p9_poll_work, p9_poll_workfn); 1638a0dc95fSEric Van Hensbergen 1648a0dc95fSEric Van Hensbergen static void p9_mux_poll_stop(struct p9_conn *m) 1658a0dc95fSEric Van Hensbergen { 166992b3f1dSTejun Heo unsigned long flags; 1678a0dc95fSEric Van Hensbergen int i; 1688a0dc95fSEric Van Hensbergen 169992b3f1dSTejun Heo for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { 170992b3f1dSTejun Heo struct p9_poll_wait *pwait = &m->poll_wait[i]; 171992b3f1dSTejun Heo 172992b3f1dSTejun Heo if (pwait->wait_addr) { 173992b3f1dSTejun Heo remove_wait_queue(pwait->wait_addr, &pwait->wait); 174992b3f1dSTejun Heo pwait->wait_addr = NULL; 1758a0dc95fSEric Van Hensbergen } 1768a0dc95fSEric Van Hensbergen } 177992b3f1dSTejun Heo 178992b3f1dSTejun Heo spin_lock_irqsave(&p9_poll_lock, flags); 179992b3f1dSTejun Heo list_del_init(&m->poll_pending_link); 180992b3f1dSTejun Heo spin_unlock_irqrestore(&p9_poll_lock, flags); 1818a0dc95fSEric Van Hensbergen } 1828a0dc95fSEric Van Hensbergen 1838a0dc95fSEric Van Hensbergen /** 1845503ac56SEric Van Hensbergen * p9_conn_cancel - cancel all pending requests with error 1855503ac56SEric Van Hensbergen * @m: mux data 1865503ac56SEric Van Hensbergen * @err: error code 187ee443996SEric Van Hensbergen * 1888a0dc95fSEric Van Hensbergen */ 189ee443996SEric Van Hensbergen 19051a87c55SEric Van Hensbergen static void p9_conn_cancel(struct p9_conn *m, int err) 1918a0dc95fSEric Van Hensbergen { 192673d62cdSEric Van Hensbergen struct p9_req_t *req, *rtmp; 19391b8534fSEric Van Hensbergen unsigned long flags; 1945503ac56SEric Van Hensbergen LIST_HEAD(cancel_list); 1958a0dc95fSEric Van Hensbergen 1965d385153SJoe Perches p9_debug(P9_DEBUG_ERROR, "mux %p err %d\n", m, err); 1977eb923b8SEric Van Hensbergen 19891b8534fSEric Van Hensbergen spin_lock_irqsave(&m->client->lock, flags); 1997eb923b8SEric Van Hensbergen 2007eb923b8SEric Van Hensbergen if (m->err) { 2017eb923b8SEric Van Hensbergen spin_unlock_irqrestore(&m->client->lock, flags); 2027eb923b8SEric Van Hensbergen return; 2037eb923b8SEric Van Hensbergen } 2047eb923b8SEric Van Hensbergen 2057eb923b8SEric Van Hensbergen m->err = err; 2067eb923b8SEric Van Hensbergen 2075503ac56SEric Van Hensbergen list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { 208673d62cdSEric Van Hensbergen req->status = REQ_STATUS_ERROR; 209673d62cdSEric Van Hensbergen if (!req->t_err) 210673d62cdSEric Van Hensbergen req->t_err = err; 2115503ac56SEric Van Hensbergen list_move(&req->req_list, &cancel_list); 2125503ac56SEric Van Hensbergen } 2135503ac56SEric Van Hensbergen list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) { 214673d62cdSEric Van Hensbergen req->status = REQ_STATUS_ERROR; 215673d62cdSEric Van Hensbergen if (!req->t_err) 216673d62cdSEric Van Hensbergen req->t_err = err; 2175503ac56SEric Van Hensbergen list_move(&req->req_list, &cancel_list); 2185503ac56SEric Van Hensbergen } 21991b8534fSEric Van Hensbergen spin_unlock_irqrestore(&m->client->lock, flags); 2208a0dc95fSEric Van Hensbergen 2215503ac56SEric Van Hensbergen list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) { 2225d385153SJoe Perches p9_debug(P9_DEBUG_ERROR, "call back req %p\n", req); 2231bab88b2SLatchesar Ionkov list_del(&req->req_list); 22491b8534fSEric Van Hensbergen p9_client_cb(m->client, req); 2258a0dc95fSEric Van Hensbergen } 2268a0dc95fSEric Van Hensbergen } 2278a0dc95fSEric Van Hensbergen 22829af9309SJulia Lawall static int 2295503ac56SEric Van Hensbergen p9_fd_poll(struct p9_client *client, struct poll_table_struct *pt) 2305503ac56SEric Van Hensbergen { 2315503ac56SEric Van Hensbergen int ret, n; 2325503ac56SEric Van Hensbergen struct p9_trans_fd *ts = NULL; 2335503ac56SEric Van Hensbergen 2345503ac56SEric Van Hensbergen if (client && client->status == Connected) 2355503ac56SEric Van Hensbergen ts = client->trans; 2365503ac56SEric Van Hensbergen 2375503ac56SEric Van Hensbergen if (!ts) 2385503ac56SEric Van Hensbergen return -EREMOTEIO; 2395503ac56SEric Van Hensbergen 2405503ac56SEric Van Hensbergen if (!ts->rd->f_op || !ts->rd->f_op->poll) 2415503ac56SEric Van Hensbergen return -EIO; 2425503ac56SEric Van Hensbergen 2435503ac56SEric Van Hensbergen if (!ts->wr->f_op || !ts->wr->f_op->poll) 2445503ac56SEric Van Hensbergen return -EIO; 2455503ac56SEric Van Hensbergen 2465503ac56SEric Van Hensbergen ret = ts->rd->f_op->poll(ts->rd, pt); 2475503ac56SEric Van Hensbergen if (ret < 0) 2485503ac56SEric Van Hensbergen return ret; 2495503ac56SEric Van Hensbergen 2505503ac56SEric Van Hensbergen if (ts->rd != ts->wr) { 2515503ac56SEric Van Hensbergen n = ts->wr->f_op->poll(ts->wr, pt); 2525503ac56SEric Van Hensbergen if (n < 0) 2535503ac56SEric Van Hensbergen return n; 2545503ac56SEric Van Hensbergen ret = (ret & ~POLLOUT) | (n & ~POLLIN); 2555503ac56SEric Van Hensbergen } 2565503ac56SEric Van Hensbergen 2575503ac56SEric Van Hensbergen return ret; 2585503ac56SEric Van Hensbergen } 2595503ac56SEric Van Hensbergen 2605503ac56SEric Van Hensbergen /** 2615503ac56SEric Van Hensbergen * p9_fd_read- read from a fd 2625503ac56SEric Van Hensbergen * @client: client instance 2635503ac56SEric Van Hensbergen * @v: buffer to receive data into 2645503ac56SEric Van Hensbergen * @len: size of receive buffer 2655503ac56SEric Van Hensbergen * 2665503ac56SEric Van Hensbergen */ 2675503ac56SEric Van Hensbergen 2685503ac56SEric Van Hensbergen static int p9_fd_read(struct p9_client *client, void *v, int len) 2695503ac56SEric Van Hensbergen { 2705503ac56SEric Van Hensbergen int ret; 2715503ac56SEric Van Hensbergen struct p9_trans_fd *ts = NULL; 2725503ac56SEric Van Hensbergen 2735503ac56SEric Van Hensbergen if (client && client->status != Disconnected) 2745503ac56SEric Van Hensbergen ts = client->trans; 2755503ac56SEric Van Hensbergen 2765503ac56SEric Van Hensbergen if (!ts) 2775503ac56SEric Van Hensbergen return -EREMOTEIO; 2785503ac56SEric Van Hensbergen 2795503ac56SEric Van Hensbergen if (!(ts->rd->f_flags & O_NONBLOCK)) 2805d385153SJoe Perches p9_debug(P9_DEBUG_ERROR, "blocking read ...\n"); 2815503ac56SEric Van Hensbergen 2825503ac56SEric Van Hensbergen ret = kernel_read(ts->rd, ts->rd->f_pos, v, len); 2835503ac56SEric Van Hensbergen if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) 2845503ac56SEric Van Hensbergen client->status = Disconnected; 2855503ac56SEric Van Hensbergen return ret; 2865503ac56SEric Van Hensbergen } 2875503ac56SEric Van Hensbergen 2888a0dc95fSEric Van Hensbergen /** 2898a0dc95fSEric Van Hensbergen * p9_read_work - called when there is some data to be read from a transport 290ee443996SEric Van Hensbergen * @work: container of work to be done 291ee443996SEric Van Hensbergen * 2928a0dc95fSEric Van Hensbergen */ 293ee443996SEric Van Hensbergen 2948a0dc95fSEric Van Hensbergen static void p9_read_work(struct work_struct *work) 2958a0dc95fSEric Van Hensbergen { 2968a0dc95fSEric Van Hensbergen int n, err; 2978a0dc95fSEric Van Hensbergen struct p9_conn *m; 2988a0dc95fSEric Van Hensbergen 2998a0dc95fSEric Van Hensbergen m = container_of(work, struct p9_conn, rq); 3008a0dc95fSEric Van Hensbergen 3018a0dc95fSEric Van Hensbergen if (m->err < 0) 3028a0dc95fSEric Van Hensbergen return; 3038a0dc95fSEric Van Hensbergen 3045d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "start mux %p pos %d\n", m, m->rpos); 3058a0dc95fSEric Van Hensbergen 3061b0a763bSEric Van Hensbergen if (!m->rbuf) { 3071b0a763bSEric Van Hensbergen m->rbuf = m->tmp_buf; 3088a0dc95fSEric Van Hensbergen m->rpos = 0; 3091b0a763bSEric Van Hensbergen m->rsize = 7; /* start by reading header */ 3108a0dc95fSEric Van Hensbergen } 3118a0dc95fSEric Van Hensbergen 3128a0dc95fSEric Van Hensbergen clear_bit(Rpending, &m->wsched); 3135d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "read mux %p pos %d size: %d = %d\n", 3145d385153SJoe Perches m, m->rpos, m->rsize, m->rsize-m->rpos); 315bead27f0SEric Van Hensbergen err = p9_fd_read(m->client, m->rbuf + m->rpos, 3161b0a763bSEric Van Hensbergen m->rsize - m->rpos); 3175d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "mux %p got %d bytes\n", m, err); 3188a0dc95fSEric Van Hensbergen if (err == -EAGAIN) { 3198a0dc95fSEric Van Hensbergen clear_bit(Rworksched, &m->wsched); 3208a0dc95fSEric Van Hensbergen return; 3218a0dc95fSEric Van Hensbergen } 3228a0dc95fSEric Van Hensbergen 3238a0dc95fSEric Van Hensbergen if (err <= 0) 3248a0dc95fSEric Van Hensbergen goto error; 3258a0dc95fSEric Van Hensbergen 3268a0dc95fSEric Van Hensbergen m->rpos += err; 3271b0a763bSEric Van Hensbergen 3281b0a763bSEric Van Hensbergen if ((!m->req) && (m->rpos == m->rsize)) { /* header read in */ 3291b0a763bSEric Van Hensbergen u16 tag; 3305d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "got new header\n"); 3311b0a763bSEric Van Hensbergen 3321b0a763bSEric Van Hensbergen n = le32_to_cpu(*(__le32 *) m->rbuf); /* read packet size */ 333bead27f0SEric Van Hensbergen if (n >= m->client->msize) { 3345d385153SJoe Perches p9_debug(P9_DEBUG_ERROR, 3358a0dc95fSEric Van Hensbergen "requested packet size too big: %d\n", n); 3368a0dc95fSEric Van Hensbergen err = -EIO; 3378a0dc95fSEric Van Hensbergen goto error; 3388a0dc95fSEric Van Hensbergen } 3398a0dc95fSEric Van Hensbergen 3401b0a763bSEric Van Hensbergen tag = le16_to_cpu(*(__le16 *) (m->rbuf+5)); /* read tag */ 3415d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, 34251a87c55SEric Van Hensbergen "mux %p pkt: size: %d bytes tag: %d\n", m, n, tag); 3438a0dc95fSEric Van Hensbergen 3441b0a763bSEric Van Hensbergen m->req = p9_tag_lookup(m->client, tag); 3451bab88b2SLatchesar Ionkov if (!m->req || (m->req->status != REQ_STATUS_SENT && 3461bab88b2SLatchesar Ionkov m->req->status != REQ_STATUS_FLSH)) { 3475d385153SJoe Perches p9_debug(P9_DEBUG_ERROR, "Unexpected packet tag %d\n", 3481b0a763bSEric Van Hensbergen tag); 3491b0a763bSEric Van Hensbergen err = -EIO; 3508a0dc95fSEric Van Hensbergen goto error; 3511b0a763bSEric Van Hensbergen } 3521b0a763bSEric Van Hensbergen 3531b0a763bSEric Van Hensbergen if (m->req->rc == NULL) { 3541b0a763bSEric Van Hensbergen m->req->rc = kmalloc(sizeof(struct p9_fcall) + 355eeff66efSAneesh Kumar K.V m->client->msize, GFP_NOFS); 3561b0a763bSEric Van Hensbergen if (!m->req->rc) { 3571b0a763bSEric Van Hensbergen m->req = NULL; 3581b0a763bSEric Van Hensbergen err = -ENOMEM; 3591b0a763bSEric Van Hensbergen goto error; 3601b0a763bSEric Van Hensbergen } 3611b0a763bSEric Van Hensbergen } 3621b0a763bSEric Van Hensbergen m->rbuf = (char *)m->req->rc + sizeof(struct p9_fcall); 3631b0a763bSEric Van Hensbergen memcpy(m->rbuf, m->tmp_buf, m->rsize); 3641b0a763bSEric Van Hensbergen m->rsize = n; 3651b0a763bSEric Van Hensbergen } 3661b0a763bSEric Van Hensbergen 3671b0a763bSEric Van Hensbergen /* not an else because some packets (like clunk) have no payload */ 3681b0a763bSEric Van Hensbergen if ((m->req) && (m->rpos == m->rsize)) { /* packet is read in */ 3695d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "got new packet\n"); 3707eb923b8SEric Van Hensbergen spin_lock(&m->client->lock); 3711bab88b2SLatchesar Ionkov if (m->req->status != REQ_STATUS_ERROR) 3721bab88b2SLatchesar Ionkov m->req->status = REQ_STATUS_RCVD; 37391b8534fSEric Van Hensbergen list_del(&m->req->req_list); 3747eb923b8SEric Van Hensbergen spin_unlock(&m->client->lock); 37591b8534fSEric Van Hensbergen p9_client_cb(m->client, m->req); 3768a0dc95fSEric Van Hensbergen m->rbuf = NULL; 3778a0dc95fSEric Van Hensbergen m->rpos = 0; 3781b0a763bSEric Van Hensbergen m->rsize = 0; 3791b0a763bSEric Van Hensbergen m->req = NULL; 3808a0dc95fSEric Van Hensbergen } 3818a0dc95fSEric Van Hensbergen 3828a0dc95fSEric Van Hensbergen if (!list_empty(&m->req_list)) { 3838a0dc95fSEric Van Hensbergen if (test_and_clear_bit(Rpending, &m->wsched)) 3848a0dc95fSEric Van Hensbergen n = POLLIN; 3858a0dc95fSEric Van Hensbergen else 3868b81ef58SEric Van Hensbergen n = p9_fd_poll(m->client, NULL); 3878a0dc95fSEric Van Hensbergen 3888a0dc95fSEric Van Hensbergen if (n & POLLIN) { 3895d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "sched read work %p\n", m); 39061edeeedSTejun Heo schedule_work(&m->rq); 3918a0dc95fSEric Van Hensbergen } else 3928a0dc95fSEric Van Hensbergen clear_bit(Rworksched, &m->wsched); 3938a0dc95fSEric Van Hensbergen } else 3948a0dc95fSEric Van Hensbergen clear_bit(Rworksched, &m->wsched); 3958a0dc95fSEric Van Hensbergen 3968a0dc95fSEric Van Hensbergen return; 3978a0dc95fSEric Van Hensbergen error: 3988a0dc95fSEric Van Hensbergen p9_conn_cancel(m, err); 3998a0dc95fSEric Van Hensbergen clear_bit(Rworksched, &m->wsched); 4008a0dc95fSEric Van Hensbergen } 4018a0dc95fSEric Van Hensbergen 4028a0dc95fSEric Van Hensbergen /** 4035503ac56SEric Van Hensbergen * p9_fd_write - write to a socket 4045503ac56SEric Van Hensbergen * @client: client instance 4055503ac56SEric Van Hensbergen * @v: buffer to send data from 4065503ac56SEric Van Hensbergen * @len: size of send buffer 4075503ac56SEric Van Hensbergen * 4085503ac56SEric Van Hensbergen */ 4095503ac56SEric Van Hensbergen 4105503ac56SEric Van Hensbergen static int p9_fd_write(struct p9_client *client, void *v, int len) 4115503ac56SEric Van Hensbergen { 4125503ac56SEric Van Hensbergen int ret; 4135503ac56SEric Van Hensbergen mm_segment_t oldfs; 4145503ac56SEric Van Hensbergen struct p9_trans_fd *ts = NULL; 4155503ac56SEric Van Hensbergen 4165503ac56SEric Van Hensbergen if (client && client->status != Disconnected) 4175503ac56SEric Van Hensbergen ts = client->trans; 4185503ac56SEric Van Hensbergen 4195503ac56SEric Van Hensbergen if (!ts) 4205503ac56SEric Van Hensbergen return -EREMOTEIO; 4215503ac56SEric Van Hensbergen 4225503ac56SEric Van Hensbergen if (!(ts->wr->f_flags & O_NONBLOCK)) 4235d385153SJoe Perches p9_debug(P9_DEBUG_ERROR, "blocking write ...\n"); 4245503ac56SEric Van Hensbergen 4255503ac56SEric Van Hensbergen oldfs = get_fs(); 4265503ac56SEric Van Hensbergen set_fs(get_ds()); 4275503ac56SEric Van Hensbergen /* The cast to a user pointer is valid due to the set_fs() */ 428e3db6cb4SHannes Eder ret = vfs_write(ts->wr, (__force void __user *)v, len, &ts->wr->f_pos); 4295503ac56SEric Van Hensbergen set_fs(oldfs); 4305503ac56SEric Van Hensbergen 4315503ac56SEric Van Hensbergen if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) 4325503ac56SEric Van Hensbergen client->status = Disconnected; 4335503ac56SEric Van Hensbergen return ret; 4345503ac56SEric Van Hensbergen } 4355503ac56SEric Van Hensbergen 4365503ac56SEric Van Hensbergen /** 4375503ac56SEric Van Hensbergen * p9_write_work - called when a transport can send some data 4385503ac56SEric Van Hensbergen * @work: container for work to be done 4395503ac56SEric Van Hensbergen * 4405503ac56SEric Van Hensbergen */ 4415503ac56SEric Van Hensbergen 4425503ac56SEric Van Hensbergen static void p9_write_work(struct work_struct *work) 4435503ac56SEric Van Hensbergen { 4445503ac56SEric Van Hensbergen int n, err; 4455503ac56SEric Van Hensbergen struct p9_conn *m; 446673d62cdSEric Van Hensbergen struct p9_req_t *req; 4475503ac56SEric Van Hensbergen 4485503ac56SEric Van Hensbergen m = container_of(work, struct p9_conn, wq); 4495503ac56SEric Van Hensbergen 4505503ac56SEric Van Hensbergen if (m->err < 0) { 4515503ac56SEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 4525503ac56SEric Van Hensbergen return; 4535503ac56SEric Van Hensbergen } 4545503ac56SEric Van Hensbergen 4555503ac56SEric Van Hensbergen if (!m->wsize) { 4565503ac56SEric Van Hensbergen if (list_empty(&m->unsent_req_list)) { 4575503ac56SEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 4585503ac56SEric Van Hensbergen return; 4595503ac56SEric Van Hensbergen } 4605503ac56SEric Van Hensbergen 461673d62cdSEric Van Hensbergen spin_lock(&m->client->lock); 462673d62cdSEric Van Hensbergen req = list_entry(m->unsent_req_list.next, struct p9_req_t, 4635503ac56SEric Van Hensbergen req_list); 464673d62cdSEric Van Hensbergen req->status = REQ_STATUS_SENT; 4655d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "move req %p\n", req); 4665503ac56SEric Van Hensbergen list_move_tail(&req->req_list, &m->req_list); 4675503ac56SEric Van Hensbergen 468673d62cdSEric Van Hensbergen m->wbuf = req->tc->sdata; 469673d62cdSEric Van Hensbergen m->wsize = req->tc->size; 4705503ac56SEric Van Hensbergen m->wpos = 0; 471673d62cdSEric Van Hensbergen spin_unlock(&m->client->lock); 4725503ac56SEric Van Hensbergen } 4735503ac56SEric Van Hensbergen 4745d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "mux %p pos %d size %d\n", 4755d385153SJoe Perches m, m->wpos, m->wsize); 4765503ac56SEric Van Hensbergen clear_bit(Wpending, &m->wsched); 4775503ac56SEric Van Hensbergen err = p9_fd_write(m->client, m->wbuf + m->wpos, m->wsize - m->wpos); 4785d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "mux %p sent %d bytes\n", m, err); 4795503ac56SEric Van Hensbergen if (err == -EAGAIN) { 4805503ac56SEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 4815503ac56SEric Van Hensbergen return; 4825503ac56SEric Van Hensbergen } 4835503ac56SEric Van Hensbergen 4845503ac56SEric Van Hensbergen if (err < 0) 4855503ac56SEric Van Hensbergen goto error; 4865503ac56SEric Van Hensbergen else if (err == 0) { 4875503ac56SEric Van Hensbergen err = -EREMOTEIO; 4885503ac56SEric Van Hensbergen goto error; 4895503ac56SEric Van Hensbergen } 4905503ac56SEric Van Hensbergen 4915503ac56SEric Van Hensbergen m->wpos += err; 4925503ac56SEric Van Hensbergen if (m->wpos == m->wsize) 4935503ac56SEric Van Hensbergen m->wpos = m->wsize = 0; 4945503ac56SEric Van Hensbergen 4955503ac56SEric Van Hensbergen if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) { 4965503ac56SEric Van Hensbergen if (test_and_clear_bit(Wpending, &m->wsched)) 4975503ac56SEric Van Hensbergen n = POLLOUT; 4985503ac56SEric Van Hensbergen else 4995503ac56SEric Van Hensbergen n = p9_fd_poll(m->client, NULL); 5005503ac56SEric Van Hensbergen 5015503ac56SEric Van Hensbergen if (n & POLLOUT) { 5025d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "sched write work %p\n", m); 50361edeeedSTejun Heo schedule_work(&m->wq); 5045503ac56SEric Van Hensbergen } else 5055503ac56SEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 5065503ac56SEric Van Hensbergen } else 5075503ac56SEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 5085503ac56SEric Van Hensbergen 5095503ac56SEric Van Hensbergen return; 5105503ac56SEric Van Hensbergen 5115503ac56SEric Van Hensbergen error: 5125503ac56SEric Van Hensbergen p9_conn_cancel(m, err); 5135503ac56SEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 5145503ac56SEric Van Hensbergen } 5155503ac56SEric Van Hensbergen 51695c96174SEric Dumazet static int p9_pollwake(wait_queue_t *wait, unsigned int mode, int sync, void *key) 5175503ac56SEric Van Hensbergen { 5185503ac56SEric Van Hensbergen struct p9_poll_wait *pwait = 5195503ac56SEric Van Hensbergen container_of(wait, struct p9_poll_wait, wait); 5205503ac56SEric Van Hensbergen struct p9_conn *m = pwait->conn; 5215503ac56SEric Van Hensbergen unsigned long flags; 5225503ac56SEric Van Hensbergen 5235503ac56SEric Van Hensbergen spin_lock_irqsave(&p9_poll_lock, flags); 5245503ac56SEric Van Hensbergen if (list_empty(&m->poll_pending_link)) 5255503ac56SEric Van Hensbergen list_add_tail(&m->poll_pending_link, &p9_poll_pending_list); 5265503ac56SEric Van Hensbergen spin_unlock_irqrestore(&p9_poll_lock, flags); 5275503ac56SEric Van Hensbergen 528aa70c585STejun Heo schedule_work(&p9_poll_work); 529aa70c585STejun Heo return 1; 5305503ac56SEric Van Hensbergen } 5315503ac56SEric Van Hensbergen 5325503ac56SEric Van Hensbergen /** 5335503ac56SEric Van Hensbergen * p9_pollwait - add poll task to the wait queue 5345503ac56SEric Van Hensbergen * @filp: file pointer being polled 5355503ac56SEric Van Hensbergen * @wait_address: wait_q to block on 5365503ac56SEric Van Hensbergen * @p: poll state 5375503ac56SEric Van Hensbergen * 5385503ac56SEric Van Hensbergen * called by files poll operation to add v9fs-poll task to files wait queue 5395503ac56SEric Van Hensbergen */ 5405503ac56SEric Van Hensbergen 5415503ac56SEric Van Hensbergen static void 5425503ac56SEric Van Hensbergen p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p) 5435503ac56SEric Van Hensbergen { 5445503ac56SEric Van Hensbergen struct p9_conn *m = container_of(p, struct p9_conn, pt); 5455503ac56SEric Van Hensbergen struct p9_poll_wait *pwait = NULL; 5465503ac56SEric Van Hensbergen int i; 5475503ac56SEric Van Hensbergen 5485503ac56SEric Van Hensbergen for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { 5495503ac56SEric Van Hensbergen if (m->poll_wait[i].wait_addr == NULL) { 5505503ac56SEric Van Hensbergen pwait = &m->poll_wait[i]; 5515503ac56SEric Van Hensbergen break; 5525503ac56SEric Van Hensbergen } 5535503ac56SEric Van Hensbergen } 5545503ac56SEric Van Hensbergen 5555503ac56SEric Van Hensbergen if (!pwait) { 5565d385153SJoe Perches p9_debug(P9_DEBUG_ERROR, "not enough wait_address slots\n"); 5575503ac56SEric Van Hensbergen return; 5585503ac56SEric Van Hensbergen } 5595503ac56SEric Van Hensbergen 5605503ac56SEric Van Hensbergen pwait->conn = m; 5615503ac56SEric Van Hensbergen pwait->wait_addr = wait_address; 5625503ac56SEric Van Hensbergen init_waitqueue_func_entry(&pwait->wait, p9_pollwake); 5635503ac56SEric Van Hensbergen add_wait_queue(wait_address, &pwait->wait); 5645503ac56SEric Van Hensbergen } 5655503ac56SEric Van Hensbergen 5665503ac56SEric Van Hensbergen /** 5675503ac56SEric Van Hensbergen * p9_conn_create - allocate and initialize the per-session mux data 5685503ac56SEric Van Hensbergen * @client: client instance 5695503ac56SEric Van Hensbergen * 5705503ac56SEric Van Hensbergen * Note: Creates the polling task if this is the first session. 5715503ac56SEric Van Hensbergen */ 5725503ac56SEric Van Hensbergen 5735503ac56SEric Van Hensbergen static struct p9_conn *p9_conn_create(struct p9_client *client) 5745503ac56SEric Van Hensbergen { 57595820a36STejun Heo int n; 5765503ac56SEric Van Hensbergen struct p9_conn *m; 5775503ac56SEric Van Hensbergen 5785d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "client %p msize %d\n", client, client->msize); 5795503ac56SEric Van Hensbergen m = kzalloc(sizeof(struct p9_conn), GFP_KERNEL); 5805503ac56SEric Van Hensbergen if (!m) 5815503ac56SEric Van Hensbergen return ERR_PTR(-ENOMEM); 5825503ac56SEric Van Hensbergen 5835503ac56SEric Van Hensbergen INIT_LIST_HEAD(&m->mux_list); 5845503ac56SEric Van Hensbergen m->client = client; 5855503ac56SEric Van Hensbergen 5865503ac56SEric Van Hensbergen INIT_LIST_HEAD(&m->req_list); 5875503ac56SEric Van Hensbergen INIT_LIST_HEAD(&m->unsent_req_list); 5885503ac56SEric Van Hensbergen INIT_WORK(&m->rq, p9_read_work); 5895503ac56SEric Van Hensbergen INIT_WORK(&m->wq, p9_write_work); 5905503ac56SEric Van Hensbergen INIT_LIST_HEAD(&m->poll_pending_link); 5915503ac56SEric Van Hensbergen init_poll_funcptr(&m->pt, p9_pollwait); 5925503ac56SEric Van Hensbergen 5935503ac56SEric Van Hensbergen n = p9_fd_poll(client, &m->pt); 5945503ac56SEric Van Hensbergen if (n & POLLIN) { 5955d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "mux %p can read\n", m); 5965503ac56SEric Van Hensbergen set_bit(Rpending, &m->wsched); 5975503ac56SEric Van Hensbergen } 5985503ac56SEric Van Hensbergen 5995503ac56SEric Van Hensbergen if (n & POLLOUT) { 6005d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "mux %p can write\n", m); 6015503ac56SEric Van Hensbergen set_bit(Wpending, &m->wsched); 6025503ac56SEric Van Hensbergen } 6035503ac56SEric Van Hensbergen 6045503ac56SEric Van Hensbergen return m; 6055503ac56SEric Van Hensbergen } 6065503ac56SEric Van Hensbergen 6075503ac56SEric Van Hensbergen /** 6085503ac56SEric Van Hensbergen * p9_poll_mux - polls a mux and schedules read or write works if necessary 6095503ac56SEric Van Hensbergen * @m: connection to poll 6105503ac56SEric Van Hensbergen * 6115503ac56SEric Van Hensbergen */ 6125503ac56SEric Van Hensbergen 6135503ac56SEric Van Hensbergen static void p9_poll_mux(struct p9_conn *m) 6145503ac56SEric Van Hensbergen { 6155503ac56SEric Van Hensbergen int n; 6165503ac56SEric Van Hensbergen 6175503ac56SEric Van Hensbergen if (m->err < 0) 6185503ac56SEric Van Hensbergen return; 6195503ac56SEric Van Hensbergen 6205503ac56SEric Van Hensbergen n = p9_fd_poll(m->client, NULL); 6215503ac56SEric Van Hensbergen if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) { 6225d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "error mux %p err %d\n", m, n); 6235503ac56SEric Van Hensbergen if (n >= 0) 6245503ac56SEric Van Hensbergen n = -ECONNRESET; 6255503ac56SEric Van Hensbergen p9_conn_cancel(m, n); 6265503ac56SEric Van Hensbergen } 6275503ac56SEric Van Hensbergen 6285503ac56SEric Van Hensbergen if (n & POLLIN) { 6295503ac56SEric Van Hensbergen set_bit(Rpending, &m->wsched); 6305d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "mux %p can read\n", m); 6315503ac56SEric Van Hensbergen if (!test_and_set_bit(Rworksched, &m->wsched)) { 6325d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "sched read work %p\n", m); 63361edeeedSTejun Heo schedule_work(&m->rq); 6345503ac56SEric Van Hensbergen } 6355503ac56SEric Van Hensbergen } 6365503ac56SEric Van Hensbergen 6375503ac56SEric Van Hensbergen if (n & POLLOUT) { 6385503ac56SEric Van Hensbergen set_bit(Wpending, &m->wsched); 6395d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "mux %p can write\n", m); 640f64f9e71SJoe Perches if ((m->wsize || !list_empty(&m->unsent_req_list)) && 641f64f9e71SJoe Perches !test_and_set_bit(Wworksched, &m->wsched)) { 6425d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "sched write work %p\n", m); 64361edeeedSTejun Heo schedule_work(&m->wq); 6445503ac56SEric Van Hensbergen } 6455503ac56SEric Van Hensbergen } 6465503ac56SEric Van Hensbergen } 6475503ac56SEric Van Hensbergen 6485503ac56SEric Van Hensbergen /** 64991b8534fSEric Van Hensbergen * p9_fd_request - send 9P request 6508a0dc95fSEric Van Hensbergen * The function can sleep until the request is scheduled for sending. 6518a0dc95fSEric Van Hensbergen * The function can be interrupted. Return from the function is not 65291b8534fSEric Van Hensbergen * a guarantee that the request is sent successfully. 6538a0dc95fSEric Van Hensbergen * 65491b8534fSEric Van Hensbergen * @client: client instance 65591b8534fSEric Van Hensbergen * @req: request to be sent 656ee443996SEric Van Hensbergen * 6578a0dc95fSEric Van Hensbergen */ 658ee443996SEric Van Hensbergen 65991b8534fSEric Van Hensbergen static int p9_fd_request(struct p9_client *client, struct p9_req_t *req) 6608a0dc95fSEric Van Hensbergen { 6618a0dc95fSEric Van Hensbergen int n; 66291b8534fSEric Van Hensbergen struct p9_trans_fd *ts = client->trans; 66391b8534fSEric Van Hensbergen struct p9_conn *m = ts->conn; 6648a0dc95fSEric Van Hensbergen 6655d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "mux %p task %p tcall %p id %d\n", 6665d385153SJoe Perches m, current, req->tc, req->tc->id); 6678a0dc95fSEric Van Hensbergen if (m->err < 0) 66891b8534fSEric Van Hensbergen return m->err; 6698a0dc95fSEric Van Hensbergen 67091b8534fSEric Van Hensbergen spin_lock(&client->lock); 6717eb923b8SEric Van Hensbergen req->status = REQ_STATUS_UNSENT; 6728a0dc95fSEric Van Hensbergen list_add_tail(&req->req_list, &m->unsent_req_list); 67391b8534fSEric Van Hensbergen spin_unlock(&client->lock); 6748a0dc95fSEric Van Hensbergen 6758a0dc95fSEric Van Hensbergen if (test_and_clear_bit(Wpending, &m->wsched)) 6768a0dc95fSEric Van Hensbergen n = POLLOUT; 6778a0dc95fSEric Van Hensbergen else 6788b81ef58SEric Van Hensbergen n = p9_fd_poll(m->client, NULL); 6798a0dc95fSEric Van Hensbergen 6808a0dc95fSEric Van Hensbergen if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched)) 68161edeeedSTejun Heo schedule_work(&m->wq); 6828a0dc95fSEric Van Hensbergen 68391b8534fSEric Van Hensbergen return 0; 6848a0dc95fSEric Van Hensbergen } 6858a0dc95fSEric Van Hensbergen 68691b8534fSEric Van Hensbergen static int p9_fd_cancel(struct p9_client *client, struct p9_req_t *req) 6878a0dc95fSEric Van Hensbergen { 6887eb923b8SEric Van Hensbergen int ret = 1; 6898a0dc95fSEric Van Hensbergen 6905d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "client %p req %p\n", client, req); 6918a0dc95fSEric Van Hensbergen 69291b8534fSEric Van Hensbergen spin_lock(&client->lock); 69391b8534fSEric Van Hensbergen 69491b8534fSEric Van Hensbergen if (req->status == REQ_STATUS_UNSENT) { 6951bab88b2SLatchesar Ionkov list_del(&req->req_list); 696673d62cdSEric Van Hensbergen req->status = REQ_STATUS_FLSHD; 6977eb923b8SEric Van Hensbergen ret = 0; 6981bab88b2SLatchesar Ionkov } else if (req->status == REQ_STATUS_SENT) 6991bab88b2SLatchesar Ionkov req->status = REQ_STATUS_FLSH; 7008a0dc95fSEric Van Hensbergen 7017eb923b8SEric Van Hensbergen spin_unlock(&client->lock); 7027eb923b8SEric Van Hensbergen 7037eb923b8SEric Van Hensbergen return ret; 7048a0dc95fSEric Van Hensbergen } 7058a0dc95fSEric Van Hensbergen 7068a0dc95fSEric Van Hensbergen /** 7070e15597eSAbhishek Kulkarni * parse_opts - parse mount options into p9_fd_opts structure 7080e15597eSAbhishek Kulkarni * @params: options string passed from mount 7090e15597eSAbhishek Kulkarni * @opts: fd transport-specific structure to parse options into 710a80d923eSEric Van Hensbergen * 711bb8ffdfcSEric Van Hensbergen * Returns 0 upon success, -ERRNO upon failure 712a80d923eSEric Van Hensbergen */ 713a80d923eSEric Van Hensbergen 714bb8ffdfcSEric Van Hensbergen static int parse_opts(char *params, struct p9_fd_opts *opts) 715bd238fb4SLatchesar Ionkov { 716a80d923eSEric Van Hensbergen char *p; 717a80d923eSEric Van Hensbergen substring_t args[MAX_OPT_ARGS]; 718a80d923eSEric Van Hensbergen int option; 719d8c8a9e3SEric Van Hensbergen char *options, *tmp_options; 720bd238fb4SLatchesar Ionkov 721a80d923eSEric Van Hensbergen opts->port = P9_PORT; 722a80d923eSEric Van Hensbergen opts->rfd = ~0; 723a80d923eSEric Van Hensbergen opts->wfd = ~0; 724bd238fb4SLatchesar Ionkov 725bb8ffdfcSEric Van Hensbergen if (!params) 726bb8ffdfcSEric Van Hensbergen return 0; 727bb8ffdfcSEric Van Hensbergen 728d8c8a9e3SEric Van Hensbergen tmp_options = kstrdup(params, GFP_KERNEL); 729d8c8a9e3SEric Van Hensbergen if (!tmp_options) { 7305d385153SJoe Perches p9_debug(P9_DEBUG_ERROR, 731bb8ffdfcSEric Van Hensbergen "failed to allocate copy of option string\n"); 732bb8ffdfcSEric Van Hensbergen return -ENOMEM; 733bb8ffdfcSEric Van Hensbergen } 734d8c8a9e3SEric Van Hensbergen options = tmp_options; 735bd238fb4SLatchesar Ionkov 736a80d923eSEric Van Hensbergen while ((p = strsep(&options, ",")) != NULL) { 737a80d923eSEric Van Hensbergen int token; 738bb8ffdfcSEric Van Hensbergen int r; 739a80d923eSEric Van Hensbergen if (!*p) 740a80d923eSEric Van Hensbergen continue; 741a80d923eSEric Van Hensbergen token = match_token(p, tokens, args); 74215da4b16SAbhishek Kulkarni if (token != Opt_err) { 743bb8ffdfcSEric Van Hensbergen r = match_int(&args[0], &option); 744bb8ffdfcSEric Van Hensbergen if (r < 0) { 7455d385153SJoe Perches p9_debug(P9_DEBUG_ERROR, 746a80d923eSEric Van Hensbergen "integer field, but no integer?\n"); 747a80d923eSEric Van Hensbergen continue; 748a80d923eSEric Van Hensbergen } 74915da4b16SAbhishek Kulkarni } 750a80d923eSEric Van Hensbergen switch (token) { 751a80d923eSEric Van Hensbergen case Opt_port: 752a80d923eSEric Van Hensbergen opts->port = option; 753a80d923eSEric Van Hensbergen break; 754a80d923eSEric Van Hensbergen case Opt_rfdno: 755a80d923eSEric Van Hensbergen opts->rfd = option; 756a80d923eSEric Van Hensbergen break; 757a80d923eSEric Van Hensbergen case Opt_wfdno: 758a80d923eSEric Van Hensbergen opts->wfd = option; 759a80d923eSEric Van Hensbergen break; 760a80d923eSEric Van Hensbergen default: 761a80d923eSEric Van Hensbergen continue; 762a80d923eSEric Van Hensbergen } 763a80d923eSEric Van Hensbergen } 764d8c8a9e3SEric Van Hensbergen 765d8c8a9e3SEric Van Hensbergen kfree(tmp_options); 766bb8ffdfcSEric Van Hensbergen return 0; 767bd238fb4SLatchesar Ionkov } 768bd238fb4SLatchesar Ionkov 7698b81ef58SEric Van Hensbergen static int p9_fd_open(struct p9_client *client, int rfd, int wfd) 770bd238fb4SLatchesar Ionkov { 771bd238fb4SLatchesar Ionkov struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd), 772bd238fb4SLatchesar Ionkov GFP_KERNEL); 773bd238fb4SLatchesar Ionkov if (!ts) 774bd238fb4SLatchesar Ionkov return -ENOMEM; 775bd238fb4SLatchesar Ionkov 776bd238fb4SLatchesar Ionkov ts->rd = fget(rfd); 777bd238fb4SLatchesar Ionkov ts->wr = fget(wfd); 778bd238fb4SLatchesar Ionkov if (!ts->rd || !ts->wr) { 779bd238fb4SLatchesar Ionkov if (ts->rd) 780bd238fb4SLatchesar Ionkov fput(ts->rd); 781bd238fb4SLatchesar Ionkov if (ts->wr) 782bd238fb4SLatchesar Ionkov fput(ts->wr); 783bd238fb4SLatchesar Ionkov kfree(ts); 784bd238fb4SLatchesar Ionkov return -EIO; 785bd238fb4SLatchesar Ionkov } 786bd238fb4SLatchesar Ionkov 7878b81ef58SEric Van Hensbergen client->trans = ts; 7888b81ef58SEric Van Hensbergen client->status = Connected; 789bd238fb4SLatchesar Ionkov 790bd238fb4SLatchesar Ionkov return 0; 791bd238fb4SLatchesar Ionkov } 792bd238fb4SLatchesar Ionkov 7938b81ef58SEric Van Hensbergen static int p9_socket_open(struct p9_client *client, struct socket *csocket) 794a80d923eSEric Van Hensbergen { 7956b18662eSAl Viro struct p9_trans_fd *p; 79656b31d1cSAl Viro struct file *file; 79756b31d1cSAl Viro int ret; 7986b18662eSAl Viro 7996b18662eSAl Viro p = kmalloc(sizeof(struct p9_trans_fd), GFP_KERNEL); 8006b18662eSAl Viro if (!p) 8016b18662eSAl Viro return -ENOMEM; 802a80d923eSEric Van Hensbergen 803a80d923eSEric Van Hensbergen csocket->sk->sk_allocation = GFP_NOIO; 804aab174f0SLinus Torvalds file = sock_alloc_file(csocket, 0, NULL); 80556b31d1cSAl Viro if (IS_ERR(file)) { 8065d385153SJoe Perches pr_err("%s (%d): failed to map fd\n", 8075d385153SJoe Perches __func__, task_pid_nr(current)); 8086b18662eSAl Viro sock_release(csocket); 8096b18662eSAl Viro kfree(p); 81056b31d1cSAl Viro return PTR_ERR(file); 811a80d923eSEric Van Hensbergen } 812a80d923eSEric Van Hensbergen 81356b31d1cSAl Viro get_file(file); 81456b31d1cSAl Viro p->wr = p->rd = file; 8156b18662eSAl Viro client->trans = p; 8166b18662eSAl Viro client->status = Connected; 8176b18662eSAl Viro 8186b18662eSAl Viro p->rd->f_flags |= O_NONBLOCK; 8196b18662eSAl Viro 8206b18662eSAl Viro p->conn = p9_conn_create(client); 8216b18662eSAl Viro if (IS_ERR(p->conn)) { 8226b18662eSAl Viro ret = PTR_ERR(p->conn); 8236b18662eSAl Viro p->conn = NULL; 8246b18662eSAl Viro kfree(p); 8256b18662eSAl Viro sockfd_put(csocket); 826a80d923eSEric Van Hensbergen sockfd_put(csocket); 827a80d923eSEric Van Hensbergen return ret; 828a80d923eSEric Van Hensbergen } 829a80d923eSEric Van Hensbergen return 0; 830a80d923eSEric Van Hensbergen } 831a80d923eSEric Van Hensbergen 832bd238fb4SLatchesar Ionkov /** 8335503ac56SEric Van Hensbergen * p9_mux_destroy - cancels all pending requests and frees mux resources 8345503ac56SEric Van Hensbergen * @m: mux to destroy 835bd238fb4SLatchesar Ionkov * 836bd238fb4SLatchesar Ionkov */ 837ee443996SEric Van Hensbergen 8385503ac56SEric Van Hensbergen static void p9_conn_destroy(struct p9_conn *m) 839bd238fb4SLatchesar Ionkov { 8405d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "mux %p prev %p next %p\n", 8415d385153SJoe Perches m, m->mux_list.prev, m->mux_list.next); 842bd238fb4SLatchesar Ionkov 8435503ac56SEric Van Hensbergen p9_mux_poll_stop(m); 8445503ac56SEric Van Hensbergen cancel_work_sync(&m->rq); 8455503ac56SEric Van Hensbergen cancel_work_sync(&m->wq); 846bd238fb4SLatchesar Ionkov 8475503ac56SEric Van Hensbergen p9_conn_cancel(m, -ECONNRESET); 848bd238fb4SLatchesar Ionkov 8495503ac56SEric Van Hensbergen m->client = NULL; 8505503ac56SEric Van Hensbergen kfree(m); 851bd238fb4SLatchesar Ionkov } 852bd238fb4SLatchesar Ionkov 853bd238fb4SLatchesar Ionkov /** 8548b81ef58SEric Van Hensbergen * p9_fd_close - shutdown file descriptor transport 8558b81ef58SEric Van Hensbergen * @client: client instance 856bd238fb4SLatchesar Ionkov * 857bd238fb4SLatchesar Ionkov */ 858ee443996SEric Van Hensbergen 8598b81ef58SEric Van Hensbergen static void p9_fd_close(struct p9_client *client) 860bd238fb4SLatchesar Ionkov { 861bd238fb4SLatchesar Ionkov struct p9_trans_fd *ts; 862bd238fb4SLatchesar Ionkov 8638b81ef58SEric Van Hensbergen if (!client) 864bd238fb4SLatchesar Ionkov return; 865bd238fb4SLatchesar Ionkov 8668b81ef58SEric Van Hensbergen ts = client->trans; 867bd238fb4SLatchesar Ionkov if (!ts) 868bd238fb4SLatchesar Ionkov return; 869bd238fb4SLatchesar Ionkov 8708b81ef58SEric Van Hensbergen client->status = Disconnected; 8718b81ef58SEric Van Hensbergen 8728a0dc95fSEric Van Hensbergen p9_conn_destroy(ts->conn); 8738a0dc95fSEric Van Hensbergen 874bd238fb4SLatchesar Ionkov if (ts->rd) 875bd238fb4SLatchesar Ionkov fput(ts->rd); 876bd238fb4SLatchesar Ionkov if (ts->wr) 877bd238fb4SLatchesar Ionkov fput(ts->wr); 8788b81ef58SEric Van Hensbergen 879bd238fb4SLatchesar Ionkov kfree(ts); 880bd238fb4SLatchesar Ionkov } 881bd238fb4SLatchesar Ionkov 882887b3eceSEric Van Hensbergen /* 883887b3eceSEric Van Hensbergen * stolen from NFS - maybe should be made a generic function? 884887b3eceSEric Van Hensbergen */ 885887b3eceSEric Van Hensbergen static inline int valid_ipaddr4(const char *buf) 886887b3eceSEric Van Hensbergen { 887887b3eceSEric Van Hensbergen int rc, count, in[4]; 888887b3eceSEric Van Hensbergen 889887b3eceSEric Van Hensbergen rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]); 890887b3eceSEric Van Hensbergen if (rc != 4) 891887b3eceSEric Van Hensbergen return -EINVAL; 892887b3eceSEric Van Hensbergen for (count = 0; count < 4; count++) { 893887b3eceSEric Van Hensbergen if (in[count] > 255) 894887b3eceSEric Van Hensbergen return -EINVAL; 895887b3eceSEric Van Hensbergen } 896887b3eceSEric Van Hensbergen return 0; 897887b3eceSEric Van Hensbergen } 898887b3eceSEric Van Hensbergen 8998b81ef58SEric Van Hensbergen static int 9008b81ef58SEric Van Hensbergen p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args) 901a80d923eSEric Van Hensbergen { 902a80d923eSEric Van Hensbergen int err; 903a80d923eSEric Van Hensbergen struct socket *csocket; 904a80d923eSEric Van Hensbergen struct sockaddr_in sin_server; 905a80d923eSEric Van Hensbergen struct p9_fd_opts opts; 906a80d923eSEric Van Hensbergen 907bb8ffdfcSEric Van Hensbergen err = parse_opts(args, &opts); 908bb8ffdfcSEric Van Hensbergen if (err < 0) 9098b81ef58SEric Van Hensbergen return err; 910a80d923eSEric Van Hensbergen 911887b3eceSEric Van Hensbergen if (valid_ipaddr4(addr) < 0) 9128b81ef58SEric Van Hensbergen return -EINVAL; 913887b3eceSEric Van Hensbergen 914a80d923eSEric Van Hensbergen csocket = NULL; 915a80d923eSEric Van Hensbergen 916a80d923eSEric Van Hensbergen sin_server.sin_family = AF_INET; 917a80d923eSEric Van Hensbergen sin_server.sin_addr.s_addr = in_aton(addr); 918a80d923eSEric Van Hensbergen sin_server.sin_port = htons(opts.port); 919e75762fdSRob Landley err = __sock_create(read_pnet(¤t->nsproxy->net_ns), PF_INET, 920e75762fdSRob Landley SOCK_STREAM, IPPROTO_TCP, &csocket, 1); 9216b18662eSAl Viro if (err) { 9225d385153SJoe Perches pr_err("%s (%d): problem creating socket\n", 9235d385153SJoe Perches __func__, task_pid_nr(current)); 9246b18662eSAl Viro return err; 925a80d923eSEric Van Hensbergen } 926a80d923eSEric Van Hensbergen 927a80d923eSEric Van Hensbergen err = csocket->ops->connect(csocket, 928a80d923eSEric Van Hensbergen (struct sockaddr *)&sin_server, 929a80d923eSEric Van Hensbergen sizeof(struct sockaddr_in), 0); 930a80d923eSEric Van Hensbergen if (err < 0) { 9315d385153SJoe Perches pr_err("%s (%d): problem connecting socket to %s\n", 9325d385153SJoe Perches __func__, task_pid_nr(current), addr); 933a80d923eSEric Van Hensbergen sock_release(csocket); 9348b81ef58SEric Van Hensbergen return err; 935a80d923eSEric Van Hensbergen } 936a80d923eSEric Van Hensbergen 9376b18662eSAl Viro return p9_socket_open(client, csocket); 9386b18662eSAl Viro } 9396b18662eSAl Viro 9408b81ef58SEric Van Hensbergen static int 9418b81ef58SEric Van Hensbergen p9_fd_create_unix(struct p9_client *client, const char *addr, char *args) 942a80d923eSEric Van Hensbergen { 943a80d923eSEric Van Hensbergen int err; 944a80d923eSEric Van Hensbergen struct socket *csocket; 945a80d923eSEric Van Hensbergen struct sockaddr_un sun_server; 946a80d923eSEric Van Hensbergen 947a80d923eSEric Van Hensbergen csocket = NULL; 948a80d923eSEric Van Hensbergen 949cff6b8a9SDan Carpenter if (strlen(addr) >= UNIX_PATH_MAX) { 9505d385153SJoe Perches pr_err("%s (%d): address too long: %s\n", 9515d385153SJoe Perches __func__, task_pid_nr(current), addr); 9526b18662eSAl Viro return -ENAMETOOLONG; 953a80d923eSEric Van Hensbergen } 954a80d923eSEric Van Hensbergen 955a80d923eSEric Van Hensbergen sun_server.sun_family = PF_UNIX; 956a80d923eSEric Van Hensbergen strcpy(sun_server.sun_path, addr); 957e75762fdSRob Landley err = __sock_create(read_pnet(¤t->nsproxy->net_ns), PF_UNIX, 958e75762fdSRob Landley SOCK_STREAM, 0, &csocket, 1); 9596b18662eSAl Viro if (err < 0) { 9605d385153SJoe Perches pr_err("%s (%d): problem creating socket\n", 9615d385153SJoe Perches __func__, task_pid_nr(current)); 9625d385153SJoe Perches 9636b18662eSAl Viro return err; 9646b18662eSAl Viro } 965a80d923eSEric Van Hensbergen err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server, 966a80d923eSEric Van Hensbergen sizeof(struct sockaddr_un) - 1, 0); 967a80d923eSEric Van Hensbergen if (err < 0) { 9685d385153SJoe Perches pr_err("%s (%d): problem connecting socket: %s: %d\n", 9695d385153SJoe Perches __func__, task_pid_nr(current), addr, err); 970a80d923eSEric Van Hensbergen sock_release(csocket); 9718b81ef58SEric Van Hensbergen return err; 972a80d923eSEric Van Hensbergen } 973a80d923eSEric Van Hensbergen 9746b18662eSAl Viro return p9_socket_open(client, csocket); 9756b18662eSAl Viro } 9766b18662eSAl Viro 9778b81ef58SEric Van Hensbergen static int 9788b81ef58SEric Van Hensbergen p9_fd_create(struct p9_client *client, const char *addr, char *args) 979a80d923eSEric Van Hensbergen { 980a80d923eSEric Van Hensbergen int err; 981a80d923eSEric Van Hensbergen struct p9_fd_opts opts; 9826b18662eSAl Viro struct p9_trans_fd *p; 983a80d923eSEric Van Hensbergen 984a80d923eSEric Van Hensbergen parse_opts(args, &opts); 985a80d923eSEric Van Hensbergen 986a80d923eSEric Van Hensbergen if (opts.rfd == ~0 || opts.wfd == ~0) { 9875d385153SJoe Perches pr_err("Insufficient options for proto=fd\n"); 9888b81ef58SEric Van Hensbergen return -ENOPROTOOPT; 989a80d923eSEric Van Hensbergen } 990a80d923eSEric Van Hensbergen 9918b81ef58SEric Van Hensbergen err = p9_fd_open(client, opts.rfd, opts.wfd); 992a80d923eSEric Van Hensbergen if (err < 0) 9936b18662eSAl Viro return err; 994a80d923eSEric Van Hensbergen 9958b81ef58SEric Van Hensbergen p = (struct p9_trans_fd *) client->trans; 9968b81ef58SEric Van Hensbergen p->conn = p9_conn_create(client); 9978a0dc95fSEric Van Hensbergen if (IS_ERR(p->conn)) { 9988a0dc95fSEric Van Hensbergen err = PTR_ERR(p->conn); 9998a0dc95fSEric Van Hensbergen p->conn = NULL; 10006b18662eSAl Viro fput(p->rd); 10016b18662eSAl Viro fput(p->wr); 10026b18662eSAl Viro return err; 10038a0dc95fSEric Van Hensbergen } 10048a0dc95fSEric Van Hensbergen 10058b81ef58SEric Van Hensbergen return 0; 1006a80d923eSEric Van Hensbergen } 1007a80d923eSEric Van Hensbergen 1008a80d923eSEric Van Hensbergen static struct p9_trans_module p9_tcp_trans = { 1009a80d923eSEric Van Hensbergen .name = "tcp", 1010a80d923eSEric Van Hensbergen .maxsize = MAX_SOCK_BUF, 1011a80d923eSEric Van Hensbergen .def = 1, 10128b81ef58SEric Van Hensbergen .create = p9_fd_create_tcp, 10138b81ef58SEric Van Hensbergen .close = p9_fd_close, 101491b8534fSEric Van Hensbergen .request = p9_fd_request, 101591b8534fSEric Van Hensbergen .cancel = p9_fd_cancel, 101672029fe8STejun Heo .owner = THIS_MODULE, 1017a80d923eSEric Van Hensbergen }; 1018a80d923eSEric Van Hensbergen 1019a80d923eSEric Van Hensbergen static struct p9_trans_module p9_unix_trans = { 1020a80d923eSEric Van Hensbergen .name = "unix", 1021a80d923eSEric Van Hensbergen .maxsize = MAX_SOCK_BUF, 1022a80d923eSEric Van Hensbergen .def = 0, 10238b81ef58SEric Van Hensbergen .create = p9_fd_create_unix, 10248b81ef58SEric Van Hensbergen .close = p9_fd_close, 102591b8534fSEric Van Hensbergen .request = p9_fd_request, 102691b8534fSEric Van Hensbergen .cancel = p9_fd_cancel, 102772029fe8STejun Heo .owner = THIS_MODULE, 1028a80d923eSEric Van Hensbergen }; 1029a80d923eSEric Van Hensbergen 1030a80d923eSEric Van Hensbergen static struct p9_trans_module p9_fd_trans = { 1031a80d923eSEric Van Hensbergen .name = "fd", 1032a80d923eSEric Van Hensbergen .maxsize = MAX_SOCK_BUF, 1033a80d923eSEric Van Hensbergen .def = 0, 10348b81ef58SEric Van Hensbergen .create = p9_fd_create, 10358b81ef58SEric Van Hensbergen .close = p9_fd_close, 103691b8534fSEric Van Hensbergen .request = p9_fd_request, 103791b8534fSEric Van Hensbergen .cancel = p9_fd_cancel, 103872029fe8STejun Heo .owner = THIS_MODULE, 1039a80d923eSEric Van Hensbergen }; 1040a80d923eSEric Van Hensbergen 10415503ac56SEric Van Hensbergen /** 10425503ac56SEric Van Hensbergen * p9_poll_proc - poll worker thread 10435503ac56SEric Van Hensbergen * @a: thread state and arguments 10445503ac56SEric Van Hensbergen * 10455503ac56SEric Van Hensbergen * polls all v9fs transports for new events and queues the appropriate 10465503ac56SEric Van Hensbergen * work to the work queue 10475503ac56SEric Van Hensbergen * 10485503ac56SEric Van Hensbergen */ 10495503ac56SEric Van Hensbergen 1050aa70c585STejun Heo static void p9_poll_workfn(struct work_struct *work) 10515503ac56SEric Van Hensbergen { 10525503ac56SEric Van Hensbergen unsigned long flags; 10535503ac56SEric Van Hensbergen 10545d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "start %p\n", current); 1055aa70c585STejun Heo 10565503ac56SEric Van Hensbergen spin_lock_irqsave(&p9_poll_lock, flags); 10575503ac56SEric Van Hensbergen while (!list_empty(&p9_poll_pending_list)) { 10585503ac56SEric Van Hensbergen struct p9_conn *conn = list_first_entry(&p9_poll_pending_list, 10595503ac56SEric Van Hensbergen struct p9_conn, 10605503ac56SEric Van Hensbergen poll_pending_link); 10615503ac56SEric Van Hensbergen list_del_init(&conn->poll_pending_link); 10625503ac56SEric Van Hensbergen spin_unlock_irqrestore(&p9_poll_lock, flags); 10635503ac56SEric Van Hensbergen 10645503ac56SEric Van Hensbergen p9_poll_mux(conn); 10655503ac56SEric Van Hensbergen 10665503ac56SEric Van Hensbergen spin_lock_irqsave(&p9_poll_lock, flags); 10675503ac56SEric Van Hensbergen } 10685503ac56SEric Van Hensbergen spin_unlock_irqrestore(&p9_poll_lock, flags); 10695503ac56SEric Van Hensbergen 10705d385153SJoe Perches p9_debug(P9_DEBUG_TRANS, "finish\n"); 10715503ac56SEric Van Hensbergen } 10725503ac56SEric Van Hensbergen 1073887b3eceSEric Van Hensbergen int p9_trans_fd_init(void) 1074a80d923eSEric Van Hensbergen { 1075a80d923eSEric Van Hensbergen v9fs_register_trans(&p9_tcp_trans); 1076a80d923eSEric Van Hensbergen v9fs_register_trans(&p9_unix_trans); 1077a80d923eSEric Van Hensbergen v9fs_register_trans(&p9_fd_trans); 1078a80d923eSEric Van Hensbergen 10793387b804SAndrew Morton return 0; 1080a80d923eSEric Van Hensbergen } 108172029fe8STejun Heo 108272029fe8STejun Heo void p9_trans_fd_exit(void) 108372029fe8STejun Heo { 108443829731STejun Heo flush_work(&p9_poll_work); 108572029fe8STejun Heo v9fs_unregister_trans(&p9_tcp_trans); 108672029fe8STejun Heo v9fs_unregister_trans(&p9_unix_trans); 108772029fe8STejun Heo v9fs_unregister_trans(&p9_fd_trans); 108872029fe8STejun Heo } 1089