|
@@ -346,6 +346,16 @@ static const struct pipe_buf_operations anon_pipe_buf_ops = {
|
|
|
.get = generic_pipe_buf_get,
|
|
|
};
|
|
|
|
|
|
+static const struct pipe_buf_operations packet_pipe_buf_ops = {
|
|
|
+ .can_merge = 0,
|
|
|
+ .map = generic_pipe_buf_map,
|
|
|
+ .unmap = generic_pipe_buf_unmap,
|
|
|
+ .confirm = generic_pipe_buf_confirm,
|
|
|
+ .release = anon_pipe_buf_release,
|
|
|
+ .steal = generic_pipe_buf_steal,
|
|
|
+ .get = generic_pipe_buf_get,
|
|
|
+};
|
|
|
+
|
|
|
static ssize_t
|
|
|
pipe_read(struct kiocb *iocb, const struct iovec *_iov,
|
|
|
unsigned long nr_segs, loff_t pos)
|
|
@@ -407,6 +417,13 @@ redo:
|
|
|
ret += chars;
|
|
|
buf->offset += chars;
|
|
|
buf->len -= chars;
|
|
|
+
|
|
|
+ /* Was it a packet buffer? Clean up and exit */
|
|
|
+ if (buf->flags & PIPE_BUF_FLAG_PACKET) {
|
|
|
+ total_len = chars;
|
|
|
+ buf->len = 0;
|
|
|
+ }
|
|
|
+
|
|
|
if (!buf->len) {
|
|
|
buf->ops = NULL;
|
|
|
ops->release(pipe, buf);
|
|
@@ -459,6 +476,11 @@ redo:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static inline int is_packetized(struct file *file)
|
|
|
+{
|
|
|
+ return (file->f_flags & O_DIRECT) != 0;
|
|
|
+}
|
|
|
+
|
|
|
static ssize_t
|
|
|
pipe_write(struct kiocb *iocb, const struct iovec *_iov,
|
|
|
unsigned long nr_segs, loff_t ppos)
|
|
@@ -593,6 +615,11 @@ redo2:
|
|
|
buf->ops = &anon_pipe_buf_ops;
|
|
|
buf->offset = 0;
|
|
|
buf->len = chars;
|
|
|
+ buf->flags = 0;
|
|
|
+ if (is_packetized(filp)) {
|
|
|
+ buf->ops = &packet_pipe_buf_ops;
|
|
|
+ buf->flags = PIPE_BUF_FLAG_PACKET;
|
|
|
+ }
|
|
|
pipe->nrbufs = ++bufs;
|
|
|
pipe->tmp_page = NULL;
|
|
|
|
|
@@ -1013,7 +1040,7 @@ struct file *create_write_pipe(int flags)
|
|
|
goto err_dentry;
|
|
|
f->f_mapping = inode->i_mapping;
|
|
|
|
|
|
- f->f_flags = O_WRONLY | (flags & O_NONBLOCK);
|
|
|
+ f->f_flags = O_WRONLY | (flags & (O_NONBLOCK | O_DIRECT));
|
|
|
f->f_version = 0;
|
|
|
|
|
|
return f;
|
|
@@ -1057,7 +1084,7 @@ int do_pipe_flags(int *fd, int flags)
|
|
|
int error;
|
|
|
int fdw, fdr;
|
|
|
|
|
|
- if (flags & ~(O_CLOEXEC | O_NONBLOCK))
|
|
|
+ if (flags & ~(O_CLOEXEC | O_NONBLOCK | O_DIRECT))
|
|
|
return -EINVAL;
|
|
|
|
|
|
fw = create_write_pipe(flags);
|