Commit 241699cd authored by Al Viro's avatar Al Viro

new iov_iter flavour: pipe-backed

iov_iter variant for passing data into pipe.  copy_to_iter()
copies data into page(s) it has allocated and stuffs them into
the pipe; copy_page_to_iter() stuffs there a reference to the
page given to it.  Both will try to coalesce if possible.
iov_iter_zero() is similar to copy_to_iter(); iov_iter_get_pages()
and friends will do as copy_to_iter() would have and return the
pages where the data would've been copied.  iov_iter_advance()
will truncate everything past the spot it has advanced to.

New primitive: iov_iter_pipe(), used for initializing those.
pipe should be locked all along.

Running out of space acts as fault would for iovec-backed ones;
in other words, giving it to ->read_iter() may result in short
read if the pipe overflows, or -EFAULT if it happens with nothing
copied there.

In other words, ->read_iter() on those acts pretty much like
->splice_read().  Moreover, all generic_file_splice_read() users,
as well as many other ->splice_read() instances can be switched
to that scheme - that'll happen in the next commit.
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent d82718e3
...@@ -524,7 +524,7 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos, ...@@ -524,7 +524,7 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
} }
EXPORT_SYMBOL(generic_file_splice_read); EXPORT_SYMBOL(generic_file_splice_read);
static const struct pipe_buf_operations default_pipe_buf_ops = { const struct pipe_buf_operations default_pipe_buf_ops = {
.can_merge = 0, .can_merge = 0,
.confirm = generic_pipe_buf_confirm, .confirm = generic_pipe_buf_confirm,
.release = generic_pipe_buf_release, .release = generic_pipe_buf_release,
......
...@@ -85,4 +85,5 @@ extern void splice_shrink_spd(struct splice_pipe_desc *); ...@@ -85,4 +85,5 @@ extern void splice_shrink_spd(struct splice_pipe_desc *);
extern void spd_release_page(struct splice_pipe_desc *, unsigned int); extern void spd_release_page(struct splice_pipe_desc *, unsigned int);
extern const struct pipe_buf_operations page_cache_pipe_buf_ops; extern const struct pipe_buf_operations page_cache_pipe_buf_ops;
extern const struct pipe_buf_operations default_pipe_buf_ops;
#endif #endif
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <uapi/linux/uio.h> #include <uapi/linux/uio.h>
struct page; struct page;
struct pipe_inode_info;
struct kvec { struct kvec {
void *iov_base; /* and that should *never* hold a userland pointer */ void *iov_base; /* and that should *never* hold a userland pointer */
...@@ -23,6 +24,7 @@ enum { ...@@ -23,6 +24,7 @@ enum {
ITER_IOVEC = 0, ITER_IOVEC = 0,
ITER_KVEC = 2, ITER_KVEC = 2,
ITER_BVEC = 4, ITER_BVEC = 4,
ITER_PIPE = 8,
}; };
struct iov_iter { struct iov_iter {
...@@ -33,8 +35,12 @@ struct iov_iter { ...@@ -33,8 +35,12 @@ struct iov_iter {
const struct iovec *iov; const struct iovec *iov;
const struct kvec *kvec; const struct kvec *kvec;
const struct bio_vec *bvec; const struct bio_vec *bvec;
struct pipe_inode_info *pipe;
}; };
union {
unsigned long nr_segs; unsigned long nr_segs;
int idx;
};
}; };
/* /*
...@@ -64,7 +70,7 @@ static inline struct iovec iov_iter_iovec(const struct iov_iter *iter) ...@@ -64,7 +70,7 @@ static inline struct iovec iov_iter_iovec(const struct iov_iter *iter)
} }
#define iov_for_each(iov, iter, start) \ #define iov_for_each(iov, iter, start) \
if (!((start).type & ITER_BVEC)) \ if (!((start).type & (ITER_BVEC | ITER_PIPE))) \
for (iter = (start); \ for (iter = (start); \
(iter).count && \ (iter).count && \
((iov = iov_iter_iovec(&(iter))), 1); \ ((iov = iov_iter_iovec(&(iter))), 1); \
...@@ -94,6 +100,8 @@ void iov_iter_kvec(struct iov_iter *i, int direction, const struct kvec *kvec, ...@@ -94,6 +100,8 @@ void iov_iter_kvec(struct iov_iter *i, int direction, const struct kvec *kvec,
unsigned long nr_segs, size_t count); unsigned long nr_segs, size_t count);
void iov_iter_bvec(struct iov_iter *i, int direction, const struct bio_vec *bvec, void iov_iter_bvec(struct iov_iter *i, int direction, const struct bio_vec *bvec,
unsigned long nr_segs, size_t count); unsigned long nr_segs, size_t count);
void iov_iter_pipe(struct iov_iter *i, int direction, struct pipe_inode_info *pipe,
size_t count);
ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages, ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages,
size_t maxsize, unsigned maxpages, size_t *start); size_t maxsize, unsigned maxpages, size_t *start);
ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages, ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages,
...@@ -109,7 +117,7 @@ static inline size_t iov_iter_count(struct iov_iter *i) ...@@ -109,7 +117,7 @@ static inline size_t iov_iter_count(struct iov_iter *i)
static inline bool iter_is_iovec(struct iov_iter *i) static inline bool iter_is_iovec(struct iov_iter *i)
{ {
return !(i->type & (ITER_BVEC | ITER_KVEC)); return !(i->type & (ITER_BVEC | ITER_KVEC | ITER_PIPE));
} }
/* /*
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment