Messages in this thread | | | Date | Fri, 11 Dec 2020 03:24:00 +0000 | From | Matthew Wilcox <> | 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; } }
| |