diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-11-30 10:47:50 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-11-30 10:47:50 -0800 |
commit | 5f1ca5c619c2af5e03114b0276642cdc15d11a94 (patch) | |
tree | 9dde48dc03bd345e184bbed650282adff68dd739 /lib | |
parent | 49afe6614321e78727729680b97e96998695249a (diff) | |
parent | 73116df7bb90435ccb2817f44113295240d15034 (diff) | |
download | linux-stable-5f1ca5c619c2af5e03114b0276642cdc15d11a94.tar.gz linux-stable-5f1ca5c619c2af5e03114b0276642cdc15d11a94.tar.bz2 linux-stable-5f1ca5c619c2af5e03114b0276642cdc15d11a94.zip |
Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs fixes from Al Viro:
"Assorted fixes all over the place.
The iov_iter one is this cycle regression (splice from UDP triggering
WARN_ON()), the rest is older"
* 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
afs: Use d_instantiate() rather than d_add() and don't d_drop()
afs: Fix missing net error handling
afs: Fix validation/callback interaction
iov_iter: teach csum_and_copy_to_iter() to handle pipe-backed ones
exportfs: do not read dentry after free
exportfs: fix 'passing zero to ERR_PTR()' warning
aio: fix failure to put the file pointer
sysv: return 'err' instead of 0 in __sysv_write_inode
Diffstat (limited to 'lib')
-rw-r--r-- | lib/iov_iter.c | 38 |
1 files changed, 37 insertions, 1 deletions
diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 7ebccb5c1637..54c248526b55 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -560,6 +560,38 @@ static size_t copy_pipe_to_iter(const void *addr, size_t bytes, return bytes; } +static size_t csum_and_copy_to_pipe_iter(const void *addr, size_t bytes, + __wsum *csum, struct iov_iter *i) +{ + struct pipe_inode_info *pipe = i->pipe; + size_t n, r; + size_t off = 0; + __wsum sum = *csum, next; + int idx; + + if (!sanity(i)) + return 0; + + bytes = n = push_pipe(i, bytes, &idx, &r); + if (unlikely(!n)) + return 0; + for ( ; n; idx = next_idx(idx, pipe), r = 0) { + size_t chunk = min_t(size_t, n, PAGE_SIZE - r); + char *p = kmap_atomic(pipe->bufs[idx].page); + next = csum_partial_copy_nocheck(addr, p + r, chunk, 0); + sum = csum_block_add(sum, next, off); + kunmap_atomic(p); + i->idx = idx; + i->iov_offset = r + chunk; + n -= chunk; + off += chunk; + addr += chunk; + } + i->count -= bytes; + *csum = sum; + return bytes; +} + size_t _copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i) { const char *from = addr; @@ -1438,8 +1470,12 @@ size_t csum_and_copy_to_iter(const void *addr, size_t bytes, __wsum *csum, const char *from = addr; __wsum sum, next; size_t off = 0; + + if (unlikely(iov_iter_is_pipe(i))) + return csum_and_copy_to_pipe_iter(addr, bytes, csum, i); + sum = *csum; - if (unlikely(iov_iter_is_pipe(i) || iov_iter_is_discard(i))) { + if (unlikely(iov_iter_is_discard(i))) { WARN_ON(1); /* for now */ return 0; } |