Blame view

net/9p/trans_virtio.c 15.8 KB
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
1
  /*
fea511a64   Eric Van Hensbergen   9p: move request ...
2
   * The Virtio 9p transport driver
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
3
   *
e2735b772   Eric Van Hensbergen   9p: block-based v...
4
5
   * This is a block based transport driver based on the lguest block driver
   * code.
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
6
   *
fea511a64   Eric Van Hensbergen   9p: move request ...
7
   *  Copyright (C) 2007, 2008 Eric Van Hensbergen, IBM Corporation
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
   *
   *  Based on virtio console driver
   *  Copyright (C) 2006, 2007 Rusty Russell, IBM Corporation
   *
   *  This program is free software; you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License version 2
   *  as published by the Free Software Foundation.
   *
   *  This program is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *  along with this program; if not, write to:
   *  Free Software Foundation
   *  51 Franklin Street, Fifth Floor
   *  Boston, MA  02111-1301  USA
   *
   */
  
  #include <linux/in.h>
  #include <linux/module.h>
  #include <linux/net.h>
  #include <linux/ipv6.h>
  #include <linux/errno.h>
  #include <linux/kernel.h>
  #include <linux/un.h>
  #include <linux/uaccess.h>
  #include <linux/inet.h>
  #include <linux/idr.h>
  #include <linux/file.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
40
  #include <linux/slab.h>
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
41
42
  #include <net/9p/9p.h>
  #include <linux/parser.h>
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
43
  #include <net/9p/client.h>
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
44
45
  #include <net/9p/transport.h>
  #include <linux/scatterlist.h>
68da9ba4e   Venkateswararao Jujjuri (JV)   [net/9p]: Introdu...
46
  #include <linux/swap.h>
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
47
48
  #include <linux/virtio.h>
  #include <linux/virtio_9p.h>
4038866da   Venkateswararao Jujjuri (JV)   [net/9p] Add gup/...
49
  #include "trans_common.h"
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
50

e2735b772   Eric Van Hensbergen   9p: block-based v...
51
  #define VIRTQUEUE_NUM	128
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
52
  /* a single mutex to manage channel initialization and attachment */
c1549497e   Josef 'Jeff' Sipek   9p: use struct mu...
53
  static DEFINE_MUTEX(virtio_9p_lock);
68da9ba4e   Venkateswararao Jujjuri (JV)   [net/9p]: Introdu...
54
55
  static DECLARE_WAIT_QUEUE_HEAD(vp_wq);
  static atomic_t vp_pinned = ATOMIC_INIT(0);
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
56

ee443996a   Eric Van Hensbergen   9p: Documentation...
57
58
59
60
61
  /**
   * struct virtio_chan - per-instance transport information
   * @initialized: whether the channel is initialized
   * @inuse: whether the channel is in use
   * @lock: protects multiple elements within this structure
0e15597eb   Abhishek Kulkarni   9p: minor comment...
62
   * @client: client instance
ee443996a   Eric Van Hensbergen   9p: Documentation...
63
64
   * @vdev: virtio dev associated with this channel
   * @vq: virtio queue associated with this channel
ee443996a   Eric Van Hensbergen   9p: Documentation...
65
66
67
   * @sg: scatter gather list which is used to pack a request (protected?)
   *
   * We keep all per-channel information in a structure.
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
68
69
   * This structure is allocated within the devices dev->mem space.
   * A pointer to the structure will get put in the transport private.
ee443996a   Eric Van Hensbergen   9p: Documentation...
70
   *
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
71
   */
ee443996a   Eric Van Hensbergen   9p: Documentation...
72

