diff options
Diffstat (limited to 'fs/block_dev.c')
-rw-r--r-- | fs/block_dev.c | 51 |
1 files changed, 50 insertions, 1 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 8b18e43b82fe..fc7028b685f2 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -129,6 +129,46 @@ blkdev_get_block(struct inode *inode, sector_t iblock, | |||
129 | return 0; | 129 | return 0; |
130 | } | 130 | } |
131 | 131 | ||
132 | static int | ||
133 | blkdev_get_blocks(struct inode *inode, sector_t iblock, | ||
134 | struct buffer_head *bh, int create) | ||
135 | { | ||
136 | sector_t end_block = max_block(I_BDEV(inode)); | ||
137 | unsigned long max_blocks = bh->b_size >> inode->i_blkbits; | ||
138 | |||
139 | if ((iblock + max_blocks) > end_block) { | ||
140 | max_blocks = end_block - iblock; | ||
141 | if ((long)max_blocks <= 0) { | ||
142 | if (create) | ||
143 | return -EIO; /* write fully beyond EOF */ | ||
144 | /* | ||
145 | * It is a read which is fully beyond EOF. We return | ||
146 | * a !buffer_mapped buffer | ||
147 | */ | ||
148 | max_blocks = 0; | ||
149 | } | ||
150 | } | ||
151 | |||
152 | bh->b_bdev = I_BDEV(inode); | ||
153 | bh->b_blocknr = iblock; | ||
154 | bh->b_size = max_blocks << inode->i_blkbits; | ||
155 | if (max_blocks) | ||
156 | set_buffer_mapped(bh); | ||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static ssize_t | ||
161 | blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | ||
162 | loff_t offset, unsigned long nr_segs) | ||
163 | { | ||
164 | struct file *file = iocb->ki_filp; | ||
165 | struct inode *inode = file->f_mapping->host; | ||
166 | |||
167 | return blockdev_direct_IO_no_locking(rw, iocb, inode, I_BDEV(inode), | ||
168 | iov, offset, nr_segs, blkdev_get_blocks, NULL); | ||
169 | } | ||
170 | |||
171 | #if 0 | ||
132 | static int blk_end_aio(struct bio *bio, unsigned int bytes_done, int error) | 172 | static int blk_end_aio(struct bio *bio, unsigned int bytes_done, int error) |
133 | { | 173 | { |
134 | struct kiocb *iocb = bio->bi_private; | 174 | struct kiocb *iocb = bio->bi_private; |
@@ -146,7 +186,7 @@ static int blk_end_aio(struct bio *bio, unsigned int bytes_done, int error) | |||
146 | iocb->ki_nbytes = -EIO; | 186 | iocb->ki_nbytes = -EIO; |
147 | 187 | ||
148 | if (atomic_dec_and_test(bio_count)) { | 188 | if (atomic_dec_and_test(bio_count)) { |
149 | if (iocb->ki_nbytes < 0) | 189 | if ((long)iocb->ki_nbytes < 0) |
150 | aio_complete(iocb, iocb->ki_nbytes, 0); | 190 | aio_complete(iocb, iocb->ki_nbytes, 0); |
151 | else | 191 | else |
152 | aio_complete(iocb, iocb->ki_left, 0); | 192 | aio_complete(iocb, iocb->ki_left, 0); |
@@ -190,6 +230,12 @@ static struct page *blk_get_page(unsigned long addr, size_t count, int rw, | |||
190 | return pvec->page[pvec->idx++]; | 230 | return pvec->page[pvec->idx++]; |
191 | } | 231 | } |
192 | 232 | ||
233 | /* return a page back to pvec array */ | ||
234 | static void blk_unget_page(struct page *page, struct pvec *pvec) | ||
235 | { | ||
236 | pvec->page[--pvec->idx] = page; | ||
237 | } | ||
238 | |||
193 | static ssize_t | 239 | static ssize_t |
194 | blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | 240 | blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, |
195 | loff_t pos, unsigned long nr_segs) | 241 | loff_t pos, unsigned long nr_segs) |
@@ -278,6 +324,8 @@ same_bio: | |||
278 | count = min(count, nbytes); | 324 | count = min(count, nbytes); |
279 | goto same_bio; | 325 | goto same_bio; |
280 | } | 326 | } |
327 | } else { | ||
328 | blk_unget_page(page, &pvec); | ||
281 | } | 329 | } |
282 | 330 | ||
283 | /* bio is ready, submit it */ | 331 | /* bio is ready, submit it */ |
@@ -315,6 +363,7 @@ backout: | |||
315 | return PTR_ERR(page); | 363 | return PTR_ERR(page); |
316 | goto completion; | 364 | goto completion; |
317 | } | 365 | } |
366 | #endif | ||
318 | 367 | ||
319 | static int blkdev_writepage(struct page *page, struct writeback_control *wbc) | 368 | static int blkdev_writepage(struct page *page, struct writeback_control *wbc) |
320 | { | 369 | { |