diff options
Diffstat (limited to 'drivers/block/xen-blkfront.c')
-rw-r--r-- | drivers/block/xen-blkfront.c | 58 |
1 files changed, 46 insertions, 12 deletions
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 60eed4bdd2e4..e4fb3374dcd2 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c | |||
@@ -141,14 +141,36 @@ static int get_id_from_freelist(struct blkfront_info *info) | |||
141 | return free; | 141 | return free; |
142 | } | 142 | } |
143 | 143 | ||
144 | static void add_id_to_freelist(struct blkfront_info *info, | 144 | static int add_id_to_freelist(struct blkfront_info *info, |
145 | unsigned long id) | 145 | unsigned long id) |
146 | { | 146 | { |
147 | if (info->shadow[id].req.u.rw.id != id) | ||
148 | return -EINVAL; | ||
149 | if (info->shadow[id].request == NULL) | ||
150 | return -EINVAL; | ||
147 | info->shadow[id].req.u.rw.id = info->shadow_free; | 151 | info->shadow[id].req.u.rw.id = info->shadow_free; |
148 | info->shadow[id].request = NULL; | 152 | info->shadow[id].request = NULL; |
149 | info->shadow_free = id; | 153 | info->shadow_free = id; |
154 | return 0; | ||
150 | } | 155 | } |
151 | 156 | ||
157 | static const char *op_name(int op) | ||
158 | { | ||
159 | static const char *const names[] = { | ||
160 | [BLKIF_OP_READ] = "read", | ||
161 | [BLKIF_OP_WRITE] = "write", | ||
162 | [BLKIF_OP_WRITE_BARRIER] = "barrier", | ||
163 | [BLKIF_OP_FLUSH_DISKCACHE] = "flush", | ||
164 | [BLKIF_OP_DISCARD] = "discard" }; | ||
165 | |||
166 | if (op < 0 || op >= ARRAY_SIZE(names)) | ||
167 | return "unknown"; | ||
168 | |||
169 | if (!names[op]) | ||
170 | return "reserved"; | ||
171 | |||
172 | return names[op]; | ||
173 | } | ||
152 | static int xlbd_reserve_minors(unsigned int minor, unsigned int nr) | 174 | static int xlbd_reserve_minors(unsigned int minor, unsigned int nr) |
153 | { | 175 | { |
154 | unsigned int end = minor + nr; | 176 | unsigned int end = minor + nr; |
@@ -746,20 +768,36 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) | |||
746 | 768 | ||
747 | bret = RING_GET_RESPONSE(&info->ring, i); | 769 | bret = RING_GET_RESPONSE(&info->ring, i); |
748 | id = bret->id; | 770 | id = bret->id; |
771 | /* | ||
772 | * The backend has messed up and given us an id that we would | ||
773 | * never have given to it (we stamp it up to BLK_RING_SIZE - | ||
774 | * look in get_id_from_freelist. | ||
775 | */ | ||
776 | if (id >= BLK_RING_SIZE) { | ||
777 | WARN(1, "%s: response to %s has incorrect id (%ld)\n", | ||
778 | info->gd->disk_name, op_name(bret->operation), id); | ||
779 | /* We can't safely get the 'struct request' as | ||
780 | * the id is busted. */ | ||
781 | continue; | ||
782 | } | ||
749 | req = info->shadow[id].request; | 783 | req = info->shadow[id].request; |
750 | 784 | ||
751 | if (bret->operation != BLKIF_OP_DISCARD) | 785 | if (bret->operation != BLKIF_OP_DISCARD) |
752 | blkif_completion(&info->shadow[id]); | 786 | blkif_completion(&info->shadow[id]); |
753 | 787 | ||
754 | add_id_to_freelist(info, id); | 788 | if (add_id_to_freelist(info, id)) { |
789 | WARN(1, "%s: response to %s (id %ld) couldn't be recycled!\n", | ||
790 | info->gd->disk_name, op_name(bret->operation), id); | ||
791 | continue; | ||
792 | } | ||
755 | 793 | ||
756 | error = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO; | 794 | error = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO; |
757 | switch (bret->operation) { | 795 | switch (bret->operation) { |
758 | case BLKIF_OP_DISCARD: | 796 | case BLKIF_OP_DISCARD: |
759 | if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) { | 797 | if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) { |
760 | struct request_queue *rq = info->rq; | 798 | struct request_queue *rq = info->rq; |
761 | printk(KERN_WARNING "blkfront: %s: discard op failed\n", | 799 | printk(KERN_WARNING "blkfront: %s: %s op failed\n", |
762 | info->gd->disk_name); | 800 | info->gd->disk_name, op_name(bret->operation)); |
763 | error = -EOPNOTSUPP; | 801 | error = -EOPNOTSUPP; |
764 | info->feature_discard = 0; | 802 | info->feature_discard = 0; |
765 | info->feature_secdiscard = 0; | 803 | info->feature_secdiscard = 0; |
@@ -771,18 +809,14 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) | |||
771 | case BLKIF_OP_FLUSH_DISKCACHE: | 809 | case BLKIF_OP_FLUSH_DISKCACHE: |
772 | case BLKIF_OP_WRITE_BARRIER: | 810 | case BLKIF_OP_WRITE_BARRIER: |
773 | if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) { | 811 | if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) { |
774 | printk(KERN_WARNING "blkfront: %s: write %s op failed\n", | 812 | printk(KERN_WARNING "blkfront: %s: %s op failed\n", |
775 | info->flush_op == BLKIF_OP_WRITE_BARRIER ? | 813 | info->gd->disk_name, op_name(bret->operation)); |
776 | "barrier" : "flush disk cache", | ||
777 | info->gd->disk_name); | ||
778 | error = -EOPNOTSUPP; | 814 | error = -EOPNOTSUPP; |
779 | } | 815 | } |
780 | if (unlikely(bret->status == BLKIF_RSP_ERROR && | 816 | if (unlikely(bret->status == BLKIF_RSP_ERROR && |
781 | info->shadow[id].req.u.rw.nr_segments == 0)) { | 817 | info->shadow[id].req.u.rw.nr_segments == 0)) { |
782 | printk(KERN_WARNING "blkfront: %s: empty write %s op failed\n", | 818 | printk(KERN_WARNING "blkfront: %s: empty %s op failed\n", |
783 | info->flush_op == BLKIF_OP_WRITE_BARRIER ? | 819 | info->gd->disk_name, op_name(bret->operation)); |
784 | "barrier" : "flush disk cache", | ||
785 | info->gd->disk_name); | ||
786 | error = -EOPNOTSUPP; | 820 | error = -EOPNOTSUPP; |
787 | } | 821 | } |
788 | if (unlikely(error)) { | 822 | if (unlikely(error)) { |