fs/netfs/iterator.c

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

File Facts

System
Linux kernel
Corpus path
fs/netfs/iterator.c
Extension
.c
Size
8139 bytes
Lines
309
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: exported/initcall integration point
Status
integration 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

if (unlikely(ret <= 0)) {
			ret = ret ?: -EIO;
			break;
		}

		if (WARN(ret > count,
			 "%s: extract_pages overrun %zd > %zu bytes\n",
			 __func__, ret, count)) {
			ret = -EIO;
			break;
		}

		cur_npages = DIV_ROUND_UP(offset + ret, PAGE_SIZE);
		if (WARN(cur_npages > max_pages - npages,
			 "%s: extract_pages overrun %u > %u pages\n",
			 __func__, npages + cur_npages, max_pages)) {
			ret = -EIO;
			break;
		}

		count -= ret;
		ret += offset;

		for (i = 0; i < cur_npages; i++) {
			len = ret > PAGE_SIZE ? PAGE_SIZE : ret;
			bvec_set_page(bv + npages + i, *pages++, len - offset, offset);
			ret -= len;
			offset = 0;
		}

		npages += cur_npages;
	}

	/* Note: Don't try to clean up after EIO.  Either we got no pages, so
	 * nothing to clean up, or we got a buffer overrun, memory corruption
	 * and can't trust the stuff in the buffer (a WARN was emitted).
	 */

	if (ret < 0 && (ret == -ENOMEM || npages == 0)) {
		for (i = 0; i < npages; i++)
			unpin_user_page(bv[i].bv_page);
		kvfree(bv);
		return ret;
	}

	iov_iter_bvec(new, orig->data_source, bv, npages, orig_len - count);
	return npages;
}
EXPORT_SYMBOL_GPL(netfs_extract_user_iter);

/*
 * Select the span of a bvec iterator we're going to use.  Limit it by both maximum
 * size and maximum number of segments.  Returns the size of the span in bytes.
 */
static size_t netfs_limit_bvec(const struct iov_iter *iter, size_t start_offset,
			       size_t max_size, size_t max_segs)
{
	const struct bio_vec *bvecs = iter->bvec;
	unsigned int nbv = iter->nr_segs, ix = 0, nsegs = 0;
	size_t len, span = 0, n = iter->count;
	size_t skip = iter->iov_offset + start_offset;

	if (WARN_ON(!iov_iter_is_bvec(iter)) ||
	    WARN_ON(start_offset > n) ||
	    n == 0)
		return 0;

	while (n && ix < nbv && skip) {
		len = bvecs[ix].bv_len;
		if (skip < len)
			break;
		skip -= len;
		n -= len;
		ix++;
	}

	while (n && ix < nbv) {
		len = min3(n, bvecs[ix].bv_len - skip, max_size);
		span += len;
		nsegs++;
		ix++;
		if (span >= max_size || nsegs >= max_segs)
			break;
		skip = 0;
		n -= len;
	}

	return min(span, max_size);
}

Annotation

Implementation Notes