Skip to content

Commit 05d69d9

Browse files
Christoph Hellwigaxboe
authored andcommitted
xen-blkfront: sanitize the removal state machine
xen-blkfront has a weird protocol where close message from the remote side can be delayed, and where hot removals are treated somewhat differently from regular removals, all leading to potential NULL pointer removals, and a del_gendisk from the block device release method, which will deadlock. Fix this by just performing normal hot removals even when the device is opened like all other Linux block drivers. Fixes: c76f48e ("block: take bd_mutex around delete_partitions in del_gendisk") Reported-by: Vitaly Kuznetsov <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]> Tested-by: Vitaly Kuznetsov <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent a347c15 commit 05d69d9

File tree

1 file changed

+26
-198
lines changed

1 file changed

+26
-198
lines changed

drivers/block/xen-blkfront.c

Lines changed: 26 additions & 198 deletions
Original file line numberDiff line numberDiff line change
@@ -502,34 +502,21 @@ static int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg)
502502
static int blkif_ioctl(struct block_device *bdev, fmode_t mode,
503503
unsigned command, unsigned long argument)
504504
{
505-
struct blkfront_info *info = bdev->bd_disk->private_data;
506505
int i;
507506

508-
dev_dbg(&info->xbdev->dev, "command: 0x%x, argument: 0x%lx\n",
509-
command, (long)argument);
510-
511507
switch (command) {
512508
case CDROMMULTISESSION:
513-
dev_dbg(&info->xbdev->dev, "FIXME: support multisession CDs later\n");
514509
for (i = 0; i < sizeof(struct cdrom_multisession); i++)
515510
if (put_user(0, (char __user *)(argument + i)))
516511
return -EFAULT;
517512
return 0;
518-
519-
case CDROM_GET_CAPABILITY: {
520-
struct gendisk *gd = info->gd;
521-
if (gd->flags & GENHD_FL_CD)
513+
case CDROM_GET_CAPABILITY:
514+
if (bdev->bd_disk->flags & GENHD_FL_CD)
522515
return 0;
523516
return -EINVAL;
524-
}
525-
526517
default:
527-
/*printk(KERN_ALERT "ioctl %08x not supported by Xen blkdev\n",
528-
command);*/
529-
return -EINVAL; /* same return as native Linux */
518+
return -EINVAL;
530519
}
531-
532-
return 0;
533520
}
534521

535522
static unsigned long blkif_ring_get_request(struct blkfront_ring_info *rinfo,
@@ -1177,36 +1164,6 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
11771164
return err;
11781165
}
11791166

