18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * The Virtio 9p transport driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This is a block based transport driver based on the lguest block driver
68c2ecf20Sopenharmony_ci * code.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci *  Copyright (C) 2007, 2008 Eric Van Hensbergen, IBM Corporation
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *  Based on virtio console driver
118c2ecf20Sopenharmony_ci *  Copyright (C) 2006, 2007 Rusty Russell, IBM Corporation
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/in.h>
178c2ecf20Sopenharmony_ci#include <linux/module.h>
188c2ecf20Sopenharmony_ci#include <linux/net.h>
198c2ecf20Sopenharmony_ci#include <linux/ipv6.h>
208c2ecf20Sopenharmony_ci#include <linux/errno.h>
218c2ecf20Sopenharmony_ci#include <linux/kernel.h>
228c2ecf20Sopenharmony_ci#include <linux/un.h>
238c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
248c2ecf20Sopenharmony_ci#include <linux/inet.h>
258c2ecf20Sopenharmony_ci#include <linux/idr.h>
268c2ecf20Sopenharmony_ci#include <linux/file.h>
278c2ecf20Sopenharmony_ci#include <linux/highmem.h>
288c2ecf20Sopenharmony_ci#include <linux/slab.h>
298c2ecf20Sopenharmony_ci#include <net/9p/9p.h>
308c2ecf20Sopenharmony_ci#include <linux/parser.h>
318c2ecf20Sopenharmony_ci#include <net/9p/client.h>
328c2ecf20Sopenharmony_ci#include <net/9p/transport.h>
338c2ecf20Sopenharmony_ci#include <linux/scatterlist.h>
348c2ecf20Sopenharmony_ci#include <linux/swap.h>
358c2ecf20Sopenharmony_ci#include <linux/virtio.h>
368c2ecf20Sopenharmony_ci#include <linux/virtio_9p.h>
378c2ecf20Sopenharmony_ci#include "trans_common.h"
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define VIRTQUEUE_NUM	128
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/* a single mutex to manage channel initialization and attachment */
428c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(virtio_9p_lock);
438c2ecf20Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(vp_wq);
448c2ecf20Sopenharmony_cistatic atomic_t vp_pinned = ATOMIC_INIT(0);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/**
478c2ecf20Sopenharmony_ci * struct virtio_chan - per-instance transport information
488c2ecf20Sopenharmony_ci * @inuse: whether the channel is in use
498c2ecf20Sopenharmony_ci * @lock: protects multiple elements within this structure
508c2ecf20Sopenharmony_ci * @client: client instance
518c2ecf20Sopenharmony_ci * @vdev: virtio dev associated with this channel
528c2ecf20Sopenharmony_ci * @vq: virtio queue associated with this channel
538c2ecf20Sopenharmony_ci * @sg: scatter gather list which is used to pack a request (protected?)
548c2ecf20Sopenharmony_ci *
558c2ecf20Sopenharmony_ci * We keep all per-channel information in a structure.
568c2ecf20Sopenharmony_ci * This structure is allocated within the devices dev->mem space.
578c2ecf20Sopenharmony_ci * A pointer to the structure will get put in the transport private.
588c2ecf20Sopenharmony_ci *
598c2ecf20Sopenharmony_ci */
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistruct virtio_chan {
628c2ecf20Sopenharmony_ci	bool inuse;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	spinlock_t lock;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	struct p9_client *client;
678c2ecf20Sopenharmony_ci	struct virtio_device *vdev;
688c2ecf20Sopenharmony_ci	struct virtqueue *vq;
698c2ecf20Sopenharmony_ci	int ring_bufs_avail;
708c2ecf20Sopenharmony_ci	wait_queue_head_t *vc_wq;
718c2ecf20Sopenharmony_ci	/* This is global limit. Since we don't have a global structure,
728c2ecf20Sopenharmony_ci	 * will be placing it in each channel.
738c2ecf20Sopenharmony_ci	 */
748c2ecf20Sopenharmony_ci	unsigned long p9_max_pages;
758c2ecf20Sopenharmony_ci	/* Scatterlist: can be too big for stack. */
768c2ecf20Sopenharmony_ci	struct scatterlist sg[VIRTQUEUE_NUM];
778c2ecf20Sopenharmony_ci	/*
788c2ecf20Sopenharmony_ci	 * tag name to identify a mount null terminated
798c2ecf20Sopenharmony_ci	 */
808c2ecf20Sopenharmony_ci	char *tag;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	struct list_head chan_list;
838c2ecf20Sopenharmony_ci};
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic struct list_head virtio_chan_list;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci/* How many bytes left in this page. */
888c2ecf20Sopenharmony_cistatic unsigned int rest_of_page(void *data)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	return PAGE_SIZE - offset_in_page(data);
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci/**
948c2ecf20Sopenharmony_ci * p9_virtio_close - reclaim resources of a channel
958c2ecf20Sopenharmony_ci * @client: client instance
968c2ecf20Sopenharmony_ci *
978c2ecf20Sopenharmony_ci * This reclaims a channel by freeing its resources and
988c2ecf20Sopenharmony_ci * reseting its inuse flag.
998c2ecf20Sopenharmony_ci *
1008c2ecf20Sopenharmony_ci */
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic void p9_virtio_close(struct p9_client *client)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	struct virtio_chan *chan = client->trans;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	mutex_lock(&virtio_9p_lock);
1078c2ecf20Sopenharmony_ci	if (chan)
1088c2ecf20Sopenharmony_ci		chan->inuse = false;
1098c2ecf20Sopenharmony_ci	mutex_unlock(&virtio_9p_lock);
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci/**
1138c2ecf20Sopenharmony_ci * req_done - callback which signals activity from the server
1148c2ecf20Sopenharmony_ci * @vq: virtio queue activity was received on
1158c2ecf20Sopenharmony_ci *
1168c2ecf20Sopenharmony_ci * This notifies us that the server has triggered some activity
1178c2ecf20Sopenharmony_ci * on the virtio channel - most likely a response to request we
1188c2ecf20Sopenharmony_ci * sent.  Figure out which requests now have responses and wake up
1198c2ecf20Sopenharmony_ci * those threads.
1208c2ecf20Sopenharmony_ci *
1218c2ecf20Sopenharmony_ci * Bugs: could do with some additional sanity checking, but appears to work.
1228c2ecf20Sopenharmony_ci *
1238c2ecf20Sopenharmony_ci */
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic void req_done(struct virtqueue *vq)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	struct virtio_chan *chan = vq->vdev->priv;
1288c2ecf20Sopenharmony_ci	unsigned int len;
1298c2ecf20Sopenharmony_ci	struct p9_req_t *req;
1308c2ecf20Sopenharmony_ci	bool need_wakeup = false;
1318c2ecf20Sopenharmony_ci	unsigned long flags;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	p9_debug(P9_DEBUG_TRANS, ": request done\n");
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chan->lock, flags);
1368c2ecf20Sopenharmony_ci	while ((req = virtqueue_get_buf(chan->vq, &len)) != NULL) {
1378c2ecf20Sopenharmony_ci		if (!chan->ring_bufs_avail) {
1388c2ecf20Sopenharmony_ci			chan->ring_bufs_avail = 1;
1398c2ecf20Sopenharmony_ci			need_wakeup = true;
1408c2ecf20Sopenharmony_ci		}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci		if (len) {
1438c2ecf20Sopenharmony_ci			req->rc.size = len;
1448c2ecf20Sopenharmony_ci			p9_client_cb(chan->client, req, REQ_STATUS_RCVD);
1458c2ecf20Sopenharmony_ci		}
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chan->lock, flags);
1488c2ecf20Sopenharmony_ci	/* Wakeup if anyone waiting for VirtIO ring space. */
1498c2ecf20Sopenharmony_ci	if (need_wakeup)
1508c2ecf20Sopenharmony_ci		wake_up(chan->vc_wq);
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci/**
1548c2ecf20Sopenharmony_ci * pack_sg_list - pack a scatter gather list from a linear buffer
1558c2ecf20Sopenharmony_ci * @sg: scatter/gather list to pack into
1568c2ecf20Sopenharmony_ci * @start: which segment of the sg_list to start at
1578c2ecf20Sopenharmony_ci * @limit: maximum segment to pack data to
1588c2ecf20Sopenharmony_ci * @data: data to pack into scatter/gather list
1598c2ecf20Sopenharmony_ci * @count: amount of data to pack into the scatter/gather list
1608c2ecf20Sopenharmony_ci *
1618c2ecf20Sopenharmony_ci * sg_lists have multiple segments of various sizes.  This will pack
1628c2ecf20Sopenharmony_ci * arbitrary data into an existing scatter gather list, segmenting the
1638c2ecf20Sopenharmony_ci * data as necessary within constraints.
1648c2ecf20Sopenharmony_ci *
1658c2ecf20Sopenharmony_ci */
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic int pack_sg_list(struct scatterlist *sg, int start,
1688c2ecf20Sopenharmony_ci			int limit, char *data, int count)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	int s;
1718c2ecf20Sopenharmony_ci	int index = start;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	while (count) {
1748c2ecf20Sopenharmony_ci		s = rest_of_page(data);
1758c2ecf20Sopenharmony_ci		if (s > count)
1768c2ecf20Sopenharmony_ci			s = count;
1778c2ecf20Sopenharmony_ci		BUG_ON(index >= limit);
1788c2ecf20Sopenharmony_ci		/* Make sure we don't terminate early. */
1798c2ecf20Sopenharmony_ci		sg_unmark_end(&sg[index]);
1808c2ecf20Sopenharmony_ci		sg_set_buf(&sg[index++], data, s);
1818c2ecf20Sopenharmony_ci		count -= s;
1828c2ecf20Sopenharmony_ci		data += s;
1838c2ecf20Sopenharmony_ci	}
1848c2ecf20Sopenharmony_ci	if (index-start)
1858c2ecf20Sopenharmony_ci		sg_mark_end(&sg[index - 1]);
1868c2ecf20Sopenharmony_ci	return index-start;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci/* We don't currently allow canceling of virtio requests */
1908c2ecf20Sopenharmony_cistatic int p9_virtio_cancel(struct p9_client *client, struct p9_req_t *req)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	return 1;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci/* Reply won't come, so drop req ref */
1968c2ecf20Sopenharmony_cistatic int p9_virtio_cancelled(struct p9_client *client, struct p9_req_t *req)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	p9_req_put(req);
1998c2ecf20Sopenharmony_ci	return 0;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci/**
2038c2ecf20Sopenharmony_ci * pack_sg_list_p - Just like pack_sg_list. Instead of taking a buffer,
2048c2ecf20Sopenharmony_ci * this takes a list of pages.
2058c2ecf20Sopenharmony_ci * @sg: scatter/gather list to pack into
2068c2ecf20Sopenharmony_ci * @start: which segment of the sg_list to start at
2078c2ecf20Sopenharmony_ci * @pdata: a list of pages to add into sg.
2088c2ecf20Sopenharmony_ci * @nr_pages: number of pages to pack into the scatter/gather list
2098c2ecf20Sopenharmony_ci * @offs: amount of data in the beginning of first page _not_ to pack
2108c2ecf20Sopenharmony_ci * @count: amount of data to pack into the scatter/gather list
2118c2ecf20Sopenharmony_ci */
2128c2ecf20Sopenharmony_cistatic int
2138c2ecf20Sopenharmony_cipack_sg_list_p(struct scatterlist *sg, int start, int limit,
2148c2ecf20Sopenharmony_ci	       struct page **pdata, int nr_pages, size_t offs, int count)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	int i = 0, s;
2178c2ecf20Sopenharmony_ci	int data_off = offs;
2188c2ecf20Sopenharmony_ci	int index = start;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	BUG_ON(nr_pages > (limit - start));
2218c2ecf20Sopenharmony_ci	/*
2228c2ecf20Sopenharmony_ci	 * if the first page doesn't start at
2238c2ecf20Sopenharmony_ci	 * page boundary find the offset
2248c2ecf20Sopenharmony_ci	 */
2258c2ecf20Sopenharmony_ci	while (nr_pages) {
2268c2ecf20Sopenharmony_ci		s = PAGE_SIZE - data_off;
2278c2ecf20Sopenharmony_ci		if (s > count)
2288c2ecf20Sopenharmony_ci			s = count;
2298c2ecf20Sopenharmony_ci		BUG_ON(index >= limit);
2308c2ecf20Sopenharmony_ci		/* Make sure we don't terminate early. */
2318c2ecf20Sopenharmony_ci		sg_unmark_end(&sg[index]);
2328c2ecf20Sopenharmony_ci		sg_set_page(&sg[index++], pdata[i++], s, data_off);
2338c2ecf20Sopenharmony_ci		data_off = 0;
2348c2ecf20Sopenharmony_ci		count -= s;
2358c2ecf20Sopenharmony_ci		nr_pages--;
2368c2ecf20Sopenharmony_ci	}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	if (index-start)
2398c2ecf20Sopenharmony_ci		sg_mark_end(&sg[index - 1]);
2408c2ecf20Sopenharmony_ci	return index - start;
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci/**
2448c2ecf20Sopenharmony_ci * p9_virtio_request - issue a request
2458c2ecf20Sopenharmony_ci * @client: client instance issuing the request
2468c2ecf20Sopenharmony_ci * @req: request to be issued
2478c2ecf20Sopenharmony_ci *
2488c2ecf20Sopenharmony_ci */
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cistatic int
2518c2ecf20Sopenharmony_cip9_virtio_request(struct p9_client *client, struct p9_req_t *req)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	int err;
2548c2ecf20Sopenharmony_ci	int in, out, out_sgs, in_sgs;
2558c2ecf20Sopenharmony_ci	unsigned long flags;
2568c2ecf20Sopenharmony_ci	struct virtio_chan *chan = client->trans;
2578c2ecf20Sopenharmony_ci	struct scatterlist *sgs[2];
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	p9_debug(P9_DEBUG_TRANS, "9p debug: virtio request\n");
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	req->status = REQ_STATUS_SENT;
2628c2ecf20Sopenharmony_cireq_retry:
2638c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chan->lock, flags);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	out_sgs = in_sgs = 0;
2668c2ecf20Sopenharmony_ci	/* Handle out VirtIO ring buffers */
2678c2ecf20Sopenharmony_ci	out = pack_sg_list(chan->sg, 0,
2688c2ecf20Sopenharmony_ci			   VIRTQUEUE_NUM, req->tc.sdata, req->tc.size);
2698c2ecf20Sopenharmony_ci	if (out)
2708c2ecf20Sopenharmony_ci		sgs[out_sgs++] = chan->sg;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	in = pack_sg_list(chan->sg, out,
2738c2ecf20Sopenharmony_ci			  VIRTQUEUE_NUM, req->rc.sdata, req->rc.capacity);
2748c2ecf20Sopenharmony_ci	if (in)
2758c2ecf20Sopenharmony_ci		sgs[out_sgs + in_sgs++] = chan->sg + out;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	err = virtqueue_add_sgs(chan->vq, sgs, out_sgs, in_sgs, req,
2788c2ecf20Sopenharmony_ci				GFP_ATOMIC);
2798c2ecf20Sopenharmony_ci	if (err < 0) {
2808c2ecf20Sopenharmony_ci		if (err == -ENOSPC) {
2818c2ecf20Sopenharmony_ci			chan->ring_bufs_avail = 0;
2828c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&chan->lock, flags);
2838c2ecf20Sopenharmony_ci			err = wait_event_killable(*chan->vc_wq,
2848c2ecf20Sopenharmony_ci						  chan->ring_bufs_avail);
2858c2ecf20Sopenharmony_ci			if (err  == -ERESTARTSYS)
2868c2ecf20Sopenharmony_ci				return err;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci			p9_debug(P9_DEBUG_TRANS, "Retry virtio request\n");
2898c2ecf20Sopenharmony_ci			goto req_retry;
2908c2ecf20Sopenharmony_ci		} else {
2918c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&chan->lock, flags);
2928c2ecf20Sopenharmony_ci			p9_debug(P9_DEBUG_TRANS,
2938c2ecf20Sopenharmony_ci				 "virtio rpc add_sgs returned failure\n");
2948c2ecf20Sopenharmony_ci			return -EIO;
2958c2ecf20Sopenharmony_ci		}
2968c2ecf20Sopenharmony_ci	}
2978c2ecf20Sopenharmony_ci	virtqueue_kick(chan->vq);
2988c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chan->lock, flags);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	p9_debug(P9_DEBUG_TRANS, "virtio request kicked\n");
3018c2ecf20Sopenharmony_ci	return 0;
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic int p9_get_mapped_pages(struct virtio_chan *chan,
3058c2ecf20Sopenharmony_ci			       struct page ***pages,
3068c2ecf20Sopenharmony_ci			       struct iov_iter *data,
3078c2ecf20Sopenharmony_ci			       int count,
3088c2ecf20Sopenharmony_ci			       size_t *offs,
3098c2ecf20Sopenharmony_ci			       int *need_drop)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	int nr_pages;
3128c2ecf20Sopenharmony_ci	int err;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	if (!iov_iter_count(data))
3158c2ecf20Sopenharmony_ci		return 0;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	if (!iov_iter_is_kvec(data)) {
3188c2ecf20Sopenharmony_ci		int n;
3198c2ecf20Sopenharmony_ci		/*
3208c2ecf20Sopenharmony_ci		 * We allow only p9_max_pages pinned. We wait for the
3218c2ecf20Sopenharmony_ci		 * Other zc request to finish here
3228c2ecf20Sopenharmony_ci		 */
3238c2ecf20Sopenharmony_ci		if (atomic_read(&vp_pinned) >= chan->p9_max_pages) {
3248c2ecf20Sopenharmony_ci			err = wait_event_killable(vp_wq,
3258c2ecf20Sopenharmony_ci			      (atomic_read(&vp_pinned) < chan->p9_max_pages));
3268c2ecf20Sopenharmony_ci			if (err == -ERESTARTSYS)
3278c2ecf20Sopenharmony_ci				return err;
3288c2ecf20Sopenharmony_ci		}
3298c2ecf20Sopenharmony_ci		n = iov_iter_get_pages_alloc(data, pages, count, offs);
3308c2ecf20Sopenharmony_ci		if (n < 0)
3318c2ecf20Sopenharmony_ci			return n;
3328c2ecf20Sopenharmony_ci		*need_drop = 1;
3338c2ecf20Sopenharmony_ci		nr_pages = DIV_ROUND_UP(n + *offs, PAGE_SIZE);
3348c2ecf20Sopenharmony_ci		atomic_add(nr_pages, &vp_pinned);
3358c2ecf20Sopenharmony_ci		return n;
3368c2ecf20Sopenharmony_ci	} else {
3378c2ecf20Sopenharmony_ci		/* kernel buffer, no need to pin pages */
3388c2ecf20Sopenharmony_ci		int index;
3398c2ecf20Sopenharmony_ci		size_t len;
3408c2ecf20Sopenharmony_ci		void *p;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci		/* we'd already checked that it's non-empty */
3438c2ecf20Sopenharmony_ci		while (1) {
3448c2ecf20Sopenharmony_ci			len = iov_iter_single_seg_count(data);
3458c2ecf20Sopenharmony_ci			if (likely(len)) {
3468c2ecf20Sopenharmony_ci				p = data->kvec->iov_base + data->iov_offset;
3478c2ecf20Sopenharmony_ci				break;
3488c2ecf20Sopenharmony_ci			}
3498c2ecf20Sopenharmony_ci			iov_iter_advance(data, 0);
3508c2ecf20Sopenharmony_ci		}
3518c2ecf20Sopenharmony_ci		if (len > count)
3528c2ecf20Sopenharmony_ci			len = count;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci		nr_pages = DIV_ROUND_UP((unsigned long)p + len, PAGE_SIZE) -
3558c2ecf20Sopenharmony_ci			   (unsigned long)p / PAGE_SIZE;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci		*pages = kmalloc_array(nr_pages, sizeof(struct page *),
3588c2ecf20Sopenharmony_ci				       GFP_NOFS);
3598c2ecf20Sopenharmony_ci		if (!*pages)
3608c2ecf20Sopenharmony_ci			return -ENOMEM;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci		*need_drop = 0;
3638c2ecf20Sopenharmony_ci		p -= (*offs = offset_in_page(p));
3648c2ecf20Sopenharmony_ci		for (index = 0; index < nr_pages; index++) {
3658c2ecf20Sopenharmony_ci			if (is_vmalloc_addr(p))
3668c2ecf20Sopenharmony_ci				(*pages)[index] = vmalloc_to_page(p);
3678c2ecf20Sopenharmony_ci			else
3688c2ecf20Sopenharmony_ci				(*pages)[index] = kmap_to_page(p);
3698c2ecf20Sopenharmony_ci			p += PAGE_SIZE;
3708c2ecf20Sopenharmony_ci		}
3718c2ecf20Sopenharmony_ci		return len;
3728c2ecf20Sopenharmony_ci	}
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci/**
3768c2ecf20Sopenharmony_ci * p9_virtio_zc_request - issue a zero copy request
3778c2ecf20Sopenharmony_ci * @client: client instance issuing the request
3788c2ecf20Sopenharmony_ci * @req: request to be issued
3798c2ecf20Sopenharmony_ci * @uidata: user buffer that should be used for zero copy read
3808c2ecf20Sopenharmony_ci * @uodata: user buffer that should be used for zero copy write
3818c2ecf20Sopenharmony_ci * @inlen: read buffer size
3828c2ecf20Sopenharmony_ci * @outlen: write buffer size
3838c2ecf20Sopenharmony_ci * @in_hdr_len: reader header size, This is the size of response protocol data
3848c2ecf20Sopenharmony_ci *
3858c2ecf20Sopenharmony_ci */
3868c2ecf20Sopenharmony_cistatic int
3878c2ecf20Sopenharmony_cip9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
3888c2ecf20Sopenharmony_ci		     struct iov_iter *uidata, struct iov_iter *uodata,
3898c2ecf20Sopenharmony_ci		     int inlen, int outlen, int in_hdr_len)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	int in, out, err, out_sgs, in_sgs;
3928c2ecf20Sopenharmony_ci	unsigned long flags;
3938c2ecf20Sopenharmony_ci	int in_nr_pages = 0, out_nr_pages = 0;
3948c2ecf20Sopenharmony_ci	struct page **in_pages = NULL, **out_pages = NULL;
3958c2ecf20Sopenharmony_ci	struct virtio_chan *chan = client->trans;
3968c2ecf20Sopenharmony_ci	struct scatterlist *sgs[4];
3978c2ecf20Sopenharmony_ci	size_t offs = 0;
3988c2ecf20Sopenharmony_ci	int need_drop = 0;
3998c2ecf20Sopenharmony_ci	int kicked = 0;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	p9_debug(P9_DEBUG_TRANS, "virtio request\n");
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	if (uodata) {
4048c2ecf20Sopenharmony_ci		__le32 sz;
4058c2ecf20Sopenharmony_ci		int n = p9_get_mapped_pages(chan, &out_pages, uodata,
4068c2ecf20Sopenharmony_ci					    outlen, &offs, &need_drop);
4078c2ecf20Sopenharmony_ci		if (n < 0) {
4088c2ecf20Sopenharmony_ci			err = n;
4098c2ecf20Sopenharmony_ci			goto err_out;
4108c2ecf20Sopenharmony_ci		}
4118c2ecf20Sopenharmony_ci		out_nr_pages = DIV_ROUND_UP(n + offs, PAGE_SIZE);
4128c2ecf20Sopenharmony_ci		if (n != outlen) {
4138c2ecf20Sopenharmony_ci			__le32 v = cpu_to_le32(n);
4148c2ecf20Sopenharmony_ci			memcpy(&req->tc.sdata[req->tc.size - 4], &v, 4);
4158c2ecf20Sopenharmony_ci			outlen = n;
4168c2ecf20Sopenharmony_ci		}
4178c2ecf20Sopenharmony_ci		/* The size field of the message must include the length of the
4188c2ecf20Sopenharmony_ci		 * header and the length of the data.  We didn't actually know
4198c2ecf20Sopenharmony_ci		 * the length of the data until this point so add it in now.
4208c2ecf20Sopenharmony_ci		 */
4218c2ecf20Sopenharmony_ci		sz = cpu_to_le32(req->tc.size + outlen);
4228c2ecf20Sopenharmony_ci		memcpy(&req->tc.sdata[0], &sz, sizeof(sz));
4238c2ecf20Sopenharmony_ci	} else if (uidata) {
4248c2ecf20Sopenharmony_ci		int n = p9_get_mapped_pages(chan, &in_pages, uidata,
4258c2ecf20Sopenharmony_ci					    inlen, &offs, &need_drop);
4268c2ecf20Sopenharmony_ci		if (n < 0) {
4278c2ecf20Sopenharmony_ci			err = n;
4288c2ecf20Sopenharmony_ci			goto err_out;
4298c2ecf20Sopenharmony_ci		}
4308c2ecf20Sopenharmony_ci		in_nr_pages = DIV_ROUND_UP(n + offs, PAGE_SIZE);
4318c2ecf20Sopenharmony_ci		if (n != inlen) {
4328c2ecf20Sopenharmony_ci			__le32 v = cpu_to_le32(n);
4338c2ecf20Sopenharmony_ci			memcpy(&req->tc.sdata[req->tc.size - 4], &v, 4);
4348c2ecf20Sopenharmony_ci			inlen = n;
4358c2ecf20Sopenharmony_ci		}
4368c2ecf20Sopenharmony_ci	}
4378c2ecf20Sopenharmony_ci	req->status = REQ_STATUS_SENT;
4388c2ecf20Sopenharmony_cireq_retry_pinned:
4398c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chan->lock, flags);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	out_sgs = in_sgs = 0;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	/* out data */
4448c2ecf20Sopenharmony_ci	out = pack_sg_list(chan->sg, 0,
4458c2ecf20Sopenharmony_ci			   VIRTQUEUE_NUM, req->tc.sdata, req->tc.size);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	if (out)
4488c2ecf20Sopenharmony_ci		sgs[out_sgs++] = chan->sg;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	if (out_pages) {
4518c2ecf20Sopenharmony_ci		sgs[out_sgs++] = chan->sg + out;
4528c2ecf20Sopenharmony_ci		out += pack_sg_list_p(chan->sg, out, VIRTQUEUE_NUM,
4538c2ecf20Sopenharmony_ci				      out_pages, out_nr_pages, offs, outlen);
4548c2ecf20Sopenharmony_ci	}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	/*
4578c2ecf20Sopenharmony_ci	 * Take care of in data
4588c2ecf20Sopenharmony_ci	 * For example TREAD have 11.
4598c2ecf20Sopenharmony_ci	 * 11 is the read/write header = PDU Header(7) + IO Size (4).
4608c2ecf20Sopenharmony_ci	 * Arrange in such a way that server places header in the
4618c2ecf20Sopenharmony_ci	 * alloced memory and payload onto the user buffer.
4628c2ecf20Sopenharmony_ci	 */
4638c2ecf20Sopenharmony_ci	in = pack_sg_list(chan->sg, out,
4648c2ecf20Sopenharmony_ci			  VIRTQUEUE_NUM, req->rc.sdata, in_hdr_len);
4658c2ecf20Sopenharmony_ci	if (in)
4668c2ecf20Sopenharmony_ci		sgs[out_sgs + in_sgs++] = chan->sg + out;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	if (in_pages) {
4698c2ecf20Sopenharmony_ci		sgs[out_sgs + in_sgs++] = chan->sg + out + in;
4708c2ecf20Sopenharmony_ci		in += pack_sg_list_p(chan->sg, out + in, VIRTQUEUE_NUM,
4718c2ecf20Sopenharmony_ci				     in_pages, in_nr_pages, offs, inlen);
4728c2ecf20Sopenharmony_ci	}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	BUG_ON(out_sgs + in_sgs > ARRAY_SIZE(sgs));
4758c2ecf20Sopenharmony_ci	err = virtqueue_add_sgs(chan->vq, sgs, out_sgs, in_sgs, req,
4768c2ecf20Sopenharmony_ci				GFP_ATOMIC);
4778c2ecf20Sopenharmony_ci	if (err < 0) {
4788c2ecf20Sopenharmony_ci		if (err == -ENOSPC) {
4798c2ecf20Sopenharmony_ci			chan->ring_bufs_avail = 0;
4808c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&chan->lock, flags);
4818c2ecf20Sopenharmony_ci			err = wait_event_killable(*chan->vc_wq,
4828c2ecf20Sopenharmony_ci						  chan->ring_bufs_avail);
4838c2ecf20Sopenharmony_ci			if (err  == -ERESTARTSYS)
4848c2ecf20Sopenharmony_ci				goto err_out;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci			p9_debug(P9_DEBUG_TRANS, "Retry virtio request\n");
4878c2ecf20Sopenharmony_ci			goto req_retry_pinned;
4888c2ecf20Sopenharmony_ci		} else {
4898c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&chan->lock, flags);
4908c2ecf20Sopenharmony_ci			p9_debug(P9_DEBUG_TRANS,
4918c2ecf20Sopenharmony_ci				 "virtio rpc add_sgs returned failure\n");
4928c2ecf20Sopenharmony_ci			err = -EIO;
4938c2ecf20Sopenharmony_ci			goto err_out;
4948c2ecf20Sopenharmony_ci		}
4958c2ecf20Sopenharmony_ci	}
4968c2ecf20Sopenharmony_ci	virtqueue_kick(chan->vq);
4978c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chan->lock, flags);
4988c2ecf20Sopenharmony_ci	kicked = 1;
4998c2ecf20Sopenharmony_ci	p9_debug(P9_DEBUG_TRANS, "virtio request kicked\n");
5008c2ecf20Sopenharmony_ci	err = wait_event_killable(req->wq, req->status >= REQ_STATUS_RCVD);
5018c2ecf20Sopenharmony_ci	/*
5028c2ecf20Sopenharmony_ci	 * Non kernel buffers are pinned, unpin them
5038c2ecf20Sopenharmony_ci	 */
5048c2ecf20Sopenharmony_cierr_out:
5058c2ecf20Sopenharmony_ci	if (need_drop) {
5068c2ecf20Sopenharmony_ci		if (in_pages) {
5078c2ecf20Sopenharmony_ci			p9_release_pages(in_pages, in_nr_pages);
5088c2ecf20Sopenharmony_ci			atomic_sub(in_nr_pages, &vp_pinned);
5098c2ecf20Sopenharmony_ci		}
5108c2ecf20Sopenharmony_ci		if (out_pages) {
5118c2ecf20Sopenharmony_ci			p9_release_pages(out_pages, out_nr_pages);
5128c2ecf20Sopenharmony_ci			atomic_sub(out_nr_pages, &vp_pinned);
5138c2ecf20Sopenharmony_ci		}
5148c2ecf20Sopenharmony_ci		/* wakeup anybody waiting for slots to pin pages */
5158c2ecf20Sopenharmony_ci		wake_up(&vp_wq);
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci	kvfree(in_pages);
5188c2ecf20Sopenharmony_ci	kvfree(out_pages);
5198c2ecf20Sopenharmony_ci	if (!kicked) {
5208c2ecf20Sopenharmony_ci		/* reply won't come */
5218c2ecf20Sopenharmony_ci		p9_req_put(req);
5228c2ecf20Sopenharmony_ci	}
5238c2ecf20Sopenharmony_ci	return err;
5248c2ecf20Sopenharmony_ci}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_cistatic ssize_t p9_mount_tag_show(struct device *dev,
5278c2ecf20Sopenharmony_ci				struct device_attribute *attr, char *buf)
5288c2ecf20Sopenharmony_ci{
5298c2ecf20Sopenharmony_ci	struct virtio_chan *chan;
5308c2ecf20Sopenharmony_ci	struct virtio_device *vdev;
5318c2ecf20Sopenharmony_ci	int tag_len;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	vdev = dev_to_virtio(dev);
5348c2ecf20Sopenharmony_ci	chan = vdev->priv;
5358c2ecf20Sopenharmony_ci	tag_len = strlen(chan->tag);
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	memcpy(buf, chan->tag, tag_len + 1);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	return tag_len + 1;
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_cistatic DEVICE_ATTR(mount_tag, 0444, p9_mount_tag_show, NULL);
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci/**
5458c2ecf20Sopenharmony_ci * p9_virtio_probe - probe for existence of 9P virtio channels
5468c2ecf20Sopenharmony_ci * @vdev: virtio device to probe
5478c2ecf20Sopenharmony_ci *
5488c2ecf20Sopenharmony_ci * This probes for existing virtio channels.
5498c2ecf20Sopenharmony_ci *
5508c2ecf20Sopenharmony_ci */
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_cistatic int p9_virtio_probe(struct virtio_device *vdev)
5538c2ecf20Sopenharmony_ci{
5548c2ecf20Sopenharmony_ci	__u16 tag_len;
5558c2ecf20Sopenharmony_ci	char *tag;
5568c2ecf20Sopenharmony_ci	int err;
5578c2ecf20Sopenharmony_ci	struct virtio_chan *chan;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	if (!vdev->config->get) {
5608c2ecf20Sopenharmony_ci		dev_err(&vdev->dev, "%s failure: config access disabled\n",
5618c2ecf20Sopenharmony_ci			__func__);
5628c2ecf20Sopenharmony_ci		return -EINVAL;
5638c2ecf20Sopenharmony_ci	}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	chan = kmalloc(sizeof(struct virtio_chan), GFP_KERNEL);
5668c2ecf20Sopenharmony_ci	if (!chan) {
5678c2ecf20Sopenharmony_ci		pr_err("Failed to allocate virtio 9P channel\n");
5688c2ecf20Sopenharmony_ci		err = -ENOMEM;
5698c2ecf20Sopenharmony_ci		goto fail;
5708c2ecf20Sopenharmony_ci	}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	chan->vdev = vdev;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	/* We expect one virtqueue, for requests. */
5758c2ecf20Sopenharmony_ci	chan->vq = virtio_find_single_vq(vdev, req_done, "requests");
5768c2ecf20Sopenharmony_ci	if (IS_ERR(chan->vq)) {
5778c2ecf20Sopenharmony_ci		err = PTR_ERR(chan->vq);
5788c2ecf20Sopenharmony_ci		goto out_free_chan;
5798c2ecf20Sopenharmony_ci	}
5808c2ecf20Sopenharmony_ci	chan->vq->vdev->priv = chan;
5818c2ecf20Sopenharmony_ci	spin_lock_init(&chan->lock);
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	sg_init_table(chan->sg, VIRTQUEUE_NUM);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	chan->inuse = false;
5868c2ecf20Sopenharmony_ci	if (virtio_has_feature(vdev, VIRTIO_9P_MOUNT_TAG)) {
5878c2ecf20Sopenharmony_ci		virtio_cread(vdev, struct virtio_9p_config, tag_len, &tag_len);
5888c2ecf20Sopenharmony_ci	} else {
5898c2ecf20Sopenharmony_ci		err = -EINVAL;
5908c2ecf20Sopenharmony_ci		goto out_free_vq;
5918c2ecf20Sopenharmony_ci	}
5928c2ecf20Sopenharmony_ci	tag = kzalloc(tag_len + 1, GFP_KERNEL);
5938c2ecf20Sopenharmony_ci	if (!tag) {
5948c2ecf20Sopenharmony_ci		err = -ENOMEM;
5958c2ecf20Sopenharmony_ci		goto out_free_vq;
5968c2ecf20Sopenharmony_ci	}
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	virtio_cread_bytes(vdev, offsetof(struct virtio_9p_config, tag),
5998c2ecf20Sopenharmony_ci			   tag, tag_len);
6008c2ecf20Sopenharmony_ci	chan->tag = tag;
6018c2ecf20Sopenharmony_ci	err = sysfs_create_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
6028c2ecf20Sopenharmony_ci	if (err) {
6038c2ecf20Sopenharmony_ci		goto out_free_tag;
6048c2ecf20Sopenharmony_ci	}
6058c2ecf20Sopenharmony_ci	chan->vc_wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL);
6068c2ecf20Sopenharmony_ci	if (!chan->vc_wq) {
6078c2ecf20Sopenharmony_ci		err = -ENOMEM;
6088c2ecf20Sopenharmony_ci		goto out_remove_file;
6098c2ecf20Sopenharmony_ci	}
6108c2ecf20Sopenharmony_ci	init_waitqueue_head(chan->vc_wq);
6118c2ecf20Sopenharmony_ci	chan->ring_bufs_avail = 1;
6128c2ecf20Sopenharmony_ci	/* Ceiling limit to avoid denial of service attacks */
6138c2ecf20Sopenharmony_ci	chan->p9_max_pages = nr_free_buffer_pages()/4;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	virtio_device_ready(vdev);
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	mutex_lock(&virtio_9p_lock);
6188c2ecf20Sopenharmony_ci	list_add_tail(&chan->chan_list, &virtio_chan_list);
6198c2ecf20Sopenharmony_ci	mutex_unlock(&virtio_9p_lock);
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	/* Let udev rules use the new mount_tag attribute. */
6228c2ecf20Sopenharmony_ci	kobject_uevent(&(vdev->dev.kobj), KOBJ_CHANGE);
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	return 0;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ciout_remove_file:
6278c2ecf20Sopenharmony_ci	sysfs_remove_file(&vdev->dev.kobj, &dev_attr_mount_tag.attr);
6288c2ecf20Sopenharmony_ciout_free_tag:
6298c2ecf20Sopenharmony_ci	kfree(tag);
6308c2ecf20Sopenharmony_ciout_free_vq:
6318c2ecf20Sopenharmony_ci	vdev->config->del_vqs(vdev);
6328c2ecf20Sopenharmony_ciout_free_chan:
6338c2ecf20Sopenharmony_ci	kfree(chan);
6348c2ecf20Sopenharmony_cifail:
6358c2ecf20Sopenharmony_ci	return err;
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci/**
6408c2ecf20Sopenharmony_ci * p9_virtio_create - allocate a new virtio channel
6418c2ecf20Sopenharmony_ci * @client: client instance invoking this transport
6428c2ecf20Sopenharmony_ci * @devname: string identifying the channel to connect to (unused)
6438c2ecf20Sopenharmony_ci * @args: args passed from sys_mount() for per-transport options (unused)
6448c2ecf20Sopenharmony_ci *
6458c2ecf20Sopenharmony_ci * This sets up a transport channel for 9p communication.  Right now
6468c2ecf20Sopenharmony_ci * we only match the first available channel, but eventually we couldlook up
6478c2ecf20Sopenharmony_ci * alternate channels by matching devname versus a virtio_config entry.
6488c2ecf20Sopenharmony_ci * We use a simple reference count mechanism to ensure that only a single
6498c2ecf20Sopenharmony_ci * mount has a channel open at a time.
6508c2ecf20Sopenharmony_ci *
6518c2ecf20Sopenharmony_ci */
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_cistatic int
6548c2ecf20Sopenharmony_cip9_virtio_create(struct p9_client *client, const char *devname, char *args)
6558c2ecf20Sopenharmony_ci{
6568c2ecf20Sopenharmony_ci	struct virtio_chan *chan;
6578c2ecf20Sopenharmony_ci	int ret = -ENOENT;
6588c2ecf20Sopenharmony_ci	int found = 0;
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	if (devname == NULL)
6618c2ecf20Sopenharmony_ci		return -EINVAL;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	mutex_lock(&virtio_9p_lock);
6648c2ecf20Sopenharmony_ci	list_for_each_entry(chan, &virtio_chan_list, chan_list) {
6658c2ecf20Sopenharmony_ci		if (!strcmp(devname, chan->tag)) {
6668c2ecf20Sopenharmony_ci			if (!chan->inuse) {
6678c2ecf20Sopenharmony_ci				chan->inuse = true;
6688c2ecf20Sopenharmony_ci				found = 1;
6698c2ecf20Sopenharmony_ci				break;
6708c2ecf20Sopenharmony_ci			}
6718c2ecf20Sopenharmony_ci			ret = -EBUSY;
6728c2ecf20Sopenharmony_ci		}
6738c2ecf20Sopenharmony_ci	}
6748c2ecf20Sopenharmony_ci	mutex_unlock(&virtio_9p_lock);
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	if (!found) {
6778c2ecf20Sopenharmony_ci		pr_err("no channels available for device %s\n", devname);
6788c2ecf20Sopenharmony_ci		return ret;
6798c2ecf20Sopenharmony_ci	}
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	client->trans = (void *)chan;
6828c2ecf20Sopenharmony_ci	client->status = Connected;
6838c2ecf20Sopenharmony_ci	chan->client = client;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	return 0;
6868c2ecf20Sopenharmony_ci}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci/**
6898c2ecf20Sopenharmony_ci * p9_virtio_remove - clean up resources associated with a virtio device
6908c2ecf20Sopenharmony_ci * @vdev: virtio device to remove
6918c2ecf20Sopenharmony_ci *
6928c2ecf20Sopenharmony_ci */
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_cistatic void p9_virtio_remove(struct virtio_device *vdev)
6958c2ecf20Sopenharmony_ci{
6968c2ecf20Sopenharmony_ci	struct virtio_chan *chan = vdev->priv;
6978c2ecf20Sopenharmony_ci	unsigned long warning_time;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	mutex_lock(&virtio_9p_lock);
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	/* Remove self from list so we don't get new users. */
7028c2ecf20Sopenharmony_ci	list_del(&chan->chan_list);
7038c2ecf20Sopenharmony_ci	warning_time = jiffies;
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	/* Wait for existing users to close. */
7068c2ecf20Sopenharmony_ci	while (chan->inuse) {
7078c2ecf20Sopenharmony_ci		mutex_unlock(&virtio_9p_lock);
7088c2ecf20Sopenharmony_ci		msleep(250);
7098c2ecf20Sopenharmony_ci		if (time_after(jiffies, warning_time + 10 * HZ)) {
7108c2ecf20Sopenharmony_ci			dev_emerg(&vdev->dev,
7118c2ecf20Sopenharmony_ci				  "p9_virtio_remove: waiting for device in use.\n");
7128c2ecf20Sopenharmony_ci			warning_time = jiffies;
7138c2ecf20Sopenharmony_ci		}
7148c2ecf20Sopenharmony_ci		mutex_lock(&virtio_9p_lock);
7158c2ecf20Sopenharmony_ci	}
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	mutex_unlock(&virtio_9p_lock);
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	vdev->config->reset(vdev);
7208c2ecf20Sopenharmony_ci	vdev->config->del_vqs(vdev);
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
7238c2ecf20Sopenharmony_ci	kobject_uevent(&(vdev->dev.kobj), KOBJ_CHANGE);
7248c2ecf20Sopenharmony_ci	kfree(chan->tag);
7258c2ecf20Sopenharmony_ci	kfree(chan->vc_wq);
7268c2ecf20Sopenharmony_ci	kfree(chan);
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci}
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_cistatic struct virtio_device_id id_table[] = {
7318c2ecf20Sopenharmony_ci	{ VIRTIO_ID_9P, VIRTIO_DEV_ANY_ID },
7328c2ecf20Sopenharmony_ci	{ 0 },
7338c2ecf20Sopenharmony_ci};
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_cistatic unsigned int features[] = {
7368c2ecf20Sopenharmony_ci	VIRTIO_9P_MOUNT_TAG,
7378c2ecf20Sopenharmony_ci};
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci/* The standard "struct lguest_driver": */
7408c2ecf20Sopenharmony_cistatic struct virtio_driver p9_virtio_drv = {
7418c2ecf20Sopenharmony_ci	.feature_table  = features,
7428c2ecf20Sopenharmony_ci	.feature_table_size = ARRAY_SIZE(features),
7438c2ecf20Sopenharmony_ci	.driver.name    = KBUILD_MODNAME,
7448c2ecf20Sopenharmony_ci	.driver.owner	= THIS_MODULE,
7458c2ecf20Sopenharmony_ci	.id_table	= id_table,
7468c2ecf20Sopenharmony_ci	.probe		= p9_virtio_probe,
7478c2ecf20Sopenharmony_ci	.remove		= p9_virtio_remove,
7488c2ecf20Sopenharmony_ci};
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_cistatic struct p9_trans_module p9_virtio_trans = {
7518c2ecf20Sopenharmony_ci	.name = "virtio",
7528c2ecf20Sopenharmony_ci	.create = p9_virtio_create,
7538c2ecf20Sopenharmony_ci	.close = p9_virtio_close,
7548c2ecf20Sopenharmony_ci	.request = p9_virtio_request,
7558c2ecf20Sopenharmony_ci	.zc_request = p9_virtio_zc_request,
7568c2ecf20Sopenharmony_ci	.cancel = p9_virtio_cancel,
7578c2ecf20Sopenharmony_ci	.cancelled = p9_virtio_cancelled,
7588c2ecf20Sopenharmony_ci	/*
7598c2ecf20Sopenharmony_ci	 * We leave one entry for input and one entry for response
7608c2ecf20Sopenharmony_ci	 * headers. We also skip one more entry to accomodate, address
7618c2ecf20Sopenharmony_ci	 * that are not at page boundary, that can result in an extra
7628c2ecf20Sopenharmony_ci	 * page in zero copy.
7638c2ecf20Sopenharmony_ci	 */
7648c2ecf20Sopenharmony_ci	.maxsize = PAGE_SIZE * (VIRTQUEUE_NUM - 3),
7658c2ecf20Sopenharmony_ci	.def = 1,
7668c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
7678c2ecf20Sopenharmony_ci};
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci/* The standard init function */
7708c2ecf20Sopenharmony_cistatic int __init p9_virtio_init(void)
7718c2ecf20Sopenharmony_ci{
7728c2ecf20Sopenharmony_ci	int rc;
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&virtio_chan_list);
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	v9fs_register_trans(&p9_virtio_trans);
7778c2ecf20Sopenharmony_ci	rc = register_virtio_driver(&p9_virtio_drv);
7788c2ecf20Sopenharmony_ci	if (rc)
7798c2ecf20Sopenharmony_ci		v9fs_unregister_trans(&p9_virtio_trans);
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	return rc;
7828c2ecf20Sopenharmony_ci}
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_cistatic void __exit p9_virtio_cleanup(void)
7858c2ecf20Sopenharmony_ci{
7868c2ecf20Sopenharmony_ci	unregister_virtio_driver(&p9_virtio_drv);
7878c2ecf20Sopenharmony_ci	v9fs_unregister_trans(&p9_virtio_trans);
7888c2ecf20Sopenharmony_ci}
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_cimodule_init(p9_virtio_init);
7918c2ecf20Sopenharmony_cimodule_exit(p9_virtio_cleanup);
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(virtio, id_table);
7948c2ecf20Sopenharmony_ciMODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
7958c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Virtio 9p Transport");
7968c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
797