37c1209d4   Aneesh Kumar K.V   net/9p: Remove MA...
73
  struct virtio_chan {
ee443996a   Eric Van Hensbergen   9p: Documentation...
74
  	bool inuse;
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
75

e2735b772   Eric Van Hensbergen   9p: block-based v...
76
  	spinlock_t lock;
fea511a64   Eric Van Hensbergen   9p: move request ...
77
  	struct p9_client *client;
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
78
  	struct virtio_device *vdev;
e2735b772   Eric Van Hensbergen   9p: block-based v...
79
  	struct virtqueue *vq;
52f44e0d0   Venkateswararao Jujjuri (JV)   net/9p: Add waitq...
80
81
  	int ring_bufs_avail;
  	wait_queue_head_t *vc_wq;
68da9ba4e   Venkateswararao Jujjuri (JV)   [net/9p]: Introdu...
82
83
84
85
  	/* This is global limit. Since we don't have a global structure,
  	 * will be placing it in each channel.
  	 */
  	int p9_max_pages;
e2735b772   Eric Van Hensbergen   9p: block-based v...
86
87
  	/* Scatterlist: can be too big for stack. */
  	struct scatterlist sg[VIRTQUEUE_NUM];
37c1209d4   Aneesh Kumar K.V   net/9p: Remove MA...
88

97ee9b025   Aneesh Kumar K.V   net/9p: Use the t...
89
90
91
92
93
  	int tag_len;
  	/*
  	 * tag name to identify a mount Non-null terminated
  	 */
  	char *tag;
37c1209d4   Aneesh Kumar K.V   net/9p: Remove MA...
94
95
96
97
  	struct list_head chan_list;
  };
  
  static struct list_head virtio_chan_list;
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
98
99
100
101
102
103
  
  /* How many bytes left in this page. */
  static unsigned int rest_of_page(void *data)
  {
  	return PAGE_SIZE - ((unsigned long)data % PAGE_SIZE);
  }
ee443996a   Eric Van Hensbergen   9p: Documentation...
104
105
  /**
   * p9_virtio_close - reclaim resources of a channel
0e15597eb   Abhishek Kulkarni   9p: minor comment...
106
   * @client: client instance
ee443996a   Eric Van Hensbergen   9p: Documentation...
107
108
109
110
111
   *
   * This reclaims a channel by freeing its resources and
   * reseting its inuse flag.
   *
   */
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
112
  static void p9_virtio_close(struct p9_client *client)
e2735b772   Eric Van Hensbergen   9p: block-based v...
113
  {
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
114
  	struct virtio_chan *chan = client->trans;
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
115

c1549497e   Josef 'Jeff' Sipek   9p: use struct mu...
116
  	mutex_lock(&virtio_9p_lock);
fb786100f   Aneesh Kumar K.V   9p: Fix the kerne...
117
118
  	if (chan)
  		chan->inuse = false;
c1549497e   Josef 'Jeff' Sipek   9p: use struct mu...
119
  	mutex_unlock(&virtio_9p_lock);
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
120
  }
ee443996a   Eric Van Hensbergen   9p: Documentation...
121
122
123
124
125
126
127
128
129
130
131
132
  /**
   * req_done - callback which signals activity from the server
   * @vq: virtio queue activity was received on
   *
   * This notifies us that the server has triggered some activity
   * on the virtio channel - most likely a response to request we
   * sent.  Figure out which requests now have responses and wake up
   * those threads.
   *
   * Bugs: could do with some additional sanity checking, but appears to work.
   *
   */
