xref: /linux/block/blk-lib.c (revision 5dba3089ed03f84b84c6c739df8330112f04a15d)
1f31e7e40SDmitry Monakhov /*
2f31e7e40SDmitry Monakhov  * Functions related to generic helpers functions
3f31e7e40SDmitry Monakhov  */
4f31e7e40SDmitry Monakhov #include <linux/kernel.h>
5f31e7e40SDmitry Monakhov #include <linux/module.h>
6f31e7e40SDmitry Monakhov #include <linux/bio.h>
7f31e7e40SDmitry Monakhov #include <linux/blkdev.h>
8f31e7e40SDmitry Monakhov #include <linux/scatterlist.h>
9f31e7e40SDmitry Monakhov 
10f31e7e40SDmitry Monakhov #include "blk.h"
11f31e7e40SDmitry Monakhov 
12*5dba3089SLukas Czerner struct bio_batch {
13*5dba3089SLukas Czerner 	atomic_t		done;
14*5dba3089SLukas Czerner 	unsigned long		flags;
15*5dba3089SLukas Czerner 	struct completion	*wait;
16*5dba3089SLukas Czerner };
17*5dba3089SLukas Czerner 
18*5dba3089SLukas Czerner static void bio_batch_end_io(struct bio *bio, int err)
19f31e7e40SDmitry Monakhov {
20*5dba3089SLukas Czerner 	struct bio_batch *bb = bio->bi_private;
21*5dba3089SLukas Czerner 
22f31e7e40SDmitry Monakhov 	if (err) {
23f31e7e40SDmitry Monakhov 		if (err == -EOPNOTSUPP)
24*5dba3089SLukas Czerner 			set_bit(BIO_EOPNOTSUPP, &bb->flags);
25*5dba3089SLukas Czerner 		clear_bit(BIO_UPTODATE, &bb->flags);
26f31e7e40SDmitry Monakhov 	}
27*5dba3089SLukas Czerner 	if (atomic_dec_and_test(&bb->done))
28*5dba3089SLukas Czerner 		complete(bb->wait);
29f31e7e40SDmitry Monakhov 	bio_put(bio);
30f31e7e40SDmitry Monakhov }
31f31e7e40SDmitry Monakhov 
32f31e7e40SDmitry Monakhov /**
33f31e7e40SDmitry Monakhov  * blkdev_issue_discard - queue a discard
34f31e7e40SDmitry Monakhov  * @bdev:	blockdev to issue discard for
35f31e7e40SDmitry Monakhov  * @sector:	start sector
36f31e7e40SDmitry Monakhov  * @nr_sects:	number of sectors to discard
37f31e7e40SDmitry Monakhov  * @gfp_mask:	memory allocation flags (for bio_alloc)
38f31e7e40SDmitry Monakhov  * @flags:	BLKDEV_IFL_* flags to control behaviour
39f31e7e40SDmitry Monakhov  *
40f31e7e40SDmitry Monakhov  * Description:
41f31e7e40SDmitry Monakhov  *    Issue a discard request for the sectors in question.
42f31e7e40SDmitry Monakhov  */
43f31e7e40SDmitry Monakhov int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
44f31e7e40SDmitry Monakhov 		sector_t nr_sects, gfp_t gfp_mask, unsigned long flags)
45f31e7e40SDmitry Monakhov {
46f31e7e40SDmitry Monakhov 	DECLARE_COMPLETION_ONSTACK(wait);
47f31e7e40SDmitry Monakhov 	struct request_queue *q = bdev_get_queue(bdev);
488c555367SChristoph Hellwig 	int type = REQ_WRITE | REQ_DISCARD;
4910d1f9e2SJens Axboe 	unsigned int max_discard_sectors;
50*5dba3089SLukas Czerner 	struct bio_batch bb;
51f31e7e40SDmitry Monakhov 	struct bio *bio;
52f31e7e40SDmitry Monakhov 	int ret = 0;
53f31e7e40SDmitry Monakhov 
54f31e7e40SDmitry Monakhov 	if (!q)
55f31e7e40SDmitry Monakhov 		return -ENXIO;
56f31e7e40SDmitry Monakhov 
57f31e7e40SDmitry Monakhov 	if (!blk_queue_discard(q))
58f31e7e40SDmitry Monakhov 		return -EOPNOTSUPP;
59f31e7e40SDmitry Monakhov 
6010d1f9e2SJens Axboe 	/*
6110d1f9e2SJens Axboe 	 * Ensure that max_discard_sectors is of the proper
6210d1f9e2SJens Axboe 	 * granularity
6310d1f9e2SJens Axboe 	 */
6410d1f9e2SJens Axboe 	max_discard_sectors = min(q->limits.max_discard_sectors, UINT_MAX >> 9);
6510d1f9e2SJens Axboe 	if (q->limits.discard_granularity) {
6610d1f9e2SJens Axboe 		unsigned int disc_sects = q->limits.discard_granularity >> 9;
67f31e7e40SDmitry Monakhov 
6810d1f9e2SJens Axboe 		max_discard_sectors &= ~(disc_sects - 1);
6910d1f9e2SJens Axboe 	}
7010d1f9e2SJens Axboe 
71dd3932edSChristoph Hellwig 	if (flags & BLKDEV_DISCARD_SECURE) {
728d57a98cSAdrian Hunter 		if (!blk_queue_secdiscard(q))
738d57a98cSAdrian Hunter 			return -EOPNOTSUPP;
748c555367SChristoph Hellwig 		type |= REQ_SECURE;
758d57a98cSAdrian Hunter 	}
768d57a98cSAdrian Hunter 
77*5dba3089SLukas Czerner 	atomic_set(&bb.done, 1);
78*5dba3089SLukas Czerner 	bb.flags = 1 << BIO_UPTODATE;
79*5dba3089SLukas Czerner 	bb.wait = &wait;
80*5dba3089SLukas Czerner 
81*5dba3089SLukas Czerner 	while (nr_sects) {
82f31e7e40SDmitry Monakhov 		bio = bio_alloc(gfp_mask, 1);
8366ac0280SChristoph Hellwig 		if (!bio) {
8466ac0280SChristoph Hellwig 			ret = -ENOMEM;
8566ac0280SChristoph Hellwig 			break;
8666ac0280SChristoph Hellwig 		}
8766ac0280SChristoph Hellwig 
88f31e7e40SDmitry Monakhov 		bio->bi_sector = sector;
89*5dba3089SLukas Czerner 		bio->bi_end_io = bio_batch_end_io;
90f31e7e40SDmitry Monakhov 		bio->bi_bdev = bdev;
91*5dba3089SLukas Czerner 		bio->bi_private = &bb;
92f31e7e40SDmitry Monakhov 
93f31e7e40SDmitry Monakhov 		if (nr_sects > max_discard_sectors) {
94f31e7e40SDmitry Monakhov 			bio->bi_size = max_discard_sectors << 9;
95f31e7e40SDmitry Monakhov 			nr_sects -= max_discard_sectors;
96f31e7e40SDmitry Monakhov 			sector += max_discard_sectors;
97f31e7e40SDmitry Monakhov 		} else {
98f31e7e40SDmitry Monakhov 			bio->bi_size = nr_sects << 9;
99f31e7e40SDmitry Monakhov 			nr_sects = 0;
100f31e7e40SDmitry Monakhov 		}
101f31e7e40SDmitry Monakhov 
102*5dba3089SLukas Czerner 		atomic_inc(&bb.done);
103f31e7e40SDmitry Monakhov 		submit_bio(type, bio);
104*5dba3089SLukas Czerner 	}
105f31e7e40SDmitry Monakhov 
106*5dba3089SLukas Czerner 	/* Wait for bios in-flight */
107*5dba3089SLukas Czerner 	if (!atomic_dec_and_test(&bb.done))
108f31e7e40SDmitry Monakhov 		wait_for_completion(&wait);
109f31e7e40SDmitry Monakhov 
110*5dba3089SLukas Czerner 	if (test_bit(BIO_EOPNOTSUPP, &bb.flags))
111f31e7e40SDmitry Monakhov 		ret = -EOPNOTSUPP;
112*5dba3089SLukas Czerner 	else if (!test_bit(BIO_UPTODATE, &bb.flags))
113f31e7e40SDmitry Monakhov 		ret = -EIO;
11466ac0280SChristoph Hellwig 
115f31e7e40SDmitry Monakhov 	return ret;
116f31e7e40SDmitry Monakhov }
117f31e7e40SDmitry Monakhov EXPORT_SYMBOL(blkdev_issue_discard);
1183f14d792SDmitry Monakhov 
1193f14d792SDmitry Monakhov /**
120291d24f6SBen Hutchings  * blkdev_issue_zeroout - generate number of zero filed write bios
1213f14d792SDmitry Monakhov  * @bdev:	blockdev to issue
1223f14d792SDmitry Monakhov  * @sector:	start sector
1233f14d792SDmitry Monakhov  * @nr_sects:	number of sectors to write
1243f14d792SDmitry Monakhov  * @gfp_mask:	memory allocation flags (for bio_alloc)
1253f14d792SDmitry Monakhov  *
1263f14d792SDmitry Monakhov  * Description:
1273f14d792SDmitry Monakhov  *  Generate and issue number of bios with zerofiled pages.
1283f14d792SDmitry Monakhov  */
1293f14d792SDmitry Monakhov 
1303f14d792SDmitry Monakhov int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
131dd3932edSChristoph Hellwig 			sector_t nr_sects, gfp_t gfp_mask)
1323f14d792SDmitry Monakhov {
13318edc8eaSDmitry Monakhov 	int ret;
1343f14d792SDmitry Monakhov 	struct bio *bio;
1353f14d792SDmitry Monakhov 	struct bio_batch bb;
1360aeea189SLukas Czerner 	unsigned int sz;
1373f14d792SDmitry Monakhov 	DECLARE_COMPLETION_ONSTACK(wait);
1383f14d792SDmitry Monakhov 
1390aeea189SLukas Czerner 	atomic_set(&bb.done, 1);
1403f14d792SDmitry Monakhov 	bb.flags = 1 << BIO_UPTODATE;
1413f14d792SDmitry Monakhov 	bb.wait = &wait;
1423f14d792SDmitry Monakhov 
1433f14d792SDmitry Monakhov submit:
14418edc8eaSDmitry Monakhov 	ret = 0;
1453f14d792SDmitry Monakhov 	while (nr_sects != 0) {
1463f14d792SDmitry Monakhov 		bio = bio_alloc(gfp_mask,
1473f14d792SDmitry Monakhov 				min(nr_sects, (sector_t)BIO_MAX_PAGES));
14818edc8eaSDmitry Monakhov 		if (!bio) {
14918edc8eaSDmitry Monakhov 			ret = -ENOMEM;
1503f14d792SDmitry Monakhov 			break;
15118edc8eaSDmitry Monakhov 		}
1523f14d792SDmitry Monakhov 
1533f14d792SDmitry Monakhov 		bio->bi_sector = sector;
1543f14d792SDmitry Monakhov 		bio->bi_bdev   = bdev;
1553f14d792SDmitry Monakhov 		bio->bi_end_io = bio_batch_end_io;
1563f14d792SDmitry Monakhov 		bio->bi_private = &bb;
1573f14d792SDmitry Monakhov 
1583f14d792SDmitry Monakhov 		while (nr_sects != 0) {
1590341aafbSJens Axboe 			sz = min((sector_t) PAGE_SIZE >> 9 , nr_sects);
1603f14d792SDmitry Monakhov 			if (sz == 0)
1613f14d792SDmitry Monakhov 				/* bio has maximum size possible */
1623f14d792SDmitry Monakhov 				break;
1633f14d792SDmitry Monakhov 			ret = bio_add_page(bio, ZERO_PAGE(0), sz << 9, 0);
1643f14d792SDmitry Monakhov 			nr_sects -= ret >> 9;
1653f14d792SDmitry Monakhov 			sector += ret >> 9;
1663f14d792SDmitry Monakhov 			if (ret < (sz << 9))
1673f14d792SDmitry Monakhov 				break;
1683f14d792SDmitry Monakhov 		}
16918edc8eaSDmitry Monakhov 		ret = 0;
1700aeea189SLukas Czerner 		atomic_inc(&bb.done);
1713f14d792SDmitry Monakhov 		submit_bio(WRITE, bio);
1723f14d792SDmitry Monakhov 	}
1733f14d792SDmitry Monakhov 
1743f14d792SDmitry Monakhov 	/* Wait for bios in-flight */
1750aeea189SLukas Czerner 	if (!atomic_dec_and_test(&bb.done))
1763f14d792SDmitry Monakhov 		wait_for_completion(&wait);
1773f14d792SDmitry Monakhov 
1783f14d792SDmitry Monakhov 	if (!test_bit(BIO_UPTODATE, &bb.flags))
1793f14d792SDmitry Monakhov 		/* One of bios in the batch was completed with error.*/
1803f14d792SDmitry Monakhov 		ret = -EIO;
1813f14d792SDmitry Monakhov 
1823f14d792SDmitry Monakhov 	if (ret)
1833f14d792SDmitry Monakhov 		goto out;
1843f14d792SDmitry Monakhov 
1853f14d792SDmitry Monakhov 	if (test_bit(BIO_EOPNOTSUPP, &bb.flags)) {
1863f14d792SDmitry Monakhov 		ret = -EOPNOTSUPP;
1873f14d792SDmitry Monakhov 		goto out;
1883f14d792SDmitry Monakhov 	}
1893f14d792SDmitry Monakhov 	if (nr_sects != 0)
1903f14d792SDmitry Monakhov 		goto submit;
1913f14d792SDmitry Monakhov out:
1923f14d792SDmitry Monakhov 	return ret;
1933f14d792SDmitry Monakhov }
1943f14d792SDmitry Monakhov EXPORT_SYMBOL(blkdev_issue_zeroout);
195