debuggers.hg

view linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap_datapath.c @ 3370:72b23176fb04

bitkeeper revision 1.1159.1.506 (41d00f89OifvQoN_EcnO5XuQN0RRjA)

Update to Linux 2.6.10.
author cl349@arcadians.cl.cam.ac.uk
date Mon Dec 27 13:35:05 2004 +0000 (2004-12-27)
parents
children 70b803ca7d24 671aaec9d333 9e77c2678efa
line source
1 /******************************************************************************
2 * blktap_datapath.c
3 *
4 * XenLinux virtual block-device tap.
5 * Block request routing data path.
6 *
7 * Copyright (c) 2004, Andrew Warfield
8 *
9 */
11 #include "blktap.h"
13 /*-----[ The data paths ]-------------------------------------------------*/
15 /* Connections to the frontend domains.*/
16 blkif_t ptfe_blkif;
18 /* Connection to a single backend domain. */
19 blkif_ring_t *blk_ptbe_ring; /* Ring from the PT to the BE dom */
20 BLKIF_RING_IDX ptbe_resp_cons; /* Response consumer for comms ring. */
21 BLKIF_RING_IDX ptbe_req_prod; /* Private request producer. */
23 /* Rings up to user space. */
24 blkif_req_ring_t fe_ring;// = BLKIF_REQ_RING_INIT;
25 blkif_rsp_ring_t be_ring;// = BLKIF_RSP_RING_INIT;
27 /*-----[ Ring helpers ]---------------------------------------------------*/
29 inline int BLKTAP_RING_FULL(blkif_generic_ring_t *ring)
30 {
31 if (ring->type == BLKIF_REQ_RING_TYPE) {
32 blkif_req_ring_t *r = (blkif_req_ring_t *)ring;
33 return ( ( r->req_prod - r->rsp_cons ) == BLKIF_RING_SIZE );
34 }
36 /* for now assume that there is always room in the response path. */
37 return 0;
38 }
40 /*-----[ Tracking active requests ]---------------------------------------*/
42 /* this must be the same as MAX_PENDING_REQS in blkback.c */
43 #define MAX_ACTIVE_REQS 64
45 active_req_t active_reqs[MAX_ACTIVE_REQS];
46 unsigned char active_req_ring[MAX_ACTIVE_REQS];
47 spinlock_t active_req_lock = SPIN_LOCK_UNLOCKED;
48 typedef unsigned int ACTIVE_RING_IDX;
49 ACTIVE_RING_IDX active_prod, active_cons;
50 #define MASK_ACTIVE_IDX(_i) ((_i)&(MAX_ACTIVE_REQS-1))
51 #define ACTIVE_IDX(_ar) (_ar - active_reqs)
53 inline active_req_t *get_active_req(void)
54 {
55 ASSERT(active_cons != active_prod);
56 return &active_reqs[MASK_ACTIVE_IDX(active_cons++)];
57 }
59 inline void free_active_req(active_req_t *ar)
60 {
61 unsigned long flags;
63 spin_lock_irqsave(&active_req_lock, flags);
64 active_req_ring[MASK_ACTIVE_IDX(active_prod++)] = ACTIVE_IDX(ar);
65 spin_unlock_irqrestore(&active_req_lock, flags);
66 }
68 inline void active_reqs_init(void)
69 {
70 ACTIVE_RING_IDX i;
72 active_cons = 0;
73 active_prod = MAX_ACTIVE_REQS;
74 memset(active_reqs, 0, sizeof(active_reqs));
75 for ( i = 0; i < MAX_ACTIVE_REQS; i++ )
76 active_req_ring[i] = i;
77 }
79 /*-----[ Data to/from Frontend (client) VMs ]-----------------------------*/
81 irqreturn_t blkif_ptfe_int(int irq, void *dev_id, struct pt_regs *regs)
82 {
83 /* we have pending messages from the real frontend. */
85 blkif_request_t *req_s, *req_d;
86 BLKIF_RING_IDX fe_rp;
87 unsigned long flags;
88 int notify;
89 unsigned long i;
90 active_req_t *ar;
92 DPRINTK("PT got FE interrupt.\n");
94 /* lock both rings */
95 spin_lock_irqsave(&blkif_io_lock, flags);
97 /* While there are REQUESTS on FERing: */
98 fe_rp = ptfe_blkif.blk_ring_base->req_prod;
99 rmb();
100 notify = (ptfe_blkif.blk_req_cons != fe_rp);
102 for (i = ptfe_blkif.blk_req_cons; i != fe_rp; i++) {
104 /* Get the next request */
105 req_s = &ptfe_blkif.blk_ring_base->ring[MASK_BLKIF_IDX(i)].req;
107 /* This is a new request:
108 * Assign an active request record, and remap the id.
109 */
110 ar = get_active_req();
111 ar->id = req_s->id;
112 req_s->id = ACTIVE_IDX(ar);
113 DPRINTK("%3lu < %3lu\n", req_s->id, ar->id);
115 /* FE -> BE interposition point is here. */
117 /* ------------------------------------------------------------- */
118 /* BLKIF_OP_PROBE_HACK: */
119 /* Until we have grant tables, we need to allow the backent to */
120 /* map pages that are either from this domain, or more commonly */
121 /* from the real front end. We achieve this in a terrible way, */
122 /* by passing the front end's domid allong with PROBE messages */
123 /* Once grant tables appear, this should all go away. */
125 if (req_s->operation == BLKIF_OP_PROBE) {
126 DPRINTK("Adding FE domid to PROBE request.\n");
127 (domid_t)(req_s->frame_and_sects[1]) = ptfe_blkif.domid;
128 }
130 /* ------------------------------------------------------------- */
132 /* If we are in MODE_INTERCEPT_FE or MODE_COPY_FE: */
133 if ( (blktap_mode & BLKTAP_MODE_INTERCEPT_FE) ||
134 (blktap_mode & BLKTAP_MODE_COPY_FE) ) {
136 /* Copy the response message to UFERing */
137 /* In MODE_INTERCEPT_FE, map attached pages into the app vma */
138 /* In MODE_COPY_FE_PAGES, copy attached pages into the app vma */
140 /* XXX: mapping/copying of attached pages is still not done! */
142 DPRINTK("req->UFERing\n");
143 blktap_write_fe_ring(req_s);
146 }
148 /* If we are not in MODE_INTERCEPT_FE or MODE_INTERCEPT_BE: */
149 if ( !((blktap_mode & BLKTAP_MODE_INTERCEPT_FE) ||
150 (blktap_mode & BLKTAP_MODE_INTERCEPT_BE)) ) {
152 /* be included to prevent noise from the fe when its off */
153 /* copy the request message to the BERing */
155 DPRINTK("blktap: FERing[%u] -> BERing[%u]\n",
156 (unsigned)MASK_BLKIF_IDX(i),
157 (unsigned)MASK_BLKIF_IDX(ptbe_req_prod));
159 req_d = &blk_ptbe_ring->ring[MASK_BLKIF_IDX(ptbe_req_prod)].req;
161 memcpy(req_d, req_s, sizeof(blkif_request_t));
163 ptbe_req_prod++;
164 }
165 }
167 ptfe_blkif.blk_req_cons = i;
169 /* If we have forwarded any responses, notify the appropriate ends. */
170 if (notify) {
172 /* we have sent stuff to the be, notify it. */
173 if ( !((blktap_mode & BLKTAP_MODE_INTERCEPT_FE) ||
174 (blktap_mode & BLKTAP_MODE_INTERCEPT_BE)) ) {
175 wmb();
176 blk_ptbe_ring->req_prod = ptbe_req_prod;
178 notify_via_evtchn(blkif_ptbe_evtchn);
179 DPRINTK(" -- and notified.\n");
180 }
182 /* we sent stuff to the app, notify it. */
183 if ( (blktap_mode & BLKTAP_MODE_INTERCEPT_FE) ||
184 (blktap_mode & BLKTAP_MODE_COPY_FE) ) {
186 blktap_kick_user();
187 }
188 }
190 /* unlock rings */
191 spin_unlock_irqrestore(&blkif_io_lock, flags);
193 return IRQ_HANDLED;
194 }
196 inline int write_req_to_be_ring(blkif_request_t *req)
197 {
198 blkif_request_t *req_d;
200 req_d = &blk_ptbe_ring->ring[MASK_BLKIF_IDX(ptbe_req_prod)].req;
201 memcpy(req_d, req, sizeof(blkif_request_t));
202 ptbe_req_prod++;
204 return 0;
205 }
207 inline void kick_be_domain(void) {
208 wmb();
209 blk_ptbe_ring->req_prod = ptbe_req_prod;
210 notify_via_evtchn(blkif_ptbe_evtchn);
211 }
213 /*-----[ Data to/from Backend (server) VM ]------------------------------*/
216 irqreturn_t blkif_ptbe_int(int irq, void *dev_id,
217 struct pt_regs *ptregs)
218 {
219 blkif_response_t *resp_s, *resp_d;
220 BLKIF_RING_IDX be_rp;
221 unsigned long flags;
222 int notify;
223 unsigned long i;
224 active_req_t *ar;
226 DPRINTK("PT got BE interrupt.\n");
228 /* lock both rings */
229 spin_lock_irqsave(&blkif_io_lock, flags);
231 /* While there are RESPONSES on BERing: */
232 be_rp = blk_ptbe_ring->resp_prod;
233 rmb();
234 notify = (ptbe_resp_cons != be_rp);
236 for ( i = ptbe_resp_cons; i != be_rp; i++ )
237 {
238 /* BE -> FE interposition point is here. */
240 /* Get the next response */
241 resp_s = &blk_ptbe_ring->ring[MASK_BLKIF_IDX(i)].resp;
244 /* If we are in MODE_INTERCEPT_BE or MODE_COPY_BE: */
245 if ( (blktap_mode & BLKTAP_MODE_INTERCEPT_BE) ||
246 (blktap_mode & BLKTAP_MODE_COPY_BE) ) {
248 /* Copy the response message to UBERing */
249 /* In MODE_INTERCEPT_BE, map attached pages into the app vma */
250 /* In MODE_COPY_BE_PAGES, copy attached pages into the app vma */
252 /* XXX: copy/map the attached page! */
254 DPRINTK("rsp->UBERing\n");
255 blktap_write_be_ring(resp_s);
257 }
259 /* If we are NOT in MODE_INTERCEPT_BE or MODE_INTERCEPT_FE: */
260 if ( !((blktap_mode & BLKTAP_MODE_INTERCEPT_BE) ||
261 (blktap_mode & BLKTAP_MODE_INTERCEPT_FE)) ) {
263 /* (fe included to prevent random interference from the BE) */
264 /* Copy the response message to FERing */
266 DPRINTK("blktap: BERing[%u] -> FERing[%u]\n",
267 (unsigned) MASK_BLKIF_IDX(i),
268 (unsigned) MASK_BLKIF_IDX(ptfe_blkif.blk_resp_prod));
270 /* remap id, and free the active req. blkif lookup goes here too.*/
271 ar = &active_reqs[resp_s->id];
272 DPRINTK("%3lu > %3lu\n", resp_s->id, ar->id);
273 resp_s->id = ar->id;
274 free_active_req(ar);
276 resp_d = &ptfe_blkif.blk_ring_base->ring[
277 MASK_BLKIF_IDX(ptfe_blkif.blk_resp_prod)].resp;
279 memcpy(resp_d, resp_s, sizeof(blkif_response_t));
281 ptfe_blkif.blk_resp_prod++;
283 }
284 }
286 ptbe_resp_cons = i;
288 /* If we have forwarded any responses, notify the apropriate domains. */
289 if (notify) {
291 /* we have sent stuff to the fe. notify it. */
292 if ( !((blktap_mode & BLKTAP_MODE_INTERCEPT_BE) ||
293 (blktap_mode & BLKTAP_MODE_INTERCEPT_FE)) ) {
294 wmb();
295 ptfe_blkif.blk_ring_base->resp_prod = ptfe_blkif.blk_resp_prod;
297 notify_via_evtchn(ptfe_blkif.evtchn);
298 DPRINTK(" -- and notified.\n");
299 }
301 /* we sent stuff to the app, notify it. */
302 if ( (blktap_mode & BLKTAP_MODE_INTERCEPT_BE) ||
303 (blktap_mode & BLKTAP_MODE_COPY_BE) ) {
305 blktap_kick_user();
306 }
307 }
309 spin_unlock_irqrestore(&blkif_io_lock, flags);
310 return IRQ_HANDLED;
311 }
313 inline int write_resp_to_fe_ring(blkif_response_t *rsp)
314 {
315 blkif_response_t *resp_d;
316 active_req_t *ar;
318 /* remap id, and free the active req. blkif lookup goes here too.*/
319 ar = &active_reqs[rsp->id];
320 DPRINTK("%3lu > %3lu\n", rsp->id, ar->id);
321 rsp->id = ar->id;
322 free_active_req(ar);
324 resp_d = &ptfe_blkif.blk_ring_base->ring[
325 MASK_BLKIF_IDX(ptfe_blkif.blk_resp_prod)].resp;
327 memcpy(resp_d, rsp, sizeof(blkif_response_t));
328 ptfe_blkif.blk_resp_prod++;
330 return 0;
331 }
333 inline void kick_fe_domain(void) {
334 wmb();
335 ptfe_blkif.blk_ring_base->resp_prod = ptfe_blkif.blk_resp_prod;
336 notify_via_evtchn(ptfe_blkif.evtchn);
338 }
340 static inline void flush_requests(void)
341 {
342 wmb(); /* Ensure that the frontend can see the requests. */
343 blk_ptbe_ring->req_prod = ptbe_req_prod;
344 notify_via_evtchn(blkif_ptbe_evtchn);
345 }
347 /*-----[ Data to/from user space ]----------------------------------------*/
350 int blktap_write_fe_ring(blkif_request_t *req)
351 {
352 blkif_request_t *target;
353 int error, i;
355 /*
356 * This is called to pass a request from the real frontend domain's
357 * blkif ring to the character device.
358 */
360 if ( ! blktap_ring_ok ) {
361 DPRINTK("blktap: fe_ring not ready for a request!\n");
362 return 0;
363 }
365 if ( BLKTAP_RING_FULL(RING(&fe_ring)) ) {
366 DPRINTK("blktap: fe_ring is full, can't add.\n");
367 return 0;
368 }
370 target = &fe_ring.ring->ring[MASK_BLKIF_IDX(fe_ring.req_prod)].req;
371 memcpy(target, req, sizeof(*req));
373 /* maybe move this stuff out into a seperate func ------------------- */
375 /*
376 * For now, map attached page into a fixed position into the vma.
377 * XXX: make this map to a free page.
378 */
380 /* Attempt to map the foreign pages directly in to the application */
381 for (i=0; i<target->nr_segments; i++) {
383 /* get an unused virtual address from the char device */
384 /* store the old page address */
385 /* replace the address with the virtual address */
387 /* blktap_vma->vm_start+((2+i)*PAGE_SIZE) */
389 error = direct_remap_area_pages(blktap_vma->vm_mm,
390 MMAP_VADDR(req->id, i),
391 target->frame_and_sects[0] & PAGE_MASK,
392 PAGE_SIZE,
393 blktap_vma->vm_page_prot,
394 ptfe_blkif.domid);
395 if ( error != 0 ) {
396 printk(KERN_INFO "remapping attached page failed! (%d)\n", error);
397 return 0;
398 }
399 }
400 /* fix the address of the attached page in the message. */
401 /* TODO: preserve the segment number stuff here... */
402 /* target->frame_and_sects[0] = blktap_vma->vm_start + PAGE_SIZE;*/
403 /* ------------------------------------------------------------------ */
406 fe_ring.req_prod++;
408 return 0;
409 }
411 int blktap_write_be_ring(blkif_response_t *rsp)
412 {
413 blkif_response_t *target;
415 /*
416 * This is called to pass a request from the real backend domain's
417 * blkif ring to the character device.
418 */
420 if ( ! blktap_ring_ok ) {
421 DPRINTK("blktap: be_ring not ready for a request!\n");
422 return 0;
423 }
425 if ( BLKTAP_RING_FULL(RING(&be_ring)) ) {
426 DPRINTK("blktap: be_ring is full, can't add.\n");
427 return 0;
428 }
430 target = &be_ring.ring->ring[MASK_BLKIF_IDX(be_ring.rsp_prod)].resp;
431 memcpy(target, rsp, sizeof(*rsp));
434 /* XXX: map attached pages and fix-up addresses in the copied address. */
436 be_ring.rsp_prod++;
438 return 0;
439 }
441 int blktap_read_fe_ring(void)
442 {
443 /* This is called to read responses from the UFE ring. */
445 BLKIF_RING_IDX fe_rp;
446 unsigned long i;
447 int notify;
449 DPRINTK("blktap_read_fe_ring()\n");
451 fe_rp = fe_ring.ring->resp_prod;
452 rmb();
453 notify = (fe_rp != fe_ring.rsp_cons);
455 /* if we are forwarding from UFERring to FERing */
456 if (blktap_mode & BLKTAP_MODE_INTERCEPT_FE) {
458 /* for each outstanding message on the UFEring */
459 for ( i = fe_ring.rsp_cons; i != fe_rp; i++ ) {
461 /* XXX: remap pages on that message as necessary */
462 /* copy the message to the UBEring */
464 DPRINTK("resp->fe_ring\n");
465 write_resp_to_fe_ring(&fe_ring.ring->ring[MASK_BLKIF_IDX(i)].resp);
466 }
468 fe_ring.rsp_cons = fe_rp;
470 /* notify the fe if necessary */
471 if ( notify ) {
472 DPRINTK("kick_fe_domain()\n");
473 kick_fe_domain();
474 }
475 }
477 return 0;
478 }
480 int blktap_read_be_ring(void)
481 {
482 /* This is called to read responses from the UBE ring. */
484 BLKIF_RING_IDX be_rp;
485 unsigned long i;
486 int notify;
488 DPRINTK("blktap_read_be_ring()\n");
490 be_rp = be_ring.ring->req_prod;
491 rmb();
492 notify = (be_rp != be_ring.req_cons);
494 /* if we are forwarding from UFERring to FERing */
495 if (blktap_mode & BLKTAP_MODE_INTERCEPT_BE) {
497 /* for each outstanding message on the UFEring */
498 for ( i = be_ring.req_cons; i != be_rp; i++ ) {
500 /* XXX: remap pages on that message as necessary */
501 /* copy the message to the UBEring */
503 DPRINTK("req->be_ring\n");
504 write_req_to_be_ring(&be_ring.ring->ring[MASK_BLKIF_IDX(i)].req);
505 }
507 be_ring.req_cons = be_rp;
509 /* notify the fe if necessary */
510 if ( notify ) {
511 DPRINTK("kick_be_domain()\n");
512 kick_be_domain();
513 }
514 }
516 return 0;
517 }