block: add a blk_alloc_discard_bio helper
[linux-2.6-block.git] / block / blk-lib.c
index 6e54ef140bab126273a6da4d5d3c5252a7a94867..442da9dad04213d8014164784204d552fab04feb 100644 (file)
@@ -35,31 +35,39 @@ static sector_t bio_discard_limit(struct block_device *bdev, sector_t sector)
        return round_down(UINT_MAX, discard_granularity) >> SECTOR_SHIFT;
 }
 
-int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
-               sector_t nr_sects, gfp_t gfp_mask, struct bio **biop)
+struct bio *blk_alloc_discard_bio(struct block_device *bdev,
+               sector_t *sector, sector_t *nr_sects, gfp_t gfp_mask)
 {
-       struct bio *bio = *biop;
+       sector_t bio_sects = min(*nr_sects, bio_discard_limit(bdev, *sector));
+       struct bio *bio;
 
-       while (nr_sects) {
-               sector_t req_sects =
-                       min(nr_sects, bio_discard_limit(bdev, sector));
+       if (!bio_sects)
+               return NULL;
 
-               bio = blk_next_bio(bio, bdev, 0, REQ_OP_DISCARD, gfp_mask);
-               bio->bi_iter.bi_sector = sector;
-               bio->bi_iter.bi_size = req_sects << 9;
-               sector += req_sects;
-               nr_sects -= req_sects;
-
-               /*
-                * We can loop for a long time in here, if someone does
-                * full device discards (like mkfs). Be nice and allow
-                * us to schedule out to avoid softlocking if preempt
-                * is disabled.
-                */
-               cond_resched();
-       }
+       bio = bio_alloc(bdev, 0, REQ_OP_DISCARD, gfp_mask);
+       if (!bio)
+               return NULL;
+       bio->bi_iter.bi_sector = *sector;
+       bio->bi_iter.bi_size = bio_sects << SECTOR_SHIFT;
+       *sector += bio_sects;
+       *nr_sects -= bio_sects;
+       /*
+        * We can loop for a long time in here if someone does full device
+        * discards (like mkfs).  Be nice and allow us to schedule out to avoid
+        * softlocking if preempt is disabled.
+        */
+       cond_resched();
+       return bio;
+}
 
-       *biop = bio;
+int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
+               sector_t nr_sects, gfp_t gfp_mask, struct bio **biop)
+{
+       struct bio *bio;
+
+       while ((bio = blk_alloc_discard_bio(bdev, &sector, &nr_sects,
+                       gfp_mask)))
+               *biop = bio_chain_and_submit(*biop, bio);
        return 0;
 }
 EXPORT_SYMBOL(__blkdev_issue_discard);