aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2018-05-26 21:39:52 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2018-06-11 02:14:04 -0400
commit87a3002af9e30852ce90a028f8259c9e399fd888 (patch)
treea98b9ac17c4cecfc7f4f4d53acf4a8b7977b1bc0
parent4faa99965e027cc057c5145ce45fa772caa04e8d (diff)
vmsplice(): lift importing iovec into vmsplice(2) and compat counterpart
... getting rid of transformations in the latter - just use compat_import_iovec(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/splice.c144
1 files changed, 75 insertions, 69 deletions
diff --git a/fs/splice.c b/fs/splice.c
index 005d09cf3fa8..e3d0ae5383e7 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -1242,38 +1242,26 @@ static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
1242 * For lack of a better implementation, implement vmsplice() to userspace 1242 * For lack of a better implementation, implement vmsplice() to userspace
1243 * as a simple copy of the pipes pages to the user iov. 1243 * as a simple copy of the pipes pages to the user iov.
1244 */ 1244 */
1245static long vmsplice_to_user(struct file *file, const struct iovec __user *uiov, 1245static long vmsplice_to_user(struct file *file, struct iov_iter *iter,
1246 unsigned long nr_segs, unsigned int flags) 1246 unsigned int flags)
1247{ 1247{
1248 struct pipe_inode_info *pipe; 1248 struct pipe_inode_info *pipe = get_pipe_info(file);
1249 struct splice_desc sd; 1249 struct splice_desc sd = {
1250 long ret; 1250 .total_len = iov_iter_count(iter),
1251 struct iovec iovstack[UIO_FASTIOV]; 1251 .flags = flags,
1252 struct iovec *iov = iovstack; 1252 .u.data = iter
1253 struct iov_iter iter; 1253 };
1254 long ret = 0;
1254 1255
1255 pipe = get_pipe_info(file);
1256 if (!pipe) 1256 if (!pipe)
1257 return -EBADF; 1257 return -EBADF;
1258 1258
1259 ret = import_iovec(READ, uiov, nr_segs,
1260 ARRAY_SIZE(iovstack), &iov, &iter);
1261 if (ret < 0)
1262 return ret;
1263
1264 sd.total_len = iov_iter_count(&iter);
1265 sd.len = 0;
1266 sd.flags = flags;
1267 sd.u.data = &iter;
1268 sd.pos = 0;
1269
1270 if (sd.total_len) { 1259 if (sd.total_len) {
1271 pipe_lock(pipe); 1260 pipe_lock(pipe);
1272 ret = __splice_from_pipe(pipe, &sd, pipe_to_user); 1261 ret = __splice_from_pipe(pipe, &sd, pipe_to_user);
1273 pipe_unlock(pipe); 1262 pipe_unlock(pipe);
1274 } 1263 }
1275 1264
1276 kfree(iov);
1277 return ret; 1265 return ret;
1278} 1266}
1279 1267
@@ -1282,14 +1270,11 @@ static long vmsplice_to_user(struct file *file, const struct iovec __user *uiov,
1282 * as splice-from-memory, where the regular splice is splice-from-file (or 1270 * as splice-from-memory, where the regular splice is splice-from-file (or
1283 * to file). In both cases the output is a pipe, naturally. 1271 * to file). In both cases the output is a pipe, naturally.
1284 */ 1272 */
1285static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov, 1273static long vmsplice_to_pipe(struct file *file, struct iov_iter *iter,
1286 unsigned long nr_segs, unsigned int flags) 1274 unsigned int flags)
1287{ 1275{
1288 struct pipe_inode_info *pipe; 1276 struct pipe_inode_info *pipe;
1289 struct iovec iovstack[UIO_FASTIOV]; 1277 long ret = 0;
1290 struct iovec *iov = iovstack;
1291 struct iov_iter from;
1292 long ret;
1293 unsigned buf_flag = 0; 1278 unsigned buf_flag = 0;
1294 1279
1295 if (flags & SPLICE_F_GIFT) 1280 if (flags & SPLICE_F_GIFT)
@@ -1299,22 +1284,31 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov,
1299 if (!pipe) 1284 if (!pipe)
1300 return -EBADF; 1285 return -EBADF;
1301 1286
1302 ret = import_iovec(WRITE, uiov, nr_segs,
1303 ARRAY_SIZE(iovstack), &iov, &from);
1304 if (ret < 0)
1305 return ret;
1306
1307 pipe_lock(pipe); 1287 pipe_lock(pipe);
1308 ret = wait_for_space(pipe, flags); 1288 ret = wait_for_space(pipe, flags);
1309 if (!ret) 1289 if (!ret)
1310 ret = iter_to_pipe(&from, pipe, buf_flag); 1290 ret = iter_to_pipe(iter, pipe, buf_flag);
1311 pipe_unlock(pipe); 1291 pipe_unlock(pipe);
1312 if (ret > 0) 1292 if (ret > 0)
1313 wakeup_pipe_readers(pipe); 1293 wakeup_pipe_readers(pipe);
1314 kfree(iov);
1315 return ret; 1294 return ret;
1316} 1295}
1317 1296
1297static int vmsplice_type(struct fd f, int *type)
1298{
1299 if (!f.file)
1300 return -EBADF;
1301 if (f.file->f_mode & FMODE_WRITE) {
1302 *type = WRITE;
1303 } else if (f.file->f_mode & FMODE_READ) {
1304 *type = READ;
1305 } else {
1306 fdput(f);
1307 return -EBADF;
1308 }
1309 return 0;
1310}
1311
1318/* 1312/*
1319 * Note that vmsplice only really supports true splicing _from_ user memory 1313 * Note that vmsplice only really supports true splicing _from_ user memory
1320 * to a pipe, not the other way around. Splicing from user memory is a simple 1314 * to a pipe, not the other way around. Splicing from user memory is a simple
@@ -1331,57 +1325,69 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov,
1331 * Currently we punt and implement it as a normal copy, see pipe_to_user(). 1325 * Currently we punt and implement it as a normal copy, see pipe_to_user().
1332 * 1326 *
1333 */ 1327 */
1334static long do_vmsplice(int fd, const struct iovec __user *iov, 1328static long do_vmsplice(struct file *f, struct iov_iter *iter, unsigned int flags)
1335 unsigned long nr_segs, unsigned int flags)
1336{ 1329{
1337 struct fd f;
1338 long error;
1339
1340 if (unlikely(flags & ~SPLICE_F_ALL)) 1330 if (unlikely(flags & ~SPLICE_F_ALL))
1341 return -EINVAL; 1331 return -EINVAL;
1342 if (unlikely(nr_segs > UIO_MAXIOV))
1343 return -EINVAL;
1344 else if (unlikely(!nr_segs))
1345 return 0;
1346 1332
1347 error = -EBADF; 1333 if (!iov_iter_count(iter))
1348 f = fdget(fd); 1334 return 0;
1349 if (f.file) {
1350 if (f.file->f_mode & FMODE_WRITE)
1351 error = vmsplice_to_pipe(f.file, iov, nr_segs, flags);
1352 else if (f.file->f_mode & FMODE_READ)
1353 error = vmsplice_to_user(f.file, iov, nr_segs, flags);
1354
1355 fdput(f);
1356 }
1357 1335
1358 return error; 1336 if (iov_iter_rw(iter) == WRITE)
1337 return vmsplice_to_pipe(f, iter, flags);
1338 else
1339 return vmsplice_to_user(f, iter, flags);
1359} 1340}
1360 1341
1361SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, iov, 1342SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, uiov,
1362 unsigned long, nr_segs, unsigned int, flags) 1343 unsigned long, nr_segs, unsigned int, flags)
1363{ 1344{
1364 return do_vmsplice(fd, iov, nr_segs, flags); 1345 struct iovec iovstack[UIO_FASTIOV];
1346 struct iovec *iov = iovstack;
1347 struct iov_iter iter;
1348 long error;
1349 struct fd f;
1350 int type;
1351
1352 f = fdget(fd);
1353 error = vmsplice_type(f, &type);
1354 if (error)
1355 return error;
1356
1357 error = import_iovec(type, uiov, nr_segs,
1358 ARRAY_SIZE(iovstack), &iov, &iter);
1359 if (!error) {
1360 error = do_vmsplice(f.file, &iter, flags);
1361 kfree(iov);
1362 }
1363 fdput(f);
1364 return error;
1365} 1365}
1366 1366
1367#ifdef CONFIG_COMPAT 1367#ifdef CONFIG_COMPAT
1368COMPAT_SYSCALL_DEFINE4(vmsplice, int, fd, const struct compat_iovec __user *, iov32, 1368COMPAT_SYSCALL_DEFINE4(vmsplice, int, fd, const struct compat_iovec __user *, iov32,
1369 unsigned int, nr_segs, unsigned int, flags) 1369 unsigned int, nr_segs, unsigned int, flags)
1370{ 1370{
1371 unsigned i; 1371 struct iovec iovstack[UIO_FASTIOV];
1372 struct iovec __user *iov; 1372 struct iovec *iov = iovstack;
1373 if (nr_segs > UIO_MAXIOV) 1373 struct iov_iter iter;
1374 return -EINVAL; 1374 long error;
1375 iov = compat_alloc_user_space(nr_segs * sizeof(struct iovec)); 1375 struct fd f;
1376 for (i = 0; i < nr_segs; i++) { 1376 int type;
1377 struct compat_iovec v; 1377
1378 if (get_user(v.iov_base, &iov32[i].iov_base) || 1378 f = fdget(fd);
1379 get_user(v.iov_len, &iov32[i].iov_len) || 1379 error = vmsplice_type(f, &type);
1380 put_user(compat_ptr(v.iov_base), &iov[i].iov_base) || 1380 if (error)
1381 put_user(v.iov_len, &iov[i].iov_len)) 1381 return error;
1382 return -EFAULT; 1382
1383 error = compat_import_iovec(type, iov32, nr_segs,
1384 ARRAY_SIZE(iovstack), &iov, &iter);
1385 if (!error) {
1386 error = do_vmsplice(f.file, &iter, flags);
1387 kfree(iov);
1383 } 1388 }
1384 return do_vmsplice(fd, iov, nr_segs, flags); 1389 fdput(f);
1390 return error;
1385} 1391}
1386#endif 1392#endif
1387 1393