e2735b772   Eric Van Hensbergen   9p: block-based v...
133
  static void req_done(struct virtqueue *vq)
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
134
  {
e2735b772   Eric Van Hensbergen   9p: block-based v...
135
136
137
  	struct virtio_chan *chan = vq->vdev->priv;
  	struct p9_fcall *rc;
  	unsigned int len;
e2735b772   Eric Van Hensbergen   9p: block-based v...
138
  	struct p9_req_t *req;
419b39561   Venkateswararao Jujjuri (JV)   [net/9p]Serialize...
139
  	unsigned long flags;
e2735b772   Eric Van Hensbergen   9p: block-based v...
140

91b8534fa   Eric Van Hensbergen   9p: make rpc code...
141
142
  	P9_DPRINTK(P9_DEBUG_TRANS, ": request done
  ");
a01a98403   Venkateswararao Jujjuri (JV)   [net/9p] Set the ...
143
  	while (1) {
419b39561   Venkateswararao Jujjuri (JV)   [net/9p]Serialize...
144
145
  		spin_lock_irqsave(&chan->lock, flags);
  		rc = virtqueue_get_buf(chan->vq, &len);
419b39561   Venkateswararao Jujjuri (JV)   [net/9p]Serialize...
146

a01a98403   Venkateswararao Jujjuri (JV)   [net/9p] Set the ...
147
  		if (rc == NULL) {
52f44e0d0   Venkateswararao Jujjuri (JV)   net/9p: Add waitq...
148
  			spin_unlock_irqrestore(&chan->lock, flags);
a01a98403   Venkateswararao Jujjuri (JV)   [net/9p] Set the ...
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  			break;
  		}
  
  		chan->ring_bufs_avail = 1;
  		spin_unlock_irqrestore(&chan->lock, flags);
  		/* Wakeup if anyone waiting for VirtIO ring space. */
  		wake_up(chan->vc_wq);
  		P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p
  ", rc);
  		P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d
  ", rc->tag);
  		req = p9_tag_lookup(chan->client, rc->tag);
  		if (req->tc->private) {
  			struct trans_rpage_info *rp = req->tc->private;
68da9ba4e   Venkateswararao Jujjuri (JV)   [net/9p]: Introdu...
163
  			int p = rp->rp_nr_pages;
a01a98403   Venkateswararao Jujjuri (JV)   [net/9p] Set the ...
164
165
  			/*Release pages */
  			p9_release_req_pages(rp);
68da9ba4e   Venkateswararao Jujjuri (JV)   [net/9p]: Introdu...
166
167
  			atomic_sub(p, &vp_pinned);
  			wake_up(&vp_wq);
a01a98403   Venkateswararao Jujjuri (JV)   [net/9p] Set the ...
168
169
170
  			if (rp->rp_alloc)
  				kfree(rp);
  			req->tc->private = NULL;
419b39561   Venkateswararao Jujjuri (JV)   [net/9p]Serialize...
171
  		}
a01a98403   Venkateswararao Jujjuri (JV)   [net/9p] Set the ...
172
173
174
  		req->status = REQ_STATUS_RCVD;
  		p9_client_cb(chan->client, req);
  	}
e2735b772   Eric Van Hensbergen   9p: block-based v...
175
  }
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
176

ee443996a   Eric Van Hensbergen   9p: Documentation...
177
178
179
180
181
182
183
184
185
186
187
188
189
  /**
   * pack_sg_list - pack a scatter gather list from a linear buffer
   * @sg: scatter/gather list to pack into
   * @start: which segment of the sg_list to start at
   * @limit: maximum segment to pack data to
   * @data: data to pack into scatter/gather list
   * @count: amount of data to pack into the scatter/gather list
   *
   * sg_lists have multiple segments of various sizes.  This will pack
   * arbitrary data into an existing scatter gather list, segmenting the
   * data as necessary within constraints.
   *
   */
e2735b772   Eric Van Hensbergen   9p: block-based v...
190
191
192
193
194
195
196
197
198
199
200
201
202
203
  static int
  pack_sg_list(struct scatterlist *sg, int start, int limit, char *data,
  								int count)
  {
  	int s;
  	int index = start;
  
  	while (count) {
  		s = rest_of_page(data);
  		if (s > count)
  			s = count;
  		sg_set_buf(&sg[index++], data, s);
  		count -= s;
  		data += s;
d6584f3a0   Julia Lawall   net/9p/trans_virt...
204
  		BUG_ON(index > limit);
e2735b772   Eric Van Hensbergen   9p: block-based v...
205
  	}
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
206

e2735b772   Eric Van Hensbergen   9p: block-based v...
207
  	return index-start;
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
208
  }
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
209
210
211
212
213
  /* We don't currently allow canceling of virtio requests */
  static int p9_virtio_cancel(struct p9_client *client, struct p9_req_t *req)
  {
  	return 1;
  }
ee443996a   Eric Van Hensbergen   9p: Documentation...
214
  /**
4038866da   Venkateswararao Jujjuri (JV)   [net/9p] Add gup/...
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
   * pack_sg_list_p - Just like pack_sg_list. Instead of taking a buffer,
   * this takes a list of pages.
   * @sg: scatter/gather list to pack into
   * @start: which segment of the sg_list to start at
   * @pdata_off: Offset into the first page
   * @**pdata: a list of pages to add into sg.
   * @count: amount of data to pack into the scatter/gather list
   */
  static int
  pack_sg_list_p(struct scatterlist *sg, int start, int limit, size_t pdata_off,
  		struct page **pdata, int count)
  {
  	int s;
  	int i = 0;
  	int index = start;
  
  	if (pdata_off) {
  		s = min((int)(PAGE_SIZE - pdata_off), count);
  		sg_set_page(&sg[index++], pdata[i++], s, pdata_off);
  		count -= s;
  	}
  
  	while (count) {
  		BUG_ON(index > limit);
  		s = min((int)PAGE_SIZE, count);
  		sg_set_page(&sg[index++], pdata[i++], s, 0);
  		count -= s;
  	}
  	return index-start;
  }
  
  /**
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
247
   * p9_virtio_request - issue a request
0e15597eb   Abhishek Kulkarni   9p: minor comment...
248
249
   * @client: client instance issuing the request
   * @req: request to be issued
ee443996a   Eric Van Hensbergen   9p: Documentation...
250
251
   *
   */
e2735b772   Eric Van Hensbergen   9p: block-based v...
252
  static int
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
253
  p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
254
  {
4038866da   Venkateswararao Jujjuri (JV)   [net/9p] Add gup/...
255
  	int in, out, inp, outp;
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
256
257
  	struct virtio_chan *chan = client->trans;
  	char *rdata = (char *)req->rc+sizeof(struct p9_fcall);
419b39561   Venkateswararao Jujjuri (JV)   [net/9p]Serialize...
258
  	unsigned long flags;
4038866da   Venkateswararao Jujjuri (JV)   [net/9p] Add gup/...
259
260
261
  	size_t pdata_off = 0;
  	struct trans_rpage_info *rpinfo = NULL;
  	int err, pdata_len = 0;
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
262

91b8534fa   Eric Van Hensbergen   9p: make rpc code...
263
264
  	P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request
  ");
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
265

419b39561   Venkateswararao Jujjuri (JV)   [net/9p]Serialize...
266
  	req->status = REQ_STATUS_SENT;
4038866da   Venkateswararao Jujjuri (JV)   [net/9p] Add gup/...
267
268
269
270
  	if (req->tc->pbuf_size && (req->tc->pubuf && P9_IS_USER_CONTEXT)) {
  		int nr_pages = p9_nr_pages(req);
  		int rpinfo_size = sizeof(struct trans_rpage_info) +
  			sizeof(struct page *) * nr_pages;
68da9ba4e   Venkateswararao Jujjuri (JV)   [net/9p]: Introdu...
271
272
273
274
275
276
277
278
  		if (atomic_read(&vp_pinned) >= chan->p9_max_pages) {
  			err = wait_event_interruptible(vp_wq,
  				atomic_read(&vp_pinned) < chan->p9_max_pages);
  			if (err  == -ERESTARTSYS)
  				return err;
  			P9_DPRINTK(P9_DEBUG_TRANS, "9p: May gup pages now.
  ");
  		}
4038866da   Venkateswararao Jujjuri (JV)   [net/9p] Add gup/...
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
  		if (rpinfo_size <= (req->tc->capacity - req->tc->size)) {
  			/* We can use sdata */
  			req->tc->private = req->tc->sdata + req->tc->size;
  			rpinfo = (struct trans_rpage_info *)req->tc->private;
  			rpinfo->rp_alloc = 0;
  		} else {
  			req->tc->private = kmalloc(rpinfo_size, GFP_NOFS);
  			if (!req->tc->private) {
  				P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: "
  					"private kmalloc returned NULL");
  				return -ENOMEM;
  			}
  			rpinfo = (struct trans_rpage_info *)req->tc->private;
  			rpinfo->rp_alloc = 1;
  		}
  
  		err = p9_payload_gup(req, &pdata_off, &pdata_len, nr_pages,
  				req->tc->id == P9_TREAD ? 1 : 0);
  		if (err < 0) {
  			if (rpinfo->rp_alloc)
  				kfree(rpinfo);
  			return err;
68da9ba4e   Venkateswararao Jujjuri (JV)   [net/9p]: Introdu...
301
302
  		} else {
  			atomic_add(rpinfo->rp_nr_pages, &vp_pinned);
4038866da   Venkateswararao Jujjuri (JV)   [net/9p] Add gup/...
303
304
  		}
  	}
316ad5501   Venkateswararao Jujjuri (JV)   [net/9p] Don't re...
305
  req_retry_pinned:
419b39561   Venkateswararao Jujjuri (JV)   [net/9p]Serialize...
306
  	spin_lock_irqsave(&chan->lock, flags);
4038866da   Venkateswararao Jujjuri (JV)   [net/9p] Add gup/...
307
308
  
  	/* Handle out VirtIO ring buffers */
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
309
  	out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, req->tc->sdata,
4038866da   Venkateswararao Jujjuri (JV)   [net/9p] Add gup/...
310
311
312
313
314
315
316
317
  			req->tc->size);
  
  	if (req->tc->pbuf_size && (req->tc->id == P9_TWRITE)) {
  		/* We have additional write payload buffer to take care */
  		if (req->tc->pubuf && P9_IS_USER_CONTEXT) {
  			outp = pack_sg_list_p(chan->sg, out, VIRTQUEUE_NUM,
  					pdata_off, rpinfo->rp_data, pdata_len);
  		} else {
bd8c8ade6   Aneesh Kumar K.V   9p: Fix sparse error
318
319
320
321
322
  			char *pbuf;
  			if (req->tc->pubuf)
  				pbuf = (__force char *) req->tc->pubuf;
  			else
  				pbuf = req->tc->pkbuf;
4038866da   Venkateswararao Jujjuri (JV)   [net/9p] Add gup/...
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
  			outp = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, pbuf,
  					req->tc->pbuf_size);
  		}
  		out += outp;
  	}
  
  	/* Handle in VirtIO ring buffers */
  	if (req->tc->pbuf_size &&
  		((req->tc->id == P9_TREAD) || (req->tc->id == P9_TREADDIR))) {
  		/*
  		 * Take care of additional Read payload.
  		 * 11 is the read/write header = PDU Header(7) + IO Size (4).
  		 * Arrange in such a way that server places header in the
  		 * alloced memory and payload onto the user buffer.
  		 */
  		inp = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, rdata, 11);
  		/*
  		 * Running executables in the filesystem may result in
  		 * a read request with kernel buffer as opposed to user buffer.
  		 */
  		if (req->tc->pubuf && P9_IS_USER_CONTEXT) {
  			in = pack_sg_list_p(chan->sg, out+inp, VIRTQUEUE_NUM,
  					pdata_off, rpinfo->rp_data, pdata_len);
  		} else {
bd8c8ade6   Aneesh Kumar K.V   9p: Fix sparse error
347
348
349
350
351
  			char *pbuf;
  			if (req->tc->pubuf)
  				pbuf = (__force char *) req->tc->pubuf;
  			else
  				pbuf = req->tc->pkbuf;
4038866da   Venkateswararao Jujjuri (JV)   [net/9p] Add gup/...
352
353
354
355
356
357
358
359
  			in = pack_sg_list(chan->sg, out+inp, VIRTQUEUE_NUM,
  					pbuf, req->tc->pbuf_size);
  		}
  		in += inp;
  	} else {
  		in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, rdata,
  				client->msize);
  	}
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
360

