1 1.203 mlelstv /* $NetBSD: nfs_socket.c,v 1.203 2025/02/22 09:27:05 mlelstv Exp $ */ 2 1.15 cgd 3 1.1 cgd /* 4 1.24 fvdl * Copyright (c) 1989, 1991, 1993, 1995 5 1.14 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * This code is derived from software contributed to Berkeley by 8 1.1 cgd * Rick Macklem at The University of Guelph. 9 1.1 cgd * 10 1.1 cgd * Redistribution and use in source and binary forms, with or without 11 1.1 cgd * modification, are permitted provided that the following conditions 12 1.1 cgd * are met: 13 1.1 cgd * 1. Redistributions of source code must retain the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer. 15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 cgd * notice, this list of conditions and the following disclaimer in the 17 1.1 cgd * documentation and/or other materials provided with the distribution. 18 1.96 agc * 3. Neither the name of the University nor the names of its contributors 19 1.1 cgd * may be used to endorse or promote products derived from this software 20 1.1 cgd * without specific prior written permission. 21 1.1 cgd * 22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 cgd * SUCH DAMAGE. 33 1.1 cgd * 34 1.24 fvdl * @(#)nfs_socket.c 8.5 (Berkeley) 3/30/95 35 1.1 cgd */ 36 1.1 cgd 37 1.1 cgd /* 38 1.1 cgd * Socket operations for use by nfs 39 1.1 cgd */ 40 1.69 lukem 41 1.69 lukem #include <sys/cdefs.h> 42 1.203 mlelstv __KERNEL_RCSID(0, "$NetBSD: nfs_socket.c,v 1.203 2025/02/22 09:27:05 mlelstv Exp $"); 43 1.42 thorpej 44 1.174 ad #ifdef _KERNEL_OPT 45 1.59 bjh21 #include "opt_nfs.h" 46 1.89 martin #include "opt_mbuftrace.h" 47 1.174 ad #endif 48 1.1 cgd 49 1.9 mycroft #include <sys/param.h> 50 1.9 mycroft #include <sys/systm.h> 51 1.161 yamt #include <sys/evcnt.h> 52 1.54 thorpej #include <sys/callout.h> 53 1.9 mycroft #include <sys/proc.h> 54 1.9 mycroft #include <sys/mount.h> 55 1.9 mycroft #include <sys/kernel.h> 56 1.167 yamt #include <sys/kmem.h> 57 1.9 mycroft #include <sys/mbuf.h> 58 1.9 mycroft #include <sys/vnode.h> 59 1.9 mycroft #include <sys/domain.h> 60 1.9 mycroft #include <sys/protosw.h> 61 1.9 mycroft #include <sys/socket.h> 62 1.9 mycroft #include <sys/socketvar.h> 63 1.9 mycroft #include <sys/syslog.h> 64 1.9 mycroft #include <sys/tprintf.h> 65 1.23 christos #include <sys/namei.h> 66 1.47 mycroft #include <sys/signal.h> 67 1.47 mycroft #include <sys/signalvar.h> 68 1.130 elad #include <sys/kauth.h> 69 1.197 manu #include <sys/time.h> 70 1.1 cgd 71 1.9 mycroft #include <netinet/in.h> 72 1.9 mycroft #include <netinet/tcp.h> 73 1.24 fvdl 74 1.9 mycroft #include <nfs/rpcv2.h> 75 1.24 fvdl #include <nfs/nfsproto.h> 76 1.9 mycroft #include <nfs/nfs.h> 77 1.9 mycroft #include <nfs/xdr_subs.h> 78 1.9 mycroft #include <nfs/nfsm_subs.h> 79 1.9 mycroft #include <nfs/nfsmount.h> 80 1.14 mycroft #include <nfs/nfsnode.h> 81 1.14 mycroft #include <nfs/nfsrtt.h> 82 1.23 christos #include <nfs/nfs_var.h> 83 1.78 thorpej 84 1.79 matt #ifdef MBUFTRACE 85 1.139 dogcow struct mowner nfs_mowner = MOWNER_INIT("nfs",""); 86 1.79 matt #endif 87 1.1 cgd 88 1.1 cgd /* 89 1.14 mycroft * Estimate rto for an nfs rpc sent via. an unreliable datagram. 90 1.14 mycroft * Use the mean and mean deviation of rtt for the appropriate type of rpc 91 1.14 mycroft * for the frequent rpcs and a default for the others. 92 1.14 mycroft * The justification for doing "other" this way is that these rpcs 93 1.14 mycroft * happen so infrequently that timer est. would probably be stale. 94 1.14 mycroft * Also, since many of these rpcs are 95 1.14 mycroft * non-idempotent, a conservative timeout is desired. 96 1.14 mycroft * getattr, lookup - A+2D 97 1.14 mycroft * read, write - A+4D 98 1.14 mycroft * other - nm_timeo 99 1.14 mycroft */ 100 1.14 mycroft #define NFS_RTO(n, t) \ 101 1.14 mycroft ((t) == 0 ? (n)->nm_timeo : \ 102 1.14 mycroft ((t) < 3 ? \ 103 1.14 mycroft (((((n)->nm_srtt[t-1] + 3) >> 2) + (n)->nm_sdrtt[t-1] + 1) >> 1) : \ 104 1.14 mycroft ((((n)->nm_srtt[t-1] + 7) >> 3) + (n)->nm_sdrtt[t-1] + 1))) 105 1.187 pooka #define NFS_SRTT(r) (r)->r_nmp->nm_srtt[nfs_proct[(r)->r_procnum] - 1] 106 1.187 pooka #define NFS_SDRTT(r) (r)->r_nmp->nm_sdrtt[nfs_proct[(r)->r_procnum] - 1] 107 1.175 mrg 108 1.14 mycroft /* 109 1.14 mycroft * Defines which timer to use for the procnum. 110 1.14 mycroft * 0 - default 111 1.14 mycroft * 1 - getattr 112 1.14 mycroft * 2 - lookup 113 1.14 mycroft * 3 - read 114 1.14 mycroft * 4 - write 115 1.14 mycroft */ 116 1.187 pooka const int nfs_proct[NFS_NPROCS] = { 117 1.118 yamt [NFSPROC_NULL] = 0, 118 1.118 yamt [NFSPROC_GETATTR] = 1, 119 1.118 yamt [NFSPROC_SETATTR] = 0, 120 1.118 yamt [NFSPROC_LOOKUP] = 2, 121 1.118 yamt [NFSPROC_ACCESS] = 1, 122 1.118 yamt [NFSPROC_READLINK] = 3, 123 1.118 yamt [NFSPROC_READ] = 3, 124 1.118 yamt [NFSPROC_WRITE] = 4, 125 1.118 yamt [NFSPROC_CREATE] = 0, 126 1.118 yamt [NFSPROC_MKDIR] = 0, 127 1.118 yamt [NFSPROC_SYMLINK] = 0, 128 1.118 yamt [NFSPROC_MKNOD] = 0, 129 1.118 yamt [NFSPROC_REMOVE] = 0, 130 1.118 yamt [NFSPROC_RMDIR] = 0, 131 1.118 yamt [NFSPROC_RENAME] = 0, 132 1.118 yamt [NFSPROC_LINK] = 0, 133 1.118 yamt [NFSPROC_READDIR] = 3, 134 1.118 yamt [NFSPROC_READDIRPLUS] = 3, 135 1.118 yamt [NFSPROC_FSSTAT] = 0, 136 1.118 yamt [NFSPROC_FSINFO] = 0, 137 1.118 yamt [NFSPROC_PATHCONF] = 0, 138 1.118 yamt [NFSPROC_COMMIT] = 0, 139 1.118 yamt [NFSPROC_NOOP] = 0, 140 1.1 cgd }; 141 1.14 mycroft 142 1.187 pooka #ifdef DEBUG 143 1.187 pooka /* 144 1.187 pooka * Avoid spamming the console with debugging messages. We only print 145 1.187 pooka * the nfs timer and reply error debugs every 10 seconds. 146 1.187 pooka */ 147 1.187 pooka const struct timeval nfs_err_interval = { 10, 0 }; 148 1.187 pooka struct timeval nfs_reply_last_err_time; 149 1.187 pooka struct timeval nfs_timer_last_err_time; 150 1.187 pooka #endif 151 1.187 pooka 152 1.14 mycroft /* 153 1.14 mycroft * There is a congestion window for outstanding rpcs maintained per mount 154 1.14 mycroft * point. The cwnd size is adjusted in roughly the way that: 155 1.14 mycroft * Van Jacobson, Congestion avoidance and Control, In "Proceedings of 156 1.14 mycroft * SIGCOMM '88". ACM, August 1988. 157 1.14 mycroft * describes for TCP. The cwnd size is chopped in half on a retransmit timeout 158 1.14 mycroft * and incremented by 1/cwnd when each rpc reply is received and a full cwnd 159 1.14 mycroft * of rpcs is in progress. 160 1.14 mycroft * (The sent count and cwnd are scaled for integer arith.) 161 1.14 mycroft * Variants of "slow start" were tried and were found to be too much of a 162 1.14 mycroft * performance hit (ave. rtt 3 times larger), 163 1.14 mycroft * I suspect due to the large rtt that nfs rpcs have. 164 1.14 mycroft */ 165 1.187 pooka int nfsrtton = 0; 166 1.187 pooka struct nfsrtt nfsrtt; 167 1.66 jdolecek static const int nfs_backoff[8] = { 2, 4, 8, 16, 32, 64, 128, 256, }; 168 1.74 matt struct nfsreqhead nfs_reqq; 169 1.199 christos kmutex_t nfs_reqq_lock; 170 1.161 yamt static callout_t nfs_timer_ch; 171 1.161 yamt static struct evcnt nfs_timer_ev; 172 1.161 yamt static struct evcnt nfs_timer_start_ev; 173 1.161 yamt static struct evcnt nfs_timer_stop_ev; 174 1.174 ad static kmutex_t nfs_timer_lock; 175 1.174 ad static bool (*nfs_timer_srvvec)(void); 176 1.54 thorpej 177 1.1 cgd /* 178 1.1 cgd * Initialize sockets and congestion for a new NFS connection. 179 1.1 cgd * We do not free the sockaddr if error. 180 1.1 cgd */ 181 1.23 christos int 182 1.179 dsl nfs_connect(struct nfsmount *nmp, struct nfsreq *rep, struct lwp *l) 183 1.1 cgd { 184 1.55 augustss struct socket *so; 185 1.170 ad int error, rcvreserve, sndreserve; 186 1.11 cgd struct sockaddr *saddr; 187 1.194 rtr struct sockaddr_in sin; 188 1.194 rtr struct sockaddr_in6 sin6; 189 1.171 plunky int val; 190 1.1 cgd 191 1.183 dyoung nmp->nm_so = NULL; 192 1.11 cgd saddr = mtod(nmp->nm_nam, struct sockaddr *); 193 1.105 jonathan error = socreate(saddr->sa_family, &nmp->nm_so, 194 1.170 ad nmp->nm_sotype, nmp->nm_soproto, l, NULL); 195 1.23 christos if (error) 196 1.1 cgd goto bad; 197 1.1 cgd so = nmp->nm_so; 198 1.79 matt #ifdef MBUFTRACE 199 1.79 matt so->so_mowner = &nfs_mowner; 200 1.79 matt so->so_rcv.sb_mowner = &nfs_mowner; 201 1.79 matt so->so_snd.sb_mowner = &nfs_mowner; 202 1.79 matt #endif 203 1.1 cgd nmp->nm_soflags = so->so_proto->pr_flags; 204 1.1 cgd 205 1.2 cgd /* 206 1.2 cgd * Some servers require that the client port be a reserved port number. 207 1.2 cgd */ 208 1.14 mycroft if (saddr->sa_family == AF_INET && (nmp->nm_flag & NFSMNT_RESVPORT)) { 209 1.171 plunky val = IP_PORTRANGE_LOW; 210 1.171 plunky 211 1.171 plunky if ((error = so_setsockopt(NULL, so, IPPROTO_IP, IP_PORTRANGE, 212 1.171 plunky &val, sizeof(val)))) 213 1.72 lukem goto bad; 214 1.194 rtr sin.sin_len = sizeof(struct sockaddr_in); 215 1.194 rtr sin.sin_family = AF_INET; 216 1.194 rtr sin.sin_addr.s_addr = INADDR_ANY; 217 1.194 rtr sin.sin_port = 0; 218 1.194 rtr error = sobind(so, (struct sockaddr *)&sin, &lwp0); 219 1.14 mycroft if (error) 220 1.14 mycroft goto bad; 221 1.2 cgd } 222 1.57 fvdl if (saddr->sa_family == AF_INET6 && (nmp->nm_flag & NFSMNT_RESVPORT)) { 223 1.171 plunky val = IPV6_PORTRANGE_LOW; 224 1.171 plunky 225 1.171 plunky if ((error = so_setsockopt(NULL, so, IPPROTO_IPV6, 226 1.171 plunky IPV6_PORTRANGE, &val, sizeof(val)))) 227 1.72 lukem goto bad; 228 1.194 rtr memset(&sin6, 0, sizeof(sin6)); 229 1.194 rtr sin6.sin6_len = sizeof(struct sockaddr_in6); 230 1.194 rtr sin6.sin6_family = AF_INET6; 231 1.194 rtr error = sobind(so, (struct sockaddr *)&sin6, &lwp0); 232 1.57 fvdl if (error) 233 1.57 fvdl goto bad; 234 1.57 fvdl } 235 1.2 cgd 236 1.1 cgd /* 237 1.1 cgd * Protocols that do not require connections may be optionally left 238 1.1 cgd * unconnected for servers that reply from a port other than NFS_PORT. 239 1.1 cgd */ 240 1.170 ad solock(so); 241 1.1 cgd if (nmp->nm_flag & NFSMNT_NOCONN) { 242 1.1 cgd if (nmp->nm_soflags & PR_CONNREQUIRED) { 243 1.170 ad sounlock(so); 244 1.1 cgd error = ENOTCONN; 245 1.1 cgd goto bad; 246 1.1 cgd } 247 1.1 cgd } else { 248 1.195 rtr error = soconnect(so, mtod(nmp->nm_nam, struct sockaddr *), l); 249 1.170 ad if (error) { 250 1.170 ad sounlock(so); 251 1.1 cgd goto bad; 252 1.170 ad } 253 1.1 cgd 254 1.1 cgd /* 255 1.1 cgd * Wait for the connection to complete. Cribbed from the 256 1.14 mycroft * connect system call but with the wait timing out so 257 1.14 mycroft * that interruptible mounts don't hang here for a long time. 258 1.1 cgd */ 259 1.14 mycroft while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { 260 1.177 yamt (void)sowait(so, false, 2 * hz); 261 1.14 mycroft if ((so->so_state & SS_ISCONNECTING) && 262 1.14 mycroft so->so_error == 0 && rep && 263 1.119 christos (error = nfs_sigintr(nmp, rep, rep->r_lwp)) != 0){ 264 1.14 mycroft so->so_state &= ~SS_ISCONNECTING; 265 1.170 ad sounlock(so); 266 1.14 mycroft goto bad; 267 1.14 mycroft } 268 1.14 mycroft } 269 1.1 cgd if (so->so_error) { 270 1.1 cgd error = so->so_error; 271 1.14 mycroft so->so_error = 0; 272 1.170 ad sounlock(so); 273 1.1 cgd goto bad; 274 1.1 cgd } 275 1.14 mycroft } 276 1.14 mycroft if (nmp->nm_flag & (NFSMNT_SOFT | NFSMNT_INT)) { 277 1.14 mycroft so->so_rcv.sb_timeo = (5 * hz); 278 1.14 mycroft so->so_snd.sb_timeo = (5 * hz); 279 1.14 mycroft } else { 280 1.106 yamt /* 281 1.106 yamt * enable receive timeout to detect server crash and reconnect. 282 1.106 yamt * otherwise, we can be stuck in soreceive forever. 283 1.106 yamt */ 284 1.106 yamt so->so_rcv.sb_timeo = (5 * hz); 285 1.14 mycroft so->so_snd.sb_timeo = 0; 286 1.1 cgd } 287 1.1 cgd if (nmp->nm_sotype == SOCK_DGRAM) { 288 1.189 tls sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * 3; 289 1.200 riastrad rcvreserve = (uimax(nmp->nm_rsize, nmp->nm_readdirsize) + 290 1.37 fvdl NFS_MAXPKTHDR) * 2; 291 1.14 mycroft } else if (nmp->nm_sotype == SOCK_SEQPACKET) { 292 1.189 tls sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * 3; 293 1.200 riastrad rcvreserve = (uimax(nmp->nm_rsize, nmp->nm_readdirsize) + 294 1.189 tls NFS_MAXPKTHDR) * 3; 295 1.1 cgd } else { 296 1.170 ad sounlock(so); 297 1.14 mycroft if (nmp->nm_sotype != SOCK_STREAM) 298 1.14 mycroft panic("nfscon sotype"); 299 1.1 cgd if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 300 1.171 plunky val = 1; 301 1.171 plunky so_setsockopt(NULL, so, SOL_SOCKET, SO_KEEPALIVE, &val, 302 1.171 plunky sizeof(val)); 303 1.1 cgd } 304 1.14 mycroft if (so->so_proto->pr_protocol == IPPROTO_TCP) { 305 1.171 plunky val = 1; 306 1.171 plunky so_setsockopt(NULL, so, IPPROTO_TCP, TCP_NODELAY, &val, 307 1.171 plunky sizeof(val)); 308 1.1 cgd } 309 1.22 cgd sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR + 310 1.189 tls sizeof (u_int32_t)) * 3; 311 1.22 cgd rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR + 312 1.189 tls sizeof (u_int32_t)) * 3; 313 1.170 ad solock(so); 314 1.1 cgd } 315 1.24 fvdl error = soreserve(so, sndreserve, rcvreserve); 316 1.170 ad if (error) { 317 1.170 ad sounlock(so); 318 1.14 mycroft goto bad; 319 1.170 ad } 320 1.1 cgd so->so_rcv.sb_flags |= SB_NOINTR; 321 1.1 cgd so->so_snd.sb_flags |= SB_NOINTR; 322 1.170 ad sounlock(so); 323 1.1 cgd 324 1.1 cgd /* Initialize other non-zero congestion variables */ 325 1.14 mycroft nmp->nm_srtt[0] = nmp->nm_srtt[1] = nmp->nm_srtt[2] = nmp->nm_srtt[3] = 326 1.68 simonb NFS_TIMEO << 3; 327 1.14 mycroft nmp->nm_sdrtt[0] = nmp->nm_sdrtt[1] = nmp->nm_sdrtt[2] = 328 1.68 simonb nmp->nm_sdrtt[3] = 0; 329 1.14 mycroft nmp->nm_cwnd = NFS_MAXCWND / 2; /* Initial send window */ 330 1.1 cgd nmp->nm_sent = 0; 331 1.14 mycroft nmp->nm_timeouts = 0; 332 1.1 cgd return (0); 333 1.1 cgd 334 1.1 cgd bad: 335 1.1 cgd nfs_disconnect(nmp); 336 1.1 cgd return (error); 337 1.1 cgd } 338 1.1 cgd 339 1.1 cgd /* 340 1.1 cgd * Reconnect routine: 341 1.1 cgd * Called when a connection is broken on a reliable protocol. 342 1.1 cgd * - clean up the old socket 343 1.1 cgd * - nfs_connect() again 344 1.1 cgd * - set R_MUSTRESEND for all outstanding requests on mount point 345 1.1 cgd * If this fails the mount point is DEAD! 346 1.14 mycroft * nb: Must be called with the nfs_sndlock() set on the mount point. 347 1.1 cgd */ 348 1.23 christos int 349 1.164 yamt nfs_reconnect(struct nfsreq *rep) 350 1.1 cgd { 351 1.55 augustss struct nfsreq *rp; 352 1.55 augustss struct nfsmount *nmp = rep->r_nmp; 353 1.198 christos int error, s; 354 1.197 manu time_t before_ts; 355 1.1 cgd 356 1.14 mycroft nfs_disconnect(nmp); 357 1.197 manu 358 1.197 manu /* 359 1.197 manu * Force unmount: do not try to reconnect 360 1.197 manu */ 361 1.197 manu if (nmp->nm_iflag & NFSMNT_DISMNTFORCE) 362 1.197 manu return EIO; 363 1.197 manu 364 1.197 manu before_ts = time_uptime; 365 1.164 yamt while ((error = nfs_connect(nmp, rep, &lwp0)) != 0) { 366 1.14 mycroft if (error == EINTR || error == ERESTART) 367 1.1 cgd return (EINTR); 368 1.197 manu 369 1.197 manu if (rep->r_flags & R_SOFTTERM) 370 1.197 manu return (EIO); 371 1.197 manu 372 1.197 manu /* 373 1.197 manu * Soft mount can fail here, but not too fast: 374 1.197 manu * we want to make sure we at least honoured 375 1.197 manu * NFS timeout. 376 1.197 manu */ 377 1.197 manu if ((nmp->nm_flag & NFSMNT_SOFT) && 378 1.197 manu (time_uptime - before_ts > nmp->nm_timeo / NFS_HZ)) 379 1.197 manu return (EIO); 380 1.197 manu 381 1.163 yamt kpause("nfscn2", false, hz, NULL); 382 1.1 cgd } 383 1.1 cgd 384 1.1 cgd /* 385 1.1 cgd * Loop through outstanding request list and fix up all requests 386 1.1 cgd * on old socket. 387 1.1 cgd */ 388 1.198 christos s = splsoftnet(); 389 1.199 christos mutex_enter(&nfs_reqq_lock); 390 1.73 christos TAILQ_FOREACH(rp, &nfs_reqq, r_chain) { 391 1.106 yamt if (rp->r_nmp == nmp) { 392 1.106 yamt if ((rp->r_flags & R_MUSTRESEND) == 0) 393 1.106 yamt rp->r_flags |= R_MUSTRESEND | R_REXMITTED; 394 1.106 yamt rp->r_rexmit = 0; 395 1.106 yamt } 396 1.1 cgd } 397 1.199 christos mutex_exit(&nfs_reqq_lock); 398 1.198 christos splx(s); 399 1.1 cgd return (0); 400 1.1 cgd } 401 1.1 cgd 402 1.1 cgd /* 403 1.1 cgd * NFS disconnect. Clean up and unlink. 404 1.1 cgd */ 405 1.1 cgd void 406 1.179 dsl nfs_disconnect(struct nfsmount *nmp) 407 1.1 cgd { 408 1.55 augustss struct socket *so; 409 1.53 sommerfe int drain = 0; 410 1.112 perry 411 1.1 cgd if (nmp->nm_so) { 412 1.1 cgd so = nmp->nm_so; 413 1.183 dyoung nmp->nm_so = NULL; 414 1.170 ad solock(so); 415 1.143 yamt soshutdown(so, SHUT_RDWR); 416 1.170 ad sounlock(so); 417 1.53 sommerfe drain = (nmp->nm_iflag & NFSMNT_DISMNT) != 0; 418 1.53 sommerfe if (drain) { 419 1.51 sommerfe /* 420 1.51 sommerfe * soshutdown() above should wake up the current 421 1.51 sommerfe * listener. 422 1.71 minoura * Now wake up those waiting for the receive lock, and 423 1.51 sommerfe * wait for them to go away unhappy, to prevent *nmp 424 1.51 sommerfe * from evaporating while they're sleeping. 425 1.51 sommerfe */ 426 1.151 yamt mutex_enter(&nmp->nm_lock); 427 1.51 sommerfe while (nmp->nm_waiters > 0) { 428 1.150 yamt cv_broadcast(&nmp->nm_rcvcv); 429 1.150 yamt cv_broadcast(&nmp->nm_sndcv); 430 1.151 yamt cv_wait(&nmp->nm_disconcv, &nmp->nm_lock); 431 1.51 sommerfe } 432 1.151 yamt mutex_exit(&nmp->nm_lock); 433 1.51 sommerfe } 434 1.1 cgd soclose(so); 435 1.41 fvdl } 436 1.51 sommerfe #ifdef DIAGNOSTIC 437 1.53 sommerfe if (drain && (nmp->nm_waiters > 0)) 438 1.76 provos panic("nfs_disconnect: waiters left after drain?"); 439 1.51 sommerfe #endif 440 1.41 fvdl } 441 1.40 fvdl 442 1.41 fvdl void 443 1.179 dsl nfs_safedisconnect(struct nfsmount *nmp) 444 1.41 fvdl { 445 1.41 fvdl struct nfsreq dummyreq; 446 1.41 fvdl 447 1.46 perry memset(&dummyreq, 0, sizeof(dummyreq)); 448 1.41 fvdl dummyreq.r_nmp = nmp; 449 1.150 yamt nfs_rcvlock(nmp, &dummyreq); /* XXX ignored error return */ 450 1.41 fvdl nfs_disconnect(nmp); 451 1.87 yamt nfs_rcvunlock(nmp); 452 1.1 cgd } 453 1.1 cgd 454 1.1 cgd /* 455 1.1 cgd * This is the nfs send routine. For connection based socket types, it 456 1.14 mycroft * must be called with an nfs_sndlock() on the socket. 457 1.1 cgd * "rep == NULL" indicates that it has been called from a server. 458 1.14 mycroft * For the client side: 459 1.14 mycroft * - return EINTR if the RPC is terminated, 0 otherwise 460 1.14 mycroft * - set R_MUSTRESEND if the send fails for any reason 461 1.58 mrg * - do any cleanup required by recoverable socket errors (? ? ?) 462 1.14 mycroft * For the server side: 463 1.14 mycroft * - return EINTR or ERESTART if interrupted by a signal 464 1.14 mycroft * - return EPIPE if a connection is lost for connection based sockets (TCP...) 465 1.58 mrg * - do any cleanup required by recoverable socket errors (? ? ?) 466 1.1 cgd */ 467 1.23 christos int 468 1.179 dsl nfs_send(struct socket *so, struct mbuf *nam, struct mbuf *top, struct nfsreq *rep, struct lwp *l) 469 1.1 cgd { 470 1.196 rtr struct sockaddr *sendnam; 471 1.14 mycroft int error, soflags, flags; 472 1.1 cgd 473 1.119 christos /* XXX nfs_doio()/nfs_request() calls with rep->r_lwp == NULL */ 474 1.119 christos if (l == NULL && rep->r_lwp == NULL) 475 1.119 christos l = curlwp; 476 1.105 jonathan 477 1.1 cgd if (rep) { 478 1.1 cgd if (rep->r_flags & R_SOFTTERM) { 479 1.1 cgd m_freem(top); 480 1.1 cgd return (EINTR); 481 1.1 cgd } 482 1.14 mycroft if ((so = rep->r_nmp->nm_so) == NULL) { 483 1.14 mycroft rep->r_flags |= R_MUSTRESEND; 484 1.14 mycroft m_freem(top); 485 1.14 mycroft return (0); 486 1.14 mycroft } 487 1.1 cgd rep->r_flags &= ~R_MUSTRESEND; 488 1.1 cgd soflags = rep->r_nmp->nm_soflags; 489 1.1 cgd } else 490 1.1 cgd soflags = so->so_proto->pr_flags; 491 1.1 cgd if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED)) 492 1.183 dyoung sendnam = NULL; 493 1.1 cgd else 494 1.196 rtr sendnam = mtod(nam, struct sockaddr *); 495 1.14 mycroft if (so->so_type == SOCK_SEQPACKET) 496 1.14 mycroft flags = MSG_EOR; 497 1.14 mycroft else 498 1.14 mycroft flags = 0; 499 1.1 cgd 500 1.165 yamt error = (*so->so_send)(so, sendnam, NULL, top, NULL, flags, l); 501 1.14 mycroft if (error) { 502 1.14 mycroft if (rep) { 503 1.60 fvdl if (error == ENOBUFS && so->so_type == SOCK_DGRAM) { 504 1.60 fvdl /* 505 1.60 fvdl * We're too fast for the network/driver, 506 1.60 fvdl * and UDP isn't flowcontrolled. 507 1.60 fvdl * We need to resend. This is not fatal, 508 1.60 fvdl * just try again. 509 1.60 fvdl * 510 1.60 fvdl * Could be smarter here by doing some sort 511 1.60 fvdl * of a backoff, but this is rare. 512 1.60 fvdl */ 513 1.14 mycroft rep->r_flags |= R_MUSTRESEND; 514 1.60 fvdl } else { 515 1.101 matt if (error != EPIPE) 516 1.101 matt log(LOG_INFO, 517 1.101 matt "nfs send error %d for %s\n", 518 1.101 matt error, 519 1.101 matt rep->r_nmp->nm_mountp-> 520 1.101 matt mnt_stat.f_mntfromname); 521 1.60 fvdl /* 522 1.60 fvdl * Deal with errors for the client side. 523 1.60 fvdl */ 524 1.60 fvdl if (rep->r_flags & R_SOFTTERM) 525 1.60 fvdl error = EINTR; 526 1.181 pooka else if (error != EMSGSIZE) 527 1.60 fvdl rep->r_flags |= R_MUSTRESEND; 528 1.60 fvdl } 529 1.67 fvdl } else { 530 1.67 fvdl /* 531 1.67 fvdl * See above. This error can happen under normal 532 1.67 fvdl * circumstances and the log is too noisy. 533 1.67 fvdl * The error will still show up in nfsstat. 534 1.67 fvdl */ 535 1.67 fvdl if (error != ENOBUFS || so->so_type != SOCK_DGRAM) 536 1.67 fvdl log(LOG_INFO, "nfsd send error %d\n", error); 537 1.67 fvdl } 538 1.14 mycroft 539 1.14 mycroft /* 540 1.58 mrg * Handle any recoverable (soft) socket errors here. (? ? ?) 541 1.14 mycroft */ 542 1.14 mycroft if (error != EINTR && error != ERESTART && 543 1.181 pooka error != EWOULDBLOCK && error != EPIPE && 544 1.181 pooka error != EMSGSIZE) 545 1.1 cgd error = 0; 546 1.1 cgd } 547 1.1 cgd return (error); 548 1.1 cgd } 549 1.1 cgd 550 1.1 cgd /* 551 1.1 cgd * Generate the rpc reply header 552 1.1 cgd * siz arg. is used to decide if adding a cluster is worthwhile 553 1.1 cgd */ 554 1.23 christos int 555 1.179 dsl nfs_rephead(int siz, struct nfsrv_descript *nd, struct nfssvc_sock *slp, int err, int cache, u_quad_t *frev, struct mbuf **mrq, struct mbuf **mbp, char **bposp) 556 1.1 cgd { 557 1.55 augustss u_int32_t *tl; 558 1.55 augustss struct mbuf *mreq; 559 1.148 christos char *bpos; 560 1.79 matt struct mbuf *mb; 561 1.1 cgd 562 1.79 matt mreq = m_gethdr(M_WAIT, MT_DATA); 563 1.79 matt MCLAIM(mreq, &nfs_mowner); 564 1.1 cgd mb = mreq; 565 1.14 mycroft /* 566 1.14 mycroft * If this is a big reply, use a cluster else 567 1.14 mycroft * try and leave leading space for the lower level headers. 568 1.14 mycroft */ 569 1.14 mycroft siz += RPC_REPLYSIZ; 570 1.45 fvdl if (siz >= max_datalen) { 571 1.79 matt m_clget(mreq, M_WAIT); 572 1.14 mycroft } else 573 1.14 mycroft mreq->m_data += max_hdr; 574 1.22 cgd tl = mtod(mreq, u_int32_t *); 575 1.24 fvdl mreq->m_len = 6 * NFSX_UNSIGNED; 576 1.148 christos bpos = ((char *)tl) + mreq->m_len; 577 1.14 mycroft *tl++ = txdr_unsigned(nd->nd_retxid); 578 1.1 cgd *tl++ = rpc_reply; 579 1.24 fvdl if (err == ERPCMISMATCH || (err & NFSERR_AUTHERR)) { 580 1.1 cgd *tl++ = rpc_msgdenied; 581 1.24 fvdl if (err & NFSERR_AUTHERR) { 582 1.14 mycroft *tl++ = rpc_autherr; 583 1.24 fvdl *tl = txdr_unsigned(err & ~NFSERR_AUTHERR); 584 1.14 mycroft mreq->m_len -= NFSX_UNSIGNED; 585 1.14 mycroft bpos -= NFSX_UNSIGNED; 586 1.14 mycroft } else { 587 1.14 mycroft *tl++ = rpc_mismatch; 588 1.24 fvdl *tl++ = txdr_unsigned(RPC_VER2); 589 1.24 fvdl *tl = txdr_unsigned(RPC_VER2); 590 1.14 mycroft } 591 1.1 cgd } else { 592 1.1 cgd *tl++ = rpc_msgaccepted; 593 1.24 fvdl 594 1.24 fvdl /* 595 1.24 fvdl * For Kerberos authentication, we must send the nickname 596 1.24 fvdl * verifier back, otherwise just RPCAUTH_NULL. 597 1.24 fvdl */ 598 1.24 fvdl if (nd->nd_flag & ND_KERBFULL) { 599 1.84 yamt struct nfsuid *nuidp; 600 1.84 yamt struct timeval ktvin, ktvout; 601 1.24 fvdl 602 1.129 mrg memset(&ktvout, 0, sizeof ktvout); /* XXX gcc */ 603 1.129 mrg 604 1.131 yamt LIST_FOREACH(nuidp, 605 1.131 yamt NUIDHASH(slp, kauth_cred_geteuid(nd->nd_cr)), 606 1.84 yamt nu_hash) { 607 1.131 yamt if (kauth_cred_geteuid(nuidp->nu_cr) == 608 1.131 yamt kauth_cred_geteuid(nd->nd_cr) && 609 1.84 yamt (!nd->nd_nam2 || netaddr_match( 610 1.84 yamt NU_NETFAM(nuidp), &nuidp->nu_haddr, 611 1.84 yamt nd->nd_nam2))) 612 1.84 yamt break; 613 1.84 yamt } 614 1.84 yamt if (nuidp) { 615 1.84 yamt ktvin.tv_sec = 616 1.84 yamt txdr_unsigned(nuidp->nu_timestamp.tv_sec 617 1.84 yamt - 1); 618 1.84 yamt ktvin.tv_usec = 619 1.84 yamt txdr_unsigned(nuidp->nu_timestamp.tv_usec); 620 1.24 fvdl 621 1.84 yamt /* 622 1.84 yamt * Encrypt the timestamp in ecb mode using the 623 1.84 yamt * session key. 624 1.84 yamt */ 625 1.24 fvdl #ifdef NFSKERB 626 1.84 yamt XXX 627 1.190 martin #else 628 1.190 martin (void)ktvin.tv_sec; 629 1.24 fvdl #endif 630 1.24 fvdl 631 1.84 yamt *tl++ = rpc_auth_kerb; 632 1.84 yamt *tl++ = txdr_unsigned(3 * NFSX_UNSIGNED); 633 1.84 yamt *tl = ktvout.tv_sec; 634 1.84 yamt nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 635 1.84 yamt *tl++ = ktvout.tv_usec; 636 1.131 yamt *tl++ = txdr_unsigned( 637 1.131 yamt kauth_cred_geteuid(nuidp->nu_cr)); 638 1.84 yamt } else { 639 1.84 yamt *tl++ = 0; 640 1.84 yamt *tl++ = 0; 641 1.84 yamt } 642 1.24 fvdl } else { 643 1.24 fvdl *tl++ = 0; 644 1.24 fvdl *tl++ = 0; 645 1.24 fvdl } 646 1.1 cgd switch (err) { 647 1.1 cgd case EPROGUNAVAIL: 648 1.1 cgd *tl = txdr_unsigned(RPC_PROGUNAVAIL); 649 1.1 cgd break; 650 1.1 cgd case EPROGMISMATCH: 651 1.1 cgd *tl = txdr_unsigned(RPC_PROGMISMATCH); 652 1.24 fvdl nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 653 1.144 yamt *tl++ = txdr_unsigned(2); 654 1.144 yamt *tl = txdr_unsigned(3); 655 1.1 cgd break; 656 1.1 cgd case EPROCUNAVAIL: 657 1.1 cgd *tl = txdr_unsigned(RPC_PROCUNAVAIL); 658 1.1 cgd break; 659 1.24 fvdl case EBADRPC: 660 1.24 fvdl *tl = txdr_unsigned(RPC_GARBAGE); 661 1.24 fvdl break; 662 1.1 cgd default: 663 1.1 cgd *tl = 0; 664 1.24 fvdl if (err != NFSERR_RETVOID) { 665 1.22 cgd nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 666 1.14 mycroft if (err) 667 1.24 fvdl *tl = txdr_unsigned(nfsrv_errmap(nd, err)); 668 1.14 mycroft else 669 1.24 fvdl *tl = 0; 670 1.1 cgd } 671 1.1 cgd break; 672 1.1 cgd }; 673 1.1 cgd } 674 1.14 mycroft 675 1.34 fvdl if (mrq != NULL) 676 1.34 fvdl *mrq = mreq; 677 1.1 cgd *mbp = mb; 678 1.1 cgd *bposp = bpos; 679 1.24 fvdl if (err != 0 && err != NFSERR_RETVOID) 680 1.1 cgd nfsstats.srvrpc_errs++; 681 1.1 cgd return (0); 682 1.1 cgd } 683 1.1 cgd 684 1.161 yamt static void 685 1.161 yamt nfs_timer_schedule(void) 686 1.161 yamt { 687 1.161 yamt 688 1.161 yamt callout_schedule(&nfs_timer_ch, nfs_ticks); 689 1.161 yamt } 690 1.161 yamt 691 1.161 yamt void 692 1.161 yamt nfs_timer_start(void) 693 1.161 yamt { 694 1.161 yamt 695 1.161 yamt if (callout_pending(&nfs_timer_ch)) 696 1.161 yamt return; 697 1.161 yamt 698 1.161 yamt nfs_timer_start_ev.ev_count++; 699 1.161 yamt nfs_timer_schedule(); 700 1.161 yamt } 701 1.161 yamt 702 1.161 yamt void 703 1.161 yamt nfs_timer_init(void) 704 1.161 yamt { 705 1.161 yamt 706 1.174 ad mutex_init(&nfs_timer_lock, MUTEX_DEFAULT, IPL_NONE); 707 1.161 yamt callout_init(&nfs_timer_ch, 0); 708 1.161 yamt callout_setfunc(&nfs_timer_ch, nfs_timer, NULL); 709 1.161 yamt evcnt_attach_dynamic(&nfs_timer_ev, EVCNT_TYPE_MISC, NULL, 710 1.161 yamt "nfs", "timer"); 711 1.161 yamt evcnt_attach_dynamic(&nfs_timer_start_ev, EVCNT_TYPE_MISC, NULL, 712 1.161 yamt "nfs", "timer start"); 713 1.161 yamt evcnt_attach_dynamic(&nfs_timer_stop_ev, EVCNT_TYPE_MISC, NULL, 714 1.161 yamt "nfs", "timer stop"); 715 1.161 yamt } 716 1.161 yamt 717 1.174 ad void 718 1.174 ad nfs_timer_fini(void) 719 1.174 ad { 720 1.174 ad 721 1.174 ad callout_halt(&nfs_timer_ch, NULL); 722 1.174 ad callout_destroy(&nfs_timer_ch); 723 1.174 ad mutex_destroy(&nfs_timer_lock); 724 1.174 ad evcnt_detach(&nfs_timer_ev); 725 1.174 ad evcnt_detach(&nfs_timer_start_ev); 726 1.174 ad evcnt_detach(&nfs_timer_stop_ev); 727 1.174 ad } 728 1.174 ad 729 1.174 ad void 730 1.174 ad nfs_timer_srvinit(bool (*func)(void)) 731 1.174 ad { 732 1.174 ad 733 1.174 ad nfs_timer_srvvec = func; 734 1.174 ad } 735 1.174 ad 736 1.174 ad void 737 1.174 ad nfs_timer_srvfini(void) 738 1.174 ad { 739 1.174 ad 740 1.174 ad mutex_enter(&nfs_timer_lock); 741 1.174 ad nfs_timer_srvvec = NULL; 742 1.174 ad mutex_exit(&nfs_timer_lock); 743 1.174 ad } 744 1.174 ad 745 1.174 ad 746 1.1 cgd /* 747 1.1 cgd * Nfs timer routine 748 1.202 andvar * Scan the nfsreq list and retransmit any requests that have timed out 749 1.1 cgd * To avoid retransmission attempts on STREAM sockets (in the future) make 750 1.1 cgd * sure to set the r_retry field to 0 (implies nm_retry == 0). 751 1.1 cgd */ 752 1.7 mycroft void 753 1.141 yamt nfs_timer(void *arg) 754 1.1 cgd { 755 1.55 augustss struct nfsreq *rep; 756 1.55 augustss struct mbuf *m; 757 1.55 augustss struct socket *so; 758 1.55 augustss struct nfsmount *nmp; 759 1.55 augustss int timeo; 760 1.178 ad int error; 761 1.161 yamt bool more = false; 762 1.1 cgd 763 1.161 yamt nfs_timer_ev.ev_count++; 764 1.160 ad 765 1.199 christos mutex_enter(&nfs_reqq_lock); 766 1.73 christos TAILQ_FOREACH(rep, &nfs_reqq, r_chain) { 767 1.161 yamt more = true; 768 1.1 cgd nmp = rep->r_nmp; 769 1.14 mycroft if (rep->r_mrep || (rep->r_flags & R_SOFTTERM)) 770 1.1 cgd continue; 771 1.119 christos if (nfs_sigintr(nmp, rep, rep->r_lwp)) { 772 1.1 cgd rep->r_flags |= R_SOFTTERM; 773 1.1 cgd continue; 774 1.1 cgd } 775 1.14 mycroft if (rep->r_rtt >= 0) { 776 1.14 mycroft rep->r_rtt++; 777 1.14 mycroft if (nmp->nm_flag & NFSMNT_DUMBTIMR) 778 1.14 mycroft timeo = nmp->nm_timeo; 779 1.14 mycroft else 780 1.187 pooka timeo = NFS_RTO(nmp, nfs_proct[rep->r_procnum]); 781 1.14 mycroft if (nmp->nm_timeouts > 0) 782 1.14 mycroft timeo *= nfs_backoff[nmp->nm_timeouts - 1]; 783 1.176 mrg if (timeo > NFS_MAXTIMEO) 784 1.176 mrg timeo = NFS_MAXTIMEO; 785 1.14 mycroft if (rep->r_rtt <= timeo) 786 1.14 mycroft continue; 787 1.98 yamt if (nmp->nm_timeouts < 788 1.98 yamt (sizeof(nfs_backoff) / sizeof(nfs_backoff[0]))) 789 1.14 mycroft nmp->nm_timeouts++; 790 1.1 cgd } 791 1.1 cgd /* 792 1.1 cgd * Check for server not responding 793 1.1 cgd */ 794 1.1 cgd if ((rep->r_flags & R_TPRINTFMSG) == 0 && 795 1.14 mycroft rep->r_rexmit > nmp->nm_deadthresh) { 796 1.119 christos nfs_msg(rep->r_lwp, 797 1.1 cgd nmp->nm_mountp->mnt_stat.f_mntfromname, 798 1.1 cgd "not responding"); 799 1.1 cgd rep->r_flags |= R_TPRINTFMSG; 800 1.1 cgd } 801 1.1 cgd if (rep->r_rexmit >= rep->r_retry) { /* too many */ 802 1.1 cgd nfsstats.rpctimeouts++; 803 1.1 cgd rep->r_flags |= R_SOFTTERM; 804 1.1 cgd continue; 805 1.1 cgd } 806 1.14 mycroft if (nmp->nm_sotype != SOCK_DGRAM) { 807 1.14 mycroft if (++rep->r_rexmit > NFS_MAXREXMIT) 808 1.14 mycroft rep->r_rexmit = NFS_MAXREXMIT; 809 1.14 mycroft continue; 810 1.14 mycroft } 811 1.14 mycroft if ((so = nmp->nm_so) == NULL) 812 1.1 cgd continue; 813 1.1 cgd 814 1.1 cgd /* 815 1.1 cgd * If there is enough space and the window allows.. 816 1.1 cgd * Resend it 817 1.14 mycroft * Set r_rtt to -1 in case we fail to send it now. 818 1.1 cgd */ 819 1.199 christos solock(so); 820 1.14 mycroft rep->r_rtt = -1; 821 1.1 cgd if (sbspace(&so->so_snd) >= rep->r_mreq->m_pkthdr.len && 822 1.14 mycroft ((nmp->nm_flag & NFSMNT_DUMBTIMR) || 823 1.14 mycroft (rep->r_flags & R_SENT) || 824 1.14 mycroft nmp->nm_sent < nmp->nm_cwnd) && 825 1.14 mycroft (m = m_copym(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT))){ 826 1.40 fvdl if (so->so_state & SS_ISCONNECTED) 827 1.192 rtr error = (*so->so_proto->pr_usrreqs->pr_send)(so, 828 1.192 rtr m, NULL, NULL, NULL); 829 1.1 cgd else 830 1.192 rtr error = (*so->so_proto->pr_usrreqs->pr_send)(so, 831 1.195 rtr m, mtod(nmp->nm_nam, struct sockaddr *), 832 1.195 rtr NULL, NULL); 833 1.1 cgd if (error) { 834 1.33 fvdl if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) { 835 1.37 fvdl #ifdef DEBUG 836 1.175 mrg if (ratecheck(&nfs_timer_last_err_time, 837 1.175 mrg &nfs_err_interval)) 838 1.175 mrg printf("%s: ignoring error " 839 1.175 mrg "%d\n", __func__, error); 840 1.37 fvdl #endif 841 1.1 cgd so->so_error = 0; 842 1.33 fvdl } 843 1.1 cgd } else { 844 1.1 cgd /* 845 1.14 mycroft * Iff first send, start timing 846 1.14 mycroft * else turn timing off, backoff timer 847 1.14 mycroft * and divide congestion window by 2. 848 1.1 cgd */ 849 1.14 mycroft if (rep->r_flags & R_SENT) { 850 1.14 mycroft rep->r_flags &= ~R_TIMING; 851 1.14 mycroft if (++rep->r_rexmit > NFS_MAXREXMIT) 852 1.14 mycroft rep->r_rexmit = NFS_MAXREXMIT; 853 1.14 mycroft nmp->nm_cwnd >>= 1; 854 1.14 mycroft if (nmp->nm_cwnd < NFS_CWNDSCALE) 855 1.14 mycroft nmp->nm_cwnd = NFS_CWNDSCALE; 856 1.14 mycroft nfsstats.rpcretries++; 857 1.14 mycroft } else { 858 1.14 mycroft rep->r_flags |= R_SENT; 859 1.14 mycroft nmp->nm_sent += NFS_CWNDSCALE; 860 1.14 mycroft } 861 1.14 mycroft rep->r_rtt = 0; 862 1.1 cgd } 863 1.1 cgd } 864 1.199 christos sounlock(so); 865 1.1 cgd } 866 1.199 christos mutex_exit(&nfs_reqq_lock); 867 1.14 mycroft 868 1.174 ad mutex_enter(&nfs_timer_lock); 869 1.174 ad if (nfs_timer_srvvec != NULL) { 870 1.174 ad more |= (*nfs_timer_srvvec)(); 871 1.24 fvdl } 872 1.174 ad mutex_exit(&nfs_timer_lock); 873 1.174 ad 874 1.161 yamt if (more) { 875 1.161 yamt nfs_timer_schedule(); 876 1.161 yamt } else { 877 1.161 yamt nfs_timer_stop_ev.ev_count++; 878 1.161 yamt } 879 1.1 cgd } 880 1.1 cgd 881 1.1 cgd /* 882 1.14 mycroft * Test for a termination condition pending on the process. 883 1.14 mycroft * This is used for NFSMNT_INT mounts. 884 1.1 cgd */ 885 1.23 christos int 886 1.179 dsl nfs_sigintr(struct nfsmount *nmp, struct nfsreq *rep, struct lwp *l) 887 1.14 mycroft { 888 1.47 mycroft sigset_t ss; 889 1.14 mycroft 890 1.14 mycroft if (rep && (rep->r_flags & R_SOFTTERM)) 891 1.14 mycroft return (EINTR); 892 1.14 mycroft if (!(nmp->nm_flag & NFSMNT_INT)) 893 1.14 mycroft return (0); 894 1.119 christos if (l) { 895 1.145 ad sigpending1(l, &ss); 896 1.47 mycroft #if 0 897 1.119 christos sigminusset(&l->l_proc->p_sigctx.ps_sigignore, &ss); 898 1.47 mycroft #endif 899 1.47 mycroft if (sigismember(&ss, SIGINT) || sigismember(&ss, SIGTERM) || 900 1.47 mycroft sigismember(&ss, SIGKILL) || sigismember(&ss, SIGHUP) || 901 1.47 mycroft sigismember(&ss, SIGQUIT)) 902 1.47 mycroft return (EINTR); 903 1.47 mycroft } 904 1.14 mycroft return (0); 905 1.14 mycroft } 906 1.1 cgd 907 1.187 pooka int 908 1.150 yamt nfs_rcvlock(struct nfsmount *nmp, struct nfsreq *rep) 909 1.14 mycroft { 910 1.55 augustss int *flagp = &nmp->nm_iflag; 911 1.150 yamt int slptimeo = 0; 912 1.193 matt bool catch_p; 913 1.87 yamt int error = 0; 914 1.14 mycroft 915 1.150 yamt KASSERT(nmp == rep->r_nmp); 916 1.150 yamt 917 1.203 mlelstv /* 918 1.203 mlelstv * For interruptible mounts, we need to poll 919 1.203 mlelstv * if we are not the process that issued the 920 1.203 mlelstv * operation as we won't get the signal. 921 1.203 mlelstv */ 922 1.203 mlelstv if (nmp->nm_flag & NFSMNT_INT) { 923 1.203 mlelstv if (rep->r_lwp != curlwp) 924 1.203 mlelstv slptimeo = hz; 925 1.203 mlelstv } 926 1.203 mlelstv 927 1.197 manu if (nmp->nm_flag & NFSMNT_SOFT) 928 1.197 manu slptimeo = nmp->nm_retry * nmp->nm_timeo; 929 1.197 manu 930 1.197 manu if (nmp->nm_iflag & NFSMNT_DISMNTFORCE) 931 1.197 manu slptimeo = hz; 932 1.197 manu 933 1.193 matt catch_p = (nmp->nm_flag & NFSMNT_INT) != 0; 934 1.150 yamt mutex_enter(&nmp->nm_lock); 935 1.153 yamt while (/* CONSTCOND */ true) { 936 1.51 sommerfe if (*flagp & NFSMNT_DISMNT) { 937 1.151 yamt cv_signal(&nmp->nm_disconcv); 938 1.87 yamt error = EIO; 939 1.153 yamt break; 940 1.51 sommerfe } 941 1.36 fvdl /* If our reply was received while we were sleeping, 942 1.36 fvdl * then just return without taking the lock to avoid a 943 1.36 fvdl * situation where a single iod could 'capture' the 944 1.36 fvdl * receive lock. 945 1.36 fvdl */ 946 1.87 yamt if (rep->r_mrep != NULL) { 947 1.188 yamt cv_signal(&nmp->nm_rcvcv); 948 1.87 yamt error = EALREADY; 949 1.153 yamt break; 950 1.153 yamt } 951 1.153 yamt if (nfs_sigintr(rep->r_nmp, rep, rep->r_lwp)) { 952 1.188 yamt cv_signal(&nmp->nm_rcvcv); 953 1.153 yamt error = EINTR; 954 1.153 yamt break; 955 1.153 yamt } 956 1.153 yamt if ((*flagp & NFSMNT_RCVLOCK) == 0) { 957 1.153 yamt *flagp |= NFSMNT_RCVLOCK; 958 1.153 yamt break; 959 1.153 yamt } 960 1.193 matt if (catch_p) { 961 1.197 manu error = cv_timedwait_sig(&nmp->nm_rcvcv, &nmp->nm_lock, 962 1.153 yamt slptimeo); 963 1.153 yamt } else { 964 1.197 manu error = cv_timedwait(&nmp->nm_rcvcv, &nmp->nm_lock, 965 1.153 yamt slptimeo); 966 1.87 yamt } 967 1.197 manu if (error) { 968 1.197 manu if ((error == EWOULDBLOCK) && 969 1.197 manu (nmp->nm_flag & NFSMNT_SOFT)) { 970 1.197 manu error = EIO; 971 1.197 manu break; 972 1.197 manu } 973 1.197 manu error = 0; 974 1.197 manu } 975 1.193 matt if (catch_p) { 976 1.193 matt catch_p = false; 977 1.14 mycroft slptimeo = 2 * hz; 978 1.1 cgd } 979 1.1 cgd } 980 1.150 yamt mutex_exit(&nmp->nm_lock); 981 1.87 yamt return error; 982 1.14 mycroft } 983 1.14 mycroft 984 1.14 mycroft /* 985 1.14 mycroft * Unlock the stream socket for others. 986 1.14 mycroft */ 987 1.187 pooka void 988 1.150 yamt nfs_rcvunlock(struct nfsmount *nmp) 989 1.14 mycroft { 990 1.14 mycroft 991 1.150 yamt mutex_enter(&nmp->nm_lock); 992 1.150 yamt if ((nmp->nm_iflag & NFSMNT_RCVLOCK) == 0) 993 1.14 mycroft panic("nfs rcvunlock"); 994 1.150 yamt nmp->nm_iflag &= ~NFSMNT_RCVLOCK; 995 1.188 yamt cv_signal(&nmp->nm_rcvcv); 996 1.150 yamt mutex_exit(&nmp->nm_lock); 997 1.1 cgd } 998 1.1 cgd 999 1.14 mycroft /* 1000 1.14 mycroft * Parse an RPC request 1001 1.14 mycroft * - verify it 1002 1.131 yamt * - allocate and fill in the cred. 1003 1.1 cgd */ 1004 1.23 christos int 1005 1.179 dsl nfs_getreq(struct nfsrv_descript *nd, struct nfsd *nfsd, int has_header) 1006 1.1 cgd { 1007 1.55 augustss int len, i; 1008 1.55 augustss u_int32_t *tl; 1009 1.55 augustss int32_t t1; 1010 1.14 mycroft struct uio uio; 1011 1.14 mycroft struct iovec iov; 1012 1.148 christos char *dpos, *cp2, *cp; 1013 1.22 cgd u_int32_t nfsvers, auth_type; 1014 1.24 fvdl uid_t nickuid; 1015 1.144 yamt int error = 0, ticklen; 1016 1.14 mycroft struct mbuf *mrep, *md; 1017 1.55 augustss struct nfsuid *nuidp; 1018 1.24 fvdl struct timeval tvin, tvout; 1019 1.14 mycroft 1020 1.129 mrg memset(&tvout, 0, sizeof tvout); /* XXX gcc */ 1021 1.129 mrg 1022 1.131 yamt KASSERT(nd->nd_cr == NULL); 1023 1.14 mycroft mrep = nd->nd_mrep; 1024 1.14 mycroft md = nd->nd_md; 1025 1.14 mycroft dpos = nd->nd_dpos; 1026 1.14 mycroft if (has_header) { 1027 1.24 fvdl nfsm_dissect(tl, u_int32_t *, 10 * NFSX_UNSIGNED); 1028 1.24 fvdl nd->nd_retxid = fxdr_unsigned(u_int32_t, *tl++); 1029 1.14 mycroft if (*tl++ != rpc_call) { 1030 1.14 mycroft m_freem(mrep); 1031 1.14 mycroft return (EBADRPC); 1032 1.14 mycroft } 1033 1.24 fvdl } else 1034 1.24 fvdl nfsm_dissect(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 1035 1.14 mycroft nd->nd_repstat = 0; 1036 1.24 fvdl nd->nd_flag = 0; 1037 1.14 mycroft if (*tl++ != rpc_vers) { 1038 1.14 mycroft nd->nd_repstat = ERPCMISMATCH; 1039 1.14 mycroft nd->nd_procnum = NFSPROC_NOOP; 1040 1.14 mycroft return (0); 1041 1.14 mycroft } 1042 1.14 mycroft if (*tl != nfs_prog) { 1043 1.144 yamt nd->nd_repstat = EPROGUNAVAIL; 1044 1.144 yamt nd->nd_procnum = NFSPROC_NOOP; 1045 1.144 yamt return (0); 1046 1.14 mycroft } 1047 1.14 mycroft tl++; 1048 1.24 fvdl nfsvers = fxdr_unsigned(u_int32_t, *tl++); 1049 1.144 yamt if (nfsvers < NFS_VER2 || nfsvers > NFS_VER3) { 1050 1.14 mycroft nd->nd_repstat = EPROGMISMATCH; 1051 1.14 mycroft nd->nd_procnum = NFSPROC_NOOP; 1052 1.14 mycroft return (0); 1053 1.14 mycroft } 1054 1.144 yamt if (nfsvers == NFS_VER3) 1055 1.24 fvdl nd->nd_flag = ND_NFSV3; 1056 1.24 fvdl nd->nd_procnum = fxdr_unsigned(u_int32_t, *tl++); 1057 1.14 mycroft if (nd->nd_procnum == NFSPROC_NULL) 1058 1.14 mycroft return (0); 1059 1.144 yamt if (nd->nd_procnum > NFSPROC_COMMIT || 1060 1.144 yamt (!nd->nd_flag && nd->nd_procnum > NFSV2PROC_STATFS)) { 1061 1.14 mycroft nd->nd_repstat = EPROCUNAVAIL; 1062 1.14 mycroft nd->nd_procnum = NFSPROC_NOOP; 1063 1.1 cgd return (0); 1064 1.14 mycroft } 1065 1.24 fvdl if ((nd->nd_flag & ND_NFSV3) == 0) 1066 1.24 fvdl nd->nd_procnum = nfsv3_procid[nd->nd_procnum]; 1067 1.14 mycroft auth_type = *tl++; 1068 1.14 mycroft len = fxdr_unsigned(int, *tl++); 1069 1.14 mycroft if (len < 0 || len > RPCAUTH_MAXSIZ) { 1070 1.14 mycroft m_freem(mrep); 1071 1.14 mycroft return (EBADRPC); 1072 1.14 mycroft } 1073 1.14 mycroft 1074 1.24 fvdl nd->nd_flag &= ~ND_KERBAUTH; 1075 1.14 mycroft /* 1076 1.14 mycroft * Handle auth_unix or auth_kerb. 1077 1.14 mycroft */ 1078 1.14 mycroft if (auth_type == rpc_auth_unix) { 1079 1.130 elad uid_t uid; 1080 1.167 yamt gid_t gid; 1081 1.130 elad 1082 1.131 yamt nd->nd_cr = kauth_cred_alloc(); 1083 1.14 mycroft len = fxdr_unsigned(int, *++tl); 1084 1.14 mycroft if (len < 0 || len > NFS_MAXNAMLEN) { 1085 1.14 mycroft m_freem(mrep); 1086 1.131 yamt error = EBADRPC; 1087 1.131 yamt goto errout; 1088 1.14 mycroft } 1089 1.14 mycroft nfsm_adv(nfsm_rndup(len)); 1090 1.24 fvdl nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 1091 1.130 elad 1092 1.130 elad uid = fxdr_unsigned(uid_t, *tl++); 1093 1.130 elad gid = fxdr_unsigned(gid_t, *tl++); 1094 1.130 elad kauth_cred_setuid(nd->nd_cr, uid); 1095 1.137 yamt kauth_cred_seteuid(nd->nd_cr, uid); 1096 1.137 yamt kauth_cred_setsvuid(nd->nd_cr, uid); 1097 1.130 elad kauth_cred_setgid(nd->nd_cr, gid); 1098 1.137 yamt kauth_cred_setegid(nd->nd_cr, gid); 1099 1.130 elad kauth_cred_setsvgid(nd->nd_cr, gid); 1100 1.130 elad 1101 1.14 mycroft len = fxdr_unsigned(int, *tl); 1102 1.14 mycroft if (len < 0 || len > RPCAUTH_UNIXGIDS) { 1103 1.14 mycroft m_freem(mrep); 1104 1.131 yamt error = EBADRPC; 1105 1.131 yamt goto errout; 1106 1.14 mycroft } 1107 1.24 fvdl nfsm_dissect(tl, u_int32_t *, (len + 2) * NFSX_UNSIGNED); 1108 1.130 elad 1109 1.167 yamt if (len > 0) { 1110 1.200 riastrad size_t grbuf_size = uimin(len, NGROUPS) * sizeof(gid_t); 1111 1.167 yamt gid_t *grbuf = kmem_alloc(grbuf_size, KM_SLEEP); 1112 1.167 yamt 1113 1.167 yamt for (i = 0; i < len; i++) { 1114 1.167 yamt if (i < NGROUPS) /* XXX elad */ 1115 1.167 yamt grbuf[i] = fxdr_unsigned(gid_t, *tl++); 1116 1.167 yamt else 1117 1.167 yamt tl++; 1118 1.167 yamt } 1119 1.167 yamt kauth_cred_setgroups(nd->nd_cr, grbuf, 1120 1.200 riastrad uimin(len, NGROUPS), -1, UIO_SYSSPACE); 1121 1.167 yamt kmem_free(grbuf, grbuf_size); 1122 1.130 elad } 1123 1.130 elad 1124 1.24 fvdl len = fxdr_unsigned(int, *++tl); 1125 1.24 fvdl if (len < 0 || len > RPCAUTH_MAXSIZ) { 1126 1.14 mycroft m_freem(mrep); 1127 1.131 yamt error = EBADRPC; 1128 1.131 yamt goto errout; 1129 1.14 mycroft } 1130 1.24 fvdl if (len > 0) 1131 1.24 fvdl nfsm_adv(nfsm_rndup(len)); 1132 1.24 fvdl } else if (auth_type == rpc_auth_kerb) { 1133 1.24 fvdl switch (fxdr_unsigned(int, *tl++)) { 1134 1.24 fvdl case RPCAKN_FULLNAME: 1135 1.24 fvdl ticklen = fxdr_unsigned(int, *tl); 1136 1.24 fvdl *((u_int32_t *)nfsd->nfsd_authstr) = *tl; 1137 1.24 fvdl uio.uio_resid = nfsm_rndup(ticklen) + NFSX_UNSIGNED; 1138 1.24 fvdl nfsd->nfsd_authlen = uio.uio_resid + NFSX_UNSIGNED; 1139 1.24 fvdl if (uio.uio_resid > (len - 2 * NFSX_UNSIGNED)) { 1140 1.24 fvdl m_freem(mrep); 1141 1.131 yamt error = EBADRPC; 1142 1.131 yamt goto errout; 1143 1.24 fvdl } 1144 1.24 fvdl uio.uio_offset = 0; 1145 1.24 fvdl uio.uio_iov = &iov; 1146 1.24 fvdl uio.uio_iovcnt = 1; 1147 1.123 yamt UIO_SETUP_SYSSPACE(&uio); 1148 1.148 christos iov.iov_base = (void *)&nfsd->nfsd_authstr[4]; 1149 1.24 fvdl iov.iov_len = RPCAUTH_MAXSIZ - 4; 1150 1.24 fvdl nfsm_mtouio(&uio, uio.uio_resid); 1151 1.24 fvdl nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1152 1.24 fvdl if (*tl++ != rpc_auth_kerb || 1153 1.24 fvdl fxdr_unsigned(int, *tl) != 4 * NFSX_UNSIGNED) { 1154 1.31 christos printf("Bad kerb verifier\n"); 1155 1.24 fvdl nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF); 1156 1.24 fvdl nd->nd_procnum = NFSPROC_NOOP; 1157 1.24 fvdl return (0); 1158 1.24 fvdl } 1159 1.148 christos nfsm_dissect(cp, void *, 4 * NFSX_UNSIGNED); 1160 1.24 fvdl tl = (u_int32_t *)cp; 1161 1.24 fvdl if (fxdr_unsigned(int, *tl) != RPCAKN_FULLNAME) { 1162 1.31 christos printf("Not fullname kerb verifier\n"); 1163 1.24 fvdl nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF); 1164 1.24 fvdl nd->nd_procnum = NFSPROC_NOOP; 1165 1.24 fvdl return (0); 1166 1.24 fvdl } 1167 1.24 fvdl cp += NFSX_UNSIGNED; 1168 1.46 perry memcpy(nfsd->nfsd_verfstr, cp, 3 * NFSX_UNSIGNED); 1169 1.24 fvdl nfsd->nfsd_verflen = 3 * NFSX_UNSIGNED; 1170 1.24 fvdl nd->nd_flag |= ND_KERBFULL; 1171 1.24 fvdl nfsd->nfsd_flag |= NFSD_NEEDAUTH; 1172 1.24 fvdl break; 1173 1.24 fvdl case RPCAKN_NICKNAME: 1174 1.24 fvdl if (len != 2 * NFSX_UNSIGNED) { 1175 1.31 christos printf("Kerb nickname short\n"); 1176 1.24 fvdl nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADCRED); 1177 1.24 fvdl nd->nd_procnum = NFSPROC_NOOP; 1178 1.24 fvdl return (0); 1179 1.24 fvdl } 1180 1.24 fvdl nickuid = fxdr_unsigned(uid_t, *tl); 1181 1.24 fvdl nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1182 1.24 fvdl if (*tl++ != rpc_auth_kerb || 1183 1.24 fvdl fxdr_unsigned(int, *tl) != 3 * NFSX_UNSIGNED) { 1184 1.31 christos printf("Kerb nick verifier bad\n"); 1185 1.24 fvdl nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF); 1186 1.24 fvdl nd->nd_procnum = NFSPROC_NOOP; 1187 1.24 fvdl return (0); 1188 1.24 fvdl } 1189 1.24 fvdl nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 1190 1.24 fvdl tvin.tv_sec = *tl++; 1191 1.24 fvdl tvin.tv_usec = *tl; 1192 1.24 fvdl 1193 1.80 yamt LIST_FOREACH(nuidp, NUIDHASH(nfsd->nfsd_slp, nickuid), 1194 1.80 yamt nu_hash) { 1195 1.130 elad if (kauth_cred_geteuid(nuidp->nu_cr) == nickuid && 1196 1.24 fvdl (!nd->nd_nam2 || 1197 1.24 fvdl netaddr_match(NU_NETFAM(nuidp), 1198 1.24 fvdl &nuidp->nu_haddr, nd->nd_nam2))) 1199 1.24 fvdl break; 1200 1.24 fvdl } 1201 1.24 fvdl if (!nuidp) { 1202 1.24 fvdl nd->nd_repstat = 1203 1.24 fvdl (NFSERR_AUTHERR|AUTH_REJECTCRED); 1204 1.24 fvdl nd->nd_procnum = NFSPROC_NOOP; 1205 1.24 fvdl return (0); 1206 1.24 fvdl } 1207 1.24 fvdl 1208 1.24 fvdl /* 1209 1.24 fvdl * Now, decrypt the timestamp using the session key 1210 1.24 fvdl * and validate it. 1211 1.24 fvdl */ 1212 1.24 fvdl #ifdef NFSKERB 1213 1.24 fvdl XXX 1214 1.190 martin #else 1215 1.190 martin (void)tvin.tv_sec; 1216 1.24 fvdl #endif 1217 1.14 mycroft 1218 1.24 fvdl tvout.tv_sec = fxdr_unsigned(long, tvout.tv_sec); 1219 1.24 fvdl tvout.tv_usec = fxdr_unsigned(long, tvout.tv_usec); 1220 1.135 kardel if (nuidp->nu_expire < time_second || 1221 1.24 fvdl nuidp->nu_timestamp.tv_sec > tvout.tv_sec || 1222 1.24 fvdl (nuidp->nu_timestamp.tv_sec == tvout.tv_sec && 1223 1.24 fvdl nuidp->nu_timestamp.tv_usec > tvout.tv_usec)) { 1224 1.24 fvdl nuidp->nu_expire = 0; 1225 1.24 fvdl nd->nd_repstat = 1226 1.24 fvdl (NFSERR_AUTHERR|AUTH_REJECTVERF); 1227 1.24 fvdl nd->nd_procnum = NFSPROC_NOOP; 1228 1.24 fvdl return (0); 1229 1.24 fvdl } 1230 1.131 yamt kauth_cred_hold(nuidp->nu_cr); 1231 1.131 yamt nd->nd_cr = nuidp->nu_cr; 1232 1.24 fvdl nd->nd_flag |= ND_KERBNICK; 1233 1.131 yamt } 1234 1.24 fvdl } else { 1235 1.24 fvdl nd->nd_repstat = (NFSERR_AUTHERR | AUTH_REJECTCRED); 1236 1.24 fvdl nd->nd_procnum = NFSPROC_NOOP; 1237 1.24 fvdl return (0); 1238 1.14 mycroft } 1239 1.14 mycroft 1240 1.14 mycroft nd->nd_md = md; 1241 1.14 mycroft nd->nd_dpos = dpos; 1242 1.201 riastrad KASSERT((nd->nd_cr == NULL) == 1243 1.201 riastrad ((nfsd->nfsd_flag & NFSD_NEEDAUTH) != 0)); 1244 1.14 mycroft return (0); 1245 1.14 mycroft nfsmout: 1246 1.131 yamt errout: 1247 1.131 yamt KASSERT(error != 0); 1248 1.131 yamt if (nd->nd_cr != NULL) { 1249 1.131 yamt kauth_cred_free(nd->nd_cr); 1250 1.131 yamt nd->nd_cr = NULL; 1251 1.131 yamt } 1252 1.14 mycroft return (error); 1253 1.1 cgd } 1254 1.1 cgd 1255 1.24 fvdl int 1256 1.180 dsl nfs_msg(struct lwp *l, const char *server, const char *msg) 1257 1.1 cgd { 1258 1.1 cgd tpr_t tpr; 1259 1.1 cgd 1260 1.186 yamt #if 0 /* XXX nfs_timer can't block on proc_lock */ 1261 1.119 christos if (l) 1262 1.119 christos tpr = tprintf_open(l->l_proc); 1263 1.1 cgd else 1264 1.186 yamt #endif 1265 1.1 cgd tpr = NULL; 1266 1.1 cgd tprintf(tpr, "nfs server %s: %s\n", server, msg); 1267 1.1 cgd tprintf_close(tpr); 1268 1.24 fvdl return (0); 1269 1.1 cgd } 1270 1.1 cgd 1271 1.174 ad static struct pool nfs_srvdesc_pool; 1272 1.14 mycroft 1273 1.14 mycroft void 1274 1.174 ad nfsdreq_init(void) 1275 1.1 cgd { 1276 1.165 yamt 1277 1.174 ad pool_init(&nfs_srvdesc_pool, sizeof(struct nfsrv_descript), 1278 1.174 ad 0, 0, 0, "nfsrvdescpl", &pool_allocator_nointr, IPL_NONE); 1279 1.165 yamt } 1280 1.165 yamt 1281 1.165 yamt void 1282 1.174 ad nfsdreq_fini(void) 1283 1.122 yamt { 1284 1.122 yamt 1285 1.174 ad pool_destroy(&nfs_srvdesc_pool); 1286 1.132 yamt } 1287 1.132 yamt 1288 1.132 yamt struct nfsrv_descript * 1289 1.132 yamt nfsdreq_alloc(void) 1290 1.132 yamt { 1291 1.132 yamt struct nfsrv_descript *nd; 1292 1.132 yamt 1293 1.132 yamt nd = pool_get(&nfs_srvdesc_pool, PR_WAITOK); 1294 1.132 yamt nd->nd_cr = NULL; 1295 1.132 yamt return nd; 1296 1.132 yamt } 1297 1.132 yamt 1298 1.132 yamt void 1299 1.132 yamt nfsdreq_free(struct nfsrv_descript *nd) 1300 1.132 yamt { 1301 1.132 yamt kauth_cred_t cr; 1302 1.132 yamt 1303 1.132 yamt cr = nd->nd_cr; 1304 1.132 yamt if (cr != NULL) { 1305 1.132 yamt kauth_cred_free(cr); 1306 1.132 yamt } 1307 1.132 yamt pool_put(&nfs_srvdesc_pool, nd); 1308 1.132 yamt } 1309