[PATCH 3/3] ARM: cacheflush: add new iovec-based cache flushing system call

Will Deacon
2013-05-23T10:52:54Z

On Wed, Mar 27, 2013 at 11:12:11AM +0000, Catalin Marinas wrote:
> On Mon, Mar 25, 2013 at 06:18:06PM +0000, Will Deacon wrote:
> > +static inline int
> > +do_cache_op_iov(const struct iovec __user *uiov, unsigned long cnt, int flags)
> > +{
> > + int i, ret = 0;
> > + unsigned long len = cnt * sizeof(struct iovec);
> > + struct iovec *iov = kmalloc(len, GFP_KERNEL);
> > +
> > + if (iov == NULL) {
> > + ret = -ENOMEM;
> > + goto out;
> > + }
> > +
> > + if (copy_from_user(iov, uiov, len)) {
> > + ret = -EFAULT;
> > + goto out_free;
> > + }
> > +
> > + for (i = 0; i < cnt; ++i) {
> > + unsigned long start = (unsigned long __force)iov[i].iov_base;
> > + unsigned long end = start + iov[i].iov_len;
> > + ret = do_cache_op(start, end, flags);
> > + if (ret)
> > + break;
> > + }
>
> Could you use get_user() on struct iovec fields directly to avoid
> kmalloc? It would be slightly faster.

I just had a look at this, but the problem is that we want to know the
entire (combined) region size so that we may just decide to flush the entire
cache, rather than iterate over each region line-by-line. This requires
copying the whole iovec into kernel space up front, so that we can iterate
over the regions with iov_length.

Will