block: use blkdev_issue_discard in blk_ioctl_discard
authorChristoph Hellwig <hch@infradead.org>
Sat, 12 Sep 2009 05:35:43 +0000 (07:35 +0200)
committerJens Axboe <jens.axboe@oracle.com>
Mon, 14 Sep 2009 06:24:53 +0000 (08:24 +0200)
blk_ioctl_discard duplicates large amounts of code from blkdev_issue_discard,
the only difference between the two is that blkdev_issue_discard needs to
send a barrier discard request and blk_ioctl_discard a non-barrier one,
and blk_ioctl_discard needs to wait on the request.  To facilitates this
add a flags argument to blkdev_issue_discard to control both aspects of the
behaviour.  This will be very useful later on for using the waiting
funcitonality for other callers.

Based on an earlier patch from Matthew Wilcox <matthew@wil.cx>.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
block/blk-barrier.c
block/ioctl.c
fs/btrfs/extent-tree.c
fs/gfs2/rgrp.c
include/linux/blkdev.h
mm/swapfile.c

index 30022b4e2f6306b36d6c878efc0ea4abb28e5082..6593ab39cfe9223b106d3b5a897937e58176e6b1 100644 (file)
@@ -348,6 +348,9 @@ static void blkdev_discard_end_io(struct bio *bio, int err)
                clear_bit(BIO_UPTODATE, &bio->bi_flags);
        }
 
+       if (bio->bi_private)
+               complete(bio->bi_private);
+
        bio_put(bio);
 }
 
@@ -357,21 +360,20 @@ static void blkdev_discard_end_io(struct bio *bio, int err)
  * @sector:    start sector
  * @nr_sects:  number of sectors to discard
  * @gfp_mask:  memory allocation flags (for bio_alloc)
+ * @flags:     DISCARD_FL_* flags to control behaviour
  *
  * Description:
- *    Issue a discard request for the sectors in question. Does not wait.
+ *    Issue a discard request for the sectors in question.
  */
-int blkdev_issue_discard(struct block_device *bdev,
-                        sector_t sector, sector_t nr_sects, gfp_t gfp_mask)
+int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
+               sector_t nr_sects, gfp_t gfp_mask, int flags)
 {
-       struct request_queue *q;
-       struct bio *bio;
+       DECLARE_COMPLETION_ONSTACK(wait);
+       struct request_queue *q = bdev_get_queue(bdev);
+       int type = flags & DISCARD_FL_BARRIER ?
+               DISCARD_BARRIER : DISCARD_NOBARRIER;
        int ret = 0;
 
-       if (bdev->bd_disk == NULL)
-               return -ENXIO;
-
-       q = bdev_get_queue(bdev);
        if (!q)
                return -ENXIO;
 
@@ -379,12 +381,14 @@ int blkdev_issue_discard(struct block_device *bdev,
                return -EOPNOTSUPP;
 
        while (nr_sects && !ret) {
-               bio = bio_alloc(gfp_mask, 0);
+               struct bio *bio = bio_alloc(gfp_mask, 0);
                if (!bio)
                        return -ENOMEM;
 
                bio->bi_end_io = blkdev_discard_end_io;
                bio->bi_bdev = bdev;
+               if (flags & DISCARD_FL_WAIT)
+                       bio->bi_private = &wait;
 
                bio->bi_sector = sector;
 
@@ -396,10 +400,13 @@ int blkdev_issue_discard(struct block_device *bdev,
                        bio->bi_size = nr_sects << 9;
                        nr_sects = 0;
                }
+
                bio_get(bio);
-               submit_bio(DISCARD_BARRIER, bio);
+               submit_bio(type, bio);
+
+               if (flags & DISCARD_FL_WAIT)
+                       wait_for_completion(&wait);
 
-               /* Check if it failed immediately */
                if (bio_flagged(bio, BIO_EOPNOTSUPP))
                        ret = -EOPNOTSUPP;
                else if (!bio_flagged(bio, BIO_UPTODATE))
index 500e4c73cc52ba3a36b844c9e97404508ccf4b9b..d3e6b5827a3425de1871ec4dfa9f5ca04e8744f4 100644 (file)
@@ -112,22 +112,9 @@ static int blkdev_reread_part(struct block_device *bdev)
        return res;
 }
 
-static void blk_ioc_discard_endio(struct bio *bio, int err)
-{
-       if (err) {
-               if (err == -EOPNOTSUPP)
-                       set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
-               clear_bit(BIO_UPTODATE, &bio->bi_flags);
-       }
-       complete(bio->bi_private);
-}
-
 static int blk_ioctl_discard(struct block_device *bdev, uint64_t start,
                             uint64_t len)
 {
-       struct request_queue *q = bdev_get_queue(bdev);
-       int ret = 0;
-
        if (start & 511)
                return -EINVAL;
        if (len & 511)
@@ -137,40 +124,8 @@ static int blk_ioctl_discard(struct block_device *bdev, uint64_t start,
 
        if (start + len > (bdev->bd_inode->i_size >> 9))
                return -EINVAL;
-
-       if (!q->prepare_discard_fn)
-               return -EOPNOTSUPP;
-
-       while (len && !ret) {
-               DECLARE_COMPLETION_ONSTACK(wait);
-               struct bio *bio;
-
-               bio = bio_alloc(GFP_KERNEL, 0);
-
-               bio->bi_end_io = blk_ioc_discard_endio;
-               bio->bi_bdev = bdev;
-               bio->bi_private = &wait;
-               bio->bi_sector = start;
-
-               if (len > queue_max_hw_sectors(q)) {
-                       bio->bi_size = queue_max_hw_sectors(q) << 9;
-                       len -= queue_max_hw_sectors(q);
-                       start += queue_max_hw_sectors(q);
-               } else {
-                       bio->bi_size = len << 9;
-                       len = 0;
-               }
-               submit_bio(DISCARD_NOBARRIER, bio);
-
-               wait_for_completion(&wait);
-
-               if (bio_flagged(bio, BIO_EOPNOTSUPP))
-                       ret = -EOPNOTSUPP;
-               else if (!bio_flagged(bio, BIO_UPTODATE))
-                       ret = -EIO;
-               bio_put(bio);
-       }
-       return ret;
+       return blkdev_issue_discard(bdev, start, len, GFP_KERNEL,
+                                   DISCARD_FL_WAIT);
 }
 
 static int put_ushort(unsigned long arg, unsigned short val)
index 72a2b9c28e9fc7a6a7aacce09469cb6414215635..535f85ba104f41fea1c28820533da7e1af1512c3 100644 (file)
@@ -1511,7 +1511,8 @@ static int remove_extent_backref(struct btrfs_trans_handle *trans,
 static void btrfs_issue_discard(struct block_device *bdev,
                                u64 start, u64 len)
 {
-       blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_KERNEL);
+       blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_KERNEL,
+                            DISCARD_FL_BARRIER);
 }
 #endif
 
index fba795798d3a1b63f1ea10aab5342d5f044b7f21..fbc43241f2efc3b1913ced20fc7cc2f634de6b2c 100644 (file)
@@ -857,7 +857,8 @@ static void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
                                        goto start_new_extent;
                                if ((start + nr_sects) != blk) {
                                        rv = blkdev_issue_discard(bdev, start,
-                                                           nr_sects, GFP_NOFS);
+                                                           nr_sects, GFP_NOFS,
+                                                           DISCARD_FL_BARRIER);
                                        if (rv)
                                                goto fail;
                                        nr_sects = 0;
@@ -871,7 +872,8 @@ start_new_extent:
                }
        }
        if (nr_sects) {
-               rv = blkdev_issue_discard(bdev, start, nr_sects, GFP_NOFS);
+               rv = blkdev_issue_discard(bdev, start, nr_sects, GFP_NOFS,
+                                        DISCARD_FL_BARRIER);
                if (rv)
                        goto fail;
        }
