diff options
author | Jens Axboe <axboe@fb.com> | 2014-12-10 15:58:17 -0500 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2014-12-10 15:58:17 -0500 |
commit | d8ead9b763cab553f82a6f16015d3ace5f9c6653 (patch) | |
tree | 76743bcb34cfe103b759cc7f9d4a6dc1f15404c6 /drivers/block | |
parent | 97fe383222cb8a01fb67a8823498ad2edcc20b35 (diff) | |
parent | fdf9b9650366c575650edcaaede3a68efbb24919 (diff) |
Merge branch 'for-jens-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen into for-3.19/drivers
Konrad writes:
These are two fixes for Xen blkfront. They harden how it deals with
broken backends.
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/xen-blkfront.c | 65 |
1 files changed, 39 insertions, 26 deletions
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 5ac312f6e0be..2236c6f31608 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c | |||
@@ -126,7 +126,6 @@ struct blkfront_info | |||
126 | unsigned int persistent_gnts_c; | 126 | unsigned int persistent_gnts_c; |
127 | unsigned long shadow_free; | 127 | unsigned long shadow_free; |
128 | unsigned int feature_flush; | 128 | unsigned int feature_flush; |
129 | unsigned int flush_op; | ||
130 | unsigned int feature_discard:1; | 129 | unsigned int feature_discard:1; |
131 | unsigned int feature_secdiscard:1; | 130 | unsigned int feature_secdiscard:1; |
132 | unsigned int discard_granularity; | 131 | unsigned int discard_granularity; |
@@ -479,7 +478,19 @@ static int blkif_queue_request(struct request *req) | |||
479 | * way. (It's also a FLUSH+FUA, since it is | 478 | * way. (It's also a FLUSH+FUA, since it is |
480 | * guaranteed ordered WRT previous writes.) | 479 | * guaranteed ordered WRT previous writes.) |
481 | */ | 480 | */ |
482 | ring_req->operation = info->flush_op; | 481 | switch (info->feature_flush & |
482 | ((REQ_FLUSH|REQ_FUA))) { | ||
483 | case REQ_FLUSH|REQ_FUA: | ||
484 | ring_req->operation = | ||
485 | BLKIF_OP_WRITE_BARRIER; | ||
486 | break; | ||
487 | case REQ_FLUSH: | ||
488 | ring_req->operation = | ||
489 | BLKIF_OP_FLUSH_DISKCACHE; | ||
490 | break; | ||
491 | default: | ||
492 | ring_req->operation = 0; | ||
493 | } | ||
483 | } | 494 | } |
484 | ring_req->u.rw.nr_segments = nseg; | 495 | ring_req->u.rw.nr_segments = nseg; |
485 | } | 496 | } |
@@ -582,12 +593,14 @@ static inline void flush_requests(struct blkfront_info *info) | |||
582 | notify_remote_via_irq(info->irq); | 593 | notify_remote_via_irq(info->irq); |
583 | } | 594 | } |
584 | 595 | ||
585 | static inline bool blkif_request_flush_valid(struct request *req, | 596 | static inline bool blkif_request_flush_invalid(struct request *req, |
586 | struct blkfront_info *info) | 597 | struct blkfront_info *info) |
587 | { | 598 | { |
588 | return ((req->cmd_type != REQ_TYPE_FS) || | 599 | return ((req->cmd_type != REQ_TYPE_FS) || |
589 | ((req->cmd_flags & (REQ_FLUSH | REQ_FUA)) && | 600 | ((req->cmd_flags & REQ_FLUSH) && |
590 | !info->flush_op)); | 601 | !(info->feature_flush & REQ_FLUSH)) || |
602 | ((req->cmd_flags & REQ_FUA) && | ||
603 | !(info->feature_flush & REQ_FUA))); | ||
591 | } | 604 | } |
592 | 605 | ||
593 | /* | 606 | /* |
@@ -612,8 +625,8 @@ static void do_blkif_request(struct request_queue *rq) | |||
612 | 625 | ||
613 | blk_start_request(req); | 626 | blk_start_request(req); |
614 | 627 | ||
615 | if (blkif_request_flush_valid(req, info)) { | 628 | if (blkif_request_flush_invalid(req, info)) { |
616 | __blk_end_request_all(req, -EIO); | 629 | __blk_end_request_all(req, -EOPNOTSUPP); |
617 | continue; | 630 | continue; |
618 | } | 631 | } |
619 | 632 | ||
@@ -683,20 +696,26 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size, | |||
683 | return 0; | 696 | return 0; |
684 | } | 697 | } |
685 | 698 | ||
699 | static const char *flush_info(unsigned int feature_flush) | ||
700 | { | ||
701 | switch (feature_flush & ((REQ_FLUSH | REQ_FUA))) { | ||
702 | case REQ_FLUSH|REQ_FUA: | ||
703 | return "barrier: enabled;"; | ||
704 | case REQ_FLUSH: | ||
705 | return "flush diskcache: enabled;"; | ||
706 | default: | ||
707 | return "barrier or flush: disabled;"; | ||
708 | } | ||
709 | } | ||
686 | 710 | ||
687 | static void xlvbd_flush(struct blkfront_info *info) | 711 | static void xlvbd_flush(struct blkfront_info *info) |
688 | { | 712 | { |
689 | blk_queue_flush(info->rq, info->feature_flush); | 713 | blk_queue_flush(info->rq, info->feature_flush); |
690 | printk(KERN_INFO "blkfront: %s: %s: %s %s %s %s %s\n", | 714 | pr_info("blkfront: %s: %s %s %s %s %s\n", |
691 | info->gd->disk_name, | 715 | info->gd->disk_name, flush_info(info->feature_flush), |
692 | info->flush_op == BLKIF_OP_WRITE_BARRIER ? | 716 | "persistent grants:", info->feature_persistent ? |
693 | "barrier" : (info->flush_op == BLKIF_OP_FLUSH_DISKCACHE ? | 717 | "enabled;" : "disabled;", "indirect descriptors:", |
694 | "flush diskcache" : "barrier or flush"), | 718 | info->max_indirect_segments ? "enabled;" : "disabled;"); |
695 | info->feature_flush ? "enabled;" : "disabled;", | ||
696 | "persistent grants:", | ||
697 | info->feature_persistent ? "enabled;" : "disabled;", | ||
698 | "indirect descriptors:", | ||
699 | info->max_indirect_segments ? "enabled;" : "disabled;"); | ||
700 | } | 719 | } |
701 | 720 | ||
702 | static int xen_translate_vdev(int vdevice, int *minor, unsigned int *offset) | 721 | static int xen_translate_vdev(int vdevice, int *minor, unsigned int *offset) |
@@ -1188,7 +1207,6 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) | |||
1188 | if (error == -EOPNOTSUPP) | 1207 | if (error == -EOPNOTSUPP) |
1189 | error = 0; | 1208 | error = 0; |
1190 | info->feature_flush = 0; | 1209 | info->feature_flush = 0; |
1191 | info->flush_op = 0; | ||
1192 | xlvbd_flush(info); | 1210 | xlvbd_flush(info); |
1193 | } | 1211 | } |
1194 | /* fall through */ | 1212 | /* fall through */ |
@@ -1808,7 +1826,6 @@ static void blkfront_connect(struct blkfront_info *info) | |||
1808 | physical_sector_size = sector_size; | 1826 | physical_sector_size = sector_size; |
1809 | 1827 | ||
1810 | info->feature_flush = 0; | 1828 | info->feature_flush = 0; |
1811 | info->flush_op = 0; | ||
1812 | 1829 | ||
1813 | err = xenbus_gather(XBT_NIL, info->xbdev->otherend, | 1830 | err = xenbus_gather(XBT_NIL, info->xbdev->otherend, |
1814 | "feature-barrier", "%d", &barrier, | 1831 | "feature-barrier", "%d", &barrier, |
@@ -1821,10 +1838,8 @@ static void blkfront_connect(struct blkfront_info *info) | |||
1821 | * | 1838 | * |
1822 | * If there are barriers, then we use flush. | 1839 | * If there are barriers, then we use flush. |
1823 | */ | 1840 | */ |
1824 | if (!err && barrier) { | 1841 | if (!err && barrier) |
1825 | info->feature_flush = REQ_FLUSH | REQ_FUA; | 1842 | info->feature_flush = REQ_FLUSH | REQ_FUA; |
1826 | info->flush_op = BLKIF_OP_WRITE_BARRIER; | ||
1827 | } | ||
1828 | /* | 1843 | /* |
1829 | * And if there is "feature-flush-cache" use that above | 1844 | * And if there is "feature-flush-cache" use that above |
1830 | * barriers. | 1845 | * barriers. |
@@ -1833,10 +1848,8 @@ static void blkfront_connect(struct blkfront_info *info) | |||
1833 | "feature-flush-cache", "%d", &flush, | 1848 | "feature-flush-cache", "%d", &flush, |
1834 | NULL); | 1849 | NULL); |
1835 | 1850 | ||
1836 | if (!err && flush) { | 1851 | if (!err && flush) |
1837 | info->feature_flush = REQ_FLUSH; | 1852 | info->feature_flush = REQ_FLUSH; |
1838 | info->flush_op = BLKIF_OP_FLUSH_DISKCACHE; | ||
1839 | } | ||
1840 | 1853 | ||
1841 | err = xenbus_gather(XBT_NIL, info->xbdev->otherend, | 1854 | err = xenbus_gather(XBT_NIL, info->xbdev->otherend, |
1842 | "feature-discard", "%d", &discard, | 1855 | "feature-discard", "%d", &discard, |