Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+21 -16
+21 -16
fs/pipe.c
··· 1112 1112 * Allocate a new array of pipe buffers and copy the info over. Returns the 1113 1113 * pipe size if successful, or return -ERROR on error. 1114 1114 */ 1115 - static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg) 1115 + static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long nr_pages) 1116 1116 { 1117 1117 struct pipe_buffer *bufs; 1118 - 1119 - /* 1120 - * Must be a power-of-2 currently 1121 - */ 1122 - if (!is_power_of_2(arg)) 1123 - return -EINVAL; 1124 1118 1125 1119 /* 1126 1120 * We can shrink the pipe, if arg >= pipe->nrbufs. Since we don't ··· 1122 1128 * again like we would do for growing. If the pipe currently 1123 1129 * contains more buffers than arg, then return busy. 1124 1130 */ 1125 - if (arg < pipe->nrbufs) 1131 + if (nr_pages < pipe->nrbufs) 1126 1132 return -EBUSY; 1127 1133 1128 - bufs = kcalloc(arg, sizeof(struct pipe_buffer), GFP_KERNEL); 1134 + bufs = kcalloc(nr_pages, sizeof(struct pipe_buffer), GFP_KERNEL); 1129 1135 if (unlikely(!bufs)) 1130 1136 return -ENOMEM; 1131 1137 ··· 1146 1152 pipe->curbuf = 0; 1147 1153 kfree(pipe->bufs); 1148 1154 pipe->bufs = bufs; 1149 - pipe->buffers = arg; 1150 - return arg; 1155 + pipe->buffers = nr_pages; 1156 + return nr_pages * PAGE_SIZE; 1151 1157 } 1152 1158 1153 1159 long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) ··· 1162 1168 mutex_lock(&pipe->inode->i_mutex); 1163 1169 1164 1170 switch (cmd) { 1165 - case F_SETPIPE_SZ: 1166 - if (!capable(CAP_SYS_ADMIN) && arg > pipe_max_pages) 1171 + case F_SETPIPE_SZ: { 1172 + unsigned long nr_pages; 1173 + 1174 + /* 1175 + * Currently the array must be a power-of-2 size, so adjust 1176 + * upwards if needed. 1177 + */ 1178 + nr_pages = (arg + PAGE_SIZE - 1) >> PAGE_SHIFT; 1179 + nr_pages = roundup_pow_of_two(nr_pages); 1180 + 1181 + if (!capable(CAP_SYS_ADMIN) && nr_pages > pipe_max_pages) 1167 1182 return -EPERM; 1183 + 1168 1184 /* 1169 1185 * The pipe needs to be at least 2 pages large to 1170 1186 * guarantee POSIX behaviour. 1171 1187 */ 1172 - if (arg < 2) 1188 + if (nr_pages < 2) 1173 1189 return -EINVAL; 1174 - ret = pipe_set_size(pipe, arg); 1190 + ret = pipe_set_size(pipe, nr_pages); 1175 1191 break; 1192 + } 1176 1193 case F_GETPIPE_SZ: 1177 - ret = pipe->buffers; 1194 + ret = pipe->buffers * PAGE_SIZE; 1178 1195 break; 1179 1196 default: 1180 1197 ret = -EINVAL;