diff options
author | Chunwei Chen <[email protected]> | 2015-12-08 12:26:18 -0800 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2015-12-15 16:19:55 -0800 |
commit | 502923bb447cdf4f9bc1271a46dfc11d5e0f2e9b (patch) | |
tree | 1b9cb1f509679226f7c574c24d2a1e55fd5fe66a /module/zcommon | |
parent | eba9e745dcfce252fc6c451cdf07c55bf975f1f6 (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.c | 11 |
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); |