Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 28ac4ad0 authored by Al Viro's avatar Al Viro Committed by Greg Kroah-Hartman
Browse files

lustre: simplify the living hell out of ksocknal_lib_recv_kiov()



... by using ITER_BVEC recvmsg

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent fd25dc34
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -86,9 +86,11 @@ struct ksock_sched { /* per scheduler state */
	int                     kss_nconns;     /* # connections assigned to
						 * this scheduler */
	struct ksock_sched_info *kss_info;	/* owner of it */
	struct page             *kss_rx_scratch_pgs[LNET_MAX_IOV];
	union {
		struct bio_vec          kss_scratch_bvec[LNET_MAX_IOV];
		struct kvec             kss_scratch_iov[LNET_MAX_IOV];
	};
};

struct ksock_sched_info {
	int                     ksi_nthreads_max; /* max allowed threads */
+8 −90
Original line number Diff line number Diff line
@@ -259,67 +259,11 @@ ksocknal_lib_recv_iov(struct ksock_conn *conn)
	return rc;
}

static void
ksocknal_lib_kiov_vunmap(void *addr)
{
	if (!addr)
		return;

	vunmap(addr);
}

static void *
ksocknal_lib_kiov_vmap(lnet_kiov_t *kiov, int niov,
		       struct kvec *iov, struct page **pages)
{
	void *addr;
	int nob;
	int i;

	if (!*ksocknal_tunables.ksnd_zc_recv || !pages)
		return NULL;

	LASSERT(niov <= LNET_MAX_IOV);

	if (niov < 2 ||
	    niov < *ksocknal_tunables.ksnd_zc_recv_min_nfrags)
		return NULL;

	for (nob = i = 0; i < niov; i++) {
		if ((kiov[i].kiov_offset && i > 0) ||
		    (kiov[i].kiov_offset + kiov[i].kiov_len != PAGE_SIZE && i < niov - 1))
			return NULL;

		pages[i] = kiov[i].kiov_page;
		nob += kiov[i].kiov_len;
	}

	addr = vmap(pages, niov, VM_MAP, PAGE_KERNEL);
	if (!addr)
		return NULL;

	iov->iov_base = addr + kiov[0].kiov_offset;
	iov->iov_len = nob;

	return addr;
}

int
ksocknal_lib_recv_kiov(struct ksock_conn *conn)
{
#if SOCKNAL_SINGLE_FRAG_RX || !SOCKNAL_RISK_KMAP_DEADLOCK
	struct kvec scratch;
	struct kvec *scratchiov = &scratch;
	struct page **pages = NULL;
	unsigned int niov = 1;
#else
#ifdef CONFIG_HIGHMEM
#warning "XXX risk of kmap deadlock on multiple frags..."
#endif
	struct kvec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
	struct page **pages = conn->ksnc_scheduler->kss_rx_scratch_pgs;
	struct bio_vec *bv = conn->ksnc_scheduler->kss_scratch_bvec;
	unsigned int niov = conn->ksnc_rx_nkiov;
#endif
	lnet_kiov_t   *kiov = conn->ksnc_rx_kiov;
	struct msghdr msg = {
		.msg_flags = 0
@@ -328,44 +272,26 @@ ksocknal_lib_recv_kiov(struct ksock_conn *conn)
	int i;
	int rc;
	void *base;
	void *addr;
	int sum;
	int fragnob;
	int n;

	/*
	 * NB we can't trust socket ops to either consume our iovs
	 * or leave them alone.
	 */
	addr = ksocknal_lib_kiov_vmap(kiov, niov, scratchiov, pages);
	if (addr) {
		nob = scratchiov[0].iov_len;
		n = 1;

	} else {
	for (nob = i = 0; i < niov; i++) {
			nob += scratchiov[i].iov_len = kiov[i].kiov_len;
			scratchiov[i].iov_base = kmap(kiov[i].kiov_page) +
						 kiov[i].kiov_offset;
		nob += bv[i].bv_len = kiov[i].kiov_len;
		bv[i].bv_page = kiov[i].kiov_page;
		bv[i].bv_offset = kiov[i].kiov_offset;
	}
	n = niov;
	}

	LASSERT(nob <= conn->ksnc_rx_nob_wanted);

	rc = kernel_recvmsg(conn->ksnc_sock, &msg, (struct kvec *)scratchiov,
			    n, nob, MSG_DONTWAIT);
	iov_iter_bvec(&msg.msg_iter, READ | ITER_BVEC, bv, n, nob);
	rc = sock_recvmsg(conn->ksnc_sock, &msg, MSG_DONTWAIT);

	if (conn->ksnc_msg.ksm_csum) {
		for (i = 0, sum = rc; sum > 0; i++, sum -= fragnob) {
			LASSERT(i < niov);

			/*
			 * Dang! have to kmap again because I have nowhere to
			 * stash the mapped address.  But by doing it while the
			 * page is still mapped, the kernel just bumps the map
			 * count and returns me the address it stashed.
			 */
			base = kmap(kiov[i].kiov_page) + kiov[i].kiov_offset;
			fragnob = kiov[i].kiov_len;
			if (fragnob > sum)
@@ -377,14 +303,6 @@ ksocknal_lib_recv_kiov(struct ksock_conn *conn)
			kunmap(kiov[i].kiov_page);
		}
	}

	if (addr) {
		ksocknal_lib_kiov_vunmap(addr);
	} else {
		for (i = 0; i < niov; i++)
			kunmap(kiov[i].kiov_page);
	}

	return rc;
}