550-loop-better-discard-for-block-devices.patch 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. From: Evan Green <[email protected]>
  2. Subject: [PATCH v5 0/2] loop: Better discard for block devices
  3. Date: Mon, 6 May 2019 11:27:35 -0700
  4. Message-Id: <[email protected]>
  5. This series addresses some errors seen when using the loop
  6. device directly backed by a block device.
  7. The first change titled "loop: Better discard for block devices"
  8. plumbs out the correct error message, and the second change prevents
  9. the error from occurring in many cases.
  10. The errors look like this:
  11. [ 90.880875] print_req_error: I/O error, dev loop5, sector 0
  12. The errors occur when trying to do a discard or write zeroes operation
  13. on a loop device backed by a block device that does not support write zeroes.
  14. Firstly, the error itself is incorrectly reported as I/O error, but is
  15. actually EOPNOTSUPP. The first patch plumbs out EOPNOTSUPP to properly
  16. report the error.
  17. The second patch called "loop: Better discard support for block devices"
  18. prevents these errors from occurring by mirroring the zeroing capabilities
  19. of the underlying block device into the loop device.
  20. Before this change, discard was always reported as being supported, and
  21. the loop device simply turns around and does an fallocate operation on the
  22. backing device. After this change, backing block devices that do support
  23. zeroing will continue to work as before, and continue to get all the
  24. benefits of doing that. Backing devices that do not support zeroing will
  25. fail earlier, avoiding hitting the loop device at all and ultimately
  26. avoiding this error in the logs.
  27. I can also confirm that this fixes test block/003 in the blktests, when
  28. running blktests on a loop device backed by a block device.
  29. Signed-off-by: Evan Green <[email protected]>
  30. Reviewed-by: Ming Lei <[email protected]>
  31. Reviewed-by: Bart Van Assche <[email protected]>
  32. Reviewed-by: Martin K. Petersen <[email protected]>
  33. Reviewed-by: Gwendal Grignou <[email protected]>
  34. Reviewed-by: Chaitanya Kulkarni <[email protected]>
  35. ---
  36. --- a/drivers/block/loop.c
  37. +++ b/drivers/block/loop.c
  38. @@ -416,19 +416,14 @@ out_free_page:
  39. return ret;
  40. }
  41. -static int lo_discard(struct loop_device *lo, struct request *rq, loff_t pos)
  42. +static int lo_discard(struct loop_device *lo, struct request *rq,
  43. + int mode, loff_t pos)
  44. {
  45. - /*
  46. - * We use punch hole to reclaim the free space used by the
  47. - * image a.k.a. discard. However we do not support discard if
  48. - * encryption is enabled, because it may give an attacker
  49. - * useful information.
  50. - */
  51. struct file *file = lo->lo_backing_file;
  52. - int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE;
  53. + struct request_queue *q = lo->lo_queue;
  54. int ret;
  55. - if ((!file->f_op->fallocate) || lo->lo_encrypt_key_size) {
  56. + if (!blk_queue_discard(q)) {
  57. ret = -EOPNOTSUPP;
  58. goto out;
  59. }
  60. @@ -457,7 +452,9 @@ static void lo_complete_rq(struct reques
  61. if (!cmd->use_aio || cmd->ret < 0 || cmd->ret == blk_rq_bytes(rq) ||
  62. req_op(rq) != REQ_OP_READ) {
  63. - if (cmd->ret < 0)
  64. + if (cmd->ret == -EOPNOTSUPP)
  65. + ret = BLK_STS_NOTSUPP;
  66. + else if (cmd->ret < 0)
  67. ret = BLK_STS_IOERR;
  68. goto end_io;
  69. }
  70. @@ -597,8 +594,13 @@ static int do_req_filebacked(struct loop
  71. case REQ_OP_FLUSH:
  72. return lo_req_flush(lo, rq);
  73. case REQ_OP_DISCARD:
  74. + return lo_discard(lo, rq,
  75. + FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, pos);
  76. +
  77. case REQ_OP_WRITE_ZEROES:
  78. - return lo_discard(lo, rq, pos);
  79. + return lo_discard(lo, rq,
  80. + FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE, pos);
  81. +
  82. case REQ_OP_WRITE:
  83. if (lo->transfer)
  84. return lo_write_transfer(lo, rq, pos);
  85. @@ -853,6 +855,21 @@ static void loop_config_discard(struct l
  86. struct file *file = lo->lo_backing_file;
  87. struct inode *inode = file->f_mapping->host;
  88. struct request_queue *q = lo->lo_queue;
  89. + struct request_queue *backingq;
  90. +
  91. + /*
  92. + * If the backing device is a block device, mirror its zeroing
  93. + * capability. REQ_OP_DISCARD translates to a zero-out even when backed
  94. + * by block devices to keep consistent behavior with file-backed loop
  95. + * devices.
  96. + */
  97. + if (S_ISBLK(inode->i_mode) && !lo->lo_encrypt_key_size) {
  98. + backingq = bdev_get_queue(inode->i_bdev);
  99. + blk_queue_max_discard_sectors(q,
  100. + backingq->limits.max_write_zeroes_sectors);
  101. +
  102. + blk_queue_max_write_zeroes_sectors(q,
  103. + backingq->limits.max_write_zeroes_sectors);
  104. /*
  105. * We use punch hole to reclaim the free space used by the
  106. @@ -860,22 +877,24 @@ static void loop_config_discard(struct l
  107. * encryption is enabled, because it may give an attacker
  108. * useful information.
  109. */
  110. - if ((!file->f_op->fallocate) ||
  111. - lo->lo_encrypt_key_size) {
  112. + } else if ((!file->f_op->fallocate) || lo->lo_encrypt_key_size) {
  113. q->limits.discard_granularity = 0;
  114. q->limits.discard_alignment = 0;
  115. blk_queue_max_discard_sectors(q, 0);
  116. blk_queue_max_write_zeroes_sectors(q, 0);
  117. - blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q);
  118. - return;
  119. - }
  120. - q->limits.discard_granularity = inode->i_sb->s_blocksize;
  121. - q->limits.discard_alignment = 0;
  122. + } else {
  123. + q->limits.discard_granularity = inode->i_sb->s_blocksize;
  124. + q->limits.discard_alignment = 0;
  125. - blk_queue_max_discard_sectors(q, UINT_MAX >> 9);
  126. - blk_queue_max_write_zeroes_sectors(q, UINT_MAX >> 9);
  127. - blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
  128. + blk_queue_max_discard_sectors(q, UINT_MAX >> 9);
  129. + blk_queue_max_write_zeroes_sectors(q, UINT_MAX >> 9);
  130. + }
  131. +
  132. + if (q->limits.max_write_zeroes_sectors)
  133. + blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
  134. + else
  135. + blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q);
  136. }
  137. static void loop_unprepare_queue(struct loop_device *lo)
  138. @@ -1893,7 +1912,10 @@ static void loop_handle_cmd(struct loop_
  139. failed:
  140. /* complete non-aio request */
  141. if (!cmd->use_aio || ret) {
  142. - cmd->ret = ret ? -EIO : 0;
  143. + if (ret == -EOPNOTSUPP)
  144. + cmd->ret = ret;
  145. + else
  146. + cmd->ret = ret ? -EIO : 0;
  147. blk_mq_complete_request(rq);
  148. }
  149. }