Commit 2f5705a5 authored by David Howells's avatar David Howells
Browse files

afs: Use a bvec rather than a kvec in afs_send_pages()



Use a bvec rather than a kvec in afs_send_pages() as we don't then have to
call kmap() in advance.  This allows us to pass the array of contiguous
pages that we extracted through to rxrpc in one go rather than passing a
single page at a time.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent 6a0e3999
Loading
Loading
Loading
Loading
+52 −45
Original line number Diff line number Diff line
@@ -259,67 +259,74 @@ void afs_flat_call_destructor(struct afs_call *call)
	call->buffer = NULL;
}

#define AFS_BVEC_MAX 8

/*
 * Load the given bvec with the next few pages.
 */
static void afs_load_bvec(struct afs_call *call, struct msghdr *msg,
			  struct bio_vec *bv, pgoff_t first, pgoff_t last,
			  unsigned offset)
{
	struct page *pages[AFS_BVEC_MAX];
	unsigned int nr, n, i, to, bytes = 0;

	nr = min_t(pgoff_t, last - first + 1, AFS_BVEC_MAX);
	n = find_get_pages_contig(call->mapping, first, nr, pages);
	ASSERTCMP(n, ==, nr);

	msg->msg_flags |= MSG_MORE;
	for (i = 0; i < nr; i++) {
		to = PAGE_SIZE;
		if (first + i >= last) {
			to = call->last_to;
			msg->msg_flags &= ~MSG_MORE;
		}
		bv[i].bv_page = pages[i];
		bv[i].bv_len = to - offset;
		bv[i].bv_offset = offset;
		bytes += to - offset;
		offset = 0;
	}

	iov_iter_bvec(&msg->msg_iter, WRITE | ITER_BVEC, bv, nr, bytes);
}

/*
 * attach the data from a bunch of pages on an inode to a call
 */
static int afs_send_pages(struct afs_call *call, struct msghdr *msg)
{
	struct page *pages[8];
	unsigned count, n, loop, offset, to;
	struct bio_vec bv[AFS_BVEC_MAX];
	unsigned int bytes, nr, loop, offset;
	pgoff_t first = call->first, last = call->last;
	int ret;

	_enter("");

	offset = call->first_offset;
	call->first_offset = 0;

	do {
		_debug("attach %lx-%lx", first, last);

		count = last - first + 1;
		if (count > ARRAY_SIZE(pages))
			count = ARRAY_SIZE(pages);
		n = find_get_pages_contig(call->mapping, first, count, pages);
		ASSERTCMP(n, ==, count);

		loop = 0;
		do {
			struct bio_vec bvec = {.bv_page = pages[loop],
					       .bv_offset = offset};
			msg->msg_flags = 0;
			to = PAGE_SIZE;
			if (first + loop >= last)
				to = call->last_to;
			else
				msg->msg_flags = MSG_MORE;
			bvec.bv_len = to - offset;
		afs_load_bvec(call, msg, bv, first, last, offset);
		offset = 0;
		bytes = msg->msg_iter.count;
		nr = msg->msg_iter.nr_segs;

			_debug("- range %u-%u%s",
			       offset, to, msg->msg_flags ? " [more]" : "");
			iov_iter_bvec(&msg->msg_iter, WRITE | ITER_BVEC,
				      &bvec, 1, to - offset);

			/* have to change the state *before* sending the last
		/* Have to change the state *before* sending the last
		 * packet as RxRPC might give us the reply before it
			 * returns from sending the request */
			if (first + loop >= last)
		 * returns from sending the request.
		 */
		if (first + nr >= last)
			call->state = AFS_CALL_AWAIT_REPLY;
		ret = rxrpc_kernel_send_data(afs_socket, call->rxcall,
						     msg, to - offset);
					     msg, bytes);
		for (loop = 0; loop < nr; loop++)
			put_page(bv[loop].bv_page);
		if (ret < 0)
			break;
		} while (++loop < count);
		first += count;

		for (loop = 0; loop < count; loop++)
			put_page(pages[loop]);
		if (ret < 0)
			break;
		first += nr;
	} while (first <= last);

	_leave(" = %d", ret);
	return ret;
}