]> rtime.felk.cvut.cz Git - lisovros/linux_canprio.git/blobdiff - fs/pipe.c
Merge branch 'master' into for-linus
[lisovros/linux_canprio.git] / fs / pipe.c
index db6eaaba0dd81fb777f2b64f1e385d40eb3f1819..541d6626f9d93d060541d601494064a825fa7622 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -1118,26 +1118,20 @@ SYSCALL_DEFINE1(pipe, int __user *, fildes)
  * Allocate a new array of pipe buffers and copy the info over. Returns the
  * pipe size if successful, or return -ERROR on error.
  */
-static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg)
+static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long nr_pages)
 {
        struct pipe_buffer *bufs;
 
-       /*
-        * Must be a power-of-2 currently
-        */
-       if (!is_power_of_2(arg))
-               return -EINVAL;
-
        /*
         * We can shrink the pipe, if arg >= pipe->nrbufs. Since we don't
         * expect a lot of shrink+grow operations, just free and allocate
         * again like we would do for growing. If the pipe currently
         * contains more buffers than arg, then return busy.
         */
-       if (arg < pipe->nrbufs)
+       if (nr_pages < pipe->nrbufs)
                return -EBUSY;
 
-       bufs = kcalloc(arg, sizeof(struct pipe_buffer), GFP_KERNEL);
+       bufs = kcalloc(nr_pages, sizeof(struct pipe_buffer), GFP_KERNEL);
        if (unlikely(!bufs))
                return -ENOMEM;
 
@@ -1158,8 +1152,8 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg)
        pipe->curbuf = 0;
        kfree(pipe->bufs);
        pipe->bufs = bufs;
-       pipe->buffers = arg;
-       return arg;
+       pipe->buffers = nr_pages;
+       return nr_pages * PAGE_SIZE;
 }
 
 long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -1174,11 +1168,21 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
        mutex_lock(&pipe->inode->i_mutex);
 
        switch (cmd) {
-       case F_SETPIPE_SZ:
-               if (!capable(CAP_SYS_ADMIN) && arg > pipe_max_pages) {
-                       ret = -EINVAL;
+       case F_SETPIPE_SZ: {
+               unsigned long nr_pages;
+
+               /*
+                * Currently the array must be a power-of-2 size, so adjust
+                * upwards if needed.
+                */
+               nr_pages = (arg + PAGE_SIZE - 1) >> PAGE_SHIFT;
+               nr_pages = roundup_pow_of_two(nr_pages);
+
+               if (!capable(CAP_SYS_ADMIN) && nr_pages > pipe_max_pages) {
+                       ret = -EPERM;
                        goto out;
                }
+
                /*
                 * The pipe needs to be at least 2 pages large to
                 * guarantee POSIX behaviour.
@@ -1189,8 +1193,9 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
                }
                ret = pipe_set_size(pipe, arg);
                break;
+               }
        case F_GETPIPE_SZ:
-               ret = pipe->buffers;
+               ret = pipe->buffers * PAGE_SIZE;
                break;
        default:
                ret = -EINVAL;