diff options
Diffstat (limited to 'fs/pipe.c')
| -rw-r--r-- | fs/pipe.c | 54 |
1 files changed, 42 insertions, 12 deletions
| @@ -26,9 +26,14 @@ | |||
| 26 | 26 | ||
| 27 | /* | 27 | /* |
| 28 | * The max size that a non-root user is allowed to grow the pipe. Can | 28 | * The max size that a non-root user is allowed to grow the pipe. Can |
| 29 | * be set by root in /proc/sys/fs/pipe-max-pages | 29 | * be set by root in /proc/sys/fs/pipe-max-size |
| 30 | */ | 30 | */ |
| 31 | unsigned int pipe_max_pages = PIPE_DEF_BUFFERS * 16; | 31 | unsigned int pipe_max_size = 1048576; |
| 32 | |||
| 33 | /* | ||
| 34 | * Minimum pipe size, as required by POSIX | ||
| 35 | */ | ||
| 36 | unsigned int pipe_min_size = PAGE_SIZE; | ||
| 32 | 37 | ||
| 33 | /* | 38 | /* |
| 34 | * We use a start+len construction, which provides full use of the | 39 | * We use a start+len construction, which provides full use of the |
| @@ -1156,6 +1161,35 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long nr_pages) | |||
| 1156 | return nr_pages * PAGE_SIZE; | 1161 | return nr_pages * PAGE_SIZE; |
| 1157 | } | 1162 | } |
| 1158 | 1163 | ||
| 1164 | /* | ||
| 1165 | * Currently we rely on the pipe array holding a power-of-2 number | ||
| 1166 | * of pages. | ||
| 1167 | */ | ||
| 1168 | static inline unsigned int round_pipe_size(unsigned int size) | ||
| 1169 | { | ||
| 1170 | unsigned long nr_pages; | ||
| 1171 | |||
| 1172 | nr_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
| 1173 | return roundup_pow_of_two(nr_pages) << PAGE_SHIFT; | ||
| 1174 | } | ||
| 1175 | |||
| 1176 | /* | ||
| 1177 | * This should work even if CONFIG_PROC_FS isn't set, as proc_dointvec_minmax | ||
| 1178 | * will return an error. | ||
| 1179 | */ | ||
| 1180 | int pipe_proc_fn(struct ctl_table *table, int write, void __user *buf, | ||
| 1181 | size_t *lenp, loff_t *ppos) | ||
| 1182 | { | ||
| 1183 | int ret; | ||
| 1184 | |||
| 1185 | ret = proc_dointvec_minmax(table, write, buf, lenp, ppos); | ||
| 1186 | if (ret < 0 || !write) | ||
| 1187 | return ret; | ||
| 1188 | |||
| 1189 | pipe_max_size = round_pipe_size(pipe_max_size); | ||
| 1190 | return ret; | ||
| 1191 | } | ||
| 1192 | |||
| 1159 | long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) | 1193 | long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) |
| 1160 | { | 1194 | { |
| 1161 | struct pipe_inode_info *pipe; | 1195 | struct pipe_inode_info *pipe; |
| @@ -1169,23 +1203,19 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) | |||
| 1169 | 1203 | ||
| 1170 | switch (cmd) { | 1204 | switch (cmd) { |
| 1171 | case F_SETPIPE_SZ: { | 1205 | case F_SETPIPE_SZ: { |
| 1172 | unsigned long nr_pages; | 1206 | unsigned int size, nr_pages; |
| 1173 | 1207 | ||
| 1174 | /* | 1208 | size = round_pipe_size(arg); |
| 1175 | * Currently the array must be a power-of-2 size, so adjust | 1209 | nr_pages = size >> PAGE_SHIFT; |
| 1176 | * upwards if needed. | ||
| 1177 | */ | ||
| 1178 | nr_pages = (arg + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
| 1179 | nr_pages = roundup_pow_of_two(nr_pages); | ||
| 1180 | 1210 | ||
| 1181 | if (!capable(CAP_SYS_RESOURCE) && nr_pages > pipe_max_pages) { | 1211 | if (!capable(CAP_SYS_RESOURCE) && size > pipe_max_size) { |
| 1182 | ret = -EPERM; | 1212 | ret = -EPERM; |
| 1183 | goto out; | 1213 | goto out; |
| 1184 | } else if (nr_pages < 1) { | 1214 | } else if (nr_pages < PAGE_SIZE) { |
| 1185 | ret = -EINVAL; | 1215 | ret = -EINVAL; |
| 1186 | goto out; | 1216 | goto out; |
| 1187 | } | 1217 | } |
| 1188 | ret = pipe_set_size(pipe, arg); | 1218 | ret = pipe_set_size(pipe, nr_pages); |
| 1189 | break; | 1219 | break; |
| 1190 | } | 1220 | } |
| 1191 | case F_GETPIPE_SZ: | 1221 | case F_GETPIPE_SZ: |