1180-
static void xlvbd_release_gendisk(struct blkfront_info *info)
1181-
{
1182-
unsigned int minor, nr_minors, i;
1183-
struct blkfront_ring_info *rinfo;
1184-
1185-
if (info->rq == NULL)
1186-
return;
1187-
1188-
/* No more blkif_request(). */
1189-
blk_mq_stop_hw_queues(info->rq);
1190-
1191-
for_each_rinfo(info, rinfo, i) {
1192-
/* No more gnttab callback work. */
1193-
gnttab_cancel_free_callback(&rinfo->callback);
1194-
1195-
/* Flush gnttab callback work. Must be done with no locks held. */
1196-
flush_work(&rinfo->work);
1197-
}
1198-
1199-
del_gendisk(info->gd);
1200-
1201-
minor = info->gd->first_minor;
1202-
nr_minors = info->gd->minors;
1203-
xlbd_release_minors(minor, nr_minors);
1204-
1205-
blk_cleanup_disk(info->gd);
1206-
info->gd = NULL;
1207-
blk_mq_free_tag_set(&info->tag_set);
1208-
}
1209-
12101167
/* Already hold rinfo->ring_lock. */
12111168
static inline void kick_pending_request_queues_locked(struct blkfront_ring_info *rinfo)
12121169
{
@@ -1756,12 +1713,6 @@ static int write_per_ring_nodes(struct xenbus_transaction xbt,
17561713
return err;
17571714
}
17581715

1759-
static void free_info(struct blkfront_info *info)
1760-
{
1761-
list_del(&info->info_list);
1762-
kfree(info);
1763-
}
1764-
17651716
/* Common code used when first setting up, and when resuming. */
17661717
static int talk_to_blkback(struct xenbus_device *dev,
17671718
struct blkfront_info *info)
@@ -1880,13 +1831,6 @@ static int talk_to_blkback(struct xenbus_device *dev,
18801831
xenbus_dev_fatal(dev, err, "%s", message);
18811832
destroy_blkring:
18821833
blkif_free(info, 0);
1883-
1884-
mutex_lock(&blkfront_mutex);
1885-
free_info(info);
1886-
mutex_unlock(&blkfront_mutex);
1887-
1888-
dev_set_drvdata(&dev->dev, NULL);
1889-
18901834
return err;
18911835
}
18921836

@@ -2126,38 +2070,26 @@ static int blkfront_resume(struct xenbus_device *dev)
21262070
static void blkfront_closing(struct blkfront_info *info)
21272071
{
21282072
struct xenbus_device *xbdev = info->xbdev;
2129-
struct block_device *bdev = NULL;
2130-
2131-
mutex_lock(&info->mutex);
2073+
struct blkfront_ring_info *rinfo;
2074+
unsigned int i;
21322075

2133-
if (xbdev->state == XenbusStateClosing) {
2134-
mutex_unlock(&info->mutex);
2076+
if (xbdev->state == XenbusStateClosing)
21352077
return;
2136-
}
21372078

2138-
if (info->gd)
2139-
bdev = bdgrab(info->gd->part0);
2140-
2141-
mutex_unlock(&info->mutex);
2142-
2143-
if (!bdev) {
2144-
xenbus_frontend_closed(xbdev);
2145-
return;
2146-
}
2079+
/* No more blkif_request(). */
2080+
blk_mq_stop_hw_queues(info->rq);
2081+
blk_set_queue_dying(info->rq);
2082+
set_capacity(info->gd, 0);
21472083

2148-
mutex_lock(&bdev->bd_disk->open_mutex);
2084+
for_each_rinfo(info, rinfo, i) {
2085+
/* No more gnttab callback work. */
2086+
gnttab_cancel_free_callback(&rinfo->callback);
21492087

2150-
if (bdev->bd_openers) {
2151-
xenbus_dev_error(xbdev, -EBUSY,
2152-
"Device in use; refusing to close");
2153-
xenbus_switch_state(xbdev, XenbusStateClosing);
2154-
} else {
2155-
xlvbd_release_gendisk(info);
2156-
xenbus_frontend_closed(xbdev);
2088+
/* Flush gnttab callback work. Must be done with no locks held. */
2089+
flush_work(&rinfo->work);
21572090
}
21582091

2159-
mutex_unlock(&bdev->bd_disk->open_mutex);
2160-
bdput(bdev);
2092+
xenbus_frontend_closed(xbdev);
21612093
}
21622094

21632095
static void blkfront_setup_discard(struct blkfront_info *info)
@@ -2472,65 +2404,29 @@ static void blkback_changed(struct xenbus_device *dev,
24722404
break;
24732405
fallthrough;
24742406
case XenbusStateClosing:
2475-
if (info)
2476-
blkfront_closing(info);
2407+
blkfront_closing(info);
24772408
break;
24782409
}
24792410
}
24802411

24812412
static int blkfront_remove(struct xenbus_device *xbdev)
24822413
{
24832414
struct blkfront_info *info = dev_get_drvdata(&xbdev->dev);
2484-
struct block_device *bdev = NULL;
2485-
struct gendisk *disk;
24862415

24872416
dev_dbg(&xbdev->dev, "%s removed", xbdev->nodename);
24882417

2489-
if (!info)
2490-
return 0;
2491-
2492-
blkif_free(info, 0);
2493-
2494-
mutex_lock(&info->mutex);
2495-
2496-
disk = info->gd;
2497-
if (disk)
2498-
bdev = bdgrab(disk->part0);
2499-
2500-
info->xbdev = NULL;
2501-
mutex_unlock(&info->mutex);
2502-
2503-
if (!bdev) {
2504-
mutex_lock(&blkfront_mutex);
2505-
free_info(info);
2506-
mutex_unlock(&blkfront_mutex);
2507-
return 0;
2508-
}
2509-
2510-
/*
2511-
* The xbdev was removed before we reached the Closed
2512-
* state. See if it's safe to remove the disk. If the bdev
2513-
* isn't closed yet, we let release take care of it.
2514-
*/
2515-
2516-
mutex_lock(&disk->open_mutex);
2517-
info = disk->private_data;
2518-
2519-
dev_warn(disk_to_dev(disk),
2520-
"%s was hot-unplugged, %d stale handles\n",
2521-
xbdev->nodename, bdev->bd_openers);
2418+
del_gendisk(info->gd);
25222419

2523-
if (info && !bdev->bd_openers) {
2524-
xlvbd_release_gendisk(info);
2525-
disk->private_data = NULL;
2526-
mutex_lock(&blkfront_mutex);
2527-
free_info(info);
2528-
mutex_unlock(&blkfront_mutex);
2529-
}
2420+
mutex_lock(&blkfront_mutex);
2421+
list_del(&info->info_list);
2422+
mutex_unlock(&blkfront_mutex);
25302423

2531-
mutex_unlock(&disk->open_mutex);
2532-
bdput(bdev);
2424+
blkif_free(info, 0);
2425+
xlbd_release_minors(info->gd->first_minor, info->gd->minors);
2426+
blk_cleanup_disk(info->gd);
2427+
blk_mq_free_tag_set(&info->tag_set);
25332428

2429+
kfree(info);
25342430
return 0;
25352431
}
25362432

@@ -2541,77 +2437,9 @@ static int blkfront_is_ready(struct xenbus_device *dev)
25412437
return info->is_ready && info->xbdev;
25422438
}
25432439

