aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/xen-blkfront.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/block/xen-blkfront.c')
-rw-r--r--drivers/block/xen-blkfront.c88
1 files changed, 81 insertions, 7 deletions
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 304009e77c73..22091e4e401f 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -105,6 +105,10 @@ struct blkfront_info
105 105
106static DEFINE_SPINLOCK(blkif_io_lock); 106static DEFINE_SPINLOCK(blkif_io_lock);
107 107
108static unsigned int nr_minors;
109static unsigned long *minors;
110static DEFINE_SPINLOCK(minor_lock);
111
108#define MAXIMUM_OUTSTANDING_BLOCK_REQS \ 112#define MAXIMUM_OUTSTANDING_BLOCK_REQS \
109 (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLK_RING_SIZE) 113 (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLK_RING_SIZE)
110#define GRANT_INVALID_REF 0 114#define GRANT_INVALID_REF 0
@@ -139,6 +143,55 @@ static void add_id_to_freelist(struct blkfront_info *info,
139 info->shadow_free = id; 143 info->shadow_free = id;
140} 144}
141 145
146static int xlbd_reserve_minors(unsigned int minor, unsigned int nr)
147{
148 unsigned int end = minor + nr;
149 int rc;
150
151 if (end > nr_minors) {
152 unsigned long *bitmap, *old;
153
154 bitmap = kzalloc(BITS_TO_LONGS(end) * sizeof(*bitmap),
155 GFP_KERNEL);
156 if (bitmap == NULL)
157 return -ENOMEM;
158
159 spin_lock(&minor_lock);
160 if (end > nr_minors) {
161 old = minors;
162 memcpy(bitmap, minors,
163 BITS_TO_LONGS(nr_minors) * sizeof(*bitmap));
164 minors = bitmap;
165 nr_minors = BITS_TO_LONGS(end) * BITS_PER_LONG;
166 } else
167 old = bitmap;
168 spin_unlock(&minor_lock);
169 kfree(old);
170 }
171
172 spin_lock(&minor_lock);
173 if (find_next_bit(minors, end, minor) >= end) {
174 for (; minor < end; ++minor)
175 __set_bit(minor, minors);
176 rc = 0;
177 } else
178 rc = -EBUSY;
179 spin_unlock(&minor_lock);
180
181 return rc;
182}
183
184static void xlbd_release_minors(unsigned int minor, unsigned int nr)
185{
186 unsigned int end = minor + nr;
187
188 BUG_ON(end > nr_minors);
189 spin_lock(&minor_lock);
190 for (; minor < end; ++minor)
191 __clear_bit(minor, minors);
192 spin_unlock(&minor_lock);
193}
194
142static void blkif_restart_queue_callback(void *arg) 195static void blkif_restart_queue_callback(void *arg)
143{ 196{
144 struct blkfront_info *info = (struct blkfront_info *)arg; 197 struct blkfront_info *info = (struct blkfront_info *)arg;
@@ -417,9 +470,14 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
417 if ((minor % nr_parts) == 0) 470 if ((minor % nr_parts) == 0)
418 nr_minors = nr_parts; 471 nr_minors = nr_parts;
419 472
473 err = xlbd_reserve_minors(minor, nr_minors);
474 if (err)
475 goto out;
476 err = -ENODEV;
477
420 gd = alloc_disk(nr_minors); 478 gd = alloc_disk(nr_minors);
421 if (gd == NULL) 479 if (gd == NULL)
422 goto out; 480 goto release;
423 481
424 offset = minor / nr_parts; 482 offset = minor / nr_parts;
425 483
@@ -450,7 +508,7 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
450 508
451 if (xlvbd_init_blk_queue(gd, sector_size)) { 509 if (xlvbd_init_blk_queue(gd, sector_size)) {
452 del_gendisk(gd); 510 del_gendisk(gd);
453 goto out; 511 goto release;
454 } 512 }
455 513
456 info->rq = gd->queue; 514 info->rq = gd->queue;
@@ -470,6 +528,8 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
470 528
471 return 0; 529 return 0;
472 530
531 release:
532 xlbd_release_minors(minor, nr_minors);
473 out: 533 out:
474 return err; 534 return err;
475} 535}
@@ -924,6 +984,7 @@ static void blkfront_connect(struct blkfront_info *info)
924static void blkfront_closing(struct xenbus_device *dev) 984static void blkfront_closing(struct xenbus_device *dev)
925{ 985{
926 struct blkfront_info *info = dev_get_drvdata(&dev->dev); 986 struct blkfront_info *info = dev_get_drvdata(&dev->dev);
987 unsigned int minor, nr_minors;
927 unsigned long flags; 988 unsigned long flags;
928 989
929 dev_dbg(&dev->dev, "blkfront_closing: %s removed\n", dev->nodename); 990 dev_dbg(&dev->dev, "blkfront_closing: %s removed\n", dev->nodename);
@@ -946,7 +1007,10 @@ static void blkfront_closing(struct xenbus_device *dev)
946 blk_cleanup_queue(info->rq); 1007 blk_cleanup_queue(info->rq);
947 info->rq = NULL; 1008 info->rq = NULL;
948 1009
1010 minor = info->gd->first_minor;
1011 nr_minors = info->gd->minors;
949 del_gendisk(info->gd); 1012 del_gendisk(info->gd);
1013 xlbd_release_minors(minor, nr_minors);
950 1014
951 out: 1015 out:
952 xenbus_frontend_closed(dev); 1016 xenbus_frontend_closed(dev);
@@ -1004,7 +1068,10 @@ static int blkfront_remove(struct xenbus_device *dev)
1004 1068
1005 blkif_free(info, 0); 1069 blkif_free(info, 0);
1006 1070
1007 kfree(info); 1071 if(info->users == 0)
1072 kfree(info);
1073 else
1074 info->is_ready = -1;
1008 1075
1009 return 0; 1076 return 0;
1010} 1077}
@@ -1013,18 +1080,22 @@ static int blkfront_is_ready(struct xenbus_device *dev)
1013{ 1080{
1014 struct blkfront_info *info = dev_get_drvdata(&dev->dev); 1081 struct blkfront_info *info = dev_get_drvdata(&dev->dev);
1015 1082
1016 return info->is_ready; 1083 return info->is_ready > 0;
1017} 1084}
1018 1085
1019static int blkif_open(struct block_device *bdev, fmode_t mode) 1086static int blkif_open(struct block_device *bdev, fmode_t mode)
1020{ 1087{
1021 struct blkfront_info *info = bdev->bd_disk->private_data; 1088 struct blkfront_info *info = bdev->bd_disk->private_data;
1089 int ret = 0;
1022 1090
1023 lock_kernel(); 1091 lock_kernel();
1024 info->users++; 1092 if (info->is_ready < 0)
1093 ret = -ENODEV;
1094 else
1095 info->users++;
1025 unlock_kernel(); 1096 unlock_kernel();
1026 1097
1027 return 0; 1098 return ret;
1028} 1099}
1029 1100
1030static int blkif_release(struct gendisk *disk, fmode_t mode) 1101static int blkif_release(struct gendisk *disk, fmode_t mode)
@@ -1039,7 +1110,10 @@ static int blkif_release(struct gendisk *disk, fmode_t mode)
1039 struct xenbus_device *dev = info->xbdev; 1110 struct xenbus_device *dev = info->xbdev;
1040 enum xenbus_state state = xenbus_read_driver_state(dev->otherend); 1111 enum xenbus_state state = xenbus_read_driver_state(dev->otherend);
1041 1112
1042 if (state == XenbusStateClosing && info->is_ready) 1113 if(info->is_ready < 0) {
1114 blkfront_closing(dev);
1115 kfree(info);
1116 } else if (state == XenbusStateClosing && info->is_ready)
1043 blkfront_closing(dev); 1117 blkfront_closing(dev);
1044 } 1118 }
1045 unlock_kernel(); 1119 unlock_kernel();