linux/block/blk-lib.c
<<
>>
Prefs
   1/*
   2 * Functions related to generic helpers functions
   3 */
   4#include <linux/kernel.h>
   5#include <linux/module.h>
   6#include <linux/bio.h>
   7#include <linux/blkdev.h>
   8#include <linux/scatterlist.h>
   9
  10#include "blk.h"
  11
  12static void blkdev_discard_end_io(struct bio *bio, int err)
  13{
  14        if (err) {
  15                if (err == -EOPNOTSUPP)
  16                        set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
  17                clear_bit(BIO_UPTODATE, &bio->bi_flags);
  18        }
  19
  20        if (bio->bi_private)
  21                complete(bio->bi_private);
  22        __free_page(bio_page(bio));
  23
  24        bio_put(bio);
  25}
  26
  27/**
  28 * blkdev_issue_discard - queue a discard
  29 * @bdev:       blockdev to issue discard for
  30 * @sector:     start sector
  31 * @nr_sects:   number of sectors to discard
  32 * @gfp_mask:   memory allocation flags (for bio_alloc)
  33 * @flags:      BLKDEV_IFL_* flags to control behaviour
  34 *
  35 * Description:
  36 *    Issue a discard request for the sectors in question.
  37 */
  38int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
  39                sector_t nr_sects, gfp_t gfp_mask, unsigned long flags)
  40{
  41        DECLARE_COMPLETION_ONSTACK(wait);
  42        struct request_queue *q = bdev_get_queue(bdev);
  43        int type = flags & BLKDEV_IFL_BARRIER ?
  44                DISCARD_BARRIER : DISCARD_NOBARRIER;
  45        struct bio *bio;
  46        struct page *page;
  47        int ret = 0;
  48
  49        if (!q)
  50                return -ENXIO;
  51
  52        if (!blk_queue_discard(q))
  53                return -EOPNOTSUPP;
  54
  55        while (nr_sects && !ret) {
  56                unsigned int sector_size = q->limits.logical_block_size;
  57                unsigned int max_discard_sectors =
  58                        min(q->limits.max_discard_sectors, UINT_MAX >> 9);
  59
  60                bio = bio_alloc(gfp_mask, 1);
  61                if (!bio)
  62                        goto out;
  63                bio->bi_sector = sector;
  64                bio->bi_end_io = blkdev_discard_end_io;
  65                bio->bi_bdev = bdev;
  66                if (flags & BLKDEV_IFL_WAIT)
  67                        bio->bi_private = &wait;
  68
  69                /*
  70                 * Add a zeroed one-sector payload as that's what
  71                 * our current implementations need.  If we'll ever need
  72                 * more the interface will need revisiting.
  73                 */
  74                page = alloc_page(gfp_mask | __GFP_ZERO);
  75                if (!page)
  76                        goto out_free_bio;
  77                if (bio_add_pc_page(q, bio, page, sector_size, 0) < sector_size)
  78                        goto out_free_page;
  79
  80                /*
  81                 * And override the bio size - the way discard works we
  82                 * touch many more blocks on disk than the actual payload
  83                 * length.
  84                 */
  85                if (nr_sects > max_discard_sectors) {
  86                        bio->bi_size = max_discard_sectors << 9;
  87                        nr_sects -= max_discard_sectors;
  88                        sector += max_discard_sectors;
  89                } else {
  90                        bio->bi_size = nr_sects << 9;
  91                        nr_sects = 0;
  92                }
  93
  94                bio_get(bio);
  95                submit_bio(type, bio);
  96
  97                if (flags & BLKDEV_IFL_WAIT)
  98                        wait_for_completion(&wait);
  99
 100                if (bio_flagged(bio, BIO_EOPNOTSUPP))
 101                        ret = -EOPNOTSUPP;
 102                else if (!bio_flagged(bio, BIO_UPTODATE))
 103                        ret = -EIO;
 104                bio_put(bio);
 105        }
 106        return ret;
 107out_free_page:
 108        __free_page(page);
 109out_free_bio:
 110        bio_put(bio);
 111out:
 112        return -ENOMEM;
 113}
 114EXPORT_SYMBOL(blkdev_issue_discard);
 115
 116struct bio_batch
 117{
 118        atomic_t                done;
 119        unsigned long           flags;
 120        struct completion       *wait;
 121        bio_end_io_t            *end_io;
 122};
 123
 124static void bio_batch_end_io(struct bio *bio, int err)
 125{
 126        struct bio_batch *bb = bio->bi_private;
 127
 128        if (err) {
 129                if (err == -EOPNOTSUPP)
 130                        set_bit(BIO_EOPNOTSUPP, &bb->flags);
 131                else
 132                        clear_bit(BIO_UPTODATE, &bb->flags);
 133        }
 134        if (bb) {
 135                if (bb->end_io)
 136                        bb->end_io(bio, err);
 137                atomic_inc(&bb->done);
 138                complete(bb->wait);
 139        }
 140        bio_put(bio);
 141}
 142
 143/**
 144 * blkdev_issue_zeroout generate number of zero filed write bios
 145 * @bdev:       blockdev to issue
 146 * @sector:     start sector
 147 * @nr_sects:   number of sectors to write
 148 * @gfp_mask:   memory allocation flags (for bio_alloc)
 149 * @flags:      BLKDEV_IFL_* flags to control behaviour
 150 *
 151 * Description:
 152 *  Generate and issue number of bios with zerofiled pages.
 153 *  Send barrier at the beginning and at the end if requested. This guarantie
 154 *  correct request ordering. Empty barrier allow us to avoid post queue flush.
 155 */
 156
 157int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
 158                        sector_t nr_sects, gfp_t gfp_mask, unsigned long flags)
 159{
 160        int ret = 0;
 161        struct bio *bio;
 162        struct bio_batch bb;
 163        unsigned int sz, issued = 0;
 164        DECLARE_COMPLETION_ONSTACK(wait);
 165
 166        atomic_set(&bb.done, 0);
 167        bb.flags = 1 << BIO_UPTODATE;
 168        bb.wait = &wait;
 169        bb.end_io = NULL;
 170
 171        if (flags & BLKDEV_IFL_BARRIER) {
 172                /* issue async barrier before the data */
 173                ret = blkdev_issue_flush(bdev, gfp_mask, NULL, 0);
 174                if (ret)
 175                        return ret;
 176        }
 177submit:
 178        while (nr_sects != 0) {
 179                bio = bio_alloc(gfp_mask,
 180                                min(nr_sects, (sector_t)BIO_MAX_PAGES));
 181                if (!bio)
 182                        break;
 183
 184                bio->bi_sector = sector;
 185                bio->bi_bdev   = bdev;
 186                bio->bi_end_io = bio_batch_end_io;
 187                if (flags & BLKDEV_IFL_WAIT)
 188                        bio->bi_private = &bb;
 189
 190                while (nr_sects != 0) {
 191                        sz = min((sector_t) PAGE_SIZE >> 9 , nr_sects);
 192                        if (sz == 0)
 193                                /* bio has maximum size possible */
 194                                break;
 195                        ret = bio_add_page(bio, ZERO_PAGE(0), sz << 9, 0);
 196                        nr_sects -= ret >> 9;
 197                        sector += ret >> 9;
 198                        if (ret < (sz << 9))
 199                                break;
 200                }
 201                issued++;
 202                submit_bio(WRITE, bio);
 203        }
 204        /*
 205         * When all data bios are in flight. Send final barrier if requeted.
 206         */
 207        if (nr_sects == 0 && flags & BLKDEV_IFL_BARRIER)
 208                ret = blkdev_issue_flush(bdev, gfp_mask, NULL,
 209                                        flags & BLKDEV_IFL_WAIT);
 210
 211
 212        if (flags & BLKDEV_IFL_WAIT)
 213                /* Wait for bios in-flight */
 214                while ( issued != atomic_read(&bb.done))
 215                        wait_for_completion(&wait);
 216
 217        if (!test_bit(BIO_UPTODATE, &bb.flags))
 218                /* One of bios in the batch was completed with error.*/
 219                ret = -EIO;
 220
 221        if (ret)
 222                goto out;
 223
 224        if (test_bit(BIO_EOPNOTSUPP, &bb.flags)) {
 225                ret = -EOPNOTSUPP;
 226                goto out;
 227        }
 228        if (nr_sects != 0)
 229                goto submit;
 230out:
 231        return ret;
 232}
 233EXPORT_SYMBOL(blkdev_issue_zeroout);
 234