View | Details | Raw Unified | Return to bug 262535
Collapse All | Expand All

(-)b/sys/compat/linux/linux_socket.c (-5 / +161 lines)
Lines 54-59 __FBSDID("$FreeBSD$"); Link Here
54
#include <sys/syslog.h>
54
#include <sys/syslog.h>
55
#include <sys/un.h>
55
#include <sys/un.h>
56
#include <sys/unistd.h>
56
#include <sys/unistd.h>
57
#include <sys/protosw.h>
58
#include <sys/vnode.h>
57
59
58
#include <security/audit/audit.h>
60
#include <security/audit/audit.h>
59
61
Lines 2058-2063 linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args) Link Here
2058
	return (error);
2060
	return (error);
2059
}
2061
}
2060
2062
2063
2064
/*
2065
 * Based on sendfile_getsock from kern_sendfile.c
2066
 * Determines whether an fd is a stream socket that can be used
2067
 * with FreeBSD sendfile.
2068
 */
2069
static bool
2070
_is_stream_socket(struct thread *td, l_int fd)
2071
{
2072
	int error;
2073
	struct file *sock_fp = NULL;
2074
	struct socket *so = NULL;
2075
2076
	/*
2077
	 * The socket must be a stream socket and connected.
2078
	 */
2079
	error = getsock_cap(td, fd, &cap_send_rights,
2080
	    &sock_fp, NULL, NULL);
2081
	if (error != 0)
2082
		return false;
2083
	so = sock_fp->f_data;
2084
	if (so->so_type != SOCK_STREAM)
2085
		return false;
2086
	/*
2087
	 * SCTP one-to-one style sockets currently don't work with
2088
	 * sendfile().
2089
	 */
2090
	if (so->so_proto->pr_protocol == IPPROTO_SCTP)
2091
		return false;
2092
	if (SOLISTENING(so))
2093
		return false;
2094
2095
	return true;
2096
}
2097
2098
#define TMPBUF_SIZE 8192
2099
2100
static int
2101
_sendfile_fallback(struct thread *td, struct file *fp,
2102
	struct file *outfp, l_loff_t current_offset,
2103
	l_size_t count, off_t *bytes_read)
2104
{
2105
	int error;
2106
	struct uio auio;
2107
	struct iovec aiov;
2108
	void *tmpbuf;
2109
	off_t out_offset;
2110
	l_size_t bytes_sent;
2111
	l_size_t n_read;
2112
2113
	error = (outfp->f_ops->fo_flags & DFLAG_SEEKABLE) != 0 ?
2114
		fo_seek(outfp, 0, SEEK_CUR, td) : 0;
2115
2116
	if (error != 0)
2117
		return (error);
2118
2119
	out_offset = td->td_uretoff.tdu_off;
2120
2121
	bytes_sent = 0;
2122
	tmpbuf = malloc(TMPBUF_SIZE, M_TEMP, M_WAITOK);
2123
2124
	if(!tmpbuf) {
2125
		error = ENOMEM;
2126
		return (error);
2127
	}
2128
2129
	while(bytes_sent < count) {
2130
2131
		off_t to_send = MIN(count - bytes_sent, TMPBUF_SIZE);
2132
2133
		/*
2134
		 * Read
2135
		 */
2136
2137
		aiov.iov_base = tmpbuf;
2138
		aiov.iov_len = TMPBUF_SIZE;
2139
2140
		auio.uio_iov = &aiov;
2141
		auio.uio_iovcnt = 1;
2142
		auio.uio_segflg = UIO_SYSSPACE;
2143
		auio.uio_td = td;
2144
2145
		auio.uio_rw = UIO_READ;
2146
		auio.uio_offset = current_offset + bytes_sent;
2147
		auio.uio_resid = to_send;
2148
2149
		error = fo_read(fp, &auio, fp->f_cred, FOF_OFFSET, td);
2150
		if (error != 0) {
2151
			goto cleanup;
2152
		}
2153
2154
		n_read = to_send - auio.uio_resid;
2155
2156
		if(n_read == 0)
2157
			break; /* eof */
2158
2159
		/*
2160
		 * Write
2161
		 */
2162
2163
		aiov.iov_base = tmpbuf;
2164
		aiov.iov_len = TMPBUF_SIZE;
2165
2166
		auio.uio_iov = &aiov;
2167
		auio.uio_iovcnt = 1;
2168
		auio.uio_segflg = UIO_SYSSPACE;
2169
		auio.uio_td = td;
2170
2171
		auio.uio_rw = UIO_WRITE;
2172
2173
		auio.uio_offset = ((outfp->f_ops->fo_flags & DFLAG_SEEKABLE) != 0) ?
2174
			out_offset + bytes_sent :
2175
			0;
2176
2177
		auio.uio_resid = n_read;
2178
2179
		error = fo_write(outfp, &auio, outfp->f_cred, FOF_OFFSET, td);
2180
		if (error != 0) {
2181
			goto cleanup;
2182
		}
2183
2184
		bytes_sent += n_read;
2185
	}
2186
2187
	if((outfp->f_ops->fo_flags & DFLAG_SEEKABLE) != 0) {
2188
		error = fo_seek(outfp, out_offset + bytes_sent, SEEK_SET, td);
2189
		if (error != 0) {
2190
			goto cleanup;
2191
		}
2192
	}
2193
2194
cleanup:
2195
	*bytes_read = bytes_sent;
2196
	free(tmpbuf, M_TEMP);
2197
	return (error);
2198
}
2199
2061
static int
2200
static int
2062
linux_sendfile_common(struct thread *td, l_int out, l_int in,
2201
linux_sendfile_common(struct thread *td, l_int out, l_int in,
2063
    l_loff_t *offset, l_size_t count)
2202
    l_loff_t *offset, l_size_t count)
