diff options
author | jh <jh@FreeBSD.org> | 2012-01-06 10:12:59 +0000 |
---|---|---|
committer | jh <jh@FreeBSD.org> | 2012-01-06 10:12:59 +0000 |
commit | 6417e1b242465c92e6adaf104b1cc3c1ec7384b8 (patch) | |
tree | 2fa0cbb3709536f2d46506d789480aa7586419a9 /sys/fs | |
parent | 372ed30c8e91cc51f38d19fefbe08ea92e21a01c (diff) | |
download | FreeBSD-src-6417e1b242465c92e6adaf104b1cc3c1ec7384b8.zip FreeBSD-src-6417e1b242465c92e6adaf104b1cc3c1ec7384b8.tar.gz |
r222004 changed sbuf_finish() to not clear the buffer error status. As a
consequence sbuf_len() will return -1 for buffers which had the error
status set prior to sbuf_finish() call. This causes a problem in
pfs_read() which purposely uses a fixed size sbuf to discard bytes which
are not needed to fulfill the read request.
Work around the problem by using the full buffer length when
sbuf_finish() indicates an overflow. An overflowed sbuf with fixed size
is always full.
PR: kern/163076
Approved by: des
MFC after: 2 weeks
Diffstat (limited to 'sys/fs')
-rw-r--r-- | sys/fs/pseudofs/pseudofs_vnops.c | 18 |
1 files changed, 12 insertions, 6 deletions
diff --git a/sys/fs/pseudofs/pseudofs_vnops.c b/sys/fs/pseudofs/pseudofs_vnops.c index 7d192e9..7db61e4 100644 --- a/sys/fs/pseudofs/pseudofs_vnops.c +++ b/sys/fs/pseudofs/pseudofs_vnops.c @@ -630,14 +630,14 @@ pfs_read(struct vop_read_args *va) if (uio->uio_offset < 0 || uio->uio_resid < 0 || (offset = uio->uio_offset) != uio->uio_offset || (resid = uio->uio_resid) != uio->uio_resid || - (buflen = offset + resid + 1) < offset || buflen > INT_MAX) { + (buflen = offset + resid) < offset || buflen >= INT_MAX) { error = EINVAL; goto ret; } - if (buflen > MAXPHYS + 1) - buflen = MAXPHYS + 1; + if (buflen > MAXPHYS) + buflen = MAXPHYS; - sb = sbuf_new(sb, NULL, buflen, 0); + sb = sbuf_new(sb, NULL, buflen + 1, 0); if (sb == NULL) { error = EIO; goto ret; @@ -650,8 +650,14 @@ pfs_read(struct vop_read_args *va) goto ret; } - sbuf_finish(sb); - error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio); + /* + * XXX: If the buffer overflowed, sbuf_len() will not return + * the data length. Then just use the full length because an + * overflowed sbuf must be full. + */ + if (sbuf_finish(sb) == 0) + buflen = sbuf_len(sb); + error = uiomove_frombuf(sbuf_data(sb), buflen, uio); sbuf_delete(sb); ret: vn_lock(vn, locked | LK_RETRY); |