2544-
static int blkif_open(struct block_device *bdev, fmode_t mode)
2545-
{
2546-
struct gendisk *disk = bdev->bd_disk;
2547-
struct blkfront_info *info;
2548-
int err = 0;
2549-
2550-
mutex_lock(&blkfront_mutex);
2551-
2552-
info = disk->private_data;
2553-
if (!info) {
2554-
/* xbdev gone */
2555-
err = -ERESTARTSYS;
2556-
goto out;
2557-
}
2558-
2559-
mutex_lock(&info->mutex);
2560-
2561-
if (!info->gd)
2562-
/* xbdev is closed */
2563-
err = -ERESTARTSYS;
2564-
2565-
mutex_unlock(&info->mutex);
2566-
2567-
out:
2568-
mutex_unlock(&blkfront_mutex);
2569-
return err;
2570-
}
2571-
2572-
static void blkif_release(struct gendisk *disk, fmode_t mode)
2573-
{
2574-
struct blkfront_info *info = disk->private_data;
2575-
struct xenbus_device *xbdev;
2576-
2577-
mutex_lock(&blkfront_mutex);
2578-
if (disk->part0->bd_openers)
2579-
goto out_mutex;
2580-
2581-
/*
2582-
* Check if we have been instructed to close. We will have
2583-
* deferred this request, because the bdev was still open.
2584-
*/
2585-
2586-
mutex_lock(&info->mutex);
2587-
xbdev = info->xbdev;
2588-
2589-
if (xbdev && xbdev->state == XenbusStateClosing) {
2590-
/* pending switch to state closed */
2591-
dev_info(disk_to_dev(disk), "releasing disk\n");
2592-
xlvbd_release_gendisk(info);
2593-
xenbus_frontend_closed(info->xbdev);
2594-
}
2595-
2596-
mutex_unlock(&info->mutex);
2597-
2598-
if (!xbdev) {
2599-
/* sudden device removal */
2600-
dev_info(disk_to_dev(disk), "releasing disk\n");
2601-
xlvbd_release_gendisk(info);
2602-
disk->private_data = NULL;
2603-
free_info(info);
2604-
}
2605-
2606-
out_mutex:
2607-
mutex_unlock(&blkfront_mutex);
2608-
}
2609-
26102440
static const struct block_device_operations xlvbd_block_fops =
26112441
{
26122442
.owner = THIS_MODULE,
2613-
.open = blkif_open,
2614-
.release = blkif_release,
26152443
.getgeo = blkif_getgeo,
26162444
.ioctl = blkif_ioctl,
26172445
.compat_ioctl = blkdev_compat_ptr_ioctl,

0 commit comments

Comments
 (0)