Lines 2065-2077 linux_sendfile_common(struct thread *td, l_int out, l_int in, Link Here
2065
	off_t bytes_read;
2204
	off_t bytes_read;
2066
	int error;
2205
	int error;
2067
	l_loff_t current_offset;
2206
	l_loff_t current_offset;
2068
	struct file *fp;
2207
	struct file *fp, *outfp;
2208
	bool use_sendfile;
2069
2209
2070
	AUDIT_ARG_FD(in);
2210
	AUDIT_ARG_FD(in);
2071
	error = fget_read(td, in, &cap_pread_rights, &fp);
2211
	error = fget_read(td, in, &cap_pread_rights, &fp);
2072
	if (error != 0)
2212
	if (error != 0)
2073
		return (error);
2213
		return (error);
2074
2214
2215
	use_sendfile = _is_stream_socket(td, out) &&
2216
		((fp->f_type == DTYPE_VNODE && fp->f_vnode->v_type == VREG) ||
2217
		 fp->f_type == DTYPE_SHM);
2218
2075
	if (offset != NULL) {
2219
	if (offset != NULL) {
2076
		current_offset = *offset;
2220
		current_offset = *offset;
2077
	} else {
2221
	} else {
Lines 2090-2099 linux_sendfile_common(struct thread *td, l_int out, l_int in, Link Here
2090
		goto drop;
2234
		goto drop;
2091
	}
2235
	}
2092
2236
2093
	error = fo_sendfile(fp, out, NULL, NULL, current_offset, count,
2237
	if(use_sendfile) {
2094
	    &bytes_read, 0, td);
2238
		error = fo_sendfile(fp, out, NULL, NULL, current_offset, count,
2095
	if (error != 0)
2239
				&bytes_read, 0, td);
2240
	} else {
2241
		error = fget_write(td, out, &cap_pwrite_rights, &outfp);
2242
		if (error != 0)
2243
			return (error);
2244
		error = _sendfile_fallback(td, fp, outfp, current_offset, count, &bytes_read);
2245
		fdrop(outfp, td);
2246
	}
2247
2248
	if (error != 0) {
2096
		goto drop;
2249
		goto drop;
2250
	}
2251
2097
	current_offset += bytes_read;
2252
	current_offset += bytes_read;
2098
2253
2099
	if (offset != NULL) {
2254
	if (offset != NULL) {
Lines 2121-2127 linux_sendfile(struct thread *td, struct linux_sendfile_args *arg) Link Here
2121
	 *   mean send the whole file.)  In linux_sendfile given fds are still
2276
	 *   mean send the whole file.)  In linux_sendfile given fds are still
2122
	 *   checked for validity when the count is 0.
2277
	 *   checked for validity when the count is 0.
2123
	 * - Linux can send to any fd whereas FreeBSD only supports sockets.
2278
	 * - Linux can send to any fd whereas FreeBSD only supports sockets.
2124
	 *   The same restriction follows for linux_sendfile.
2279
	 *   We therefore use FreeBSD sendfile where possible for performance,
2280
	 *   but fall back on a manual copy (_sendfile_fallback)
2125
	 * - Linux doesn't have an equivalent for FreeBSD's flags and sf_hdtr.
2281
	 * - Linux doesn't have an equivalent for FreeBSD's flags and sf_hdtr.
2126
	 * - Linux takes an offset pointer and updates it to the read location.
2282
	 * - Linux takes an offset pointer and updates it to the read location.
2127
	 *   FreeBSD takes in an offset and a 'bytes read' parameter which is
2283
	 *   FreeBSD takes in an offset and a 'bytes read' parameter which is

Return to bug 262535