diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2017-03-23 10:28:11 +1100 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2017-03-23 10:28:14 +1100 |
commit | 9edad0d1d666181dd905072c1604c96813f87875 (patch) | |
tree | f423bac3e5158a848ef035ef06f314a71ef4575c | |
parent | 8a459d2906799966e7ad22a3597a33e715a19f31 (diff) | |
parent | 9e9c5ba8bd70714708bc9ae9b557eb8141f1de74 (diff) |
Merge remote-tracking branch 'vfs/for-next'
-rw-r--r-- | fs/splice.c | 22 | ||||
-rw-r--r-- | fs/xattr.c | 20 | ||||
-rw-r--r-- | include/linux/fs.h | 1 | ||||
-rw-r--r-- | include/linux/net.h | 2 | ||||
-rw-r--r-- | include/linux/skbuff.h | 3 | ||||
-rw-r--r-- | include/linux/splice.h | 4 | ||||
-rw-r--r-- | include/net/tcp.h | 2 | ||||
-rw-r--r-- | kernel/relay.c | 1 | ||||
-rw-r--r-- | kernel/trace/trace.c | 2 | ||||
-rw-r--r-- | net/core/skbuff.c | 4 | ||||
-rw-r--r-- | net/ipv4/tcp.c | 7 | ||||
-rw-r--r-- | net/kcm/kcmsock.c | 5 | ||||
-rw-r--r-- | net/smc/af_smc.c | 5 | ||||
-rw-r--r-- | net/socket.c | 4 | ||||
-rw-r--r-- | net/unix/af_unix.c | 113 |
15 files changed, 54 insertions, 141 deletions
diff --git a/fs/splice.c b/fs/splice.c index 006ba50f4ece..9299b59511b9 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -247,11 +247,6 @@ ssize_t add_to_pipe(struct pipe_inode_info *pipe, struct pipe_buffer *buf) } EXPORT_SYMBOL(add_to_pipe); -void spd_release_page(struct splice_pipe_desc *spd, unsigned int i) -{ - put_page(spd->pages[i]); -} - /* * Check if we need to grow the arrays holding pages and partial page * descriptions. @@ -308,6 +303,8 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos, iov_iter_pipe(&to, ITER_PIPE | READ, pipe, len); idx = to.idx; init_sync_kiocb(&kiocb, in); + if (flags & SPLICE_F_NONBLOCK) + kiocb.ki_flags |= IOCB_NDELAY; kiocb.ki_pos = *ppos; ret = call_read_iter(in, &kiocb, &to); if (ret > 0) { @@ -393,7 +390,7 @@ static ssize_t default_file_splice_read(struct file *in, loff_t *ppos, struct iov_iter to; struct page **pages; unsigned int nr_pages; - size_t offset, dummy, copied = 0; + size_t offset, base, copied = 0; ssize_t res; int i; @@ -408,12 +405,11 @@ static ssize_t default_file_splice_read(struct file *in, loff_t *ppos, iov_iter_pipe(&to, ITER_PIPE | READ, pipe, len + offset); - res = iov_iter_get_pages_alloc(&to, &pages, len + offset, &dummy); + res = iov_iter_get_pages_alloc(&to, &pages, len + offset, &base); if (res <= 0) return -ENOMEM; - BUG_ON(dummy); - nr_pages = DIV_ROUND_UP(res, PAGE_SIZE); + nr_pages = DIV_ROUND_UP(res + base, PAGE_SIZE); vec = __vec; if (nr_pages > PIPE_DEF_BUFFERS) { @@ -1359,6 +1355,8 @@ SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, iov, struct fd f; long error; + if (unlikely(flags & ~SPLICE_F_ALL)) + return -EINVAL; if (unlikely(nr_segs > UIO_MAXIOV)) return -EINVAL; else if (unlikely(!nr_segs)) @@ -1409,6 +1407,9 @@ SYSCALL_DEFINE6(splice, int, fd_in, loff_t __user *, off_in, if (unlikely(!len)) return 0; + if (unlikely(flags & ~SPLICE_F_ALL)) + return -EINVAL; + error = -EBADF; in = fdget(fd_in); if (in.file) { @@ -1737,6 +1738,9 @@ SYSCALL_DEFINE4(tee, int, fdin, int, fdout, size_t, len, unsigned int, flags) struct fd in; int error; + if (unlikely(flags & ~SPLICE_F_ALL)) + return -EINVAL; + if (unlikely(!len)) return 0; diff --git a/fs/xattr.c b/fs/xattr.c index 7e3317cf4045..c19a16323c2c 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -537,16 +537,18 @@ getxattr(struct dentry *d, const char __user *name, void __user *value, } error = vfs_getxattr(d, kname, kvalue, size); + if (error > XATTR_SIZE_MAX || + (error == -ERANGE && size >= XATTR_SIZE_MAX)) { + /* The file system tried to returned a value bigger + than XATTR_SIZE_MAX bytes. Not possible. */ + error = -E2BIG; + } if (error > 0) { if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) || (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0)) posix_acl_fix_xattr_to_user(kvalue, size); if (size && copy_to_user(value, kvalue, error)) error = -EFAULT; - } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) { - /* The file system tried to returned a value bigger - than XATTR_SIZE_MAX bytes. Not possible. */ - error = -E2BIG; } kvfree(kvalue); @@ -620,14 +622,16 @@ listxattr(struct dentry *d, char __user *list, size_t size) } error = vfs_listxattr(d, klist, size); - if (error > 0) { - if (size && copy_to_user(list, klist, error)) - error = -EFAULT; - } else if (error == -ERANGE && size >= XATTR_LIST_MAX) { + if (error > XATTR_LIST_MAX || + (error == -ERANGE && size >= XATTR_LIST_MAX)) { /* The file system tried to returned a list bigger than XATTR_LIST_MAX bytes. Not possible. */ error = -E2BIG; } + if (error > 0) { + if (size && copy_to_user(list, klist, error)) + error = -EFAULT; + } kvfree(klist); diff --git a/include/linux/fs.h b/include/linux/fs.h index 7251f7bb45e8..0dc9bc3fb1df 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -270,6 +270,7 @@ struct writeback_control; #define IOCB_DSYNC (1 << 4) #define IOCB_SYNC (1 << 5) #define IOCB_WRITE (1 << 6) +#define IOCB_NDELAY (1 << 7) struct kiocb { struct file *ki_filp; diff --git a/include/linux/net.h b/include/linux/net.h index 0620f5e18c96..7b89e24de8a1 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -186,7 +186,7 @@ struct proto_ops { struct vm_area_struct * vma); ssize_t (*sendpage) (struct socket *sock, struct page *page, int offset, size_t size, int flags); - ssize_t (*splice_read)(struct socket *sock, loff_t *ppos, + ssize_t (*splice_read)(struct file *file, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags); int (*set_peek_off)(struct sock *sk, int val); int (*peek_len)(struct socket *sock); diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index c776abd86937..4bcb75ffbad0 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3091,8 +3091,7 @@ int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len); __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, int len, __wsum csum); int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset, - struct pipe_inode_info *pipe, unsigned int len, - unsigned int flags); + struct pipe_inode_info *pipe, unsigned int len); void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to); unsigned int skb_zerocopy_headlen(const struct sk_buff *from); int skb_zerocopy(struct sk_buff *to, struct sk_buff *from, diff --git a/include/linux/splice.h b/include/linux/splice.h index 00a21166e268..db42746bdfea 100644 --- a/include/linux/splice.h +++ b/include/linux/splice.h @@ -20,6 +20,8 @@ #define SPLICE_F_MORE (0x04) /* expect more data */ #define SPLICE_F_GIFT (0x08) /* pages passed in are a gift */ +#define SPLICE_F_ALL (SPLICE_F_MOVE|SPLICE_F_NONBLOCK|SPLICE_F_MORE|SPLICE_F_GIFT) + /* * Passed to the actors */ @@ -55,7 +57,6 @@ struct splice_pipe_desc { struct partial_page *partial; /* pages[] may not be contig */ int nr_pages; /* number of populated pages in map */ unsigned int nr_pages_max; /* pages[] & partial[] arrays size */ - unsigned int flags; /* splice flags */ const struct pipe_buf_operations *ops;/* ops associated with output pipe */ void (*spd_release)(struct splice_pipe_desc *, unsigned int); }; @@ -82,7 +83,6 @@ extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *, */ extern int splice_grow_spd(const struct pipe_inode_info *, struct splice_pipe_desc *); extern void splice_shrink_spd(struct splice_pipe_desc *); -extern void spd_release_page(struct splice_pipe_desc *, unsigned int); extern const struct pipe_buf_operations page_cache_pipe_buf_ops; extern const struct pipe_buf_operations default_pipe_buf_ops; diff --git a/include/net/tcp.h b/include/net/tcp.h index 6ec4ea652f3f..1fce46b3d839 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -361,7 +361,7 @@ void tcp_rcv_established(struct sock *sk, struct sk_buff *skb, void tcp_rcv_space_adjust(struct sock *sk); int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp); void tcp_twsk_destructor(struct sock *sk); -ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos, +ssize_t tcp_splice_read(struct file *file, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags); diff --git a/kernel/relay.c b/kernel/relay.c index 0e413d9eec8a..39a9dfc69486 100644 --- a/kernel/relay.c +++ b/kernel/relay.c @@ -1212,7 +1212,6 @@ static ssize_t subbuf_splice_actor(struct file *in, .nr_pages = 0, .nr_pages_max = PIPE_DEF_BUFFERS, .partial = partial, - .flags = flags, .ops = &relay_pipe_buf_ops, .spd_release = relay_page_release, }; diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index f35109514a01..12f67868358b 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -5529,7 +5529,6 @@ static ssize_t tracing_splice_read_pipe(struct file *filp, .partial = partial_def, .nr_pages = 0, /* This gets updated below. */ .nr_pages_max = PIPE_DEF_BUFFERS, - .flags = flags, .ops = &tracing_pipe_buf_ops, .spd_release = tracing_spd_release_pipe, }; @@ -6427,7 +6426,6 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, .pages = pages_def, .partial = partial_def, .nr_pages_max = PIPE_DEF_BUFFERS, - .flags = flags, .ops = &buffer_pipe_buf_ops, .spd_release = buffer_spd_release, }; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 9f781092fda9..f30d65ba2eb8 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1971,8 +1971,7 @@ static bool __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe, * the fragments, and the frag list. */ int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset, - struct pipe_inode_info *pipe, unsigned int tlen, - unsigned int flags) + struct pipe_inode_info *pipe, unsigned int tlen) { struct partial_page partial[MAX_SKB_FRAGS]; struct page *pages[MAX_SKB_FRAGS]; @@ -1980,7 +1979,6 @@ int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset, .pages = pages, .partial = partial, .nr_pages_max = MAX_SKB_FRAGS, - .flags = flags, .ops = &nosteal_pipe_buf_ops, .spd_release = sock_spd_release, }; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 1e319a525d51..9b1b1c09d622 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -311,7 +311,6 @@ EXPORT_SYMBOL(tcp_sockets_allocated); struct tcp_splice_state { struct pipe_inode_info *pipe; size_t len; - unsigned int flags; }; /* @@ -690,7 +689,7 @@ static int tcp_splice_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, int ret; ret = skb_splice_bits(skb, skb->sk, offset, tss->pipe, - min(rd_desc->count, len), tss->flags); + min(rd_desc->count, len)); if (ret > 0) rd_desc->count -= ret; return ret; @@ -719,15 +718,15 @@ static int __tcp_splice_read(struct sock *sk, struct tcp_splice_state *tss) * Will read pages from given socket and fill them into a pipe. * **/ -ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos, +ssize_t tcp_splice_read(struct file *file, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags) { + struct socket *sock = file->private_data; struct sock *sk = sock->sk; struct tcp_splice_state tss = { .pipe = pipe, .len = len, - .flags = flags, }; long timeo; ssize_t spliced; diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index 309062f3debe..876da9dfd3fa 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -1168,10 +1168,11 @@ out: return copied ? : err; } -static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos, +static ssize_t kcm_splice_read(struct file *file, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags) { + struct socket *sock = file->private_data; struct sock *sk = sock->sk; struct kcm_sock *kcm = kcm_sk(sk); long timeo; @@ -1197,7 +1198,7 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos, if (len > rxm->full_len) len = rxm->full_len; - copied = skb_splice_bits(skb, sk, rxm->offset, pipe, len, flags); + copied = skb_splice_bits(skb, sk, rxm->offset, pipe, len); if (copied < 0) { err = copied; goto err_out; diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index 093803786eac..7a98dda6d1e0 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -1244,10 +1244,11 @@ out: return rc; } -static ssize_t smc_splice_read(struct socket *sock, loff_t *ppos, +static ssize_t smc_splice_read(struct file *file, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags) { + struct socket *sock = file->private_data; struct sock *sk = sock->sk; struct smc_sock *smc; int rc = -ENOTCONN; @@ -1257,7 +1258,7 @@ static ssize_t smc_splice_read(struct socket *sock, loff_t *ppos, if ((sk->sk_state != SMC_ACTIVE) && (sk->sk_state != SMC_CLOSED)) goto out; if (smc->use_fallback) { - rc = smc->clcsock->ops->splice_read(smc->clcsock, ppos, + rc = smc->clcsock->ops->splice_read(file, ppos, pipe, len, flags); } else { rc = -EOPNOTSUPP; diff --git a/net/socket.c b/net/socket.c index 985ef06792d6..62db2bbebe5b 100644 --- a/net/socket.c +++ b/net/socket.c @@ -812,7 +812,7 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos, if (unlikely(!sock->ops->splice_read)) return -EINVAL; - return sock->ops->splice_read(sock, ppos, pipe, len, flags); + return sock->ops->splice_read(file, ppos, pipe, len, flags); } static ssize_t sock_read_iter(struct kiocb *iocb, struct iov_iter *to) @@ -823,7 +823,7 @@ static ssize_t sock_read_iter(struct kiocb *iocb, struct iov_iter *to) .msg_iocb = iocb}; ssize_t res; - if (file->f_flags & O_NONBLOCK) + if ((file->f_flags & O_NONBLOCK) || (iocb->ki_flags & IOCB_NDELAY)) msg.msg_flags = MSG_DONTWAIT; if (iocb->ki_pos != 0) diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 928691c43408..26aaa5fd841b 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -647,9 +647,6 @@ static int unix_stream_sendmsg(struct socket *, struct msghdr *, size_t); static int unix_stream_recvmsg(struct socket *, struct msghdr *, size_t, int); static ssize_t unix_stream_sendpage(struct socket *, struct page *, int offset, size_t size, int flags); -static ssize_t unix_stream_splice_read(struct socket *, loff_t *ppos, - struct pipe_inode_info *, size_t size, - unsigned int flags); static int unix_dgram_sendmsg(struct socket *, struct msghdr *, size_t); static int unix_dgram_recvmsg(struct socket *, struct msghdr *, size_t, int); static int unix_dgram_connect(struct socket *, struct sockaddr *, @@ -691,7 +688,7 @@ static const struct proto_ops unix_stream_ops = { .recvmsg = unix_stream_recvmsg, .mmap = sock_no_mmap, .sendpage = unix_stream_sendpage, - .splice_read = unix_stream_splice_read, + .splice_read = generic_file_splice_read, .set_peek_off = unix_set_peek_off, }; @@ -2250,34 +2247,21 @@ static unsigned int unix_skb_len(const struct sk_buff *skb) return skb->len - UNIXCB(skb).consumed; } -struct unix_stream_read_state { - int (*recv_actor)(struct sk_buff *, int, int, - struct unix_stream_read_state *); - struct socket *socket; - struct msghdr *msg; - struct pipe_inode_info *pipe; - size_t size; - int flags; - unsigned int splice_flags; -}; - -static int unix_stream_read_generic(struct unix_stream_read_state *state, - bool freezable) +static int unix_stream_recvmsg(struct socket *sock, struct msghdr *msg, + size_t size, int flags) { struct scm_cookie scm; - struct socket *sock = state->socket; struct sock *sk = sock->sk; struct unix_sock *u = unix_sk(sk); int copied = 0; - int flags = state->flags; int noblock = flags & MSG_DONTWAIT; bool check_creds = false; int target; int err = 0; long timeo; int skip; - size_t size = state->size; unsigned int last_len; + bool freezable = !(msg->msg_iter.type & ITER_PIPE); if (unlikely(sk->sk_state != TCP_ESTABLISHED)) { err = -EINVAL; @@ -2306,7 +2290,6 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state, do { int chunk; - bool drop_skb; struct sk_buff *skb, *last; redo: @@ -2380,20 +2363,16 @@ unlock: } /* Copy address just once */ - if (state->msg && state->msg->msg_name) { + if (msg->msg_name) { DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, - state->msg->msg_name); - unix_copy_addr(state->msg, skb->sk); + msg->msg_name); + unix_copy_addr(msg, skb->sk); sunaddr = NULL; } chunk = min_t(unsigned int, unix_skb_len(skb) - skip, size); - skb_get(skb); - chunk = state->recv_actor(skb, skip, chunk, state); - drop_skb = !unix_skb_len(skb); - /* skb is only safe to use if !drop_skb */ - consume_skb(skb); - if (chunk < 0) { + if (skb_copy_datagram_msg(skb, UNIXCB(skb).consumed + skip, + msg, chunk)) { if (copied == 0) copied = -EFAULT; break; @@ -2401,18 +2380,6 @@ unlock: copied += chunk; size -= chunk; - if (drop_skb) { - /* the skb was touched by a concurrent reader; - * we should not expect anything from this skb - * anymore and assume it invalid - we can be - * sure it was dropped from the socket queue - * - * let's report a short read - */ - err = 0; - break; - } - /* Mark read part of skb as used */ if (!(flags & MSG_PEEK)) { UNIXCB(skb).consumed += chunk; @@ -2454,70 +2421,12 @@ unlock: } while (size); mutex_unlock(&u->iolock); - if (state->msg) - scm_recv(sock, state->msg, &scm, flags); - else - scm_destroy(&scm); + if (msg) + scm_recv(sock, msg, &scm, flags); out: return copied ? : err; } -static int unix_stream_read_actor(struct sk_buff *skb, - int skip, int chunk, - struct unix_stream_read_state *state) -{ - int ret; - - ret = skb_copy_datagram_msg(skb, UNIXCB(skb).consumed + skip, - state->msg, chunk); - return ret ?: chunk; -} - -static int unix_stream_recvmsg(struct socket *sock, struct msghdr *msg, - size_t size, int flags) -{ - struct unix_stream_read_state state = { - .recv_actor = unix_stream_read_actor, - .socket = sock, - .msg = msg, - .size = size, - .flags = flags - }; - - return unix_stream_read_generic(&state, true); -} - -static int unix_stream_splice_actor(struct sk_buff *skb, - int skip, int chunk, - struct unix_stream_read_state *state) -{ - return skb_splice_bits(skb, state->socket->sk, - UNIXCB(skb).consumed + skip, - state->pipe, chunk, state->splice_flags); -} - -static ssize_t unix_stream_splice_read(struct socket *sock, loff_t *ppos, - struct pipe_inode_info *pipe, - size_t size, unsigned int flags) -{ - struct unix_stream_read_state state = { - .recv_actor = unix_stream_splice_actor, - .socket = sock, - .pipe = pipe, - .size = size, - .splice_flags = flags, - }; - - if (unlikely(*ppos)) - return -ESPIPE; - - if (sock->file->f_flags & O_NONBLOCK || - flags & SPLICE_F_NONBLOCK) - state.flags = MSG_DONTWAIT; - - return unix_stream_read_generic(&state, false); -} - static int unix_shutdown(struct socket *sock, int mode) { struct sock *sk = sock->sk; |