diff options
| -rw-r--r-- | drivers/block/xen-blkfront.c | 94 |
1 files changed, 90 insertions, 4 deletions
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 8986adab9bf5..a2a395f85a41 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c | |||
| @@ -46,6 +46,7 @@ | |||
| 46 | #include <linux/scatterlist.h> | 46 | #include <linux/scatterlist.h> |
| 47 | #include <linux/bitmap.h> | 47 | #include <linux/bitmap.h> |
| 48 | #include <linux/list.h> | 48 | #include <linux/list.h> |
| 49 | #include <linux/workqueue.h> | ||
| 49 | 50 | ||
| 50 | #include <xen/xen.h> | 51 | #include <xen/xen.h> |
| 51 | #include <xen/xenbus.h> | 52 | #include <xen/xenbus.h> |
| @@ -121,6 +122,8 @@ static inline struct blkif_req *blkif_req(struct request *rq) | |||
| 121 | 122 | ||
| 122 | static DEFINE_MUTEX(blkfront_mutex); | 123 | static DEFINE_MUTEX(blkfront_mutex); |
| 123 | static const struct block_device_operations xlvbd_block_fops; | 124 | static const struct block_device_operations xlvbd_block_fops; |
| 125 | static struct delayed_work blkfront_work; | ||
| 126 | static LIST_HEAD(info_list); | ||
| 124 | 127 | ||
| 125 | /* | 128 | /* |
| 126 | * Maximum number of segments in indirect requests, the actual value used by | 129 | * Maximum number of segments in indirect requests, the actual value used by |
| @@ -216,6 +219,7 @@ struct blkfront_info | |||
| 216 | /* Save uncomplete reqs and bios for migration. */ | 219 | /* Save uncomplete reqs and bios for migration. */ |
| 217 | struct list_head requests; | 220 | struct list_head requests; |
| 218 | struct bio_list bio_list; | 221 | struct bio_list bio_list; |
| 222 | struct list_head info_list; | ||
| 219 | }; | 223 | }; |
| 220 | 224 | ||
| 221 | static unsigned int nr_minors; | 225 | static unsigned int nr_minors; |
| @@ -1759,6 +1763,12 @@ abort_transaction: | |||
| 1759 | return err; | 1763 | return err; |
| 1760 | } | 1764 | } |
| 1761 | 1765 | ||
| 1766 | static void free_info(struct blkfront_info *info) | ||
| 1767 | { | ||
| 1768 | list_del(&info->info_list); | ||
| 1769 | kfree(info); | ||
| 1770 | } | ||
| 1771 | |||
| 1762 | /* Common code used when first setting up, and when resuming. */ | 1772 | /* Common code used when first setting up, and when resuming. */ |
| 1763 | static int talk_to_blkback(struct xenbus_device *dev, | 1773 | static int talk_to_blkback(struct xenbus_device *dev, |
| 1764 | struct blkfront_info *info) | 1774 | struct blkfront_info *info) |
| @@ -1880,7 +1890,10 @@ again: | |||
| 1880 | destroy_blkring: | 1890 | destroy_blkring: |
| 1881 | blkif_free(info, 0); | 1891 | blkif_free(info, 0); |
| 1882 | 1892 | ||
| 1883 | kfree(info); | 1893 | mutex_lock(&blkfront_mutex); |
| 1894 | free_info(info); | ||
| 1895 | mutex_unlock(&blkfront_mutex); | ||
| 1896 | |||
| 1884 | dev_set_drvdata(&dev->dev, NULL); | 1897 | dev_set_drvdata(&dev->dev, NULL); |
| 1885 | 1898 | ||
| 1886 | return err; | 1899 | return err; |
| @@ -1991,6 +2004,10 @@ static int blkfront_probe(struct xenbus_device *dev, | |||
| 1991 | info->handle = simple_strtoul(strrchr(dev->nodename, '/')+1, NULL, 0); | 2004 | info->handle = simple_strtoul(strrchr(dev->nodename, '/')+1, NULL, 0); |
| 1992 | dev_set_drvdata(&dev->dev, info); | 2005 | dev_set_drvdata(&dev->dev, info); |
| 1993 | 2006 | ||
| 2007 | mutex_lock(&blkfront_mutex); | ||
| 2008 | list_add(&info->info_list, &info_list); | ||
| 2009 | mutex_unlock(&blkfront_mutex); | ||
| 2010 | |||
| 1994 | return 0; | 2011 | return 0; |
| 1995 | } | 2012 | } |
| 1996 | 2013 | ||
| @@ -2301,6 +2318,12 @@ static void blkfront_gather_backend_features(struct blkfront_info *info) | |||
| 2301 | if (indirect_segments <= BLKIF_MAX_SEGMENTS_PER_REQUEST) | 2318 | if (indirect_segments <= BLKIF_MAX_SEGMENTS_PER_REQUEST) |
| 2302 | indirect_segments = 0; | 2319 | indirect_segments = 0; |
| 2303 | info->max_indirect_segments = indirect_segments; | 2320 | info->max_indirect_segments = indirect_segments; |
| 2321 | |||
| 2322 | if (info->feature_persistent) { | ||
| 2323 | mutex_lock(&blkfront_mutex); | ||
| 2324 | schedule_delayed_work(&blkfront_work, HZ * 10); | ||
| 2325 | mutex_unlock(&blkfront_mutex); | ||
| 2326 | } | ||
| 2304 | } | 2327 | } |
| 2305 | 2328 | ||
| 2306 | /* | 2329 | /* |
| @@ -2482,7 +2505,9 @@ static int blkfront_remove(struct xenbus_device *xbdev) | |||
| 2482 | mutex_unlock(&info->mutex); | 2505 | mutex_unlock(&info->mutex); |
| 2483 | 2506 | ||
| 2484 | if (!bdev) { | 2507 | if (!bdev) { |
| 2485 | kfree(info); | 2508 | mutex_lock(&blkfront_mutex); |
| 2509 | free_info(info); | ||
| 2510 | mutex_unlock(&blkfront_mutex); | ||
| 2486 | return 0; | 2511 | return 0; |
| 2487 | } | 2512 | } |
| 2488 | 2513 | ||
| @@ -2502,7 +2527,9 @@ static int blkfront_remove(struct xenbus_device *xbdev) | |||
| 2502 | if (info && !bdev->bd_openers) { | 2527 | if (info && !bdev->bd_openers) { |
| 2503 | xlvbd_release_gendisk(info); | 2528 | xlvbd_release_gendisk(info); |
| 2504 | disk->private_data = NULL; | 2529 | disk->private_data = NULL; |
| 2505 | kfree(info); | 2530 | mutex_lock(&blkfront_mutex); |
| 2531 | free_info(info); | ||
| 2532 | mutex_unlock(&blkfront_mutex); | ||
| 2506 | } | 2533 | } |
| 2507 | 2534 | ||
| 2508 | mutex_unlock(&bdev->bd_mutex); | 2535 | mutex_unlock(&bdev->bd_mutex); |
| @@ -2585,7 +2612,7 @@ static void blkif_release(struct gendisk *disk, fmode_t mode) | |||
| 2585 | dev_info(disk_to_dev(bdev->bd_disk), "releasing disk\n"); | 2612 | dev_info(disk_to_dev(bdev->bd_disk), "releasing disk\n"); |
| 2586 | xlvbd_release_gendisk(info); | 2613 | xlvbd_release_gendisk(info); |
| 2587 | disk->private_data = NULL; | 2614 | disk->private_data = NULL; |
| 2588 | kfree(info); | 2615 | free_info(info); |
| 2589 | } | 2616 | } |
| 2590 | 2617 | ||
| 2591 | out: | 2618 | out: |
| @@ -2618,6 +2645,61 @@ static struct xenbus_driver blkfront_driver = { | |||
| 2618 | .is_ready = blkfront_is_ready, | 2645 | .is_ready = blkfront_is_ready, |
| 2619 | }; | 2646 | }; |
| 2620 | 2647 | ||
| 2648 | static void purge_persistent_grants(struct blkfront_info *info) | ||
| 2649 | { | ||
| 2650 | unsigned int i; | ||
| 2651 | unsigned long flags; | ||
| 2652 | |||
| 2653 | for (i = 0; i < info->nr_rings; i++) { | ||
| 2654 | struct blkfront_ring_info *rinfo = &info->rinfo[i]; | ||
| 2655 | struct grant *gnt_list_entry, *tmp; | ||
| 2656 | |||
| 2657 | spin_lock_irqsave(&rinfo->ring_lock, flags); | ||
| 2658 | |||
| 2659 | if (rinfo->persistent_gnts_c == 0) { | ||
| 2660 | spin_unlock_irqrestore(&rinfo->ring_lock, flags); | ||
| 2661 | continue; | ||
| 2662 | } | ||
| 2663 | |||
| 2664 | list_for_each_entry_safe(gnt_list_entry, tmp, &rinfo->grants, | ||
| 2665 | node) { | ||
| 2666 | if (gnt_list_entry->gref == GRANT_INVALID_REF || | ||
| 2667 | gnttab_query_foreign_access(gnt_list_entry->gref)) | ||
| 2668 | continue; | ||
| 2669 | |||
| 2670 | list_del(&gnt_list_entry->node); | ||
| 2671 | gnttab_end_foreign_access(gnt_list_entry->gref, 0, 0UL); | ||
| 2672 | rinfo->persistent_gnts_c--; | ||
| 2673 | __free_page(gnt_list_entry->page); | ||
| 2674 | kfree(gnt_list_entry); | ||
| 2675 | } | ||
| 2676 | |||
| 2677 | spin_unlock_irqrestore(&rinfo->ring_lock, flags); | ||
| 2678 | } | ||
| 2679 | } | ||
| 2680 | |||
| 2681 | static void blkfront_delay_work(struct work_struct *work) | ||
| 2682 | { | ||
| 2683 | struct blkfront_info *info; | ||
| 2684 | bool need_schedule_work = false; | ||
| 2685 | |||
| 2686 | mutex_lock(&blkfront_mutex); | ||
| 2687 | |||
| 2688 | list_for_each_entry(info, &info_list, info_list) { | ||
| 2689 | if (info->feature_persistent) { | ||
| 2690 | need_schedule_work = true; | ||
| 2691 | mutex_lock(&info->mutex); | ||
| 2692 | purge_persistent_grants(info); | ||
| 2693 | mutex_unlock(&info->mutex); | ||
| 2694 | } | ||
| 2695 | } | ||
| 2696 | |||
| 2697 | if (need_schedule_work) | ||
| 2698 | schedule_delayed_work(&blkfront_work, HZ * 10); | ||
| 2699 | |||
| 2700 | mutex_unlock(&blkfront_mutex); | ||
| 2701 | } | ||
| 2702 | |||
| 2621 | static int __init xlblk_init(void) | 2703 | static int __init xlblk_init(void) |
| 2622 | { | 2704 | { |
| 2623 | int ret; | 2705 | int ret; |
| @@ -2650,6 +2732,8 @@ static int __init xlblk_init(void) | |||
| 2650 | return -ENODEV; | 2732 | return -ENODEV; |
| 2651 | } | 2733 | } |
| 2652 | 2734 | ||
| 2735 | INIT_DELAYED_WORK(&blkfront_work, blkfront_delay_work); | ||
| 2736 | |||
| 2653 | ret = xenbus_register_frontend(&blkfront_driver); | 2737 | ret = xenbus_register_frontend(&blkfront_driver); |
| 2654 | if (ret) { | 2738 | if (ret) { |
| 2655 | unregister_blkdev(XENVBD_MAJOR, DEV_NAME); | 2739 | unregister_blkdev(XENVBD_MAJOR, DEV_NAME); |
| @@ -2663,6 +2747,8 @@ module_init(xlblk_init); | |||
| 2663 | 2747 | ||
| 2664 | static void __exit xlblk_exit(void) | 2748 | static void __exit xlblk_exit(void) |
| 2665 | { | 2749 | { |
| 2750 | cancel_delayed_work_sync(&blkfront_work); | ||
| 2751 | |||
| 2666 | xenbus_unregister_driver(&blkfront_driver); | 2752 | xenbus_unregister_driver(&blkfront_driver); |
| 2667 | unregister_blkdev(XENVBD_MAJOR, DEV_NAME); | 2753 | unregister_blkdev(XENVBD_MAJOR, DEV_NAME); |
| 2668 | kfree(minors); | 2754 | kfree(minors); |
