Skip to content

Commit 87a3002

Browse files
author
Al Viro
committed
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>
1 parent 4faa999 commit 87a3002

File tree

1 file changed

+75
-69
lines changed

1 file changed

+75
-69
lines changed

fs/splice.c

Lines changed: 75 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,38 +1242,26 @@ static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
12421242
* For lack of a better implementation, implement vmsplice() to userspace
12431243
* as a simple copy of the pipes pages to the user iov.
12441244
*/
1245-
static long vmsplice_to_user(struct file *file, const struct iovec __user *uiov,
1246-
unsigned long nr_segs, unsigned int flags)
1245+
static long vmsplice_to_user(struct file *file, struct iov_iter *iter,
1246+
unsigned int flags)
12471247
{
1248-
struct pipe_inode_info *pipe;
1249-
struct splice_desc sd;
1250-
long ret;
1251-
struct iovec iovstack[UIO_FASTIOV];
1252-
struct iovec *iov = iovstack;
1253-
struct iov_iter iter;
1248+
struct pipe_inode_info *pipe = get_pipe_info(file);
1249+
struct splice_desc sd = {
1250+
.total_len = iov_iter_count(iter),
1251+
.flags = flags,
1252+
.u.data = iter
1253+
};
1254+
long ret = 0;
12541255

1255-
pipe = get_pipe_info(file);
12561256
if (!pipe)
12571257
return -EBADF;
12581258

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-
12701259
if (sd.total_len) {
12711260
pipe_lock(pipe);
12721261
ret = __splice_from_pipe(pipe, &sd, pipe_to_user);
12731262
pipe_unlock(pipe);
12741263
}
12751264

1276-
kfree(iov);
12771265
return ret;
12781266
}
12791267

@@ -1282,14 +1270,11 @@ static long vmsplice_to_user(struct file *file, const struct iovec __user *uiov,
12821270
* as splice-from-memory, where the regular splice is splice-from-file (or
12831271
* to file). In both cases the output is a pipe, naturally.
12841272
*/
1285-
static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov,
1286-
unsigned long nr_segs, unsigned int flags)
1273+
static long vmsplice_to_pipe(struct file *file, struct iov_iter *iter,
1274+
unsigned int flags)
12871275
{
12881276
struct pipe_inode_info *pipe;
1289-
struct iovec iovstack[UIO_FASTIOV];
1290-
struct iovec *iov = iovstack;
1291-
struct iov_iter from;
1292-
long ret;
1277+
long ret = 0;
12931278
unsigned buf_flag = 0;
12941279

12951280
if (flags & SPLICE_F_GIFT)
@@ -1299,22 +1284,31 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov,
12991284
if (!pipe)
13001285
return -EBADF;
13011286

1302-
ret = import_iovec(WRITE, uiov, nr_segs,
1303-
ARRAY_SIZE(iovstack), &iov, &from);
1304-
if (ret < 0)
1305-
return ret;
1306-
13071287
pipe_lock(pipe);
13081288
ret = wait_for_space(pipe, flags);
13091289
if (!ret)
1310-
ret = iter_to_pipe(&from, pipe, buf_flag);
1290+
ret = iter_to_pipe(iter, pipe, buf_flag);
13111291
pipe_unlock(pipe);
13121292
if (ret > 0)
13131293
wakeup_pipe_readers(pipe);
1314-
kfree(iov);
13151294
return ret;
13161295
}
13171296

1297+
static 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+
13181312
/*
13191313
* Note that vmsplice only really supports true splicing _from_ user memory
13201314
* 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,
13311325
* Currently we punt and implement it as a normal copy, see pipe_to_user().
13321326
*
13331327
*/
1334-
static long do_vmsplice(int fd, const struct iovec __user *iov,
1335-
unsigned long nr_segs, unsigned int flags)
1328+
static long do_vmsplice(struct file *f, struct iov_iter *iter, unsigned int flags)
13361329
{
1337-
struct fd f;
1338-
long error;
1339-
13401330
if (unlikely(flags & ~SPLICE_F_ALL))
13411331
return -EINVAL;
1342-
if (unlikely(nr_segs > UIO_MAXIOV))
1343-
return -EINVAL;
1344-
else if (unlikely(!nr_segs))
1345-
return 0;
13461332

1347-
error = -EBADF;
1348-
f = fdget(fd);
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-
}
1333+
if (!iov_iter_count(iter))
1334+
return 0;
13571335

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);
13591340
}
13601341

1361-
SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, iov,
1342+
SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, uiov,
13621343
unsigned long, nr_segs, unsigned int, flags)
13631344
{
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;
13651365
}
13661366

13671367
#ifdef CONFIG_COMPAT
13681368
COMPAT_SYSCALL_DEFINE4(vmsplice, int, fd, const struct compat_iovec __user *, iov32,
13691369
unsigned int, nr_segs, unsigned int, flags)
13701370
{
1371-
unsigned i;
1372-
struct iovec __user *iov;
1373-
if (nr_segs > UIO_MAXIOV)
1374-
return -EINVAL;
1375-
iov = compat_alloc_user_space(nr_segs * sizeof(struct iovec));
1376-
for (i = 0; i < nr_segs; i++) {
1377-
struct compat_iovec v;
1378-
if (get_user(v.iov_base, &iov32[i].iov_base) ||
1379-
get_user(v.iov_len, &iov32[i].iov_len) ||
1380-
put_user(compat_ptr(v.iov_base), &iov[i].iov_base) ||
1381-
put_user(v.iov_len, &iov[i].iov_len))
1382-
return -EFAULT;
1371+
struct iovec iovstack[UIO_FASTIOV];
1372+
struct iovec *iov = iovstack;
1373+
struct iov_iter iter;
1374+
long error;
1375+
struct fd f;
1376+
int type;
1377+
1378+
f = fdget(fd);
1379+
error = vmsplice_type(f, &type);
1380+
if (error)
1381+
return error;
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);
13831388
}
1384-
return do_vmsplice(fd, iov, nr_segs, flags);
1389+
fdput(f);
1390+
return error;
13851391
}
13861392
#endif
13871393

0 commit comments

Comments
 (0)