Skip to content

Commit 8924fef

Browse files
author
Al Viro
committed
splice: lift pipe_lock out of splice_to_pipe()
* splice_to_pipe() stops at pipe overflow and does *not* take pipe_lock * ->splice_read() instances do the same * vmsplice_to_pipe() and do_splice() (ultimate callers of splice_to_pipe()) arrange for waiting, looping, etc. themselves. That should make pipe_lock the outermost one. Unfortunately, existing rules for the amount passed by vmsplice_to_pipe() and do_splice() are quite ugly _and_ userland code can be easily broken by changing those. It's not even "no more than the maximal capacity of this pipe" - it's "once we'd fed pipe->nr_buffers pages into the pipe, leave instead of waiting". Considering how poorly these rules are documented, let's try "wait for some space to appear, unless given SPLICE_F_NONBLOCK, then push into pipe and if we run into overflow, we are done". Signed-off-by: Al Viro <[email protected]>
1 parent db85a9e commit 8924fef

File tree

2 files changed

+58
-73
lines changed

2 files changed

+58
-73
lines changed

fs/fuse/dev.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,7 +1364,6 @@ static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos,
13641364
goto out;
13651365

13661366
ret = 0;
1367-
pipe_lock(pipe);
13681367

13691368
if (!pipe->readers) {
13701369
send_sig(SIGPIPE, current, 0);
@@ -1400,7 +1399,6 @@ static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos,
14001399
}
14011400

14021401
out_unlock:
1403-
pipe_unlock(pipe);
14041402

14051403
if (do_wakeup) {
14061404
smp_mb();

fs/splice.c

Lines changed: 58 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -183,79 +183,41 @@ ssize_t splice_to_pipe(struct pipe_inode_info *pipe,
183183
struct splice_pipe_desc *spd)
184184
{
185185
unsigned int spd_pages = spd->nr_pages;
186-
int ret, do_wakeup, page_nr;
186+
int ret = 0, page_nr = 0;
187187

188188
if (!spd_pages)
189189
return 0;
190190

191-
ret = 0;
192-
do_wakeup = 0;
193-
page_nr = 0;
194-
195-
pipe_lock(pipe);
196-
197-
for (;;) {
198-
if (!pipe->readers) {
199-
send_sig(SIGPIPE, current, 0);
200-
if (!ret)
201-
ret = -EPIPE;
202-
break;
203-
}
204-
205-
if (pipe->nrbufs < pipe->buffers) {
206-
int newbuf = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);
207-
struct pipe_buffer *buf = pipe->bufs + newbuf;
208-
209-
buf->page = spd->pages[page_nr];
210-
buf->offset = spd->partial[page_nr].offset;
211-
buf->len = spd->partial[page_nr].len;
212-
buf->private = spd->partial[page_nr].private;
213-
buf->ops = spd->ops;
214-
if (spd->flags & SPLICE_F_GIFT)
215-
buf->flags |= PIPE_BUF_FLAG_GIFT;
216-
217-
pipe->nrbufs++;
218-
page_nr++;
219-
ret += buf->len;
220-
221-
if (pipe->files)
222-
do_wakeup = 1;
191+
if (unlikely(!pipe->readers)) {
192+
send_sig(SIGPIPE, current, 0);
193+
ret = -EPIPE;
194+
goto out;
195+
}
223196

224-
if (!--spd->nr_pages)
225-
break;
226-
if (pipe->nrbufs < pipe->buffers)
227-
continue;
197+
while (pipe->nrbufs < pipe->buffers) {
198+
int newbuf = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);
199+
struct pipe_buffer *buf = pipe->bufs + newbuf;
228200

229-
break;
230-
}
201+
buf->page = spd->pages[page_nr];
202+
buf->offset = spd->partial[page_nr].offset;
203+
buf->len = spd->partial[page_nr].len;
204+
buf->private = spd->partial[page_nr].private;
205+
buf->ops = spd->ops;
206+
if (spd->flags & SPLICE_F_GIFT)
207+
buf->flags |= PIPE_BUF_FLAG_GIFT;
231208

232-
if (spd->flags & SPLICE_F_NONBLOCK) {
233-
if (!ret)
234-
ret = -EAGAIN;
235-
break;
236-
}
209+
pipe->nrbufs++;
210+
page_nr++;
211+
ret += buf->len;
237212

238-
if (signal_pending(current)) {
239-
if (!ret)
240-
ret = -ERESTARTSYS;
213+
if (!--spd->nr_pages)
241214
break;
242-
}
243-
244-
if (do_wakeup) {
245-
wakeup_pipe_readers(pipe);
246-
do_wakeup = 0;
247-
}
248-
249-
pipe->waiting_writers++;
250-
pipe_wait(pipe);
251-
pipe->waiting_writers--;
252215
}
253216

254-
pipe_unlock(pipe);
255-
256-
if (do_wakeup)
257-
wakeup_pipe_readers(pipe);
217+
if (!ret)
218+
ret = -EAGAIN;
258219

220+
out:
259221
while (page_nr < spd_pages)
260222
spd->spd_release(spd, page_nr++);
261223

@@ -1339,6 +1301,20 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
13391301
}
13401302
EXPORT_SYMBOL(do_splice_direct);
13411303

