1bd238fb4SLatchesar Ionkov /* 2bd238fb4SLatchesar Ionkov * linux/fs/9p/trans_fd.c 3bd238fb4SLatchesar Ionkov * 4bd238fb4SLatchesar Ionkov * Fd transport layer. Includes deprecated socket layer. 5bd238fb4SLatchesar Ionkov * 6bd238fb4SLatchesar Ionkov * Copyright (C) 2006 by Russ Cox <rsc@swtch.com> 7bd238fb4SLatchesar Ionkov * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net> 88a0dc95fSEric Van Hensbergen * Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com> 9bd238fb4SLatchesar Ionkov * Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com> 10bd238fb4SLatchesar Ionkov * 11bd238fb4SLatchesar Ionkov * This program is free software; you can redistribute it and/or modify 12bd238fb4SLatchesar Ionkov * it under the terms of the GNU General Public License version 2 13bd238fb4SLatchesar Ionkov * as published by the Free Software Foundation. 14bd238fb4SLatchesar Ionkov * 15bd238fb4SLatchesar Ionkov * This program is distributed in the hope that it will be useful, 16bd238fb4SLatchesar Ionkov * but WITHOUT ANY WARRANTY; without even the implied warranty of 17bd238fb4SLatchesar Ionkov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18bd238fb4SLatchesar Ionkov * GNU General Public License for more details. 19bd238fb4SLatchesar Ionkov * 20bd238fb4SLatchesar Ionkov * You should have received a copy of the GNU General Public License 21bd238fb4SLatchesar Ionkov * along with this program; if not, write to: 22bd238fb4SLatchesar Ionkov * Free Software Foundation 23bd238fb4SLatchesar Ionkov * 51 Franklin Street, Fifth Floor 24bd238fb4SLatchesar Ionkov * Boston, MA 02111-1301 USA 25bd238fb4SLatchesar Ionkov * 26bd238fb4SLatchesar Ionkov */ 27bd238fb4SLatchesar Ionkov 28bd238fb4SLatchesar Ionkov #include <linux/in.h> 29bd238fb4SLatchesar Ionkov #include <linux/module.h> 30bd238fb4SLatchesar Ionkov #include <linux/net.h> 31bd238fb4SLatchesar Ionkov #include <linux/ipv6.h> 328a0dc95fSEric Van Hensbergen #include <linux/kthread.h> 33bd238fb4SLatchesar Ionkov #include <linux/errno.h> 34bd238fb4SLatchesar Ionkov #include <linux/kernel.h> 35bd238fb4SLatchesar Ionkov #include <linux/un.h> 36bd238fb4SLatchesar Ionkov #include <linux/uaccess.h> 37bd238fb4SLatchesar Ionkov #include <linux/inet.h> 38bd238fb4SLatchesar Ionkov #include <linux/idr.h> 39bd238fb4SLatchesar Ionkov #include <linux/file.h> 40a80d923eSEric Van Hensbergen #include <linux/parser.h> 41bd238fb4SLatchesar Ionkov #include <net/9p/9p.h> 428b81ef58SEric Van Hensbergen #include <net/9p/client.h> 43bd238fb4SLatchesar Ionkov #include <net/9p/transport.h> 44bd238fb4SLatchesar Ionkov 45bd238fb4SLatchesar Ionkov #define P9_PORT 564 46a80d923eSEric Van Hensbergen #define MAX_SOCK_BUF (64*1024) 478a0dc95fSEric Van Hensbergen #define MAXPOLLWADDR 2 48a80d923eSEric Van Hensbergen 49ee443996SEric Van Hensbergen /** 50ee443996SEric Van Hensbergen * struct p9_fd_opts - per-transport options 51ee443996SEric Van Hensbergen * @rfd: file descriptor for reading (trans=fd) 52ee443996SEric Van Hensbergen * @wfd: file descriptor for writing (trans=fd) 53ee443996SEric Van Hensbergen * @port: port to connect to (trans=tcp) 54ee443996SEric Van Hensbergen * 55ee443996SEric Van Hensbergen */ 56ee443996SEric Van Hensbergen 57a80d923eSEric Van Hensbergen struct p9_fd_opts { 58a80d923eSEric Van Hensbergen int rfd; 59a80d923eSEric Van Hensbergen int wfd; 60a80d923eSEric Van Hensbergen u16 port; 61a80d923eSEric Van Hensbergen }; 62bd238fb4SLatchesar Ionkov 63ee443996SEric Van Hensbergen /** 64ee443996SEric Van Hensbergen * struct p9_trans_fd - transport state 65ee443996SEric Van Hensbergen * @rd: reference to file to read from 66ee443996SEric Van Hensbergen * @wr: reference of file to write to 67ee443996SEric Van Hensbergen * @conn: connection state reference 68ee443996SEric Van Hensbergen * 69ee443996SEric Van Hensbergen */ 70ee443996SEric Van Hensbergen 71bd238fb4SLatchesar Ionkov struct p9_trans_fd { 72bd238fb4SLatchesar Ionkov struct file *rd; 73bd238fb4SLatchesar Ionkov struct file *wr; 748a0dc95fSEric Van Hensbergen struct p9_conn *conn; 75bd238fb4SLatchesar Ionkov }; 76bd238fb4SLatchesar Ionkov 77a80d923eSEric Van Hensbergen /* 78a80d923eSEric Van Hensbergen * Option Parsing (code inspired by NFS code) 79a80d923eSEric Van Hensbergen * - a little lazy - parse all fd-transport options 80a80d923eSEric Van Hensbergen */ 81bd238fb4SLatchesar Ionkov 82a80d923eSEric Van Hensbergen enum { 83a80d923eSEric Van Hensbergen /* Options that take integer arguments */ 8455762690SLatchesar Ionkov Opt_port, Opt_rfdno, Opt_wfdno, Opt_err, 85a80d923eSEric Van Hensbergen }; 86a80d923eSEric Van Hensbergen 87a447c093SSteven Whitehouse static const match_table_t tokens = { 88a80d923eSEric Van Hensbergen {Opt_port, "port=%u"}, 89a80d923eSEric Van Hensbergen {Opt_rfdno, "rfdno=%u"}, 90a80d923eSEric Van Hensbergen {Opt_wfdno, "wfdno=%u"}, 9155762690SLatchesar Ionkov {Opt_err, NULL}, 92a80d923eSEric Van Hensbergen }; 93a80d923eSEric Van Hensbergen 948a0dc95fSEric Van Hensbergen enum { 958a0dc95fSEric Van Hensbergen Rworksched = 1, /* read work scheduled or running */ 968a0dc95fSEric Van Hensbergen Rpending = 2, /* can read */ 978a0dc95fSEric Van Hensbergen Wworksched = 4, /* write work scheduled or running */ 988a0dc95fSEric Van Hensbergen Wpending = 8, /* can write */ 998a0dc95fSEric Van Hensbergen }; 1008a0dc95fSEric Van Hensbergen 101992b3f1dSTejun Heo struct p9_poll_wait { 102992b3f1dSTejun Heo struct p9_conn *conn; 103992b3f1dSTejun Heo wait_queue_t wait; 104992b3f1dSTejun Heo wait_queue_head_t *wait_addr; 105ee443996SEric Van Hensbergen }; 106ee443996SEric Van Hensbergen 107ee443996SEric Van Hensbergen /** 108ee443996SEric Van Hensbergen * struct p9_conn - fd mux connection state information 109ee443996SEric Van Hensbergen * @mux_list: list link for mux to manage multiple connections (?) 1108b81ef58SEric Van Hensbergen * @client: reference to client instance for this connection 111ee443996SEric Van Hensbergen * @err: error state 112ee443996SEric Van Hensbergen * @req_list: accounting for requests which have been sent 113ee443996SEric Van Hensbergen * @unsent_req_list: accounting for requests that haven't been sent 1141b0a763bSEric Van Hensbergen * @req: current request being processed (if any) 1151b0a763bSEric Van Hensbergen * @tmp_buf: temporary buffer to read in header 1161b0a763bSEric Van Hensbergen * @rsize: amount to read for current frame 117ee443996SEric Van Hensbergen * @rpos: read position in current frame 118ee443996SEric Van Hensbergen * @rbuf: current read buffer 119ee443996SEric Van Hensbergen * @wpos: write position for current frame 120ee443996SEric Van Hensbergen * @wsize: amount of data to write for current frame 121ee443996SEric Van Hensbergen * @wbuf: current write buffer 122ee443996SEric Van Hensbergen * @poll_wait: array of wait_q's for various worker threads 123ee443996SEric Van Hensbergen * @poll_waddr: ???? 124ee443996SEric Van Hensbergen * @pt: poll state 125ee443996SEric Van Hensbergen * @rq: current read work 126ee443996SEric Van Hensbergen * @wq: current write work 127ee443996SEric Van Hensbergen * @wsched: ???? 128ee443996SEric Van Hensbergen * 129ee443996SEric Van Hensbergen */ 1308a0dc95fSEric Van Hensbergen 1318a0dc95fSEric Van Hensbergen struct p9_conn { 1328a0dc95fSEric Van Hensbergen struct list_head mux_list; 1338b81ef58SEric Van Hensbergen struct p9_client *client; 1348a0dc95fSEric Van Hensbergen int err; 1358a0dc95fSEric Van Hensbergen struct list_head req_list; 1368a0dc95fSEric Van Hensbergen struct list_head unsent_req_list; 1371b0a763bSEric Van Hensbergen struct p9_req_t *req; 1381b0a763bSEric Van Hensbergen char tmp_buf[7]; 1391b0a763bSEric Van Hensbergen int rsize; 1408a0dc95fSEric Van Hensbergen int rpos; 1418a0dc95fSEric Van Hensbergen char *rbuf; 1428a0dc95fSEric Van Hensbergen int wpos; 1438a0dc95fSEric Van Hensbergen int wsize; 1448a0dc95fSEric Van Hensbergen char *wbuf; 145992b3f1dSTejun Heo struct list_head poll_pending_link; 146992b3f1dSTejun Heo struct p9_poll_wait poll_wait[MAXPOLLWADDR]; 1478a0dc95fSEric Van Hensbergen poll_table pt; 1488a0dc95fSEric Van Hensbergen struct work_struct rq; 1498a0dc95fSEric Van Hensbergen struct work_struct wq; 1508a0dc95fSEric Van Hensbergen unsigned long wsched; 1518a0dc95fSEric Van Hensbergen }; 1528a0dc95fSEric Van Hensbergen 153992b3f1dSTejun Heo static DEFINE_SPINLOCK(p9_poll_lock); 154992b3f1dSTejun Heo static LIST_HEAD(p9_poll_pending_list); 1558a0dc95fSEric Van Hensbergen static struct workqueue_struct *p9_mux_wq; 156992b3f1dSTejun Heo static struct task_struct *p9_poll_task; 1578a0dc95fSEric Van Hensbergen 1588a0dc95fSEric Van Hensbergen static void p9_mux_poll_stop(struct p9_conn *m) 1598a0dc95fSEric Van Hensbergen { 160992b3f1dSTejun Heo unsigned long flags; 1618a0dc95fSEric Van Hensbergen int i; 1628a0dc95fSEric Van Hensbergen 163992b3f1dSTejun Heo for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { 164992b3f1dSTejun Heo struct p9_poll_wait *pwait = &m->poll_wait[i]; 165992b3f1dSTejun Heo 166992b3f1dSTejun Heo if (pwait->wait_addr) { 167992b3f1dSTejun Heo remove_wait_queue(pwait->wait_addr, &pwait->wait); 168992b3f1dSTejun Heo pwait->wait_addr = NULL; 1698a0dc95fSEric Van Hensbergen } 1708a0dc95fSEric Van Hensbergen } 171992b3f1dSTejun Heo 172992b3f1dSTejun Heo spin_lock_irqsave(&p9_poll_lock, flags); 173992b3f1dSTejun Heo list_del_init(&m->poll_pending_link); 174992b3f1dSTejun Heo spin_unlock_irqrestore(&p9_poll_lock, flags); 1758a0dc95fSEric Van Hensbergen } 1768a0dc95fSEric Van Hensbergen 1778a0dc95fSEric Van Hensbergen /** 1785503ac56SEric Van Hensbergen * p9_conn_cancel - cancel all pending requests with error 1795503ac56SEric Van Hensbergen * @m: mux data 1805503ac56SEric Van Hensbergen * @err: error code 181ee443996SEric Van Hensbergen * 1828a0dc95fSEric Van Hensbergen */ 183ee443996SEric Van Hensbergen 18451a87c55SEric Van Hensbergen static void p9_conn_cancel(struct p9_conn *m, int err) 1858a0dc95fSEric Van Hensbergen { 186673d62cdSEric Van Hensbergen struct p9_req_t *req, *rtmp; 18791b8534fSEric Van Hensbergen unsigned long flags; 1885503ac56SEric Van Hensbergen LIST_HEAD(cancel_list); 1898a0dc95fSEric Van Hensbergen 1905503ac56SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err); 1917eb923b8SEric Van Hensbergen 19291b8534fSEric Van Hensbergen spin_lock_irqsave(&m->client->lock, flags); 1937eb923b8SEric Van Hensbergen 1947eb923b8SEric Van Hensbergen if (m->err) { 1957eb923b8SEric Van Hensbergen spin_unlock_irqrestore(&m->client->lock, flags); 1967eb923b8SEric Van Hensbergen return; 1977eb923b8SEric Van Hensbergen } 1987eb923b8SEric Van Hensbergen 1997eb923b8SEric Van Hensbergen m->err = err; 2007eb923b8SEric Van Hensbergen 2015503ac56SEric Van Hensbergen list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { 202673d62cdSEric Van Hensbergen req->status = REQ_STATUS_ERROR; 203673d62cdSEric Van Hensbergen if (!req->t_err) 204673d62cdSEric Van Hensbergen req->t_err = err; 2055503ac56SEric Van Hensbergen list_move(&req->req_list, &cancel_list); 2065503ac56SEric Van Hensbergen } 2075503ac56SEric Van Hensbergen list_for_each_entry_safe(req, rtmp, &m->unsent_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 } 21391b8534fSEric Van Hensbergen spin_unlock_irqrestore(&m->client->lock, flags); 2148a0dc95fSEric Van Hensbergen 2155503ac56SEric Van Hensbergen list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) { 2165503ac56SEric Van Hensbergen list_del(&req->req_list); 21791b8534fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, "call back req %p\n", req); 21891b8534fSEric Van Hensbergen p9_client_cb(m->client, req); 2198a0dc95fSEric Van Hensbergen } 2208a0dc95fSEric Van Hensbergen } 2218a0dc95fSEric Van Hensbergen 2225503ac56SEric Van Hensbergen static unsigned int 2235503ac56SEric Van Hensbergen p9_fd_poll(struct p9_client *client, struct poll_table_struct *pt) 2245503ac56SEric Van Hensbergen { 2255503ac56SEric Van Hensbergen int ret, n; 2265503ac56SEric Van Hensbergen struct p9_trans_fd *ts = NULL; 2275503ac56SEric Van Hensbergen 2285503ac56SEric Van Hensbergen if (client && client->status == Connected) 2295503ac56SEric Van Hensbergen ts = client->trans; 2305503ac56SEric Van Hensbergen 2315503ac56SEric Van Hensbergen if (!ts) 2325503ac56SEric Van Hensbergen return -EREMOTEIO; 2335503ac56SEric Van Hensbergen 2345503ac56SEric Van Hensbergen if (!ts->rd->f_op || !ts->rd->f_op->poll) 2355503ac56SEric Van Hensbergen return -EIO; 2365503ac56SEric Van Hensbergen 2375503ac56SEric Van Hensbergen if (!ts->wr->f_op || !ts->wr->f_op->poll) 2385503ac56SEric Van Hensbergen return -EIO; 2395503ac56SEric Van Hensbergen 2405503ac56SEric Van Hensbergen ret = ts->rd->f_op->poll(ts->rd, pt); 2415503ac56SEric Van Hensbergen if (ret < 0) 2425503ac56SEric Van Hensbergen return ret; 2435503ac56SEric Van Hensbergen 2445503ac56SEric Van Hensbergen if (ts->rd != ts->wr) { 2455503ac56SEric Van Hensbergen n = ts->wr->f_op->poll(ts->wr, pt); 2465503ac56SEric Van Hensbergen if (n < 0) 2475503ac56SEric Van Hensbergen return n; 2485503ac56SEric Van Hensbergen ret = (ret & ~POLLOUT) | (n & ~POLLIN); 2495503ac56SEric Van Hensbergen } 2505503ac56SEric Van Hensbergen 2515503ac56SEric Van Hensbergen return ret; 2525503ac56SEric Van Hensbergen } 2535503ac56SEric Van Hensbergen 2545503ac56SEric Van Hensbergen /** 2555503ac56SEric Van Hensbergen * p9_fd_read- read from a fd 2565503ac56SEric Van Hensbergen * @client: client instance 2575503ac56SEric Van Hensbergen * @v: buffer to receive data into 2585503ac56SEric Van Hensbergen * @len: size of receive buffer 2595503ac56SEric Van Hensbergen * 2605503ac56SEric Van Hensbergen */ 2615503ac56SEric Van Hensbergen 2625503ac56SEric Van Hensbergen static int p9_fd_read(struct p9_client *client, void *v, int len) 2635503ac56SEric Van Hensbergen { 2645503ac56SEric Van Hensbergen int ret; 2655503ac56SEric Van Hensbergen struct p9_trans_fd *ts = NULL; 2665503ac56SEric Van Hensbergen 2675503ac56SEric Van Hensbergen if (client && client->status != Disconnected) 2685503ac56SEric Van Hensbergen ts = client->trans; 2695503ac56SEric Van Hensbergen 2705503ac56SEric Van Hensbergen if (!ts) 2715503ac56SEric Van Hensbergen return -EREMOTEIO; 2725503ac56SEric Van Hensbergen 2735503ac56SEric Van Hensbergen if (!(ts->rd->f_flags & O_NONBLOCK)) 2745503ac56SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, "blocking read ...\n"); 2755503ac56SEric Van Hensbergen 2765503ac56SEric Van Hensbergen ret = kernel_read(ts->rd, ts->rd->f_pos, v, len); 2775503ac56SEric Van Hensbergen if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) 2785503ac56SEric Van Hensbergen client->status = Disconnected; 2795503ac56SEric Van Hensbergen return ret; 2805503ac56SEric Van Hensbergen } 2815503ac56SEric Van Hensbergen 2828a0dc95fSEric Van Hensbergen /** 2838a0dc95fSEric Van Hensbergen * p9_read_work - called when there is some data to be read from a transport 284ee443996SEric Van Hensbergen * @work: container of work to be done 285ee443996SEric Van Hensbergen * 2868a0dc95fSEric Van Hensbergen */ 287ee443996SEric Van Hensbergen 2888a0dc95fSEric Van Hensbergen static void p9_read_work(struct work_struct *work) 2898a0dc95fSEric Van Hensbergen { 2908a0dc95fSEric Van Hensbergen int n, err; 2918a0dc95fSEric Van Hensbergen struct p9_conn *m; 2928a0dc95fSEric Van Hensbergen 2938a0dc95fSEric Van Hensbergen m = container_of(work, struct p9_conn, rq); 2948a0dc95fSEric Van Hensbergen 2958a0dc95fSEric Van Hensbergen if (m->err < 0) 2968a0dc95fSEric Van Hensbergen return; 2978a0dc95fSEric Van Hensbergen 29851a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "start mux %p pos %d\n", m, m->rpos); 2998a0dc95fSEric Van Hensbergen 3001b0a763bSEric Van Hensbergen if (!m->rbuf) { 3011b0a763bSEric Van Hensbergen m->rbuf = m->tmp_buf; 3028a0dc95fSEric Van Hensbergen m->rpos = 0; 3031b0a763bSEric Van Hensbergen m->rsize = 7; /* start by reading header */ 3048a0dc95fSEric Van Hensbergen } 3058a0dc95fSEric Van Hensbergen 3068a0dc95fSEric Van Hensbergen clear_bit(Rpending, &m->wsched); 30751a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "read mux %p pos %d size: %d = %d\n", m, 3081b0a763bSEric Van Hensbergen m->rpos, m->rsize, m->rsize-m->rpos); 309bead27f0SEric Van Hensbergen err = p9_fd_read(m->client, m->rbuf + m->rpos, 3101b0a763bSEric Van Hensbergen m->rsize - m->rpos); 31151a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "mux %p got %d bytes\n", m, err); 3128a0dc95fSEric Van Hensbergen if (err == -EAGAIN) { 3138a0dc95fSEric Van Hensbergen clear_bit(Rworksched, &m->wsched); 3148a0dc95fSEric Van Hensbergen return; 3158a0dc95fSEric Van Hensbergen } 3168a0dc95fSEric Van Hensbergen 3178a0dc95fSEric Van Hensbergen if (err <= 0) 3188a0dc95fSEric Van Hensbergen goto error; 3198a0dc95fSEric Van Hensbergen 3208a0dc95fSEric Van Hensbergen m->rpos += err; 3211b0a763bSEric Van Hensbergen 3221b0a763bSEric Van Hensbergen if ((!m->req) && (m->rpos == m->rsize)) { /* header read in */ 3231b0a763bSEric Van Hensbergen u16 tag; 32451a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "got new header\n"); 3251b0a763bSEric Van Hensbergen 3261b0a763bSEric Van Hensbergen n = le32_to_cpu(*(__le32 *) m->rbuf); /* read packet size */ 327bead27f0SEric Van Hensbergen if (n >= m->client->msize) { 3288a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, 3298a0dc95fSEric Van Hensbergen "requested packet size too big: %d\n", n); 3308a0dc95fSEric Van Hensbergen err = -EIO; 3318a0dc95fSEric Van Hensbergen goto error; 3328a0dc95fSEric Van Hensbergen } 3338a0dc95fSEric Van Hensbergen 3341b0a763bSEric Van Hensbergen tag = le16_to_cpu(*(__le16 *) (m->rbuf+5)); /* read tag */ 33551a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, 33651a87c55SEric Van Hensbergen "mux %p pkt: size: %d bytes tag: %d\n", m, n, tag); 3378a0dc95fSEric Van Hensbergen 3381b0a763bSEric Van Hensbergen m->req = p9_tag_lookup(m->client, tag); 3391b0a763bSEric Van Hensbergen if (!m->req) { 3401b0a763bSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, "Unexpected packet tag %d\n", 3411b0a763bSEric Van Hensbergen tag); 3421b0a763bSEric Van Hensbergen err = -EIO; 3438a0dc95fSEric Van Hensbergen goto error; 3441b0a763bSEric Van Hensbergen } 3451b0a763bSEric Van Hensbergen 3461b0a763bSEric Van Hensbergen if (m->req->rc == NULL) { 3471b0a763bSEric Van Hensbergen m->req->rc = kmalloc(sizeof(struct p9_fcall) + 3481b0a763bSEric Van Hensbergen m->client->msize, GFP_KERNEL); 3491b0a763bSEric Van Hensbergen if (!m->req->rc) { 3501b0a763bSEric Van Hensbergen m->req = NULL; 3511b0a763bSEric Van Hensbergen err = -ENOMEM; 3521b0a763bSEric Van Hensbergen goto error; 3531b0a763bSEric Van Hensbergen } 3541b0a763bSEric Van Hensbergen } 3551b0a763bSEric Van Hensbergen m->rbuf = (char *)m->req->rc + sizeof(struct p9_fcall); 3561b0a763bSEric Van Hensbergen memcpy(m->rbuf, m->tmp_buf, m->rsize); 3571b0a763bSEric Van Hensbergen m->rsize = n; 3581b0a763bSEric Van Hensbergen } 3591b0a763bSEric Van Hensbergen 3601b0a763bSEric Van Hensbergen /* not an else because some packets (like clunk) have no payload */ 3611b0a763bSEric Van Hensbergen if ((m->req) && (m->rpos == m->rsize)) { /* packet is read in */ 36251a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "got new packet\n"); 3637eb923b8SEric Van Hensbergen spin_lock(&m->client->lock); 36491b8534fSEric Van Hensbergen list_del(&m->req->req_list); 3657eb923b8SEric Van Hensbergen spin_unlock(&m->client->lock); 36691b8534fSEric Van Hensbergen p9_client_cb(m->client, m->req); 3678a0dc95fSEric Van Hensbergen 3688a0dc95fSEric Van Hensbergen m->rbuf = NULL; 3698a0dc95fSEric Van Hensbergen m->rpos = 0; 3701b0a763bSEric Van Hensbergen m->rsize = 0; 3711b0a763bSEric Van Hensbergen m->req = NULL; 3728a0dc95fSEric Van Hensbergen } 3738a0dc95fSEric Van Hensbergen 3748a0dc95fSEric Van Hensbergen if (!list_empty(&m->req_list)) { 3758a0dc95fSEric Van Hensbergen if (test_and_clear_bit(Rpending, &m->wsched)) 3768a0dc95fSEric Van Hensbergen n = POLLIN; 3778a0dc95fSEric Van Hensbergen else 3788b81ef58SEric Van Hensbergen n = p9_fd_poll(m->client, NULL); 3798a0dc95fSEric Van Hensbergen 3808a0dc95fSEric Van Hensbergen if (n & POLLIN) { 38151a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "sched read work %p\n", m); 3828a0dc95fSEric Van Hensbergen queue_work(p9_mux_wq, &m->rq); 3838a0dc95fSEric Van Hensbergen } else 3848a0dc95fSEric Van Hensbergen clear_bit(Rworksched, &m->wsched); 3858a0dc95fSEric Van Hensbergen } else 3868a0dc95fSEric Van Hensbergen clear_bit(Rworksched, &m->wsched); 3878a0dc95fSEric Van Hensbergen 3888a0dc95fSEric Van Hensbergen return; 3898a0dc95fSEric Van Hensbergen error: 3908a0dc95fSEric Van Hensbergen p9_conn_cancel(m, err); 3918a0dc95fSEric Van Hensbergen clear_bit(Rworksched, &m->wsched); 3928a0dc95fSEric Van Hensbergen } 3938a0dc95fSEric Van Hensbergen 3948a0dc95fSEric Van Hensbergen /** 3955503ac56SEric Van Hensbergen * p9_fd_write - write to a socket 3965503ac56SEric Van Hensbergen * @client: client instance 3975503ac56SEric Van Hensbergen * @v: buffer to send data from 3985503ac56SEric Van Hensbergen * @len: size of send buffer 3995503ac56SEric Van Hensbergen * 4005503ac56SEric Van Hensbergen */ 4015503ac56SEric Van Hensbergen 4025503ac56SEric Van Hensbergen static int p9_fd_write(struct p9_client *client, void *v, int len) 4035503ac56SEric Van Hensbergen { 4045503ac56SEric Van Hensbergen int ret; 4055503ac56SEric Van Hensbergen mm_segment_t oldfs; 4065503ac56SEric Van Hensbergen struct p9_trans_fd *ts = NULL; 4075503ac56SEric Van Hensbergen 4085503ac56SEric Van Hensbergen if (client && client->status != Disconnected) 4095503ac56SEric Van Hensbergen ts = client->trans; 4105503ac56SEric Van Hensbergen 4115503ac56SEric Van Hensbergen if (!ts) 4125503ac56SEric Van Hensbergen return -EREMOTEIO; 4135503ac56SEric Van Hensbergen 4145503ac56SEric Van Hensbergen if (!(ts->wr->f_flags & O_NONBLOCK)) 4155503ac56SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, "blocking write ...\n"); 4165503ac56SEric Van Hensbergen 4175503ac56SEric Van Hensbergen oldfs = get_fs(); 4185503ac56SEric Van Hensbergen set_fs(get_ds()); 4195503ac56SEric Van Hensbergen /* The cast to a user pointer is valid due to the set_fs() */ 4205503ac56SEric Van Hensbergen ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos); 4215503ac56SEric Van Hensbergen set_fs(oldfs); 4225503ac56SEric Van Hensbergen 4235503ac56SEric Van Hensbergen if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) 4245503ac56SEric Van Hensbergen client->status = Disconnected; 4255503ac56SEric Van Hensbergen return ret; 4265503ac56SEric Van Hensbergen } 4275503ac56SEric Van Hensbergen 4285503ac56SEric Van Hensbergen /** 4295503ac56SEric Van Hensbergen * p9_write_work - called when a transport can send some data 4305503ac56SEric Van Hensbergen * @work: container for work to be done 4315503ac56SEric Van Hensbergen * 4325503ac56SEric Van Hensbergen */ 4335503ac56SEric Van Hensbergen 4345503ac56SEric Van Hensbergen static void p9_write_work(struct work_struct *work) 4355503ac56SEric Van Hensbergen { 4365503ac56SEric Van Hensbergen int n, err; 4375503ac56SEric Van Hensbergen struct p9_conn *m; 438673d62cdSEric Van Hensbergen struct p9_req_t *req; 4395503ac56SEric Van Hensbergen 4405503ac56SEric Van Hensbergen m = container_of(work, struct p9_conn, wq); 4415503ac56SEric Van Hensbergen 4425503ac56SEric Van Hensbergen if (m->err < 0) { 4435503ac56SEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 4445503ac56SEric Van Hensbergen return; 4455503ac56SEric Van Hensbergen } 4465503ac56SEric Van Hensbergen 4475503ac56SEric Van Hensbergen if (!m->wsize) { 4485503ac56SEric Van Hensbergen if (list_empty(&m->unsent_req_list)) { 4495503ac56SEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 4505503ac56SEric Van Hensbergen return; 4515503ac56SEric Van Hensbergen } 4525503ac56SEric Van Hensbergen 453673d62cdSEric Van Hensbergen spin_lock(&m->client->lock); 454673d62cdSEric Van Hensbergen req = list_entry(m->unsent_req_list.next, struct p9_req_t, 4555503ac56SEric Van Hensbergen req_list); 456673d62cdSEric Van Hensbergen req->status = REQ_STATUS_SENT; 4575503ac56SEric Van Hensbergen list_move_tail(&req->req_list, &m->req_list); 4585503ac56SEric Van Hensbergen 459673d62cdSEric Van Hensbergen m->wbuf = req->tc->sdata; 460673d62cdSEric Van Hensbergen m->wsize = req->tc->size; 4615503ac56SEric Van Hensbergen m->wpos = 0; 462673d62cdSEric Van Hensbergen spin_unlock(&m->client->lock); 4635503ac56SEric Van Hensbergen } 4645503ac56SEric Van Hensbergen 46551a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "mux %p pos %d size %d\n", m, m->wpos, 4665503ac56SEric Van Hensbergen m->wsize); 4675503ac56SEric Van Hensbergen clear_bit(Wpending, &m->wsched); 4685503ac56SEric Van Hensbergen err = p9_fd_write(m->client, m->wbuf + m->wpos, m->wsize - m->wpos); 46951a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "mux %p sent %d bytes\n", m, err); 4705503ac56SEric Van Hensbergen if (err == -EAGAIN) { 4715503ac56SEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 4725503ac56SEric Van Hensbergen return; 4735503ac56SEric Van Hensbergen } 4745503ac56SEric Van Hensbergen 4755503ac56SEric Van Hensbergen if (err < 0) 4765503ac56SEric Van Hensbergen goto error; 4775503ac56SEric Van Hensbergen else if (err == 0) { 4785503ac56SEric Van Hensbergen err = -EREMOTEIO; 4795503ac56SEric Van Hensbergen goto error; 4805503ac56SEric Van Hensbergen } 4815503ac56SEric Van Hensbergen 4825503ac56SEric Van Hensbergen m->wpos += err; 4835503ac56SEric Van Hensbergen if (m->wpos == m->wsize) 4845503ac56SEric Van Hensbergen m->wpos = m->wsize = 0; 4855503ac56SEric Van Hensbergen 4865503ac56SEric Van Hensbergen if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) { 4875503ac56SEric Van Hensbergen if (test_and_clear_bit(Wpending, &m->wsched)) 4885503ac56SEric Van Hensbergen n = POLLOUT; 4895503ac56SEric Van Hensbergen else 4905503ac56SEric Van Hensbergen n = p9_fd_poll(m->client, NULL); 4915503ac56SEric Van Hensbergen 4925503ac56SEric Van Hensbergen if (n & POLLOUT) { 49351a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "sched write work %p\n", m); 4945503ac56SEric Van Hensbergen queue_work(p9_mux_wq, &m->wq); 4955503ac56SEric Van Hensbergen } else 4965503ac56SEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 4975503ac56SEric Van Hensbergen } else 4985503ac56SEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 4995503ac56SEric Van Hensbergen 5005503ac56SEric Van Hensbergen return; 5015503ac56SEric Van Hensbergen 5025503ac56SEric Van Hensbergen error: 5035503ac56SEric Van Hensbergen p9_conn_cancel(m, err); 5045503ac56SEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 5055503ac56SEric Van Hensbergen } 5065503ac56SEric Van Hensbergen 5075503ac56SEric Van Hensbergen static int p9_pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) 5085503ac56SEric Van Hensbergen { 5095503ac56SEric Van Hensbergen struct p9_poll_wait *pwait = 5105503ac56SEric Van Hensbergen container_of(wait, struct p9_poll_wait, wait); 5115503ac56SEric Van Hensbergen struct p9_conn *m = pwait->conn; 5125503ac56SEric Van Hensbergen unsigned long flags; 5135503ac56SEric Van Hensbergen DECLARE_WAITQUEUE(dummy_wait, p9_poll_task); 5145503ac56SEric Van Hensbergen 5155503ac56SEric Van Hensbergen spin_lock_irqsave(&p9_poll_lock, flags); 5165503ac56SEric Van Hensbergen if (list_empty(&m->poll_pending_link)) 5175503ac56SEric Van Hensbergen list_add_tail(&m->poll_pending_link, &p9_poll_pending_list); 5185503ac56SEric Van Hensbergen spin_unlock_irqrestore(&p9_poll_lock, flags); 5195503ac56SEric Van Hensbergen 5205503ac56SEric Van Hensbergen /* perform the default wake up operation */ 5215503ac56SEric Van Hensbergen return default_wake_function(&dummy_wait, mode, sync, key); 5225503ac56SEric Van Hensbergen } 5235503ac56SEric Van Hensbergen 5245503ac56SEric Van Hensbergen /** 5255503ac56SEric Van Hensbergen * p9_pollwait - add poll task to the wait queue 5265503ac56SEric Van Hensbergen * @filp: file pointer being polled 5275503ac56SEric Van Hensbergen * @wait_address: wait_q to block on 5285503ac56SEric Van Hensbergen * @p: poll state 5295503ac56SEric Van Hensbergen * 5305503ac56SEric Van Hensbergen * called by files poll operation to add v9fs-poll task to files wait queue 5315503ac56SEric Van Hensbergen */ 5325503ac56SEric Van Hensbergen 5335503ac56SEric Van Hensbergen static void 5345503ac56SEric Van Hensbergen p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p) 5355503ac56SEric Van Hensbergen { 5365503ac56SEric Van Hensbergen struct p9_conn *m = container_of(p, struct p9_conn, pt); 5375503ac56SEric Van Hensbergen struct p9_poll_wait *pwait = NULL; 5385503ac56SEric Van Hensbergen int i; 5395503ac56SEric Van Hensbergen 5405503ac56SEric Van Hensbergen for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { 5415503ac56SEric Van Hensbergen if (m->poll_wait[i].wait_addr == NULL) { 5425503ac56SEric Van Hensbergen pwait = &m->poll_wait[i]; 5435503ac56SEric Van Hensbergen break; 5445503ac56SEric Van Hensbergen } 5455503ac56SEric Van Hensbergen } 5465503ac56SEric Van Hensbergen 5475503ac56SEric Van Hensbergen if (!pwait) { 5485503ac56SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n"); 5495503ac56SEric Van Hensbergen return; 5505503ac56SEric Van Hensbergen } 5515503ac56SEric Van Hensbergen 5525503ac56SEric Van Hensbergen pwait->conn = m; 5535503ac56SEric Van Hensbergen pwait->wait_addr = wait_address; 5545503ac56SEric Van Hensbergen init_waitqueue_func_entry(&pwait->wait, p9_pollwake); 5555503ac56SEric Van Hensbergen add_wait_queue(wait_address, &pwait->wait); 5565503ac56SEric Van Hensbergen } 5575503ac56SEric Van Hensbergen 5585503ac56SEric Van Hensbergen /** 5595503ac56SEric Van Hensbergen * p9_conn_create - allocate and initialize the per-session mux data 5605503ac56SEric Van Hensbergen * @client: client instance 5615503ac56SEric Van Hensbergen * 5625503ac56SEric Van Hensbergen * Note: Creates the polling task if this is the first session. 5635503ac56SEric Van Hensbergen */ 5645503ac56SEric Van Hensbergen 5655503ac56SEric Van Hensbergen static struct p9_conn *p9_conn_create(struct p9_client *client) 5665503ac56SEric Van Hensbergen { 56795820a36STejun Heo int n; 5685503ac56SEric Van Hensbergen struct p9_conn *m; 5695503ac56SEric Van Hensbergen 57051a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "client %p msize %d\n", client, 57151a87c55SEric Van Hensbergen client->msize); 5725503ac56SEric Van Hensbergen m = kzalloc(sizeof(struct p9_conn), GFP_KERNEL); 5735503ac56SEric Van Hensbergen if (!m) 5745503ac56SEric Van Hensbergen return ERR_PTR(-ENOMEM); 5755503ac56SEric Van Hensbergen 5765503ac56SEric Van Hensbergen INIT_LIST_HEAD(&m->mux_list); 5775503ac56SEric Van Hensbergen m->client = client; 5785503ac56SEric Van Hensbergen 5795503ac56SEric Van Hensbergen INIT_LIST_HEAD(&m->req_list); 5805503ac56SEric Van Hensbergen INIT_LIST_HEAD(&m->unsent_req_list); 5815503ac56SEric Van Hensbergen INIT_WORK(&m->rq, p9_read_work); 5825503ac56SEric Van Hensbergen INIT_WORK(&m->wq, p9_write_work); 5835503ac56SEric Van Hensbergen INIT_LIST_HEAD(&m->poll_pending_link); 5845503ac56SEric Van Hensbergen init_poll_funcptr(&m->pt, p9_pollwait); 5855503ac56SEric Van Hensbergen 5865503ac56SEric Van Hensbergen n = p9_fd_poll(client, &m->pt); 5875503ac56SEric Van Hensbergen if (n & POLLIN) { 58851a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can read\n", m); 5895503ac56SEric Van Hensbergen set_bit(Rpending, &m->wsched); 5905503ac56SEric Van Hensbergen } 5915503ac56SEric Van Hensbergen 5925503ac56SEric Van Hensbergen if (n & POLLOUT) { 59351a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can write\n", m); 5945503ac56SEric Van Hensbergen set_bit(Wpending, &m->wsched); 5955503ac56SEric Van Hensbergen } 5965503ac56SEric Van Hensbergen 5975503ac56SEric Van Hensbergen return m; 5985503ac56SEric Van Hensbergen } 5995503ac56SEric Van Hensbergen 6005503ac56SEric Van Hensbergen /** 6015503ac56SEric Van Hensbergen * p9_poll_mux - polls a mux and schedules read or write works if necessary 6025503ac56SEric Van Hensbergen * @m: connection to poll 6035503ac56SEric Van Hensbergen * 6045503ac56SEric Van Hensbergen */ 6055503ac56SEric Van Hensbergen 6065503ac56SEric Van Hensbergen static void p9_poll_mux(struct p9_conn *m) 6075503ac56SEric Van Hensbergen { 6085503ac56SEric Van Hensbergen int n; 6095503ac56SEric Van Hensbergen 6105503ac56SEric Van Hensbergen if (m->err < 0) 6115503ac56SEric Van Hensbergen return; 6125503ac56SEric Van Hensbergen 6135503ac56SEric Van Hensbergen n = p9_fd_poll(m->client, NULL); 6145503ac56SEric Van Hensbergen if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) { 61551a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "error mux %p err %d\n", m, n); 6165503ac56SEric Van Hensbergen if (n >= 0) 6175503ac56SEric Van Hensbergen n = -ECONNRESET; 6185503ac56SEric Van Hensbergen p9_conn_cancel(m, n); 6195503ac56SEric Van Hensbergen } 6205503ac56SEric Van Hensbergen 6215503ac56SEric Van Hensbergen if (n & POLLIN) { 6225503ac56SEric Van Hensbergen set_bit(Rpending, &m->wsched); 62351a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can read\n", m); 6245503ac56SEric Van Hensbergen if (!test_and_set_bit(Rworksched, &m->wsched)) { 62551a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "sched read work %p\n", m); 6265503ac56SEric Van Hensbergen queue_work(p9_mux_wq, &m->rq); 6275503ac56SEric Van Hensbergen } 6285503ac56SEric Van Hensbergen } 6295503ac56SEric Van Hensbergen 6305503ac56SEric Van Hensbergen if (n & POLLOUT) { 6315503ac56SEric Van Hensbergen set_bit(Wpending, &m->wsched); 63251a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can write\n", m); 6335503ac56SEric Van Hensbergen if ((m->wsize || !list_empty(&m->unsent_req_list)) 6345503ac56SEric Van Hensbergen && !test_and_set_bit(Wworksched, &m->wsched)) { 63551a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "sched write work %p\n", m); 6365503ac56SEric Van Hensbergen queue_work(p9_mux_wq, &m->wq); 6375503ac56SEric Van Hensbergen } 6385503ac56SEric Van Hensbergen } 6395503ac56SEric Van Hensbergen } 6405503ac56SEric Van Hensbergen 6415503ac56SEric Van Hensbergen /** 64291b8534fSEric Van Hensbergen * p9_fd_request - send 9P request 6438a0dc95fSEric Van Hensbergen * The function can sleep until the request is scheduled for sending. 6448a0dc95fSEric Van Hensbergen * The function can be interrupted. Return from the function is not 64591b8534fSEric Van Hensbergen * a guarantee that the request is sent successfully. 6468a0dc95fSEric Van Hensbergen * 64791b8534fSEric Van Hensbergen * @client: client instance 64891b8534fSEric Van Hensbergen * @req: request to be sent 649ee443996SEric Van Hensbergen * 6508a0dc95fSEric Van Hensbergen */ 651ee443996SEric Van Hensbergen 65291b8534fSEric Van Hensbergen static int p9_fd_request(struct p9_client *client, struct p9_req_t *req) 6538a0dc95fSEric Van Hensbergen { 6548a0dc95fSEric Van Hensbergen int n; 65591b8534fSEric Van Hensbergen struct p9_trans_fd *ts = client->trans; 65691b8534fSEric Van Hensbergen struct p9_conn *m = ts->conn; 6578a0dc95fSEric Van Hensbergen 65851a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "mux %p task %p tcall %p id %d\n", m, 65951a87c55SEric Van Hensbergen current, req->tc, req->tc->id); 6608a0dc95fSEric Van Hensbergen if (m->err < 0) 66191b8534fSEric Van Hensbergen return m->err; 6628a0dc95fSEric Van Hensbergen 66391b8534fSEric Van Hensbergen spin_lock(&client->lock); 6647eb923b8SEric Van Hensbergen req->status = REQ_STATUS_UNSENT; 6658a0dc95fSEric Van Hensbergen list_add_tail(&req->req_list, &m->unsent_req_list); 66691b8534fSEric Van Hensbergen spin_unlock(&client->lock); 6678a0dc95fSEric Van Hensbergen 6688a0dc95fSEric Van Hensbergen if (test_and_clear_bit(Wpending, &m->wsched)) 6698a0dc95fSEric Van Hensbergen n = POLLOUT; 6708a0dc95fSEric Van Hensbergen else 6718b81ef58SEric Van Hensbergen n = p9_fd_poll(m->client, NULL); 6728a0dc95fSEric Van Hensbergen 6738a0dc95fSEric Van Hensbergen if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched)) 6748a0dc95fSEric Van Hensbergen queue_work(p9_mux_wq, &m->wq); 6758a0dc95fSEric Van Hensbergen 67691b8534fSEric Van Hensbergen return 0; 6778a0dc95fSEric Van Hensbergen } 6788a0dc95fSEric Van Hensbergen 67991b8534fSEric Van Hensbergen static int p9_fd_cancel(struct p9_client *client, struct p9_req_t *req) 6808a0dc95fSEric Van Hensbergen { 6817eb923b8SEric Van Hensbergen int ret = 1; 6828a0dc95fSEric Van Hensbergen 6830b15a3a5SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "client %p req %p\n", client, req); 6848a0dc95fSEric Van Hensbergen 68591b8534fSEric Van Hensbergen spin_lock(&client->lock); 68691b8534fSEric Van Hensbergen list_del(&req->req_list); 68791b8534fSEric Van Hensbergen 68891b8534fSEric Van Hensbergen if (req->status == REQ_STATUS_UNSENT) { 689673d62cdSEric Van Hensbergen req->status = REQ_STATUS_FLSHD; 6907eb923b8SEric Van Hensbergen ret = 0; 6918a0dc95fSEric Van Hensbergen } 6928a0dc95fSEric Van Hensbergen 6937eb923b8SEric Van Hensbergen spin_unlock(&client->lock); 6947eb923b8SEric Van Hensbergen 6957eb923b8SEric Van Hensbergen return ret; 6968a0dc95fSEric Van Hensbergen } 6978a0dc95fSEric Van Hensbergen 6988a0dc95fSEric Van Hensbergen /** 699bb8ffdfcSEric Van Hensbergen * parse_options - parse mount options into session structure 700a80d923eSEric Van Hensbergen * @options: options string passed from mount 701ee443996SEric Van Hensbergen * @opts: transport-specific structure to parse options into 702a80d923eSEric Van Hensbergen * 703bb8ffdfcSEric Van Hensbergen * Returns 0 upon success, -ERRNO upon failure 704a80d923eSEric Van Hensbergen */ 705a80d923eSEric Van Hensbergen 706bb8ffdfcSEric Van Hensbergen static int parse_opts(char *params, struct p9_fd_opts *opts) 707bd238fb4SLatchesar Ionkov { 708a80d923eSEric Van Hensbergen char *p; 709a80d923eSEric Van Hensbergen substring_t args[MAX_OPT_ARGS]; 710a80d923eSEric Van Hensbergen int option; 711bb8ffdfcSEric Van Hensbergen char *options; 712a80d923eSEric Van Hensbergen int ret; 713bd238fb4SLatchesar Ionkov 714a80d923eSEric Van Hensbergen opts->port = P9_PORT; 715a80d923eSEric Van Hensbergen opts->rfd = ~0; 716a80d923eSEric Van Hensbergen opts->wfd = ~0; 717bd238fb4SLatchesar Ionkov 718bb8ffdfcSEric Van Hensbergen if (!params) 719bb8ffdfcSEric Van Hensbergen return 0; 720bb8ffdfcSEric Van Hensbergen 721bb8ffdfcSEric Van Hensbergen options = kstrdup(params, GFP_KERNEL); 722bb8ffdfcSEric Van Hensbergen if (!options) { 723bb8ffdfcSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, 724bb8ffdfcSEric Van Hensbergen "failed to allocate copy of option string\n"); 725bb8ffdfcSEric Van Hensbergen return -ENOMEM; 726bb8ffdfcSEric Van Hensbergen } 727bd238fb4SLatchesar Ionkov 728a80d923eSEric Van Hensbergen while ((p = strsep(&options, ",")) != NULL) { 729a80d923eSEric Van Hensbergen int token; 730bb8ffdfcSEric Van Hensbergen int r; 731a80d923eSEric Van Hensbergen if (!*p) 732a80d923eSEric Van Hensbergen continue; 733a80d923eSEric Van Hensbergen token = match_token(p, tokens, args); 734bb8ffdfcSEric Van Hensbergen r = match_int(&args[0], &option); 735bb8ffdfcSEric Van Hensbergen if (r < 0) { 736a80d923eSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, 737a80d923eSEric Van Hensbergen "integer field, but no integer?\n"); 738bb8ffdfcSEric Van Hensbergen ret = r; 739a80d923eSEric Van Hensbergen continue; 740a80d923eSEric Van Hensbergen } 741a80d923eSEric Van Hensbergen switch (token) { 742a80d923eSEric Van Hensbergen case Opt_port: 743a80d923eSEric Van Hensbergen opts->port = option; 744a80d923eSEric Van Hensbergen break; 745a80d923eSEric Van Hensbergen case Opt_rfdno: 746a80d923eSEric Van Hensbergen opts->rfd = option; 747a80d923eSEric Van Hensbergen break; 748a80d923eSEric Van Hensbergen case Opt_wfdno: 749a80d923eSEric Van Hensbergen opts->wfd = option; 750a80d923eSEric Van Hensbergen break; 751a80d923eSEric Van Hensbergen default: 752a80d923eSEric Van Hensbergen continue; 753a80d923eSEric Van Hensbergen } 754a80d923eSEric Van Hensbergen } 755bb8ffdfcSEric Van Hensbergen kfree(options); 756bb8ffdfcSEric Van Hensbergen return 0; 757bd238fb4SLatchesar Ionkov } 758bd238fb4SLatchesar Ionkov 7598b81ef58SEric Van Hensbergen static int p9_fd_open(struct p9_client *client, int rfd, int wfd) 760bd238fb4SLatchesar Ionkov { 761bd238fb4SLatchesar Ionkov struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd), 762bd238fb4SLatchesar Ionkov GFP_KERNEL); 763bd238fb4SLatchesar Ionkov if (!ts) 764bd238fb4SLatchesar Ionkov return -ENOMEM; 765bd238fb4SLatchesar Ionkov 766bd238fb4SLatchesar Ionkov ts->rd = fget(rfd); 767bd238fb4SLatchesar Ionkov ts->wr = fget(wfd); 768bd238fb4SLatchesar Ionkov if (!ts->rd || !ts->wr) { 769bd238fb4SLatchesar Ionkov if (ts->rd) 770bd238fb4SLatchesar Ionkov fput(ts->rd); 771bd238fb4SLatchesar Ionkov if (ts->wr) 772bd238fb4SLatchesar Ionkov fput(ts->wr); 773bd238fb4SLatchesar Ionkov kfree(ts); 774bd238fb4SLatchesar Ionkov return -EIO; 775bd238fb4SLatchesar Ionkov } 776bd238fb4SLatchesar Ionkov 7778b81ef58SEric Van Hensbergen client->trans = ts; 7788b81ef58SEric Van Hensbergen client->status = Connected; 779bd238fb4SLatchesar Ionkov 780bd238fb4SLatchesar Ionkov return 0; 781bd238fb4SLatchesar Ionkov } 782bd238fb4SLatchesar Ionkov 7838b81ef58SEric Van Hensbergen static int p9_socket_open(struct p9_client *client, struct socket *csocket) 784a80d923eSEric Van Hensbergen { 785a80d923eSEric Van Hensbergen int fd, ret; 786a80d923eSEric Van Hensbergen 787a80d923eSEric Van Hensbergen csocket->sk->sk_allocation = GFP_NOIO; 788a677a039SUlrich Drepper fd = sock_map_fd(csocket, 0); 789a80d923eSEric Van Hensbergen if (fd < 0) { 790a80d923eSEric Van Hensbergen P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n"); 791a80d923eSEric Van Hensbergen return fd; 792a80d923eSEric Van Hensbergen } 793a80d923eSEric Van Hensbergen 7948b81ef58SEric Van Hensbergen ret = p9_fd_open(client, fd, fd); 795a80d923eSEric Van Hensbergen if (ret < 0) { 796a80d923eSEric Van Hensbergen P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to open fd\n"); 797a80d923eSEric Van Hensbergen sockfd_put(csocket); 798a80d923eSEric Van Hensbergen return ret; 799a80d923eSEric Van Hensbergen } 800a80d923eSEric Van Hensbergen 8018b81ef58SEric Van Hensbergen ((struct p9_trans_fd *)client->trans)->rd->f_flags |= O_NONBLOCK; 802a80d923eSEric Van Hensbergen 803a80d923eSEric Van Hensbergen return 0; 804a80d923eSEric Van Hensbergen } 805a80d923eSEric Van Hensbergen 806bd238fb4SLatchesar Ionkov /** 8075503ac56SEric Van Hensbergen * p9_mux_destroy - cancels all pending requests and frees mux resources 8085503ac56SEric Van Hensbergen * @m: mux to destroy 809bd238fb4SLatchesar Ionkov * 810bd238fb4SLatchesar Ionkov */ 811ee443996SEric Van Hensbergen 8125503ac56SEric Van Hensbergen static void p9_conn_destroy(struct p9_conn *m) 813bd238fb4SLatchesar Ionkov { 81451a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "mux %p prev %p next %p\n", m, 8155503ac56SEric Van Hensbergen m->mux_list.prev, m->mux_list.next); 816bd238fb4SLatchesar Ionkov 8175503ac56SEric Van Hensbergen p9_mux_poll_stop(m); 8185503ac56SEric Van Hensbergen cancel_work_sync(&m->rq); 8195503ac56SEric Van Hensbergen cancel_work_sync(&m->wq); 820bd238fb4SLatchesar Ionkov 8215503ac56SEric Van Hensbergen p9_conn_cancel(m, -ECONNRESET); 822bd238fb4SLatchesar Ionkov 8235503ac56SEric Van Hensbergen m->client = NULL; 8245503ac56SEric Van Hensbergen kfree(m); 825bd238fb4SLatchesar Ionkov } 826bd238fb4SLatchesar Ionkov 827bd238fb4SLatchesar Ionkov /** 8288b81ef58SEric Van Hensbergen * p9_fd_close - shutdown file descriptor transport 8298b81ef58SEric Van Hensbergen * @client: client instance 830bd238fb4SLatchesar Ionkov * 831bd238fb4SLatchesar Ionkov */ 832ee443996SEric Van Hensbergen 8338b81ef58SEric Van Hensbergen static void p9_fd_close(struct p9_client *client) 834bd238fb4SLatchesar Ionkov { 835bd238fb4SLatchesar Ionkov struct p9_trans_fd *ts; 836bd238fb4SLatchesar Ionkov 8378b81ef58SEric Van Hensbergen if (!client) 838bd238fb4SLatchesar Ionkov return; 839bd238fb4SLatchesar Ionkov 8408b81ef58SEric Van Hensbergen ts = client->trans; 841bd238fb4SLatchesar Ionkov if (!ts) 842bd238fb4SLatchesar Ionkov return; 843bd238fb4SLatchesar Ionkov 8448b81ef58SEric Van Hensbergen client->status = Disconnected; 8458b81ef58SEric Van Hensbergen 8468a0dc95fSEric Van Hensbergen p9_conn_destroy(ts->conn); 8478a0dc95fSEric Van Hensbergen 848bd238fb4SLatchesar Ionkov if (ts->rd) 849bd238fb4SLatchesar Ionkov fput(ts->rd); 850bd238fb4SLatchesar Ionkov if (ts->wr) 851bd238fb4SLatchesar Ionkov fput(ts->wr); 8528b81ef58SEric Van Hensbergen 853bd238fb4SLatchesar Ionkov kfree(ts); 854bd238fb4SLatchesar Ionkov } 855bd238fb4SLatchesar Ionkov 856887b3eceSEric Van Hensbergen /* 857887b3eceSEric Van Hensbergen * stolen from NFS - maybe should be made a generic function? 858887b3eceSEric Van Hensbergen */ 859887b3eceSEric Van Hensbergen static inline int valid_ipaddr4(const char *buf) 860887b3eceSEric Van Hensbergen { 861887b3eceSEric Van Hensbergen int rc, count, in[4]; 862887b3eceSEric Van Hensbergen 863887b3eceSEric Van Hensbergen rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]); 864887b3eceSEric Van Hensbergen if (rc != 4) 865887b3eceSEric Van Hensbergen return -EINVAL; 866887b3eceSEric Van Hensbergen for (count = 0; count < 4; count++) { 867887b3eceSEric Van Hensbergen if (in[count] > 255) 868887b3eceSEric Van Hensbergen return -EINVAL; 869887b3eceSEric Van Hensbergen } 870887b3eceSEric Van Hensbergen return 0; 871887b3eceSEric Van Hensbergen } 872887b3eceSEric Van Hensbergen 8738b81ef58SEric Van Hensbergen static int 8748b81ef58SEric Van Hensbergen p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args) 875a80d923eSEric Van Hensbergen { 876a80d923eSEric Van Hensbergen int err; 877a80d923eSEric Van Hensbergen struct socket *csocket; 878a80d923eSEric Van Hensbergen struct sockaddr_in sin_server; 879a80d923eSEric Van Hensbergen struct p9_fd_opts opts; 8808b81ef58SEric Van Hensbergen struct p9_trans_fd *p = NULL; /* this gets allocated in p9_fd_open */ 881a80d923eSEric Van Hensbergen 882bb8ffdfcSEric Van Hensbergen err = parse_opts(args, &opts); 883bb8ffdfcSEric Van Hensbergen if (err < 0) 8848b81ef58SEric Van Hensbergen return err; 885a80d923eSEric Van Hensbergen 886887b3eceSEric Van Hensbergen if (valid_ipaddr4(addr) < 0) 8878b81ef58SEric Van Hensbergen return -EINVAL; 888887b3eceSEric Van Hensbergen 889a80d923eSEric Van Hensbergen csocket = NULL; 890a80d923eSEric Van Hensbergen 891a80d923eSEric Van Hensbergen sin_server.sin_family = AF_INET; 892a80d923eSEric Van Hensbergen sin_server.sin_addr.s_addr = in_aton(addr); 893a80d923eSEric Van Hensbergen sin_server.sin_port = htons(opts.port); 894a80d923eSEric Van Hensbergen sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket); 895a80d923eSEric Van Hensbergen 896a80d923eSEric Van Hensbergen if (!csocket) { 897a80d923eSEric Van Hensbergen P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n"); 898a80d923eSEric Van Hensbergen err = -EIO; 899a80d923eSEric Van Hensbergen goto error; 900a80d923eSEric Van Hensbergen } 901a80d923eSEric Van Hensbergen 902a80d923eSEric Van Hensbergen err = csocket->ops->connect(csocket, 903a80d923eSEric Van Hensbergen (struct sockaddr *)&sin_server, 904a80d923eSEric Van Hensbergen sizeof(struct sockaddr_in), 0); 905a80d923eSEric Van Hensbergen if (err < 0) { 906a80d923eSEric Van Hensbergen P9_EPRINTK(KERN_ERR, 907a80d923eSEric Van Hensbergen "p9_trans_tcp: problem connecting socket to %s\n", 908a80d923eSEric Van Hensbergen addr); 909a80d923eSEric Van Hensbergen goto error; 910a80d923eSEric Van Hensbergen } 911a80d923eSEric Van Hensbergen 9128b81ef58SEric Van Hensbergen err = p9_socket_open(client, csocket); 913a80d923eSEric Van Hensbergen if (err < 0) 914a80d923eSEric Van Hensbergen goto error; 915a80d923eSEric Van Hensbergen 9168b81ef58SEric Van Hensbergen p = (struct p9_trans_fd *) client->trans; 9178b81ef58SEric Van Hensbergen p->conn = p9_conn_create(client); 9188a0dc95fSEric Van Hensbergen if (IS_ERR(p->conn)) { 9198a0dc95fSEric Van Hensbergen err = PTR_ERR(p->conn); 9208a0dc95fSEric Van Hensbergen p->conn = NULL; 9218a0dc95fSEric Van Hensbergen goto error; 9228a0dc95fSEric Van Hensbergen } 9238a0dc95fSEric Van Hensbergen 9248b81ef58SEric Van Hensbergen return 0; 925a80d923eSEric Van Hensbergen 926a80d923eSEric Van Hensbergen error: 927a80d923eSEric Van Hensbergen if (csocket) 928a80d923eSEric Van Hensbergen sock_release(csocket); 929a80d923eSEric Van Hensbergen 9308b81ef58SEric Van Hensbergen kfree(p); 9318b81ef58SEric Van Hensbergen 9328b81ef58SEric Van Hensbergen return err; 933a80d923eSEric Van Hensbergen } 934a80d923eSEric Van Hensbergen 9358b81ef58SEric Van Hensbergen static int 9368b81ef58SEric Van Hensbergen p9_fd_create_unix(struct p9_client *client, const char *addr, char *args) 937a80d923eSEric Van Hensbergen { 938a80d923eSEric Van Hensbergen int err; 939a80d923eSEric Van Hensbergen struct socket *csocket; 940a80d923eSEric Van Hensbergen struct sockaddr_un sun_server; 9418b81ef58SEric Van Hensbergen struct p9_trans_fd *p = NULL; /* this gets allocated in p9_fd_open */ 942a80d923eSEric Van Hensbergen 943a80d923eSEric Van Hensbergen csocket = NULL; 944a80d923eSEric Van Hensbergen 945a80d923eSEric Van Hensbergen if (strlen(addr) > UNIX_PATH_MAX) { 946a80d923eSEric Van Hensbergen P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n", 947a80d923eSEric Van Hensbergen addr); 948a80d923eSEric Van Hensbergen err = -ENAMETOOLONG; 949a80d923eSEric Van Hensbergen goto error; 950a80d923eSEric Van Hensbergen } 951a80d923eSEric Van Hensbergen 952a80d923eSEric Van Hensbergen sun_server.sun_family = PF_UNIX; 953a80d923eSEric Van Hensbergen strcpy(sun_server.sun_path, addr); 954a80d923eSEric Van Hensbergen sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket); 955a80d923eSEric Van Hensbergen err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server, 956a80d923eSEric Van Hensbergen sizeof(struct sockaddr_un) - 1, 0); 957a80d923eSEric Van Hensbergen if (err < 0) { 958a80d923eSEric Van Hensbergen P9_EPRINTK(KERN_ERR, 959a80d923eSEric Van Hensbergen "p9_trans_unix: problem connecting socket: %s: %d\n", 960a80d923eSEric Van Hensbergen addr, err); 961a80d923eSEric Van Hensbergen goto error; 962a80d923eSEric Van Hensbergen } 963a80d923eSEric Van Hensbergen 9648b81ef58SEric Van Hensbergen err = p9_socket_open(client, csocket); 965a80d923eSEric Van Hensbergen if (err < 0) 966a80d923eSEric Van Hensbergen goto error; 967a80d923eSEric Van Hensbergen 9688b81ef58SEric Van Hensbergen p = (struct p9_trans_fd *) client->trans; 9698b81ef58SEric Van Hensbergen p->conn = p9_conn_create(client); 9708a0dc95fSEric Van Hensbergen if (IS_ERR(p->conn)) { 9718a0dc95fSEric Van Hensbergen err = PTR_ERR(p->conn); 9728a0dc95fSEric Van Hensbergen p->conn = NULL; 9738a0dc95fSEric Van Hensbergen goto error; 9748a0dc95fSEric Van Hensbergen } 9758a0dc95fSEric Van Hensbergen 9768b81ef58SEric Van Hensbergen return 0; 977a80d923eSEric Van Hensbergen 978a80d923eSEric Van Hensbergen error: 979a80d923eSEric Van Hensbergen if (csocket) 980a80d923eSEric Van Hensbergen sock_release(csocket); 981a80d923eSEric Van Hensbergen 9828b81ef58SEric Van Hensbergen kfree(p); 9838b81ef58SEric Van Hensbergen return err; 984a80d923eSEric Van Hensbergen } 985a80d923eSEric Van Hensbergen 9868b81ef58SEric Van Hensbergen static int 9878b81ef58SEric Van Hensbergen p9_fd_create(struct p9_client *client, const char *addr, char *args) 988a80d923eSEric Van Hensbergen { 989a80d923eSEric Van Hensbergen int err; 990a80d923eSEric Van Hensbergen struct p9_fd_opts opts; 9918b81ef58SEric Van Hensbergen struct p9_trans_fd *p = NULL; /* this get allocated in p9_fd_open */ 992a80d923eSEric Van Hensbergen 993a80d923eSEric Van Hensbergen parse_opts(args, &opts); 994a80d923eSEric Van Hensbergen 995a80d923eSEric Van Hensbergen if (opts.rfd == ~0 || opts.wfd == ~0) { 996a80d923eSEric Van Hensbergen printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n"); 9978b81ef58SEric Van Hensbergen return -ENOPROTOOPT; 998a80d923eSEric Van Hensbergen } 999a80d923eSEric Van Hensbergen 10008b81ef58SEric Van Hensbergen err = p9_fd_open(client, opts.rfd, opts.wfd); 1001a80d923eSEric Van Hensbergen if (err < 0) 1002a80d923eSEric Van Hensbergen goto error; 1003a80d923eSEric Van Hensbergen 10048b81ef58SEric Van Hensbergen p = (struct p9_trans_fd *) client->trans; 10058b81ef58SEric Van Hensbergen p->conn = p9_conn_create(client); 10068a0dc95fSEric Van Hensbergen if (IS_ERR(p->conn)) { 10078a0dc95fSEric Van Hensbergen err = PTR_ERR(p->conn); 10088a0dc95fSEric Van Hensbergen p->conn = NULL; 10098a0dc95fSEric Van Hensbergen goto error; 10108a0dc95fSEric Van Hensbergen } 10118a0dc95fSEric Van Hensbergen 10128b81ef58SEric Van Hensbergen return 0; 1013a80d923eSEric Van Hensbergen 1014a80d923eSEric Van Hensbergen error: 10158b81ef58SEric Van Hensbergen kfree(p); 10168b81ef58SEric Van Hensbergen return err; 1017a80d923eSEric Van Hensbergen } 1018a80d923eSEric Van Hensbergen 1019a80d923eSEric Van Hensbergen static struct p9_trans_module p9_tcp_trans = { 1020a80d923eSEric Van Hensbergen .name = "tcp", 1021a80d923eSEric Van Hensbergen .maxsize = MAX_SOCK_BUF, 1022a80d923eSEric Van Hensbergen .def = 1, 10238b81ef58SEric Van Hensbergen .create = p9_fd_create_tcp, 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_unix_trans = { 1031a80d923eSEric Van Hensbergen .name = "unix", 1032a80d923eSEric Van Hensbergen .maxsize = MAX_SOCK_BUF, 1033a80d923eSEric Van Hensbergen .def = 0, 10348b81ef58SEric Van Hensbergen .create = p9_fd_create_unix, 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 1041a80d923eSEric Van Hensbergen static struct p9_trans_module p9_fd_trans = { 1042a80d923eSEric Van Hensbergen .name = "fd", 1043a80d923eSEric Van Hensbergen .maxsize = MAX_SOCK_BUF, 1044a80d923eSEric Van Hensbergen .def = 0, 10458b81ef58SEric Van Hensbergen .create = p9_fd_create, 10468b81ef58SEric Van Hensbergen .close = p9_fd_close, 104791b8534fSEric Van Hensbergen .request = p9_fd_request, 104891b8534fSEric Van Hensbergen .cancel = p9_fd_cancel, 104972029fe8STejun Heo .owner = THIS_MODULE, 1050a80d923eSEric Van Hensbergen }; 1051a80d923eSEric Van Hensbergen 10525503ac56SEric Van Hensbergen /** 10535503ac56SEric Van Hensbergen * p9_poll_proc - poll worker thread 10545503ac56SEric Van Hensbergen * @a: thread state and arguments 10555503ac56SEric Van Hensbergen * 10565503ac56SEric Van Hensbergen * polls all v9fs transports for new events and queues the appropriate 10575503ac56SEric Van Hensbergen * work to the work queue 10585503ac56SEric Van Hensbergen * 10595503ac56SEric Van Hensbergen */ 10605503ac56SEric Van Hensbergen 10615503ac56SEric Van Hensbergen static int p9_poll_proc(void *a) 10625503ac56SEric Van Hensbergen { 10635503ac56SEric Van Hensbergen unsigned long flags; 10645503ac56SEric Van Hensbergen 106551a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "start %p\n", current); 10665503ac56SEric Van Hensbergen repeat: 10675503ac56SEric Van Hensbergen spin_lock_irqsave(&p9_poll_lock, flags); 10685503ac56SEric Van Hensbergen while (!list_empty(&p9_poll_pending_list)) { 10695503ac56SEric Van Hensbergen struct p9_conn *conn = list_first_entry(&p9_poll_pending_list, 10705503ac56SEric Van Hensbergen struct p9_conn, 10715503ac56SEric Van Hensbergen poll_pending_link); 10725503ac56SEric Van Hensbergen list_del_init(&conn->poll_pending_link); 10735503ac56SEric Van Hensbergen spin_unlock_irqrestore(&p9_poll_lock, flags); 10745503ac56SEric Van Hensbergen 10755503ac56SEric Van Hensbergen p9_poll_mux(conn); 10765503ac56SEric Van Hensbergen 10775503ac56SEric Van Hensbergen spin_lock_irqsave(&p9_poll_lock, flags); 10785503ac56SEric Van Hensbergen } 10795503ac56SEric Van Hensbergen spin_unlock_irqrestore(&p9_poll_lock, flags); 10805503ac56SEric Van Hensbergen 10815503ac56SEric Van Hensbergen set_current_state(TASK_INTERRUPTIBLE); 10825503ac56SEric Van Hensbergen if (list_empty(&p9_poll_pending_list)) { 108351a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "sleeping...\n"); 10845503ac56SEric Van Hensbergen schedule(); 10855503ac56SEric Van Hensbergen } 10865503ac56SEric Van Hensbergen __set_current_state(TASK_RUNNING); 10875503ac56SEric Van Hensbergen 10885503ac56SEric Van Hensbergen if (!kthread_should_stop()) 10895503ac56SEric Van Hensbergen goto repeat; 10905503ac56SEric Van Hensbergen 109151a87c55SEric Van Hensbergen P9_DPRINTK(P9_DEBUG_TRANS, "finish\n"); 10925503ac56SEric Van Hensbergen return 0; 10935503ac56SEric Van Hensbergen } 10945503ac56SEric Van Hensbergen 1095887b3eceSEric Van Hensbergen int p9_trans_fd_init(void) 1096a80d923eSEric Van Hensbergen { 1097206ca50dSTejun Heo p9_mux_wq = create_workqueue("v9fs"); 1098206ca50dSTejun Heo if (!p9_mux_wq) { 1099206ca50dSTejun Heo printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n"); 1100206ca50dSTejun Heo return -ENOMEM; 11018a0dc95fSEric Van Hensbergen } 11028a0dc95fSEric Van Hensbergen 1103992b3f1dSTejun Heo p9_poll_task = kthread_run(p9_poll_proc, NULL, "v9fs-poll"); 1104992b3f1dSTejun Heo if (IS_ERR(p9_poll_task)) { 1105992b3f1dSTejun Heo destroy_workqueue(p9_mux_wq); 1106992b3f1dSTejun Heo printk(KERN_WARNING "v9fs: mux: creating poll task failed\n"); 1107992b3f1dSTejun Heo return PTR_ERR(p9_poll_task); 1108992b3f1dSTejun Heo } 1109992b3f1dSTejun Heo 1110a80d923eSEric Van Hensbergen v9fs_register_trans(&p9_tcp_trans); 1111a80d923eSEric Van Hensbergen v9fs_register_trans(&p9_unix_trans); 1112a80d923eSEric Van Hensbergen v9fs_register_trans(&p9_fd_trans); 1113a80d923eSEric Van Hensbergen 11143387b804SAndrew Morton return 0; 1115a80d923eSEric Van Hensbergen } 111672029fe8STejun Heo 111772029fe8STejun Heo void p9_trans_fd_exit(void) 111872029fe8STejun Heo { 1119992b3f1dSTejun Heo kthread_stop(p9_poll_task); 112072029fe8STejun Heo v9fs_unregister_trans(&p9_tcp_trans); 112172029fe8STejun Heo v9fs_unregister_trans(&p9_unix_trans); 112272029fe8STejun Heo v9fs_unregister_trans(&p9_fd_trans); 1123206ca50dSTejun Heo 1124206ca50dSTejun Heo destroy_workqueue(p9_mux_wq); 112572029fe8STejun Heo } 1126