Commit b9598db3401282bb27b4aef77e3eee12015f7f29
1 parent
0191f8697b
Exists in
master
and in
7 other branches
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>
Showing 1 changed file with 21 additions and 16 deletions Side-by-side Diff
fs/pipe.c
... | ... | @@ -1112,26 +1112,20 @@ |
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 | 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 | 1120 | * We can shrink the pipe, if arg >= pipe->nrbufs. Since we don't |
1127 | 1121 | * expect a lot of shrink+grow operations, just free and allocate |
1128 | 1122 | * again like we would do for growing. If the pipe currently |
1129 | 1123 | * contains more buffers than arg, then return busy. |
1130 | 1124 | */ |
1131 | - if (arg < pipe->nrbufs) | |
1125 | + if (nr_pages < pipe->nrbufs) | |
1132 | 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 | 1129 | if (unlikely(!bufs)) |
1136 | 1130 | return -ENOMEM; |
1137 | 1131 | |
... | ... | @@ -1152,8 +1146,8 @@ |
1152 | 1146 | pipe->curbuf = 0; |
1153 | 1147 | kfree(pipe->bufs); |
1154 | 1148 | pipe->bufs = bufs; |
1155 | - pipe->buffers = arg; | |
1156 | - return arg; | |
1149 | + pipe->buffers = nr_pages; | |
1150 | + return nr_pages * PAGE_SIZE; | |
1157 | 1151 | } |
1158 | 1152 | |
1159 | 1153 | long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) |
1160 | 1154 | |
1161 | 1155 | |
1162 | 1156 | |
1163 | 1157 | |
1164 | 1158 | |
... | ... | @@ -1168,19 +1162,30 @@ |
1168 | 1162 | mutex_lock(&pipe->inode->i_mutex); |
1169 | 1163 | |
1170 | 1164 | switch (cmd) { |
1171 | - case F_SETPIPE_SZ: | |
1172 | - if (!capable(CAP_SYS_ADMIN) && arg > pipe_max_pages) | |
1165 | + case F_SETPIPE_SZ: { | |
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 | 1176 | return -EPERM; |
1177 | + | |
1174 | 1178 | /* |
1175 | 1179 | * The pipe needs to be at least 2 pages large to |
1176 | 1180 | * guarantee POSIX behaviour. |
1177 | 1181 | */ |
1178 | - if (arg < 2) | |
1182 | + if (nr_pages < 2) | |
1179 | 1183 | return -EINVAL; |
1180 | - ret = pipe_set_size(pipe, arg); | |
1184 | + ret = pipe_set_size(pipe, nr_pages); | |
1181 | 1185 | break; |
1186 | + } | |
1182 | 1187 | case F_GETPIPE_SZ: |
1183 | - ret = pipe->buffers; | |
1188 | + ret = pipe->buffers * PAGE_SIZE; | |
1184 | 1189 | break; |
1185 | 1190 | default: |
1186 | 1191 | ret = -EINVAL; |