diff options
Diffstat (limited to 'fs/pipe.c')
-rw-r--r-- | fs/pipe.c | 93 |
1 files changed, 65 insertions, 28 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 |
@@ -1118,26 +1123,20 @@ SYSCALL_DEFINE1(pipe, int __user *, fildes) | |||
1118 | * Allocate a new array of pipe buffers and copy the info over. Returns the | 1123 | * Allocate a new array of pipe buffers and copy the info over. Returns the |
1119 | * pipe size if successful, or return -ERROR on error. | 1124 | * pipe size if successful, or return -ERROR on error. |
1120 | */ | 1125 | */ |
1121 | static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg) | 1126 | static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long nr_pages) |
1122 | { | 1127 | { |
1123 | struct pipe_buffer *bufs; | 1128 | struct pipe_buffer *bufs; |
1124 | 1129 | ||
1125 | /* | 1130 | /* |
1126 | * Must be a power-of-2 currently | ||
1127 | */ | ||
1128 | if (!is_power_of_2(arg)) | ||
1129 | return -EINVAL; | ||
1130 | |||
1131 | /* | ||
1132 | * We can shrink the pipe, if arg >= pipe->nrbufs. Since we don't | 1131 | * We can shrink the pipe, if arg >= pipe->nrbufs. Since we don't |
1133 | * expect a lot of shrink+grow operations, just free and allocate | 1132 | * expect a lot of shrink+grow operations, just free and allocate |
1134 | * again like we would do for growing. If the pipe currently | 1133 | * again like we would do for growing. If the pipe currently |
1135 | * contains more buffers than arg, then return busy. | 1134 | * contains more buffers than arg, then return busy. |
1136 | */ | 1135 | */ |
1137 | if (arg < pipe->nrbufs) | 1136 | if (nr_pages < pipe->nrbufs) |
1138 | return -EBUSY; | 1137 | return -EBUSY; |
1139 | 1138 | ||
1140 | bufs = kcalloc(arg, sizeof(struct pipe_buffer), GFP_KERNEL); | 1139 | bufs = kcalloc(nr_pages, sizeof(struct pipe_buffer), GFP_KERNEL); |
1141 | if (unlikely(!bufs)) | 1140 | if (unlikely(!bufs)) |
1142 | return -ENOMEM; | 1141 | return -ENOMEM; |
1143 | 1142 | ||
@@ -1146,20 +1145,56 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg) | |||
1146 | * and adjust the indexes. | 1145 | * and adjust the indexes. |
1147 | */ | 1146 | */ |
1148 | if (pipe->nrbufs) { | 1147 | if (pipe->nrbufs) { |
1149 | const unsigned int tail = pipe->nrbufs & (pipe->buffers - 1); | 1148 | unsigned int tail; |
1150 | const unsigned int head = pipe->nrbufs - tail; | 1149 | unsigned int head; |
1150 | |||
1151 | tail = pipe->curbuf + pipe->nrbufs; | ||
1152 | if (tail < pipe->buffers) | ||
1153 | tail = 0; | ||
1154 | else | ||
1155 | tail &= (pipe->buffers - 1); | ||
1151 | 1156 | ||
1157 | head = pipe->nrbufs - tail; | ||
1152 | if (head) | 1158 | if (head) |
1153 | memcpy(bufs, pipe->bufs + pipe->curbuf, head * sizeof(struct pipe_buffer)); | 1159 | memcpy(bufs, pipe->bufs + pipe->curbuf, head * sizeof(struct pipe_buffer)); |
1154 | if (tail) | 1160 | if (tail) |
1155 | memcpy(bufs + head, pipe->bufs + pipe->curbuf, tail * sizeof(struct pipe_buffer)); | 1161 | memcpy(bufs + head, pipe->bufs, tail * sizeof(struct pipe_buffer)); |
1156 | } | 1162 | } |
1157 | 1163 | ||
1158 | pipe->curbuf = 0; | 1164 | pipe->curbuf = 0; |
1159 | kfree(pipe->bufs); | 1165 | kfree(pipe->bufs); |
1160 | pipe->bufs = bufs; | 1166 | pipe->bufs = bufs; |
1161 | pipe->buffers = arg; | 1167 | pipe->buffers = nr_pages; |
1162 | return arg; | 1168 | return nr_pages * PAGE_SIZE; |
1169 | } | ||
1170 | |||
1171 | /* | ||
1172 | * Currently we rely on the pipe array holding a power-of-2 number | ||
1173 | * of pages. | ||
1174 | */ | ||
1175 | static inline unsigned int round_pipe_size(unsigned int size) | ||
1176 | { | ||
1177 | unsigned long nr_pages; | ||
1178 | |||
1179 | nr_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
1180 | return roundup_pow_of_two(nr_pages) << PAGE_SHIFT; | ||
1181 | } | ||
1182 | |||
1183 | /* | ||
1184 | * This should work even if CONFIG_PROC_FS isn't set, as proc_dointvec_minmax | ||
1185 | * will return an error. | ||
1186 | */ | ||
1187 | int pipe_proc_fn(struct ctl_table *table, int write, void __user *buf, | ||
1188 | size_t *lenp, loff_t *ppos) | ||
1189 | { | ||
1190 | int ret; | ||
1191 | |||
1192 | ret = proc_dointvec_minmax(table, write, buf, lenp, ppos); | ||
1193 | if (ret < 0 || !write) | ||
1194 | return ret; | ||
1195 | |||
1196 | pipe_max_size = round_pipe_size(pipe_max_size); | ||
1197 | return ret; | ||
1163 | } | 1198 | } |
1164 | 1199 | ||
1165 | long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) | 1200 | long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) |
@@ -1174,23 +1209,25 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) | |||
1174 | mutex_lock(&pipe->inode->i_mutex); | 1209 | mutex_lock(&pipe->inode->i_mutex); |
1175 | 1210 | ||
1176 | switch (cmd) { | 1211 | switch (cmd) { |
1177 | case F_SETPIPE_SZ: | 1212 | case F_SETPIPE_SZ: { |
1178 | if (!capable(CAP_SYS_ADMIN) && arg > pipe_max_pages) { | 1213 | unsigned int size, nr_pages; |
1179 | ret = -EINVAL; | 1214 | |
1215 | size = round_pipe_size(arg); | ||
1216 | nr_pages = size >> PAGE_SHIFT; | ||
1217 | |||
1218 | ret = -EINVAL; | ||
1219 | if (!nr_pages) | ||
1180 | goto out; | 1220 | goto out; |
1181 | } | 1221 | |
1182 | /* | 1222 | if (!capable(CAP_SYS_RESOURCE) && size > pipe_max_size) { |
1183 | * The pipe needs to be at least 2 pages large to | 1223 | ret = -EPERM; |
1184 | * guarantee POSIX behaviour. | ||
1185 | */ | ||
1186 | if (arg < 2) { | ||
1187 | ret = -EINVAL; | ||
1188 | goto out; | 1224 | goto out; |
1189 | } | 1225 | } |
1190 | ret = pipe_set_size(pipe, arg); | 1226 | ret = pipe_set_size(pipe, nr_pages); |
1191 | break; | 1227 | break; |
1228 | } | ||
1192 | case F_GETPIPE_SZ: | 1229 | case F_GETPIPE_SZ: |
1193 | ret = pipe->buffers; | 1230 | ret = pipe->buffers * PAGE_SIZE; |
1194 | break; | 1231 | break; |
1195 | default: | 1232 | default: |
1196 | ret = -EINVAL; | 1233 | ret = -EINVAL; |