1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
9 #include <sys/statvfs.h>
10 #include "workqueue.h"
12 #include "xfs_scrub.h"
16 #include "read_verify.h"
22 * Manages the data block read verification phase. The caller schedules
23 * verification requests, which are then scheduled to be run by a thread
24 * pool worker. Adjacent (or nearly adjacent) requests can be combined
25 * to reduce overhead when free space fragmentation is high. The thread
26 * pool takes care of issuing multiple IOs to the device, if possible.
30 * Perform all IO in 32M chunks. This cannot exceed 65536 sectors
31 * because that's the biggest SCSI VERIFY(16) we dare to send.
33 #define RVP_IO_MAX_SIZE (33554432)
34 #define RVP_IO_MAX_SECTORS (RVP_IO_MAX_SIZE >> BBSHIFT)
36 /* Tolerate 64k holes in adjacent read verify requests. */
37 #define RVP_IO_BATCH_LOCALITY (65536)
39 struct read_verify_pool
{
40 struct workqueue wq
; /* thread pool */
41 struct scrub_ctx
*ctx
; /* scrub context */
42 void *readbuf
; /* read buffer */
43 struct ptcounter
*verified_bytes
;
44 read_verify_ioerr_fn_t ioerr_fn
; /* io error callback */
45 size_t miniosz
; /* minimum io size, bytes */
48 /* Create a thread pool to run read verifiers. */
49 struct read_verify_pool
*
50 read_verify_pool_init(
51 struct scrub_ctx
*ctx
,
53 read_verify_ioerr_fn_t ioerr_fn
,
56 struct read_verify_pool
*rvp
;
60 rvp
= calloc(1, sizeof(struct read_verify_pool
));
64 error
= posix_memalign((void **)&rvp
->readbuf
, page_size
,
66 if (error
|| !rvp
->readbuf
)
68 rvp
->verified_bytes
= ptcounter_init(nproc
);
69 if (!rvp
->verified_bytes
)
71 rvp
->miniosz
= miniosz
;
73 rvp
->ioerr_fn
= ioerr_fn
;
74 /* Run in the main thread if we only want one thread. */
77 ret
= workqueue_create(&rvp
->wq
, (struct xfs_mount
*)rvp
, nproc
);
83 ptcounter_free(rvp
->verified_bytes
);
91 /* Finish up any read verification work. */
93 read_verify_pool_flush(
94 struct read_verify_pool
*rvp
)
96 workqueue_destroy(&rvp
->wq
);
99 /* Finish up any read verification work and tear it down. */
101 read_verify_pool_destroy(
102 struct read_verify_pool
*rvp
)
104 ptcounter_free(rvp
->verified_bytes
);
110 * Issue a read-verify IO in big batches.
114 struct workqueue
*wq
,
118 struct read_verify
*rv
= arg
;
119 struct read_verify_pool
*rvp
;
120 unsigned long long verified
= 0;
124 rvp
= (struct read_verify_pool
*)wq
->wq_ctx
;
125 while (rv
->io_length
> 0) {
126 len
= min(rv
->io_length
, RVP_IO_MAX_SIZE
);
127 dbg_printf("diskverify %d %"PRIu64
" %zu\n", rv
->io_disk
->d_fd
,
129 sz
= disk_read_verify(rv
->io_disk
, rvp
->readbuf
,
132 dbg_printf("IOERR %d %"PRIu64
" %zu\n",
135 /* IO error, so try the next logical block. */
137 rvp
->ioerr_fn(rvp
->ctx
, rv
->io_disk
, rv
->io_start
, len
,
138 errno
, rv
->io_end_arg
);
144 rv
->io_length
-= len
;
148 ptcounter_add(rvp
->verified_bytes
, verified
);
151 /* Queue a read verify request. */
154 struct read_verify_pool
*rvp
,
155 struct read_verify
*rv
)
157 struct read_verify
*tmp
;
160 dbg_printf("verify fd %d start %"PRIu64
" len %"PRIu64
"\n",
161 rv
->io_disk
->d_fd
, rv
->io_start
, rv
->io_length
);
163 tmp
= malloc(sizeof(struct read_verify
));
165 rvp
->ioerr_fn(rvp
->ctx
, rv
->io_disk
, rv
->io_start
,
166 rv
->io_length
, errno
, rv
->io_end_arg
);
169 memcpy(tmp
, rv
, sizeof(*tmp
));
171 ret
= workqueue_add(&rvp
->wq
, read_verify
, 0, tmp
);
173 str_info(rvp
->ctx
, rvp
->ctx
->mntpoint
,
174 _("Could not queue read-verify work."));
183 * Issue an IO request. We'll batch subsequent requests if they're
184 * within 64k of each other
187 read_verify_schedule_io(
188 struct read_verify_pool
*rvp
,
189 struct read_verify
*rv
,
198 assert(rvp
->readbuf
);
199 req_end
= start
+ length
;
200 rv_end
= rv
->io_start
+ rv
->io_length
;
203 * If we have a stashed IO, we haven't changed fds, the error
204 * reporting is the same, and the two extents are close,
205 * we can combine them.
207 if (rv
->io_length
> 0 && disk
== rv
->io_disk
&&
208 end_arg
== rv
->io_end_arg
&&
209 ((start
>= rv
->io_start
&& start
<= rv_end
+ RVP_IO_BATCH_LOCALITY
) ||
210 (rv
->io_start
>= start
&&
211 rv
->io_start
<= req_end
+ RVP_IO_BATCH_LOCALITY
))) {
212 rv
->io_start
= min(rv
->io_start
, start
);
213 rv
->io_length
= max(req_end
, rv_end
) - rv
->io_start
;
215 /* Otherwise, issue the stashed IO (if there is one) */
216 if (rv
->io_length
> 0)
217 return read_verify_queue(rvp
, rv
);
219 /* Stash the new IO. */
221 rv
->io_start
= start
;
222 rv
->io_length
= length
;
223 rv
->io_end_arg
= end_arg
;
229 /* Force any stashed IOs into the verifier. */
231 read_verify_force_io(
232 struct read_verify_pool
*rvp
,
233 struct read_verify
*rv
)
237 assert(rvp
->readbuf
);
238 if (rv
->io_length
== 0)
241 moveon
= read_verify_queue(rvp
, rv
);
247 /* How many bytes has this process verified? */
250 struct read_verify_pool
*rvp
)
252 return ptcounter_value(rvp
->verified_bytes
);