aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Axboe <jens.axboe@oracle.com>2010-05-24 13:34:43 -0400
committerJens Axboe <jens.axboe@oracle.com>2010-05-24 13:34:43 -0400
commitb9598db3401282bb27b4aef77e3eee12015f7f29 (patch)
tree614f6d8df9613905ab8625c0985d0c0c96cfb39c
parent0191f8697bbdfefcd36e7b8dc3eeddfe82893e4b (diff)
pipe: make F_{GET,SET}PIPE_SZ deal with byte sizes
Instead of requiring an exact number of pages as the argument and return value, change the API to deal with number of bytes instead. This also relaxes the requirement that the passed in size must result in a power-of-2 page array size. Round up to the nearest power-of-2 automatically and return the resulting size of the pipe on success. Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r--fs/pipe.c37
1 files changed, 21 insertions, 16 deletions
diff --git a/fs/pipe.c b/fs/pipe.c
index 01ca9fab95fa..bdd3f96054b9 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -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 */
1115static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg) 1115static 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
1159long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) 1153long 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;