/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include <sys/sysmacros.h>
#include <sys/socketvar.h>
#include <sys/sendfile.h>
ssize32_t *);
int, ssize_t *);
#if defined(_SYSCALL32_IMPL) || defined(_ILP32)
/*
* 64 bit offsets for 32 bit applications only running either on
* 64 bit kernel or 32 bit kernel. For 32 bit apps, we can't transfer
* more than 2GB of data.
*/
int
{
int ioflag;
int i, error;
for (i = 0; i < copy_cnt; i++) {
return (EINTR);
/*
* Do similar checks as "write" as we are writing
* sfv_len bytes into "vp".
*/
if (sfv_len == 0) {
sfv++;
continue;
}
if (sfv_len < 0)
return (EINVAL);
(void) rctl_action(
return (EFBIG);
}
return (EFBIG);
return (EINVAL);
}
if (tmpcount < 0)
return (EINVAL);
while (sfv_len > 0) {
if (error != 0)
return (error);
}
} else {
return (EBADF);
return (EBADF);
}
return (EINVAL);
}
/*
* No point reading and writing to same vp,
* as long as both are regular files. readvp is not
* locked; but since we got it from an open file the
* contents will be valid during the time of access.
*/
return (EINVAL);
}
/*
* Optimize the regular file over
* the socket case.
*/
if (error)
return (error);
sfv++;
continue;
}
/*
* Note: we assume readvp != vp. "vp" is already
* locked, and "readvp" must not be.
*/
NULL);
} else {
NULL);
}
/*
* Same checks as in pread64.
*/
if (sfv_off > MAXOFFSET_T) {
return (EINVAL);
}
/* Find the native blocksize to transfer data */
return (ENOMEM);
}
while (sfv_len > 0) {
/*
* If read sync is not asked for,
* filter sync flags
*/
if (error) {
NULL);
return (error);
}
/*
* Check how must data was really read.
* Decrement the 'len' and increment the
* 'off' appropriately.
*/
if (cnt == 0) {
/*
* If we were reading a pipe (currently
* not implemented), we may now lose
* data.
*/
NULL);
return (EINVAL);
}
/*
* Check how much data was written. Increment
* the 'len' and decrement the 'off' if all
* the data was not written.
*/
if (error != 0) {
NULL);
return (error);
}
}
}
sfv++;
}
return (0);
}
{
int copy_cnt;
int error;
do {
sizeof (struct ksendfilevec64))) {
break;
}
if (error != 0)
break;
} while (sfvcnt > 0);
if (error != 0)
return (count);
}
#endif
int
{
int ioflag;
int i, error;
#ifdef _SYSCALL32_IMPL
#else
#endif
int wroff;
int buf_left = 0;
int tail_len;
/* If nothing to send, return */
if (total_size == 0)
return (0);
} else {
}
return (ENOMEM);
for (i = 0; i < copy_cnt; i++) {
return (EINTR);
}
/*
* Do similar checks as "write" as we are writing
* sfv_len bytes into "vp".
*/
if (sfv_len == 0) {
sfv++;
continue;
}
/* Check for overflow */
#ifdef _SYSCALL32_IMPL
if (model == DATAMODEL_ILP32) {
return (EINVAL);
}
} else
#endif
return (EINVAL);
}
while (sfv_len > 0) {
if (buf_left == 0) {
return (ENOMEM);
}
} else {
}
total_size -= iov_len;
if (error != 0) {
return (error);
}
}
} else {
return (EBADF);
}
return (EACCES);
}
return (EINVAL);
}
/*
* No point reading and writing to same vp,
* as long as both are regular files. readvp is not
* locked; but since we got it from an open file the
* contents will be valid during the time of access.
*/
return (EINVAL);
}
/*
* Note: we assume readvp != vp. "vp" is already
* locked, and "readvp" must not be.
*/
NULL);
} else {
NULL);
}
/* Same checks as in pread */
return (EINVAL);
}
sfv_off);
}
while (sfv_len > 0) {
if (buf_left == 0) {
return (ENOMEM);
}
} else {
}
/*
* If read sync is not asked for,
* filter sync flags
*/
if (error != 0) {
/*
* If we were reading a pipe (currently
* not implemented), we may now loose
* data.
*/
NULL);
return (error);
}
/*
* Check how much data was really read.
* Decrement the 'len' and increment the
* 'off' appropriately.
*/
if (cnt == 0) {
NULL);
return (EINVAL);
}
total_size -= cnt;
}
}
sfv++;
}
ASSERT(total_size == 0);
if (error != 0) {
return (error);
}
return (0);
}
int
{
int ioflag;
int i, error;
#ifdef _SYSCALL32_IMPL
#else
#endif
} else {
}
}
for (i = 0; i < copy_cnt; i++) {
return (EINTR);
/*
* Do similar checks as "write" as we are writing
* sfv_len bytes into "vp".
*/
if (sfv_len == 0) {
sfv++;
continue;
}
(void) rctl_action(
return (EFBIG);
}
return (EFBIG);
return (EINVAL);
}
/* Check for overflow */
#ifdef _SYSCALL32_IMPL
if (model == DATAMODEL_ILP32) {
return (EINVAL);
} else
#endif
return (EINVAL);
while (sfv_len > 0) {
/*
* Socket filters can limit the mblk
* size, so limit reads to maxblk if
* there are filters present.
*/
if (so->so_filter_active > 0 &&
return (ENOMEM);
if (error != 0) {
return (error);
}
if (error != 0) {
return (error);
}
}
} else {
while (sfv_len > 0) {
if (error != 0)
return (error);
}
}
} else {
int segmapit = 0;
return (EBADF);
return (EBADF);
}
return (EINVAL);
}
/*
* No point reading and writing to same vp,
* as long as both are regular files. readvp is not
* locked; but since we got it from an open file the
* contents will be valid during the time of access.
*/
return (EINVAL);
}
/*
* Note: we assume readvp != vp. "vp" is already
* locked, and "readvp" must not be.
*/
NULL);
} else {
NULL);
}
/* Same checks as in pread */
return (EINVAL);
}
sfv_off);
}
/* Find the native blocksize to transfer data */
segmapit = 0;
NULL);
return (ENOMEM);
}
} else {
/*
* Socket filters can limit the mblk size,
* so limit reads to maxblk if there are
* filters present.
*/
if (so->so_filter_active > 0 &&
if (vn_has_flocks(readvp) ||
copyflag & STZCVMUNSAFE) {
segmapit = 0;
} else if (copyflag & STZCVMSAFE) {
segmapit = 1;
} else {
segmapit = 1;
}
}
if (segmapit) {
nowait);
if (error)
return (error);
sfv++;
continue;
}
while (sfv_len > 0) {
return (ENOMEM);
}
} else {
}
/*
* If read sync is not asked for,
* filter sync flags
*/
if (error != 0) {
/*
* If we were reading a pipe (currently
* not implemented), we may now lose
* data.
*/
else
NULL);
return (error);
}
/*
* Check how much data was really read.
* Decrement the 'len' and increment the
* 'off' appropriately.
*/
if (cnt == 0) {
else
NULL);
return (EINVAL);
}
if (error != 0) {
return (error);
}
} else {
/*
* Check how much data was written.
* Increment the 'len' and decrement the
* 'off' if all the data was not
* written.
*/
if (error != 0) {
return (error);
}
}
}
if (buf) {
}
}
sfv++;
}
return (0);
}
{
int error = 0;
int first_vector_error = 0;
int copy_cnt;
#ifdef _SYSCALL32_IMPL
#endif
int i;
int maxblk = 0;
if (sfvcnt <= 0)
goto err;
}
case VSOCK:
if (SOCK_IS_NONSTR(so)) {
} else {
}
break;
case VREG:
break;
default:
goto err;
}
switch (opcode) {
case SENDFILEV :
break;
#if defined(_SYSCALL32_IMPL) || defined(_ILP32)
case SENDFILEV64 :
#endif
default :
break;
}
do {
total_size = 0;
#ifdef _SYSCALL32_IMPL
/* 32-bit callers need to have their iovec expanded. */
if (get_udatamodel() == DATAMODEL_ILP32) {
copy_cnt * sizeof (ksendfilevec32_t))) {
break;
}
for (i = 0; i < copy_cnt; i++) {
/*
* Individual elements of the vector must not
* wrap or overflow, as later math is signed.
* Equally total_size needs to be checked after
* each vector is added in, to be sure that
* rogue values haven't overflowed the counter.
*/
((ssize32_t)total_size < 0)) {
/*
* Truncate the vector to send data
* described by elements before the
* error.
*/
copy_cnt = i;
/* total_size can't be trusted */
if ((ssize32_t)total_size < 0)
break;
}
}
/* Nothing to do, process errors */
if (copy_cnt == 0)
break;
} else {
#endif
copy_cnt * sizeof (sendfilevec_t))) {
break;
}
for (i = 0; i < copy_cnt; i++) {
/*
* Individual elements of the vector must not
* wrap or overflow, as later math is signed.
* Equally total_size needs to be checked after
* each vector is added in, to be sure that
* rogue values haven't overflowed the counter.
*/
(total_size < 0)) {
/*
* Truncate the vector to send data
* described by elements before the
* error.
*/
copy_cnt = i;
/* total_size can't be trusted */
if (total_size < 0)
break;
}
}
/* Nothing to do, process errors */
if (copy_cnt == 0)
break;
#ifdef _SYSCALL32_IMPL
}
#endif
/*
* The task between deciding to use sendvec_small_chunk
* and sendvec_chunk is dependant on multiple things:
*
* i) latency is important for smaller files. So if the
* data is smaller than 'tcp_slow_start_initial' times
* maxblk, then use sendvec_small_chunk which creates
* maxblk size mblks and chains them together and sends
* them to TCP in one shot. It also leaves 'wroff' size
* space for the headers in each mblk.
*
* ii) for total size bigger than 'tcp_slow_start_initial'
* time maxblk, its probably real file data which is
* dominating. So its better to use sendvec_chunk because
* performance goes to dog if we don't do pagesize reads.
* sendvec_chunk will do pagesize reads and write them
* in pagesize mblks to TCP.
*
* Side Notes: A write to file has not been optimized.
* Future zero copy code will plugin into sendvec_chunk
* only because doing zero copy for files smaller then
* pagesize is useless.
*
* Note, if socket has NL7C enabled then call NL7C's
* senfilev() function to consume the sfv[].
*/
if (is_sock) {
if (!SOCK_IS_NONSTR(so) &&
error == 0) {
} else {
}
} else {
&count);
}
#ifdef _SYSCALL32_IMPL
if (get_udatamodel() == DATAMODEL_ILP32)
(copy_cnt * sizeof (ksendfilevec32_t)));
else
#endif
/* Process all vector members up to first error */
#ifdef _SYSCALL32_IMPL
if (get_udatamodel() == DATAMODEL_ILP32) {
if (error != 0)
if (first_vector_error != 0)
return (set_errno(first_vector_error));
return (count32);
}
#endif
if (error != 0)
if (first_vector_error != 0)
return (set_errno(first_vector_error));
return (count);
err:
}