Commit 66531c65 authored by Al Viro's avatar Al Viro
Browse files

iov_iter_npages(): don't bother with iterate_all_kinds()



note that in bvec case pages can be compound ones - we can't just assume
that each segment is covered by one (sub)page

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 3d671ca6
Loading
Loading
Loading
Loading
+54 −34
Original line number Diff line number Diff line
@@ -1864,19 +1864,56 @@ size_t hash_and_copy_to_iter(const void *addr, size_t bytes, void *hashp,
}
EXPORT_SYMBOL(hash_and_copy_to_iter);

int iov_iter_npages(const struct iov_iter *i, int maxpages)
static int iov_npages(const struct iov_iter *i, int maxpages)
{
	size_t size = i->count;
	size_t skip = i->iov_offset, size = i->count;
	const struct iovec *p;
	int npages = 0;

	if (!size)
		return 0;
	if (unlikely(iov_iter_is_discard(i)))
		return 0;
	for (p = i->iov; size; skip = 0, p++) {
		unsigned offs = offset_in_page(p->iov_base + skip);
		size_t len = min(p->iov_len - skip, size);

	if (unlikely(iov_iter_is_pipe(i))) {
		struct pipe_inode_info *pipe = i->pipe;
		if (len) {
			size -= len;
			npages += DIV_ROUND_UP(offs + len, PAGE_SIZE);
			if (unlikely(npages > maxpages))
				return maxpages;
		}
	}
	return npages;
}

static int bvec_npages(const struct iov_iter *i, int maxpages)
{
	size_t skip = i->iov_offset, size = i->count;
	const struct bio_vec *p;
	int npages = 0;

	for (p = i->bvec; size; skip = 0, p++) {
		unsigned offs = (p->bv_offset + skip) % PAGE_SIZE;
		size_t len = min(p->bv_len - skip, size);

		size -= len;
		npages += DIV_ROUND_UP(offs + len, PAGE_SIZE);
		if (unlikely(npages > maxpages))
			return maxpages;
	}
	return npages;
}

int iov_iter_npages(const struct iov_iter *i, int maxpages)
{
	if (unlikely(!i->count))
		return 0;
	/* iovec and kvec have identical layouts */
	if (likely(iter_is_iovec(i) || iov_iter_is_kvec(i)))
		return iov_npages(i, maxpages);
	if (iov_iter_is_bvec(i))
		return bvec_npages(i, maxpages);
	if (iov_iter_is_pipe(i)) {
		unsigned int iter_head;
		int npages;
		size_t off;

		if (!sanity(i))
@@ -1884,11 +1921,13 @@ int iov_iter_npages(const struct iov_iter *i, int maxpages)

		data_start(i, &iter_head, &off);
		/* some of this one + all after this one */
		npages = pipe_space_for_user(iter_head, pipe->tail, pipe);
		if (npages >= maxpages)
			return maxpages;
	} else if (unlikely(iov_iter_is_xarray(i))) {
		npages = pipe_space_for_user(iter_head, i->pipe->tail, i->pipe);
		return min(npages, maxpages);
	}
	if (iov_iter_is_xarray(i)) {
		size_t size = i->count;
		unsigned offset;
		int npages;

		offset = (i->xarray_start + i->iov_offset) & ~PAGE_MASK;

@@ -1900,28 +1939,9 @@ int iov_iter_npages(const struct iov_iter *i, int maxpages)
			if (size)
				npages++;
		}
		if (npages >= maxpages)
			return maxpages;
	} else iterate_all_kinds(i, size, v, ({
		unsigned long p = (unsigned long)v.iov_base;
		npages += DIV_ROUND_UP(p + v.iov_len, PAGE_SIZE)
			- p / PAGE_SIZE;
		if (npages >= maxpages)
			return maxpages;
	0;}),({
		npages++;
		if (npages >= maxpages)
			return maxpages;
	}),({
		unsigned long p = (unsigned long)v.iov_base;
		npages += DIV_ROUND_UP(p + v.iov_len, PAGE_SIZE)
			- p / PAGE_SIZE;
		if (npages >= maxpages)
			return maxpages;
	}),
	0
	)
	return npages;
		return min(npages, maxpages);
	}
	return 0;
}
EXPORT_SYMBOL(iov_iter_npages);