Skip to content

Commit

Permalink
Merge branch 'work.splice' of git://git.kernel.org/pub/scm/linux/kern…
Browse files Browse the repository at this point in the history
…el/git/viro/vfs

Pull splice updates from Al Viro:
 "Christoph's assorted splice cleanups"

* 'work.splice' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  fs: rename pipe_buf ->steal to ->try_steal
  fs: make the pipe_buf_operations ->confirm operation optional
  fs: make the pipe_buf_operations ->steal operation optional
  trace: remove tracing_pipe_buf_ops
  pipe: merge anon_pipe_buf*_ops
  fs: simplify do_splice_from
  fs: simplify do_splice_to
  • Loading branch information
Linus Torvalds committed Jun 3, 2020
2 parents 039aeb9 + c928f64 commit ae03c53
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 170 deletions.
2 changes: 1 addition & 1 deletion drivers/char/virtio_console.c
Original file line number Diff line number Diff line change
Expand Up @@ -871,7 +871,7 @@ static int pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
return 0;

/* Try lock this page */
if (pipe_buf_steal(pipe, buf) == 0) {
if (pipe_buf_try_steal(pipe, buf)) {
/* Get reference and unlock page for moving */
get_page(buf->page);
unlock_page(buf->page);
Expand Down
2 changes: 1 addition & 1 deletion fs/fuse/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
if (cs->len != PAGE_SIZE)
goto out_fallback;

if (pipe_buf_steal(cs->pipe, buf) != 0)
if (!pipe_buf_try_steal(cs->pipe, buf))
goto out_fallback;

newpage = buf->page;
Expand Down
96 changes: 21 additions & 75 deletions fs/pipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,21 +140,20 @@ static void anon_pipe_buf_release(struct pipe_inode_info *pipe,
put_page(page);
}

static int anon_pipe_buf_steal(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
static bool anon_pipe_buf_try_steal(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
{
struct page *page = buf->page;

if (page_count(page) == 1) {
memcg_kmem_uncharge_page(page, 0);
__SetPageLocked(page);
return 0;
}
return 1;
if (page_count(page) != 1)
return false;
memcg_kmem_uncharge_page(page, 0);
__SetPageLocked(page);
return true;
}

/**
* generic_pipe_buf_steal - attempt to take ownership of a &pipe_buffer
* generic_pipe_buf_try_steal - attempt to take ownership of a &pipe_buffer
* @pipe: the pipe that the buffer belongs to
* @buf: the buffer to attempt to steal
*
Expand All @@ -165,8 +164,8 @@ static int anon_pipe_buf_steal(struct pipe_inode_info *pipe,
* he wishes; the typical use is insertion into a different file
* page cache.
*/
int generic_pipe_buf_steal(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
bool generic_pipe_buf_try_steal(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
{
struct page *page = buf->page;

Expand All @@ -177,12 +176,11 @@ int generic_pipe_buf_steal(struct pipe_inode_info *pipe,
*/
if (page_count(page) == 1) {
lock_page(page);
return 0;
return true;
}

return 1;
return false;
}
EXPORT_SYMBOL(generic_pipe_buf_steal);
EXPORT_SYMBOL(generic_pipe_buf_try_steal);

/**
* generic_pipe_buf_get - get a reference to a &struct pipe_buffer
Expand All @@ -200,22 +198,6 @@ bool generic_pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf)
}
EXPORT_SYMBOL(generic_pipe_buf_get);

/**
* generic_pipe_buf_confirm - verify contents of the pipe buffer
* @info: the pipe that the buffer belongs to
* @buf: the buffer to confirm
*
* Description:
* This function does nothing, because the generic pipe code uses
* pages that are always good when inserted into the pipe.
*/
int generic_pipe_buf_confirm(struct pipe_inode_info *info,
struct pipe_buffer *buf)
{
return 0;
}
EXPORT_SYMBOL(generic_pipe_buf_confirm);

/**
* generic_pipe_buf_release - put a reference to a &struct pipe_buffer
* @pipe: the pipe that the buffer belongs to
Expand All @@ -231,48 +213,12 @@ void generic_pipe_buf_release(struct pipe_inode_info *pipe,
}
EXPORT_SYMBOL(generic_pipe_buf_release);

/* New data written to a pipe may be appended to a buffer with this type. */
static const struct pipe_buf_operations anon_pipe_buf_ops = {
.confirm = generic_pipe_buf_confirm,
.release = anon_pipe_buf_release,
.steal = anon_pipe_buf_steal,
.get = generic_pipe_buf_get,
};

static const struct pipe_buf_operations anon_pipe_buf_nomerge_ops = {
.confirm = generic_pipe_buf_confirm,
.release = anon_pipe_buf_release,
.steal = anon_pipe_buf_steal,
.get = generic_pipe_buf_get,
};

static const struct pipe_buf_operations packet_pipe_buf_ops = {
.confirm = generic_pipe_buf_confirm,
.release = anon_pipe_buf_release,
.steal = anon_pipe_buf_steal,
.get = generic_pipe_buf_get,
.release = anon_pipe_buf_release,
.try_steal = anon_pipe_buf_try_steal,
.get = generic_pipe_buf_get,
};

/**
* pipe_buf_mark_unmergeable - mark a &struct pipe_buffer as unmergeable
* @buf: the buffer to mark
*
* Description:
* This function ensures that no future writes will be merged into the
* given &struct pipe_buffer. This is necessary when multiple pipe buffers
* share the same backing page.
*/
void pipe_buf_mark_unmergeable(struct pipe_buffer *buf)
{
if (buf->ops == &anon_pipe_buf_ops)
buf->ops = &anon_pipe_buf_nomerge_ops;
}

static bool pipe_buf_can_merge(struct pipe_buffer *buf)
{
return buf->ops == &anon_pipe_buf_ops;
}

/* Done while waiting without holding the pipe lock - thus the READ_ONCE() */
static inline bool pipe_readable(const struct pipe_inode_info *pipe)
{
Expand Down Expand Up @@ -478,7 +424,8 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
struct pipe_buffer *buf = &pipe->bufs[(head - 1) & mask];
int offset = buf->offset + buf->len;

if (pipe_buf_can_merge(buf) && offset + chars <= PAGE_SIZE) {
if ((buf->flags & PIPE_BUF_FLAG_CAN_MERGE) &&
offset + chars <= PAGE_SIZE) {
ret = pipe_buf_confirm(pipe, buf);
if (ret)
goto out;
Expand Down Expand Up @@ -541,11 +488,10 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
buf->ops = &anon_pipe_buf_ops;
buf->offset = 0;
buf->len = 0;
buf->flags = 0;
if (is_packetized(filp)) {
buf->ops = &packet_pipe_buf_ops;
if (is_packetized(filp))
buf->flags = PIPE_BUF_FLAG_PACKET;
}
else
buf->flags = PIPE_BUF_FLAG_CAN_MERGE;
pipe->tmp_page = NULL;

copied = copy_page_from_iter(page, 0, PAGE_SIZE, from);
Expand Down
81 changes: 29 additions & 52 deletions fs/splice.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@
* addition of remove_mapping(). If success is returned, the caller may
* attempt to reuse this page for another destination.
*/
static int page_cache_pipe_buf_steal(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
static bool page_cache_pipe_buf_try_steal(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
{
struct page *page = buf->page;
struct address_space *mapping;
Expand Down Expand Up @@ -76,7 +76,7 @@ static int page_cache_pipe_buf_steal(struct pipe_inode_info *pipe,
*/
if (remove_mapping(mapping, page)) {
buf->flags |= PIPE_BUF_FLAG_LRU;
return 0;
return true;
}
}

Expand All @@ -86,7 +86,7 @@ static int page_cache_pipe_buf_steal(struct pipe_inode_info *pipe,
*/
out_unlock:
unlock_page(page);
return 1;
return false;
}

static void page_cache_pipe_buf_release(struct pipe_inode_info *pipe,
Expand Down Expand Up @@ -139,27 +139,26 @@ static int page_cache_pipe_buf_confirm(struct pipe_inode_info *pipe,
}

const struct pipe_buf_operations page_cache_pipe_buf_ops = {
.confirm = page_cache_pipe_buf_confirm,
.release = page_cache_pipe_buf_release,
.steal = page_cache_pipe_buf_steal,
.get = generic_pipe_buf_get,
.confirm = page_cache_pipe_buf_confirm,
.release = page_cache_pipe_buf_release,
.try_steal = page_cache_pipe_buf_try_steal,
.get = generic_pipe_buf_get,
};

static int user_page_pipe_buf_steal(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
static bool user_page_pipe_buf_try_steal(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
{
if (!(buf->flags & PIPE_BUF_FLAG_GIFT))
return 1;
return false;

buf->flags |= PIPE_BUF_FLAG_LRU;
return generic_pipe_buf_steal(pipe, buf);
return generic_pipe_buf_try_steal(pipe, buf);
}

static const struct pipe_buf_operations user_page_pipe_buf_ops = {
.confirm = generic_pipe_buf_confirm,
.release = page_cache_pipe_buf_release,
.steal = user_page_pipe_buf_steal,
.get = generic_pipe_buf_get,
.release = page_cache_pipe_buf_release,
.try_steal = user_page_pipe_buf_try_steal,
.get = generic_pipe_buf_get,
};

static void wakeup_pipe_readers(struct pipe_inode_info *pipe)
Expand Down Expand Up @@ -331,24 +330,15 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
EXPORT_SYMBOL(generic_file_splice_read);

const struct pipe_buf_operations default_pipe_buf_ops = {
.confirm = generic_pipe_buf_confirm,
.release = generic_pipe_buf_release,
.steal = generic_pipe_buf_steal,
.get = generic_pipe_buf_get,
.release = generic_pipe_buf_release,
.try_steal = generic_pipe_buf_try_steal,
.get = generic_pipe_buf_get,
};

int generic_pipe_buf_nosteal(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
{
return 1;
}

/* Pipe buffer operations for a socket and similar. */
const struct pipe_buf_operations nosteal_pipe_buf_ops = {
.confirm = generic_pipe_buf_confirm,
.release = generic_pipe_buf_release,
.steal = generic_pipe_buf_nosteal,
.get = generic_pipe_buf_get,
.release = generic_pipe_buf_release,
.get = generic_pipe_buf_get,
};
EXPORT_SYMBOL(nosteal_pipe_buf_ops);

Expand Down Expand Up @@ -852,15 +842,9 @@ EXPORT_SYMBOL(generic_splice_sendpage);
static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
loff_t *ppos, size_t len, unsigned int flags)
{
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *,
loff_t *, size_t, unsigned int);

if (out->f_op->splice_write)
splice_write = out->f_op->splice_write;
else
splice_write = default_file_splice_write;

return splice_write(pipe, out, ppos, len, flags);
return out->f_op->splice_write(pipe, out, ppos, len, flags);
return default_file_splice_write(pipe, out, ppos, len, flags);
}

/*
Expand All @@ -870,8 +854,6 @@ static long do_splice_to(struct file *in, loff_t *ppos,
struct pipe_inode_info *pipe, size_t len,
unsigned int flags)
{
ssize_t (*splice_read)(struct file *, loff_t *,
struct pipe_inode_info *, size_t, unsigned int);
int ret;

if (unlikely(!(in->f_mode & FMODE_READ)))
Expand All @@ -885,11 +867,8 @@ static long do_splice_to(struct file *in, loff_t *ppos,
len = MAX_RW_COUNT;

if (in->f_op->splice_read)
splice_read = in->f_op->splice_read;
else
splice_read = default_file_splice_read;

return splice_read(in, ppos, pipe, len, flags);
return in->f_op->splice_read(in, ppos, pipe, len, flags);
return default_file_splice_read(in, ppos, pipe, len, flags);
}

/**
Expand Down Expand Up @@ -1626,12 +1605,11 @@ static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
*obuf = *ibuf;

/*
* Don't inherit the gift flag, we need to
* Don't inherit the gift and merge flags, we need to
* prevent multiple steals of this page.
*/
obuf->flags &= ~PIPE_BUF_FLAG_GIFT;

pipe_buf_mark_unmergeable(obuf);
obuf->flags &= ~PIPE_BUF_FLAG_CAN_MERGE;

obuf->len = len;
ibuf->offset += len;
Expand Down Expand Up @@ -1719,12 +1697,11 @@ static int link_pipe(struct pipe_inode_info *ipipe,
*obuf = *ibuf;

/*
* Don't inherit the gift flag, we need to
* prevent multiple steals of this page.
* Don't inherit the gift and merge flag, we need to prevent
* multiple steals of this page.
*/
obuf->flags &= ~PIPE_BUF_FLAG_GIFT;

pipe_buf_mark_unmergeable(obuf);
obuf->flags &= ~PIPE_BUF_FLAG_CAN_MERGE;

if (obuf->len > len)
obuf->len = len;
Expand Down
Loading

0 comments on commit ae03c53

Please sign in to comment.