From 439900b6d514405a2330bd987ccfb3fdc0e31cc7 Mon Sep 17 00:00:00 2001 From: Chunwei Chen Date: Tue, 8 Dec 2015 12:26:18 -0800 Subject: [PATCH] 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 Signed-off-by: Brian Behlendorf Closes #4078 --- module/zcommon/zfs_uio.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/module/zcommon/zfs_uio.c b/module/zcommon/zfs_uio.c index f78db68e4ea6..9ec3002a29e4 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);