1bd238fb4SLatchesar Ionkov /* 2bd238fb4SLatchesar Ionkov * linux/fs/9p/trans_fd.c 3bd238fb4SLatchesar Ionkov * 4bd238fb4SLatchesar Ionkov * Fd transport layer. Includes deprecated socket layer. 5bd238fb4SLatchesar Ionkov * 6bd238fb4SLatchesar Ionkov * Copyright (C) 2006 by Russ Cox <rsc@swtch.com> 7bd238fb4SLatchesar Ionkov * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net> 88a0dc95fSEric Van Hensbergen * Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com> 9bd238fb4SLatchesar Ionkov * Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com> 10bd238fb4SLatchesar Ionkov * 11bd238fb4SLatchesar Ionkov * This program is free software; you can redistribute it and/or modify 12bd238fb4SLatchesar Ionkov * it under the terms of the GNU General Public License version 2 13bd238fb4SLatchesar Ionkov * as published by the Free Software Foundation. 14bd238fb4SLatchesar Ionkov * 15bd238fb4SLatchesar Ionkov * This program is distributed in the hope that it will be useful, 16bd238fb4SLatchesar Ionkov * but WITHOUT ANY WARRANTY; without even the implied warranty of 17bd238fb4SLatchesar Ionkov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18bd238fb4SLatchesar Ionkov * GNU General Public License for more details. 19bd238fb4SLatchesar Ionkov * 20bd238fb4SLatchesar Ionkov * You should have received a copy of the GNU General Public License 21bd238fb4SLatchesar Ionkov * along with this program; if not, write to: 22bd238fb4SLatchesar Ionkov * Free Software Foundation 23bd238fb4SLatchesar Ionkov * 51 Franklin Street, Fifth Floor 24bd238fb4SLatchesar Ionkov * Boston, MA 02111-1301 USA 25bd238fb4SLatchesar Ionkov * 26bd238fb4SLatchesar Ionkov */ 27bd238fb4SLatchesar Ionkov 28bd238fb4SLatchesar Ionkov #include <linux/in.h> 29bd238fb4SLatchesar Ionkov #include <linux/module.h> 30bd238fb4SLatchesar Ionkov #include <linux/net.h> 31bd238fb4SLatchesar Ionkov #include <linux/ipv6.h> 328a0dc95fSEric Van Hensbergen #include <linux/kthread.h> 33bd238fb4SLatchesar Ionkov #include <linux/errno.h> 34bd238fb4SLatchesar Ionkov #include <linux/kernel.h> 35bd238fb4SLatchesar Ionkov #include <linux/un.h> 36bd238fb4SLatchesar Ionkov #include <linux/uaccess.h> 37bd238fb4SLatchesar Ionkov #include <linux/inet.h> 38bd238fb4SLatchesar Ionkov #include <linux/idr.h> 39bd238fb4SLatchesar Ionkov #include <linux/file.h> 40a80d923eSEric Van Hensbergen #include <linux/parser.h> 415a0e3ad6STejun Heo #include <linux/slab.h> 42bd238fb4SLatchesar Ionkov #include <net/9p/9p.h> 438b81ef58SEric Van Hensbergen #include <net/9p/client.h> 44bd238fb4SLatchesar Ionkov #include <net/9p/transport.h> 45bd238fb4SLatchesar Ionkov 466b18662eSAl Viro #include <linux/syscalls.h> /* killme */ 476b18662eSAl Viro 48bd238fb4SLatchesar Ionkov #define P9_PORT 564 49a80d923eSEric Van Hensbergen #define MAX_SOCK_BUF (64*1024) 508a0dc95fSEric Van Hensbergen #define MAXPOLLWADDR 2 51a80d923eSEric Van Hensbergen 52ee443996SEric Van Hensbergen /** 53ee443996SEric Van Hensbergen * struct p9_fd_opts - per-transport options 54ee443996SEric Van Hensbergen * @rfd: file descriptor for reading (trans=fd) 55ee443996SEric Van Hensbergen * @wfd: file descriptor for writing (trans=fd) 56ee443996SEric Van Hensbergen * @port: port to connect to (trans=tcp) 57ee443996SEric Van Hensbergen * 58ee443996SEric Van Hensbergen */ 59ee443996SEric Van Hensbergen 60a80d923eSEric Van Hensbergen struct p9_fd_opts { 61a80d923eSEric Van Hensbergen int rfd; 62a80d923eSEric Van Hensbergen int wfd; 63a80d923eSEric Van Hensbergen u16 port; 64a80d923eSEric Van Hensbergen }; 65bd238fb4SLatchesar Ionkov 66ee443996SEric Van Hensbergen /** 67ee443996SEric Van Hensbergen * struct p9_trans_fd - transport state 68ee443996SEric Van Hensbergen * @rd: reference to file to read from 69ee443996SEric Van Hensbergen * @wr: reference of file to write to 70ee443996SEric Van Hensbergen * @conn: connection state reference 71ee443996SEric Van Hensbergen * 72ee443996SEric Van Hensbergen */ 73ee443996SEric Van Hensbergen 74bd238fb4SLatchesar Ionkov struct p9_trans_fd { 75bd238fb4SLatchesar Ionkov struct file *rd; 76bd238fb4SLatchesar Ionkov struct file *wr; 778a0dc95fSEric Van Hensbergen struct p9_conn *conn; 78bd238fb4SLatchesar Ionkov }; 79bd238fb4SLatchesar Ionkov 80a80d923eSEric Van Hensbergen /* 81a80d923eSEric Van Hensbergen * Option Parsing (code inspired by NFS code) 82a80d923eSEric Van Hensbergen * - a little lazy - parse all fd-transport options 83a80d923eSEric Van Hensbergen */ 84bd238fb4SLatchesar Ionkov 85a80d923eSEric Van Hensbergen enum { 86a80d923eSEric Van Hensbergen /* Options that take integer arguments */ 8755762690SLatchesar Ionkov Opt_port, Opt_rfdno, Opt_wfdno, Opt_err, 88a80d923eSEric Van Hensbergen }; 89a80d923eSEric Van Hensbergen 90a447c093SSteven Whitehouse static const match_table_t tokens = { 91a80d923eSEric Van Hensbergen {Opt_port, "port=%u"}, 92a80d923eSEric Van Hensbergen {Opt_rfdno, "rfdno=%u"}, 93a80d923eSEric Van Hensbergen {Opt_wfdno, "wfdno=%u"}, 9455762690SLatchesar Ionkov {Opt_err, NULL}, 95a80d923eSEric Van Hensbergen }; 96a80d923eSEric Van Hensbergen 978a0dc95fSEric Van Hensbergen enum { 988a0dc95fSEric Van Hensbergen Rworksched = 1, /* read work scheduled or running */ 998a0dc95fSEric Van Hensbergen Rpending = 2, /* can read */ 1008a0dc95fSEric Van Hensbergen Wworksched = 4, /* write work scheduled or running */ 1018a0dc95fSEric Van Hensbergen Wpending = 8, /* can write */ 1028a0dc95fSEric Van Hensbergen }; 1038a0dc95fSEric Van Hensbergen 104992b3f1dSTejun Heo struct p9_poll_wait { 105992b3f1dSTejun Heo struct p9_conn *conn; 106992b3f1dSTejun Heo wait_queue_t wait; 107992b3f1dSTejun Heo wait_queue_head_t *wait_addr; 108ee443996SEric Van Hensbergen }; 109ee443996SEric Van Hensbergen 110ee443996SEric Van Hensbergen /** 111ee443996SEric Van Hensbergen * struct p9_conn - fd mux connection state information 112ee443996SEric Van Hensbergen * @mux_list: list link for mux to manage multiple connections (?) 1138b81ef58SEric Van Hensbergen * @client: reference to client instance for this connection 114ee443996SEric Van Hensbergen * @err: error state 115ee443996SEric Van Hensbergen * @req_list: accounting for requests which have been sent 116ee443996SEric Van Hensbergen * @unsent_req_list: accounting for requests that haven't been sent 1171b0a763bSEric Van Hensbergen * @req: current request being processed (if any) 1181b0a763bSEric Van Hensbergen * @tmp_buf: temporary buffer to read in header 1191b0a763bSEric Van Hensbergen * @rsize: amount to read for current frame 120ee443996SEric Van Hensbergen * @rpos: read position in current frame 121ee443996SEric Van Hensbergen * @rbuf: current read buffer 122ee443996SEric Van Hensbergen * @wpos: write position for current frame 123ee443996SEric Van Hensbergen * @wsize: amount of data to write for current frame 124ee443996SEric Van Hensbergen * @wbuf: current write buffer 1250e15597eSAbhishek Kulkarni * @poll_pending_link: pending links to be polled per conn 126ee443996SEric Van Hensbergen * @poll_wait: array of wait_q's for various worker threads 127ee443996SEric Van Hensbergen * @pt: poll state 128ee443996SEric Van Hensbergen * @rq: current read work 129ee443996SEric Van Hensbergen * @wq: current write work 130ee443996SEric Van Hensbergen * @wsched: ???? 131ee443996SEric Van Hensbergen * 132ee443996SEric Van Hensbergen */ 1338a0dc95fSEric Van Hensbergen 1348a0dc95fSEric Van Hensbergen struct p9_conn { 1358a0dc95fSEric Van Hensbergen struct list_head mux_list; 1368b81ef58SEric Van Hensbergen struct p9_client *client; 1378a0dc95fSEric Van Hensbergen int err; 1388a0dc95fSEric Van Hensbergen struct list_head req_list; 1398a0dc95fSEric Van Hensbergen struct list_head unsent_req_list; 1401b0a763bSEric Van Hensbergen struct p9_req_t *req; 1411b0a763bSEric Van Hensbergen char tmp_buf[7]; 1421b0a763bSEric Van Hensbergen int rsize; 1438a0dc95fSEric Van Hensbergen int rpos; 1448a0dc95fSEric Van Hensbergen char *rbuf; 1458a0dc95fSEric Van Hensbergen int wpos; 1468a0dc95fSEric Van Hensbergen int wsize; 1478a0dc95fSEric Van Hensbergen char *wbuf; 148992b3f1dSTejun Heo struct list_head poll_pending_link; 149992b3f1dSTejun Heo struct p9_poll_wait poll_wait[MAXPOLLWADDR]; 1508a0dc95fSEric Van Hensbergen poll_table pt; 1518a0dc95fSEric Van Hensbergen struct work_struct rq; 1528a0dc95fSEric Van Hensbergen struct work_struct wq; 1538a0dc95fSEric Van Hensbergen unsigned long wsched; 1548a0dc95fSEric Van Hensbergen }; 1558a0dc95fSEric Van Hensbergen 156aa70c585STejun Heo static void p9_poll_workfn(struct work_struct *work); 157aa70c585STejun Heo 158992b3f1dSTejun Heo static DEFINE_SPINLOCK(p9_poll_lock); 159992b3f1dSTejun Heo static LIST_HEAD(p9_poll_pending_list); 160aa70c585STejun Heo static DECLARE_WORK(p9_poll_work, p9_poll_workfn); 1618a0dc95fSEric Van Hensbergen 1628a0dc95fSEric Van Hensbergen static void p9_mux_poll_stop(struct p9_conn *m) 1638a0dc95fSEric Van Hensbergen { 164992b3f1dSTejun Heo unsigned long flags; 1658a0dc95fSEric Van Hensbergen int i; 1668a0dc95fSEric Van Hensbergen 167992b3f1dSTejun Heo for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { 168992b3f1dSTejun Heo struct p9_poll_wait *pwait = &m->poll_wait[i]; 169992b3f1dSTejun Heo 170992b3f1dSTejun Heo if (pwait->wait_addr) { 171992b3f1dSTejun Heo remove_wait_queue(pwait->wait_addr, &pwait->wait); 172992b3f1dSTejun Heo pwait->wait_addr = NULL; 1738a0dc95fSEric Van Hensbergen } 1748a0dc95fSEric Van Hensbergen } 175992b3f1dSTejun Heo 176992b3f1dSTejun Heo spin_lock_irqsave(&p9_poll_lock, flags); 177992b3f1dSTejun Heo list_del_init(&m->poll_pending_link); 178992b3f1dSTejun Heo spin_unlock_irqrestore(&p9_poll_lock, flags); 1798a0dc95fSEric Van Hensbergen } 1808a0dc95fSEric Van Hensbergen 1818a0dc95fSEric Van Hensbergen /** 1825503ac56SEric Van Hensbergen * p9_conn_cancel - cancel all pending requests with error 1835503ac56SEric Van Hensbergen * @m: mux data 1845503ac56SEric Van Hensbergen * @err: error code 185ee443996SEric Van Hensbergen * 1868a0dc95fSEric Van Hensbergen */ 187ee443996SEric Van Hensbergen 18851a87c55SEric Van Hensbergen static void p9_conn_cancel(struct p9_conn *m, int err) 1898a0dc95fSEric Van Hensbergen { 190673d62cdSEric Van Hensbergen struct p9_req_t *req, *rtmp; 19191b8534fSEric Van Hensbergen unsigned long flags; 1925503ac56SEric Van Hensbergen LIST_HEAD(cancel_list); 1938a0dc95fSEric Van Hensbergen 1945503ac56SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err); 1957eb923b8SEric Van Hensbergen 19691b8534fSEric Van Hensbergen spin_lock_irqsave(&m->client->lock, flags); 1977eb923b8SEric Van Hensbergen 1987eb923b8SEric Van Hensbergen if (m->err) { 1997eb923b8SEric Van Hensbergen spin_unlock_irqrestore(&m->client->lock, flags); 2007eb923b8SEric Van Hensbergen return; 2017eb923b8SEric Van Hensbergen } 2027eb923b8SEric Van Hensbergen 2037eb923b8SEric Van Hensbergen m->err = err; 2047eb923b8SEric Van Hensbergen 2055503ac56SEric Van Hensbergen list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { 206673d62cdSEric Van Hensbergen req->status = REQ_STATUS_ERROR; 207673d62cdSEric Van Hensbergen if (!req->t_err) 208673d62cdSEric Van Hensbergen req->t_err = err; 2095503ac56SEric Van Hensbergen list_move(&req->req_list, &cancel_list); 2105503ac56SEric Van Hensbergen } 2115503ac56SEric Van Hensbergen list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) { 212673d62cdSEric Van Hensbergen req->status = REQ_STATUS_ERROR; 213673d62cdSEric Van Hensbergen if (!req->t_err) 214673d62cdSEric Van Hensbergen req->t_err = err; 2155503ac56SEric Van Hensbergen list_move(&req->req_list, &cancel_list); 2165503ac56SEric Van Hensbergen } 21791b8534fSEric Van Hensbergen spin_unlock_irqrestore(&m->client->lock, flags); 2188a0dc95fSEric Van Hensbergen 2195503ac56SEric Van Hensbergen list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) { 22091b8534fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, "call back req %p\n", req); 2211bab88b2SLatchesar Ionkov list_del(&req->req_list); 22291b8534fSEric Van Hensbergen p9_client_cb(m->client, req); 2238a0dc95fSEric Van Hensbergen } 2248a0dc95fSEric Van Hensbergen } 2258a0dc95fSEric Van Hensbergen 22629af9309SJulia Lawall static int 2275503ac56SEric Van Hensbergen p9_fd_poll(struct p9_client *client, struct poll_table_struct *pt) 2285503ac56SEric Van Hensbergen { 2295503ac56SEric Van Hensbergen int ret, n; 2305503ac56SEric Van Hensbergen struct p9_trans_fd *ts = NULL; 2315503ac56SEric Van Hensbergen 2325503ac56SEric Van Hensbergen if (client && client->status == Connected) 2335503ac56SEric Van Hensbergen ts = client->trans; 2345503ac56SEric Van Hensbergen 2355503ac56SEric Van Hensbergen if (!ts) 2365503ac56SEric Van Hensbergen return -EREMOTEIO; 2375503ac56SEric Van Hensbergen 2385503ac56SEric Van Hensbergen if (!ts->rd->f_op || !ts->rd->f_op->poll) 2395503ac56SEric Van Hensbergen return -EIO; 2405503ac56SEric Van Hensbergen 2415503ac56SEric Van Hensbergen if (!ts->wr->f_op || !ts->wr->f_op->poll) 2425503ac56SEric Van Hensbergen return -EIO; 2435503ac56SEric Van Hensbergen 2445503ac56SEric Van Hensbergen ret = ts->rd->f_op->poll(ts->rd, pt); 2455503ac56SEric Van Hensbergen if (ret < 0) 2465503ac56SEric Van Hensbergen return ret; 2475503ac56SEric Van Hensbergen 2485503ac56SEric Van Hensbergen if (ts->rd != ts->wr) { 2495503ac56SEric Van Hensbergen n = ts->wr->f_op->poll(ts->wr, pt); 2505503ac56SEric Van Hensbergen if (n < 0) 2515503ac56SEric Van Hensbergen return n; 2525503ac56SEric Van Hensbergen ret = (ret & ~POLLOUT) | (n & ~POLLIN); 2535503ac56SEric Van Hensbergen } 2545503ac56SEric Van Hensbergen 2555503ac56SEric Van Hensbergen return ret; 2565503ac56SEric Van Hensbergen } 2575503ac56SEric Van Hensbergen 2585503ac56SEric Van Hensbergen /** 2595503ac56SEric Van Hensbergen * p9_fd_read- read from a fd 2605503ac56SEric Van Hensbergen * @client: client instance 2615503ac56SEric Van Hensbergen * @v: buffer to receive data into 2625503ac56SEric Van Hensbergen * @len: size of receive buffer 2635503ac56SEric Van Hensbergen * 2645503ac56SEric Van Hensbergen */ 2655503ac56SEric Van Hensbergen 2665503ac56SEric Van Hensbergen static int p9_fd_read(struct p9_client *client, void *v, int len) 2675503ac56SEric Van Hensbergen { 2685503ac56SEric Van Hensbergen int ret; 2695503ac56SEric Van Hensbergen struct p9_trans_fd *ts = NULL; 2705503ac56SEric Van Hensbergen 2715503ac56SEric Van Hensbergen if (client && client->status != Disconnected) 2725503ac56SEric Van Hensbergen ts = client->trans; 2735503ac56SEric Van Hensbergen 2745503ac56SEric Van Hensbergen if (!ts) 2755503ac56SEric Van Hensbergen return -EREMOTEIO; 2765503ac56SEric Van Hensbergen 2775503ac56SEric Van Hensbergen if (!(ts->rd->f_flags & O_NONBLOCK)) 2785503ac56SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, "blocking read ...\n"); 2795503ac56SEric Van Hensbergen 2805503ac56SEric Van Hensbergen ret = kernel_read(ts->rd, ts->rd->f_pos, v, len); 2815503ac56SEric Van Hensbergen if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) 2825503ac56SEric Van Hensbergen client->status = Disconnected; 2835503ac56SEric Van Hensbergen return ret; 2845503ac56SEric Van Hensbergen } 2855503ac56SEric Van Hensbergen 2868a0dc95fSEric Van Hensbergen /** 2878a0dc95fSEric Van Hensbergen * p9_read_work - called when there is some data to be read from a transport 288ee443996SEric Van Hensbergen * @work: container of work to be done 289ee443996SEric Van Hensbergen * 2908a0dc95fSEric Van Hensbergen */ 291ee443996SEric Van Hensbergen 2928a0dc95fSEric Van Hensbergen static void p9_read_work(struct work_struct *work) 2938a0dc95fSEric Van Hensbergen { 2948a0dc95fSEric Van Hensbergen int n, err; 2958a0dc95fSEric Van Hensbergen struct p9_conn *m; 2968a0dc95fSEric Van Hensbergen 2978a0dc95fSEric Van Hensbergen m = container_of(work, struct p9_conn, rq); 2988a0dc95fSEric Van Hensbergen 2998a0dc95fSEric Van Hensbergen if (m->err < 0) 3008a0dc95fSEric Van Hensbergen return; 3018a0dc95fSEric Van Hensbergen 30251a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "start mux %p pos %d\n", m, m->rpos); 3038a0dc95fSEric Van Hensbergen 3041b0a763bSEric Van Hensbergen if (!m->rbuf) { 3051b0a763bSEric Van Hensbergen m->rbuf = m->tmp_buf; 3068a0dc95fSEric Van Hensbergen m->rpos = 0; 3071b0a763bSEric Van Hensbergen m->rsize = 7; /* start by reading header */ 3088a0dc95fSEric Van Hensbergen } 3098a0dc95fSEric Van Hensbergen 3108a0dc95fSEric Van Hensbergen clear_bit(Rpending, &m->wsched); 31151a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "read mux %p pos %d size: %d = %d\n", m, 3121b0a763bSEric Van Hensbergen m->rpos, m->rsize, m->rsize-m->rpos); 313bead27f0SEric Van Hensbergen err = p9_fd_read(m->client, m->rbuf + m->rpos, 3141b0a763bSEric Van Hensbergen m->rsize - m->rpos); 31551a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "mux %p got %d bytes\n", m, err); 3168a0dc95fSEric Van Hensbergen if (err == -EAGAIN) { 3178a0dc95fSEric Van Hensbergen clear_bit(Rworksched, &m->wsched); 3188a0dc95fSEric Van Hensbergen return; 3198a0dc95fSEric Van Hensbergen } 3208a0dc95fSEric Van Hensbergen 3218a0dc95fSEric Van Hensbergen if (err <= 0) 3228a0dc95fSEric Van Hensbergen goto error; 3238a0dc95fSEric Van Hensbergen 3248a0dc95fSEric Van Hensbergen m->rpos += err; 3251b0a763bSEric Van Hensbergen 3261b0a763bSEric Van Hensbergen if ((!m->req) && (m->rpos == m->rsize)) { /* header read in */ 3271b0a763bSEric Van Hensbergen u16 tag; 32851a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "got new header\n"); 3291b0a763bSEric Van Hensbergen 3301b0a763bSEric Van Hensbergen n = le32_to_cpu(*(__le32 *) m->rbuf); /* read packet size */ 331bead27f0SEric Van Hensbergen if (n >= m->client->msize) { 3328a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, 3338a0dc95fSEric Van Hensbergen "requested packet size too big: %d\n", n); 3348a0dc95fSEric Van Hensbergen err = -EIO; 3358a0dc95fSEric Van Hensbergen goto error; 3368a0dc95fSEric Van Hensbergen } 3378a0dc95fSEric Van Hensbergen 3381b0a763bSEric Van Hensbergen tag = le16_to_cpu(*(__le16 *) (m->rbuf+5)); /* read tag */ 33951a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, 34051a87c55SEric Van Hensbergen "mux %p pkt: size: %d bytes tag: %d\n", m, n, tag); 3418a0dc95fSEric Van Hensbergen 3421b0a763bSEric Van Hensbergen m->req = p9_tag_lookup(m->client, tag); 3431bab88b2SLatchesar Ionkov if (!m->req || (m->req->status != REQ_STATUS_SENT && 3441bab88b2SLatchesar Ionkov m->req->status != REQ_STATUS_FLSH)) { 3451b0a763bSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, "Unexpected packet tag %d\n", 3461b0a763bSEric Van Hensbergen tag); 3471b0a763bSEric Van Hensbergen err = -EIO; 3488a0dc95fSEric Van Hensbergen goto error; 3491b0a763bSEric Van Hensbergen } 3501b0a763bSEric Van Hensbergen 3511b0a763bSEric Van Hensbergen if (m->req->rc == NULL) { 3521b0a763bSEric Van Hensbergen m->req->rc = kmalloc(sizeof(struct p9_fcall) + 353eeff66efSAneesh Kumar K.V m->client->msize, GFP_NOFS); 3541b0a763bSEric Van Hensbergen if (!m->req->rc) { 3551b0a763bSEric Van Hensbergen m->req = NULL; 3561b0a763bSEric Van Hensbergen err = -ENOMEM; 3571b0a763bSEric Van Hensbergen goto error; 3581b0a763bSEric Van Hensbergen } 3591b0a763bSEric Van Hensbergen } 3601b0a763bSEric Van Hensbergen m->rbuf = (char *)m->req->rc + sizeof(struct p9_fcall); 3611b0a763bSEric Van Hensbergen memcpy(m->rbuf, m->tmp_buf, m->rsize); 3621b0a763bSEric Van Hensbergen m->rsize = n; 3631b0a763bSEric Van Hensbergen } 3641b0a763bSEric Van Hensbergen 3651b0a763bSEric Van Hensbergen /* not an else because some packets (like clunk) have no payload */ 3661b0a763bSEric Van Hensbergen if ((m->req) && (m->rpos == m->rsize)) { /* packet is read in */ 36751a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "got new packet\n"); 3687eb923b8SEric Van Hensbergen spin_lock(&m->client->lock); 3691bab88b2SLatchesar Ionkov if (m->req->status != REQ_STATUS_ERROR) 3701bab88b2SLatchesar Ionkov m->req->status = REQ_STATUS_RCVD; 37191b8534fSEric Van Hensbergen list_del(&m->req->req_list); 3727eb923b8SEric Van Hensbergen spin_unlock(&m->client->lock); 37391b8534fSEric Van Hensbergen p9_client_cb(m->client, m->req); 3748a0dc95fSEric Van Hensbergen m->rbuf = NULL; 3758a0dc95fSEric Van Hensbergen m->rpos = 0; 3761b0a763bSEric Van Hensbergen m->rsize = 0; 3771b0a763bSEric Van Hensbergen m->req = NULL; 3788a0dc95fSEric Van Hensbergen } 3798a0dc95fSEric Van Hensbergen 3808a0dc95fSEric Van Hensbergen if (!list_empty(&m->req_list)) { 3818a0dc95fSEric Van Hensbergen if (test_and_clear_bit(Rpending, &m->wsched)) 3828a0dc95fSEric Van Hensbergen n = POLLIN; 3838a0dc95fSEric Van Hensbergen else 3848b81ef58SEric Van Hensbergen n = p9_fd_poll(m->client, NULL); 3858a0dc95fSEric Van Hensbergen 3868a0dc95fSEric Van Hensbergen if (n & POLLIN) { 38751a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "sched read work %p\n", m); 38861edeeedSTejun Heo schedule_work(&m->rq); 3898a0dc95fSEric Van Hensbergen } else 3908a0dc95fSEric Van Hensbergen clear_bit(Rworksched, &m->wsched); 3918a0dc95fSEric Van Hensbergen } else 3928a0dc95fSEric Van Hensbergen clear_bit(Rworksched, &m->wsched); 3938a0dc95fSEric Van Hensbergen 3948a0dc95fSEric Van Hensbergen return; 3958a0dc95fSEric Van Hensbergen error: 3968a0dc95fSEric Van Hensbergen p9_conn_cancel(m, err); 3978a0dc95fSEric Van Hensbergen clear_bit(Rworksched, &m->wsched); 3988a0dc95fSEric Van Hensbergen } 3998a0dc95fSEric Van Hensbergen 4008a0dc95fSEric Van Hensbergen /** 4015503ac56SEric Van Hensbergen * p9_fd_write - write to a socket 4025503ac56SEric Van Hensbergen * @client: client instance 4035503ac56SEric Van Hensbergen * @v: buffer to send data from 4045503ac56SEric Van Hensbergen * @len: size of send buffer 4055503ac56SEric Van Hensbergen * 4065503ac56SEric Van Hensbergen */ 4075503ac56SEric Van Hensbergen 4085503ac56SEric Van Hensbergen static int p9_fd_write(struct p9_client *client, void *v, int len) 4095503ac56SEric Van Hensbergen { 4105503ac56SEric Van Hensbergen int ret; 4115503ac56SEric Van Hensbergen mm_segment_t oldfs; 4125503ac56SEric Van Hensbergen struct p9_trans_fd *ts = NULL; 4135503ac56SEric Van Hensbergen 4145503ac56SEric Van Hensbergen if (client && client->status != Disconnected) 4155503ac56SEric Van Hensbergen ts = client->trans; 4165503ac56SEric Van Hensbergen 4175503ac56SEric Van Hensbergen if (!ts) 4185503ac56SEric Van Hensbergen return -EREMOTEIO; 4195503ac56SEric Van Hensbergen 4205503ac56SEric Van Hensbergen if (!(ts->wr->f_flags & O_NONBLOCK)) 4215503ac56SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, "blocking write ...\n"); 4225503ac56SEric Van Hensbergen 4235503ac56SEric Van Hensbergen oldfs = get_fs(); 4245503ac56SEric Van Hensbergen set_fs(get_ds()); 4255503ac56SEric Van Hensbergen /* The cast to a user pointer is valid due to the set_fs() */ 426e3db6cb4SHannes Eder ret = vfs_write(ts->wr, (__force void __user *)v, len, &ts->wr->f_pos); 4275503ac56SEric Van Hensbergen set_fs(oldfs); 4285503ac56SEric Van Hensbergen 4295503ac56SEric Van Hensbergen if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) 4305503ac56SEric Van Hensbergen client->status = Disconnected; 4315503ac56SEric Van Hensbergen return ret; 4325503ac56SEric Van Hensbergen } 4335503ac56SEric Van Hensbergen 4345503ac56SEric Van Hensbergen /** 4355503ac56SEric Van Hensbergen * p9_write_work - called when a transport can send some data 4365503ac56SEric Van Hensbergen * @work: container for work to be done 4375503ac56SEric Van Hensbergen * 4385503ac56SEric Van Hensbergen */ 4395503ac56SEric Van Hensbergen 4405503ac56SEric Van Hensbergen static void p9_write_work(struct work_struct *work) 4415503ac56SEric Van Hensbergen { 4425503ac56SEric Van Hensbergen int n, err; 4435503ac56SEric Van Hensbergen struct p9_conn *m; 444673d62cdSEric Van Hensbergen struct p9_req_t *req; 4455503ac56SEric Van Hensbergen 4465503ac56SEric Van Hensbergen m = container_of(work, struct p9_conn, wq); 4475503ac56SEric Van Hensbergen 4485503ac56SEric Van Hensbergen if (m->err < 0) { 4495503ac56SEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 4505503ac56SEric Van Hensbergen return; 4515503ac56SEric Van Hensbergen } 4525503ac56SEric Van Hensbergen 4535503ac56SEric Van Hensbergen if (!m->wsize) { 4545503ac56SEric Van Hensbergen if (list_empty(&m->unsent_req_list)) { 4555503ac56SEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 4565503ac56SEric Van Hensbergen return; 4575503ac56SEric Van Hensbergen } 4585503ac56SEric Van Hensbergen 459673d62cdSEric Van Hensbergen spin_lock(&m->client->lock); 460673d62cdSEric Van Hensbergen req = list_entry(m->unsent_req_list.next, struct p9_req_t, 4615503ac56SEric Van Hensbergen req_list); 462673d62cdSEric Van Hensbergen req->status = REQ_STATUS_SENT; 4631bab88b2SLatchesar Ionkov P9_DPRINTK(P9_DEBUG_TRANS, "move req %p\n", req); 4645503ac56SEric Van Hensbergen list_move_tail(&req->req_list, &m->req_list); 4655503ac56SEric Van Hensbergen 466673d62cdSEric Van Hensbergen m->wbuf = req->tc->sdata; 467673d62cdSEric Van Hensbergen m->wsize = req->tc->size; 4685503ac56SEric Van Hensbergen m->wpos = 0; 469673d62cdSEric Van Hensbergen spin_unlock(&m->client->lock); 4705503ac56SEric Van Hensbergen } 4715503ac56SEric Van Hensbergen 47251a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "mux %p pos %d size %d\n", m, m->wpos, 4735503ac56SEric Van Hensbergen m->wsize); 4745503ac56SEric Van Hensbergen clear_bit(Wpending, &m->wsched); 4755503ac56SEric Van Hensbergen err = p9_fd_write(m->client, m->wbuf + m->wpos, m->wsize - m->wpos); 47651a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "mux %p sent %d bytes\n", m, err); 4775503ac56SEric Van Hensbergen if (err == -EAGAIN) { 4785503ac56SEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 4795503ac56SEric Van Hensbergen return; 4805503ac56SEric Van Hensbergen } 4815503ac56SEric Van Hensbergen 4825503ac56SEric Van Hensbergen if (err < 0) 4835503ac56SEric Van Hensbergen goto error; 4845503ac56SEric Van Hensbergen else if (err == 0) { 4855503ac56SEric Van Hensbergen err = -EREMOTEIO; 4865503ac56SEric Van Hensbergen goto error; 4875503ac56SEric Van Hensbergen } 4885503ac56SEric Van Hensbergen 4895503ac56SEric Van Hensbergen m->wpos += err; 4905503ac56SEric Van Hensbergen if (m->wpos == m->wsize) 4915503ac56SEric Van Hensbergen m->wpos = m->wsize = 0; 4925503ac56SEric Van Hensbergen 4935503ac56SEric Van Hensbergen if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) { 4945503ac56SEric Van Hensbergen if (test_and_clear_bit(Wpending, &m->wsched)) 4955503ac56SEric Van Hensbergen n = POLLOUT; 4965503ac56SEric Van Hensbergen else 4975503ac56SEric Van Hensbergen n = p9_fd_poll(m->client, NULL); 4985503ac56SEric Van Hensbergen 4995503ac56SEric Van Hensbergen if (n & POLLOUT) { 50051a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "sched write work %p\n", m); 50161edeeedSTejun Heo schedule_work(&m->wq); 5025503ac56SEric Van Hensbergen } else 5035503ac56SEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 5045503ac56SEric Van Hensbergen } else 5055503ac56SEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 5065503ac56SEric Van Hensbergen 5075503ac56SEric Van Hensbergen return; 5085503ac56SEric Van Hensbergen 5095503ac56SEric Van Hensbergen error: 5105503ac56SEric Van Hensbergen p9_conn_cancel(m, err); 5115503ac56SEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 5125503ac56SEric Van Hensbergen } 5135503ac56SEric Van Hensbergen 5145503ac56SEric Van Hensbergen static int p9_pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) 5155503ac56SEric Van Hensbergen { 5165503ac56SEric Van Hensbergen struct p9_poll_wait *pwait = 5175503ac56SEric Van Hensbergen container_of(wait, struct p9_poll_wait, wait); 5185503ac56SEric Van Hensbergen struct p9_conn *m = pwait->conn; 5195503ac56SEric Van Hensbergen unsigned long flags; 5205503ac56SEric Van Hensbergen 5215503ac56SEric Van Hensbergen spin_lock_irqsave(&p9_poll_lock, flags); 5225503ac56SEric Van Hensbergen if (list_empty(&m->poll_pending_link)) 5235503ac56SEric Van Hensbergen list_add_tail(&m->poll_pending_link, &p9_poll_pending_list); 5245503ac56SEric Van Hensbergen spin_unlock_irqrestore(&p9_poll_lock, flags); 5255503ac56SEric Van Hensbergen 526aa70c585STejun Heo schedule_work(&p9_poll_work); 527aa70c585STejun Heo return 1; 5285503ac56SEric Van Hensbergen } 5295503ac56SEric Van Hensbergen 5305503ac56SEric Van Hensbergen /** 5315503ac56SEric Van Hensbergen * p9_pollwait - add poll task to the wait queue 5325503ac56SEric Van Hensbergen * @filp: file pointer being polled 5335503ac56SEric Van Hensbergen * @wait_address: wait_q to block on 5345503ac56SEric Van Hensbergen * @p: poll state 5355503ac56SEric Van Hensbergen * 5365503ac56SEric Van Hensbergen * called by files poll operation to add v9fs-poll task to files wait queue 5375503ac56SEric Van Hensbergen */ 5385503ac56SEric Van Hensbergen 5395503ac56SEric Van Hensbergen static void 5405503ac56SEric Van Hensbergen p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p) 5415503ac56SEric Van Hensbergen { 5425503ac56SEric Van Hensbergen struct p9_conn *m = container_of(p, struct p9_conn, pt); 5435503ac56SEric Van Hensbergen struct p9_poll_wait *pwait = NULL; 5445503ac56SEric Van Hensbergen int i; 5455503ac56SEric Van Hensbergen 5465503ac56SEric Van Hensbergen for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { 5475503ac56SEric Van Hensbergen if (m->poll_wait[i].wait_addr == NULL) { 5485503ac56SEric Van Hensbergen pwait = &m->poll_wait[i]; 5495503ac56SEric Van Hensbergen break; 5505503ac56SEric Van Hensbergen } 5515503ac56SEric Van Hensbergen } 5525503ac56SEric Van Hensbergen 5535503ac56SEric Van Hensbergen if (!pwait) { 5545503ac56SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n"); 5555503ac56SEric Van Hensbergen return; 5565503ac56SEric Van Hensbergen } 5575503ac56SEric Van Hensbergen 5585503ac56SEric Van Hensbergen pwait->conn = m; 5595503ac56SEric Van Hensbergen pwait->wait_addr = wait_address; 5605503ac56SEric Van Hensbergen init_waitqueue_func_entry(&pwait->wait, p9_pollwake); 5615503ac56SEric Van Hensbergen add_wait_queue(wait_address, &pwait->wait); 5625503ac56SEric Van Hensbergen } 5635503ac56SEric Van Hensbergen 5645503ac56SEric Van Hensbergen /** 5655503ac56SEric Van Hensbergen * p9_conn_create - allocate and initialize the per-session mux data 5665503ac56SEric Van Hensbergen * @client: client instance 5675503ac56SEric Van Hensbergen * 5685503ac56SEric Van Hensbergen * Note: Creates the polling task if this is the first session. 5695503ac56SEric Van Hensbergen */ 5705503ac56SEric Van Hensbergen 5715503ac56SEric Van Hensbergen static struct p9_conn *p9_conn_create(struct p9_client *client) 5725503ac56SEric Van Hensbergen { 57395820a36STejun Heo int n; 5745503ac56SEric Van Hensbergen struct p9_conn *m; 5755503ac56SEric Van Hensbergen 57651a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "client %p msize %d\n", client, 57751a87c55SEric Van Hensbergen client->msize); 5785503ac56SEric Van Hensbergen m = kzalloc(sizeof(struct p9_conn), GFP_KERNEL); 5795503ac56SEric Van Hensbergen if (!m) 5805503ac56SEric Van Hensbergen return ERR_PTR(-ENOMEM); 5815503ac56SEric Van Hensbergen 5825503ac56SEric Van Hensbergen INIT_LIST_HEAD(&m->mux_list); 5835503ac56SEric Van Hensbergen m->client = client; 5845503ac56SEric Van Hensbergen 5855503ac56SEric Van Hensbergen INIT_LIST_HEAD(&m->req_list); 5865503ac56SEric Van Hensbergen INIT_LIST_HEAD(&m->unsent_req_list); 5875503ac56SEric Van Hensbergen INIT_WORK(&m->rq, p9_read_work); 5885503ac56SEric Van Hensbergen INIT_WORK(&m->wq, p9_write_work); 5895503ac56SEric Van Hensbergen INIT_LIST_HEAD(&m->poll_pending_link); 5905503ac56SEric Van Hensbergen init_poll_funcptr(&m->pt, p9_pollwait); 5915503ac56SEric Van Hensbergen 5925503ac56SEric Van Hensbergen n = p9_fd_poll(client, &m->pt); 5935503ac56SEric Van Hensbergen if (n & POLLIN) { 59451a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can read\n", m); 5955503ac56SEric Van Hensbergen set_bit(Rpending, &m->wsched); 5965503ac56SEric Van Hensbergen } 5975503ac56SEric Van Hensbergen 5985503ac56SEric Van Hensbergen if (n & POLLOUT) { 59951a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can write\n", m); 6005503ac56SEric Van Hensbergen set_bit(Wpending, &m->wsched); 6015503ac56SEric Van Hensbergen } 6025503ac56SEric Van Hensbergen 6035503ac56SEric Van Hensbergen return m; 6045503ac56SEric Van Hensbergen } 6055503ac56SEric Van Hensbergen 6065503ac56SEric Van Hensbergen /** 6075503ac56SEric Van Hensbergen * p9_poll_mux - polls a mux and schedules read or write works if necessary 6085503ac56SEric Van Hensbergen * @m: connection to poll 6095503ac56SEric Van Hensbergen * 6105503ac56SEric Van Hensbergen */ 6115503ac56SEric Van Hensbergen 6125503ac56SEric Van Hensbergen static void p9_poll_mux(struct p9_conn *m) 6135503ac56SEric Van Hensbergen { 6145503ac56SEric Van Hensbergen int n; 6155503ac56SEric Van Hensbergen 6165503ac56SEric Van Hensbergen if (m->err < 0) 6175503ac56SEric Van Hensbergen return; 6185503ac56SEric Van Hensbergen 6195503ac56SEric Van Hensbergen n = p9_fd_poll(m->client, NULL); 6205503ac56SEric Van Hensbergen if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) { 62151a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "error mux %p err %d\n", m, n); 6225503ac56SEric Van Hensbergen if (n >= 0) 6235503ac56SEric Van Hensbergen n = -ECONNRESET; 6245503ac56SEric Van Hensbergen p9_conn_cancel(m, n); 6255503ac56SEric Van Hensbergen } 6265503ac56SEric Van Hensbergen 6275503ac56SEric Van Hensbergen if (n & POLLIN) { 6285503ac56SEric Van Hensbergen set_bit(Rpending, &m->wsched); 62951a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can read\n", m); 6305503ac56SEric Van Hensbergen if (!test_and_set_bit(Rworksched, &m->wsched)) { 63151a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "sched read work %p\n", m); 63261edeeedSTejun Heo schedule_work(&m->rq); 6335503ac56SEric Van Hensbergen } 6345503ac56SEric Van Hensbergen } 6355503ac56SEric Van Hensbergen 6365503ac56SEric Van Hensbergen if (n & POLLOUT) { 6375503ac56SEric Van Hensbergen set_bit(Wpending, &m->wsched); 63851a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can write\n", m); 639f64f9e71SJoe Perches if ((m->wsize || !list_empty(&m->unsent_req_list)) && 640f64f9e71SJoe Perches !test_and_set_bit(Wworksched, &m->wsched)) { 64151a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "sched write work %p\n", m); 64261edeeedSTejun Heo schedule_work(&m->wq); 6435503ac56SEric Van Hensbergen } 6445503ac56SEric Van Hensbergen } 6455503ac56SEric Van Hensbergen } 6465503ac56SEric Van Hensbergen 6475503ac56SEric Van Hensbergen /** 64891b8534fSEric Van Hensbergen * p9_fd_request - send 9P request 6498a0dc95fSEric Van Hensbergen * The function can sleep until the request is scheduled for sending. 6508a0dc95fSEric Van Hensbergen * The function can be interrupted. Return from the function is not 65191b8534fSEric Van Hensbergen * a guarantee that the request is sent successfully. 6528a0dc95fSEric Van Hensbergen * 65391b8534fSEric Van Hensbergen * @client: client instance 65491b8534fSEric Van Hensbergen * @req: request to be sent 655ee443996SEric Van Hensbergen * 6568a0dc95fSEric Van Hensbergen */ 657ee443996SEric Van Hensbergen 65891b8534fSEric Van Hensbergen static int p9_fd_request(struct p9_client *client, struct p9_req_t *req) 6598a0dc95fSEric Van Hensbergen { 6608a0dc95fSEric Van Hensbergen int n; 66191b8534fSEric Van Hensbergen struct p9_trans_fd *ts = client->trans; 66291b8534fSEric Van Hensbergen struct p9_conn *m = ts->conn; 6638a0dc95fSEric Van Hensbergen 66451a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "mux %p task %p tcall %p id %d\n", m, 66551a87c55SEric Van Hensbergen current, req->tc, req->tc->id); 6668a0dc95fSEric Van Hensbergen if (m->err < 0) 66791b8534fSEric Van Hensbergen return m->err; 6688a0dc95fSEric Van Hensbergen 66991b8534fSEric Van Hensbergen spin_lock(&client->lock); 6707eb923b8SEric Van Hensbergen req->status = REQ_STATUS_UNSENT; 6718a0dc95fSEric Van Hensbergen list_add_tail(&req->req_list, &m->unsent_req_list); 67291b8534fSEric Van Hensbergen spin_unlock(&client->lock); 6738a0dc95fSEric Van Hensbergen 6748a0dc95fSEric Van Hensbergen if (test_and_clear_bit(Wpending, &m->wsched)) 6758a0dc95fSEric Van Hensbergen n = POLLOUT; 6768a0dc95fSEric Van Hensbergen else 6778b81ef58SEric Van Hensbergen n = p9_fd_poll(m->client, NULL); 6788a0dc95fSEric Van Hensbergen 6798a0dc95fSEric Van Hensbergen if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched)) 68061edeeedSTejun Heo schedule_work(&m->wq); 6818a0dc95fSEric Van Hensbergen 68291b8534fSEric Van Hensbergen return 0; 6838a0dc95fSEric Van Hensbergen } 6848a0dc95fSEric Van Hensbergen 68591b8534fSEric Van Hensbergen static int p9_fd_cancel(struct p9_client *client, struct p9_req_t *req) 6868a0dc95fSEric Van Hensbergen { 6877eb923b8SEric Van Hensbergen int ret = 1; 6888a0dc95fSEric Van Hensbergen 6890b15a3a5SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "client %p req %p\n", client, req); 6908a0dc95fSEric Van Hensbergen 69191b8534fSEric Van Hensbergen spin_lock(&client->lock); 69291b8534fSEric Van Hensbergen 69391b8534fSEric Van Hensbergen if (req->status == REQ_STATUS_UNSENT) { 6941bab88b2SLatchesar Ionkov list_del(&req->req_list); 695673d62cdSEric Van Hensbergen req->status = REQ_STATUS_FLSHD; 6967eb923b8SEric Van Hensbergen ret = 0; 6971bab88b2SLatchesar Ionkov } else if (req->status == REQ_STATUS_SENT) 6981bab88b2SLatchesar Ionkov req->status = REQ_STATUS_FLSH; 6998a0dc95fSEric Van Hensbergen 7007eb923b8SEric Van Hensbergen spin_unlock(&client->lock); 7017eb923b8SEric Van Hensbergen 7027eb923b8SEric Van Hensbergen return ret; 7038a0dc95fSEric Van Hensbergen } 7048a0dc95fSEric Van Hensbergen 7058a0dc95fSEric Van Hensbergen /** 7060e15597eSAbhishek Kulkarni * parse_opts - parse mount options into p9_fd_opts structure 7070e15597eSAbhishek Kulkarni * @params: options string passed from mount 7080e15597eSAbhishek Kulkarni * @opts: fd transport-specific structure to parse options into 709a80d923eSEric Van Hensbergen * 710bb8ffdfcSEric Van Hensbergen * Returns 0 upon success, -ERRNO upon failure 711a80d923eSEric Van Hensbergen */ 712a80d923eSEric Van Hensbergen 713bb8ffdfcSEric Van Hensbergen static int parse_opts(char *params, struct p9_fd_opts *opts) 714bd238fb4SLatchesar Ionkov { 715a80d923eSEric Van Hensbergen char *p; 716a80d923eSEric Van Hensbergen substring_t args[MAX_OPT_ARGS]; 717a80d923eSEric Van Hensbergen int option; 718d8c8a9e3SEric Van Hensbergen char *options, *tmp_options; 719a80d923eSEric Van Hensbergen int ret; 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) { 730bb8ffdfcSEric Van Hensbergen P9_DPRINTK(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) { 745a80d923eSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, 746a80d923eSEric Van Hensbergen "integer field, but no integer?\n"); 747bb8ffdfcSEric Van Hensbergen ret = r; 748a80d923eSEric Van Hensbergen continue; 749a80d923eSEric Van Hensbergen } 75015da4b16SAbhishek Kulkarni } 751a80d923eSEric Van Hensbergen switch (token) { 752a80d923eSEric Van Hensbergen case Opt_port: 753a80d923eSEric Van Hensbergen opts->port = option; 754a80d923eSEric Van Hensbergen break; 755a80d923eSEric Van Hensbergen case Opt_rfdno: 756a80d923eSEric Van Hensbergen opts->rfd = option; 757a80d923eSEric Van Hensbergen break; 758a80d923eSEric Van Hensbergen case Opt_wfdno: 759a80d923eSEric Van Hensbergen opts->wfd = option; 760a80d923eSEric Van Hensbergen break; 761a80d923eSEric Van Hensbergen default: 762a80d923eSEric Van Hensbergen continue; 763a80d923eSEric Van Hensbergen } 764a80d923eSEric Van Hensbergen } 765d8c8a9e3SEric Van Hensbergen 766d8c8a9e3SEric Van Hensbergen kfree(tmp_options); 767bb8ffdfcSEric Van Hensbergen return 0; 768bd238fb4SLatchesar Ionkov } 769bd238fb4SLatchesar Ionkov 7708b81ef58SEric Van Hensbergen static int p9_fd_open(struct p9_client *client, int rfd, int wfd) 771bd238fb4SLatchesar Ionkov { 772bd238fb4SLatchesar Ionkov struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd), 773bd238fb4SLatchesar Ionkov GFP_KERNEL); 774bd238fb4SLatchesar Ionkov if (!ts) 775bd238fb4SLatchesar Ionkov return -ENOMEM; 776bd238fb4SLatchesar Ionkov 777bd238fb4SLatchesar Ionkov ts->rd = fget(rfd); 778bd238fb4SLatchesar Ionkov ts->wr = fget(wfd); 779bd238fb4SLatchesar Ionkov if (!ts->rd || !ts->wr) { 780bd238fb4SLatchesar Ionkov if (ts->rd) 781bd238fb4SLatchesar Ionkov fput(ts->rd); 782bd238fb4SLatchesar Ionkov if (ts->wr) 783bd238fb4SLatchesar Ionkov fput(ts->wr); 784bd238fb4SLatchesar Ionkov kfree(ts); 785bd238fb4SLatchesar Ionkov return -EIO; 786bd238fb4SLatchesar Ionkov } 787bd238fb4SLatchesar Ionkov 7888b81ef58SEric Van Hensbergen client->trans = ts; 7898b81ef58SEric Van Hensbergen client->status = Connected; 790bd238fb4SLatchesar Ionkov 791bd238fb4SLatchesar Ionkov return 0; 792bd238fb4SLatchesar Ionkov } 793bd238fb4SLatchesar Ionkov 7948b81ef58SEric Van Hensbergen static int p9_socket_open(struct p9_client *client, struct socket *csocket) 795a80d923eSEric Van Hensbergen { 7966b18662eSAl Viro struct p9_trans_fd *p; 7976b18662eSAl Viro int ret, fd; 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; 804a677a039SUlrich Drepper fd = sock_map_fd(csocket, 0); 805a80d923eSEric Van Hensbergen if (fd < 0) { 806a80d923eSEric Van Hensbergen P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n"); 8076b18662eSAl Viro sock_release(csocket); 8086b18662eSAl Viro kfree(p); 809a80d923eSEric Van Hensbergen return fd; 810a80d923eSEric Van Hensbergen } 811a80d923eSEric Van Hensbergen 8126b18662eSAl Viro get_file(csocket->file); 8136b18662eSAl Viro get_file(csocket->file); 8146b18662eSAl Viro p->wr = p->rd = csocket->file; 8156b18662eSAl Viro client->trans = p; 8166b18662eSAl Viro client->status = Connected; 8176b18662eSAl Viro 8186b18662eSAl Viro sys_close(fd); /* still racy */ 8196b18662eSAl Viro 8206b18662eSAl Viro p->rd->f_flags |= O_NONBLOCK; 8216b18662eSAl Viro 8226b18662eSAl Viro p->conn = p9_conn_create(client); 8236b18662eSAl Viro if (IS_ERR(p->conn)) { 8246b18662eSAl Viro ret = PTR_ERR(p->conn); 8256b18662eSAl Viro p->conn = NULL; 8266b18662eSAl Viro kfree(p); 8276b18662eSAl Viro sockfd_put(csocket); 828a80d923eSEric Van Hensbergen sockfd_put(csocket); 829a80d923eSEric Van Hensbergen return ret; 830a80d923eSEric Van Hensbergen } 831a80d923eSEric Van Hensbergen return 0; 832a80d923eSEric Van Hensbergen } 833a80d923eSEric Van Hensbergen 834bd238fb4SLatchesar Ionkov /** 8355503ac56SEric Van Hensbergen * p9_mux_destroy - cancels all pending requests and frees mux resources 8365503ac56SEric Van Hensbergen * @m: mux to destroy 837bd238fb4SLatchesar Ionkov * 838bd238fb4SLatchesar Ionkov */ 839ee443996SEric Van Hensbergen 8405503ac56SEric Van Hensbergen static void p9_conn_destroy(struct p9_conn *m) 841bd238fb4SLatchesar Ionkov { 84251a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "mux %p prev %p next %p\n", m, 8435503ac56SEric Van Hensbergen m->mux_list.prev, m->mux_list.next); 844bd238fb4SLatchesar Ionkov 8455503ac56SEric Van Hensbergen p9_mux_poll_stop(m); 8465503ac56SEric Van Hensbergen cancel_work_sync(&m->rq); 8475503ac56SEric Van Hensbergen cancel_work_sync(&m->wq); 848bd238fb4SLatchesar Ionkov 8495503ac56SEric Van Hensbergen p9_conn_cancel(m, -ECONNRESET); 850bd238fb4SLatchesar Ionkov 8515503ac56SEric Van Hensbergen m->client = NULL; 8525503ac56SEric Van Hensbergen kfree(m); 853bd238fb4SLatchesar Ionkov } 854bd238fb4SLatchesar Ionkov 855bd238fb4SLatchesar Ionkov /** 8568b81ef58SEric Van Hensbergen * p9_fd_close - shutdown file descriptor transport 8578b81ef58SEric Van Hensbergen * @client: client instance 858bd238fb4SLatchesar Ionkov * 859bd238fb4SLatchesar Ionkov */ 860ee443996SEric Van Hensbergen 8618b81ef58SEric Van Hensbergen static void p9_fd_close(struct p9_client *client) 862bd238fb4SLatchesar Ionkov { 863bd238fb4SLatchesar Ionkov struct p9_trans_fd *ts; 864bd238fb4SLatchesar Ionkov 8658b81ef58SEric Van Hensbergen if (!client) 866bd238fb4SLatchesar Ionkov return; 867bd238fb4SLatchesar Ionkov 8688b81ef58SEric Van Hensbergen ts = client->trans; 869bd238fb4SLatchesar Ionkov if (!ts) 870bd238fb4SLatchesar Ionkov return; 871bd238fb4SLatchesar Ionkov 8728b81ef58SEric Van Hensbergen client->status = Disconnected; 8738b81ef58SEric Van Hensbergen 8748a0dc95fSEric Van Hensbergen p9_conn_destroy(ts->conn); 8758a0dc95fSEric Van Hensbergen 876bd238fb4SLatchesar Ionkov if (ts->rd) 877bd238fb4SLatchesar Ionkov fput(ts->rd); 878bd238fb4SLatchesar Ionkov if (ts->wr) 879bd238fb4SLatchesar Ionkov fput(ts->wr); 8808b81ef58SEric Van Hensbergen 881bd238fb4SLatchesar Ionkov kfree(ts); 882bd238fb4SLatchesar Ionkov } 883bd238fb4SLatchesar Ionkov 884887b3eceSEric Van Hensbergen /* 885887b3eceSEric Van Hensbergen * stolen from NFS - maybe should be made a generic function? 886887b3eceSEric Van Hensbergen */ 887887b3eceSEric Van Hensbergen static inline int valid_ipaddr4(const char *buf) 888887b3eceSEric Van Hensbergen { 889887b3eceSEric Van Hensbergen int rc, count, in[4]; 890887b3eceSEric Van Hensbergen 891887b3eceSEric Van Hensbergen rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]); 892887b3eceSEric Van Hensbergen if (rc != 4) 893887b3eceSEric Van Hensbergen return -EINVAL; 894887b3eceSEric Van Hensbergen for (count = 0; count < 4; count++) { 895887b3eceSEric Van Hensbergen if (in[count] > 255) 896887b3eceSEric Van Hensbergen return -EINVAL; 897887b3eceSEric Van Hensbergen } 898887b3eceSEric Van Hensbergen return 0; 899887b3eceSEric Van Hensbergen } 900887b3eceSEric Van Hensbergen 9018b81ef58SEric Van Hensbergen static int 9028b81ef58SEric Van Hensbergen p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args) 903a80d923eSEric Van Hensbergen { 904a80d923eSEric Van Hensbergen int err; 905a80d923eSEric Van Hensbergen struct socket *csocket; 906a80d923eSEric Van Hensbergen struct sockaddr_in sin_server; 907a80d923eSEric Van Hensbergen struct p9_fd_opts opts; 908a80d923eSEric Van Hensbergen 909bb8ffdfcSEric Van Hensbergen err = parse_opts(args, &opts); 910bb8ffdfcSEric Van Hensbergen if (err < 0) 9118b81ef58SEric Van Hensbergen return err; 912a80d923eSEric Van Hensbergen 913887b3eceSEric Van Hensbergen if (valid_ipaddr4(addr) < 0) 9148b81ef58SEric Van Hensbergen return -EINVAL; 915887b3eceSEric Van Hensbergen 916a80d923eSEric Van Hensbergen csocket = NULL; 917a80d923eSEric Van Hensbergen 918a80d923eSEric Van Hensbergen sin_server.sin_family = AF_INET; 919a80d923eSEric Van Hensbergen sin_server.sin_addr.s_addr = in_aton(addr); 920a80d923eSEric Van Hensbergen sin_server.sin_port = htons(opts.port); 9216b18662eSAl Viro err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket); 922a80d923eSEric Van Hensbergen 9236b18662eSAl Viro if (err) { 924a80d923eSEric Van Hensbergen P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n"); 9256b18662eSAl Viro return err; 926a80d923eSEric Van Hensbergen } 927a80d923eSEric Van Hensbergen 928a80d923eSEric Van Hensbergen err = csocket->ops->connect(csocket, 929a80d923eSEric Van Hensbergen (struct sockaddr *)&sin_server, 930a80d923eSEric Van Hensbergen sizeof(struct sockaddr_in), 0); 931a80d923eSEric Van Hensbergen if (err < 0) { 932a80d923eSEric Van Hensbergen P9_EPRINTK(KERN_ERR, 933a80d923eSEric Van Hensbergen "p9_trans_tcp: problem connecting socket to %s\n", 934a80d923eSEric Van Hensbergen addr); 935a80d923eSEric Van Hensbergen sock_release(csocket); 9368b81ef58SEric Van Hensbergen return err; 937a80d923eSEric Van Hensbergen } 938a80d923eSEric Van Hensbergen 9396b18662eSAl Viro return p9_socket_open(client, csocket); 9406b18662eSAl Viro } 9416b18662eSAl Viro 9428b81ef58SEric Van Hensbergen static int 9438b81ef58SEric Van Hensbergen p9_fd_create_unix(struct p9_client *client, const char *addr, char *args) 944a80d923eSEric Van Hensbergen { 945a80d923eSEric Van Hensbergen int err; 946a80d923eSEric Van Hensbergen struct socket *csocket; 947a80d923eSEric Van Hensbergen struct sockaddr_un sun_server; 948a80d923eSEric Van Hensbergen 949a80d923eSEric Van Hensbergen csocket = NULL; 950a80d923eSEric Van Hensbergen 951cff6b8a9SDan Carpenter if (strlen(addr) >= UNIX_PATH_MAX) { 952a80d923eSEric Van Hensbergen P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n", 953a80d923eSEric Van Hensbergen addr); 9546b18662eSAl Viro return -ENAMETOOLONG; 955a80d923eSEric Van Hensbergen } 956a80d923eSEric Van Hensbergen 957a80d923eSEric Van Hensbergen sun_server.sun_family = PF_UNIX; 958a80d923eSEric Van Hensbergen strcpy(sun_server.sun_path, addr); 9596b18662eSAl Viro err = sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket); 9606b18662eSAl Viro if (err < 0) { 9616b18662eSAl Viro P9_EPRINTK(KERN_ERR, "p9_trans_unix: problem creating socket\n"); 9626b18662eSAl Viro return err; 9636b18662eSAl Viro } 964a80d923eSEric Van Hensbergen err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server, 965a80d923eSEric Van Hensbergen sizeof(struct sockaddr_un) - 1, 0); 966a80d923eSEric Van Hensbergen if (err < 0) { 967a80d923eSEric Van Hensbergen P9_EPRINTK(KERN_ERR, 968a80d923eSEric Van Hensbergen "p9_trans_unix: problem connecting socket: %s: %d\n", 969a80d923eSEric Van Hensbergen 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) { 987a80d923eSEric Van Hensbergen printk(KERN_ERR "v9fs: 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 105451a87c55SEric Van Hensbergen P9_DPRINTK(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 107051a87c55SEric Van Hensbergen P9_DPRINTK(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 { 1084aa70c585STejun Heo flush_work_sync(&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