1 /******************************************************************************
4 * Routines for managing virtual block devices (VBDs).
6 * NOTE: vbd_lock protects updates to the rb_tree against concurrent lookups
7 * in vbd_translate. All other lookups are implicitly protected because the
8 * only caller (the control message dispatch routine) serializes the calls.
10 * Copyright (c) 2003-2005, Keir Fraser & Steve Hand
16 blkif_vdev_t vdevice; /* what the domain refers to this vbd as */
17 unsigned char readonly; /* Non-zero -> read-only */
18 unsigned char type; /* VDISK_TYPE_xxx */
19 blkif_pdev_t pdevice; /* phys device that this vbd maps to */
20 struct block_device *bdev;
21 rb_node_t rb; /* for linking into R-B tree lookup struct */
24 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
25 static inline dev_t vbd_map_devnum(blkif_pdev_t cookie)
26 { return MKDEV(cookie>>8, cookie&0xff); }
27 #define vbd_sz(_v) ((_v)->bdev->bd_part ? \
28 (_v)->bdev->bd_part->nr_sects : (_v)->bdev->bd_disk->capacity)
29 #define bdev_put(_b) blkdev_put(_b)
31 #define vbd_sz(_v) (blk_size[MAJOR((_v)->pdevice)][MINOR((_v)->pdevice)]*2)
32 #define bdev_put(_b) ((void)0)
35 void vbd_create(blkif_be_vbd_create_t *create)
38 rb_node_t **rb_p, *rb_parent = NULL;
40 blkif_vdev_t vdevice = create->vdevice;
42 blkif = blkif_find_by_handle(create->domid, create->blkif_handle);
43 if ( unlikely(blkif == NULL) )
45 DPRINTK("vbd_create attempted for non-existent blkif (%u,%u)\n",
46 create->domid, create->blkif_handle);
47 create->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND;
51 rb_p = &blkif->vbd_rb.rb_node;
52 while ( *rb_p != NULL )
55 vbd = rb_entry(rb_parent, struct vbd, rb);
56 if ( vdevice < vbd->vdevice )
58 rb_p = &rb_parent->rb_left;
60 else if ( vdevice > vbd->vdevice )
62 rb_p = &rb_parent->rb_right;
66 DPRINTK("vbd_create attempted for already existing vbd\n");
67 create->status = BLKIF_BE_STATUS_VBD_EXISTS;
72 if ( unlikely((vbd = kmalloc(sizeof(struct vbd), GFP_KERNEL)) == NULL) )
74 DPRINTK("vbd_create: out of memory\n");
75 create->status = BLKIF_BE_STATUS_OUT_OF_MEMORY;
79 vbd->vdevice = vdevice;
80 vbd->readonly = create->readonly;
81 vbd->type = VDISK_TYPE_DISK | VDISK_FLAG_VIRT;
83 /* Mask to 16-bit for compatibility with old tools */
84 vbd->pdevice = create->pdevice & 0xffff;
86 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
87 vbd->bdev = open_by_devnum(
88 vbd_map_devnum(vbd->pdevice),
89 vbd->readonly ? FMODE_READ : FMODE_WRITE);
90 if ( IS_ERR(vbd->bdev) )
92 DPRINTK("vbd_creat: device %08x doesn't exist.\n", vbd->pdevice);
93 create->status = BLKIF_BE_STATUS_PHYSDEV_NOT_FOUND;
97 if ( (vbd->bdev->bd_disk == NULL) )
99 DPRINTK("vbd_creat: device %08x doesn't exist.\n", vbd->pdevice);
100 create->status = BLKIF_BE_STATUS_PHYSDEV_NOT_FOUND;
105 if ( (blk_size[MAJOR(vbd->pdevice)] == NULL) || (vbd_sz(vbd) == 0) )
107 DPRINTK("vbd_creat: device %08x doesn't exist.\n", vbd->pdevice);
108 create->status = BLKIF_BE_STATUS_PHYSDEV_NOT_FOUND;
113 spin_lock(&blkif->vbd_lock);
114 rb_link_node(&vbd->rb, rb_parent, rb_p);
115 rb_insert_color(&vbd->rb, &blkif->vbd_rb);
116 spin_unlock(&blkif->vbd_lock);
118 DPRINTK("Successful creation of vdev=%04x (dom=%u)\n",
119 vdevice, create->domid);
120 create->status = BLKIF_BE_STATUS_OKAY;
124 void vbd_destroy(blkif_be_vbd_destroy_t *destroy)
129 blkif_vdev_t vdevice = destroy->vdevice;
131 blkif = blkif_find_by_handle(destroy->domid, destroy->blkif_handle);
132 if ( unlikely(blkif == NULL) )
134 DPRINTK("vbd_destroy attempted for non-existent blkif (%u,%u)\n",
135 destroy->domid, destroy->blkif_handle);
136 destroy->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND;
140 rb = blkif->vbd_rb.rb_node;
143 vbd = rb_entry(rb, struct vbd, rb);
144 if ( vdevice < vbd->vdevice )
146 else if ( vdevice > vbd->vdevice )
152 destroy->status = BLKIF_BE_STATUS_VBD_NOT_FOUND;
156 spin_lock(&blkif->vbd_lock);
157 rb_erase(rb, &blkif->vbd_rb);
158 spin_unlock(&blkif->vbd_lock);
164 void destroy_all_vbds(blkif_t *blkif)
169 spin_lock(&blkif->vbd_lock);
171 while ( (rb = blkif->vbd_rb.rb_node) != NULL )
173 vbd = rb_entry(rb, struct vbd, rb);
174 rb_erase(rb, &blkif->vbd_rb);
175 spin_unlock(&blkif->vbd_lock);
178 spin_lock(&blkif->vbd_lock);
181 spin_unlock(&blkif->vbd_lock);
185 static void vbd_probe_single(
186 blkif_t *blkif, vdisk_t *vbd_info, struct vbd *vbd)
188 vbd_info->device = vbd->vdevice;
189 vbd_info->info = vbd->type | (vbd->readonly ? VDISK_FLAG_RO : 0);
190 vbd_info->capacity = vbd_sz(vbd);
194 int vbd_probe(blkif_t *blkif, vdisk_t *vbd_info, int max_vbds)
196 int rc = 0, nr_vbds = 0;
199 spin_lock(&blkif->vbd_lock);
201 if ( (rb = blkif->vbd_rb.rb_node) == NULL )
205 /* STEP 1. Find least node (it'll be left-most). */
206 while ( rb->rb_left != NULL )
211 /* STEP 2. Dealt with left subtree. Now process current node. */
212 vbd_probe_single(blkif, &vbd_info[nr_vbds],
213 rb_entry(rb, struct vbd, rb));
214 if ( ++nr_vbds == max_vbds )
217 /* STEP 3. Process right subtree, if any. */
218 if ( rb->rb_right != NULL )
224 /* STEP 4. Done both subtrees. Head back through ancesstors. */
227 /* We're done when we get back to the root node. */
228 if ( rb->rb_parent == NULL )
230 /* If we are left of parent, then parent is next to process. */
231 if ( rb->rb_parent->rb_left == rb )
233 /* If we are right of parent, then we climb to grandparent. */
241 spin_unlock(&blkif->vbd_lock);
242 return (rc == 0) ? nr_vbds : rc;
246 int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation)
252 /* Take the vbd_lock because another thread could be updating the tree. */
253 spin_lock(&blkif->vbd_lock);
255 rb = blkif->vbd_rb.rb_node;
258 vbd = rb_entry(rb, struct vbd, rb);
259 if ( req->dev < vbd->vdevice )
261 else if ( req->dev > vbd->vdevice )
267 DPRINTK("vbd_translate; domain %u attempted to access "
268 "non-existent VBD.\n", blkif->domid);
274 if ( (operation == WRITE) && vbd->readonly )
277 if ( unlikely((req->sector_number + req->nr_sects) > vbd_sz(vbd)) )
280 req->dev = vbd->pdevice;
281 req->bdev = vbd->bdev;
285 spin_unlock(&blkif->vbd_lock);