diff options
-rw-r--r-- | fs/pipe.c | 37 |
1 files changed, 21 insertions, 16 deletions
@@ -1112,26 +1112,20 @@ SYSCALL_DEFINE1(pipe, int __user *, fildes) | |||
1112 | * Allocate a new array of pipe buffers and copy the info over. Returns the | 1112 | * Allocate a new array of pipe buffers and copy the info over. Returns the |
1113 | * pipe size if successful, or return -ERROR on error. | 1113 | * pipe size if successful, or return -ERROR on error. |
1114 | */ | 1114 | */ |
1115 | static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg) | 1115 | static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long nr_pages) |
1116 | { | 1116 | { |
1117 | struct pipe_buffer *bufs; | 1117 | struct pipe_buffer *bufs; |
1118 | 1118 | ||
1119 | /* | 1119 | /* |
1120 | * Must be a power-of-2 currently | ||
1121 | */ | ||
1122 | if (!is_power_of_2(arg)) | ||
1123 | return -EINVAL; | ||
1124 | |||
1125 | /* | ||
1126 | * We can shrink the pipe, if arg >= pipe->nrbufs. Since we don't | 1120 | * We can shrink the pipe, if arg >= pipe->nrbufs. Since we don't |
1127 | * expect a lot of shrink+grow operations, just free and allocate | 1121 | * expect a lot of shrink+grow operations, just free and allocate |
1128 | * again like we would do for growing. If the pipe currently | 1122 | * again like we would do for growing. If the pipe currently |
1129 | * contains more buffers than arg, then return busy. | 1123 | * contains more buffers than arg, then return busy. |
1130 | */ | 1124 | */ |
1131 | if (arg < pipe->nrbufs) | 1125 | if (nr_pages < pipe->nrbufs) |
1132 | return -EBUSY; | 1126 | return -EBUSY; |
1133 | 1127 | ||
1134 | bufs = kcalloc(arg, sizeof(struct pipe_buffer), GFP_KERNEL); | 1128 | bufs = kcalloc(nr_pages, sizeof(struct pipe_buffer), GFP_KERNEL); |
1135 | if (unlikely(!bufs)) | 1129 | if (unlikely(!bufs)) |
1136 | return -ENOMEM; | 1130 | return -ENOMEM; |
1137 | 1131 | ||
@@ -1152,8 +1146,8 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg) | |||
1152 | pipe->curbuf = 0; | 1146 | pipe->curbuf = 0; |
1153 | kfree(pipe->bufs); | 1147 | kfree(pipe->bufs); |
1154 | pipe->bufs = bufs; | 1148 | pipe->bufs = bufs; |
1155 | pipe->buffers = arg; | 1149 | pipe->buffers = nr_pages; |
1156 | return arg; | 1150 | return nr_pages * PAGE_SIZE; |
1157 | } | 1151 | } |
1158 | 1152 | ||
1159 | long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) | 1153 | long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) |
@@ -1168,19 +1162,30 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) | |||
1168 | mutex_lock(&pipe->inode->i_mutex); | 1162 | mutex_lock(&pipe->inode->i_mutex); |
1169 | 1163 | ||
1170 | switch (cmd) { | 1164 | switch (cmd) { |
1171 | case F_SETPIPE_SZ: | 1165 | case F_SETPIPE_SZ: { |
1172 | if (!capable(CAP_SYS_ADMIN) && arg > pipe_max_pages) | 1166 | unsigned long nr_pages; |
1167 | |||
1168 | /* | ||
1169 | * Currently the array must be a power-of-2 size, so adjust | ||
1170 | * upwards if needed. | ||
1171 | */ | ||
1172 | nr_pages = (arg + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
1173 | nr_pages = roundup_pow_of_two(nr_pages); | ||
1174 | |||
1175 | if (!capable(CAP_SYS_ADMIN) && nr_pages > pipe_max_pages) | ||
1173 | return -EPERM; | 1176 | return -EPERM; |
1177 | |||
1174 | /* | 1178 | /* |
1175 | * The pipe needs to be at least 2 pages large to | 1179 | * The pipe needs to be at least 2 pages large to |
1176 | * guarantee POSIX behaviour. | 1180 | * guarantee POSIX behaviour. |
1177 | */ | 1181 | */ |
1178 | if (arg < 2) | 1182 | if (nr_pages < 2) |
1179 | return -EINVAL; | 1183 | return -EINVAL; |
1180 | ret = pipe_set_size(pipe, arg); | 1184 | ret = pipe_set_size(pipe, nr_pages); |
1181 | break; | 1185 | break; |
1186 | } | ||
1182 | case F_GETPIPE_SZ: | 1187 | case F_GETPIPE_SZ: |
1183 | ret = pipe->buffers; | 1188 | ret = pipe->buffers * PAGE_SIZE; |
1184 | break; | 1189 | break; |
1185 | default: | 1190 | default: |
1186 | ret = -EINVAL; | 1191 | ret = -EINVAL; |