aboutsummaryrefslogtreecommitdiffstats
path: root/fs/pipe.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/pipe.c')
-rw-r--r--fs/pipe.c77
1 files changed, 53 insertions, 24 deletions
diff --git a/fs/pipe.c b/fs/pipe.c
index db6eaaba0dd8..69c4c7c13ea9 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -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 */
31unsigned int pipe_max_pages = PIPE_DEF_BUFFERS * 16; 31unsigned int pipe_max_size = 1048576;
32
33/*
34 * Minimum pipe size, as required by POSIX
35 */
36unsigned 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 */
1121static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg) 1126static 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
@@ -1158,8 +1157,37 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg)
1158 pipe->curbuf = 0; 1157 pipe->curbuf = 0;
1159 kfree(pipe->bufs); 1158 kfree(pipe->bufs);
1160 pipe->bufs = bufs; 1159 pipe->bufs = bufs;
1161 pipe->buffers = arg; 1160 pipe->buffers = nr_pages;
1162 return arg; 1161 return nr_pages * PAGE_SIZE;
1162}
1163
1164/*
1165 * Currently we rely on the pipe array holding a power-of-2 number
1166 * of pages.
1167 */
1168static 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 */
1180int 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;
1163} 1191}
1164 1192
1165long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) 1193long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -1174,23 +1202,24 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
1174 mutex_lock(&pipe->inode->i_mutex); 1202 mutex_lock(&pipe->inode->i_mutex);
1175 1203
1176 switch (cmd) { 1204 switch (cmd) {
1177 case F_SETPIPE_SZ: 1205 case F_SETPIPE_SZ: {
1178 if (!capable(CAP_SYS_ADMIN) && arg > pipe_max_pages) { 1206 unsigned int size, nr_pages;
1179 ret = -EINVAL; 1207
1208 size = round_pipe_size(arg);
1209 nr_pages = size >> PAGE_SHIFT;
1210
1211 if (!capable(CAP_SYS_RESOURCE) && size > pipe_max_size) {
1212 ret = -EPERM;
1180 goto out; 1213 goto out;
1181 } 1214 } else if (nr_pages < PAGE_SIZE) {
1182 /*
1183 * The pipe needs to be at least 2 pages large to
1184 * guarantee POSIX behaviour.
1185 */
1186 if (arg < 2) {
1187 ret = -EINVAL; 1215 ret = -EINVAL;
1188 goto out; 1216 goto out;
1189 } 1217 }
1190 ret = pipe_set_size(pipe, arg); 1218 ret = pipe_set_size(pipe, nr_pages);
1191 break; 1219 break;
1220 }
1192 case F_GETPIPE_SZ: 1221 case F_GETPIPE_SZ:
1193 ret = pipe->buffers; 1222 ret = pipe->buffers * PAGE_SIZE;
1194 break; 1223 break;
1195 default: 1224 default:
1196 ret = -EINVAL; 1225 ret = -EINVAL;