Konrad Rzeszutek Wilk | 4d05a28 | 2011-04-14 18:25:47 -0400 | [diff] [blame] | 1 | /****************************************************************************** |
Konrad Rzeszutek Wilk | 4d05a28 | 2011-04-14 18:25:47 -0400 | [diff] [blame] | 2 | * Routines for managing virtual block devices (VBDs). |
| 3 | * |
| 4 | * Copyright (c) 2003-2005, Keir Fraser & Steve Hand |
| 5 | * |
| 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: |
| 11 | * |
| 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: |
| 18 | * |
| 19 | * The above copyright notice and this permission notice shall be included in |
| 20 | * all copies or substantial portions of the Software. |
| 21 | * |
| 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 |
| 28 | * IN THE SOFTWARE. |
| 29 | */ |
| 30 | |
| 31 | #include "common.h" |
| 32 | |
| 33 | #define vbd_sz(_v) ((_v)->bdev->bd_part ? \ |
Jeremy Fitzhardinge | 8812293 | 2009-02-09 12:05:51 -0800 | [diff] [blame] | 34 | (_v)->bdev->bd_part->nr_sects : get_capacity((_v)->bdev->bd_disk)) |
Konrad Rzeszutek Wilk | 4d05a28 | 2011-04-14 18:25:47 -0400 | [diff] [blame] | 35 | |
| 36 | unsigned long long vbd_size(struct vbd *vbd) |
| 37 | { |
| 38 | return vbd_sz(vbd); |
| 39 | } |
| 40 | |
| 41 | unsigned int vbd_info(struct vbd *vbd) |
| 42 | { |
| 43 | return vbd->type | (vbd->readonly?VDISK_READONLY:0); |
| 44 | } |
| 45 | |
| 46 | unsigned long vbd_secsize(struct vbd *vbd) |
| 47 | { |
Jeremy Fitzhardinge | 05d4386 | 2009-06-29 14:58:45 -0700 | [diff] [blame] | 48 | return bdev_logical_block_size(vbd->bdev); |
Konrad Rzeszutek Wilk | 4d05a28 | 2011-04-14 18:25:47 -0400 | [diff] [blame] | 49 | } |
| 50 | |
Konrad Rzeszutek Wilk | 5489377 | 2011-04-14 17:21:50 -0400 | [diff] [blame^] | 51 | int vbd_create(struct blkif_st *blkif, blkif_vdev_t handle, unsigned major, |
Konrad Rzeszutek Wilk | 4d05a28 | 2011-04-14 18:25:47 -0400 | [diff] [blame] | 52 | unsigned minor, int readonly, int cdrom) |
| 53 | { |
| 54 | struct vbd *vbd; |
| 55 | struct block_device *bdev; |
| 56 | |
| 57 | vbd = &blkif->vbd; |
| 58 | vbd->handle = handle; |
| 59 | vbd->readonly = readonly; |
| 60 | vbd->type = 0; |
| 61 | |
| 62 | vbd->pdevice = MKDEV(major, minor); |
| 63 | |
Konrad Rzeszutek Wilk | bc0c081 | 2011-02-25 10:02:39 -0500 | [diff] [blame] | 64 | bdev = blkdev_get_by_dev(vbd->pdevice, vbd->readonly ? |
| 65 | FMODE_READ : FMODE_WRITE, NULL); |
Konrad Rzeszutek Wilk | 4d05a28 | 2011-04-14 18:25:47 -0400 | [diff] [blame] | 66 | |
| 67 | if (IS_ERR(bdev)) { |
| 68 | DPRINTK("vbd_creat: device %08x could not be opened.\n", |
| 69 | vbd->pdevice); |
| 70 | return -ENOENT; |
| 71 | } |
| 72 | |
| 73 | vbd->bdev = bdev; |
K. Y. Srinivasan | 2ccbfe2 | 2010-03-11 13:39:50 -0800 | [diff] [blame] | 74 | vbd->size = vbd_size(vbd); |
Konrad Rzeszutek Wilk | 4d05a28 | 2011-04-14 18:25:47 -0400 | [diff] [blame] | 75 | |
| 76 | if (vbd->bdev->bd_disk == NULL) { |
| 77 | DPRINTK("vbd_creat: device %08x doesn't exist.\n", |
| 78 | vbd->pdevice); |
| 79 | vbd_free(vbd); |
| 80 | return -ENOENT; |
| 81 | } |
| 82 | |
| 83 | if (vbd->bdev->bd_disk->flags & GENHD_FL_CD || cdrom) |
| 84 | vbd->type |= VDISK_CDROM; |
| 85 | if (vbd->bdev->bd_disk->flags & GENHD_FL_REMOVABLE) |
| 86 | vbd->type |= VDISK_REMOVABLE; |
| 87 | |
| 88 | DPRINTK("Successful creation of handle=%04x (dom=%u)\n", |
| 89 | handle, blkif->domid); |
| 90 | return 0; |
| 91 | } |
| 92 | |
| 93 | void vbd_free(struct vbd *vbd) |
| 94 | { |
| 95 | if (vbd->bdev) |
Jeremy Fitzhardinge | 8812293 | 2009-02-09 12:05:51 -0800 | [diff] [blame] | 96 | blkdev_put(vbd->bdev, vbd->readonly ? FMODE_READ : FMODE_WRITE); |
Konrad Rzeszutek Wilk | 4d05a28 | 2011-04-14 18:25:47 -0400 | [diff] [blame] | 97 | vbd->bdev = NULL; |
| 98 | } |
| 99 | |
Konrad Rzeszutek Wilk | 5489377 | 2011-04-14 17:21:50 -0400 | [diff] [blame^] | 100 | int vbd_translate(struct phys_req *req, struct blkif_st *blkif, int operation) |
Konrad Rzeszutek Wilk | 4d05a28 | 2011-04-14 18:25:47 -0400 | [diff] [blame] | 101 | { |
| 102 | struct vbd *vbd = &blkif->vbd; |
| 103 | int rc = -EACCES; |
| 104 | |
| 105 | if ((operation != READ) && vbd->readonly) |
| 106 | goto out; |
| 107 | |
| 108 | if (unlikely((req->sector_number + req->nr_sects) > vbd_sz(vbd))) |
| 109 | goto out; |
| 110 | |
| 111 | req->dev = vbd->pdevice; |
| 112 | req->bdev = vbd->bdev; |
| 113 | rc = 0; |
| 114 | |
| 115 | out: |
| 116 | return rc; |
| 117 | } |
K. Y. Srinivasan | 2ccbfe2 | 2010-03-11 13:39:50 -0800 | [diff] [blame] | 118 | |
Konrad Rzeszutek Wilk | 5489377 | 2011-04-14 17:21:50 -0400 | [diff] [blame^] | 119 | void vbd_resize(struct blkif_st *blkif) |
K. Y. Srinivasan | 2ccbfe2 | 2010-03-11 13:39:50 -0800 | [diff] [blame] | 120 | { |
| 121 | struct vbd *vbd = &blkif->vbd; |
| 122 | struct xenbus_transaction xbt; |
| 123 | int err; |
Jeremy Fitzhardinge | 98e036a | 2010-03-18 15:35:05 -0700 | [diff] [blame] | 124 | struct xenbus_device *dev = blkback_xenbus(blkif->be); |
K. Y. Srinivasan | 2ccbfe2 | 2010-03-11 13:39:50 -0800 | [diff] [blame] | 125 | unsigned long long new_size = vbd_size(vbd); |
| 126 | |
K. Y. Srinivasan | a81135d | 2010-08-16 13:43:06 -0700 | [diff] [blame] | 127 | printk(KERN_INFO "VBD Resize: Domid: %d, Device: (%d, %d)\n", |
| 128 | blkif->domid, MAJOR(vbd->pdevice), MINOR(vbd->pdevice)); |
K. Y. Srinivasan | 2ccbfe2 | 2010-03-11 13:39:50 -0800 | [diff] [blame] | 129 | printk(KERN_INFO "VBD Resize: new size %Lu\n", new_size); |
| 130 | vbd->size = new_size; |
| 131 | again: |
| 132 | err = xenbus_transaction_start(&xbt); |
| 133 | if (err) { |
| 134 | printk(KERN_WARNING "Error starting transaction"); |
| 135 | return; |
| 136 | } |
| 137 | err = xenbus_printf(xbt, dev->nodename, "sectors", "%Lu", |
| 138 | vbd_size(vbd)); |
| 139 | if (err) { |
| 140 | printk(KERN_WARNING "Error writing new size"); |
| 141 | goto abort; |
| 142 | } |
| 143 | /* |
| 144 | * Write the current state; we will use this to synchronize |
| 145 | * the front-end. If the current state is "connected" the |
| 146 | * front-end will get the new size information online. |
| 147 | */ |
| 148 | err = xenbus_printf(xbt, dev->nodename, "state", "%d", dev->state); |
| 149 | if (err) { |
| 150 | printk(KERN_WARNING "Error writing the state"); |
| 151 | goto abort; |
| 152 | } |
| 153 | |
| 154 | err = xenbus_transaction_end(xbt, 0); |
| 155 | if (err == -EAGAIN) |
| 156 | goto again; |
| 157 | if (err) |
| 158 | printk(KERN_WARNING "Error ending transaction"); |
| 159 | abort: |
| 160 | xenbus_transaction_end(xbt, 1); |
| 161 | } |