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> 42bd238fb4SLatchesar Ionkov #include <net/9p/transport.h> 43bd238fb4SLatchesar Ionkov 44bd238fb4SLatchesar Ionkov #define P9_PORT 564 45a80d923eSEric Van Hensbergen #define MAX_SOCK_BUF (64*1024) 468a0dc95fSEric Van Hensbergen #define ERREQFLUSH 1 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 /** 65ee443996SEric Van Hensbergen * struct p9_trans_fd - transport state 66ee443996SEric Van Hensbergen * @rd: reference to file to read from 67ee443996SEric Van Hensbergen * @wr: reference of file to write to 68ee443996SEric Van Hensbergen * @conn: connection state reference 69ee443996SEric Van Hensbergen * 70ee443996SEric Van Hensbergen */ 71ee443996SEric Van Hensbergen 72bd238fb4SLatchesar Ionkov struct p9_trans_fd { 73bd238fb4SLatchesar Ionkov struct file *rd; 74bd238fb4SLatchesar Ionkov struct file *wr; 758a0dc95fSEric Van Hensbergen struct p9_conn *conn; 76bd238fb4SLatchesar Ionkov }; 77bd238fb4SLatchesar Ionkov 78a80d923eSEric Van Hensbergen /* 79a80d923eSEric Van Hensbergen * Option Parsing (code inspired by NFS code) 80a80d923eSEric Van Hensbergen * - a little lazy - parse all fd-transport options 81a80d923eSEric Van Hensbergen */ 82bd238fb4SLatchesar Ionkov 83a80d923eSEric Van Hensbergen enum { 84a80d923eSEric Van Hensbergen /* Options that take integer arguments */ 8555762690SLatchesar Ionkov Opt_port, Opt_rfdno, Opt_wfdno, Opt_err, 86a80d923eSEric Van Hensbergen }; 87a80d923eSEric Van Hensbergen 88a447c093SSteven Whitehouse static const match_table_t tokens = { 89a80d923eSEric Van Hensbergen {Opt_port, "port=%u"}, 90a80d923eSEric Van Hensbergen {Opt_rfdno, "rfdno=%u"}, 91a80d923eSEric Van Hensbergen {Opt_wfdno, "wfdno=%u"}, 9255762690SLatchesar Ionkov {Opt_err, NULL}, 93a80d923eSEric Van Hensbergen }; 94a80d923eSEric Van Hensbergen 958a0dc95fSEric Van Hensbergen enum { 968a0dc95fSEric Van Hensbergen Rworksched = 1, /* read work scheduled or running */ 978a0dc95fSEric Van Hensbergen Rpending = 2, /* can read */ 988a0dc95fSEric Van Hensbergen Wworksched = 4, /* write work scheduled or running */ 998a0dc95fSEric Van Hensbergen Wpending = 8, /* can write */ 1008a0dc95fSEric Van Hensbergen }; 1018a0dc95fSEric Van Hensbergen 1028a0dc95fSEric Van Hensbergen enum { 1038a0dc95fSEric Van Hensbergen None, 1048a0dc95fSEric Van Hensbergen Flushing, 1058a0dc95fSEric Van Hensbergen Flushed, 1068a0dc95fSEric Van Hensbergen }; 1078a0dc95fSEric Van Hensbergen 1088a0dc95fSEric Van Hensbergen struct p9_req; 1098a0dc95fSEric Van Hensbergen typedef void (*p9_conn_req_callback)(struct p9_req *req, void *a); 110ee443996SEric Van Hensbergen 111ee443996SEric Van Hensbergen /** 112ee443996SEric Van Hensbergen * struct p9_req - fd mux encoding of an rpc transaction 113ee443996SEric Van Hensbergen * @lock: protects req_list 114ee443996SEric Van Hensbergen * @tag: numeric tag for rpc transaction 115ee443996SEric Van Hensbergen * @tcall: request &p9_fcall structure 116ee443996SEric Van Hensbergen * @rcall: response &p9_fcall structure 117ee443996SEric Van Hensbergen * @err: error state 118ee443996SEric Van Hensbergen * @cb: callback for when response is received 119ee443996SEric Van Hensbergen * @cba: argument to pass to callback 120ee443996SEric Van Hensbergen * @flush: flag to indicate RPC has been flushed 121ee443996SEric Van Hensbergen * @req_list: list link for higher level objects to chain requests 122ee443996SEric Van Hensbergen * 123ee443996SEric Van Hensbergen */ 124ee443996SEric Van Hensbergen 1258a0dc95fSEric Van Hensbergen struct p9_req { 126ee443996SEric Van Hensbergen spinlock_t lock; 1278a0dc95fSEric Van Hensbergen int tag; 1288a0dc95fSEric Van Hensbergen struct p9_fcall *tcall; 1298a0dc95fSEric Van Hensbergen struct p9_fcall *rcall; 1308a0dc95fSEric Van Hensbergen int err; 1318a0dc95fSEric Van Hensbergen p9_conn_req_callback cb; 1328a0dc95fSEric Van Hensbergen void *cba; 1338a0dc95fSEric Van Hensbergen int flush; 1348a0dc95fSEric Van Hensbergen struct list_head req_list; 1358a0dc95fSEric Van Hensbergen }; 1368a0dc95fSEric Van Hensbergen 137992b3f1dSTejun Heo struct p9_poll_wait { 138992b3f1dSTejun Heo struct p9_conn *conn; 139992b3f1dSTejun Heo wait_queue_t wait; 140992b3f1dSTejun Heo wait_queue_head_t *wait_addr; 141ee443996SEric Van Hensbergen }; 142ee443996SEric Van Hensbergen 143ee443996SEric Van Hensbergen /** 144ee443996SEric Van Hensbergen * struct p9_conn - fd mux connection state information 145ee443996SEric Van Hensbergen * @lock: protects mux_list (?) 146ee443996SEric Van Hensbergen * @mux_list: list link for mux to manage multiple connections (?) 147ee443996SEric Van Hensbergen * @msize: maximum size for connection (dup) 148ee443996SEric Van Hensbergen * @extended: 9p2000.u flag (dup) 149ee443996SEric Van Hensbergen * @trans: reference to transport instance for this connection 150ee443996SEric Van Hensbergen * @tagpool: id accounting for transactions 151ee443996SEric Van Hensbergen * @err: error state 152ee443996SEric Van Hensbergen * @req_list: accounting for requests which have been sent 153ee443996SEric Van Hensbergen * @unsent_req_list: accounting for requests that haven't been sent 154ee443996SEric Van Hensbergen * @rcall: current response &p9_fcall structure 155ee443996SEric Van Hensbergen * @rpos: read position in current frame 156ee443996SEric Van Hensbergen * @rbuf: current read buffer 157ee443996SEric Van Hensbergen * @wpos: write position for current frame 158ee443996SEric Van Hensbergen * @wsize: amount of data to write for current frame 159ee443996SEric Van Hensbergen * @wbuf: current write buffer 160ee443996SEric Van Hensbergen * @poll_wait: array of wait_q's for various worker threads 161ee443996SEric Van Hensbergen * @poll_waddr: ???? 162ee443996SEric Van Hensbergen * @pt: poll state 163ee443996SEric Van Hensbergen * @rq: current read work 164ee443996SEric Van Hensbergen * @wq: current write work 165ee443996SEric Van Hensbergen * @wsched: ???? 166ee443996SEric Van Hensbergen * 167ee443996SEric Van Hensbergen */ 1688a0dc95fSEric Van Hensbergen 1698a0dc95fSEric Van Hensbergen struct p9_conn { 1708a0dc95fSEric Van Hensbergen spinlock_t lock; /* protect lock structure */ 1718a0dc95fSEric Van Hensbergen struct list_head mux_list; 1728a0dc95fSEric Van Hensbergen int msize; 1738a0dc95fSEric Van Hensbergen unsigned char extended; 1748a0dc95fSEric Van Hensbergen struct p9_trans *trans; 1758a0dc95fSEric Van Hensbergen struct p9_idpool *tagpool; 1768a0dc95fSEric Van Hensbergen int err; 1778a0dc95fSEric Van Hensbergen struct list_head req_list; 1788a0dc95fSEric Van Hensbergen struct list_head unsent_req_list; 1798a0dc95fSEric Van Hensbergen struct p9_fcall *rcall; 1808a0dc95fSEric Van Hensbergen int rpos; 1818a0dc95fSEric Van Hensbergen char *rbuf; 1828a0dc95fSEric Van Hensbergen int wpos; 1838a0dc95fSEric Van Hensbergen int wsize; 1848a0dc95fSEric Van Hensbergen char *wbuf; 185992b3f1dSTejun Heo struct list_head poll_pending_link; 186992b3f1dSTejun Heo struct p9_poll_wait poll_wait[MAXPOLLWADDR]; 1878a0dc95fSEric Van Hensbergen poll_table pt; 1888a0dc95fSEric Van Hensbergen struct work_struct rq; 1898a0dc95fSEric Van Hensbergen struct work_struct wq; 1908a0dc95fSEric Van Hensbergen unsigned long wsched; 1918a0dc95fSEric Van Hensbergen }; 1928a0dc95fSEric Van Hensbergen 193ee443996SEric Van Hensbergen /** 194ee443996SEric Van Hensbergen * struct p9_mux_rpc - fd mux rpc accounting structure 195ee443996SEric Van Hensbergen * @m: connection this request was issued on 196ee443996SEric Van Hensbergen * @err: error state 197ee443996SEric Van Hensbergen * @tcall: request &p9_fcall 198ee443996SEric Van Hensbergen * @rcall: response &p9_fcall 199ee443996SEric Van Hensbergen * @wqueue: wait queue that client is blocked on for this rpc 200ee443996SEric Van Hensbergen * 201ee443996SEric Van Hensbergen * Bug: isn't this information duplicated elsewhere like &p9_req 202ee443996SEric Van Hensbergen */ 2038a0dc95fSEric Van Hensbergen 2048a0dc95fSEric Van Hensbergen struct p9_mux_rpc { 2058a0dc95fSEric Van Hensbergen struct p9_conn *m; 2068a0dc95fSEric Van Hensbergen int err; 2078a0dc95fSEric Van Hensbergen struct p9_fcall *tcall; 2088a0dc95fSEric Van Hensbergen struct p9_fcall *rcall; 2098a0dc95fSEric Van Hensbergen wait_queue_head_t wqueue; 2108a0dc95fSEric Van Hensbergen }; 2118a0dc95fSEric Van Hensbergen 2128a0dc95fSEric Van Hensbergen static int p9_poll_proc(void *); 2138a0dc95fSEric Van Hensbergen static void p9_read_work(struct work_struct *work); 2148a0dc95fSEric Van Hensbergen static void p9_write_work(struct work_struct *work); 2158a0dc95fSEric Van Hensbergen static void p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, 2168a0dc95fSEric Van Hensbergen poll_table *p); 2178a0dc95fSEric Van Hensbergen static int p9_fd_write(struct p9_trans *trans, void *v, int len); 2188a0dc95fSEric Van Hensbergen static int p9_fd_read(struct p9_trans *trans, void *v, int len); 2198a0dc95fSEric Van Hensbergen 220992b3f1dSTejun Heo static DEFINE_SPINLOCK(p9_poll_lock); 221992b3f1dSTejun Heo static LIST_HEAD(p9_poll_pending_list); 2228a0dc95fSEric Van Hensbergen static struct workqueue_struct *p9_mux_wq; 223992b3f1dSTejun Heo static struct task_struct *p9_poll_task; 2248a0dc95fSEric Van Hensbergen 2258a0dc95fSEric Van Hensbergen static void p9_conn_destroy(struct p9_conn *); 2268a0dc95fSEric Van Hensbergen static unsigned int p9_fd_poll(struct p9_trans *trans, 2278a0dc95fSEric Van Hensbergen struct poll_table_struct *pt); 2288a0dc95fSEric Van Hensbergen 2298a0dc95fSEric Van Hensbergen #ifdef P9_NONBLOCK 2308a0dc95fSEric Van Hensbergen static int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc, 2318a0dc95fSEric Van Hensbergen p9_conn_req_callback cb, void *a); 2328a0dc95fSEric Van Hensbergen #endif /* P9_NONBLOCK */ 2338a0dc95fSEric Van Hensbergen 2348a0dc95fSEric Van Hensbergen static void p9_conn_cancel(struct p9_conn *m, int err); 2358a0dc95fSEric Van Hensbergen 2368a0dc95fSEric Van Hensbergen static u16 p9_mux_get_tag(struct p9_conn *m) 2378a0dc95fSEric Van Hensbergen { 2388a0dc95fSEric Van Hensbergen int tag; 2398a0dc95fSEric Van Hensbergen 2408a0dc95fSEric Van Hensbergen tag = p9_idpool_get(m->tagpool); 2418a0dc95fSEric Van Hensbergen if (tag < 0) 2428a0dc95fSEric Van Hensbergen return P9_NOTAG; 2438a0dc95fSEric Van Hensbergen else 2448a0dc95fSEric Van Hensbergen return (u16) tag; 2458a0dc95fSEric Van Hensbergen } 2468a0dc95fSEric Van Hensbergen 2478a0dc95fSEric Van Hensbergen static void p9_mux_put_tag(struct p9_conn *m, u16 tag) 2488a0dc95fSEric Van Hensbergen { 2498a0dc95fSEric Van Hensbergen if (tag != P9_NOTAG && p9_idpool_check(tag, m->tagpool)) 2508a0dc95fSEric Van Hensbergen p9_idpool_put(tag, m->tagpool); 2518a0dc95fSEric Van Hensbergen } 2528a0dc95fSEric Van Hensbergen 2538a0dc95fSEric Van Hensbergen static void p9_mux_poll_stop(struct p9_conn *m) 2548a0dc95fSEric Van Hensbergen { 255992b3f1dSTejun Heo unsigned long flags; 2568a0dc95fSEric Van Hensbergen int i; 2578a0dc95fSEric Van Hensbergen 258992b3f1dSTejun Heo for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { 259992b3f1dSTejun Heo struct p9_poll_wait *pwait = &m->poll_wait[i]; 260992b3f1dSTejun Heo 261992b3f1dSTejun Heo if (pwait->wait_addr) { 262992b3f1dSTejun Heo remove_wait_queue(pwait->wait_addr, &pwait->wait); 263992b3f1dSTejun Heo pwait->wait_addr = NULL; 2648a0dc95fSEric Van Hensbergen } 2658a0dc95fSEric Van Hensbergen } 266992b3f1dSTejun Heo 267992b3f1dSTejun Heo spin_lock_irqsave(&p9_poll_lock, flags); 268992b3f1dSTejun Heo list_del_init(&m->poll_pending_link); 269992b3f1dSTejun Heo spin_unlock_irqrestore(&p9_poll_lock, flags); 2708a0dc95fSEric Van Hensbergen } 2718a0dc95fSEric Van Hensbergen 2728a0dc95fSEric Van Hensbergen /** 2738a0dc95fSEric Van Hensbergen * p9_conn_create - allocate and initialize the per-session mux data 274ee443996SEric Van Hensbergen * @trans: transport structure 2758a0dc95fSEric Van Hensbergen * 276ee443996SEric Van Hensbergen * Note: Creates the polling task if this is the first session. 2778a0dc95fSEric Van Hensbergen */ 278ee443996SEric Van Hensbergen 2798a0dc95fSEric Van Hensbergen static struct p9_conn *p9_conn_create(struct p9_trans *trans) 2808a0dc95fSEric Van Hensbergen { 2818a0dc95fSEric Van Hensbergen int i, n; 282571ffeafSTejun Heo struct p9_conn *m; 2838a0dc95fSEric Van Hensbergen 2848a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "transport %p msize %d\n", trans, 2858a0dc95fSEric Van Hensbergen trans->msize); 286571ffeafSTejun Heo m = kzalloc(sizeof(struct p9_conn), GFP_KERNEL); 2878a0dc95fSEric Van Hensbergen if (!m) 2888a0dc95fSEric Van Hensbergen return ERR_PTR(-ENOMEM); 2898a0dc95fSEric Van Hensbergen 2908a0dc95fSEric Van Hensbergen spin_lock_init(&m->lock); 2918a0dc95fSEric Van Hensbergen INIT_LIST_HEAD(&m->mux_list); 2928a0dc95fSEric Van Hensbergen m->msize = trans->msize; 2938a0dc95fSEric Van Hensbergen m->extended = trans->extended; 2948a0dc95fSEric Van Hensbergen m->trans = trans; 2958a0dc95fSEric Van Hensbergen m->tagpool = p9_idpool_create(); 2968a0dc95fSEric Van Hensbergen if (IS_ERR(m->tagpool)) { 2978a0dc95fSEric Van Hensbergen kfree(m); 298571ffeafSTejun Heo return ERR_PTR(-ENOMEM); 2998a0dc95fSEric Van Hensbergen } 3008a0dc95fSEric Van Hensbergen 3018a0dc95fSEric Van Hensbergen INIT_LIST_HEAD(&m->req_list); 3028a0dc95fSEric Van Hensbergen INIT_LIST_HEAD(&m->unsent_req_list); 3038a0dc95fSEric Van Hensbergen INIT_WORK(&m->rq, p9_read_work); 3048a0dc95fSEric Van Hensbergen INIT_WORK(&m->wq, p9_write_work); 305992b3f1dSTejun Heo INIT_LIST_HEAD(&m->poll_pending_link); 306992b3f1dSTejun Heo init_poll_funcptr(&m->pt, p9_pollwait); 3078a0dc95fSEric Van Hensbergen 3088a0dc95fSEric Van Hensbergen n = p9_fd_poll(trans, &m->pt); 3098a0dc95fSEric Van Hensbergen if (n & POLLIN) { 3108a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m); 3118a0dc95fSEric Van Hensbergen set_bit(Rpending, &m->wsched); 3128a0dc95fSEric Van Hensbergen } 3138a0dc95fSEric Van Hensbergen 3148a0dc95fSEric Van Hensbergen if (n & POLLOUT) { 3158a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m); 3168a0dc95fSEric Van Hensbergen set_bit(Wpending, &m->wsched); 3178a0dc95fSEric Van Hensbergen } 3188a0dc95fSEric Van Hensbergen 319992b3f1dSTejun Heo for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { 320992b3f1dSTejun Heo if (IS_ERR(m->poll_wait[i].wait_addr)) { 3218a0dc95fSEric Van Hensbergen p9_mux_poll_stop(m); 3228a0dc95fSEric Van Hensbergen kfree(m); 323992b3f1dSTejun Heo /* return the error code */ 324992b3f1dSTejun Heo return (void *)m->poll_wait[i].wait_addr; 3258a0dc95fSEric Van Hensbergen } 3268a0dc95fSEric Van Hensbergen } 3278a0dc95fSEric Van Hensbergen 3288a0dc95fSEric Van Hensbergen return m; 3298a0dc95fSEric Van Hensbergen } 3308a0dc95fSEric Van Hensbergen 3318a0dc95fSEric Van Hensbergen /** 3328a0dc95fSEric Van Hensbergen * p9_mux_destroy - cancels all pending requests and frees mux resources 333ee443996SEric Van Hensbergen * @m: mux to destroy 334ee443996SEric Van Hensbergen * 3358a0dc95fSEric Van Hensbergen */ 336ee443996SEric Van Hensbergen 3378a0dc95fSEric Van Hensbergen static void p9_conn_destroy(struct p9_conn *m) 3388a0dc95fSEric Van Hensbergen { 3398a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m, 3408a0dc95fSEric Van Hensbergen m->mux_list.prev, m->mux_list.next); 3418a0dc95fSEric Van Hensbergen 3428a0dc95fSEric Van Hensbergen p9_mux_poll_stop(m); 3437dc5d24bSTejun Heo cancel_work_sync(&m->rq); 3447dc5d24bSTejun Heo cancel_work_sync(&m->wq); 3457dc5d24bSTejun Heo 3467dc5d24bSTejun Heo p9_conn_cancel(m, -ECONNRESET); 3477dc5d24bSTejun Heo 3488a0dc95fSEric Van Hensbergen m->trans = NULL; 3498a0dc95fSEric Van Hensbergen p9_idpool_destroy(m->tagpool); 3508a0dc95fSEric Van Hensbergen kfree(m); 3518a0dc95fSEric Van Hensbergen } 3528a0dc95fSEric Van Hensbergen 353992b3f1dSTejun Heo static int p9_pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) 354992b3f1dSTejun Heo { 355992b3f1dSTejun Heo struct p9_poll_wait *pwait = 356992b3f1dSTejun Heo container_of(wait, struct p9_poll_wait, wait); 357992b3f1dSTejun Heo struct p9_conn *m = pwait->conn; 358992b3f1dSTejun Heo unsigned long flags; 359992b3f1dSTejun Heo DECLARE_WAITQUEUE(dummy_wait, p9_poll_task); 360992b3f1dSTejun Heo 361992b3f1dSTejun Heo spin_lock_irqsave(&p9_poll_lock, flags); 362992b3f1dSTejun Heo if (list_empty(&m->poll_pending_link)) 363992b3f1dSTejun Heo list_add_tail(&m->poll_pending_link, &p9_poll_pending_list); 364992b3f1dSTejun Heo spin_unlock_irqrestore(&p9_poll_lock, flags); 365992b3f1dSTejun Heo 366992b3f1dSTejun Heo /* perform the default wake up operation */ 367992b3f1dSTejun Heo return default_wake_function(&dummy_wait, mode, sync, key); 368992b3f1dSTejun Heo } 369992b3f1dSTejun Heo 3708a0dc95fSEric Van Hensbergen /** 371ee443996SEric Van Hensbergen * p9_pollwait - add poll task to the wait queue 372ee443996SEric Van Hensbergen * @filp: file pointer being polled 373ee443996SEric Van Hensbergen * @wait_address: wait_q to block on 374ee443996SEric Van Hensbergen * @p: poll state 375ee443996SEric Van Hensbergen * 376ee443996SEric Van Hensbergen * called by files poll operation to add v9fs-poll task to files wait queue 3778a0dc95fSEric Van Hensbergen */ 378ee443996SEric Van Hensbergen 3798a0dc95fSEric Van Hensbergen static void 3808a0dc95fSEric Van Hensbergen p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p) 3818a0dc95fSEric Van Hensbergen { 382992b3f1dSTejun Heo struct p9_conn *m = container_of(p, struct p9_conn, pt); 383992b3f1dSTejun Heo struct p9_poll_wait *pwait = NULL; 3848a0dc95fSEric Van Hensbergen int i; 3858a0dc95fSEric Van Hensbergen 386992b3f1dSTejun Heo for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { 387992b3f1dSTejun Heo if (m->poll_wait[i].wait_addr == NULL) { 388992b3f1dSTejun Heo pwait = &m->poll_wait[i]; 3898a0dc95fSEric Van Hensbergen break; 390992b3f1dSTejun Heo } 391992b3f1dSTejun Heo } 3928a0dc95fSEric Van Hensbergen 393992b3f1dSTejun Heo if (!pwait) { 3948a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n"); 3958a0dc95fSEric Van Hensbergen return; 3968a0dc95fSEric Van Hensbergen } 3978a0dc95fSEric Van Hensbergen 3988a0dc95fSEric Van Hensbergen if (!wait_address) { 3998a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, "no wait_address\n"); 400992b3f1dSTejun Heo pwait->wait_addr = ERR_PTR(-EIO); 4018a0dc95fSEric Van Hensbergen return; 4028a0dc95fSEric Van Hensbergen } 4038a0dc95fSEric Van Hensbergen 404992b3f1dSTejun Heo pwait->conn = m; 405992b3f1dSTejun Heo pwait->wait_addr = wait_address; 406992b3f1dSTejun Heo init_waitqueue_func_entry(&pwait->wait, p9_pollwake); 407992b3f1dSTejun Heo add_wait_queue(wait_address, &pwait->wait); 4088a0dc95fSEric Van Hensbergen } 4098a0dc95fSEric Van Hensbergen 4108a0dc95fSEric Van Hensbergen /** 4118a0dc95fSEric Van Hensbergen * p9_poll_mux - polls a mux and schedules read or write works if necessary 412ee443996SEric Van Hensbergen * @m: connection to poll 413ee443996SEric Van Hensbergen * 4148a0dc95fSEric Van Hensbergen */ 415ee443996SEric Van Hensbergen 4168a0dc95fSEric Van Hensbergen static void p9_poll_mux(struct p9_conn *m) 4178a0dc95fSEric Van Hensbergen { 4188a0dc95fSEric Van Hensbergen int n; 4198a0dc95fSEric Van Hensbergen 4208a0dc95fSEric Van Hensbergen if (m->err < 0) 4218a0dc95fSEric Van Hensbergen return; 4228a0dc95fSEric Van Hensbergen 4238a0dc95fSEric Van Hensbergen n = p9_fd_poll(m->trans, NULL); 4248a0dc95fSEric Van Hensbergen if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) { 4258a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "error mux %p err %d\n", m, n); 4268a0dc95fSEric Van Hensbergen if (n >= 0) 4278a0dc95fSEric Van Hensbergen n = -ECONNRESET; 4288a0dc95fSEric Van Hensbergen p9_conn_cancel(m, n); 4298a0dc95fSEric Van Hensbergen } 4308a0dc95fSEric Van Hensbergen 4318a0dc95fSEric Van Hensbergen if (n & POLLIN) { 4328a0dc95fSEric Van Hensbergen set_bit(Rpending, &m->wsched); 4338a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m); 4348a0dc95fSEric Van Hensbergen if (!test_and_set_bit(Rworksched, &m->wsched)) { 4358a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m); 4368a0dc95fSEric Van Hensbergen queue_work(p9_mux_wq, &m->rq); 4378a0dc95fSEric Van Hensbergen } 4388a0dc95fSEric Van Hensbergen } 4398a0dc95fSEric Van Hensbergen 4408a0dc95fSEric Van Hensbergen if (n & POLLOUT) { 4418a0dc95fSEric Van Hensbergen set_bit(Wpending, &m->wsched); 4428a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m); 4438a0dc95fSEric Van Hensbergen if ((m->wsize || !list_empty(&m->unsent_req_list)) 4448a0dc95fSEric Van Hensbergen && !test_and_set_bit(Wworksched, &m->wsched)) { 4458a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m); 4468a0dc95fSEric Van Hensbergen queue_work(p9_mux_wq, &m->wq); 4478a0dc95fSEric Van Hensbergen } 4488a0dc95fSEric Van Hensbergen } 4498a0dc95fSEric Van Hensbergen } 4508a0dc95fSEric Van Hensbergen 4518a0dc95fSEric Van Hensbergen /** 452ee443996SEric Van Hensbergen * p9_poll_proc - poll worker thread 453ee443996SEric Van Hensbergen * @a: thread state and arguments 454ee443996SEric Van Hensbergen * 455ee443996SEric Van Hensbergen * polls all v9fs transports for new events and queues the appropriate 456ee443996SEric Van Hensbergen * work to the work queue 457ee443996SEric Van Hensbergen * 4588a0dc95fSEric Van Hensbergen */ 459ee443996SEric Van Hensbergen 4608a0dc95fSEric Van Hensbergen static int p9_poll_proc(void *a) 4618a0dc95fSEric Van Hensbergen { 462992b3f1dSTejun Heo unsigned long flags; 4638a0dc95fSEric Van Hensbergen 464992b3f1dSTejun Heo P9_DPRINTK(P9_DEBUG_MUX, "start %p\n", current); 465992b3f1dSTejun Heo repeat: 466992b3f1dSTejun Heo spin_lock_irqsave(&p9_poll_lock, flags); 467992b3f1dSTejun Heo while (!list_empty(&p9_poll_pending_list)) { 468992b3f1dSTejun Heo struct p9_conn *conn = list_first_entry(&p9_poll_pending_list, 469992b3f1dSTejun Heo struct p9_conn, 470992b3f1dSTejun Heo poll_pending_link); 471992b3f1dSTejun Heo list_del_init(&conn->poll_pending_link); 472992b3f1dSTejun Heo spin_unlock_irqrestore(&p9_poll_lock, flags); 473992b3f1dSTejun Heo 474992b3f1dSTejun Heo p9_poll_mux(conn); 475992b3f1dSTejun Heo 476992b3f1dSTejun Heo spin_lock_irqsave(&p9_poll_lock, flags); 477992b3f1dSTejun Heo } 478992b3f1dSTejun Heo spin_unlock_irqrestore(&p9_poll_lock, flags); 479992b3f1dSTejun Heo 4808a0dc95fSEric Van Hensbergen set_current_state(TASK_INTERRUPTIBLE); 481992b3f1dSTejun Heo if (list_empty(&p9_poll_pending_list)) { 4828a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n"); 483992b3f1dSTejun Heo schedule(); 4848a0dc95fSEric Van Hensbergen } 4858a0dc95fSEric Van Hensbergen __set_current_state(TASK_RUNNING); 486992b3f1dSTejun Heo 487992b3f1dSTejun Heo if (!kthread_should_stop()) 488992b3f1dSTejun Heo goto repeat; 489992b3f1dSTejun Heo 4908a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "finish\n"); 4918a0dc95fSEric Van Hensbergen return 0; 4928a0dc95fSEric Van Hensbergen } 4938a0dc95fSEric Van Hensbergen 4948a0dc95fSEric Van Hensbergen /** 4958a0dc95fSEric Van Hensbergen * p9_write_work - called when a transport can send some data 496ee443996SEric Van Hensbergen * @work: container for work to be done 497ee443996SEric Van Hensbergen * 4988a0dc95fSEric Van Hensbergen */ 499ee443996SEric Van Hensbergen 5008a0dc95fSEric Van Hensbergen static void p9_write_work(struct work_struct *work) 5018a0dc95fSEric Van Hensbergen { 5028a0dc95fSEric Van Hensbergen int n, err; 5038a0dc95fSEric Van Hensbergen struct p9_conn *m; 5048a0dc95fSEric Van Hensbergen struct p9_req *req; 5058a0dc95fSEric Van Hensbergen 5068a0dc95fSEric Van Hensbergen m = container_of(work, struct p9_conn, wq); 5078a0dc95fSEric Van Hensbergen 5088a0dc95fSEric Van Hensbergen if (m->err < 0) { 5098a0dc95fSEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 5108a0dc95fSEric Van Hensbergen return; 5118a0dc95fSEric Van Hensbergen } 5128a0dc95fSEric Van Hensbergen 5138a0dc95fSEric Van Hensbergen if (!m->wsize) { 5148a0dc95fSEric Van Hensbergen if (list_empty(&m->unsent_req_list)) { 5158a0dc95fSEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 5168a0dc95fSEric Van Hensbergen return; 5178a0dc95fSEric Van Hensbergen } 5188a0dc95fSEric Van Hensbergen 5198a0dc95fSEric Van Hensbergen spin_lock(&m->lock); 5208a0dc95fSEric Van Hensbergen again: 5218a0dc95fSEric Van Hensbergen req = list_entry(m->unsent_req_list.next, struct p9_req, 5228a0dc95fSEric Van Hensbergen req_list); 5238a0dc95fSEric Van Hensbergen list_move_tail(&req->req_list, &m->req_list); 5248a0dc95fSEric Van Hensbergen if (req->err == ERREQFLUSH) 5258a0dc95fSEric Van Hensbergen goto again; 5268a0dc95fSEric Van Hensbergen 5278a0dc95fSEric Van Hensbergen m->wbuf = req->tcall->sdata; 5288a0dc95fSEric Van Hensbergen m->wsize = req->tcall->size; 5298a0dc95fSEric Van Hensbergen m->wpos = 0; 5308a0dc95fSEric Van Hensbergen spin_unlock(&m->lock); 5318a0dc95fSEric Van Hensbergen } 5328a0dc95fSEric Van Hensbergen 5338a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos, 5348a0dc95fSEric Van Hensbergen m->wsize); 5358a0dc95fSEric Van Hensbergen clear_bit(Wpending, &m->wsched); 5368a0dc95fSEric Van Hensbergen err = p9_fd_write(m->trans, m->wbuf + m->wpos, m->wsize - m->wpos); 5378a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "mux %p sent %d bytes\n", m, err); 5388a0dc95fSEric Van Hensbergen if (err == -EAGAIN) { 5398a0dc95fSEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 5408a0dc95fSEric Van Hensbergen return; 5418a0dc95fSEric Van Hensbergen } 5428a0dc95fSEric Van Hensbergen 5438a0dc95fSEric Van Hensbergen if (err < 0) 5448a0dc95fSEric Van Hensbergen goto error; 5458a0dc95fSEric Van Hensbergen else if (err == 0) { 5468a0dc95fSEric Van Hensbergen err = -EREMOTEIO; 5478a0dc95fSEric Van Hensbergen goto error; 5488a0dc95fSEric Van Hensbergen } 5498a0dc95fSEric Van Hensbergen 5508a0dc95fSEric Van Hensbergen m->wpos += err; 5518a0dc95fSEric Van Hensbergen if (m->wpos == m->wsize) 5528a0dc95fSEric Van Hensbergen m->wpos = m->wsize = 0; 5538a0dc95fSEric Van Hensbergen 5548a0dc95fSEric Van Hensbergen if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) { 5558a0dc95fSEric Van Hensbergen if (test_and_clear_bit(Wpending, &m->wsched)) 5568a0dc95fSEric Van Hensbergen n = POLLOUT; 5578a0dc95fSEric Van Hensbergen else 5588a0dc95fSEric Van Hensbergen n = p9_fd_poll(m->trans, NULL); 5598a0dc95fSEric Van Hensbergen 5608a0dc95fSEric Van Hensbergen if (n & POLLOUT) { 5618a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m); 5628a0dc95fSEric Van Hensbergen queue_work(p9_mux_wq, &m->wq); 5638a0dc95fSEric Van Hensbergen } else 5648a0dc95fSEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 5658a0dc95fSEric Van Hensbergen } else 5668a0dc95fSEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 5678a0dc95fSEric Van Hensbergen 5688a0dc95fSEric Van Hensbergen return; 5698a0dc95fSEric Van Hensbergen 5708a0dc95fSEric Van Hensbergen error: 5718a0dc95fSEric Van Hensbergen p9_conn_cancel(m, err); 5728a0dc95fSEric Van Hensbergen clear_bit(Wworksched, &m->wsched); 5738a0dc95fSEric Van Hensbergen } 5748a0dc95fSEric Van Hensbergen 5758a0dc95fSEric Van Hensbergen static void process_request(struct p9_conn *m, struct p9_req *req) 5768a0dc95fSEric Van Hensbergen { 5778a0dc95fSEric Van Hensbergen int ecode; 5788a0dc95fSEric Van Hensbergen struct p9_str *ename; 5798a0dc95fSEric Van Hensbergen 5808a0dc95fSEric Van Hensbergen if (!req->err && req->rcall->id == P9_RERROR) { 5818a0dc95fSEric Van Hensbergen ecode = req->rcall->params.rerror.errno; 5828a0dc95fSEric Van Hensbergen ename = &req->rcall->params.rerror.error; 5838a0dc95fSEric Van Hensbergen 5848a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len, 5858a0dc95fSEric Van Hensbergen ename->str); 5868a0dc95fSEric Van Hensbergen 5878a0dc95fSEric Van Hensbergen if (m->extended) 5888a0dc95fSEric Van Hensbergen req->err = -ecode; 5898a0dc95fSEric Van Hensbergen 5908a0dc95fSEric Van Hensbergen if (!req->err) { 5918a0dc95fSEric Van Hensbergen req->err = p9_errstr2errno(ename->str, ename->len); 5928a0dc95fSEric Van Hensbergen 5938a0dc95fSEric Van Hensbergen /* string match failed */ 5948a0dc95fSEric Van Hensbergen if (!req->err) { 5958a0dc95fSEric Van Hensbergen PRINT_FCALL_ERROR("unknown error", req->rcall); 5968a0dc95fSEric Van Hensbergen req->err = -ESERVERFAULT; 5978a0dc95fSEric Van Hensbergen } 5988a0dc95fSEric Van Hensbergen } 5998a0dc95fSEric Van Hensbergen } else if (req->tcall && req->rcall->id != req->tcall->id + 1) { 6008a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, 6018a0dc95fSEric Van Hensbergen "fcall mismatch: expected %d, got %d\n", 6028a0dc95fSEric Van Hensbergen req->tcall->id + 1, req->rcall->id); 6038a0dc95fSEric Van Hensbergen if (!req->err) 6048a0dc95fSEric Van Hensbergen req->err = -EIO; 6058a0dc95fSEric Van Hensbergen } 6068a0dc95fSEric Van Hensbergen } 6078a0dc95fSEric Van Hensbergen 6088a0dc95fSEric Van Hensbergen /** 6098a0dc95fSEric Van Hensbergen * p9_read_work - called when there is some data to be read from a transport 610ee443996SEric Van Hensbergen * @work: container of work to be done 611ee443996SEric Van Hensbergen * 6128a0dc95fSEric Van Hensbergen */ 613ee443996SEric Van Hensbergen 6148a0dc95fSEric Van Hensbergen static void p9_read_work(struct work_struct *work) 6158a0dc95fSEric Van Hensbergen { 6168a0dc95fSEric Van Hensbergen int n, err; 6178a0dc95fSEric Van Hensbergen struct p9_conn *m; 6188a0dc95fSEric Van Hensbergen struct p9_req *req, *rptr, *rreq; 6198a0dc95fSEric Van Hensbergen struct p9_fcall *rcall; 6208a0dc95fSEric Van Hensbergen char *rbuf; 6218a0dc95fSEric Van Hensbergen 6228a0dc95fSEric Van Hensbergen m = container_of(work, struct p9_conn, rq); 6238a0dc95fSEric Van Hensbergen 6248a0dc95fSEric Van Hensbergen if (m->err < 0) 6258a0dc95fSEric Van Hensbergen return; 6268a0dc95fSEric Van Hensbergen 6278a0dc95fSEric Van Hensbergen rcall = NULL; 6288a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos); 6298a0dc95fSEric Van Hensbergen 6308a0dc95fSEric Van Hensbergen if (!m->rcall) { 6318a0dc95fSEric Van Hensbergen m->rcall = 6328a0dc95fSEric Van Hensbergen kmalloc(sizeof(struct p9_fcall) + m->msize, GFP_KERNEL); 6338a0dc95fSEric Van Hensbergen if (!m->rcall) { 6348a0dc95fSEric Van Hensbergen err = -ENOMEM; 6358a0dc95fSEric Van Hensbergen goto error; 6368a0dc95fSEric Van Hensbergen } 6378a0dc95fSEric Van Hensbergen 6388a0dc95fSEric Van Hensbergen m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall); 6398a0dc95fSEric Van Hensbergen m->rpos = 0; 6408a0dc95fSEric Van Hensbergen } 6418a0dc95fSEric Van Hensbergen 6428a0dc95fSEric Van Hensbergen clear_bit(Rpending, &m->wsched); 6438a0dc95fSEric Van Hensbergen err = p9_fd_read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos); 6448a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "mux %p got %d bytes\n", m, err); 6458a0dc95fSEric Van Hensbergen if (err == -EAGAIN) { 6468a0dc95fSEric Van Hensbergen clear_bit(Rworksched, &m->wsched); 6478a0dc95fSEric Van Hensbergen return; 6488a0dc95fSEric Van Hensbergen } 6498a0dc95fSEric Van Hensbergen 6508a0dc95fSEric Van Hensbergen if (err <= 0) 6518a0dc95fSEric Van Hensbergen goto error; 6528a0dc95fSEric Van Hensbergen 6538a0dc95fSEric Van Hensbergen m->rpos += err; 6548a0dc95fSEric Van Hensbergen while (m->rpos > 4) { 6558a0dc95fSEric Van Hensbergen n = le32_to_cpu(*(__le32 *) m->rbuf); 6568a0dc95fSEric Van Hensbergen if (n >= m->msize) { 6578a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, 6588a0dc95fSEric Van Hensbergen "requested packet size too big: %d\n", n); 6598a0dc95fSEric Van Hensbergen err = -EIO; 6608a0dc95fSEric Van Hensbergen goto error; 6618a0dc95fSEric Van Hensbergen } 6628a0dc95fSEric Van Hensbergen 6638a0dc95fSEric Van Hensbergen if (m->rpos < n) 6648a0dc95fSEric Van Hensbergen break; 6658a0dc95fSEric Van Hensbergen 6668a0dc95fSEric Van Hensbergen err = 6678a0dc95fSEric Van Hensbergen p9_deserialize_fcall(m->rbuf, n, m->rcall, m->extended); 6688a0dc95fSEric Van Hensbergen if (err < 0) 6698a0dc95fSEric Van Hensbergen goto error; 6708a0dc95fSEric Van Hensbergen 6718a0dc95fSEric Van Hensbergen #ifdef CONFIG_NET_9P_DEBUG 6728a0dc95fSEric Van Hensbergen if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { 6738a0dc95fSEric Van Hensbergen char buf[150]; 6748a0dc95fSEric Van Hensbergen 6758a0dc95fSEric Van Hensbergen p9_printfcall(buf, sizeof(buf), m->rcall, 6768a0dc95fSEric Van Hensbergen m->extended); 6778a0dc95fSEric Van Hensbergen printk(KERN_NOTICE ">>> %p %s\n", m, buf); 6788a0dc95fSEric Van Hensbergen } 6798a0dc95fSEric Van Hensbergen #endif 6808a0dc95fSEric Van Hensbergen 6818a0dc95fSEric Van Hensbergen rcall = m->rcall; 6828a0dc95fSEric Van Hensbergen rbuf = m->rbuf; 6838a0dc95fSEric Van Hensbergen if (m->rpos > n) { 6848a0dc95fSEric Van Hensbergen m->rcall = kmalloc(sizeof(struct p9_fcall) + m->msize, 6858a0dc95fSEric Van Hensbergen GFP_KERNEL); 6868a0dc95fSEric Van Hensbergen if (!m->rcall) { 6878a0dc95fSEric Van Hensbergen err = -ENOMEM; 6888a0dc95fSEric Van Hensbergen goto error; 6898a0dc95fSEric Van Hensbergen } 6908a0dc95fSEric Van Hensbergen 6918a0dc95fSEric Van Hensbergen m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall); 6928a0dc95fSEric Van Hensbergen memmove(m->rbuf, rbuf + n, m->rpos - n); 6938a0dc95fSEric Van Hensbergen m->rpos -= n; 6948a0dc95fSEric Van Hensbergen } else { 6958a0dc95fSEric Van Hensbergen m->rcall = NULL; 6968a0dc95fSEric Van Hensbergen m->rbuf = NULL; 6978a0dc95fSEric Van Hensbergen m->rpos = 0; 6988a0dc95fSEric Van Hensbergen } 6998a0dc95fSEric Van Hensbergen 7008a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, 7018a0dc95fSEric Van Hensbergen rcall->id, rcall->tag); 7028a0dc95fSEric Van Hensbergen 7038a0dc95fSEric Van Hensbergen req = NULL; 7048a0dc95fSEric Van Hensbergen spin_lock(&m->lock); 7058a0dc95fSEric Van Hensbergen list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) { 7068a0dc95fSEric Van Hensbergen if (rreq->tag == rcall->tag) { 7078a0dc95fSEric Van Hensbergen req = rreq; 7088a0dc95fSEric Van Hensbergen if (req->flush != Flushing) 7098a0dc95fSEric Van Hensbergen list_del(&req->req_list); 7108a0dc95fSEric Van Hensbergen break; 7118a0dc95fSEric Van Hensbergen } 7128a0dc95fSEric Van Hensbergen } 7138a0dc95fSEric Van Hensbergen spin_unlock(&m->lock); 7148a0dc95fSEric Van Hensbergen 7158a0dc95fSEric Van Hensbergen if (req) { 7168a0dc95fSEric Van Hensbergen req->rcall = rcall; 7178a0dc95fSEric Van Hensbergen process_request(m, req); 7188a0dc95fSEric Van Hensbergen 7198a0dc95fSEric Van Hensbergen if (req->flush != Flushing) { 7208a0dc95fSEric Van Hensbergen if (req->cb) 7218a0dc95fSEric Van Hensbergen (*req->cb) (req, req->cba); 7228a0dc95fSEric Van Hensbergen else 7238a0dc95fSEric Van Hensbergen kfree(req->rcall); 7248a0dc95fSEric Van Hensbergen } 7258a0dc95fSEric Van Hensbergen } else { 7268a0dc95fSEric Van Hensbergen if (err >= 0 && rcall->id != P9_RFLUSH) 7278a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, 7288a0dc95fSEric Van Hensbergen "unexpected response mux %p id %d tag %d\n", 7298a0dc95fSEric Van Hensbergen m, rcall->id, rcall->tag); 7308a0dc95fSEric Van Hensbergen kfree(rcall); 7318a0dc95fSEric Van Hensbergen } 7328a0dc95fSEric Van Hensbergen } 7338a0dc95fSEric Van Hensbergen 7348a0dc95fSEric Van Hensbergen if (!list_empty(&m->req_list)) { 7358a0dc95fSEric Van Hensbergen if (test_and_clear_bit(Rpending, &m->wsched)) 7368a0dc95fSEric Van Hensbergen n = POLLIN; 7378a0dc95fSEric Van Hensbergen else 7388a0dc95fSEric Van Hensbergen n = p9_fd_poll(m->trans, NULL); 7398a0dc95fSEric Van Hensbergen 7408a0dc95fSEric Van Hensbergen if (n & POLLIN) { 7418a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m); 7428a0dc95fSEric Van Hensbergen queue_work(p9_mux_wq, &m->rq); 7438a0dc95fSEric Van Hensbergen } else 7448a0dc95fSEric Van Hensbergen clear_bit(Rworksched, &m->wsched); 7458a0dc95fSEric Van Hensbergen } else 7468a0dc95fSEric Van Hensbergen clear_bit(Rworksched, &m->wsched); 7478a0dc95fSEric Van Hensbergen 7488a0dc95fSEric Van Hensbergen return; 7498a0dc95fSEric Van Hensbergen 7508a0dc95fSEric Van Hensbergen error: 7518a0dc95fSEric Van Hensbergen p9_conn_cancel(m, err); 7528a0dc95fSEric Van Hensbergen clear_bit(Rworksched, &m->wsched); 7538a0dc95fSEric Van Hensbergen } 7548a0dc95fSEric Van Hensbergen 7558a0dc95fSEric Van Hensbergen /** 7568a0dc95fSEric Van Hensbergen * p9_send_request - send 9P request 7578a0dc95fSEric Van Hensbergen * The function can sleep until the request is scheduled for sending. 7588a0dc95fSEric Van Hensbergen * The function can be interrupted. Return from the function is not 7598a0dc95fSEric Van Hensbergen * a guarantee that the request is sent successfully. Can return errors 7608a0dc95fSEric Van Hensbergen * that can be retrieved by PTR_ERR macros. 7618a0dc95fSEric Van Hensbergen * 7628a0dc95fSEric Van Hensbergen * @m: mux data 7638a0dc95fSEric Van Hensbergen * @tc: request to be sent 7648a0dc95fSEric Van Hensbergen * @cb: callback function to call when response is received 7658a0dc95fSEric Van Hensbergen * @cba: parameter to pass to the callback function 766ee443996SEric Van Hensbergen * 7678a0dc95fSEric Van Hensbergen */ 768ee443996SEric Van Hensbergen 7698a0dc95fSEric Van Hensbergen static struct p9_req *p9_send_request(struct p9_conn *m, 7708a0dc95fSEric Van Hensbergen struct p9_fcall *tc, 7718a0dc95fSEric Van Hensbergen p9_conn_req_callback cb, void *cba) 7728a0dc95fSEric Van Hensbergen { 7738a0dc95fSEric Van Hensbergen int n; 7748a0dc95fSEric Van Hensbergen struct p9_req *req; 7758a0dc95fSEric Van Hensbergen 7768a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current, 7778a0dc95fSEric Van Hensbergen tc, tc->id); 7788a0dc95fSEric Van Hensbergen if (m->err < 0) 7798a0dc95fSEric Van Hensbergen return ERR_PTR(m->err); 7808a0dc95fSEric Van Hensbergen 7818a0dc95fSEric Van Hensbergen req = kmalloc(sizeof(struct p9_req), GFP_KERNEL); 7828a0dc95fSEric Van Hensbergen if (!req) 7838a0dc95fSEric Van Hensbergen return ERR_PTR(-ENOMEM); 7848a0dc95fSEric Van Hensbergen 7858a0dc95fSEric Van Hensbergen if (tc->id == P9_TVERSION) 7868a0dc95fSEric Van Hensbergen n = P9_NOTAG; 7878a0dc95fSEric Van Hensbergen else 7888a0dc95fSEric Van Hensbergen n = p9_mux_get_tag(m); 7898a0dc95fSEric Van Hensbergen 79062067824SJulia Lawall if (n < 0) { 79162067824SJulia Lawall kfree(req); 7928a0dc95fSEric Van Hensbergen return ERR_PTR(-ENOMEM); 79362067824SJulia Lawall } 7948a0dc95fSEric Van Hensbergen 7958a0dc95fSEric Van Hensbergen p9_set_tag(tc, n); 7968a0dc95fSEric Van Hensbergen 7978a0dc95fSEric Van Hensbergen #ifdef CONFIG_NET_9P_DEBUG 7988a0dc95fSEric Van Hensbergen if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) { 7998a0dc95fSEric Van Hensbergen char buf[150]; 8008a0dc95fSEric Van Hensbergen 8018a0dc95fSEric Van Hensbergen p9_printfcall(buf, sizeof(buf), tc, m->extended); 8028a0dc95fSEric Van Hensbergen printk(KERN_NOTICE "<<< %p %s\n", m, buf); 8038a0dc95fSEric Van Hensbergen } 8048a0dc95fSEric Van Hensbergen #endif 8058a0dc95fSEric Van Hensbergen 8068a0dc95fSEric Van Hensbergen spin_lock_init(&req->lock); 8078a0dc95fSEric Van Hensbergen req->tag = n; 8088a0dc95fSEric Van Hensbergen req->tcall = tc; 8098a0dc95fSEric Van Hensbergen req->rcall = NULL; 8108a0dc95fSEric Van Hensbergen req->err = 0; 8118a0dc95fSEric Van Hensbergen req->cb = cb; 8128a0dc95fSEric Van Hensbergen req->cba = cba; 8138a0dc95fSEric Van Hensbergen req->flush = None; 8148a0dc95fSEric Van Hensbergen 8158a0dc95fSEric Van Hensbergen spin_lock(&m->lock); 8168a0dc95fSEric Van Hensbergen list_add_tail(&req->req_list, &m->unsent_req_list); 8178a0dc95fSEric Van Hensbergen spin_unlock(&m->lock); 8188a0dc95fSEric Van Hensbergen 8198a0dc95fSEric Van Hensbergen if (test_and_clear_bit(Wpending, &m->wsched)) 8208a0dc95fSEric Van Hensbergen n = POLLOUT; 8218a0dc95fSEric Van Hensbergen else 8228a0dc95fSEric Van Hensbergen n = p9_fd_poll(m->trans, NULL); 8238a0dc95fSEric Van Hensbergen 8248a0dc95fSEric Van Hensbergen if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched)) 8258a0dc95fSEric Van Hensbergen queue_work(p9_mux_wq, &m->wq); 8268a0dc95fSEric Van Hensbergen 8278a0dc95fSEric Van Hensbergen return req; 8288a0dc95fSEric Van Hensbergen } 8298a0dc95fSEric Van Hensbergen 8308a0dc95fSEric Van Hensbergen static void p9_mux_free_request(struct p9_conn *m, struct p9_req *req) 8318a0dc95fSEric Van Hensbergen { 8328a0dc95fSEric Van Hensbergen p9_mux_put_tag(m, req->tag); 8338a0dc95fSEric Van Hensbergen kfree(req); 8348a0dc95fSEric Van Hensbergen } 8358a0dc95fSEric Van Hensbergen 8368a0dc95fSEric Van Hensbergen static void p9_mux_flush_cb(struct p9_req *freq, void *a) 8378a0dc95fSEric Van Hensbergen { 8388a0dc95fSEric Van Hensbergen int tag; 8398a0dc95fSEric Van Hensbergen struct p9_conn *m; 8408a0dc95fSEric Van Hensbergen struct p9_req *req, *rreq, *rptr; 8418a0dc95fSEric Van Hensbergen 8428a0dc95fSEric Van Hensbergen m = a; 8438a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m, 8448a0dc95fSEric Van Hensbergen freq->tcall, freq->rcall, freq->err, 8458a0dc95fSEric Van Hensbergen freq->tcall->params.tflush.oldtag); 8468a0dc95fSEric Van Hensbergen 8478a0dc95fSEric Van Hensbergen spin_lock(&m->lock); 8488a0dc95fSEric Van Hensbergen tag = freq->tcall->params.tflush.oldtag; 8498a0dc95fSEric Van Hensbergen req = NULL; 8508a0dc95fSEric Van Hensbergen list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) { 8518a0dc95fSEric Van Hensbergen if (rreq->tag == tag) { 8528a0dc95fSEric Van Hensbergen req = rreq; 8538a0dc95fSEric Van Hensbergen list_del(&req->req_list); 8548a0dc95fSEric Van Hensbergen break; 8558a0dc95fSEric Van Hensbergen } 8568a0dc95fSEric Van Hensbergen } 8578a0dc95fSEric Van Hensbergen spin_unlock(&m->lock); 8588a0dc95fSEric Van Hensbergen 8598a0dc95fSEric Van Hensbergen if (req) { 8608a0dc95fSEric Van Hensbergen spin_lock(&req->lock); 8618a0dc95fSEric Van Hensbergen req->flush = Flushed; 8628a0dc95fSEric Van Hensbergen spin_unlock(&req->lock); 8638a0dc95fSEric Van Hensbergen 8648a0dc95fSEric Van Hensbergen if (req->cb) 8658a0dc95fSEric Van Hensbergen (*req->cb) (req, req->cba); 8668a0dc95fSEric Van Hensbergen else 8678a0dc95fSEric Van Hensbergen kfree(req->rcall); 8688a0dc95fSEric Van Hensbergen } 8698a0dc95fSEric Van Hensbergen 8708a0dc95fSEric Van Hensbergen kfree(freq->tcall); 8718a0dc95fSEric Van Hensbergen kfree(freq->rcall); 8728a0dc95fSEric Van Hensbergen p9_mux_free_request(m, freq); 8738a0dc95fSEric Van Hensbergen } 8748a0dc95fSEric Van Hensbergen 8758a0dc95fSEric Van Hensbergen static int 8768a0dc95fSEric Van Hensbergen p9_mux_flush_request(struct p9_conn *m, struct p9_req *req) 8778a0dc95fSEric Van Hensbergen { 8788a0dc95fSEric Van Hensbergen struct p9_fcall *fc; 8798a0dc95fSEric Van Hensbergen struct p9_req *rreq, *rptr; 8808a0dc95fSEric Van Hensbergen 8818a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag); 8828a0dc95fSEric Van Hensbergen 8838a0dc95fSEric Van Hensbergen /* if a response was received for a request, do nothing */ 8848a0dc95fSEric Van Hensbergen spin_lock(&req->lock); 8858a0dc95fSEric Van Hensbergen if (req->rcall || req->err) { 8868a0dc95fSEric Van Hensbergen spin_unlock(&req->lock); 8878a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, 8888a0dc95fSEric Van Hensbergen "mux %p req %p response already received\n", m, req); 8898a0dc95fSEric Van Hensbergen return 0; 8908a0dc95fSEric Van Hensbergen } 8918a0dc95fSEric Van Hensbergen 8928a0dc95fSEric Van Hensbergen req->flush = Flushing; 8938a0dc95fSEric Van Hensbergen spin_unlock(&req->lock); 8948a0dc95fSEric Van Hensbergen 8958a0dc95fSEric Van Hensbergen spin_lock(&m->lock); 8968a0dc95fSEric Van Hensbergen /* if the request is not sent yet, just remove it from the list */ 8978a0dc95fSEric Van Hensbergen list_for_each_entry_safe(rreq, rptr, &m->unsent_req_list, req_list) { 8988a0dc95fSEric Van Hensbergen if (rreq->tag == req->tag) { 8998a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, 9008a0dc95fSEric Van Hensbergen "mux %p req %p request is not sent yet\n", m, req); 9018a0dc95fSEric Van Hensbergen list_del(&rreq->req_list); 9028a0dc95fSEric Van Hensbergen req->flush = Flushed; 9038a0dc95fSEric Van Hensbergen spin_unlock(&m->lock); 9048a0dc95fSEric Van Hensbergen if (req->cb) 9058a0dc95fSEric Van Hensbergen (*req->cb) (req, req->cba); 9068a0dc95fSEric Van Hensbergen return 0; 9078a0dc95fSEric Van Hensbergen } 9088a0dc95fSEric Van Hensbergen } 9098a0dc95fSEric Van Hensbergen spin_unlock(&m->lock); 9108a0dc95fSEric Van Hensbergen 9118a0dc95fSEric Van Hensbergen clear_thread_flag(TIF_SIGPENDING); 9128a0dc95fSEric Van Hensbergen fc = p9_create_tflush(req->tag); 9138a0dc95fSEric Van Hensbergen p9_send_request(m, fc, p9_mux_flush_cb, m); 9148a0dc95fSEric Van Hensbergen return 1; 9158a0dc95fSEric Van Hensbergen } 9168a0dc95fSEric Van Hensbergen 9178a0dc95fSEric Van Hensbergen static void 9188a0dc95fSEric Van Hensbergen p9_conn_rpc_cb(struct p9_req *req, void *a) 9198a0dc95fSEric Van Hensbergen { 9208a0dc95fSEric Van Hensbergen struct p9_mux_rpc *r; 9218a0dc95fSEric Van Hensbergen 9228a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "req %p r %p\n", req, a); 9238a0dc95fSEric Van Hensbergen r = a; 9248a0dc95fSEric Van Hensbergen r->rcall = req->rcall; 9258a0dc95fSEric Van Hensbergen r->err = req->err; 9268a0dc95fSEric Van Hensbergen 9278a0dc95fSEric Van Hensbergen if (req->flush != None && !req->err) 9288a0dc95fSEric Van Hensbergen r->err = -ERESTARTSYS; 9298a0dc95fSEric Van Hensbergen 9308a0dc95fSEric Van Hensbergen wake_up(&r->wqueue); 9318a0dc95fSEric Van Hensbergen } 9328a0dc95fSEric Van Hensbergen 9338a0dc95fSEric Van Hensbergen /** 9348a0dc95fSEric Van Hensbergen * p9_fd_rpc- sends 9P request and waits until a response is available. 9358a0dc95fSEric Van Hensbergen * The function can be interrupted. 936ee443996SEric Van Hensbergen * @t: transport data 9378a0dc95fSEric Van Hensbergen * @tc: request to be sent 9388a0dc95fSEric Van Hensbergen * @rc: pointer where a pointer to the response is stored 939ee443996SEric Van Hensbergen * 9408a0dc95fSEric Van Hensbergen */ 941ee443996SEric Van Hensbergen 9428a0dc95fSEric Van Hensbergen int 9438a0dc95fSEric Van Hensbergen p9_fd_rpc(struct p9_trans *t, struct p9_fcall *tc, struct p9_fcall **rc) 9448a0dc95fSEric Van Hensbergen { 9458a0dc95fSEric Van Hensbergen struct p9_trans_fd *p = t->priv; 9468a0dc95fSEric Van Hensbergen struct p9_conn *m = p->conn; 9478a0dc95fSEric Van Hensbergen int err, sigpending; 9488a0dc95fSEric Van Hensbergen unsigned long flags; 9498a0dc95fSEric Van Hensbergen struct p9_req *req; 9508a0dc95fSEric Van Hensbergen struct p9_mux_rpc r; 9518a0dc95fSEric Van Hensbergen 9528a0dc95fSEric Van Hensbergen r.err = 0; 9538a0dc95fSEric Van Hensbergen r.tcall = tc; 9548a0dc95fSEric Van Hensbergen r.rcall = NULL; 9558a0dc95fSEric Van Hensbergen r.m = m; 9568a0dc95fSEric Van Hensbergen init_waitqueue_head(&r.wqueue); 9578a0dc95fSEric Van Hensbergen 9588a0dc95fSEric Van Hensbergen if (rc) 9598a0dc95fSEric Van Hensbergen *rc = NULL; 9608a0dc95fSEric Van Hensbergen 9618a0dc95fSEric Van Hensbergen sigpending = 0; 9628a0dc95fSEric Van Hensbergen if (signal_pending(current)) { 9638a0dc95fSEric Van Hensbergen sigpending = 1; 9648a0dc95fSEric Van Hensbergen clear_thread_flag(TIF_SIGPENDING); 9658a0dc95fSEric Van Hensbergen } 9668a0dc95fSEric Van Hensbergen 9678a0dc95fSEric Van Hensbergen req = p9_send_request(m, tc, p9_conn_rpc_cb, &r); 9688a0dc95fSEric Van Hensbergen if (IS_ERR(req)) { 9698a0dc95fSEric Van Hensbergen err = PTR_ERR(req); 9708a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err); 9718a0dc95fSEric Van Hensbergen return err; 9728a0dc95fSEric Van Hensbergen } 9738a0dc95fSEric Van Hensbergen 9748a0dc95fSEric Van Hensbergen err = wait_event_interruptible(r.wqueue, r.rcall != NULL || r.err < 0); 9758a0dc95fSEric Van Hensbergen if (r.err < 0) 9768a0dc95fSEric Van Hensbergen err = r.err; 9778a0dc95fSEric Van Hensbergen 9788a0dc95fSEric Van Hensbergen if (err == -ERESTARTSYS && m->trans->status == Connected 9798a0dc95fSEric Van Hensbergen && m->err == 0) { 9808a0dc95fSEric Van Hensbergen if (p9_mux_flush_request(m, req)) { 9818a0dc95fSEric Van Hensbergen /* wait until we get response of the flush message */ 9828a0dc95fSEric Van Hensbergen do { 9838a0dc95fSEric Van Hensbergen clear_thread_flag(TIF_SIGPENDING); 9848a0dc95fSEric Van Hensbergen err = wait_event_interruptible(r.wqueue, 9858a0dc95fSEric Van Hensbergen r.rcall || r.err); 9868a0dc95fSEric Van Hensbergen } while (!r.rcall && !r.err && err == -ERESTARTSYS && 9878a0dc95fSEric Van Hensbergen m->trans->status == Connected && !m->err); 9888a0dc95fSEric Van Hensbergen 9898a0dc95fSEric Van Hensbergen err = -ERESTARTSYS; 9908a0dc95fSEric Van Hensbergen } 9918a0dc95fSEric Van Hensbergen sigpending = 1; 9928a0dc95fSEric Van Hensbergen } 9938a0dc95fSEric Van Hensbergen 9948a0dc95fSEric Van Hensbergen if (sigpending) { 9958a0dc95fSEric Van Hensbergen spin_lock_irqsave(¤t->sighand->siglock, flags); 9968a0dc95fSEric Van Hensbergen recalc_sigpending(); 9978a0dc95fSEric Van Hensbergen spin_unlock_irqrestore(¤t->sighand->siglock, flags); 9988a0dc95fSEric Van Hensbergen } 9998a0dc95fSEric Van Hensbergen 10008a0dc95fSEric Van Hensbergen if (rc) 10018a0dc95fSEric Van Hensbergen *rc = r.rcall; 10028a0dc95fSEric Van Hensbergen else 10038a0dc95fSEric Van Hensbergen kfree(r.rcall); 10048a0dc95fSEric Van Hensbergen 10058a0dc95fSEric Van Hensbergen p9_mux_free_request(m, req); 10068a0dc95fSEric Van Hensbergen if (err > 0) 10078a0dc95fSEric Van Hensbergen err = -EIO; 10088a0dc95fSEric Van Hensbergen 10098a0dc95fSEric Van Hensbergen return err; 10108a0dc95fSEric Van Hensbergen } 10118a0dc95fSEric Van Hensbergen 10128a0dc95fSEric Van Hensbergen #ifdef P9_NONBLOCK 10138a0dc95fSEric Van Hensbergen /** 10148a0dc95fSEric Van Hensbergen * p9_conn_rpcnb - sends 9P request without waiting for response. 10158a0dc95fSEric Van Hensbergen * @m: mux data 10168a0dc95fSEric Van Hensbergen * @tc: request to be sent 10178a0dc95fSEric Van Hensbergen * @cb: callback function to be called when response arrives 1018ee443996SEric Van Hensbergen * @a: value to pass to the callback function 1019ee443996SEric Van Hensbergen * 10208a0dc95fSEric Van Hensbergen */ 1021ee443996SEric Van Hensbergen 10228a0dc95fSEric Van Hensbergen int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc, 10238a0dc95fSEric Van Hensbergen p9_conn_req_callback cb, void *a) 10248a0dc95fSEric Van Hensbergen { 10258a0dc95fSEric Van Hensbergen int err; 10268a0dc95fSEric Van Hensbergen struct p9_req *req; 10278a0dc95fSEric Van Hensbergen 10288a0dc95fSEric Van Hensbergen req = p9_send_request(m, tc, cb, a); 10298a0dc95fSEric Van Hensbergen if (IS_ERR(req)) { 10308a0dc95fSEric Van Hensbergen err = PTR_ERR(req); 10318a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err); 10328a0dc95fSEric Van Hensbergen return PTR_ERR(req); 10338a0dc95fSEric Van Hensbergen } 10348a0dc95fSEric Van Hensbergen 10358a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p tag %d\n", m, tc, req->tag); 10368a0dc95fSEric Van Hensbergen return 0; 10378a0dc95fSEric Van Hensbergen } 10388a0dc95fSEric Van Hensbergen #endif /* P9_NONBLOCK */ 10398a0dc95fSEric Van Hensbergen 10408a0dc95fSEric Van Hensbergen /** 10418a0dc95fSEric Van Hensbergen * p9_conn_cancel - cancel all pending requests with error 10428a0dc95fSEric Van Hensbergen * @m: mux data 10438a0dc95fSEric Van Hensbergen * @err: error code 1044ee443996SEric Van Hensbergen * 10458a0dc95fSEric Van Hensbergen */ 1046ee443996SEric Van Hensbergen 10478a0dc95fSEric Van Hensbergen void p9_conn_cancel(struct p9_conn *m, int err) 10488a0dc95fSEric Van Hensbergen { 10498a0dc95fSEric Van Hensbergen struct p9_req *req, *rtmp; 10508a0dc95fSEric Van Hensbergen LIST_HEAD(cancel_list); 10518a0dc95fSEric Van Hensbergen 10528a0dc95fSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err); 10538a0dc95fSEric Van Hensbergen m->err = err; 10548a0dc95fSEric Van Hensbergen spin_lock(&m->lock); 10558a0dc95fSEric Van Hensbergen list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { 10568a0dc95fSEric Van Hensbergen list_move(&req->req_list, &cancel_list); 10578a0dc95fSEric Van Hensbergen } 10588a0dc95fSEric Van Hensbergen list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) { 10598a0dc95fSEric Van Hensbergen list_move(&req->req_list, &cancel_list); 10608a0dc95fSEric Van Hensbergen } 10618a0dc95fSEric Van Hensbergen spin_unlock(&m->lock); 10628a0dc95fSEric Van Hensbergen 10638a0dc95fSEric Van Hensbergen list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) { 10648a0dc95fSEric Van Hensbergen list_del(&req->req_list); 10658a0dc95fSEric Van Hensbergen if (!req->err) 10668a0dc95fSEric Van Hensbergen req->err = err; 10678a0dc95fSEric Van Hensbergen 10688a0dc95fSEric Van Hensbergen if (req->cb) 10698a0dc95fSEric Van Hensbergen (*req->cb) (req, req->cba); 10708a0dc95fSEric Van Hensbergen else 10718a0dc95fSEric Van Hensbergen kfree(req->rcall); 10728a0dc95fSEric Van Hensbergen } 10738a0dc95fSEric Van Hensbergen } 10748a0dc95fSEric Van Hensbergen 1075a80d923eSEric Van Hensbergen /** 1076bb8ffdfcSEric Van Hensbergen * parse_options - parse mount options into session structure 1077a80d923eSEric Van Hensbergen * @options: options string passed from mount 1078ee443996SEric Van Hensbergen * @opts: transport-specific structure to parse options into 1079a80d923eSEric Van Hensbergen * 1080bb8ffdfcSEric Van Hensbergen * Returns 0 upon success, -ERRNO upon failure 1081a80d923eSEric Van Hensbergen */ 1082a80d923eSEric Van Hensbergen 1083bb8ffdfcSEric Van Hensbergen static int parse_opts(char *params, struct p9_fd_opts *opts) 1084bd238fb4SLatchesar Ionkov { 1085a80d923eSEric Van Hensbergen char *p; 1086a80d923eSEric Van Hensbergen substring_t args[MAX_OPT_ARGS]; 1087a80d923eSEric Van Hensbergen int option; 1088bb8ffdfcSEric Van Hensbergen char *options; 1089a80d923eSEric Van Hensbergen int ret; 1090bd238fb4SLatchesar Ionkov 1091a80d923eSEric Van Hensbergen opts->port = P9_PORT; 1092a80d923eSEric Van Hensbergen opts->rfd = ~0; 1093a80d923eSEric Van Hensbergen opts->wfd = ~0; 1094bd238fb4SLatchesar Ionkov 1095bb8ffdfcSEric Van Hensbergen if (!params) 1096bb8ffdfcSEric Van Hensbergen return 0; 1097bb8ffdfcSEric Van Hensbergen 1098bb8ffdfcSEric Van Hensbergen options = kstrdup(params, GFP_KERNEL); 1099bb8ffdfcSEric Van Hensbergen if (!options) { 1100bb8ffdfcSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, 1101bb8ffdfcSEric Van Hensbergen "failed to allocate copy of option string\n"); 1102bb8ffdfcSEric Van Hensbergen return -ENOMEM; 1103bb8ffdfcSEric Van Hensbergen } 1104bd238fb4SLatchesar Ionkov 1105a80d923eSEric Van Hensbergen while ((p = strsep(&options, ",")) != NULL) { 1106a80d923eSEric Van Hensbergen int token; 1107bb8ffdfcSEric Van Hensbergen int r; 1108a80d923eSEric Van Hensbergen if (!*p) 1109a80d923eSEric Van Hensbergen continue; 1110a80d923eSEric Van Hensbergen token = match_token(p, tokens, args); 1111bb8ffdfcSEric Van Hensbergen r = match_int(&args[0], &option); 1112bb8ffdfcSEric Van Hensbergen if (r < 0) { 1113a80d923eSEric Van Hensbergen P9_DPRINTK(P9_DEBUG_ERROR, 1114a80d923eSEric Van Hensbergen "integer field, but no integer?\n"); 1115bb8ffdfcSEric Van Hensbergen ret = r; 1116a80d923eSEric Van Hensbergen continue; 1117a80d923eSEric Van Hensbergen } 1118a80d923eSEric Van Hensbergen switch (token) { 1119a80d923eSEric Van Hensbergen case Opt_port: 1120a80d923eSEric Van Hensbergen opts->port = option; 1121a80d923eSEric Van Hensbergen break; 1122a80d923eSEric Van Hensbergen case Opt_rfdno: 1123a80d923eSEric Van Hensbergen opts->rfd = option; 1124a80d923eSEric Van Hensbergen break; 1125a80d923eSEric Van Hensbergen case Opt_wfdno: 1126a80d923eSEric Van Hensbergen opts->wfd = option; 1127a80d923eSEric Van Hensbergen break; 1128a80d923eSEric Van Hensbergen default: 1129a80d923eSEric Van Hensbergen continue; 1130a80d923eSEric Van Hensbergen } 1131a80d923eSEric Van Hensbergen } 1132bb8ffdfcSEric Van Hensbergen kfree(options); 1133bb8ffdfcSEric Van Hensbergen return 0; 1134bd238fb4SLatchesar Ionkov } 1135bd238fb4SLatchesar Ionkov 1136a80d923eSEric Van Hensbergen static int p9_fd_open(struct p9_trans *trans, int rfd, int wfd) 1137bd238fb4SLatchesar Ionkov { 1138bd238fb4SLatchesar Ionkov struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd), 1139bd238fb4SLatchesar Ionkov GFP_KERNEL); 1140bd238fb4SLatchesar Ionkov if (!ts) 1141bd238fb4SLatchesar Ionkov return -ENOMEM; 1142bd238fb4SLatchesar Ionkov 1143bd238fb4SLatchesar Ionkov ts->rd = fget(rfd); 1144bd238fb4SLatchesar Ionkov ts->wr = fget(wfd); 1145bd238fb4SLatchesar Ionkov if (!ts->rd || !ts->wr) { 1146bd238fb4SLatchesar Ionkov if (ts->rd) 1147bd238fb4SLatchesar Ionkov fput(ts->rd); 1148bd238fb4SLatchesar Ionkov if (ts->wr) 1149bd238fb4SLatchesar Ionkov fput(ts->wr); 1150bd238fb4SLatchesar Ionkov kfree(ts); 1151bd238fb4SLatchesar Ionkov return -EIO; 1152bd238fb4SLatchesar Ionkov } 1153bd238fb4SLatchesar Ionkov 1154bd238fb4SLatchesar Ionkov trans->priv = ts; 1155bd238fb4SLatchesar Ionkov trans->status = Connected; 1156bd238fb4SLatchesar Ionkov 1157bd238fb4SLatchesar Ionkov return 0; 1158bd238fb4SLatchesar Ionkov } 1159bd238fb4SLatchesar Ionkov 1160a80d923eSEric Van Hensbergen static int p9_socket_open(struct p9_trans *trans, struct socket *csocket) 1161a80d923eSEric Van Hensbergen { 1162a80d923eSEric Van Hensbergen int fd, ret; 1163a80d923eSEric Van Hensbergen 1164a80d923eSEric Van Hensbergen csocket->sk->sk_allocation = GFP_NOIO; 1165a677a039SUlrich Drepper fd = sock_map_fd(csocket, 0); 1166a80d923eSEric Van Hensbergen if (fd < 0) { 1167a80d923eSEric Van Hensbergen P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n"); 1168a80d923eSEric Van Hensbergen return fd; 1169a80d923eSEric Van Hensbergen } 1170a80d923eSEric Van Hensbergen 1171a80d923eSEric Van Hensbergen ret = p9_fd_open(trans, fd, fd); 1172a80d923eSEric Van Hensbergen if (ret < 0) { 1173a80d923eSEric Van Hensbergen P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to open fd\n"); 1174a80d923eSEric Van Hensbergen sockfd_put(csocket); 1175a80d923eSEric Van Hensbergen return ret; 1176a80d923eSEric Van Hensbergen } 1177a80d923eSEric Van Hensbergen 1178a80d923eSEric Van Hensbergen ((struct p9_trans_fd *)trans->priv)->rd->f_flags |= O_NONBLOCK; 1179a80d923eSEric Van Hensbergen 1180a80d923eSEric Van Hensbergen return 0; 1181a80d923eSEric Van Hensbergen } 1182a80d923eSEric Van Hensbergen 1183bd238fb4SLatchesar Ionkov /** 1184bd238fb4SLatchesar Ionkov * p9_fd_read- read from a fd 1185ee443996SEric Van Hensbergen * @trans: transport instance state 1186bd238fb4SLatchesar Ionkov * @v: buffer to receive data into 1187bd238fb4SLatchesar Ionkov * @len: size of receive buffer 1188bd238fb4SLatchesar Ionkov * 1189bd238fb4SLatchesar Ionkov */ 1190ee443996SEric Van Hensbergen 1191a80d923eSEric Van Hensbergen static int p9_fd_read(struct p9_trans *trans, void *v, int len) 1192bd238fb4SLatchesar Ionkov { 1193bd238fb4SLatchesar Ionkov int ret; 1194bd238fb4SLatchesar Ionkov struct p9_trans_fd *ts = NULL; 1195bd238fb4SLatchesar Ionkov 1196bd238fb4SLatchesar Ionkov if (trans && trans->status != Disconnected) 1197bd238fb4SLatchesar Ionkov ts = trans->priv; 1198bd238fb4SLatchesar Ionkov 1199bd238fb4SLatchesar Ionkov if (!ts) 1200bd238fb4SLatchesar Ionkov return -EREMOTEIO; 1201bd238fb4SLatchesar Ionkov 1202bd238fb4SLatchesar Ionkov if (!(ts->rd->f_flags & O_NONBLOCK)) 1203bd238fb4SLatchesar Ionkov P9_DPRINTK(P9_DEBUG_ERROR, "blocking read ...\n"); 1204bd238fb4SLatchesar Ionkov 1205bd238fb4SLatchesar Ionkov ret = kernel_read(ts->rd, ts->rd->f_pos, v, len); 1206bd238fb4SLatchesar Ionkov if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) 1207bd238fb4SLatchesar Ionkov trans->status = Disconnected; 1208bd238fb4SLatchesar Ionkov return ret; 1209bd238fb4SLatchesar Ionkov } 1210bd238fb4SLatchesar Ionkov 1211bd238fb4SLatchesar Ionkov /** 1212bd238fb4SLatchesar Ionkov * p9_fd_write - write to a socket 1213ee443996SEric Van Hensbergen * @trans: transport instance state 1214bd238fb4SLatchesar Ionkov * @v: buffer to send data from 1215bd238fb4SLatchesar Ionkov * @len: size of send buffer 1216bd238fb4SLatchesar Ionkov * 1217bd238fb4SLatchesar Ionkov */ 1218ee443996SEric Van Hensbergen 1219a80d923eSEric Van Hensbergen static int p9_fd_write(struct p9_trans *trans, void *v, int len) 1220bd238fb4SLatchesar Ionkov { 1221bd238fb4SLatchesar Ionkov int ret; 1222bd238fb4SLatchesar Ionkov mm_segment_t oldfs; 1223bd238fb4SLatchesar Ionkov struct p9_trans_fd *ts = NULL; 1224bd238fb4SLatchesar Ionkov 1225bd238fb4SLatchesar Ionkov if (trans && trans->status != Disconnected) 1226bd238fb4SLatchesar Ionkov ts = trans->priv; 1227bd238fb4SLatchesar Ionkov 1228bd238fb4SLatchesar Ionkov if (!ts) 1229bd238fb4SLatchesar Ionkov return -EREMOTEIO; 1230bd238fb4SLatchesar Ionkov 1231bd238fb4SLatchesar Ionkov if (!(ts->wr->f_flags & O_NONBLOCK)) 1232bd238fb4SLatchesar Ionkov P9_DPRINTK(P9_DEBUG_ERROR, "blocking write ...\n"); 1233bd238fb4SLatchesar Ionkov 1234bd238fb4SLatchesar Ionkov oldfs = get_fs(); 1235bd238fb4SLatchesar Ionkov set_fs(get_ds()); 1236bd238fb4SLatchesar Ionkov /* The cast to a user pointer is valid due to the set_fs() */ 1237bd238fb4SLatchesar Ionkov ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos); 1238bd238fb4SLatchesar Ionkov set_fs(oldfs); 1239bd238fb4SLatchesar Ionkov 1240bd238fb4SLatchesar Ionkov if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) 1241bd238fb4SLatchesar Ionkov trans->status = Disconnected; 1242bd238fb4SLatchesar Ionkov return ret; 1243bd238fb4SLatchesar Ionkov } 1244bd238fb4SLatchesar Ionkov 1245bd238fb4SLatchesar Ionkov static unsigned int 1246a80d923eSEric Van Hensbergen p9_fd_poll(struct p9_trans *trans, struct poll_table_struct *pt) 1247bd238fb4SLatchesar Ionkov { 1248bd238fb4SLatchesar Ionkov int ret, n; 1249bd238fb4SLatchesar Ionkov struct p9_trans_fd *ts = NULL; 1250bd238fb4SLatchesar Ionkov 1251bd238fb4SLatchesar Ionkov if (trans && trans->status == Connected) 1252bd238fb4SLatchesar Ionkov ts = trans->priv; 1253bd238fb4SLatchesar Ionkov 1254bd238fb4SLatchesar Ionkov if (!ts) 1255bd238fb4SLatchesar Ionkov return -EREMOTEIO; 1256bd238fb4SLatchesar Ionkov 1257bd238fb4SLatchesar Ionkov if (!ts->rd->f_op || !ts->rd->f_op->poll) 1258bd238fb4SLatchesar Ionkov return -EIO; 1259bd238fb4SLatchesar Ionkov 1260bd238fb4SLatchesar Ionkov if (!ts->wr->f_op || !ts->wr->f_op->poll) 1261bd238fb4SLatchesar Ionkov return -EIO; 1262bd238fb4SLatchesar Ionkov 1263bd238fb4SLatchesar Ionkov ret = ts->rd->f_op->poll(ts->rd, pt); 1264bd238fb4SLatchesar Ionkov if (ret < 0) 1265ec3c68f2STejun Heo return ret; 1266bd238fb4SLatchesar Ionkov 1267bd238fb4SLatchesar Ionkov if (ts->rd != ts->wr) { 1268bd238fb4SLatchesar Ionkov n = ts->wr->f_op->poll(ts->wr, pt); 1269ec3c68f2STejun Heo if (n < 0) 1270ec3c68f2STejun Heo return n; 1271bd238fb4SLatchesar Ionkov ret = (ret & ~POLLOUT) | (n & ~POLLIN); 1272bd238fb4SLatchesar Ionkov } 1273bd238fb4SLatchesar Ionkov 1274bd238fb4SLatchesar Ionkov return ret; 1275bd238fb4SLatchesar Ionkov } 1276bd238fb4SLatchesar Ionkov 1277bd238fb4SLatchesar Ionkov /** 12788a0dc95fSEric Van Hensbergen * p9_fd_close - shutdown socket 1279bd238fb4SLatchesar Ionkov * @trans: private socket structure 1280bd238fb4SLatchesar Ionkov * 1281bd238fb4SLatchesar Ionkov */ 1282ee443996SEric Van Hensbergen 1283a80d923eSEric Van Hensbergen static void p9_fd_close(struct p9_trans *trans) 1284bd238fb4SLatchesar Ionkov { 1285bd238fb4SLatchesar Ionkov struct p9_trans_fd *ts; 1286bd238fb4SLatchesar Ionkov 1287bd238fb4SLatchesar Ionkov if (!trans) 1288bd238fb4SLatchesar Ionkov return; 1289bd238fb4SLatchesar Ionkov 1290bd238fb4SLatchesar Ionkov ts = xchg(&trans->priv, NULL); 1291bd238fb4SLatchesar Ionkov 1292bd238fb4SLatchesar Ionkov if (!ts) 1293bd238fb4SLatchesar Ionkov return; 1294bd238fb4SLatchesar Ionkov 12958a0dc95fSEric Van Hensbergen p9_conn_destroy(ts->conn); 12968a0dc95fSEric Van Hensbergen 1297bd238fb4SLatchesar Ionkov trans->status = Disconnected; 1298bd238fb4SLatchesar Ionkov if (ts->rd) 1299bd238fb4SLatchesar Ionkov fput(ts->rd); 1300bd238fb4SLatchesar Ionkov if (ts->wr) 1301bd238fb4SLatchesar Ionkov fput(ts->wr); 1302bd238fb4SLatchesar Ionkov kfree(ts); 1303bd238fb4SLatchesar Ionkov } 1304bd238fb4SLatchesar Ionkov 1305887b3eceSEric Van Hensbergen /* 1306887b3eceSEric Van Hensbergen * stolen from NFS - maybe should be made a generic function? 1307887b3eceSEric Van Hensbergen */ 1308887b3eceSEric Van Hensbergen static inline int valid_ipaddr4(const char *buf) 1309887b3eceSEric Van Hensbergen { 1310887b3eceSEric Van Hensbergen int rc, count, in[4]; 1311887b3eceSEric Van Hensbergen 1312887b3eceSEric Van Hensbergen rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]); 1313887b3eceSEric Van Hensbergen if (rc != 4) 1314887b3eceSEric Van Hensbergen return -EINVAL; 1315887b3eceSEric Van Hensbergen for (count = 0; count < 4; count++) { 1316887b3eceSEric Van Hensbergen if (in[count] > 255) 1317887b3eceSEric Van Hensbergen return -EINVAL; 1318887b3eceSEric Van Hensbergen } 1319887b3eceSEric Van Hensbergen return 0; 1320887b3eceSEric Van Hensbergen } 1321887b3eceSEric Van Hensbergen 13228a0dc95fSEric Van Hensbergen static struct p9_trans * 13238a0dc95fSEric Van Hensbergen p9_trans_create_tcp(const char *addr, char *args, int msize, unsigned char dotu) 1324a80d923eSEric Van Hensbergen { 1325a80d923eSEric Van Hensbergen int err; 1326a80d923eSEric Van Hensbergen struct p9_trans *trans; 1327a80d923eSEric Van Hensbergen struct socket *csocket; 1328a80d923eSEric Van Hensbergen struct sockaddr_in sin_server; 1329a80d923eSEric Van Hensbergen struct p9_fd_opts opts; 13308a0dc95fSEric Van Hensbergen struct p9_trans_fd *p; 1331a80d923eSEric Van Hensbergen 1332bb8ffdfcSEric Van Hensbergen err = parse_opts(args, &opts); 1333bb8ffdfcSEric Van Hensbergen if (err < 0) 1334bb8ffdfcSEric Van Hensbergen return ERR_PTR(err); 1335a80d923eSEric Van Hensbergen 1336887b3eceSEric Van Hensbergen if (valid_ipaddr4(addr) < 0) 1337887b3eceSEric Van Hensbergen return ERR_PTR(-EINVAL); 1338887b3eceSEric Van Hensbergen 1339a80d923eSEric Van Hensbergen csocket = NULL; 1340a80d923eSEric Van Hensbergen trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL); 1341a80d923eSEric Van Hensbergen if (!trans) 1342a80d923eSEric Van Hensbergen return ERR_PTR(-ENOMEM); 13438a0dc95fSEric Van Hensbergen trans->msize = msize; 13448a0dc95fSEric Van Hensbergen trans->extended = dotu; 13458a0dc95fSEric Van Hensbergen trans->rpc = p9_fd_rpc; 1346a80d923eSEric Van Hensbergen trans->close = p9_fd_close; 1347a80d923eSEric Van Hensbergen 1348a80d923eSEric Van Hensbergen sin_server.sin_family = AF_INET; 1349a80d923eSEric Van Hensbergen sin_server.sin_addr.s_addr = in_aton(addr); 1350a80d923eSEric Van Hensbergen sin_server.sin_port = htons(opts.port); 1351a80d923eSEric Van Hensbergen sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket); 1352a80d923eSEric Van Hensbergen 1353a80d923eSEric Van Hensbergen if (!csocket) { 1354a80d923eSEric Van Hensbergen P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n"); 1355a80d923eSEric Van Hensbergen err = -EIO; 1356a80d923eSEric Van Hensbergen goto error; 1357a80d923eSEric Van Hensbergen } 1358a80d923eSEric Van Hensbergen 1359a80d923eSEric Van Hensbergen err = csocket->ops->connect(csocket, 1360a80d923eSEric Van Hensbergen (struct sockaddr *)&sin_server, 1361a80d923eSEric Van Hensbergen sizeof(struct sockaddr_in), 0); 1362a80d923eSEric Van Hensbergen if (err < 0) { 1363a80d923eSEric Van Hensbergen P9_EPRINTK(KERN_ERR, 1364a80d923eSEric Van Hensbergen "p9_trans_tcp: problem connecting socket to %s\n", 1365a80d923eSEric Van Hensbergen addr); 1366a80d923eSEric Van Hensbergen goto error; 1367a80d923eSEric Van Hensbergen } 1368a80d923eSEric Van Hensbergen 1369a80d923eSEric Van Hensbergen err = p9_socket_open(trans, csocket); 1370a80d923eSEric Van Hensbergen if (err < 0) 1371a80d923eSEric Van Hensbergen goto error; 1372a80d923eSEric Van Hensbergen 13738a0dc95fSEric Van Hensbergen p = (struct p9_trans_fd *) trans->priv; 13748a0dc95fSEric Van Hensbergen p->conn = p9_conn_create(trans); 13758a0dc95fSEric Van Hensbergen if (IS_ERR(p->conn)) { 13768a0dc95fSEric Van Hensbergen err = PTR_ERR(p->conn); 13778a0dc95fSEric Van Hensbergen p->conn = NULL; 13788a0dc95fSEric Van Hensbergen goto error; 13798a0dc95fSEric Van Hensbergen } 13808a0dc95fSEric Van Hensbergen 1381a80d923eSEric Van Hensbergen return trans; 1382a80d923eSEric Van Hensbergen 1383a80d923eSEric Van Hensbergen error: 1384a80d923eSEric Van Hensbergen if (csocket) 1385a80d923eSEric Van Hensbergen sock_release(csocket); 1386a80d923eSEric Van Hensbergen 1387a80d923eSEric Van Hensbergen kfree(trans); 1388a80d923eSEric Van Hensbergen return ERR_PTR(err); 1389a80d923eSEric Van Hensbergen } 1390a80d923eSEric Van Hensbergen 13918a0dc95fSEric Van Hensbergen static struct p9_trans * 13928a0dc95fSEric Van Hensbergen p9_trans_create_unix(const char *addr, char *args, int msize, 13938a0dc95fSEric Van Hensbergen unsigned char dotu) 1394a80d923eSEric Van Hensbergen { 1395a80d923eSEric Van Hensbergen int err; 1396a80d923eSEric Van Hensbergen struct socket *csocket; 1397a80d923eSEric Van Hensbergen struct sockaddr_un sun_server; 1398a80d923eSEric Van Hensbergen struct p9_trans *trans; 13998a0dc95fSEric Van Hensbergen struct p9_trans_fd *p; 1400a80d923eSEric Van Hensbergen 1401a80d923eSEric Van Hensbergen csocket = NULL; 1402a80d923eSEric Van Hensbergen trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL); 1403a80d923eSEric Van Hensbergen if (!trans) 1404a80d923eSEric Van Hensbergen return ERR_PTR(-ENOMEM); 1405a80d923eSEric Van Hensbergen 14068a0dc95fSEric Van Hensbergen trans->rpc = p9_fd_rpc; 1407a80d923eSEric Van Hensbergen trans->close = p9_fd_close; 1408a80d923eSEric Van Hensbergen 1409a80d923eSEric Van Hensbergen if (strlen(addr) > UNIX_PATH_MAX) { 1410a80d923eSEric Van Hensbergen P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n", 1411a80d923eSEric Van Hensbergen addr); 1412a80d923eSEric Van Hensbergen err = -ENAMETOOLONG; 1413a80d923eSEric Van Hensbergen goto error; 1414a80d923eSEric Van Hensbergen } 1415a80d923eSEric Van Hensbergen 1416a80d923eSEric Van Hensbergen sun_server.sun_family = PF_UNIX; 1417a80d923eSEric Van Hensbergen strcpy(sun_server.sun_path, addr); 1418a80d923eSEric Van Hensbergen sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket); 1419a80d923eSEric Van Hensbergen err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server, 1420a80d923eSEric Van Hensbergen sizeof(struct sockaddr_un) - 1, 0); 1421a80d923eSEric Van Hensbergen if (err < 0) { 1422a80d923eSEric Van Hensbergen P9_EPRINTK(KERN_ERR, 1423a80d923eSEric Van Hensbergen "p9_trans_unix: problem connecting socket: %s: %d\n", 1424a80d923eSEric Van Hensbergen addr, err); 1425a80d923eSEric Van Hensbergen goto error; 1426a80d923eSEric Van Hensbergen } 1427a80d923eSEric Van Hensbergen 1428a80d923eSEric Van Hensbergen err = p9_socket_open(trans, csocket); 1429a80d923eSEric Van Hensbergen if (err < 0) 1430a80d923eSEric Van Hensbergen goto error; 1431a80d923eSEric Van Hensbergen 14328a0dc95fSEric Van Hensbergen trans->msize = msize; 14338a0dc95fSEric Van Hensbergen trans->extended = dotu; 14348a0dc95fSEric Van Hensbergen p = (struct p9_trans_fd *) trans->priv; 14358a0dc95fSEric Van Hensbergen p->conn = p9_conn_create(trans); 14368a0dc95fSEric Van Hensbergen if (IS_ERR(p->conn)) { 14378a0dc95fSEric Van Hensbergen err = PTR_ERR(p->conn); 14388a0dc95fSEric Van Hensbergen p->conn = NULL; 14398a0dc95fSEric Van Hensbergen goto error; 14408a0dc95fSEric Van Hensbergen } 14418a0dc95fSEric Van Hensbergen 1442a80d923eSEric Van Hensbergen return trans; 1443a80d923eSEric Van Hensbergen 1444a80d923eSEric Van Hensbergen error: 1445a80d923eSEric Van Hensbergen if (csocket) 1446a80d923eSEric Van Hensbergen sock_release(csocket); 1447a80d923eSEric Van Hensbergen 1448a80d923eSEric Van Hensbergen kfree(trans); 1449a80d923eSEric Van Hensbergen return ERR_PTR(err); 1450a80d923eSEric Van Hensbergen } 1451a80d923eSEric Van Hensbergen 14528a0dc95fSEric Van Hensbergen static struct p9_trans * 14538a0dc95fSEric Van Hensbergen p9_trans_create_fd(const char *name, char *args, int msize, 14548a0dc95fSEric Van Hensbergen unsigned char extended) 1455a80d923eSEric Van Hensbergen { 1456a80d923eSEric Van Hensbergen int err; 1457a80d923eSEric Van Hensbergen struct p9_trans *trans; 1458a80d923eSEric Van Hensbergen struct p9_fd_opts opts; 14598a0dc95fSEric Van Hensbergen struct p9_trans_fd *p; 1460a80d923eSEric Van Hensbergen 1461a80d923eSEric Van Hensbergen parse_opts(args, &opts); 1462a80d923eSEric Van Hensbergen 1463a80d923eSEric Van Hensbergen if (opts.rfd == ~0 || opts.wfd == ~0) { 1464a80d923eSEric Van Hensbergen printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n"); 1465a80d923eSEric Van Hensbergen return ERR_PTR(-ENOPROTOOPT); 1466a80d923eSEric Van Hensbergen } 1467a80d923eSEric Van Hensbergen 1468a80d923eSEric Van Hensbergen trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL); 1469a80d923eSEric Van Hensbergen if (!trans) 1470a80d923eSEric Van Hensbergen return ERR_PTR(-ENOMEM); 1471a80d923eSEric Van Hensbergen 14728a0dc95fSEric Van Hensbergen trans->rpc = p9_fd_rpc; 1473a80d923eSEric Van Hensbergen trans->close = p9_fd_close; 1474a80d923eSEric Van Hensbergen 1475a80d923eSEric Van Hensbergen err = p9_fd_open(trans, opts.rfd, opts.wfd); 1476a80d923eSEric Van Hensbergen if (err < 0) 1477a80d923eSEric Van Hensbergen goto error; 1478a80d923eSEric Van Hensbergen 14798a0dc95fSEric Van Hensbergen trans->msize = msize; 14808a0dc95fSEric Van Hensbergen trans->extended = extended; 14818a0dc95fSEric Van Hensbergen p = (struct p9_trans_fd *) trans->priv; 14828a0dc95fSEric Van Hensbergen p->conn = p9_conn_create(trans); 14838a0dc95fSEric Van Hensbergen if (IS_ERR(p->conn)) { 14848a0dc95fSEric Van Hensbergen err = PTR_ERR(p->conn); 14858a0dc95fSEric Van Hensbergen p->conn = NULL; 14868a0dc95fSEric Van Hensbergen goto error; 14878a0dc95fSEric Van Hensbergen } 14888a0dc95fSEric Van Hensbergen 1489a80d923eSEric Van Hensbergen return trans; 1490a80d923eSEric Van Hensbergen 1491a80d923eSEric Van Hensbergen error: 1492a80d923eSEric Van Hensbergen kfree(trans); 1493a80d923eSEric Van Hensbergen return ERR_PTR(err); 1494a80d923eSEric Van Hensbergen } 1495a80d923eSEric Van Hensbergen 1496a80d923eSEric Van Hensbergen static struct p9_trans_module p9_tcp_trans = { 1497a80d923eSEric Van Hensbergen .name = "tcp", 1498a80d923eSEric Van Hensbergen .maxsize = MAX_SOCK_BUF, 1499a80d923eSEric Van Hensbergen .def = 1, 1500a80d923eSEric Van Hensbergen .create = p9_trans_create_tcp, 150172029fe8STejun Heo .owner = THIS_MODULE, 1502a80d923eSEric Van Hensbergen }; 1503a80d923eSEric Van Hensbergen 1504a80d923eSEric Van Hensbergen static struct p9_trans_module p9_unix_trans = { 1505a80d923eSEric Van Hensbergen .name = "unix", 1506a80d923eSEric Van Hensbergen .maxsize = MAX_SOCK_BUF, 1507a80d923eSEric Van Hensbergen .def = 0, 1508a80d923eSEric Van Hensbergen .create = p9_trans_create_unix, 150972029fe8STejun Heo .owner = THIS_MODULE, 1510a80d923eSEric Van Hensbergen }; 1511a80d923eSEric Van Hensbergen 1512a80d923eSEric Van Hensbergen static struct p9_trans_module p9_fd_trans = { 1513a80d923eSEric Van Hensbergen .name = "fd", 1514a80d923eSEric Van Hensbergen .maxsize = MAX_SOCK_BUF, 1515a80d923eSEric Van Hensbergen .def = 0, 1516a80d923eSEric Van Hensbergen .create = p9_trans_create_fd, 151772029fe8STejun Heo .owner = THIS_MODULE, 1518a80d923eSEric Van Hensbergen }; 1519a80d923eSEric Van Hensbergen 1520887b3eceSEric Van Hensbergen int p9_trans_fd_init(void) 1521a80d923eSEric Van Hensbergen { 1522206ca50dSTejun Heo p9_mux_wq = create_workqueue("v9fs"); 1523206ca50dSTejun Heo if (!p9_mux_wq) { 1524206ca50dSTejun Heo printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n"); 1525206ca50dSTejun Heo return -ENOMEM; 15268a0dc95fSEric Van Hensbergen } 15278a0dc95fSEric Van Hensbergen 1528992b3f1dSTejun Heo p9_poll_task = kthread_run(p9_poll_proc, NULL, "v9fs-poll"); 1529992b3f1dSTejun Heo if (IS_ERR(p9_poll_task)) { 1530992b3f1dSTejun Heo destroy_workqueue(p9_mux_wq); 1531992b3f1dSTejun Heo printk(KERN_WARNING "v9fs: mux: creating poll task failed\n"); 1532992b3f1dSTejun Heo return PTR_ERR(p9_poll_task); 1533992b3f1dSTejun Heo } 1534992b3f1dSTejun Heo 1535a80d923eSEric Van Hensbergen v9fs_register_trans(&p9_tcp_trans); 1536a80d923eSEric Van Hensbergen v9fs_register_trans(&p9_unix_trans); 1537a80d923eSEric Van Hensbergen v9fs_register_trans(&p9_fd_trans); 1538a80d923eSEric Van Hensbergen 15393387b804SAndrew Morton return 0; 1540a80d923eSEric Van Hensbergen } 154172029fe8STejun Heo 154272029fe8STejun Heo void p9_trans_fd_exit(void) 154372029fe8STejun Heo { 1544992b3f1dSTejun Heo kthread_stop(p9_poll_task); 154572029fe8STejun Heo v9fs_unregister_trans(&p9_tcp_trans); 154672029fe8STejun Heo v9fs_unregister_trans(&p9_unix_trans); 154772029fe8STejun Heo v9fs_unregister_trans(&p9_fd_trans); 1548206ca50dSTejun Heo 1549206ca50dSTejun Heo destroy_workqueue(p9_mux_wq); 155072029fe8STejun Heo } 1551