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 <david.chen@osnexus.com> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #4078
This commit is contained in:
parent
eba9e745dc
commit
502923bb44
|
@ -164,7 +164,7 @@ uio_prefaultpages(ssize_t n, struct uio *uio)
|
||||||
caddr_t p;
|
caddr_t p;
|
||||||
uint8_t tmp;
|
uint8_t tmp;
|
||||||
int iovcnt;
|
int iovcnt;
|
||||||
size_t skip = uio->uio_skip;
|
size_t skip;
|
||||||
|
|
||||||
/* no need to fault in kernel pages */
|
/* no need to fault in kernel pages */
|
||||||
switch (uio->uio_segflg) {
|
switch (uio->uio_segflg) {
|
||||||
|
@ -180,9 +180,13 @@ uio_prefaultpages(ssize_t n, struct uio *uio)
|
||||||
|
|
||||||
iov = uio->uio_iov;
|
iov = uio->uio_iov;
|
||||||
iovcnt = uio->uio_iovcnt;
|
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);
|
cnt = MIN(iov->iov_len - skip, n);
|
||||||
|
/* empty iov */
|
||||||
|
if (cnt == 0)
|
||||||
|
continue;
|
||||||
n -= cnt;
|
n -= cnt;
|
||||||
/*
|
/*
|
||||||
* touch each page in this segment.
|
* touch each page in this segment.
|
||||||
|
@ -201,9 +205,6 @@ uio_prefaultpages(ssize_t n, struct uio *uio)
|
||||||
p--;
|
p--;
|
||||||
if (fuword8((uint8_t *) p, &tmp))
|
if (fuword8((uint8_t *) p, &tmp))
|
||||||
return;
|
return;
|
||||||
iov++;
|
|
||||||
iovcnt--;
|
|
||||||
skip = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(uio_prefaultpages);
|
EXPORT_SYMBOL(uio_prefaultpages);
|
||||||
|
|
Loading…
Reference in New Issue