aboutsummaryrefslogtreecommitdiffstats
path: root/block/blk-lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'block/blk-lib.c')
-rw-r--r--block/blk-lib.c56
1 files changed, 24 insertions, 32 deletions
diff --git a/block/blk-lib.c b/block/blk-lib.c
index d0216b9f22d4..c1fc55a83ba1 100644
--- a/block/blk-lib.c
+++ b/block/blk-lib.c
@@ -19,7 +19,6 @@ static void blkdev_discard_end_io(struct bio *bio, int err)
19 19
20 if (bio->bi_private) 20 if (bio->bi_private)
21 complete(bio->bi_private); 21 complete(bio->bi_private);
22 __free_page(bio_page(bio));
23 22
24 bio_put(bio); 23 bio_put(bio);
25} 24}
@@ -42,8 +41,8 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
42 struct request_queue *q = bdev_get_queue(bdev); 41 struct request_queue *q = bdev_get_queue(bdev);
43 int type = flags & BLKDEV_IFL_BARRIER ? 42 int type = flags & BLKDEV_IFL_BARRIER ?
44 DISCARD_BARRIER : DISCARD_NOBARRIER; 43 DISCARD_BARRIER : DISCARD_NOBARRIER;
44 unsigned int max_discard_sectors;
45 struct bio *bio; 45 struct bio *bio;
46 struct page *page;
47 int ret = 0; 46 int ret = 0;
48 47
49 if (!q) 48 if (!q)
@@ -52,36 +51,30 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
52 if (!blk_queue_discard(q)) 51 if (!blk_queue_discard(q))
53 return -EOPNOTSUPP; 52 return -EOPNOTSUPP;
54 53
55 while (nr_sects && !ret) { 54 /*
56 unsigned int sector_size = q->limits.logical_block_size; 55 * Ensure that max_discard_sectors is of the proper
57 unsigned int max_discard_sectors = 56 * granularity
58 min(q->limits.max_discard_sectors, UINT_MAX >> 9); 57 */
58 max_discard_sectors = min(q->limits.max_discard_sectors, UINT_MAX >> 9);
59 if (q->limits.discard_granularity) {
60 unsigned int disc_sects = q->limits.discard_granularity >> 9;
59 61
62 max_discard_sectors &= ~(disc_sects - 1);
63 }
64
65 while (nr_sects && !ret) {
60 bio = bio_alloc(gfp_mask, 1); 66 bio = bio_alloc(gfp_mask, 1);
61 if (!bio) 67 if (!bio) {
62 goto out; 68 ret = -ENOMEM;
69 break;
70 }
71
63 bio->bi_sector = sector; 72 bio->bi_sector = sector;
64 bio->bi_end_io = blkdev_discard_end_io; 73 bio->bi_end_io = blkdev_discard_end_io;
65 bio->bi_bdev = bdev; 74 bio->bi_bdev = bdev;
66 if (flags & BLKDEV_IFL_WAIT) 75 if (flags & BLKDEV_IFL_WAIT)
67 bio->bi_private = &wait; 76 bio->bi_private = &wait;
68 77
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) { 78 if (nr_sects > max_discard_sectors) {
86 bio->bi_size = max_discard_sectors << 9; 79 bio->bi_size = max_discard_sectors << 9;
87 nr_sects -= max_discard_sectors; 80 nr_sects -= max_discard_sectors;
@@ -103,13 +96,8 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
103 ret = -EIO; 96 ret = -EIO;
104 bio_put(bio); 97 bio_put(bio);
105 } 98 }
99
106 return ret; 100 return ret;
107out_free_page:
108 __free_page(page);
109out_free_bio:
110 bio_put(bio);
111out:
112 return -ENOMEM;
113} 101}
114EXPORT_SYMBOL(blkdev_issue_discard); 102EXPORT_SYMBOL(blkdev_issue_discard);
115 103
@@ -157,7 +145,7 @@ static void bio_batch_end_io(struct bio *bio, int err)
157int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, 145int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
158 sector_t nr_sects, gfp_t gfp_mask, unsigned long flags) 146 sector_t nr_sects, gfp_t gfp_mask, unsigned long flags)
159{ 147{
160 int ret = 0; 148 int ret;
161 struct bio *bio; 149 struct bio *bio;
162 struct bio_batch bb; 150 struct bio_batch bb;
163 unsigned int sz, issued = 0; 151 unsigned int sz, issued = 0;
@@ -175,11 +163,14 @@ int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
175 return ret; 163 return ret;
176 } 164 }
177submit: 165submit:
166 ret = 0;
178 while (nr_sects != 0) { 167 while (nr_sects != 0) {
179 bio = bio_alloc(gfp_mask, 168 bio = bio_alloc(gfp_mask,
180 min(nr_sects, (sector_t)BIO_MAX_PAGES)); 169 min(nr_sects, (sector_t)BIO_MAX_PAGES));
181 if (!bio) 170 if (!bio) {
171 ret = -ENOMEM;
182 break; 172 break;
173 }
183 174
184 bio->bi_sector = sector; 175 bio->bi_sector = sector;
185 bio->bi_bdev = bdev; 176 bio->bi_bdev = bdev;
@@ -198,6 +189,7 @@ submit:
198 if (ret < (sz << 9)) 189 if (ret < (sz << 9))
199 break; 190 break;
200 } 191 }
192 ret = 0;
201 issued++; 193 issued++;
202 submit_bio(WRITE, bio); 194 submit_bio(WRITE, bio);
203 } 195 }