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 struct blkif_st
*blkif_alloc(domid_t domid
)
40 struct blkif_st
*blkif
;
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(struct blkif_st
*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(struct blkif_st
*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(struct blkif_st
*blkif
, unsigned long shared_page
,
94 /* Already connected through? */
98 blkif
->blk_ring_area
= alloc_vm_area(PAGE_SIZE
);
99 if (!blkif
->blk_ring_area
)
102 err
= map_frontend_page(blkif
, shared_page
);
104 free_vm_area(blkif
->blk_ring_area
);
108 switch (blkif
->blk_protocol
) {
109 case BLKIF_PROTOCOL_NATIVE
:
111 struct blkif_sring
*sring
;
112 sring
= (struct blkif_sring
*)blkif
->blk_ring_area
->addr
;
113 BACK_RING_INIT(&blkif
->blk_rings
.native
, sring
, PAGE_SIZE
);
116 case BLKIF_PROTOCOL_X86_32
:
118 struct blkif_x86_32_sring
*sring_x86_32
;
119 sring_x86_32
= (struct blkif_x86_32_sring
*)blkif
->blk_ring_area
->addr
;
120 BACK_RING_INIT(&blkif
->blk_rings
.x86_32
, sring_x86_32
, PAGE_SIZE
);
123 case BLKIF_PROTOCOL_X86_64
:
125 struct blkif_x86_64_sring
*sring_x86_64
;
126 sring_x86_64
= (struct blkif_x86_64_sring
*)blkif
->blk_ring_area
->addr
;
127 BACK_RING_INIT(&blkif
->blk_rings
.x86_64
, sring_x86_64
, PAGE_SIZE
);
134 err
= bind_interdomain_evtchn_to_irqhandler(
135 blkif
->domid
, evtchn
, blkif_be_int
, 0, "blkif-backend", blkif
);
137 unmap_frontend_page(blkif
);
138 free_vm_area(blkif
->blk_ring_area
);
139 blkif
->blk_rings
.common
.sring
= NULL
;
147 void blkif_disconnect(struct blkif_st
*blkif
)
149 if (blkif
->xenblkd
) {
150 kthread_stop(blkif
->xenblkd
);
151 blkif
->xenblkd
= NULL
;
154 atomic_dec(&blkif
->refcnt
);
155 wait_event(blkif
->waiting_to_free
, atomic_read(&blkif
->refcnt
) == 0);
156 atomic_inc(&blkif
->refcnt
);
159 unbind_from_irqhandler(blkif
->irq
, blkif
);
163 if (blkif
->blk_rings
.common
.sring
) {
164 unmap_frontend_page(blkif
);
165 free_vm_area(blkif
->blk_ring_area
);
166 blkif
->blk_rings
.common
.sring
= NULL
;
170 void blkif_free(struct blkif_st
*blkif
)
172 if (!atomic_dec_and_test(&blkif
->refcnt
))
174 kmem_cache_free(blkif_cachep
, blkif
);
177 int __init
blkif_interface_init(void)
179 blkif_cachep
= kmem_cache_create("blkif_cache", sizeof(struct blkif_st
),