diff options
-rw-r--r-- | drivers/block/loop.c | 135 | ||||
-rw-r--r-- | include/linux/loop.h | 1 |
2 files changed, 23 insertions, 113 deletions
diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 4720c7ade0ae..46cdd6945557 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c | |||
@@ -203,74 +203,6 @@ lo_do_transfer(struct loop_device *lo, int cmd, | |||
203 | } | 203 | } |
204 | 204 | ||
205 | /** | 205 | /** |
206 | * do_lo_send_aops - helper for writing data to a loop device | ||
207 | * | ||
208 | * This is the fast version for backing filesystems which implement the address | ||
209 | * space operations write_begin and write_end. | ||
210 | */ | ||
211 | static int do_lo_send_aops(struct loop_device *lo, struct bio_vec *bvec, | ||
212 | loff_t pos, struct page *unused) | ||
213 | { | ||
214 | struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */ | ||
215 | struct address_space *mapping = file->f_mapping; | ||
216 | pgoff_t index; | ||
217 | unsigned offset, bv_offs; | ||
218 | int len, ret; | ||
219 | |||
220 | mutex_lock(&mapping->host->i_mutex); | ||
221 | index = pos >> PAGE_CACHE_SHIFT; | ||
222 | offset = pos & ((pgoff_t)PAGE_CACHE_SIZE - 1); | ||
223 | bv_offs = bvec->bv_offset; | ||
224 | len = bvec->bv_len; | ||
225 | while (len > 0) { | ||
226 | sector_t IV; | ||
227 | unsigned size, copied; | ||
228 | int transfer_result; | ||
229 | struct page *page; | ||
230 | void *fsdata; | ||
231 | |||
232 | IV = ((sector_t)index << (PAGE_CACHE_SHIFT - 9))+(offset >> 9); | ||
233 | size = PAGE_CACHE_SIZE - offset; | ||
234 | if (size > len) | ||
235 | size = len; | ||
236 | |||
237 | ret = pagecache_write_begin(file, mapping, pos, size, 0, | ||
238 | &page, &fsdata); | ||
239 | if (ret) | ||
240 | goto fail; | ||
241 | |||
242 | file_update_time(file); | ||
243 | |||
244 | transfer_result = lo_do_transfer(lo, WRITE, page, offset, | ||
245 | bvec->bv_page, bv_offs, size, IV); | ||
246 | copied = size; | ||
247 | if (unlikely(transfer_result)) | ||
248 | copied = 0; | ||
249 | |||
250 | ret = pagecache_write_end(file, mapping, pos, size, copied, | ||
251 | page, fsdata); | ||
252 | if (ret < 0 || ret != copied) | ||
253 | goto fail; | ||
254 | |||
255 | if (unlikely(transfer_result)) | ||
256 | goto fail; | ||
257 | |||
258 | bv_offs += copied; | ||
259 | len -= copied; | ||
260 | offset = 0; | ||
261 | index++; | ||
262 | pos += copied; | ||
263 | } | ||
264 | ret = 0; | ||
265 | out: | ||
266 | mutex_unlock(&mapping->host->i_mutex); | ||
267 | return ret; | ||
268 | fail: | ||
269 | ret = -1; | ||
270 | goto out; | ||
271 | } | ||
272 | |||
273 | /** | ||
274 | * __do_lo_send_write - helper for writing data to a loop device | 206 | * __do_lo_send_write - helper for writing data to a loop device |
275 | * | 207 | * |
276 | * This helper just factors out common code between do_lo_send_direct_write() | 208 | * This helper just factors out common code between do_lo_send_direct_write() |
@@ -297,10 +229,8 @@ static int __do_lo_send_write(struct file *file, | |||
297 | /** | 229 | /** |
298 | * do_lo_send_direct_write - helper for writing data to a loop device | 230 | * do_lo_send_direct_write - helper for writing data to a loop device |
299 | * | 231 | * |
300 | * This is the fast, non-transforming version for backing filesystems which do | 232 | * This is the fast, non-transforming version that does not need double |
301 | * not implement the address space operations write_begin and write_end. | 233 | * buffering. |
302 | * It uses the write file operation which should be present on all writeable | ||
303 | * filesystems. | ||
304 | */ | 234 | */ |
305 | static int do_lo_send_direct_write(struct loop_device *lo, | 235 | static int do_lo_send_direct_write(struct loop_device *lo, |
306 | struct bio_vec *bvec, loff_t pos, struct page *page) | 236 | struct bio_vec *bvec, loff_t pos, struct page *page) |
@@ -316,15 +246,9 @@ static int do_lo_send_direct_write(struct loop_device *lo, | |||
316 | /** | 246 | /** |
317 | * do_lo_send_write - helper for writing data to a loop device | 247 | * do_lo_send_write - helper for writing data to a loop device |
318 | * | 248 | * |
319 | * This is the slow, transforming version for filesystems which do not | 249 | * This is the slow, transforming version that needs to double buffer the |
320 | * implement the address space operations write_begin and write_end. It | 250 | * data as it cannot do the transformations in place without having direct |
321 | * uses the write file operation which should be present on all writeable | 251 | * access to the destination pages of the backing file. |
322 | * filesystems. | ||
323 | * | ||
324 | * Using fops->write is slower than using aops->{prepare,commit}_write in the | ||
325 | * transforming case because we need to double buffer the data as we cannot do | ||
326 | * the transformations in place as we do not have direct access to the | ||
327 | * destination pages of the backing file. | ||
328 | */ | 252 | */ |
329 | static int do_lo_send_write(struct loop_device *lo, struct bio_vec *bvec, | 253 | static int do_lo_send_write(struct loop_device *lo, struct bio_vec *bvec, |
330 | loff_t pos, struct page *page) | 254 | loff_t pos, struct page *page) |
@@ -350,17 +274,16 @@ static int lo_send(struct loop_device *lo, struct bio *bio, loff_t pos) | |||
350 | struct page *page = NULL; | 274 | struct page *page = NULL; |
351 | int i, ret = 0; | 275 | int i, ret = 0; |
352 | 276 | ||
353 | do_lo_send = do_lo_send_aops; | 277 | if (lo->transfer != transfer_none) { |
354 | if (!(lo->lo_flags & LO_FLAGS_USE_AOPS)) { | 278 | page = alloc_page(GFP_NOIO | __GFP_HIGHMEM); |
279 | if (unlikely(!page)) | ||
280 | goto fail; | ||
281 | kmap(page); | ||
282 | do_lo_send = do_lo_send_write; | ||
283 | } else { | ||
355 | do_lo_send = do_lo_send_direct_write; | 284 | do_lo_send = do_lo_send_direct_write; |
356 | if (lo->transfer != transfer_none) { | ||
357 | page = alloc_page(GFP_NOIO | __GFP_HIGHMEM); | ||
358 | if (unlikely(!page)) | ||
359 | goto fail; | ||
360 | kmap(page); | ||
361 | do_lo_send = do_lo_send_write; | ||
362 | } | ||
363 | } | 285 | } |
286 | |||
364 | bio_for_each_segment(bvec, bio, i) { | 287 | bio_for_each_segment(bvec, bio, i) { |
365 | ret = do_lo_send(lo, bvec, pos, page); | 288 | ret = do_lo_send(lo, bvec, pos, page); |
366 | if (ret < 0) | 289 | if (ret < 0) |
@@ -849,35 +772,23 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, | |||
849 | mapping = file->f_mapping; | 772 | mapping = file->f_mapping; |
850 | inode = mapping->host; | 773 | inode = mapping->host; |
851 | 774 | ||
852 | if (!(file->f_mode & FMODE_WRITE)) | ||
853 | lo_flags |= LO_FLAGS_READ_ONLY; | ||
854 | |||
855 | error = -EINVAL; | 775 | error = -EINVAL; |
856 | if (S_ISREG(inode->i_mode) || S_ISBLK(inode->i_mode)) { | 776 | if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) |
857 | const struct address_space_operations *aops = mapping->a_ops; | 777 | goto out_putf; |
858 | |||
859 | if (aops->write_begin) | ||
860 | lo_flags |= LO_FLAGS_USE_AOPS; | ||
861 | if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write) | ||
862 | lo_flags |= LO_FLAGS_READ_ONLY; | ||
863 | 778 | ||
864 | lo_blocksize = S_ISBLK(inode->i_mode) ? | 779 | if (!(file->f_mode & FMODE_WRITE) || !(mode & FMODE_WRITE) || |
865 | inode->i_bdev->bd_block_size : PAGE_SIZE; | 780 | !file->f_op->write) |
781 | lo_flags |= LO_FLAGS_READ_ONLY; | ||
866 | 782 | ||
867 | error = 0; | 783 | lo_blocksize = S_ISBLK(inode->i_mode) ? |
868 | } else { | 784 | inode->i_bdev->bd_block_size : PAGE_SIZE; |
869 | goto out_putf; | ||
870 | } | ||
871 | 785 | ||
786 | error = -EFBIG; | ||
872 | size = get_loop_size(lo, file); | 787 | size = get_loop_size(lo, file); |
873 | 788 | if ((loff_t)(sector_t)size != size) | |
874 | if ((loff_t)(sector_t)size != size) { | ||
875 | error = -EFBIG; | ||
876 | goto out_putf; | 789 | goto out_putf; |
877 | } | ||
878 | 790 | ||
879 | if (!(mode & FMODE_WRITE)) | 791 | error = 0; |
880 | lo_flags |= LO_FLAGS_READ_ONLY; | ||
881 | 792 | ||
882 | set_device_ro(bdev, (lo_flags & LO_FLAGS_READ_ONLY) != 0); | 793 | set_device_ro(bdev, (lo_flags & LO_FLAGS_READ_ONLY) != 0); |
883 | 794 | ||
diff --git a/include/linux/loop.h b/include/linux/loop.h index 683d69890119..a06880689115 100644 --- a/include/linux/loop.h +++ b/include/linux/loop.h | |||
@@ -73,7 +73,6 @@ struct loop_device { | |||
73 | */ | 73 | */ |
74 | enum { | 74 | enum { |
75 | LO_FLAGS_READ_ONLY = 1, | 75 | LO_FLAGS_READ_ONLY = 1, |
76 | LO_FLAGS_USE_AOPS = 2, | ||
77 | LO_FLAGS_AUTOCLEAR = 4, | 76 | LO_FLAGS_AUTOCLEAR = 4, |
78 | }; | 77 | }; |
79 | 78 | ||