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