diff options
Diffstat (limited to 'fs/pipe.c')
| -rw-r--r-- | fs/pipe.c | 31 | 
1 files changed, 29 insertions, 2 deletions
diff --git a/fs/pipe.c b/fs/pipe.c index 25feaa3faac..fec5e4ad071 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -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);  |