419b39561   Venkateswararao Jujjuri (JV)   [net/9p]Serialize...
361
362
  	err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc);
  	if (err < 0) {
52f44e0d0   Venkateswararao Jujjuri (JV)   net/9p: Add waitq...
363
364
365
366
367
368
369
370
371
372
  		if (err == -ENOSPC) {
  			chan->ring_bufs_avail = 0;
  			spin_unlock_irqrestore(&chan->lock, flags);
  			err = wait_event_interruptible(*chan->vc_wq,
  							chan->ring_bufs_avail);
  			if (err  == -ERESTARTSYS)
  				return err;
  
  			P9_DPRINTK(P9_DEBUG_TRANS, "9p:Retry virtio request
  ");
316ad5501   Venkateswararao Jujjuri (JV)   [net/9p] Don't re...
373
  			goto req_retry_pinned;
52f44e0d0   Venkateswararao Jujjuri (JV)   net/9p: Add waitq...
374
375
376
377
378
  		} else {
  			spin_unlock_irqrestore(&chan->lock, flags);
  			P9_DPRINTK(P9_DEBUG_TRANS,
  					"9p debug: "
  					"virtio rpc add_buf returned failure");
4038866da   Venkateswararao Jujjuri (JV)   [net/9p] Add gup/...
379
380
  			if (rpinfo && rpinfo->rp_alloc)
  				kfree(rpinfo);
52f44e0d0   Venkateswararao Jujjuri (JV)   net/9p: Add waitq...
381
382
  			return -EIO;
  		}
e2735b772   Eric Van Hensbergen   9p: block-based v...
383
  	}
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
384

dc3f5e68f   Michael S. Tsirkin   trans_virtio: use...
385
  	virtqueue_kick(chan->vq);
419b39561   Venkateswararao Jujjuri (JV)   [net/9p]Serialize...
386
  	spin_unlock_irqrestore(&chan->lock, flags);
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
387

91b8534fa   Eric Van Hensbergen   9p: make rpc code...
388
389
  	P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked
  ");
e2735b772   Eric Van Hensbergen   9p: block-based v...
390
  	return 0;
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
391
  }
