--- x/fs/netfs/read_collect.c +++ y/fs/netfs/read_collect.c @@ -289,6 +289,10 @@ reassess: /* Remove if completely consumed. */ stream->source = front->source; spin_lock(&rreq->lock); + if (front != stream->front) { + spin_unlock(&rreq->lock); + goto reassess; + } remove = front; trace_netfs_sreq(front, netfs_sreq_trace_discard); @@ -345,6 +349,7 @@ static void netfs_rreq_assess_dio(struct struct netfs_io_subrequest *subreq; struct netfs_io_stream *stream = &rreq->io_streams[0]; unsigned int i; + struct kiocb *iocb = NULL; /* Collect unbuffered reads and direct reads, adding up the transfer * sizes until we find the first short or failed subrequest. @@ -369,12 +374,16 @@ static void netfs_rreq_assess_dio(struct } } + spin_lock(&rreq->lock); if (rreq->iocb) { rreq->iocb->ki_pos += rreq->transferred; if (rreq->iocb->ki_complete) - rreq->iocb->ki_complete( - rreq->iocb, rreq->error ? rreq->error : rreq->transferred); + iocb = rreq->iocb; + rreq->iocb = NULL; } + spin_unlock(&rreq->lock); + if (iocb) + iocb->ki_complete(iocb, rreq->error ? rreq->error : rreq->transferred); if (rreq->netfs_ops->done) rreq->netfs_ops->done(rreq); if (rreq->origin == NETFS_DIO_READ)