ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/blktap/blktap_controlmsg.c @ 6294:1a0723cd37f1

Fix many uses of machine addresses in XenLinux. Primarily
this fixes users of virt_to_machine/machine_to_virt to
use virt_to_mfn/mfn_to_virt where that is more appropriate.

This should be a big step to improved PAE stability.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Fri Aug 19 16:06:43 2005 +0000 (2005-08-19)
parents eaf498f1ffde
children f51fe43c5d1c 5f4724c13040 81576d3d1ca8 3a8f27c6d56c
line source
1 /******************************************************************************
2 * blktap_controlmsg.c
3 *
4 * XenLinux virtual block-device tap.
5 * Control interfaces to the frontend and backend drivers.
6 *
7 * Copyright (c) 2004, Andrew Warfield
8 *
9 */
11 #include "blktap.h"
12 #include <asm-xen/evtchn.h>
14 static char *blkif_state_name[] = {
15 [BLKIF_STATE_CLOSED] = "closed",
16 [BLKIF_STATE_DISCONNECTED] = "disconnected",
17 [BLKIF_STATE_CONNECTED] = "connected",
18 };
20 static char *blkif_status_name[] = {
21 [BLKIF_INTERFACE_STATUS_CLOSED] = "closed",
22 [BLKIF_INTERFACE_STATUS_DISCONNECTED] = "disconnected",
23 [BLKIF_INTERFACE_STATUS_CONNECTED] = "connected",
24 [BLKIF_INTERFACE_STATUS_CHANGED] = "changed",
25 };
27 unsigned int blktap_be_state = BLKIF_STATE_CLOSED;
28 unsigned int blktap_be_evtchn;
30 /*-----[ Control Messages to/from Frontend VMs ]--------------------------*/
32 #define BLKIF_HASHSZ 1024
33 #define BLKIF_HASH(_d,_h) (((int)(_d)^(int)(_h))&(BLKIF_HASHSZ-1))
35 static kmem_cache_t *blkif_cachep;
36 static blkif_t *blkif_hash[BLKIF_HASHSZ];
38 blkif_t *blkif_find_by_handle(domid_t domid, unsigned int handle)
39 {
40 blkif_t *blkif = blkif_hash[BLKIF_HASH(domid, handle)];
41 while ( (blkif != NULL) &&
42 ((blkif->domid != domid) || (blkif->handle != handle)) )
43 blkif = blkif->hash_next;
44 return blkif;
45 }
47 static void __blkif_disconnect_complete(void *arg)
48 {
49 blkif_t *blkif = (blkif_t *)arg;
50 ctrl_msg_t cmsg;
51 blkif_be_disconnect_t disc;
52 #ifdef CONFIG_XEN_BLKDEV_GRANT
53 struct gnttab_unmap_grant_ref op;
54 #endif
56 /*
57 * These can't be done in blkif_disconnect() because at that point there
58 * may be outstanding requests at the disc whose asynchronous responses
59 * must still be notified to the remote driver.
60 */
61 #ifdef CONFIG_XEN_BLKDEV_GRANT
62 op.host_addr = blkif->shmem_vaddr;
63 op.handle = blkif->shmem_handle;
64 op.dev_bus_addr = 0;
65 BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1));
66 #endif
67 vfree(blkif->blk_ring.sring);
69 /* Construct the deferred response message. */
70 cmsg.type = CMSG_BLKIF_BE;
71 cmsg.subtype = CMSG_BLKIF_BE_DISCONNECT;
72 cmsg.id = blkif->disconnect_rspid;
73 cmsg.length = sizeof(blkif_be_disconnect_t);
74 disc.domid = blkif->domid;
75 disc.blkif_handle = blkif->handle;
76 disc.status = BLKIF_BE_STATUS_OKAY;
77 memcpy(cmsg.msg, &disc, sizeof(disc));
79 /*
80 * Make sure message is constructed /before/ status change, because
81 * after the status change the 'blkif' structure could be deallocated at
82 * any time. Also make sure we send the response /after/ status change,
83 * as otherwise a subsequent CONNECT request could spuriously fail if
84 * another CPU doesn't see the status change yet.
85 */
86 mb();
87 if ( blkif->status != DISCONNECTING )
88 BUG();
89 blkif->status = DISCONNECTED;
90 mb();
92 /* Send the successful response. */
93 ctrl_if_send_response(&cmsg);
94 }
96 void blkif_disconnect_complete(blkif_t *blkif)
97 {
98 INIT_WORK(&blkif->work, __blkif_disconnect_complete, (void *)blkif);
99 schedule_work(&blkif->work);
100 }
102 void blkif_ptfe_create(blkif_be_create_t *create)
103 {
104 blkif_t *blkif, **pblkif;
105 domid_t domid = create->domid;
106 unsigned int handle = create->blkif_handle;
109 /* May want to store info on the connecting domain here. */
111 DPRINTK("PT got BE_CREATE\n");
113 if ( (blkif = kmem_cache_alloc(blkif_cachep, GFP_KERNEL)) == NULL )
114 {
115 WPRINTK("Could not create blkif: out of memory\n");
116 create->status = BLKIF_BE_STATUS_OUT_OF_MEMORY;
117 return;
118 }
120 /* blkif struct init code from blkback.c */
121 memset(blkif, 0, sizeof(*blkif));
122 blkif->domid = domid;
123 blkif->handle = handle;
124 blkif->status = DISCONNECTED;
125 spin_lock_init(&blkif->blk_ring_lock);
126 atomic_set(&blkif->refcnt, 0);
128 pblkif = &blkif_hash[BLKIF_HASH(domid, handle)];
129 while ( *pblkif != NULL )
130 {
131 if ( ((*pblkif)->domid == domid) && ((*pblkif)->handle == handle) )
132 {
133 WPRINTK("Could not create blkif: already exists\n");
134 create->status = BLKIF_BE_STATUS_INTERFACE_EXISTS;
135 kmem_cache_free(blkif_cachep, blkif);
136 return;
137 }
138 pblkif = &(*pblkif)->hash_next;
139 }
141 blkif->hash_next = *pblkif;
142 *pblkif = blkif;
144 create->status = BLKIF_BE_STATUS_OKAY;
145 }
148 void blkif_ptfe_destroy(blkif_be_destroy_t *destroy)
149 {
150 /* Clear anything that we initialized above. */
152 domid_t domid = destroy->domid;
153 unsigned int handle = destroy->blkif_handle;
154 blkif_t **pblkif, *blkif;
156 DPRINTK("PT got BE_DESTROY\n");
158 pblkif = &blkif_hash[BLKIF_HASH(domid, handle)];
159 while ( (blkif = *pblkif) != NULL )
160 {
161 if ( (blkif->domid == domid) && (blkif->handle == handle) )
162 {
163 if ( blkif->status != DISCONNECTED )
164 goto still_connected;
165 goto destroy;
166 }
167 pblkif = &blkif->hash_next;
168 }
170 destroy->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND;
171 return;
173 still_connected:
174 destroy->status = BLKIF_BE_STATUS_INTERFACE_CONNECTED;
175 return;
177 destroy:
178 *pblkif = blkif->hash_next;
179 kmem_cache_free(blkif_cachep, blkif);
180 destroy->status = BLKIF_BE_STATUS_OKAY;
181 }
183 void blkif_ptfe_connect(blkif_be_connect_t *connect)
184 {
185 domid_t domid = connect->domid;
186 unsigned int handle = connect->blkif_handle;
187 unsigned int evtchn = connect->evtchn;
188 unsigned long shmem_frame = connect->shmem_frame;
189 struct vm_struct *vma;
190 #ifdef CONFIG_XEN_BLKDEV_GRANT
191 int ref = connect->shmem_ref;
192 #else
193 pgprot_t prot;
194 int error;
195 #endif
196 blkif_t *blkif;
197 blkif_sring_t *sring;
199 DPRINTK("PT got BE_CONNECT\n");
201 blkif = blkif_find_by_handle(domid, handle);
202 if ( unlikely(blkif == NULL) )
203 {
204 WPRINTK("blkif_connect attempted for non-existent blkif (%u,%u)\n",
205 connect->domid, connect->blkif_handle);
206 connect->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND;
207 return;
208 }
210 if ( (vma = get_vm_area(PAGE_SIZE, VM_IOREMAP)) == NULL )
211 {
212 connect->status = BLKIF_BE_STATUS_OUT_OF_MEMORY;
213 return;
214 }
216 #ifndef CONFIG_XEN_BLKDEV_GRANT
217 prot = __pgprot(_KERNPG_TABLE);
218 error = direct_remap_area_pages(&init_mm, VMALLOC_VMADDR(vma->addr),
219 shmem_frame<<PAGE_SHIFT, PAGE_SIZE,
220 prot, domid);
221 if ( error != 0 )
222 {
223 if ( error == -ENOMEM )
224 connect->status = BLKIF_BE_STATUS_OUT_OF_MEMORY;
225 else if ( error == -EFAULT )
226 connect->status = BLKIF_BE_STATUS_MAPPING_ERROR;
227 else
228 connect->status = BLKIF_BE_STATUS_ERROR;
229 vfree(vma->addr);
230 return;
231 }
232 #else
233 { /* Map: Use the Grant table reference */
234 struct gnttab_map_grant_ref op;
235 op.host_addr = VMALLOC_VMADDR(vma->addr);
236 op.flags = GNTMAP_host_map;
237 op.ref = ref;
238 op.dom = domid;
240 BUG_ON( HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1) );
242 handle = op.handle;
244 if (op.handle < 0) {
245 DPRINTK(" Grant table operation failure !\n");
246 connect->status = BLKIF_BE_STATUS_MAPPING_ERROR;
247 vfree(vma->addr);
248 return;
249 }
251 blkif->shmem_ref = ref;
252 blkif->shmem_handle = handle;
253 blkif->shmem_vaddr = VMALLOC_VMADDR(vma->addr);
254 }
255 #endif
257 if ( blkif->status != DISCONNECTED )
258 {
259 connect->status = BLKIF_BE_STATUS_INTERFACE_CONNECTED;
260 vfree(vma->addr);
261 return;
262 }
264 sring = (blkif_sring_t *)vma->addr;
265 SHARED_RING_INIT(sring);
266 BACK_RING_INIT(&blkif->blk_ring, sring, PAGE_SIZE);
268 blkif->evtchn = evtchn;
269 blkif->shmem_frame = shmem_frame;
270 blkif->status = CONNECTED;
271 blkif_get(blkif);
273 bind_evtchn_to_irqhandler(
274 evtchn, blkif_ptfe_int, 0, "blkif-pt-backend", blkif);
276 connect->status = BLKIF_BE_STATUS_OKAY;
277 }
279 int blkif_ptfe_disconnect(blkif_be_disconnect_t *disconnect, u8 rsp_id)
280 {
281 domid_t domid = disconnect->domid;
282 unsigned int handle = disconnect->blkif_handle;
283 blkif_t *blkif;
285 DPRINTK("PT got BE_DISCONNECT\n");
287 blkif = blkif_find_by_handle(domid, handle);
288 if ( unlikely(blkif == NULL) )
289 {
290 WPRINTK("blkif_disconnect attempted for non-existent blkif"
291 " (%u,%u)\n", disconnect->domid, disconnect->blkif_handle);
292 disconnect->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND;
293 return 1; /* Caller will send response error message. */
294 }
296 if ( blkif->status == CONNECTED )
297 {
298 blkif->status = DISCONNECTING;
299 blkif->disconnect_rspid = rsp_id;
300 wmb(); /* Let other CPUs see the status change. */
301 unbind_evtchn_from_irqhandler(blkif->evtchn, blkif);
302 blkif_deschedule(blkif);
303 blkif_put(blkif);
304 return 0; /* Caller should not send response message. */
305 }
307 disconnect->status = BLKIF_BE_STATUS_OKAY;
308 return 1;
309 }
311 /*-----[ Control Messages to/from Backend VM ]----------------------------*/
313 /* Tell the controller to bring up the interface. */
314 static void blkif_ptbe_send_interface_connect(void)
315 {
316 ctrl_msg_t cmsg = {
317 .type = CMSG_BLKIF_FE,
318 .subtype = CMSG_BLKIF_FE_INTERFACE_CONNECT,
319 .length = sizeof(blkif_fe_interface_connect_t),
320 };
321 blkif_fe_interface_connect_t *msg = (void*)cmsg.msg;
322 msg->handle = 0;
323 msg->shmem_frame = virt_to_mfn(blktap_be_ring.sring);
325 ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
326 }
328 static void blkif_ptbe_close(void)
329 {
330 }
332 /* Move from CLOSED to DISCONNECTED state. */
333 static void blkif_ptbe_disconnect(void)
334 {
335 blkif_sring_t *sring;
337 sring = (blkif_sring_t *)__get_free_page(GFP_KERNEL);
338 SHARED_RING_INIT(sring);
339 FRONT_RING_INIT(&blktap_be_ring, sring, PAGE_SIZE);
340 blktap_be_state = BLKIF_STATE_DISCONNECTED;
341 DPRINTK("Blkif-Passthrough-BE is now DISCONNECTED.\n");
342 blkif_ptbe_send_interface_connect();
343 }
345 static void blkif_ptbe_connect(blkif_fe_interface_status_t *status)
346 {
347 int err = 0;
349 blktap_be_evtchn = status->evtchn;
351 err = bind_evtchn_to_irqhandler(
352 blktap_be_evtchn, blkif_ptbe_int, SA_SAMPLE_RANDOM, "blkif", NULL);
353 if ( err ) {
354 WPRINTK("blkfront bind_evtchn_to_irqhandler failed (%d)\n", err);
355 return;
356 } else {
357 /* transtion to connected in case we need to do a
358 a partion probe on a whole disk */
359 blktap_be_state = BLKIF_STATE_CONNECTED;
360 }
361 }
363 static void unexpected(blkif_fe_interface_status_t *status)
364 {
365 WPRINTK(" TAP: Unexpected blkif status %s in state %s\n",
366 blkif_status_name[status->status],
367 blkif_state_name[blktap_be_state]);
368 }
370 static void blkif_ptbe_status(
371 blkif_fe_interface_status_t *status)
372 {
373 if ( status->handle != 0 )
374 {
375 DPRINTK("Status change on unsupported blkif %d\n",
376 status->handle);
377 return;
378 }
380 DPRINTK("ptbe_status: got %s\n", blkif_status_name[status->status]);
382 switch ( status->status )
383 {
384 case BLKIF_INTERFACE_STATUS_CLOSED:
385 switch ( blktap_be_state )
386 {
387 case BLKIF_STATE_CLOSED:
388 unexpected(status);
389 break;
390 case BLKIF_STATE_DISCONNECTED:
391 case BLKIF_STATE_CONNECTED:
392 unexpected(status);
393 blkif_ptbe_close();
394 break;
395 }
396 break;
398 case BLKIF_INTERFACE_STATUS_DISCONNECTED:
399 switch ( blktap_be_state )
400 {
401 case BLKIF_STATE_CLOSED:
402 blkif_ptbe_disconnect();
403 break;
404 case BLKIF_STATE_DISCONNECTED:
405 case BLKIF_STATE_CONNECTED:
406 printk(KERN_ALERT "*** add recovery code to the tap driver. ***\n");
407 unexpected(status);
408 break;
409 }
410 break;
412 case BLKIF_INTERFACE_STATUS_CONNECTED:
413 switch ( blktap_be_state )
414 {
415 case BLKIF_STATE_CLOSED:
416 unexpected(status);
417 blkif_ptbe_disconnect();
418 blkif_ptbe_connect(status);
419 break;
420 case BLKIF_STATE_DISCONNECTED:
421 blkif_ptbe_connect(status);
422 break;
423 case BLKIF_STATE_CONNECTED:
424 unexpected(status);
425 blkif_ptbe_connect(status);
426 break;
427 }
428 break;
430 case BLKIF_INTERFACE_STATUS_CHANGED:
431 switch ( blktap_be_state )
432 {
433 case BLKIF_STATE_CLOSED:
434 case BLKIF_STATE_DISCONNECTED:
435 unexpected(status);
436 break;
437 case BLKIF_STATE_CONNECTED:
438 /* vbd_update(); */
439 /* tap doesn't really get state changes... */
440 unexpected(status);
441 break;
442 }
443 break;
445 default:
446 DPRINTK("Status change to unknown value %d\n", status->status);
447 break;
448 }
449 }
451 /*-----[ All control messages enter here: ]-------------------------------*/
453 void blkif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
454 {
455 switch ( msg->type )
456 {
457 case CMSG_BLKIF_FE:
459 switch ( msg->subtype )
460 {
461 case CMSG_BLKIF_FE_INTERFACE_STATUS:
462 blkif_ptbe_status((blkif_fe_interface_status_t *) &msg->msg[0]);
463 break;
465 default:
466 goto parse_error;
467 }
469 break;
471 case CMSG_BLKIF_BE:
473 /* send a copy of the message to user if wanted */
475 if ( (blktap_mode & BLKTAP_MODE_INTERCEPT_FE) ||
476 (blktap_mode & BLKTAP_MODE_COPY_FE) ) {
478 blktap_write_ctrl_ring(msg);
479 blktap_kick_user();
480 }
482 switch ( msg->subtype )
483 {
484 case CMSG_BLKIF_BE_CREATE:
485 blkif_ptfe_create((blkif_be_create_t *)&msg->msg[0]);
486 break;
487 case CMSG_BLKIF_BE_DESTROY:
488 blkif_ptfe_destroy((blkif_be_destroy_t *)&msg->msg[0]);
489 break;
490 case CMSG_BLKIF_BE_CONNECT:
491 blkif_ptfe_connect((blkif_be_connect_t *)&msg->msg[0]);
492 break;
493 case CMSG_BLKIF_BE_DISCONNECT:
494 if ( !blkif_ptfe_disconnect((blkif_be_disconnect_t *)&msg->msg[0],
495 msg->id) )
496 return;
497 break;
499 /* We just ignore anything to do with vbds for now. */
501 case CMSG_BLKIF_BE_VBD_CREATE:
502 DPRINTK("PT got VBD_CREATE\n");
503 ((blkif_be_vbd_create_t *)&msg->msg[0])->status
504 = BLKIF_BE_STATUS_OKAY;
505 break;
506 case CMSG_BLKIF_BE_VBD_DESTROY:
507 DPRINTK("PT got VBD_DESTROY\n");
508 ((blkif_be_vbd_destroy_t *)&msg->msg[0])->status
509 = BLKIF_BE_STATUS_OKAY;
510 break;
511 default:
512 goto parse_error;
513 }
515 break;
516 }
518 ctrl_if_send_response(msg);
519 return;
521 parse_error:
522 msg->length = 0;
523 ctrl_if_send_response(msg);
524 }
526 /*-----[ Initialization ]-------------------------------------------------*/
528 void __init blkif_interface_init(void)
529 {
530 blkif_cachep = kmem_cache_create("blkif_cache", sizeof(blkif_t),
531 0, 0, NULL, NULL);
532 memset(blkif_hash, 0, sizeof(blkif_hash));
534 blktap_be_ring.sring = NULL;
535 }
539 /* Debug : print the current ring indices. */
541 void print_fe_ring_idxs(void)
542 {
543 int i;
544 blkif_t *blkif;
546 WPRINTK("FE Rings: \n---------\n");
547 for ( i = 0; i < BLKIF_HASHSZ; i++) {
548 blkif = blkif_hash[i];
549 while (blkif != NULL) {
550 if (blkif->status == DISCONNECTED) {
551 WPRINTK("(%2d,%2d) DISCONNECTED\n",
552 blkif->domid, blkif->handle);
553 } else if (blkif->status == DISCONNECTING) {
554 WPRINTK("(%2d,%2d) DISCONNECTING\n",
555 blkif->domid, blkif->handle);
556 } else if (blkif->blk_ring.sring == NULL) {
557 WPRINTK("(%2d,%2d) CONNECTED, but null sring!\n",
558 blkif->domid, blkif->handle);
559 } else {
560 blkif_get(blkif);
561 WPRINTK("(%2d,%2d): req_cons: %2d, rsp_prod_prv: %2d "
562 "| req_prod: %2d, rsp_prod: %2d\n",
563 blkif->domid, blkif->handle,
564 blkif->blk_ring.req_cons,
565 blkif->blk_ring.rsp_prod_pvt,
566 blkif->blk_ring.sring->req_prod,
567 blkif->blk_ring.sring->rsp_prod);
568 blkif_put(blkif);
569 }
570 blkif = blkif->hash_next;
571 }
572 }
573 }