86c843738   Aneesh Kumar K.V   net/9p: Add sysfs...
392
393
394
395
396
397
398
399
400
401
402
403
404
  static ssize_t p9_mount_tag_show(struct device *dev,
  				struct device_attribute *attr, char *buf)
  {
  	struct virtio_chan *chan;
  	struct virtio_device *vdev;
  
  	vdev = dev_to_virtio(dev);
  	chan = vdev->priv;
  
  	return snprintf(buf, chan->tag_len + 1, "%s", chan->tag);
  }
  
  static DEVICE_ATTR(mount_tag, 0444, p9_mount_tag_show, NULL);
ee443996a   Eric Van Hensbergen   9p: Documentation...
405
406
407
408
  /**
   * p9_virtio_probe - probe for existence of 9P virtio channels
   * @vdev: virtio device to probe
   *
37c1209d4   Aneesh Kumar K.V   net/9p: Remove MA...
409
   * This probes for existing virtio channels.
ee443996a   Eric Van Hensbergen   9p: Documentation...
410
411
   *
   */
e2735b772   Eric Van Hensbergen   9p: block-based v...
412
  static int p9_virtio_probe(struct virtio_device *vdev)
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
413
  {
97ee9b025   Aneesh Kumar K.V   net/9p: Use the t...
414
415
  	__u16 tag_len;
  	char *tag;
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
416
417
  	int err;
  	struct virtio_chan *chan;
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
418

37c1209d4   Aneesh Kumar K.V   net/9p: Remove MA...
419
420
421
422
  	chan = kmalloc(sizeof(struct virtio_chan), GFP_KERNEL);
  	if (!chan) {
  		printk(KERN_ERR "9p: Failed to allocate virtio 9P channel
  ");
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
423
424
425
  		err = -ENOMEM;
  		goto fail;
  	}
e2735b772   Eric Van Hensbergen   9p: block-based v...
426
  	chan->vdev = vdev;
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
427

e2735b772   Eric Van Hensbergen   9p: block-based v...
428
  	/* We expect one virtqueue, for requests. */
d2a7ddda9   Michael S. Tsirkin   virtio: find_vqs/...
429
  	chan->vq = virtio_find_single_vq(vdev, req_done, "requests");
e2735b772   Eric Van Hensbergen   9p: block-based v...
430
431
432
  	if (IS_ERR(chan->vq)) {
  		err = PTR_ERR(chan->vq);
  		goto out_free_vq;
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
433
  	}
e2735b772   Eric Van Hensbergen   9p: block-based v...
434
435
  	chan->vq->vdev->priv = chan;
  	spin_lock_init(&chan->lock);
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
436

e2735b772   Eric Van Hensbergen   9p: block-based v...
437
  	sg_init_table(chan->sg, VIRTQUEUE_NUM);
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
438

b530cc794   Eric Van Hensbergen   9p: add virtio tr...
439
  	chan->inuse = false;
97ee9b025   Aneesh Kumar K.V   net/9p: Use the t...
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
  	if (virtio_has_feature(vdev, VIRTIO_9P_MOUNT_TAG)) {
  		vdev->config->get(vdev,
  				offsetof(struct virtio_9p_config, tag_len),
  				&tag_len, sizeof(tag_len));
  	} else {
  		err = -EINVAL;
  		goto out_free_vq;
  	}
  	tag = kmalloc(tag_len, GFP_KERNEL);
  	if (!tag) {
  		err = -ENOMEM;
  		goto out_free_vq;
  	}
  	vdev->config->get(vdev, offsetof(struct virtio_9p_config, tag),
  			tag, tag_len);
  	chan->tag = tag;
  	chan->tag_len = tag_len;
86c843738   Aneesh Kumar K.V   net/9p: Add sysfs...
457
458
  	err = sysfs_create_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
  	if (err) {
52f44e0d0   Venkateswararao Jujjuri (JV)   net/9p: Add waitq...
459
  		goto out_free_tag;
86c843738   Aneesh Kumar K.V   net/9p: Add sysfs...
460
  	}
52f44e0d0   Venkateswararao Jujjuri (JV)   net/9p: Add waitq...
461
462
463
464
465
466
467
  	chan->vc_wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL);
  	if (!chan->vc_wq) {
  		err = -ENOMEM;
  		goto out_free_tag;
  	}
  	init_waitqueue_head(chan->vc_wq);
  	chan->ring_bufs_avail = 1;
68da9ba4e   Venkateswararao Jujjuri (JV)   [net/9p]: Introdu...
468
469
  	/* Ceiling limit to avoid denial of service attacks */
  	chan->p9_max_pages = nr_free_buffer_pages()/4;
52f44e0d0   Venkateswararao Jujjuri (JV)   net/9p: Add waitq...
470

37c1209d4   Aneesh Kumar K.V   net/9p: Remove MA...
471
472
473
  	mutex_lock(&virtio_9p_lock);
  	list_add_tail(&chan->chan_list, &virtio_chan_list);
  	mutex_unlock(&virtio_9p_lock);
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
474
  	return 0;
52f44e0d0   Venkateswararao Jujjuri (JV)   net/9p: Add waitq...
475
476
  out_free_tag:
  	kfree(tag);
e2735b772   Eric Van Hensbergen   9p: block-based v...
477
  out_free_vq:
d2a7ddda9   Michael S. Tsirkin   virtio: find_vqs/...
478
  	vdev->config->del_vqs(vdev);
37c1209d4   Aneesh Kumar K.V   net/9p: Remove MA...
479
  	kfree(chan);
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
480
  fail:
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
481
482
  	return err;
  }
