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 |