index 86c2bdff3b891fca711352b032a17472a2b18e89..e23a86cae5ac9a328fd2fe1cc7c4eecc0741760c 100644 (file)
@@ -998,15 +998,18 @@ static inline struct request *blk_map_queue_find_tag(struct blk_queue_tag *bqt,
 }
 
 extern int blkdev_issue_flush(struct block_device *, sector_t *);
-extern int blkdev_issue_discard(struct block_device *,
-                               sector_t sector, sector_t nr_sects, gfp_t);
+#define DISCARD_FL_WAIT                0x01    /* wait for completion */
+#define DISCARD_FL_BARRIER     0x02    /* issue DISCARD_BARRIER request */
+extern int blkdev_issue_discard(struct block_device *, sector_t sector,
+               sector_t nr_sects, gfp_t, int flags);
 
 static inline int sb_issue_discard(struct super_block *sb,
                                   sector_t block, sector_t nr_blocks)
 {
        block <<= (sb->s_blocksize_bits - 9);
        nr_blocks <<= (sb->s_blocksize_bits - 9);
-       return blkdev_issue_discard(sb->s_bdev, block, nr_blocks, GFP_KERNEL);
+       return blkdev_issue_discard(sb->s_bdev, block, nr_blocks, GFP_KERNEL,
+                                   DISCARD_FL_BARRIER);
 }
 
 extern int blk_verify_command(unsigned char *cmd, fmode_t has_write_perm);
index 8ffdc0d23c536fe04779a9c559af68f6d9470997..74f1102e8749a8b207aab5ae78fa4000ab0c5ca9 100644 (file)
@@ -161,7 +161,8 @@ static int discard_swap(struct swap_info_struct *si)
                }
 
                err = blkdev_issue_discard(si->bdev, start_block,
-                                               nr_blocks, GFP_KERNEL);
+                                               nr_blocks, GFP_KERNEL,
+                                               DISCARD_FL_BARRIER);
                if (err)
                        break;
 
@@ -200,7 +201,8 @@ static void discard_swap_cluster(struct swap_info_struct *si,
                        start_block <<= PAGE_SHIFT - 9;
                        nr_blocks <<= PAGE_SHIFT - 9;
                        if (blkdev_issue_discard(si->bdev, start_block,
-                                                       nr_blocks, GFP_NOIO))
+                                                       nr_blocks, GFP_NOIO,
+                                                       DISCARD_FL_BARRIER))
                                break;
                }