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: |