aio: Fix more synchronization issues in aio_biowakeup.
- Use atomic_store to set job->error. atomic_set does an or operation, not assignment. - Use refcount_* to manage job->nbio. This ensures proper memory barriers are present so that the last bio won't see a possibly stale value of job->error. - Don't re-read job->error after reading it via atomic_load. Reported by: markj (1) Reviewed by: mjg, markj Differential Revision: https://reviews.freebsd.org/D38611
This commit is contained in:
parent
059320b8c8
commit
98844e99d4
@ -1281,7 +1281,7 @@ aio_qbio(struct proc *p, struct kaiocb *job)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bios = malloc(sizeof(struct bio *) * iovcnt, M_TEMP, M_WAITOK);
|
bios = malloc(sizeof(struct bio *) * iovcnt, M_TEMP, M_WAITOK);
|
||||||
atomic_store_int(&job->nbio, iovcnt);
|
refcount_init(&job->nbio, iovcnt);
|
||||||
for (i = 0; i < iovcnt; i++) {
|
for (i = 0; i < iovcnt; i++) {
|
||||||
struct vm_page** pages;
|
struct vm_page** pages;
|
||||||
struct bio *bp;
|
struct bio *bp;
|
||||||
@ -2489,15 +2489,16 @@ aio_biowakeup(struct bio *bp)
|
|||||||
* error of whichever failed bio completed last.
|
* error of whichever failed bio completed last.
|
||||||
*/
|
*/
|
||||||
if (flags & BIO_ERROR)
|
if (flags & BIO_ERROR)
|
||||||
atomic_set_int(&job->error, bio_error);
|
atomic_store_int(&job->error, bio_error);
|
||||||
if (opcode & LIO_WRITE)
|
if (opcode & LIO_WRITE)
|
||||||
atomic_add_int(&job->outblock, nblks);
|
atomic_add_int(&job->outblock, nblks);
|
||||||
else
|
else
|
||||||
atomic_add_int(&job->inblock, nblks);
|
atomic_add_int(&job->inblock, nblks);
|
||||||
|
|
||||||
if (atomic_fetchadd_int(&job->nbio, -1) == 1) {
|
if (refcount_release(&job->nbio)) {
|
||||||
if (atomic_load_int(&job->error))
|
bio_error = atomic_load_int(&job->error);
|
||||||
aio_complete(job, -1, job->error);
|
if (bio_error != 0)
|
||||||
|
aio_complete(job, -1, bio_error);
|
||||||
else
|
else
|
||||||
aio_complete(job, atomic_load_long(&job->nbytes), 0);
|
aio_complete(job, atomic_load_long(&job->nbytes), 0);
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,7 @@ struct kaiocb {
|
|||||||
aio_handle_fn_t *handle_fn; /* (c) backend handle function */
|
aio_handle_fn_t *handle_fn; /* (c) backend handle function */
|
||||||
union { /* Backend-specific data fields */
|
union { /* Backend-specific data fields */
|
||||||
struct { /* BIO backend */
|
struct { /* BIO backend */
|
||||||
int nbio; /* Number of remaining bios */
|
volatile u_int nbio; /* Number of remaining bios */
|
||||||
int error; /* Worst error of all bios */
|
int error; /* Worst error of all bios */
|
||||||
long nbytes; /* Bytes completed so far */
|
long nbytes; /* Bytes completed so far */
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user