blk-lib: check for kill signal in ioctl BLKDISCARD
[linux-2.6-block.git] / block / ioctl.c
index 49fa02b17ec14608e28405fd5c079b25712b3088..d7a6c6931a1e7219a8687932f7955b5f8ba4e819 100644 (file)
@@ -96,9 +96,11 @@ static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode,
                unsigned long arg)
 {
        unsigned int bs_mask = bdev_logical_block_size(bdev) - 1;
-       uint64_t range[2];
-       uint64_t start, len;
        struct inode *inode = bdev->bd_inode;
+       uint64_t range[2], start, len;
+       struct bio *prev = NULL, *bio;
+       sector_t sector, nr_sects;
+       struct blk_plug plug;
        int err;
 
        if (!(mode & BLK_OPEN_WRITE))
@@ -127,7 +129,32 @@ static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode,
        err = truncate_bdev_range(bdev, mode, start, start + len - 1);
        if (err)
                goto fail;
-       err = blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_KERNEL);
+
+       sector = start >> SECTOR_SHIFT;
+       nr_sects = len >> SECTOR_SHIFT;
+
+       blk_start_plug(&plug);
+       while (1) {
+               if (fatal_signal_pending(current)) {
+                       if (prev)
+                               bio_await_chain(prev);
+                       err = -EINTR;
+                       goto out_unplug;
+               }
+               bio = blk_alloc_discard_bio(bdev, &sector, &nr_sects,
+                               GFP_KERNEL);
+               if (!bio)
+                       break;
+               prev = bio_chain_and_submit(prev, bio);
+       }
+       if (prev) {
+               err = submit_bio_wait(prev);
+               if (err == -EOPNOTSUPP)
+                       err = 0;
+               bio_put(prev);
+       }
+out_unplug:
+       blk_finish_plug(&plug);
 fail:
        filemap_invalidate_unlock(inode->i_mapping);
        return err;