LCOV - code coverage report
Current view: top level - net/9p - trans_fd.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 5 523 1.0 %
Date: 2021-04-22 12:43:58 Functions: 1 28 3.6 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-only
       2             : /*
       3             :  * linux/fs/9p/trans_fd.c
       4             :  *
       5             :  * Fd transport layer.  Includes deprecated socket layer.
       6             :  *
       7             :  *  Copyright (C) 2006 by Russ Cox <rsc@swtch.com>
       8             :  *  Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
       9             :  *  Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com>
      10             :  *  Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com>
      11             :  */
      12             : 
      13             : #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      14             : 
      15             : #include <linux/in.h>
      16             : #include <linux/module.h>
      17             : #include <linux/net.h>
      18             : #include <linux/ipv6.h>
      19             : #include <linux/kthread.h>
      20             : #include <linux/errno.h>
      21             : #include <linux/kernel.h>
      22             : #include <linux/un.h>
      23             : #include <linux/uaccess.h>
      24             : #include <linux/inet.h>
      25             : #include <linux/idr.h>
      26             : #include <linux/file.h>
      27             : #include <linux/parser.h>
      28             : #include <linux/slab.h>
      29             : #include <linux/seq_file.h>
      30             : #include <net/9p/9p.h>
      31             : #include <net/9p/client.h>
      32             : #include <net/9p/transport.h>
      33             : 
      34             : #include <linux/syscalls.h> /* killme */
      35             : 
      36             : #define P9_PORT 564
      37             : #define MAX_SOCK_BUF (64*1024)
      38             : #define MAXPOLLWADDR    2
      39             : 
      40             : static struct p9_trans_module p9_tcp_trans;
      41             : static struct p9_trans_module p9_fd_trans;
      42             : 
      43             : /**
      44             :  * struct p9_fd_opts - per-transport options
      45             :  * @rfd: file descriptor for reading (trans=fd)
      46             :  * @wfd: file descriptor for writing (trans=fd)
      47             :  * @port: port to connect to (trans=tcp)
      48             :  * @privport: port is privileged
      49             :  */
      50             : 
      51             : struct p9_fd_opts {
      52             :         int rfd;
      53             :         int wfd;
      54             :         u16 port;
      55             :         bool privport;
      56             : };
      57             : 
      58             : /*
      59             :   * Option Parsing (code inspired by NFS code)
      60             :   *  - a little lazy - parse all fd-transport options
      61             :   */
      62             : 
      63             : enum {
      64             :         /* Options that take integer arguments */
      65             :         Opt_port, Opt_rfdno, Opt_wfdno, Opt_err,
      66             :         /* Options that take no arguments */
      67             :         Opt_privport,
      68             : };
      69             : 
      70             : static const match_table_t tokens = {
      71             :         {Opt_port, "port=%u"},
      72             :         {Opt_rfdno, "rfdno=%u"},
      73             :         {Opt_wfdno, "wfdno=%u"},
      74             :         {Opt_privport, "privport"},
      75             :         {Opt_err, NULL},
      76             : };
      77             : 
      78             : enum {
      79             :         Rworksched = 1,         /* read work scheduled or running */
      80             :         Rpending = 2,           /* can read */
      81             :         Wworksched = 4,         /* write work scheduled or running */
      82             :         Wpending = 8,           /* can write */
      83             : };
      84             : 
      85             : struct p9_poll_wait {
      86             :         struct p9_conn *conn;
      87             :         wait_queue_entry_t wait;
      88             :         wait_queue_head_t *wait_addr;
      89             : };
      90             : 
      91             : /**
      92             :  * struct p9_conn - fd mux connection state information
      93             :  * @mux_list: list link for mux to manage multiple connections (?)
      94             :  * @client: reference to client instance for this connection
      95             :  * @err: error state
      96             :  * @req_list: accounting for requests which have been sent
      97             :  * @unsent_req_list: accounting for requests that haven't been sent
      98             :  * @rreq: read request
      99             :  * @wreq: write request
     100             :  * @req: current request being processed (if any)
     101             :  * @tmp_buf: temporary buffer to read in header
     102             :  * @rc: temporary fcall for reading current frame
     103             :  * @wpos: write position for current frame
     104             :  * @wsize: amount of data to write for current frame
     105             :  * @wbuf: current write buffer
     106             :  * @poll_pending_link: pending links to be polled per conn
     107             :  * @poll_wait: array of wait_q's for various worker threads
     108             :  * @pt: poll state
     109             :  * @rq: current read work
     110             :  * @wq: current write work
     111             :  * @wsched: ????
     112             :  *
     113             :  */
     114             : 
     115             : struct p9_conn {
     116             :         struct list_head mux_list;
     117             :         struct p9_client *client;
     118             :         int err;
     119             :         struct list_head req_list;
     120             :         struct list_head unsent_req_list;
     121             :         struct p9_req_t *rreq;
     122             :         struct p9_req_t *wreq;
     123             :         char tmp_buf[7];
     124             :         struct p9_fcall rc;
     125             :         int wpos;
     126             :         int wsize;
     127             :         char *wbuf;
     128             :         struct list_head poll_pending_link;
     129             :         struct p9_poll_wait poll_wait[MAXPOLLWADDR];
     130             :         poll_table pt;
     131             :         struct work_struct rq;
     132             :         struct work_struct wq;
     133             :         unsigned long wsched;
     134             : };
     135             : 
     136             : /**
     137             :  * struct p9_trans_fd - transport state
     138             :  * @rd: reference to file to read from
     139             :  * @wr: reference of file to write to
     140             :  * @conn: connection state reference
     141             :  *
     142             :  */
     143             : 
     144             : struct p9_trans_fd {
     145             :         struct file *rd;
     146             :         struct file *wr;
     147             :         struct p9_conn conn;
     148             : };
     149             : 
     150             : static void p9_poll_workfn(struct work_struct *work);
     151             : 
     152             : static DEFINE_SPINLOCK(p9_poll_lock);
     153             : static LIST_HEAD(p9_poll_pending_list);
     154             : static DECLARE_WORK(p9_poll_work, p9_poll_workfn);
     155             : 
     156             : static unsigned int p9_ipport_resv_min = P9_DEF_MIN_RESVPORT;
     157             : static unsigned int p9_ipport_resv_max = P9_DEF_MAX_RESVPORT;
     158             : 
     159           0 : static void p9_mux_poll_stop(struct p9_conn *m)
     160             : {
     161           0 :         unsigned long flags;
     162           0 :         int i;
     163             : 
     164           0 :         for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) {
     165           0 :                 struct p9_poll_wait *pwait = &m->poll_wait[i];
     166             : 
     167           0 :                 if (pwait->wait_addr) {
     168           0 :                         remove_wait_queue(pwait->wait_addr, &pwait->wait);
     169           0 :                         pwait->wait_addr = NULL;
     170             :                 }
     171             :         }
     172             : 
     173           0 :         spin_lock_irqsave(&p9_poll_lock, flags);
     174           0 :         list_del_init(&m->poll_pending_link);
     175           0 :         spin_unlock_irqrestore(&p9_poll_lock, flags);
     176             : 
     177           0 :         flush_work(&p9_poll_work);
     178           0 : }
     179             : 
     180             : /**
     181             :  * p9_conn_cancel - cancel all pending requests with error
     182             :  * @m: mux data
     183             :  * @err: error code
     184             :  *
     185             :  */
     186             : 
     187           0 : static void p9_conn_cancel(struct p9_conn *m, int err)
     188             : {
     189           0 :         struct p9_req_t *req, *rtmp;
     190           0 :         LIST_HEAD(cancel_list);
     191             : 
     192           0 :         p9_debug(P9_DEBUG_ERROR, "mux %p err %d\n", m, err);
     193             : 
     194           0 :         spin_lock(&m->client->lock);
     195             : 
     196           0 :         if (m->err) {
     197           0 :                 spin_unlock(&m->client->lock);
     198           0 :                 return;
     199             :         }
     200             : 
     201           0 :         m->err = err;
     202             : 
     203           0 :         list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) {
     204           0 :                 list_move(&req->req_list, &cancel_list);
     205             :         }
     206           0 :         list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) {
     207           0 :                 list_move(&req->req_list, &cancel_list);
     208             :         }
     209             : 
     210           0 :         list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) {
     211           0 :                 p9_debug(P9_DEBUG_ERROR, "call back req %p\n", req);
     212           0 :                 list_del(&req->req_list);
     213           0 :                 if (!req->t_err)
     214           0 :                         req->t_err = err;
     215           0 :                 p9_client_cb(m->client, req, REQ_STATUS_ERROR);
     216             :         }
     217           0 :         spin_unlock(&m->client->lock);
     218             : }
     219             : 
     220             : static __poll_t
     221           0 : p9_fd_poll(struct p9_client *client, struct poll_table_struct *pt, int *err)
     222             : {
     223           0 :         __poll_t ret;
     224           0 :         struct p9_trans_fd *ts = NULL;
     225             : 
     226           0 :         if (client && client->status == Connected)
     227           0 :                 ts = client->trans;
     228             : 
     229           0 :         if (!ts) {
     230           0 :                 if (err)
     231           0 :                         *err = -EREMOTEIO;
     232           0 :                 return EPOLLERR;
     233             :         }
     234             : 
     235           0 :         ret = vfs_poll(ts->rd, pt);
     236           0 :         if (ts->rd != ts->wr)
     237           0 :                 ret = (ret & ~EPOLLOUT) | (vfs_poll(ts->wr, pt) & ~EPOLLIN);
     238             :         return ret;
     239             : }
     240             : 
     241             : /**
     242             :  * p9_fd_read- read from a fd
     243             :  * @client: client instance
     244             :  * @v: buffer to receive data into
     245             :  * @len: size of receive buffer
     246             :  *
     247             :  */
     248             : 
     249           0 : static int p9_fd_read(struct p9_client *client, void *v, int len)
     250             : {
     251           0 :         int ret;
     252           0 :         struct p9_trans_fd *ts = NULL;
     253           0 :         loff_t pos;
     254             : 
     255           0 :         if (client && client->status != Disconnected)
     256           0 :                 ts = client->trans;
     257             : 
     258           0 :         if (!ts)
     259             :                 return -EREMOTEIO;
     260             : 
     261           0 :         if (!(ts->rd->f_flags & O_NONBLOCK))
     262             :                 p9_debug(P9_DEBUG_ERROR, "blocking read ...\n");
     263             : 
     264           0 :         pos = ts->rd->f_pos;
     265           0 :         ret = kernel_read(ts->rd, v, len, &pos);
     266           0 :         if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
     267           0 :                 client->status = Disconnected;
     268             :         return ret;
     269             : }
     270             : 
     271             : /**
     272             :  * p9_read_work - called when there is some data to be read from a transport
     273             :  * @work: container of work to be done
     274             :  *
     275             :  */
     276             : 
     277           0 : static void p9_read_work(struct work_struct *work)
     278             : {
     279           0 :         __poll_t n;
     280           0 :         int err;
     281           0 :         struct p9_conn *m;
     282             : 
     283           0 :         m = container_of(work, struct p9_conn, rq);
     284             : 
     285           0 :         if (m->err < 0)
     286             :                 return;
     287             : 
     288           0 :         p9_debug(P9_DEBUG_TRANS, "start mux %p pos %zd\n", m, m->rc.offset);
     289             : 
     290           0 :         if (!m->rc.sdata) {
     291           0 :                 m->rc.sdata = m->tmp_buf;
     292           0 :                 m->rc.offset = 0;
     293           0 :                 m->rc.capacity = 7; /* start by reading header */
     294             :         }
     295             : 
     296           0 :         clear_bit(Rpending, &m->wsched);
     297           0 :         p9_debug(P9_DEBUG_TRANS, "read mux %p pos %zd size: %zd = %zd\n",
     298             :                  m, m->rc.offset, m->rc.capacity,
     299             :                  m->rc.capacity - m->rc.offset);
     300           0 :         err = p9_fd_read(m->client, m->rc.sdata + m->rc.offset,
     301           0 :                          m->rc.capacity - m->rc.offset);
     302           0 :         p9_debug(P9_DEBUG_TRANS, "mux %p got %d bytes\n", m, err);
     303           0 :         if (err == -EAGAIN)
     304           0 :                 goto end_clear;
     305             : 
     306           0 :         if (err <= 0)
     307           0 :                 goto error;
     308             : 
     309           0 :         m->rc.offset += err;
     310             : 
     311             :         /* header read in */
     312           0 :         if ((!m->rreq) && (m->rc.offset == m->rc.capacity)) {
     313           0 :                 p9_debug(P9_DEBUG_TRANS, "got new header\n");
     314             : 
     315             :                 /* Header size */
     316           0 :                 m->rc.size = 7;
     317           0 :                 err = p9_parse_header(&m->rc, &m->rc.size, NULL, NULL, 0);
     318           0 :                 if (err) {
     319           0 :                         p9_debug(P9_DEBUG_ERROR,
     320             :                                  "error parsing header: %d\n", err);
     321           0 :                         goto error;
     322             :                 }
     323             : 
     324           0 :                 if (m->rc.size >= m->client->msize) {
     325           0 :                         p9_debug(P9_DEBUG_ERROR,
     326             :                                  "requested packet size too big: %d\n",
     327             :                                  m->rc.size);
     328           0 :                         err = -EIO;
     329           0 :                         goto error;
     330             :                 }
     331             : 
     332           0 :                 p9_debug(P9_DEBUG_TRANS,
     333             :                          "mux %p pkt: size: %d bytes tag: %d\n",
     334             :                          m, m->rc.size, m->rc.tag);
     335             : 
     336           0 :                 m->rreq = p9_tag_lookup(m->client, m->rc.tag);
     337           0 :                 if (!m->rreq || (m->rreq->status != REQ_STATUS_SENT)) {
     338           0 :                         p9_debug(P9_DEBUG_ERROR, "Unexpected packet tag %d\n",
     339             :                                  m->rc.tag);
     340           0 :                         err = -EIO;
     341           0 :                         goto error;
     342             :                 }
     343             : 
     344           0 :                 if (!m->rreq->rc.sdata) {
     345           0 :                         p9_debug(P9_DEBUG_ERROR,
     346             :                                  "No recv fcall for tag %d (req %p), disconnecting!\n",
     347             :                                  m->rc.tag, m->rreq);
     348           0 :                         m->rreq = NULL;
     349           0 :                         err = -EIO;
     350           0 :                         goto error;
     351             :                 }
     352           0 :                 m->rc.sdata = m->rreq->rc.sdata;
     353           0 :                 memcpy(m->rc.sdata, m->tmp_buf, m->rc.capacity);
     354           0 :                 m->rc.capacity = m->rc.size;
     355             :         }
     356             : 
     357             :         /* packet is read in
     358             :          * not an else because some packets (like clunk) have no payload
     359             :          */
     360           0 :         if ((m->rreq) && (m->rc.offset == m->rc.capacity)) {
     361           0 :                 p9_debug(P9_DEBUG_TRANS, "got new packet\n");
     362           0 :                 m->rreq->rc.size = m->rc.offset;
     363           0 :                 spin_lock(&m->client->lock);
     364           0 :                 if (m->rreq->status == REQ_STATUS_SENT) {
     365           0 :                         list_del(&m->rreq->req_list);
     366           0 :                         p9_client_cb(m->client, m->rreq, REQ_STATUS_RCVD);
     367           0 :                 } else if (m->rreq->status == REQ_STATUS_FLSHD) {
     368             :                         /* Ignore replies associated with a cancelled request. */
     369             :                         p9_debug(P9_DEBUG_TRANS,
     370             :                                  "Ignore replies associated with a cancelled request\n");
     371             :                 } else {
     372           0 :                         spin_unlock(&m->client->lock);
     373           0 :                         p9_debug(P9_DEBUG_ERROR,
     374             :                                  "Request tag %d errored out while we were reading the reply\n",
     375             :                                  m->rc.tag);
     376           0 :                         err = -EIO;
     377           0 :                         goto error;
     378             :                 }
     379           0 :                 spin_unlock(&m->client->lock);
     380           0 :                 m->rc.sdata = NULL;
     381           0 :                 m->rc.offset = 0;
     382           0 :                 m->rc.capacity = 0;
     383           0 :                 p9_req_put(m->rreq);
     384           0 :                 m->rreq = NULL;
     385             :         }
     386             : 
     387           0 : end_clear:
     388           0 :         clear_bit(Rworksched, &m->wsched);
     389             : 
     390           0 :         if (!list_empty(&m->req_list)) {
     391           0 :                 if (test_and_clear_bit(Rpending, &m->wsched))
     392             :                         n = EPOLLIN;
     393             :                 else
     394           0 :                         n = p9_fd_poll(m->client, NULL, NULL);
     395             : 
     396           0 :                 if ((n & EPOLLIN) && !test_and_set_bit(Rworksched, &m->wsched)) {
     397           0 :                         p9_debug(P9_DEBUG_TRANS, "sched read work %p\n", m);
     398           0 :                         schedule_work(&m->rq);
     399             :                 }
     400             :         }
     401             : 
     402             :         return;
     403           0 : error:
     404           0 :         p9_conn_cancel(m, err);
     405           0 :         clear_bit(Rworksched, &m->wsched);
     406             : }
     407             : 
     408             : /**
     409             :  * p9_fd_write - write to a socket
     410             :  * @client: client instance
     411             :  * @v: buffer to send data from
     412             :  * @len: size of send buffer
     413             :  *
     414             :  */
     415             : 
     416           0 : static int p9_fd_write(struct p9_client *client, void *v, int len)
     417             : {
     418           0 :         ssize_t ret;
     419           0 :         struct p9_trans_fd *ts = NULL;
     420             : 
     421           0 :         if (client && client->status != Disconnected)
     422           0 :                 ts = client->trans;
     423             : 
     424           0 :         if (!ts)
     425             :                 return -EREMOTEIO;
     426             : 
     427           0 :         if (!(ts->wr->f_flags & O_NONBLOCK))
     428             :                 p9_debug(P9_DEBUG_ERROR, "blocking write ...\n");
     429             : 
     430           0 :         ret = kernel_write(ts->wr, v, len, &ts->wr->f_pos);
     431           0 :         if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
     432           0 :                 client->status = Disconnected;
     433           0 :         return ret;
     434             : }
     435             : 
     436             : /**
     437             :  * p9_write_work - called when a transport can send some data
     438             :  * @work: container for work to be done
     439             :  *
     440             :  */
     441             : 
     442           0 : static void p9_write_work(struct work_struct *work)
     443             : {
     444           0 :         __poll_t n;
     445           0 :         int err;
     446           0 :         struct p9_conn *m;
     447           0 :         struct p9_req_t *req;
     448             : 
     449           0 :         m = container_of(work, struct p9_conn, wq);
     450             : 
     451           0 :         if (m->err < 0) {
     452           0 :                 clear_bit(Wworksched, &m->wsched);
     453           0 :                 return;
     454             :         }
     455             : 
     456           0 :         if (!m->wsize) {
     457           0 :                 spin_lock(&m->client->lock);
     458           0 :                 if (list_empty(&m->unsent_req_list)) {
     459           0 :                         clear_bit(Wworksched, &m->wsched);
     460           0 :                         spin_unlock(&m->client->lock);
     461           0 :                         return;
     462             :                 }
     463             : 
     464           0 :                 req = list_entry(m->unsent_req_list.next, struct p9_req_t,
     465             :                                req_list);
     466           0 :                 req->status = REQ_STATUS_SENT;
     467           0 :                 p9_debug(P9_DEBUG_TRANS, "move req %p\n", req);
     468           0 :                 list_move_tail(&req->req_list, &m->req_list);
     469             : 
     470           0 :                 m->wbuf = req->tc.sdata;
     471           0 :                 m->wsize = req->tc.size;
     472           0 :                 m->wpos = 0;
     473           0 :                 p9_req_get(req);
     474           0 :                 m->wreq = req;
     475           0 :                 spin_unlock(&m->client->lock);
     476             :         }
     477             : 
     478           0 :         p9_debug(P9_DEBUG_TRANS, "mux %p pos %d size %d\n",
     479             :                  m, m->wpos, m->wsize);
     480           0 :         clear_bit(Wpending, &m->wsched);
     481           0 :         err = p9_fd_write(m->client, m->wbuf + m->wpos, m->wsize - m->wpos);
     482           0 :         p9_debug(P9_DEBUG_TRANS, "mux %p sent %d bytes\n", m, err);
     483           0 :         if (err == -EAGAIN)
     484           0 :                 goto end_clear;
     485             : 
     486             : 
     487           0 :         if (err < 0)
     488           0 :                 goto error;
     489           0 :         else if (err == 0) {
     490           0 :                 err = -EREMOTEIO;
     491           0 :                 goto error;
     492             :         }
     493             : 
     494           0 :         m->wpos += err;
     495           0 :         if (m->wpos == m->wsize) {
     496           0 :                 m->wpos = m->wsize = 0;
     497           0 :                 p9_req_put(m->wreq);
     498           0 :                 m->wreq = NULL;
     499             :         }
     500             : 
     501           0 : end_clear:
     502           0 :         clear_bit(Wworksched, &m->wsched);
     503             : 
     504           0 :         if (m->wsize || !list_empty(&m->unsent_req_list)) {
     505           0 :                 if (test_and_clear_bit(Wpending, &m->wsched))
     506             :                         n = EPOLLOUT;
     507             :                 else
     508           0 :                         n = p9_fd_poll(m->client, NULL, NULL);
     509             : 
     510           0 :                 if ((n & EPOLLOUT) &&
     511           0 :                    !test_and_set_bit(Wworksched, &m->wsched)) {
     512           0 :                         p9_debug(P9_DEBUG_TRANS, "sched write work %p\n", m);
     513           0 :                         schedule_work(&m->wq);
     514             :                 }
     515             :         }
     516             : 
     517             :         return;
     518             : 
     519           0 : error:
     520           0 :         p9_conn_cancel(m, err);
     521           0 :         clear_bit(Wworksched, &m->wsched);
     522             : }
     523             : 
     524           0 : static int p9_pollwake(wait_queue_entry_t *wait, unsigned int mode, int sync, void *key)
     525             : {
     526           0 :         struct p9_poll_wait *pwait =
     527           0 :                 container_of(wait, struct p9_poll_wait, wait);
     528           0 :         struct p9_conn *m = pwait->conn;
     529           0 :         unsigned long flags;
     530             : 
     531           0 :         spin_lock_irqsave(&p9_poll_lock, flags);
     532           0 :         if (list_empty(&m->poll_pending_link))
     533           0 :                 list_add_tail(&m->poll_pending_link, &p9_poll_pending_list);
     534           0 :         spin_unlock_irqrestore(&p9_poll_lock, flags);
     535             : 
     536           0 :         schedule_work(&p9_poll_work);
     537           0 :         return 1;
     538             : }
     539             : 
     540             : /**
     541             :  * p9_pollwait - add poll task to the wait queue
     542             :  * @filp: file pointer being polled
     543             :  * @wait_address: wait_q to block on
     544             :  * @p: poll state
     545             :  *
     546             :  * called by files poll operation to add v9fs-poll task to files wait queue
     547             :  */
     548             : 
     549             : static void
     550           0 : p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p)
     551             : {
     552           0 :         struct p9_conn *m = container_of(p, struct p9_conn, pt);
     553           0 :         struct p9_poll_wait *pwait = NULL;
     554           0 :         int i;
     555             : 
     556           0 :         for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) {
     557           0 :                 if (m->poll_wait[i].wait_addr == NULL) {
     558           0 :                         pwait = &m->poll_wait[i];
     559           0 :                         break;
     560             :                 }
     561             :         }
     562             : 
     563           0 :         if (!pwait) {
     564             :                 p9_debug(P9_DEBUG_ERROR, "not enough wait_address slots\n");
     565             :                 return;
     566             :         }
     567             : 
     568           0 :         pwait->conn = m;
     569           0 :         pwait->wait_addr = wait_address;
     570           0 :         init_waitqueue_func_entry(&pwait->wait, p9_pollwake);
     571           0 :         add_wait_queue(wait_address, &pwait->wait);
     572             : }
     573             : 
     574             : /**
     575             :  * p9_conn_create - initialize the per-session mux data
     576             :  * @client: client instance
     577             :  *
     578             :  * Note: Creates the polling task if this is the first session.
     579             :  */
     580             : 
     581           0 : static void p9_conn_create(struct p9_client *client)
     582             : {
     583           0 :         __poll_t n;
     584           0 :         struct p9_trans_fd *ts = client->trans;
     585           0 :         struct p9_conn *m = &ts->conn;
     586             : 
     587           0 :         p9_debug(P9_DEBUG_TRANS, "client %p msize %d\n", client, client->msize);
     588             : 
     589           0 :         INIT_LIST_HEAD(&m->mux_list);
     590           0 :         m->client = client;
     591             : 
     592           0 :         INIT_LIST_HEAD(&m->req_list);
     593           0 :         INIT_LIST_HEAD(&m->unsent_req_list);
     594           0 :         INIT_WORK(&m->rq, p9_read_work);
     595           0 :         INIT_WORK(&m->wq, p9_write_work);
     596           0 :         INIT_LIST_HEAD(&m->poll_pending_link);
     597           0 :         init_poll_funcptr(&m->pt, p9_pollwait);
     598             : 
     599           0 :         n = p9_fd_poll(client, &m->pt, NULL);
     600           0 :         if (n & EPOLLIN) {
     601           0 :                 p9_debug(P9_DEBUG_TRANS, "mux %p can read\n", m);
     602           0 :                 set_bit(Rpending, &m->wsched);
     603             :         }
     604             : 
     605           0 :         if (n & EPOLLOUT) {
     606           0 :                 p9_debug(P9_DEBUG_TRANS, "mux %p can write\n", m);
     607           0 :                 set_bit(Wpending, &m->wsched);
     608             :         }
     609           0 : }
     610             : 
     611             : /**
     612             :  * p9_poll_mux - polls a mux and schedules read or write works if necessary
     613             :  * @m: connection to poll
     614             :  *
     615             :  */
     616             : 
     617           0 : static void p9_poll_mux(struct p9_conn *m)
     618             : {
     619           0 :         __poll_t n;
     620           0 :         int err = -ECONNRESET;
     621             : 
     622           0 :         if (m->err < 0)
     623           0 :                 return;
     624             : 
     625           0 :         n = p9_fd_poll(m->client, NULL, &err);
     626           0 :         if (n & (EPOLLERR | EPOLLHUP | EPOLLNVAL)) {
     627           0 :                 p9_debug(P9_DEBUG_TRANS, "error mux %p err %d\n", m, n);
     628           0 :                 p9_conn_cancel(m, err);
     629             :         }
     630             : 
     631           0 :         if (n & EPOLLIN) {
     632           0 :                 set_bit(Rpending, &m->wsched);
     633           0 :                 p9_debug(P9_DEBUG_TRANS, "mux %p can read\n", m);
     634           0 :                 if (!test_and_set_bit(Rworksched, &m->wsched)) {
     635           0 :                         p9_debug(P9_DEBUG_TRANS, "sched read work %p\n", m);
     636           0 :                         schedule_work(&m->rq);
     637             :                 }
     638             :         }
     639             : 
     640           0 :         if (n & EPOLLOUT) {
     641           0 :                 set_bit(Wpending, &m->wsched);
     642           0 :                 p9_debug(P9_DEBUG_TRANS, "mux %p can write\n", m);
     643           0 :                 if ((m->wsize || !list_empty(&m->unsent_req_list)) &&
     644           0 :                     !test_and_set_bit(Wworksched, &m->wsched)) {
     645           0 :                         p9_debug(P9_DEBUG_TRANS, "sched write work %p\n", m);
     646           0 :                         schedule_work(&m->wq);
     647             :                 }
     648             :         }
     649             : }
     650             : 
     651             : /**
     652             :  * p9_fd_request - send 9P request
     653             :  * The function can sleep until the request is scheduled for sending.
     654             :  * The function can be interrupted. Return from the function is not
     655             :  * a guarantee that the request is sent successfully.
     656             :  *
     657             :  * @client: client instance
     658             :  * @req: request to be sent
     659             :  *
     660             :  */
     661             : 
     662           0 : static int p9_fd_request(struct p9_client *client, struct p9_req_t *req)
     663             : {
     664           0 :         __poll_t n;
     665           0 :         struct p9_trans_fd *ts = client->trans;
     666           0 :         struct p9_conn *m = &ts->conn;
     667             : 
     668           0 :         p9_debug(P9_DEBUG_TRANS, "mux %p task %p tcall %p id %d\n",
     669             :                  m, current, &req->tc, req->tc.id);
     670           0 :         if (m->err < 0)
     671             :                 return m->err;
     672             : 
     673           0 :         spin_lock(&client->lock);
     674           0 :         req->status = REQ_STATUS_UNSENT;
     675           0 :         list_add_tail(&req->req_list, &m->unsent_req_list);
     676           0 :         spin_unlock(&client->lock);
     677             : 
     678           0 :         if (test_and_clear_bit(Wpending, &m->wsched))
     679             :                 n = EPOLLOUT;
     680             :         else
     681           0 :                 n = p9_fd_poll(m->client, NULL, NULL);
     682             : 
     683           0 :         if (n & EPOLLOUT && !test_and_set_bit(Wworksched, &m->wsched))
     684           0 :                 schedule_work(&m->wq);
     685             : 
     686             :         return 0;
     687             : }
     688             : 
     689           0 : static int p9_fd_cancel(struct p9_client *client, struct p9_req_t *req)
     690             : {
     691           0 :         int ret = 1;
     692             : 
     693           0 :         p9_debug(P9_DEBUG_TRANS, "client %p req %p\n", client, req);
     694             : 
     695           0 :         spin_lock(&client->lock);
     696             : 
     697           0 :         if (req->status == REQ_STATUS_UNSENT) {
     698           0 :                 list_del(&req->req_list);
     699           0 :                 req->status = REQ_STATUS_FLSHD;
     700           0 :                 p9_req_put(req);
     701           0 :                 ret = 0;
     702             :         }
     703           0 :         spin_unlock(&client->lock);
     704             : 
     705           0 :         return ret;
     706             : }
     707             : 
     708           0 : static int p9_fd_cancelled(struct p9_client *client, struct p9_req_t *req)
     709             : {
     710           0 :         p9_debug(P9_DEBUG_TRANS, "client %p req %p\n", client, req);
     711             : 
     712           0 :         spin_lock(&client->lock);
     713             :         /* Ignore cancelled request if message has been received
     714             :          * before lock.
     715             :          */
     716           0 :         if (req->status == REQ_STATUS_RCVD) {
     717           0 :                 spin_unlock(&client->lock);
     718           0 :                 return 0;
     719             :         }
     720             : 
     721             :         /* we haven't received a response for oldreq,
     722             :          * remove it from the list.
     723             :          */
     724           0 :         list_del(&req->req_list);
     725           0 :         req->status = REQ_STATUS_FLSHD;
     726           0 :         spin_unlock(&client->lock);
     727           0 :         p9_req_put(req);
     728             : 
     729           0 :         return 0;
     730             : }
     731             : 
     732           0 : static int p9_fd_show_options(struct seq_file *m, struct p9_client *clnt)
     733             : {
     734           0 :         if (clnt->trans_mod == &p9_tcp_trans) {
     735           0 :                 if (clnt->trans_opts.tcp.port != P9_PORT)
     736           0 :                         seq_printf(m, ",port=%u", clnt->trans_opts.tcp.port);
     737           0 :         } else if (clnt->trans_mod == &p9_fd_trans) {
     738           0 :                 if (clnt->trans_opts.fd.rfd != ~0)
     739           0 :                         seq_printf(m, ",rfd=%u", clnt->trans_opts.fd.rfd);
     740           0 :                 if (clnt->trans_opts.fd.wfd != ~0)
     741           0 :                         seq_printf(m, ",wfd=%u", clnt->trans_opts.fd.wfd);
     742             :         }
     743           0 :         return 0;
     744             : }
     745             : 
     746             : /**
     747             :  * parse_opts - parse mount options into p9_fd_opts structure
     748             :  * @params: options string passed from mount
     749             :  * @opts: fd transport-specific structure to parse options into
     750             :  *
     751             :  * Returns 0 upon success, -ERRNO upon failure
     752             :  */
     753             : 
     754           0 : static int parse_opts(char *params, struct p9_fd_opts *opts)
     755             : {
     756           0 :         char *p;
     757           0 :         substring_t args[MAX_OPT_ARGS];
     758           0 :         int option;
     759           0 :         char *options, *tmp_options;
     760             : 
     761           0 :         opts->port = P9_PORT;
     762           0 :         opts->rfd = ~0;
     763           0 :         opts->wfd = ~0;
     764           0 :         opts->privport = false;
     765             : 
     766           0 :         if (!params)
     767             :                 return 0;
     768             : 
     769           0 :         tmp_options = kstrdup(params, GFP_KERNEL);
     770           0 :         if (!tmp_options) {
     771             :                 p9_debug(P9_DEBUG_ERROR,
     772             :                          "failed to allocate copy of option string\n");
     773             :                 return -ENOMEM;
     774             :         }
     775           0 :         options = tmp_options;
     776             : 
     777           0 :         while ((p = strsep(&options, ",")) != NULL) {
     778           0 :                 int token;
     779           0 :                 int r;
     780           0 :                 if (!*p)
     781           0 :                         continue;
     782           0 :                 token = match_token(p, tokens, args);
     783           0 :                 if ((token != Opt_err) && (token != Opt_privport)) {
     784           0 :                         r = match_int(&args[0], &option);
     785           0 :                         if (r < 0) {
     786           0 :                                 p9_debug(P9_DEBUG_ERROR,
     787             :                                          "integer field, but no integer?\n");
     788           0 :                                 continue;
     789             :                         }
     790             :                 }
     791           0 :                 switch (token) {
     792           0 :                 case Opt_port:
     793           0 :                         opts->port = option;
     794           0 :                         break;
     795           0 :                 case Opt_rfdno:
     796           0 :                         opts->rfd = option;
     797           0 :                         break;
     798           0 :                 case Opt_wfdno:
     799           0 :                         opts->wfd = option;
     800           0 :                         break;
     801           0 :                 case Opt_privport:
     802           0 :                         opts->privport = true;
     803           0 :                         break;
     804           0 :                 default:
     805           0 :                         continue;
     806             :                 }
     807             :         }
     808             : 
     809           0 :         kfree(tmp_options);
     810           0 :         return 0;
     811             : }
     812             : 
     813           0 : static int p9_fd_open(struct p9_client *client, int rfd, int wfd)
     814             : {
     815           0 :         struct p9_trans_fd *ts = kzalloc(sizeof(struct p9_trans_fd),
     816             :                                            GFP_KERNEL);
     817           0 :         if (!ts)
     818             :                 return -ENOMEM;
     819             : 
     820           0 :         ts->rd = fget(rfd);
     821           0 :         if (!ts->rd)
     822           0 :                 goto out_free_ts;
     823           0 :         if (!(ts->rd->f_mode & FMODE_READ))
     824           0 :                 goto out_put_rd;
     825           0 :         ts->wr = fget(wfd);
     826           0 :         if (!ts->wr)
     827           0 :                 goto out_put_rd;
     828           0 :         if (!(ts->wr->f_mode & FMODE_WRITE))
     829           0 :                 goto out_put_wr;
     830             : 
     831           0 :         client->trans = ts;
     832           0 :         client->status = Connected;
     833             : 
     834           0 :         return 0;
     835             : 
     836           0 : out_put_wr:
     837           0 :         fput(ts->wr);
     838           0 : out_put_rd:
     839           0 :         fput(ts->rd);
     840           0 : out_free_ts:
     841           0 :         kfree(ts);
     842           0 :         return -EIO;
     843             : }
     844             : 
     845           0 : static int p9_socket_open(struct p9_client *client, struct socket *csocket)
     846             : {
     847           0 :         struct p9_trans_fd *p;
     848           0 :         struct file *file;
     849             : 
     850           0 :         p = kzalloc(sizeof(struct p9_trans_fd), GFP_KERNEL);
     851           0 :         if (!p)
     852             :                 return -ENOMEM;
     853             : 
     854           0 :         csocket->sk->sk_allocation = GFP_NOIO;
     855           0 :         file = sock_alloc_file(csocket, 0, NULL);
     856           0 :         if (IS_ERR(file)) {
     857           0 :                 pr_err("%s (%d): failed to map fd\n",
     858             :                        __func__, task_pid_nr(current));
     859           0 :                 kfree(p);
     860           0 :                 return PTR_ERR(file);
     861             :         }
     862             : 
     863           0 :         get_file(file);
     864           0 :         p->wr = p->rd = file;
     865           0 :         client->trans = p;
     866           0 :         client->status = Connected;
     867             : 
     868           0 :         p->rd->f_flags |= O_NONBLOCK;
     869             : 
     870           0 :         p9_conn_create(client);
     871           0 :         return 0;
     872             : }
     873             : 
     874             : /**
     875             :  * p9_mux_destroy - cancels all pending requests of mux
     876             :  * @m: mux to destroy
     877             :  *
     878             :  */
     879             : 
     880           0 : static void p9_conn_destroy(struct p9_conn *m)
     881             : {
     882           0 :         p9_debug(P9_DEBUG_TRANS, "mux %p prev %p next %p\n",
     883             :                  m, m->mux_list.prev, m->mux_list.next);
     884             : 
     885           0 :         p9_mux_poll_stop(m);
     886           0 :         cancel_work_sync(&m->rq);
     887           0 :         if (m->rreq) {
     888           0 :                 p9_req_put(m->rreq);
     889           0 :                 m->rreq = NULL;
     890             :         }
     891           0 :         cancel_work_sync(&m->wq);
     892           0 :         if (m->wreq) {
     893           0 :                 p9_req_put(m->wreq);
     894           0 :                 m->wreq = NULL;
     895             :         }
     896             : 
     897           0 :         p9_conn_cancel(m, -ECONNRESET);
     898             : 
     899           0 :         m->client = NULL;
     900           0 : }
     901             : 
     902             : /**
     903             :  * p9_fd_close - shutdown file descriptor transport
     904             :  * @client: client instance
     905             :  *
     906             :  */
     907             : 
     908           0 : static void p9_fd_close(struct p9_client *client)
     909             : {
     910           0 :         struct p9_trans_fd *ts;
     911             : 
     912           0 :         if (!client)
     913             :                 return;
     914             : 
     915           0 :         ts = client->trans;
     916           0 :         if (!ts)
     917             :                 return;
     918             : 
     919           0 :         client->status = Disconnected;
     920             : 
     921           0 :         p9_conn_destroy(&ts->conn);
     922             : 
     923           0 :         if (ts->rd)
     924           0 :                 fput(ts->rd);
     925           0 :         if (ts->wr)
     926           0 :                 fput(ts->wr);
     927             : 
     928           0 :         kfree(ts);
     929             : }
     930             : 
     931             : /*
     932             :  * stolen from NFS - maybe should be made a generic function?
     933             :  */
     934           0 : static inline int valid_ipaddr4(const char *buf)
     935             : {
     936           0 :         int rc, count, in[4];
     937             : 
     938           0 :         rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]);
     939           0 :         if (rc != 4)
     940             :                 return -EINVAL;
     941           0 :         for (count = 0; count < 4; count++) {
     942           0 :                 if (in[count] > 255)
     943             :                         return -EINVAL;
     944             :         }
     945             :         return 0;
     946             : }
     947             : 
     948           0 : static int p9_bind_privport(struct socket *sock)
     949             : {
     950           0 :         struct sockaddr_in cl;
     951           0 :         int port, err = -EINVAL;
     952             : 
     953           0 :         memset(&cl, 0, sizeof(cl));
     954           0 :         cl.sin_family = AF_INET;
     955           0 :         cl.sin_addr.s_addr = htonl(INADDR_ANY);
     956           0 :         for (port = p9_ipport_resv_max; port >= p9_ipport_resv_min; port--) {
     957           0 :                 cl.sin_port = htons((ushort)port);
     958           0 :                 err = kernel_bind(sock, (struct sockaddr *)&cl, sizeof(cl));
     959           0 :                 if (err != -EADDRINUSE)
     960             :                         break;
     961             :         }
     962           0 :         return err;
     963             : }
     964             : 
     965             : 
     966             : static int
     967           0 : p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
     968             : {
     969           0 :         int err;
     970           0 :         struct socket *csocket;
     971           0 :         struct sockaddr_in sin_server;
     972           0 :         struct p9_fd_opts opts;
     973             : 
     974           0 :         err = parse_opts(args, &opts);
     975           0 :         if (err < 0)
     976             :                 return err;
     977             : 
     978           0 :         if (addr == NULL || valid_ipaddr4(addr) < 0)
     979           0 :                 return -EINVAL;
     980             : 
     981           0 :         csocket = NULL;
     982             : 
     983           0 :         client->trans_opts.tcp.port = opts.port;
     984           0 :         client->trans_opts.tcp.privport = opts.privport;
     985           0 :         sin_server.sin_family = AF_INET;
     986           0 :         sin_server.sin_addr.s_addr = in_aton(addr);
     987           0 :         sin_server.sin_port = htons(opts.port);
     988           0 :         err = __sock_create(current->nsproxy->net_ns, PF_INET,
     989             :                             SOCK_STREAM, IPPROTO_TCP, &csocket, 1);
     990           0 :         if (err) {
     991           0 :                 pr_err("%s (%d): problem creating socket\n",
     992             :                        __func__, task_pid_nr(current));
     993           0 :                 return err;
     994             :         }
     995             : 
     996           0 :         if (opts.privport) {
     997           0 :                 err = p9_bind_privport(csocket);
     998           0 :                 if (err < 0) {
     999           0 :                         pr_err("%s (%d): problem binding to privport\n",
    1000             :                                __func__, task_pid_nr(current));
    1001           0 :                         sock_release(csocket);
    1002           0 :                         return err;
    1003             :                 }
    1004             :         }
    1005             : 
    1006           0 :         err = csocket->ops->connect(csocket,
    1007             :                                     (struct sockaddr *)&sin_server,
    1008             :                                     sizeof(struct sockaddr_in), 0);
    1009           0 :         if (err < 0) {
    1010           0 :                 pr_err("%s (%d): problem connecting socket to %s\n",
    1011             :                        __func__, task_pid_nr(current), addr);
    1012           0 :                 sock_release(csocket);
    1013           0 :                 return err;
    1014             :         }
    1015             : 
    1016           0 :         return p9_socket_open(client, csocket);
    1017             : }
    1018             : 
    1019             : static int
    1020           0 : p9_fd_create_unix(struct p9_client *client, const char *addr, char *args)
    1021             : {
    1022           0 :         int err;
    1023           0 :         struct socket *csocket;
    1024           0 :         struct sockaddr_un sun_server;
    1025             : 
    1026           0 :         csocket = NULL;
    1027             : 
    1028           0 :         if (!addr || !strlen(addr))
    1029             :                 return -EINVAL;
    1030             : 
    1031           0 :         if (strlen(addr) >= UNIX_PATH_MAX) {
    1032           0 :                 pr_err("%s (%d): address too long: %s\n",
    1033             :                        __func__, task_pid_nr(current), addr);
    1034           0 :                 return -ENAMETOOLONG;
    1035             :         }
    1036             : 
    1037           0 :         sun_server.sun_family = PF_UNIX;
    1038           0 :         strcpy(sun_server.sun_path, addr);
    1039           0 :         err = __sock_create(current->nsproxy->net_ns, PF_UNIX,
    1040             :                             SOCK_STREAM, 0, &csocket, 1);
    1041           0 :         if (err < 0) {
    1042           0 :                 pr_err("%s (%d): problem creating socket\n",
    1043             :                        __func__, task_pid_nr(current));
    1044             : 
    1045           0 :                 return err;
    1046             :         }
    1047           0 :         err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
    1048             :                         sizeof(struct sockaddr_un) - 1, 0);
    1049           0 :         if (err < 0) {
    1050           0 :                 pr_err("%s (%d): problem connecting socket: %s: %d\n",
    1051             :                        __func__, task_pid_nr(current), addr, err);
    1052           0 :                 sock_release(csocket);
    1053           0 :                 return err;
    1054             :         }
    1055             : 
    1056           0 :         return p9_socket_open(client, csocket);
    1057             : }
    1058             : 
    1059             : static int
    1060           0 : p9_fd_create(struct p9_client *client, const char *addr, char *args)
    1061             : {
    1062           0 :         int err;
    1063           0 :         struct p9_fd_opts opts;
    1064             : 
    1065           0 :         parse_opts(args, &opts);
    1066           0 :         client->trans_opts.fd.rfd = opts.rfd;
    1067           0 :         client->trans_opts.fd.wfd = opts.wfd;
    1068             : 
    1069           0 :         if (opts.rfd == ~0 || opts.wfd == ~0) {
    1070           0 :                 pr_err("Insufficient options for proto=fd\n");
    1071           0 :                 return -ENOPROTOOPT;
    1072             :         }
    1073             : 
    1074           0 :         err = p9_fd_open(client, opts.rfd, opts.wfd);
    1075           0 :         if (err < 0)
    1076             :                 return err;
    1077             : 
    1078           0 :         p9_conn_create(client);
    1079             : 
    1080           0 :         return 0;
    1081             : }
    1082             : 
    1083             : static struct p9_trans_module p9_tcp_trans = {
    1084             :         .name = "tcp",
    1085             :         .maxsize = MAX_SOCK_BUF,
    1086             :         .def = 0,
    1087             :         .create = p9_fd_create_tcp,
    1088             :         .close = p9_fd_close,
    1089             :         .request = p9_fd_request,
    1090             :         .cancel = p9_fd_cancel,
    1091             :         .cancelled = p9_fd_cancelled,
    1092             :         .show_options = p9_fd_show_options,
    1093             :         .owner = THIS_MODULE,
    1094             : };
    1095             : 
    1096             : static struct p9_trans_module p9_unix_trans = {
    1097             :         .name = "unix",
    1098             :         .maxsize = MAX_SOCK_BUF,
    1099             :         .def = 0,
    1100             :         .create = p9_fd_create_unix,
    1101             :         .close = p9_fd_close,
    1102             :         .request = p9_fd_request,
    1103             :         .cancel = p9_fd_cancel,
    1104             :         .cancelled = p9_fd_cancelled,
    1105             :         .show_options = p9_fd_show_options,
    1106             :         .owner = THIS_MODULE,
    1107             : };
    1108             : 
    1109             : static struct p9_trans_module p9_fd_trans = {
    1110             :         .name = "fd",
    1111             :         .maxsize = MAX_SOCK_BUF,
    1112             :         .def = 0,
    1113             :         .create = p9_fd_create,
    1114             :         .close = p9_fd_close,
    1115             :         .request = p9_fd_request,
    1116             :         .cancel = p9_fd_cancel,
    1117             :         .cancelled = p9_fd_cancelled,
    1118             :         .show_options = p9_fd_show_options,
    1119             :         .owner = THIS_MODULE,
    1120             : };
    1121             : 
    1122             : /**
    1123             :  * p9_poll_workfn - poll worker thread
    1124             :  * @work: work queue
    1125             :  *
    1126             :  * polls all v9fs transports for new events and queues the appropriate
    1127             :  * work to the work queue
    1128             :  *
    1129             :  */
    1130             : 
    1131           0 : static void p9_poll_workfn(struct work_struct *work)
    1132             : {
    1133           0 :         unsigned long flags;
    1134             : 
    1135           0 :         p9_debug(P9_DEBUG_TRANS, "start %p\n", current);
    1136             : 
    1137           0 :         spin_lock_irqsave(&p9_poll_lock, flags);
    1138           0 :         while (!list_empty(&p9_poll_pending_list)) {
    1139           0 :                 struct p9_conn *conn = list_first_entry(&p9_poll_pending_list,
    1140             :                                                         struct p9_conn,
    1141             :                                                         poll_pending_link);
    1142           0 :                 list_del_init(&conn->poll_pending_link);
    1143           0 :                 spin_unlock_irqrestore(&p9_poll_lock, flags);
    1144             : 
    1145           0 :                 p9_poll_mux(conn);
    1146             : 
    1147           0 :                 spin_lock_irqsave(&p9_poll_lock, flags);
    1148             :         }
    1149           0 :         spin_unlock_irqrestore(&p9_poll_lock, flags);
    1150             : 
    1151           0 :         p9_debug(P9_DEBUG_TRANS, "finish\n");
    1152           0 : }
    1153             : 
    1154           1 : int p9_trans_fd_init(void)
    1155             : {
    1156           1 :         v9fs_register_trans(&p9_tcp_trans);
    1157           1 :         v9fs_register_trans(&p9_unix_trans);
    1158           1 :         v9fs_register_trans(&p9_fd_trans);
    1159             : 
    1160           1 :         return 0;
    1161             : }
    1162             : 
    1163           0 : void p9_trans_fd_exit(void)
    1164             : {
    1165           0 :         flush_work(&p9_poll_work);
    1166           0 :         v9fs_unregister_trans(&p9_tcp_trans);
    1167           0 :         v9fs_unregister_trans(&p9_unix_trans);
    1168           0 :         v9fs_unregister_trans(&p9_fd_trans);
    1169           0 : }

Generated by: LCOV version 1.14