summaryrefslogtreecommitdiffstats
path: root/module/zcommon
diff options
context:
space:
mode:
authorChunwei Chen <[email protected]>2015-12-08 12:26:18 -0800
committerBrian Behlendorf <[email protected]>2015-12-15 16:19:55 -0800
commit502923bb447cdf4f9bc1271a46dfc11d5e0f2e9b (patch)
tree1b9cb1f509679226f7c574c24d2a1e55fd5fe66a /module/zcommon
parenteba9e745dcfce252fc6c451cdf07c55bf975f1f6 (diff)
Fix uio_prefaultpages for 0 length iovec
Userspace can freely pass in whatever iovec it feels like, and it's perfectly legal to pass an iovec which contains a zero length segment. In the current implementation, uio_prefaultpages would touch an out of bound byte in the "last byte" logic. While this probably wouldn't cause any critical error, we would like uio_prefaultpages to be able to continue gracefully. Signed-off-by: Chunwei Chen <[email protected]> Signed-off-by: Brian Behlendorf <[email protected]> Closes #4078
Diffstat (limited to 'module/zcommon')
-rw-r--r--module/zcommon/zfs_uio.c11
1 files changed, 6 insertions, 5 deletions
diff --git a/module/zcommon/zfs_uio.c b/module/zcommon/zfs_uio.c
index f78db68e4..9ec3002a2 100644
--- a/module/zcommon/zfs_uio.c
+++ b/module/zcommon/zfs_uio.c
@@ -164,7 +164,7 @@ uio_prefaultpages(ssize_t n, struct uio *uio)
caddr_t p;
uint8_t tmp;
int iovcnt;
- size_t skip = uio->uio_skip;
+ size_t skip;
/* no need to fault in kernel pages */
switch (uio->uio_segflg) {
@@ -180,9 +180,13 @@ uio_prefaultpages(ssize_t n, struct uio *uio)
iov = uio->uio_iov;
iovcnt = uio->uio_iovcnt;
+ skip = uio->uio_skip;
- while ((n > 0) && (iovcnt > 0)) {
+ for (; n > 0 && iovcnt > 0; iov++, iovcnt--, skip = 0) {
cnt = MIN(iov->iov_len - skip, n);
+ /* empty iov */
+ if (cnt == 0)
+ continue;
n -= cnt;
/*
* touch each page in this segment.
@@ -201,9 +205,6 @@ uio_prefaultpages(ssize_t n, struct uio *uio)
p--;
if (fuword8((uint8_t *) p, &tmp))
return;
- iov++;
- iovcnt--;
- skip = 0;
}
}
EXPORT_SYMBOL(uio_prefaultpages);