1 /******************************************************************************
2 * Block-device interface management.
4 * Copyright (c) 2004, Keir Fraser
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation; or, when distributed
9 * separately from the Linux kernel or incorporated into other
10 * software packages, subject to the following license:
12 * Permission is hereby granted, free of charge, to any person obtaining a copy
13 * of this source file (the "Software"), to deal in the Software without
14 * restriction, including without limitation the rights to use, copy, modify,
15 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
16 * and to permit persons to whom the Software is furnished to do so, subject to
17 * the following conditions:
19 * The above copyright notice and this permission notice shall be included in
20 * all copies or substantial portions of the Software.
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
32 #include <xen/events.h>
33 #include <xen/grant_table.h>
34 #include <linux/kthread.h>
36 static struct kmem_cache
*blkif_cachep
;
38 blkif_t
*blkif_alloc(domid_t domid
)
42 blkif
= kmem_cache_alloc(blkif_cachep
, GFP_KERNEL
);
44 return ERR_PTR(-ENOMEM
);
46 memset(blkif
, 0, sizeof(*blkif
));
48 spin_lock_init(&blkif
->blk_ring_lock
);
49 atomic_set(&blkif
->refcnt
, 1);
50 init_waitqueue_head(&blkif
->wq
);
51 blkif
->st_print
= jiffies
;
52 init_waitqueue_head(&blkif
->waiting_to_free
);
57 static int map_frontend_page(blkif_t
*blkif
, unsigned long shared_page
)
59 struct gnttab_map_grant_ref op
;
61 gnttab_set_map_op(&op
, (unsigned long)blkif
->blk_ring_area
->addr
,
62 GNTMAP_host_map
, shared_page
, blkif
->domid
);
64 if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref
, &op
, 1))
68 DPRINTK(" Grant table operation failure !\n");
72 blkif
->shmem_ref
= shared_page
;
73 blkif
->shmem_handle
= op
.handle
;
78 static void unmap_frontend_page(blkif_t
*blkif
)
80 struct gnttab_unmap_grant_ref op
;
82 gnttab_set_unmap_op(&op
, (unsigned long)blkif
->blk_ring_area
->addr
,
83 GNTMAP_host_map
, blkif
->shmem_handle
);
85 if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref
, &op
, 1))
89 int blkif_map(blkif_t
*blkif
, unsigned long shared_page
, unsigned int evtchn
)
93 /* Already connected through? */
97 if ( (blkif
->blk_ring_area
= alloc_vm_area(PAGE_SIZE
)) == NULL
)
100 err
= map_frontend_page(blkif
, shared_page
);
102 free_vm_area(blkif
->blk_ring_area
);
106 switch (blkif
->blk_protocol
) {
107 case BLKIF_PROTOCOL_NATIVE
:
109 struct blkif_sring
*sring
;
110 sring
= (struct blkif_sring
*)blkif
->blk_ring_area
->addr
;
111 BACK_RING_INIT(&blkif
->blk_rings
.native
, sring
, PAGE_SIZE
);
114 case BLKIF_PROTOCOL_X86_32
:
116 struct blkif_x86_32_sring
*sring_x86_32
;
117 sring_x86_32
= (struct blkif_x86_32_sring
*)blkif
->blk_ring_area
->addr
;
118 BACK_RING_INIT(&blkif
->blk_rings
.x86_32
, sring_x86_32
, PAGE_SIZE
);
121 case BLKIF_PROTOCOL_X86_64
:
123 struct blkif_x86_64_sring
*sring_x86_64
;
124 sring_x86_64
= (struct blkif_x86_64_sring
*)blkif
->blk_ring_area
->addr
;
125 BACK_RING_INIT(&blkif
->blk_rings
.x86_64
, sring_x86_64
, PAGE_SIZE
);
132 err
= bind_interdomain_evtchn_to_irqhandler(
133 blkif
->domid
, evtchn
, blkif_be_int
, 0, "blkif-backend", blkif
);
136 unmap_frontend_page(blkif
);
137 free_vm_area(blkif
->blk_ring_area
);
138 blkif
->blk_rings
.common
.sring
= NULL
;
146 void blkif_disconnect(blkif_t
*blkif
)
148 if (blkif
->xenblkd
) {
149 kthread_stop(blkif
->xenblkd
);
150 blkif
->xenblkd
= NULL
;
153 atomic_dec(&blkif
->refcnt
);
154 wait_event(blkif
->waiting_to_free
, atomic_read(&blkif
->refcnt
) == 0);
155 atomic_inc(&blkif
->refcnt
);
158 unbind_from_irqhandler(blkif
->irq
, blkif
);
162 if (blkif
->blk_rings
.common
.sring
) {
163 unmap_frontend_page(blkif
);
164 free_vm_area(blkif
->blk_ring_area
);
165 blkif
->blk_rings
.common
.sring
= NULL
;
169 void blkif_free(blkif_t
*blkif
)
171 if (!atomic_dec_and_test(&blkif
->refcnt
))
173 kmem_cache_free(blkif_cachep
, blkif
);
176 int __init
blkif_interface_init(void)
178 blkif_cachep
= kmem_cache_create("blkif_cache", sizeof(blkif_t
),