lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date:   Fri, 11 Dec 2020 03:24:00 +0000
From:   Matthew Wilcox <willy@...radead.org>
To:     David Howells <dhowells@...hat.com>
Cc:     Pavel Begunkov <asml.silence@...il.com>,
        Jens Axboe <axboe@...nel.dk>,
        Alexander Viro <viro@...iv.linux.org.uk>,
        Linus Torvalds <torvalds@...ux-foundation.org>,
        linux-fsdevel@...r.kernel.org, linux-block@...r.kernel.org,
        linux-kernel@...r.kernel.org
Subject: Re: [PATCH 00/29] RFC: iov_iter: Switch to using an ops table

On Sat, Nov 21, 2020 at 02:13:21PM +0000, David Howells wrote:
> I had a go switching the iov_iter stuff away from using a type bitmask to
> using an ops table to get rid of the if-if-if-if chains that are all over
> the place.  After I pushed it, someone pointed me at Pavel's two patches.
> 
> I have another iterator class that I want to add - which would lengthen the
> if-if-if-if chains.  A lot of the time, there's a conditional clause at the
> beginning of a function that just jumps off to a type-specific handler or
> to reject the operation for that type.  An ops table can just point to that
> instead.

So, given the performance problem, how about turning this inside out?

struct iov_step {
	union {
		void *kaddr;
		void __user *uaddr;
	};
	unsigned int len;
	bool user_addr;
	bool kmap;
	struct page *page;
};

bool iov_iterate(struct iov_step *step, struct iov_iter *i, size_t max)
{
	if (step->page)
		kunmap(page)
	else if (step->kmap)
		kunmap_atomic(step->kaddr);

	if (max == 0)
		return false;

	if (i->type & ITER_IOVEC) {
		step->user_addr = true;
		step->uaddr = i->iov.iov_base + i->iov_offset;
		return true;
	}
	if (i->type & ITER_BVEC) {
		... get the page ...
	} else if (i->type & ITER_KVEC) {
		... get the page ...
	} else ...

	kmap or kmap_atomic as appropriate ...
	...set kaddr & len ...

	return true;
}

size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i)
{
	struct iov_step step = {};

	while (iov_iterate(&step, i, bytes)) {
		if (user_addr)
			copy_from_user(addr, step.uaddr, step.len);
		else
			memcpy(addr, step.kaddr, step.len);
		bytes -= step.len;
	}
}

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