diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2017-02-18 01:44:03 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2017-10-11 22:36:54 -0400 |
commit | 09cf698a594276139b7dfafb232af3fe4fbc4438 (patch) | |
tree | 163c2dbfca800af81aed88f993e6db004093c35b | |
parent | 6d1ff4d6f37dc3c14d9fc08dbbbb920a12c21f84 (diff) | |
download | op-kernel-dev-09cf698a594276139b7dfafb232af3fe4fbc4438.zip op-kernel-dev-09cf698a594276139b7dfafb232af3fe4fbc4438.tar.gz |
new primitive: iov_iter_for_each_range()
For kvec and bvec: feeds segments to given callback as long as it
returns 0. For iovec and pipe: fails.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | include/linux/uio.h | 4 | ||||
-rw-r--r-- | lib/iov_iter.c | 22 |
2 files changed, 26 insertions, 0 deletions
diff --git a/include/linux/uio.h b/include/linux/uio.h index 5885dae..e67e12a 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h @@ -244,4 +244,8 @@ int compat_import_iovec(int type, const struct compat_iovec __user * uvector, int import_single_range(int type, void __user *buf, size_t len, struct iovec *iov, struct iov_iter *i); +int iov_iter_for_each_range(struct iov_iter *i, size_t bytes, + int (*f)(struct kvec *vec, void *context), + void *context); + #endif diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 1c1c06d..9702126 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -1446,3 +1446,25 @@ int import_single_range(int rw, void __user *buf, size_t len, return 0; } EXPORT_SYMBOL(import_single_range); + +int iov_iter_for_each_range(struct iov_iter *i, size_t bytes, + int (*f)(struct kvec *vec, void *context), + void *context) +{ + struct kvec w; + int err = -EINVAL; + if (!bytes) + return 0; + + iterate_all_kinds(i, bytes, v, -EINVAL, ({ + w.iov_base = kmap(v.bv_page) + v.bv_offset; + w.iov_len = v.bv_len; + err = f(&w, context); + kunmap(v.bv_page); + err;}), ({ + w = v; + err = f(&w, context);}) + ) + return err; +} +EXPORT_SYMBOL(iov_iter_for_each_range); |