ee443996a   Eric Van Hensbergen   9p: Documentation...
483
484
485
  
  /**
   * p9_virtio_create - allocate a new virtio channel
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
486
   * @client: client instance invoking this transport
ee443996a   Eric Van Hensbergen   9p: Documentation...
487
488
   * @devname: string identifying the channel to connect to (unused)
   * @args: args passed from sys_mount() for per-transport options (unused)
ee443996a   Eric Van Hensbergen   9p: Documentation...
489
490
   *
   * This sets up a transport channel for 9p communication.  Right now
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
491
492
493
   * we only match the first available channel, but eventually we couldlook up
   * alternate channels by matching devname versus a virtio_config entry.
   * We use a simple reference count mechanism to ensure that only a single
ee443996a   Eric Van Hensbergen   9p: Documentation...
494
495
   * mount has a channel open at a time.
   *
ee443996a   Eric Van Hensbergen   9p: Documentation...
496
   */
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
497
498
  static int
  p9_virtio_create(struct p9_client *client, const char *devname, char *args)
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
499
  {
37c1209d4   Aneesh Kumar K.V   net/9p: Remove MA...
500
  	struct virtio_chan *chan;
c1a7c2262   Aneesh Kumar K.V   net/9p: Handle mo...
501
  	int ret = -ENOENT;
37c1209d4   Aneesh Kumar K.V   net/9p: Remove MA...
502
  	int found = 0;
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
503

c1549497e   Josef 'Jeff' Sipek   9p: use struct mu...
504
  	mutex_lock(&virtio_9p_lock);
37c1209d4   Aneesh Kumar K.V   net/9p: Remove MA...
505
  	list_for_each_entry(chan, &virtio_chan_list, chan_list) {
0b20406cd   Sven Eckelmann   net/9p: Mount onl...
506
507
  		if (!strncmp(devname, chan->tag, chan->tag_len) &&
  		    strlen(devname) == chan->tag_len) {
f75580c4a   Aneesh Kumar K.V   net/9p: Add multi...
508
509
  			if (!chan->inuse) {
  				chan->inuse = true;
37c1209d4   Aneesh Kumar K.V   net/9p: Remove MA...
510
  				found = 1;
f75580c4a   Aneesh Kumar K.V   net/9p: Add multi...
511
512
  				break;
  			}
c1a7c2262   Aneesh Kumar K.V   net/9p: Handle mo...
513
  			ret = -EBUSY;
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
514
515
  		}
  	}
c1549497e   Josef 'Jeff' Sipek   9p: use struct mu...
516
  	mutex_unlock(&virtio_9p_lock);
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
517

37c1209d4   Aneesh Kumar K.V   net/9p: Remove MA...
518
  	if (!found) {
e2735b772   Eric Van Hensbergen   9p: block-based v...
519
520
  		printk(KERN_ERR "9p: no channels available
  ");
c1a7c2262   Aneesh Kumar K.V   net/9p: Handle mo...
521
  		return ret;
e2735b772   Eric Van Hensbergen   9p: block-based v...
522
  	}
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
523
  	client->trans = (void *)chan;
562ada612   Eric Van Hensbergen   net/9p: fix virti...
524
  	client->status = Connected;
fea511a64   Eric Van Hensbergen   9p: move request ...
525
  	chan->client = client;
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
526

8b81ef589   Eric Van Hensbergen   9p: consolidate t...
527
  	return 0;
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
528
  }
ee443996a   Eric Van Hensbergen   9p: Documentation...
529
530
531
532
533
  /**
   * p9_virtio_remove - clean up resources associated with a virtio device
   * @vdev: virtio device to remove
   *
   */
f39335453   Eric Van Hensbergen   9p: add remove fu...
534
535
536
537
538
  static void p9_virtio_remove(struct virtio_device *vdev)
  {
  	struct virtio_chan *chan = vdev->priv;
  
  	BUG_ON(chan->inuse);
37c1209d4   Aneesh Kumar K.V   net/9p: Remove MA...
539
540
541
542
543
  	vdev->config->del_vqs(vdev);
  
  	mutex_lock(&virtio_9p_lock);
  	list_del(&chan->chan_list);
  	mutex_unlock(&virtio_9p_lock);
86c843738   Aneesh Kumar K.V   net/9p: Add sysfs...
544
  	sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
97ee9b025   Aneesh Kumar K.V   net/9p: Use the t...
545
  	kfree(chan->tag);
52f44e0d0   Venkateswararao Jujjuri (JV)   net/9p: Add waitq...
546
  	kfree(chan->vc_wq);
37c1209d4   Aneesh Kumar K.V   net/9p: Remove MA...
547
  	kfree(chan);
f39335453   Eric Van Hensbergen   9p: add remove fu...
548

f39335453   Eric Van Hensbergen   9p: add remove fu...
549
  }
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
550
551
552
553
  static struct virtio_device_id id_table[] = {
  	{ VIRTIO_ID_9P, VIRTIO_DEV_ANY_ID },
  	{ 0 },
  };
97ee9b025   Aneesh Kumar K.V   net/9p: Use the t...
554
555
556
  static unsigned int features[] = {
  	VIRTIO_9P_MOUNT_TAG,
  };
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
557
558
  /* The standard "struct lguest_driver": */
  static struct virtio_driver p9_virtio_drv = {
97ee9b025   Aneesh Kumar K.V   net/9p: Use the t...
559
560
561
562
563
564
565
  	.feature_table  = features,
  	.feature_table_size = ARRAY_SIZE(features),
  	.driver.name    = KBUILD_MODNAME,
  	.driver.owner	= THIS_MODULE,
  	.id_table	= id_table,
  	.probe		= p9_virtio_probe,
  	.remove		= p9_virtio_remove,
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
566
567
568
569
570
  };
  
  static struct p9_trans_module p9_virtio_trans = {
  	.name = "virtio",
  	.create = p9_virtio_create,
8b81ef589   Eric Van Hensbergen   9p: consolidate t...
571
  	.close = p9_virtio_close,
91b8534fa   Eric Van Hensbergen   9p: make rpc code...
572
573
  	.request = p9_virtio_request,
  	.cancel = p9_virtio_cancel,
e2735b772   Eric Van Hensbergen   9p: block-based v...
574
  	.maxsize = PAGE_SIZE*16,
6f69c395c   Venkateswararao Jujjuri (JV)   [net/9p] Add pref...
575
  	.pref = P9_TRANS_PREF_PAYLOAD_SEP,
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
576
  	.def = 0,
72029fe85   Tejun Heo   9p: implement pro...
577
  	.owner = THIS_MODULE,
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
578
579
580
581
582
  };
  
  /* The standard init function */
  static int __init p9_virtio_init(void)
  {
37c1209d4   Aneesh Kumar K.V   net/9p: Remove MA...
583
  	INIT_LIST_HEAD(&virtio_chan_list);
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
584
585
586
587
  
  	v9fs_register_trans(&p9_virtio_trans);
  	return register_virtio_driver(&p9_virtio_drv);
  }
f39335453   Eric Van Hensbergen   9p: add remove fu...
588
589
590
  static void __exit p9_virtio_cleanup(void)
  {
  	unregister_virtio_driver(&p9_virtio_drv);
72029fe85   Tejun Heo   9p: implement pro...
591
  	v9fs_unregister_trans(&p9_virtio_trans);
f39335453   Eric Van Hensbergen   9p: add remove fu...
592
  }
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
593
  module_init(p9_virtio_init);
f39335453   Eric Van Hensbergen   9p: add remove fu...
594
  module_exit(p9_virtio_cleanup);
b530cc794   Eric Van Hensbergen   9p: add virtio tr...
595
596
597
598
599
  
  MODULE_DEVICE_TABLE(virtio, id_table);
  MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
  MODULE_DESCRIPTION("Virtio 9p Transport");
  MODULE_LICENSE("GPL");