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