/* Notes made in the collector */ #define HIT_PENDING 0x01 /* A front op was still pending */ #define MADE_PROGRESS 0x04 /* Made progress cleaning up a stream or the folio set */ #define BUFFERED 0x08 /* The pagecache needs cleaning up */ #define NEED_RETRY 0x10 /* A front op requests retrying */ #define COPY_TO_CACHE 0x40 /* Need to copy subrequest to cache */ #define ABANDON_SREQ 0x80 /* Need to abandon untransferred part of subrequest */
folioq_clear(folioq, slot);
} else { // TODO: Use of PG_private_2 is deprecated. if (test_bit(NETFS_RREQ_FOLIO_COPY_TO_CACHE, &rreq->flags))
netfs_pgpriv2_copy_to_cache(rreq, folio);
}
/* Clean up the head folioq. If we clear an entire folioq, then *wecangetridofitprovidedit'snotalsothetailfolioq *beingfilledbytheissuer.
*/
folioq_clear(folioq, slot);
slot++; if (slot >= folioq_nr_slots(folioq)) {
folioq = rolling_buffer_delete_spent(&rreq->buffer); if (!folioq) goto done;
slot = 0;
trace_netfs_folioq(folioq, netfs_trace_folioq_read_progress);
}
/* Remove completed subrequests from the front of the stream and *advancethecompletionpoint.Westopwhenwehitsomethingthat's *inprogress.Theissuerthreadmaybeaddingstufftothetail *whilstwe'redoingthis.
*/
front = READ_ONCE(stream->front); while (front) {
size_t transferred;
if (netfs_check_subreq_in_progress(front))
notes |= HIT_PENDING;
smp_rmb(); /* Read counters after IN_PROGRESS flag. */
transferred = READ_ONCE(front->transferred);
/* If we can now collect the next folio, do so. We don't want *todeferthisaswehavetodecidewhetherweneedtocopy *tothecacheornot,andthatmaydifferbetweenadjacent *subreqs.
*/ if (notes & BUFFERED) {
size_t fsize = PAGE_SIZE << rreq->front_folio_order;
/* Clear the tail of a short read. */ if (!(notes & HIT_PENDING) &&
front->error == 0 &&
transferred < front->len &&
(test_bit(NETFS_SREQ_HIT_EOF, &front->flags) ||
test_bit(NETFS_SREQ_CLEAR_TAIL, &front->flags))) {
netfs_clear_unread(front);
transferred = front->transferred = front->len;
trace_netfs_sreq(front, netfs_sreq_trace_clear);
}
if (!(notes & BUFFERED))
rreq->cleaned_to = rreq->collected_to;
if (notes & NEED_RETRY) goto need_retry; if (notes & MADE_PROGRESS) {
netfs_wake_rreq_flag(rreq, NETFS_RREQ_PAUSE, netfs_rreq_trace_unpause); //cond_resched(); goto reassess;
}
out:
_leave(" = %x", notes); return;
need_retry: /* Okay... We're going to have to retry parts of the stream. Note *thatanypartiallycompletedopwillhavehadanywhollytransferred *foliosremovedfromit.
*/
_debug("retry");
netfs_retry_reads(rreq); goto out;
}
if (rreq->origin == NETFS_UNBUFFERED_READ ||
rreq->origin == NETFS_DIO_READ) { for (i = 0; i < rreq->direct_bv_count; i++) {
flush_dcache_page(rreq->direct_bv[i].bv_page); // TODO: cifs marks pages in the destination buffer // dirty under some circumstances after a read. Do we // need to do that too?
set_page_dirty(rreq->direct_bv[i].bv_page);
}
}
if (rreq->iocb) {
rreq->iocb->ki_pos += rreq->transferred; if (rreq->iocb->ki_complete) {
trace_netfs_rreq(rreq, netfs_rreq_trace_ki_complete);
rreq->iocb->ki_complete(
rreq->iocb, rreq->error ? rreq->error : rreq->transferred);
}
} if (rreq->netfs_ops->done)
rreq->netfs_ops->done(rreq); if (rreq->origin == NETFS_UNBUFFERED_READ ||
rreq->origin == NETFS_DIO_READ)
inode_dio_end(rreq->inode);
}
/* We're done when the app thread has finished posting subreqs and the *queueisempty.
*/ if (!test_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags)) returnfalse;
smp_rmb(); /* Read ALL_QUEUED before subreq lists. */
if (!list_empty(&stream->subrequests)) returnfalse;
/* Okay, declare that all I/O is complete. */
rreq->transferred = stream->transferred;
trace_netfs_rreq(rreq, netfs_rreq_trace_complete);
//netfs_rreq_is_still_valid(rreq);
switch (rreq->origin) { case NETFS_UNBUFFERED_READ: case NETFS_DIO_READ: case NETFS_READ_GAPS:
netfs_rreq_assess_dio(rreq); break; case NETFS_READ_SINGLE:
netfs_rreq_assess_single(rreq); break; default: break;
}
task_io_account_read(rreq->transferred);
netfs_wake_rreq_flag(rreq, NETFS_RREQ_IN_PROGRESS, netfs_rreq_trace_wake_ip); /* As we cleared NETFS_RREQ_IN_PROGRESS, we acquired its ref. */
trace_netfs_rreq(rreq, netfs_rreq_trace_done);
netfs_clear_subrequests(rreq);
netfs_unlock_abandoned_read_pages(rreq); if (unlikely(rreq->copy_to_cache))
netfs_pgpriv2_end_copy_to_cache(rreq); returntrue;
}
netfs_see_request(rreq, netfs_rreq_trace_see_work); if (netfs_check_rreq_in_progress(rreq)) { if (netfs_read_collection(rreq)) /* Drop the ref from the IN_PROGRESS flag. */
netfs_put_request(rreq, netfs_rreq_trace_put_work_ip); else
netfs_see_request(rreq, netfs_rreq_trace_see_work_complete);
}
}
/* If we are at the head of the queue, wake up the collector, *gettingareftoitifweweretheonestodoso.
*/ if (subreq->start + subreq->transferred > rreq->cleaned_to + fsize &&
(rreq->origin == NETFS_READAHEAD ||
rreq->origin == NETFS_READPAGE ||
rreq->origin == NETFS_READ_FOR_WRITE) &&
list_is_first(&subreq->rreq_link, &stream->subrequests)
) {
__set_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags);
netfs_wake_collector(rreq);
}
}
EXPORT_SYMBOL(netfs_read_subreq_progress);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.