fs/netfs/read_retry.c

Source file repositories/reference/linux-study-clean/fs/netfs/read_retry.c

File Facts

System
Linux kernel
Corpus path
fs/netfs/read_retry.c
Extension
.c
Size
9303 bytes
Lines
308
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

list_for_each_entry(subreq, &stream->subrequests, rreq_link) {
			if (test_bit(NETFS_SREQ_FAILED, &subreq->flags))
				break;
			if (__test_and_clear_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags)) {
				__clear_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags);
				subreq->retry_count++;
				netfs_reset_iter(subreq);
				netfs_get_subrequest(subreq, netfs_sreq_trace_get_resubmit);
				netfs_reissue_read(rreq, subreq);
			}
		}
		return;
	}

	/* Okay, we need to renegotiate all the download requests and flip any
	 * failed cache reads over to being download requests and negotiate
	 * those also.  All fully successful subreqs have been removed from the
	 * list and any spare data from those has been donated.
	 *
	 * What we do is decant the list and rebuild it one subreq at a time so
	 * that we don't end up with donations jumping over a gap we're busy
	 * populating with smaller subrequests.  In the event that the subreq
	 * we just launched finishes before we insert the next subreq, it'll
	 * fill in rreq->prev_donated instead.
	 *
	 * Note: Alternatively, we could split the tail subrequest right before
	 * we reissue it and fix up the donations under lock.
	 */
	next = stream->subrequests.next;

	do {
		struct netfs_io_subrequest *from, *to, *tmp;
		struct iov_iter source;
		unsigned long long start, len;
		size_t part;
		bool boundary = false, subreq_superfluous = false;

		/* Go through the subreqs and find the next span of contiguous
		 * buffer that we then rejig (cifs, for example, needs the
		 * rsize renegotiating) and reissue.
		 */
		from = list_entry(next, struct netfs_io_subrequest, rreq_link);
		to = from;
		start = from->start + from->transferred;
		len   = from->len   - from->transferred;

		_debug("from R=%08x[%x] s=%llx ctl=%zx/%zx",
		       rreq->debug_id, from->debug_index,
		       from->start, from->transferred, from->len);

		if (test_bit(NETFS_SREQ_FAILED, &from->flags) ||
		    !test_bit(NETFS_SREQ_NEED_RETRY, &from->flags)) {
			subreq = from;
			goto abandon;
		}

		list_for_each_continue(next, &stream->subrequests) {
			subreq = list_entry(next, struct netfs_io_subrequest, rreq_link);
			if (subreq->start + subreq->transferred != start + len ||
			    test_bit(NETFS_SREQ_BOUNDARY, &subreq->flags) ||
			    !test_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags))
				break;
			to = subreq;
			len += to->len;
		}

		_debug(" - range: %llx-%llx %llx", start, start + len - 1, len);

		/* Determine the set of buffers we're going to use.  Each
		 * subreq gets a subset of a single overall contiguous buffer.
		 */
		netfs_reset_iter(from);
		source = from->io_iter;
		source.count = len;

		/* Work through the sublist. */
		subreq = from;
		list_for_each_entry_from(subreq, &stream->subrequests, rreq_link) {
			if (!len) {
				subreq_superfluous = true;
				break;
			}
			subreq->source	= NETFS_DOWNLOAD_FROM_SERVER;
			subreq->start	= start - subreq->transferred;
			subreq->len	= len   + subreq->transferred;
			__clear_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags);
			__clear_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags);
			subreq->retry_count++;

			trace_netfs_sreq(subreq, netfs_sreq_trace_retry);

Annotation

Implementation Notes