1304+
static int wait_for_space(struct pipe_inode_info *pipe, unsigned flags)
1305+
{
1306+
while (pipe->nrbufs == pipe->buffers) {
1307+
if (flags & SPLICE_F_NONBLOCK)
1308+
return -EAGAIN;
1309+
if (signal_pending(current))
1310+
return -ERESTARTSYS;
1311+
pipe->waiting_writers++;
1312+
pipe_wait(pipe);
1313+
pipe->waiting_writers--;
1314+
}
1315+
return 0;
1316+
}
1317+
13421318
static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
13431319
struct pipe_inode_info *opipe,
13441320
size_t len, unsigned int flags);
@@ -1421,8 +1397,13 @@ static long do_splice(struct file *in, loff_t __user *off_in,
14211397
offset = in->f_pos;
14221398
}
14231399

1424-
ret = do_splice_to(in, &offset, opipe, len, flags);
1425-
1400+
pipe_lock(opipe);
1401+
ret = wait_for_space(opipe, flags);
1402+
if (!ret)
1403+
ret = do_splice_to(in, &offset, opipe, len, flags);
1404+
pipe_unlock(opipe);
1405+
if (ret > 0)
1406+
wakeup_pipe_readers(opipe);
14261407
if (!off_in)
14271408
in->f_pos = offset;
14281409
else if (copy_to_user(off_in, &offset, sizeof(loff_t)))
@@ -1546,14 +1527,20 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov,
15461527
return -ENOMEM;
15471528
}
15481529

1549-
spd.nr_pages = get_iovec_page_array(&from, spd.pages,
1550-
spd.partial,
1551-
spd.nr_pages_max);
1552-
if (spd.nr_pages <= 0)
1553-
ret = spd.nr_pages;
1554-
else
1555-
ret = splice_to_pipe(pipe, &spd);
1556-
1530+
pipe_lock(pipe);
1531+
ret = wait_for_space(pipe, flags);
1532+
if (!ret) {
1533+
spd.nr_pages = get_iovec_page_array(&from, spd.pages,
1534+
spd.partial,
1535+
spd.nr_pages_max);
1536+
if (spd.nr_pages <= 0)
1537+
ret = spd.nr_pages;
1538+
else
1539+
ret = splice_to_pipe(pipe, &spd);
1540+
}
1541+
pipe_unlock(pipe);
1542+
if (ret > 0)
1543+
wakeup_pipe_readers(pipe);
15571544
splice_shrink_spd(&spd);
15581545
kfree(iov);
15591546
return ret;

0 commit comments

Comments
 (0)