diff options
| author | Christoph Hellwig <hch@lst.de> | 2015-04-07 12:23:29 -0400 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-04-15 15:06:33 -0400 |
| commit | aa4d86163e4e91a1ac560954a554bab417e338f4 (patch) | |
| tree | 25c4f29e616669c7f2f72309b2ca2668c7c90438 | |
| parent | 6683de3886a313ae3d4b8c0323313a987073481b (diff) | |
block: loop: switch to VFS ITER_BVEC
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| -rw-r--r-- | drivers/block/loop.c | 294 |
1 files changed, 120 insertions, 174 deletions
diff --git a/drivers/block/loop.c b/drivers/block/loop.c index c4fd1e45ce1e..ae3fcb4199e9 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c | |||
| @@ -88,28 +88,6 @@ static int part_shift; | |||
| 88 | 88 | ||
| 89 | static struct workqueue_struct *loop_wq; | 89 | static struct workqueue_struct *loop_wq; |
| 90 | 90 | ||
| 91 | /* | ||
| 92 | * Transfer functions | ||
| 93 | */ | ||
| 94 | static int transfer_none(struct loop_device *lo, int cmd, | ||
| 95 | struct page *raw_page, unsigned raw_off, | ||
| 96 | struct page *loop_page, unsigned loop_off, | ||
| 97 | int size, sector_t real_block) | ||
| 98 | { | ||
| 99 | char *raw_buf = kmap_atomic(raw_page) + raw_off; | ||
| 100 | char *loop_buf = kmap_atomic(loop_page) + loop_off; | ||
| 101 | |||
| 102 | if (cmd == READ) | ||
| 103 | memcpy(loop_buf, raw_buf, size); | ||
| 104 | else | ||
| 105 | memcpy(raw_buf, loop_buf, size); | ||
| 106 | |||
| 107 | kunmap_atomic(loop_buf); | ||
| 108 | kunmap_atomic(raw_buf); | ||
| 109 | cond_resched(); | ||
| 110 | return 0; | ||
| 111 | } | ||
| 112 | |||
| 113 | static int transfer_xor(struct loop_device *lo, int cmd, | 91 | static int transfer_xor(struct loop_device *lo, int cmd, |
| 114 | struct page *raw_page, unsigned raw_off, | 92 | struct page *raw_page, unsigned raw_off, |
| 115 | struct page *loop_page, unsigned loop_off, | 93 | struct page *loop_page, unsigned loop_off, |
| @@ -148,14 +126,13 @@ static int xor_init(struct loop_device *lo, const struct loop_info64 *info) | |||
| 148 | 126 | ||
| 149 | static struct loop_func_table none_funcs = { | 127 | static struct loop_func_table none_funcs = { |
| 150 | .number = LO_CRYPT_NONE, | 128 | .number = LO_CRYPT_NONE, |
| 151 | .transfer = transfer_none, | 129 | }; |
| 152 | }; | ||
| 153 | 130 | ||
| 154 | static struct loop_func_table xor_funcs = { | 131 | static struct loop_func_table xor_funcs = { |
| 155 | .number = LO_CRYPT_XOR, | 132 | .number = LO_CRYPT_XOR, |
| 156 | .transfer = transfer_xor, | 133 | .transfer = transfer_xor, |
| 157 | .init = xor_init | 134 | .init = xor_init |
| 158 | }; | 135 | }; |
| 159 | 136 | ||
| 160 | /* xfer_funcs[0] is special - its release function is never called */ | 137 | /* xfer_funcs[0] is special - its release function is never called */ |
| 161 | static struct loop_func_table *xfer_funcs[MAX_LO_CRYPT] = { | 138 | static struct loop_func_table *xfer_funcs[MAX_LO_CRYPT] = { |
| @@ -215,207 +192,169 @@ lo_do_transfer(struct loop_device *lo, int cmd, | |||
| 215 | struct page *lpage, unsigned loffs, | 192 | struct page *lpage, unsigned loffs, |
| 216 | int size, sector_t rblock) | 193 | int size, sector_t rblock) |
| 217 | { | 194 | { |
| 218 | if (unlikely(!lo->transfer)) | 195 | int ret; |
| 196 | |||
| 197 | ret = lo->transfer(lo, cmd, rpage, roffs, lpage, loffs, size, rblock); | ||
| 198 | if (likely(!ret)) | ||
| 219 | return 0; | 199 | return 0; |
| 220 | 200 | ||
| 221 | return lo->transfer(lo, cmd, rpage, roffs, lpage, loffs, size, rblock); | 201 | printk_ratelimited(KERN_ERR |
| 202 | "loop: Transfer error at byte offset %llu, length %i.\n", | ||
| 203 | (unsigned long long)rblock << 9, size); | ||
| 204 | return ret; | ||
| 222 | } | 205 | } |
| 223 | 206 | ||
| 224 | /** | 207 | static int lo_write_bvec(struct file *file, struct bio_vec *bvec, loff_t *ppos) |
| 225 | * __do_lo_send_write - helper for writing data to a loop device | ||
| 226 | * | ||
| 227 | * This helper just factors out common code between do_lo_send_direct_write() | ||
| 228 | * and do_lo_send_write(). | ||
| 229 | */ | ||
| 230 | static int __do_lo_send_write(struct file *file, | ||
| 231 | u8 *buf, const int len, loff_t pos) | ||
| 232 | { | 208 | { |
| 233 | struct kvec kvec = {.iov_base = buf, .iov_len = len}; | 209 | struct iov_iter i; |
| 234 | struct iov_iter from; | ||
| 235 | ssize_t bw; | 210 | ssize_t bw; |
| 236 | 211 | ||
| 237 | iov_iter_kvec(&from, ITER_KVEC | WRITE, &kvec, 1, len); | 212 | iov_iter_bvec(&i, ITER_BVEC, bvec, 1, bvec->bv_len); |
| 238 | 213 | ||
| 239 | file_start_write(file); | 214 | file_start_write(file); |
| 240 | bw = vfs_iter_write(file, &from, &pos); | 215 | bw = vfs_iter_write(file, &i, ppos); |
| 241 | file_end_write(file); | 216 | file_end_write(file); |
| 242 | if (likely(bw == len)) | 217 | |
| 218 | if (likely(bw == bvec->bv_len)) | ||
| 243 | return 0; | 219 | return 0; |
| 244 | printk_ratelimited(KERN_ERR "loop: Write error at byte offset %llu, length %i.\n", | 220 | |
| 245 | (unsigned long long)pos, len); | 221 | printk_ratelimited(KERN_ERR |
| 222 | "loop: Write error at byte offset %llu, length %i.\n", | ||
| 223 | (unsigned long long)*ppos, bvec->bv_len); | ||
| 246 | if (bw >= 0) | 224 | if (bw >= 0) |
| 247 | bw = -EIO; | 225 | bw = -EIO; |
| 248 | return bw; | 226 | return bw; |
| 249 | } | 227 | } |
| 250 | 228 | ||
| 251 | /** | 229 | static int lo_write_simple(struct loop_device *lo, struct request *rq, |
| 252 | * do_lo_send_direct_write - helper for writing data to a loop device | 230 | loff_t pos) |
| 253 | * | ||
| 254 | * This is the fast, non-transforming version that does not need double | ||
| 255 | * buffering. | ||
| 256 | */ | ||
| 257 | static int do_lo_send_direct_write(struct loop_device *lo, | ||
| 258 | struct bio_vec *bvec, loff_t pos, struct page *page) | ||
| 259 | { | 231 | { |
| 260 | ssize_t bw = __do_lo_send_write(lo->lo_backing_file, | 232 | struct bio_vec bvec; |
| 261 | kmap(bvec->bv_page) + bvec->bv_offset, | 233 | struct req_iterator iter; |
| 262 | bvec->bv_len, pos); | 234 | int ret = 0; |
| 263 | kunmap(bvec->bv_page); | 235 | |
| 264 | cond_resched(); | 236 | rq_for_each_segment(bvec, rq, iter) { |
| 265 | return bw; | 237 | ret = lo_write_bvec(lo->lo_backing_file, &bvec, &pos); |
| 238 | if (ret < 0) | ||
| 239 | break; | ||
| 240 | cond_resched(); | ||
| 241 | } | ||
| 242 | |||
| 243 | return ret; | ||
| 266 | } | 244 | } |
| 267 | 245 | ||
| 268 | /** | 246 | /* |
| 269 | * do_lo_send_write - helper for writing data to a loop device | ||
| 270 | * | ||
| 271 | * This is the slow, transforming version that needs to double buffer the | 247 | * This is the slow, transforming version that needs to double buffer the |
| 272 | * data as it cannot do the transformations in place without having direct | 248 | * data as it cannot do the transformations in place without having direct |
| 273 | * access to the destination pages of the backing file. | 249 | * access to the destination pages of the backing file. |
| 274 | */ | 250 | */ |
| 275 | static int do_lo_send_write(struct loop_device *lo, struct bio_vec *bvec, | 251 | static int lo_write_transfer(struct loop_device *lo, struct request *rq, |
| 276 | loff_t pos, struct page *page) | 252 | loff_t pos) |
| 277 | { | 253 | { |
| 278 | int ret = lo_do_transfer(lo, WRITE, page, 0, bvec->bv_page, | 254 | struct bio_vec bvec, b; |
| 279 | bvec->bv_offset, bvec->bv_len, pos >> 9); | ||
| 280 | if (likely(!ret)) | ||
| 281 | return __do_lo_send_write(lo->lo_backing_file, | ||
| 282 | page_address(page), bvec->bv_len, | ||
| 283 | pos); | ||
| 284 | printk_ratelimited(KERN_ERR "loop: Transfer error at byte offset %llu, " | ||
| 285 | "length %i.\n", (unsigned long long)pos, bvec->bv_len); | ||
| 286 | if (ret > 0) | ||
| 287 | ret = -EIO; | ||
| 288 | return ret; | ||
| 289 | } | ||
| 290 | |||
| 291 | static int lo_send(struct loop_device *lo, struct request *rq, loff_t pos) | ||
| 292 | { | ||
| 293 | int (*do_lo_send)(struct loop_device *, struct bio_vec *, loff_t, | ||
| 294 | struct page *page); | ||
| 295 | struct bio_vec bvec; | ||
| 296 | struct req_iterator iter; | 255 | struct req_iterator iter; |
| 297 | struct page *page = NULL; | 256 | struct page *page; |
| 298 | int ret = 0; | 257 | int ret = 0; |
| 299 | 258 | ||
| 300 | if (lo->transfer != transfer_none) { | 259 | page = alloc_page(GFP_NOIO); |
| 301 | page = alloc_page(GFP_NOIO | __GFP_HIGHMEM); | 260 | if (unlikely(!page)) |
| 302 | if (unlikely(!page)) | 261 | return -ENOMEM; |
| 303 | goto fail; | ||
| 304 | kmap(page); | ||
| 305 | do_lo_send = do_lo_send_write; | ||
| 306 | } else { | ||
| 307 | do_lo_send = do_lo_send_direct_write; | ||
| 308 | } | ||
| 309 | 262 | ||
| 310 | rq_for_each_segment(bvec, rq, iter) { | 263 | rq_for_each_segment(bvec, rq, iter) { |
| 311 | ret = do_lo_send(lo, &bvec, pos, page); | 264 | ret = lo_do_transfer(lo, WRITE, page, 0, bvec.bv_page, |
