diff options
Diffstat (limited to 'drivers/block/loop.c')
-rw-r--r-- | drivers/block/loop.c | 73 |
1 files changed, 40 insertions, 33 deletions
diff --git a/drivers/block/loop.c b/drivers/block/loop.c index d9589017cc1e..018af27256c5 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c | |||
@@ -417,6 +417,40 @@ lo_receive(struct loop_device *lo, struct request *rq, int bsize, loff_t pos) | |||
417 | return 0; | 417 | return 0; |
418 | } | 418 | } |
419 | 419 | ||
420 | static int lo_discard(struct loop_device *lo, struct request *rq, loff_t pos) | ||
421 | { | ||
422 | /* | ||
423 | * We use punch hole to reclaim the free space used by the | ||
424 | * image a.k.a. discard. However we do not support discard if | ||
425 | * encryption is enabled, because it may give an attacker | ||
426 | * useful information. | ||
427 | */ | ||
428 | struct file *file = lo->lo_backing_file; | ||
429 | int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE; | ||
430 | int ret; | ||
431 | |||
432 | if ((!file->f_op->fallocate) || lo->lo_encrypt_key_size) { | ||
433 | ret = -EOPNOTSUPP; | ||
434 | goto out; | ||
435 | } | ||
436 | |||
437 | ret = file->f_op->fallocate(file, mode, pos, blk_rq_bytes(rq)); | ||
438 | if (unlikely(ret && ret != -EINVAL && ret != -EOPNOTSUPP)) | ||
439 | ret = -EIO; | ||
440 | out: | ||
441 | return ret; | ||
442 | } | ||
443 | |||
444 | static int lo_req_flush(struct loop_device *lo, struct request *rq) | ||
445 | { | ||
446 | struct file *file = lo->lo_backing_file; | ||
447 | int ret = vfs_fsync(file, 0); | ||
448 | if (unlikely(ret && ret != -EINVAL)) | ||
449 | ret = -EIO; | ||
450 | |||
451 | return ret; | ||
452 | } | ||
453 | |||
420 | static int do_req_filebacked(struct loop_device *lo, struct request *rq) | 454 | static int do_req_filebacked(struct loop_device *lo, struct request *rq) |
421 | { | 455 | { |
422 | loff_t pos; | 456 | loff_t pos; |
@@ -425,46 +459,19 @@ static int do_req_filebacked(struct loop_device *lo, struct request *rq) | |||
425 | pos = ((loff_t) blk_rq_pos(rq) << 9) + lo->lo_offset; | 459 | pos = ((loff_t) blk_rq_pos(rq) << 9) + lo->lo_offset; |
426 | 460 | ||
427 | if (rq->cmd_flags & REQ_WRITE) { | 461 | if (rq->cmd_flags & REQ_WRITE) { |
428 | struct file *file = lo->lo_backing_file; | ||
429 | |||
430 | if (rq->cmd_flags & REQ_FLUSH) { | ||
431 | ret = vfs_fsync(file, 0); | ||
432 | if (unlikely(ret && ret != -EINVAL)) { | ||
433 | ret = -EIO; | ||
434 | goto out; | ||
435 | } | ||
436 | } | ||
437 | 462 | ||
438 | /* | 463 | if (rq->cmd_flags & REQ_FLUSH) |
439 | * We use punch hole to reclaim the free space used by the | 464 | ret = lo_req_flush(lo, rq); |
440 | * image a.k.a. discard. However we do not support discard if | 465 | |
441 | * encryption is enabled, because it may give an attacker | ||
442 | * useful information. | ||
443 | */ | ||
444 | if (rq->cmd_flags & REQ_DISCARD) { | 466 | if (rq->cmd_flags & REQ_DISCARD) { |
445 | struct file *file = lo->lo_backing_file; | 467 | ret = lo_discard(lo, rq, pos); |
446 | int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE; | ||
447 | |||
448 | if ((!file->f_op->fallocate) || | ||
449 | lo->lo_encrypt_key_size) { | ||
450 | ret = -EOPNOTSUPP; | ||
451 | goto out; | ||
452 | } | ||
453 | ret = file->f_op->fallocate(file, mode, pos, | ||
454 | blk_rq_bytes(rq)); | ||
455 | if (unlikely(ret && ret != -EINVAL && | ||
456 | ret != -EOPNOTSUPP)) | ||
457 | ret = -EIO; | ||
458 | goto out; | 468 | goto out; |
459 | } | 469 | } |
460 | 470 | ||
461 | ret = lo_send(lo, rq, pos); | 471 | ret = lo_send(lo, rq, pos); |
462 | 472 | ||
463 | if ((rq->cmd_flags & REQ_FUA) && !ret) { | 473 | if ((rq->cmd_flags & REQ_FUA) && !ret) |
464 | ret = vfs_fsync(file, 0); | 474 | ret = lo_req_flush(lo, rq); |
465 | if (unlikely(ret && ret != -EINVAL)) | ||
466 | ret = -EIO; | ||
467 | } | ||
468 | } else | 475 | } else |
469 | ret = lo_receive(lo, rq, lo->lo_blocksize, pos); | 476 | ret = lo_receive(lo, rq, lo->lo_blocksize, pos); |
470 | 477 | ||