aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorMaurizio Lombardi <mlombard@redhat.com>2014-12-10 17:16:53 -0500
committerJens Axboe <axboe@fb.com>2014-12-11 11:11:52 -0500
commitfcbf6a087a7e4d3f03d28333678a1010810a53c3 (patch)
tree8009f078e8f8f6b96581216923b39b9e0e9bdc2c /block
parent06a41a99d13d8e919e9a00a4849e6b85ae492592 (diff)
bio: modify __bio_add_page() to accept pages that don't start a new segment
The original behaviour is to refuse to add a new page if the maximum number of segments has been reached, regardless of the fact the page we are going to add can be merged into the last segment or not. Unfortunately, when the system runs under heavy memory fragmentation conditions, a driver may try to add multiple pages to the last segment. The original code won't accept them and EBUSY will be reported to userspace. This patch modifies the function so it refuses to add a page only in case the latter starts a new segment and the maximum number of segments has already been reached. The bug can be easily reproduced with the st driver: 1) set CONFIG_SCSI_MPT2SAS_MAX_SGE or CONFIG_SCSI_MPT3SAS_MAX_SGE to 16 2) modprobe st buffer_kbs=1024 3) #dd if=/dev/zero of=/dev/st0 bs=1M count=10 dd: error writing `/dev/st0': Device or resource busy Signed-off-by: Maurizio Lombardi <mlombard@redhat.com> Signed-off-by: Ming Lei <ming.lei@canonical.com> Cc: Jet Chen <jet.chen@intel.com> Cc: Tomas Henzl <thenzl@redhat.com> Cc: Jens Axboe <axboe@kernel.dk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'block')
-rw-r--r--block/bio.c54
1 files changed, 30 insertions, 24 deletions
diff --git a/block/bio.c b/block/bio.c
index 3d4a072375ef..471d7382c7d1 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -748,6 +748,7 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
748 } 748 }
749 } 749 }
750 750
751 bio->bi_iter.bi_size += len;
751 goto done; 752 goto done;
752 } 753 }
753 754
@@ -764,29 +765,32 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
764 return 0; 765 return 0;
765 766
766 /* 767 /*
767 * we might lose a segment or two here, but rather that than 768 * setup the new entry, we might clear it again later if we
768 * make this too complex. 769 * cannot add the page
770 */
771 bvec = &bio->bi_io_vec[bio->bi_vcnt];
772 bvec->bv_page = page;
773 bvec->bv_len = len;
774 bvec->bv_offset = offset;
775 bio->bi_vcnt++;
776 bio->bi_phys_segments++;
777 bio->bi_iter.bi_size += len;
778
779 /*
780 * Perform a recount if the number of segments is greater
781 * than queue_max_segments(q).
769 */ 782 */
770 783
771 while (bio->bi_phys_segments >= queue_max_segments(q)) { 784 while (bio->bi_phys_segments > queue_max_segments(q)) {
772 785
773 if (retried_segments) 786 if (retried_segments)
774 return 0; 787 goto failed;
775 788
776 retried_segments = 1; 789 retried_segments = 1;
777 blk_recount_segments(q, bio); 790 blk_recount_segments(q, bio);
778 } 791 }
779 792
780 /* 793 /*
781 * setup the new entry, we might clear it again later if we
782 * cannot add the page
783 */
784 bvec = &bio->bi_io_vec[bio->bi_vcnt];
785 bvec->bv_page = page;
786 bvec->bv_len = len;
787 bvec->bv_offset = offset;
788
789 /*
790 * if queue has other restrictions (eg varying max sector size 794 * if queue has other restrictions (eg varying max sector size
791 * depending on offset), it can specify a merge_bvec_fn in the 795 * depending on offset), it can specify a merge_bvec_fn in the
792 * queue to get further control 796 * queue to get further control
@@ -795,7 +799,7 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
795 struct bvec_merge_data bvm = { 799 struct bvec_merge_data bvm = {
796 .bi_bdev = bio->bi_bdev, 800 .bi_bdev = bio->bi_bdev,
797 .bi_sector = bio->bi_iter.bi_sector, 801 .bi_sector = bio->bi_iter.bi_sector,
798 .bi_size = bio->bi_iter.bi_size, 802 .bi_size = bio->bi_iter.bi_size - len,
799 .bi_rw = bio->bi_rw, 803 .bi_rw = bio->bi_rw,
800 }; 804 };
801 805
@@ -803,23 +807,25 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
803 * merge_bvec_fn() returns number of bytes it can accept 807 * merge_bvec_fn() returns number of bytes it can accept
804 * at this offset 808 * at this offset
805 */ 809 */
806 if (q->merge_bvec_fn(q, &bvm, bvec) < bvec->bv_len) { 810 if (q->merge_bvec_fn(q, &bvm, bvec) < bvec->bv_len)
807 bvec->bv_page = NULL; 811 goto failed;
808 bvec->bv_len = 0;
809 bvec->bv_offset = 0;
810 return 0;
811 }
812 } 812 }
813 813
814 /* If we may be able to merge these biovecs, force a recount */ 814 /* If we may be able to merge these biovecs, force a recount */
815 if (bio->bi_vcnt && (BIOVEC_PHYS_MERGEABLE(bvec-1, bvec))) 815 if (bio->bi_vcnt > 1 && (BIOVEC_PHYS_MERGEABLE(bvec-1, bvec)))
816 bio->bi_flags &= ~(1 << BIO_SEG_VALID); 816 bio->bi_flags &= ~(1 << BIO_SEG_VALID);
817 817
818 bio->bi_vcnt++;
819 bio->bi_phys_segments++;
820 done: 818 done:
821 bio->bi_iter.bi_size += len;
822 return len; 819 return len;
820
821 failed:
822 bvec->bv_page = NULL;
823 bvec->bv_len = 0;
824 bvec->bv_offset = 0;
825 bio->bi_vcnt--;
826 bio->bi_iter.bi_size -= len;
827 blk_recount_segments(q, bio);
828 return 0;
823} 829}
824 830
825/** 831/**