diff options
Diffstat (limited to 'block/blk-lib.c')
-rw-r--r-- | block/blk-lib.c | 56 |
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; |
107 | out_free_page: | ||
108 | __free_page(page); | ||
109 | out_free_bio: | ||
110 | bio_put(bio); | ||
111 | out: | ||
112 | return -ENOMEM; | ||
113 | } | 101 | } |
114 | EXPORT_SYMBOL(blkdev_issue_discard); | 102 | EXPORT_SYMBOL(blkdev_issue_discard); |
115 | 103 | ||
@@ -157,7 +145,7 @@ static void bio_batch_end_io(struct bio *bio, int err) | |||
157 | int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, | 145 | int 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 | } |
177 | submit: | 165 | submit: |
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 | } |