Also fix other long standing issues caused by fcntl(,F_SETFL,):
- One can disable O_DIRECT for pipe[1] (paketized IO), but can not enable it 
again.
- Currently we do not set O_APPEND on pipe[1] (IMHO it is wrong, but let it be)
  so it is reasonable to completely prohibit change O_APPEND flag on both
  end's of pipe. Add ->check_flags method in order to diallow O_APPEND toggling.

Signed-off-by: Dmitry Monakhov <dmonak...@openvz.org>
---
 fs/fcntl.c |    6 ++++--
 fs/pipe.c  |   20 +++++++++++++++-----
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/fs/fcntl.c b/fs/fcntl.c
index ee85cd4..0bdc9c7 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -51,9 +51,11 @@ static int setfl(int fd, struct file * filp, unsigned long 
arg)
               if (arg & O_NDELAY)
                   arg |= O_NONBLOCK;
 
+       /* allowed only for inodes with ->direct_io method or write pipe */
        if (arg & O_DIRECT) {
-               if (!filp->f_mapping || !filp->f_mapping->a_ops ||
-                       !filp->f_mapping->a_ops->direct_IO)
+               if ((!filp->f_mapping || !filp->f_mapping->a_ops ||
+                    !filp->f_mapping->a_ops->direct_IO) &&
+                   !(get_pipe_info(filp) && (filp->f_flags | O_WRONLY)))
                                return -EINVAL;
        }
 
diff --git a/fs/pipe.c b/fs/pipe.c
index 2d084f2..95b5fe4 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -301,7 +301,7 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to)
                         */
                        if (ret)
                                break;
-                       if (filp->f_flags & O_NONBLOCK) {
+                       if (is_nonblock_kiocb(iocb)) {
                                ret = -EAGAIN;
                                break;
                        }
@@ -329,9 +329,9 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to)
        return ret;
 }
 
-static inline int is_packetized(struct file *file)
+static inline int is_packetized(struct kiocb *kiocb)
 {
-       return (file->f_flags & O_DIRECT) != 0;
+       return is_direct_kiocb(kiocb);
 }
 
 static ssize_t
@@ -427,7 +427,7 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
                        buf->offset = 0;
                        buf->len = copied;
                        buf->flags = 0;
-                       if (is_packetized(filp)) {
+                       if (is_packetized(iocb)) {
                                buf->ops = &packet_pipe_buf_ops;
                                buf->flags = PIPE_BUF_FLAG_PACKET;
                        }
@@ -439,7 +439,7 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
                }
                if (bufs < pipe->buffers)
                        continue;
-               if (filp->f_flags & O_NONBLOCK) {
+               if (is_nonblock_kiocb(iocb)) {
                        if (!ret)
                                ret = -EAGAIN;
                        break;
@@ -943,6 +943,15 @@ err:
        return ret;
 }
 
+/* XXX: Currently it is not possible distinguish read side from write one */
+static int pipe_check_flags(int flags)
+{
+       if (flags & O_APPEND)
+           return -EINVAL;
+
+       return 0;
+}
+
 const struct file_operations pipefifo_fops = {
        .open           = fifo_open,
        .llseek         = no_llseek,
@@ -954,6 +963,7 @@ const struct file_operations pipefifo_fops = {
        .unlocked_ioctl = pipe_ioctl,
        .release        = pipe_release,
        .fasync         = pipe_fasync,
+       .check_flags    = pipe_check_flags,
 };
 
 /*
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to