| File: | nfs/nfs_syscalls.c |
| Warning: | line 351, column 16 Access to field 'ns_flag' results in a dereference of a null pointer (loaded from variable 'slp') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: nfs_syscalls.c,v 1.119 2023/08/03 09:49:09 mvs Exp $ */ | |||
| 2 | /* $NetBSD: nfs_syscalls.c,v 1.19 1996/02/18 11:53:52 fvdl Exp $ */ | |||
| 3 | ||||
| 4 | /* | |||
| 5 | * Copyright (c) 1989, 1993 | |||
| 6 | * The Regents of the University of California. All rights reserved. | |||
| 7 | * | |||
| 8 | * This code is derived from software contributed to Berkeley by | |||
| 9 | * Rick Macklem at The University of Guelph. | |||
| 10 | * | |||
| 11 | * Redistribution and use in source and binary forms, with or without | |||
| 12 | * modification, are permitted provided that the following conditions | |||
| 13 | * are met: | |||
| 14 | * 1. Redistributions of source code must retain the above copyright | |||
| 15 | * notice, this list of conditions and the following disclaimer. | |||
| 16 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 17 | * notice, this list of conditions and the following disclaimer in the | |||
| 18 | * documentation and/or other materials provided with the distribution. | |||
| 19 | * 3. Neither the name of the University nor the names of its contributors | |||
| 20 | * may be used to endorse or promote products derived from this software | |||
| 21 | * without specific prior written permission. | |||
| 22 | * | |||
| 23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
| 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
| 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
| 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
| 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
| 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
| 29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
| 30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
| 31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
| 32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| 33 | * SUCH DAMAGE. | |||
| 34 | * | |||
| 35 | * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95 | |||
| 36 | */ | |||
| 37 | ||||
| 38 | #include <sys/param.h> | |||
| 39 | #include <sys/systm.h> | |||
| 40 | #include <sys/kernel.h> | |||
| 41 | #include <sys/file.h> | |||
| 42 | #include <sys/stat.h> | |||
| 43 | #include <sys/vnode.h> | |||
| 44 | #include <sys/mount.h> | |||
| 45 | #include <sys/pool.h> | |||
| 46 | #include <sys/proc.h> | |||
| 47 | #include <sys/uio.h> | |||
| 48 | #include <sys/malloc.h> | |||
| 49 | #include <sys/buf.h> | |||
| 50 | #include <sys/mbuf.h> | |||
| 51 | #include <sys/socket.h> | |||
| 52 | #include <sys/socketvar.h> | |||
| 53 | #include <sys/domain.h> | |||
| 54 | #include <sys/protosw.h> | |||
| 55 | #include <sys/namei.h> | |||
| 56 | #include <sys/syslog.h> | |||
| 57 | #include <sys/filedesc.h> | |||
| 58 | #include <sys/signalvar.h> | |||
| 59 | #include <sys/kthread.h> | |||
| 60 | #include <sys/queue.h> | |||
| 61 | ||||
| 62 | #include <sys/syscallargs.h> | |||
| 63 | ||||
| 64 | #include <netinet/in.h> | |||
| 65 | #include <netinet/tcp.h> | |||
| 66 | #include <nfs/xdr_subs.h> | |||
| 67 | #include <nfs/rpcv2.h> | |||
| 68 | #include <nfs/nfsproto.h> | |||
| 69 | #include <nfs/nfs.h> | |||
| 70 | #include <nfs/nfsrvcache.h> | |||
| 71 | #include <nfs/nfsmount.h> | |||
| 72 | #include <nfs/nfsnode.h> | |||
| 73 | #include <nfs/nfs_var.h> | |||
| 74 | ||||
| 75 | /* Global defs. */ | |||
| 76 | extern int nfs_numasync; | |||
| 77 | extern struct nfsstats nfsstats; | |||
| 78 | struct nfssvc_sock *nfs_udpsock; | |||
| 79 | int nfsd_waiting = 0; | |||
| 80 | ||||
| 81 | #ifdef NFSSERVER1 | |||
| 82 | struct pool nfsrv_descript_pl; | |||
| 83 | ||||
| 84 | int nfsrv_getslp(struct nfsd *nfsd); | |||
| 85 | ||||
| 86 | static int nfs_numnfsd = 0; | |||
| 87 | int (*nfsrv3_procs[NFS_NPROCS23])(struct nfsrv_descript *, | |||
| 88 | struct nfssvc_sock *, struct proc *, struct mbuf **) = { | |||
| 89 | nfsrv_null, | |||
| 90 | nfsrv_getattr, | |||
| 91 | nfsrv_setattr, | |||
| 92 | nfsrv_lookup, | |||
| 93 | nfsrv3_access, | |||
| 94 | nfsrv_readlink, | |||
| 95 | nfsrv_read, | |||
| 96 | nfsrv_write, | |||
| 97 | nfsrv_create, | |||
| 98 | nfsrv_mkdir, | |||
| 99 | nfsrv_symlink, | |||
| 100 | nfsrv_mknod, | |||
| 101 | nfsrv_remove, | |||
| 102 | nfsrv_rmdir, | |||
| 103 | nfsrv_rename, | |||
| 104 | nfsrv_link, | |||
| 105 | nfsrv_readdir, | |||
| 106 | nfsrv_readdirplus, | |||
| 107 | nfsrv_statfs, | |||
| 108 | nfsrv_fsinfo, | |||
| 109 | nfsrv_pathconf, | |||
| 110 | nfsrv_commit, | |||
| 111 | nfsrv_noop | |||
| 112 | }; | |||
| 113 | #endif | |||
| 114 | ||||
| 115 | TAILQ_HEAD(, nfssvc_sock)struct { struct nfssvc_sock *tqh_first; struct nfssvc_sock ** tqh_last; } nfssvc_sockhead; | |||
| 116 | struct nfsdhead nfsd_head; | |||
| 117 | ||||
| 118 | int nfssvc_sockhead_flag; | |||
| 119 | #define SLP_INIT0x01 0x01 /* NFS data undergoing initialization */ | |||
| 120 | #define SLP_WANTINIT0x02 0x02 /* thread waiting on NFS initialization */ | |||
| 121 | int nfsd_head_flag; | |||
| 122 | ||||
| 123 | #ifdef NFSCLIENT1 | |||
| 124 | struct proc *nfs_asyncdaemon[NFS_MAXASYNCDAEMON20]; | |||
| 125 | int nfs_niothreads = -1; | |||
| 126 | #endif | |||
| 127 | ||||
| 128 | int nfssvc_addsock(struct file *, struct mbuf *); | |||
| 129 | int nfssvc_nfsd(struct nfsd *); | |||
| 130 | void nfsrv_slpderef(struct nfssvc_sock *); | |||
| 131 | void nfsrv_zapsock(struct nfssvc_sock *); | |||
| 132 | void nfssvc_iod(void *); | |||
| 133 | ||||
| 134 | /* | |||
| 135 | * NFS server pseudo system call for the nfsd's | |||
| 136 | * Based on the flag value it either: | |||
| 137 | * - adds a socket to the selection list | |||
| 138 | * - remains in the kernel as an nfsd | |||
| 139 | */ | |||
| 140 | int | |||
| 141 | sys_nfssvc(struct proc *p, void *v, register_t *retval) | |||
| 142 | { | |||
| 143 | int error = 0; | |||
| 144 | #ifdef NFSSERVER1 | |||
| 145 | struct sys_nfssvc_args /* { | |||
| 146 | syscallarg(int) flag; | |||
| 147 | syscallarg(caddr_t) argp; | |||
| 148 | } */ *uap = v; | |||
| 149 | int flags = SCARG(uap, flag)((uap)->flag.le.datum); | |||
| 150 | struct file *fp; | |||
| 151 | struct mbuf *nam; | |||
| 152 | struct nfsd_args nfsdarg; | |||
| 153 | struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs; | |||
| 154 | struct nfsd *nfsd; | |||
| 155 | #endif | |||
| 156 | ||||
| 157 | /* Must be super user */ | |||
| 158 | error = suser(p); | |||
| 159 | if (error) | |||
| ||||
| 160 | return (error); | |||
| 161 | ||||
| 162 | #ifndef NFSSERVER1 | |||
| 163 | error = ENOSYS78; | |||
| 164 | #else | |||
| 165 | ||||
| 166 | while (nfssvc_sockhead_flag & SLP_INIT0x01) { | |||
| 167 | nfssvc_sockhead_flag |= SLP_WANTINIT0x02; | |||
| 168 | tsleep_nsec(&nfssvc_sockhead, PSOCK24, "nfsd init", INFSLP0xffffffffffffffffULL); | |||
| 169 | } | |||
| 170 | ||||
| 171 | switch (flags) { | |||
| 172 | case NFSSVC_ADDSOCK0x008: | |||
| 173 | error = copyin(SCARG(uap, argp)((uap)->argp.le.datum), &nfsdarg, sizeof(nfsdarg)); | |||
| 174 | if (error) | |||
| 175 | return (error); | |||
| 176 | ||||
| 177 | error = getsock(p, nfsdarg.sock, &fp); | |||
| 178 | if (error) | |||
| 179 | return (error); | |||
| 180 | ||||
| 181 | /* | |||
| 182 | * Get the client address for connected sockets. | |||
| 183 | */ | |||
| 184 | if (nfsdarg.name == NULL((void *)0) || nfsdarg.namelen == 0) | |||
| 185 | nam = NULL((void *)0); | |||
| 186 | else { | |||
| 187 | error = sockargs(&nam, nfsdarg.name, nfsdarg.namelen, | |||
| 188 | MT_SONAME3); | |||
| 189 | if (error) { | |||
| 190 | FRELE(fp, p)(_atomic_sub_int_nv((&fp->f_count), 1) == 0 ? fdrop(fp , p) : 0); | |||
| 191 | return (error); | |||
| 192 | } | |||
| 193 | } | |||
| 194 | error = nfssvc_addsock(fp, nam); | |||
| 195 | FRELE(fp, p)(_atomic_sub_int_nv((&fp->f_count), 1) == 0 ? fdrop(fp , p) : 0); | |||
| 196 | break; | |||
| 197 | case NFSSVC_NFSD0x004: | |||
| 198 | error = copyin(SCARG(uap, argp)((uap)->argp.le.datum), nsd, sizeof(*nsd)); | |||
| 199 | if (error) | |||
| 200 | return (error); | |||
| 201 | ||||
| 202 | nfsd = malloc(sizeof(*nfsd), M_NFSD52, M_WAITOK0x0001|M_ZERO0x0008); | |||
| 203 | nfsd->nfsd_procp = p; | |||
| 204 | nfsd->nfsd_slp = NULL((void *)0); | |||
| 205 | ||||
| 206 | error = nfssvc_nfsd(nfsd); | |||
| 207 | break; | |||
| 208 | default: | |||
| 209 | error = EINVAL22; | |||
| 210 | break; | |||
| 211 | } | |||
| 212 | ||||
| 213 | if (error == EINTR4 || error == ERESTART-1) | |||
| 214 | error = 0; | |||
| 215 | #endif /* !NFSSERVER */ | |||
| 216 | ||||
| 217 | return (error); | |||
| 218 | } | |||
| 219 | ||||
| 220 | #ifdef NFSSERVER1 | |||
| 221 | /* | |||
| 222 | * Adds a socket to the list for servicing by nfsds. | |||
| 223 | */ | |||
| 224 | int | |||
| 225 | nfssvc_addsock(struct file *fp, struct mbuf *mynam) | |||
| 226 | { | |||
| 227 | struct mbuf *m; | |||
| 228 | int siz; | |||
| 229 | struct nfssvc_sock *slp; | |||
| 230 | struct socket *so; | |||
| 231 | struct nfssvc_sock *tslp; | |||
| 232 | int error; | |||
| 233 | ||||
| 234 | so = (struct socket *)fp->f_data; | |||
| 235 | tslp = NULL((void *)0); | |||
| 236 | /* | |||
| 237 | * Add it to the list, as required. | |||
| 238 | */ | |||
| 239 | if (so->so_proto->pr_protocol == IPPROTO_UDP17) { | |||
| 240 | tslp = nfs_udpsock; | |||
| 241 | if (tslp->ns_flag & SLP_VALID0x01) { | |||
| 242 | m_freem(mynam); | |||
| 243 | return (EPERM1); | |||
| 244 | } | |||
| 245 | } | |||
| 246 | if (so->so_type == SOCK_STREAM1) | |||
| 247 | siz = NFS_MAXPACKET(404 + (64 * 1024)) + sizeof (u_long); | |||
| 248 | else | |||
| 249 | siz = NFS_MAXPACKET(404 + (64 * 1024)); | |||
| 250 | solock(so); | |||
| 251 | error = soreserve(so, siz, siz); | |||
| 252 | sounlock(so); | |||
| 253 | if (error) { | |||
| 254 | m_freem(mynam); | |||
| 255 | return (error); | |||
| 256 | } | |||
| 257 | ||||
| 258 | /* | |||
| 259 | * Set protocol specific options { for now TCP only } and | |||
| 260 | * reserve some space. For datagram sockets, this can get called | |||
| 261 | * repeatedly for the same socket, but that isn't harmful. | |||
| 262 | */ | |||
| 263 | if (so->so_type == SOCK_STREAM1) { | |||
| 264 | MGET(m, M_WAIT, MT_SOOPTS)m = m_get((0x0001), (4)); | |||
| 265 | *mtod(m, int32_t *)((int32_t *)((m)->m_hdr.mh_data)) = 1; | |||
| 266 | m->m_lenm_hdr.mh_len = sizeof(int32_t); | |||
| 267 | sosetopt(so, SOL_SOCKET0xffff, SO_KEEPALIVE0x0008, m); | |||
| 268 | m_freem(m); | |||
| 269 | } | |||
| 270 | if (so->so_proto->pr_domain->dom_family == AF_INET2 && | |||
| 271 | so->so_proto->pr_protocol == IPPROTO_TCP6) { | |||
| 272 | MGET(m, M_WAIT, MT_SOOPTS)m = m_get((0x0001), (4)); | |||
| 273 | *mtod(m, int32_t *)((int32_t *)((m)->m_hdr.mh_data)) = 1; | |||
| 274 | m->m_lenm_hdr.mh_len = sizeof(int32_t); | |||
| 275 | sosetopt(so, IPPROTO_TCP6, TCP_NODELAY0x01, m); | |||
| 276 | m_freem(m); | |||
| 277 | } | |||
| 278 | solock(so); | |||
| 279 | so->so_rcv.sb_flags &= ~SB_NOINTR0x40; | |||
| 280 | so->so_rcv.sb_timeo_nsecs = INFSLP0xffffffffffffffffULL; | |||
| 281 | so->so_snd.sb_flags &= ~SB_NOINTR0x40; | |||
| 282 | so->so_snd.sb_timeo_nsecs = INFSLP0xffffffffffffffffULL; | |||
| 283 | sounlock(so); | |||
| 284 | if (tslp) | |||
| 285 | slp = tslp; | |||
| 286 | else { | |||
| 287 | slp = malloc(sizeof(*slp), M_NFSSVC50, M_WAITOK0x0001|M_ZERO0x0008); | |||
| 288 | TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain)do { (slp)->ns_chain.tqe_next = ((void *)0); (slp)->ns_chain .tqe_prev = (&nfssvc_sockhead)->tqh_last; *(&nfssvc_sockhead )->tqh_last = (slp); (&nfssvc_sockhead)->tqh_last = &(slp)->ns_chain.tqe_next; } while (0); | |||
| 289 | } | |||
| 290 | slp->ns_so = so; | |||
| 291 | slp->ns_nam = mynam; | |||
| 292 | FREF(fp)do { extern void vfs_stall_barrier(void); vfs_stall_barrier() ; _atomic_inc_int(&(fp)->f_count); } while (0); | |||
| 293 | slp->ns_fp = fp; | |||
| 294 | so->so_upcallarg = (caddr_t)slp; | |||
| 295 | so->so_upcall = nfsrv_rcv; | |||
| 296 | slp->ns_flag = (SLP_VALID0x01 | SLP_NEEDQ0x04); | |||
| 297 | nfsrv_wakenfsd(slp); | |||
| 298 | return (0); | |||
| 299 | } | |||
| 300 | ||||
| 301 | /* | |||
| 302 | * Called by nfssvc() for nfsds. Just loops around servicing rpc requests | |||
| 303 | * until it is killed by a signal. | |||
| 304 | */ | |||
| 305 | int | |||
| 306 | nfssvc_nfsd(struct nfsd *nfsd) | |||
| 307 | { | |||
| 308 | struct mbuf *m; | |||
| 309 | int siz; | |||
| 310 | struct nfssvc_sock *slp; | |||
| 311 | struct socket *so; | |||
| 312 | int *solockp; | |||
| 313 | struct nfsrv_descript *nd = NULL((void *)0); | |||
| 314 | struct mbuf *mreq; | |||
| 315 | int error = 0, cacherep, sotype; | |||
| 316 | ||||
| 317 | cacherep = RC_DOIT2; | |||
| 318 | ||||
| 319 | TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain)do { (nfsd)->nfsd_chain.tqe_next = ((void *)0); (nfsd)-> nfsd_chain.tqe_prev = (&nfsd_head)->tqh_last; *(&nfsd_head )->tqh_last = (nfsd); (&nfsd_head)->tqh_last = & (nfsd)->nfsd_chain.tqe_next; } while (0); | |||
| 320 | nfs_numnfsd++; | |||
| 321 | ||||
| 322 | /* Loop getting rpc requests until SIGKILL. */ | |||
| 323 | loop: | |||
| 324 | if (!ISSET(nfsd->nfsd_flag, NFSD_REQINPROG)((nfsd->nfsd_flag) & (0x02))) { | |||
| 325 | ||||
| 326 | /* attach an nfssvc_sock to nfsd */ | |||
| 327 | error = nfsrv_getslp(nfsd); | |||
| 328 | if (error
| |||
| 329 | goto done; | |||
| 330 | ||||
| 331 | slp = nfsd->nfsd_slp; | |||
| 332 | ||||
| 333 | if (ISSET(slp->ns_flag, SLP_VALID)((slp->ns_flag) & (0x01))) { | |||
| 334 | if (ISSET(slp->ns_flag, SLP_DISCONN)((slp->ns_flag) & (0x08))) { | |||
| 335 | nfsrv_zapsock(slp); | |||
| 336 | } else if (ISSET(slp->ns_flag, SLP_NEEDQ)((slp->ns_flag) & (0x04))) { | |||
| 337 | CLR(slp->ns_flag, SLP_NEEDQ)((slp->ns_flag) &= ~(0x04)); | |||
| 338 | nfs_sndlock(&slp->ns_solock, NULL((void *)0)); | |||
| 339 | nfsrv_rcv(slp->ns_so, (caddr_t)slp, M_WAIT0x0001); | |||
| 340 | nfs_sndunlock(&slp->ns_solock); | |||
| 341 | } | |||
| 342 | ||||
| 343 | error = nfsrv_dorec(slp, nfsd, &nd); | |||
| 344 | SET(nfsd->nfsd_flag, NFSD_REQINPROG)((nfsd->nfsd_flag) |= (0x02)); | |||
| 345 | } | |||
| 346 | } else { | |||
| 347 | error = 0; | |||
| 348 | slp = nfsd->nfsd_slp; | |||
| 349 | } | |||
| 350 | ||||
| 351 | if (error
| |||
| ||||
| 352 | if (nd != NULL((void *)0)) { | |||
| 353 | pool_put(&nfsrv_descript_pl, nd); | |||
| 354 | nd = NULL((void *)0); | |||
| 355 | } | |||
| 356 | nfsd->nfsd_slp = NULL((void *)0); | |||
| 357 | CLR(nfsd->nfsd_flag, NFSD_REQINPROG)((nfsd->nfsd_flag) &= ~(0x02)); | |||
| 358 | nfsrv_slpderef(slp); | |||
| 359 | goto loop; | |||
| 360 | } | |||
| 361 | ||||
| 362 | so = slp->ns_so; | |||
| 363 | sotype = so->so_type; | |||
| 364 | if (ISSET(so->so_proto->pr_flags, PR_CONNREQUIRED)((so->so_proto->pr_flags) & (0x0004))) | |||
| 365 | solockp = &slp->ns_solock; | |||
| 366 | else | |||
| 367 | solockp = NULL((void *)0); | |||
| 368 | ||||
| 369 | if (nd) { | |||
| 370 | if (nd->nd_nam2) | |||
| 371 | nd->nd_nam = nd->nd_nam2; | |||
| 372 | else | |||
| 373 | nd->nd_nam = slp->ns_nam; | |||
| 374 | } | |||
| 375 | ||||
| 376 | cacherep = nfsrv_getcache(nd, slp, &mreq); | |||
| 377 | switch (cacherep) { | |||
| 378 | case RC_DOIT2: | |||
| 379 | error = (*(nfsrv3_procs[nd->nd_procnum]))(nd, slp, nfsd->nfsd_procp, &mreq); | |||
| 380 | if (mreq == NULL((void *)0)) { | |||
| 381 | if (nd != NULL((void *)0)) { | |||
| 382 | m_freem(nd->nd_nam2); | |||
| 383 | m_freem(nd->nd_mrep); | |||
| 384 | } | |||
| 385 | break; | |||
| 386 | } | |||
| 387 | if (error) { | |||
| 388 | nfsstats.srv_errs++; | |||
| 389 | nfsrv_updatecache(nd, 0, mreq); | |||
| 390 | m_freem(nd->nd_nam2); | |||
| 391 | break; | |||
| 392 | } | |||
| 393 | nfsstats.srvrpccnt[nd->nd_procnum]++; | |||
| 394 | nfsrv_updatecache(nd, 1, mreq); | |||
| 395 | nd->nd_mrep = NULL((void *)0); | |||
| 396 | ||||
| 397 | /* FALLTHROUGH */ | |||
| 398 | case RC_REPLY1: | |||
| 399 | m = mreq; | |||
| 400 | siz = 0; | |||
| 401 | while (m) { | |||
| 402 | siz += m->m_lenm_hdr.mh_len; | |||
| 403 | m = m->m_nextm_hdr.mh_next; | |||
| 404 | } | |||
| 405 | ||||
| 406 | if (siz <= 0 || siz > NFS_MAXPACKET(404 + (64 * 1024))) | |||
| 407 | panic("bad nfs svc reply, siz = %i", siz); | |||
| 408 | ||||
| 409 | m = mreq; | |||
| 410 | m->m_pkthdrM_dat.MH.MH_pkthdr.len = siz; | |||
| 411 | m->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx = 0; | |||
| 412 | ||||
| 413 | /* For stream protocols, prepend a Sun RPC Record Mark. */ | |||
| 414 | if (sotype == SOCK_STREAM1) { | |||
| 415 | M_PREPEND(m, NFSX_UNSIGNED, M_WAIT)(m) = m_prepend((m), (4), (0x0001)); | |||
| 416 | *mtod(m, u_int32_t *)((u_int32_t *)((m)->m_hdr.mh_data)) = htonl(0x80000000 | siz)(__uint32_t)(__builtin_constant_p(0x80000000 | siz) ? (__uint32_t )(((__uint32_t)(0x80000000 | siz) & 0xff) << 24 | ( (__uint32_t)(0x80000000 | siz) & 0xff00) << 8 | ((__uint32_t )(0x80000000 | siz) & 0xff0000) >> 8 | ((__uint32_t )(0x80000000 | siz) & 0xff000000) >> 24) : __swap32md (0x80000000 | siz)); | |||
| 417 | } | |||
| 418 | ||||
| 419 | if (solockp) | |||
| 420 | nfs_sndlock(solockp, NULL((void *)0)); | |||
| 421 | ||||
| 422 | if (ISSET(slp->ns_flag, SLP_VALID)((slp->ns_flag) & (0x01))) | |||
| 423 | error = nfs_send(so, nd->nd_nam2, m, NULL((void *)0)); | |||
| 424 | else { | |||
| 425 | error = EPIPE32; | |||
| 426 | m_freem(m); | |||
| 427 | } | |||
| 428 | m_freem(nd->nd_nam2); | |||
| 429 | m_freem(nd->nd_mrep); | |||
| 430 | if (error == EPIPE32) | |||
| 431 | nfsrv_zapsock(slp); | |||
| 432 | if (solockp) | |||
| 433 | nfs_sndunlock(solockp); | |||
| 434 | if (error == EINTR4 || error == ERESTART-1) { | |||
| 435 | pool_put(&nfsrv_descript_pl, nd); | |||
| 436 | nfsrv_slpderef(slp); | |||
| 437 | goto done; | |||
| 438 | } | |||
| 439 | break; | |||
| 440 | case RC_DROPIT0: | |||
| 441 | m_freem(nd->nd_mrep); | |||
| 442 | m_freem(nd->nd_nam2); | |||
| 443 | break; | |||
| 444 | }; | |||
| 445 | ||||
| 446 | if (nd) { | |||
| 447 | pool_put(&nfsrv_descript_pl, nd); | |||
| 448 | nd = NULL((void *)0); | |||
| 449 | } | |||
| 450 | ||||
| 451 | if (nfsrv_dorec(slp, nfsd, &nd)) { | |||
| 452 | nfsd->nfsd_flag &= ~NFSD_REQINPROG0x02; | |||
| 453 | nfsd->nfsd_slp = NULL((void *)0); | |||
| 454 | nfsrv_slpderef(slp); | |||
| 455 | } | |||
| 456 | goto loop; | |||
| 457 | ||||
| 458 | done: | |||
| 459 | TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain)do { if (((nfsd)->nfsd_chain.tqe_next) != ((void *)0)) (nfsd )->nfsd_chain.tqe_next->nfsd_chain.tqe_prev = (nfsd)-> nfsd_chain.tqe_prev; else (&nfsd_head)->tqh_last = (nfsd )->nfsd_chain.tqe_prev; *(nfsd)->nfsd_chain.tqe_prev = ( nfsd)->nfsd_chain.tqe_next; ((nfsd)->nfsd_chain.tqe_prev ) = ((void *)-1); ((nfsd)->nfsd_chain.tqe_next) = ((void * )-1); } while (0); | |||
| 460 | free(nfsd, M_NFSD52, sizeof(*nfsd)); | |||
| 461 | if (--nfs_numnfsd == 0) | |||
| 462 | nfsrv_init(1); /* Reinitialize everything */ | |||
| 463 | return (error); | |||
| 464 | } | |||
| 465 | ||||
| 466 | /* | |||
| 467 | * Shut down a socket associated with an nfssvc_sock structure. | |||
| 468 | * Should be called with the send lock set, if required. | |||
| 469 | * The trick here is to increment the sref at the start, so that the nfsds | |||
| 470 | * will stop using it and clear ns_flag at the end so that it will not be | |||
| 471 | * reassigned during cleanup. | |||
| 472 | */ | |||
| 473 | void | |||
| 474 | nfsrv_zapsock(struct nfssvc_sock *slp) | |||
| 475 | { | |||
| 476 | struct socket *so; | |||
| 477 | struct file *fp; | |||
| 478 | struct mbuf *m, *n; | |||
| 479 | ||||
| 480 | slp->ns_flag &= ~SLP_ALLFLAGS0xff; | |||
| 481 | fp = slp->ns_fp; | |||
| 482 | if (fp) { | |||
| 483 | FREF(fp)do { extern void vfs_stall_barrier(void); vfs_stall_barrier() ; _atomic_inc_int(&(fp)->f_count); } while (0); | |||
| 484 | slp->ns_fp = NULL((void *)0); | |||
| 485 | so = slp->ns_so; | |||
| 486 | so->so_upcall = NULL((void *)0); | |||
| 487 | soshutdown(so, SHUT_RDWR2); | |||
| 488 | closef(fp, NULL((void *)0)); | |||
| 489 | if (slp->ns_nam) | |||
| 490 | m = m_free(slp->ns_nam); | |||
| 491 | m_freem(slp->ns_raw); | |||
| 492 | m = slp->ns_rec; | |||
| 493 | while (m) { | |||
| 494 | n = m->m_nextpktm_hdr.mh_nextpkt; | |||
| 495 | m_freem(m); | |||
| 496 | m = n; | |||
| 497 | } | |||
| 498 | } | |||
| 499 | } | |||
| 500 | ||||
| 501 | /* | |||
| 502 | * Dereference a server socket structure. If it has no more references and | |||
| 503 | * is no longer valid, you can throw it away. | |||
| 504 | */ | |||
| 505 | void | |||
| 506 | nfsrv_slpderef(struct nfssvc_sock *slp) | |||
| 507 | { | |||
| 508 | if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID0x01) == 0) { | |||
| 509 | TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain)do { if (((slp)->ns_chain.tqe_next) != ((void *)0)) (slp)-> ns_chain.tqe_next->ns_chain.tqe_prev = (slp)->ns_chain. tqe_prev; else (&nfssvc_sockhead)->tqh_last = (slp)-> ns_chain.tqe_prev; *(slp)->ns_chain.tqe_prev = (slp)->ns_chain .tqe_next; ((slp)->ns_chain.tqe_prev) = ((void *)-1); ((slp )->ns_chain.tqe_next) = ((void *)-1); } while (0); | |||
| 510 | free(slp, M_NFSSVC50, sizeof(*slp)); | |||
| 511 | } | |||
| 512 | } | |||
| 513 | ||||
| 514 | /* | |||
| 515 | * Initialize the data structures for the server. | |||
| 516 | * Handshake with any new nfsds starting up to avoid any chance of | |||
| 517 | * corruption. | |||
| 518 | */ | |||
| 519 | void | |||
| 520 | nfsrv_init(int terminating) | |||
| 521 | { | |||
| 522 | struct nfssvc_sock *slp, *nslp; | |||
| 523 | ||||
| 524 | if (nfssvc_sockhead_flag & SLP_INIT0x01) | |||
| 525 | panic("nfsd init"); | |||
| 526 | nfssvc_sockhead_flag |= SLP_INIT0x01; | |||
| 527 | if (terminating) { | |||
| 528 | for (slp = TAILQ_FIRST(&nfssvc_sockhead)((&nfssvc_sockhead)->tqh_first); slp != NULL((void *)0); | |||
| 529 | slp = nslp) { | |||
| 530 | nslp = TAILQ_NEXT(slp, ns_chain)((slp)->ns_chain.tqe_next); | |||
| 531 | if (slp->ns_flag & SLP_VALID0x01) | |||
| 532 | nfsrv_zapsock(slp); | |||
| 533 | TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain)do { if (((slp)->ns_chain.tqe_next) != ((void *)0)) (slp)-> ns_chain.tqe_next->ns_chain.tqe_prev = (slp)->ns_chain. tqe_prev; else (&nfssvc_sockhead)->tqh_last = (slp)-> ns_chain.tqe_prev; *(slp)->ns_chain.tqe_prev = (slp)->ns_chain .tqe_next; ((slp)->ns_chain.tqe_prev) = ((void *)-1); ((slp )->ns_chain.tqe_next) = ((void *)-1); } while (0); | |||
| 534 | free(slp, M_NFSSVC50, sizeof(*slp)); | |||
| 535 | } | |||
| 536 | nfsrv_cleancache(); /* And clear out server cache */ | |||
| 537 | } | |||
| 538 | ||||
| 539 | TAILQ_INIT(&nfssvc_sockhead)do { (&nfssvc_sockhead)->tqh_first = ((void *)0); (& nfssvc_sockhead)->tqh_last = &(&nfssvc_sockhead)-> tqh_first; } while (0); | |||
| 540 | nfssvc_sockhead_flag &= ~SLP_INIT0x01; | |||
| 541 | if (nfssvc_sockhead_flag & SLP_WANTINIT0x02) { | |||
| 542 | nfssvc_sockhead_flag &= ~SLP_WANTINIT0x02; | |||
| 543 | wakeup((caddr_t)&nfssvc_sockhead); | |||
| 544 | } | |||
| 545 | ||||
| 546 | TAILQ_INIT(&nfsd_head)do { (&nfsd_head)->tqh_first = ((void *)0); (&nfsd_head )->tqh_last = &(&nfsd_head)->tqh_first; } while (0); | |||
| 547 | nfsd_head_flag &= ~NFSD_CHECKSLP0x01; | |||
| 548 | ||||
| 549 | nfs_udpsock = malloc(sizeof(*nfs_udpsock), M_NFSSVC50, | |||
| 550 | M_WAITOK0x0001|M_ZERO0x0008); | |||
| 551 | TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain)do { if (((nfs_udpsock)->ns_chain.tqe_next = (&nfssvc_sockhead )->tqh_first) != ((void *)0)) (&nfssvc_sockhead)->tqh_first ->ns_chain.tqe_prev = &(nfs_udpsock)->ns_chain.tqe_next ; else (&nfssvc_sockhead)->tqh_last = &(nfs_udpsock )->ns_chain.tqe_next; (&nfssvc_sockhead)->tqh_first = (nfs_udpsock); (nfs_udpsock)->ns_chain.tqe_prev = & (&nfssvc_sockhead)->tqh_first; } while (0); | |||
| 552 | ||||
| 553 | if (!terminating) { | |||
| 554 | pool_init(&nfsrv_descript_pl, sizeof(struct nfsrv_descript), | |||
| 555 | 0, IPL_NONE0x0, PR_WAITOK0x0001, "ndscpl", NULL((void *)0)); | |||
| 556 | } | |||
| 557 | } | |||
| 558 | #endif /* NFSSERVER */ | |||
| 559 | ||||
| 560 | #ifdef NFSCLIENT1 | |||
| 561 | /* | |||
| 562 | * Asynchronous I/O threads for client nfs. | |||
| 563 | * They do read-ahead and write-behind operations on the block I/O cache. | |||
| 564 | * Never returns unless it fails or gets killed. | |||
| 565 | */ | |||
| 566 | void | |||
| 567 | nfssvc_iod(void *arg) | |||
| 568 | { | |||
| 569 | struct proc *p = curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc; | |||
| 570 | struct buf *bp, *nbp; | |||
| 571 | int i, myiod; | |||
| 572 | struct vnode *vp; | |||
| 573 | int error = 0, s, bufcount; | |||
| 574 | ||||
| 575 | bufcount = MIN(256, bcstats.kvaslots / 8)(((256)<(bcstats.kvaslots / 8))?(256):(bcstats.kvaslots / 8 )); | |||
| 576 | bufcount = MIN(bufcount, bcstats.numbufs / 8)(((bufcount)<(bcstats.numbufs / 8))?(bufcount):(bcstats.numbufs / 8)); | |||
| 577 | ||||
| 578 | /* Assign my position or return error if too many already running. */ | |||
| 579 | myiod = -1; | |||
| 580 | for (i = 0; i < NFS_MAXASYNCDAEMON20; i++) { | |||
| 581 | if (nfs_asyncdaemon[i] == NULL((void *)0)) { | |||
| 582 | myiod = i; | |||
| 583 | break; | |||
| 584 | } | |||
| 585 | } | |||
| 586 | if (myiod == -1) | |||
| 587 | kthread_exit(EBUSY16); | |||
| 588 | ||||
| 589 | nfs_asyncdaemon[myiod] = p; | |||
| 590 | nfs_numasync++; | |||
| 591 | ||||
| 592 | /* Upper limit on how many bufs we'll queue up for this iod. */ | |||
| 593 | if (nfs_bufqmax > bcstats.kvaslots / 4) { | |||
| 594 | nfs_bufqmax = bcstats.kvaslots / 4; | |||
| 595 | bufcount = 0; | |||
| 596 | } | |||
| 597 | if (nfs_bufqmax > bcstats.numbufs / 4) { | |||
| 598 | nfs_bufqmax = bcstats.numbufs / 4; | |||
| 599 | bufcount = 0; | |||
| 600 | } | |||
| 601 | ||||
| 602 | nfs_bufqmax += bufcount; | |||
| 603 | wakeup(&nfs_bufqlen); /* wake up anyone waiting for room to enqueue IO */ | |||
| 604 | ||||
| 605 | /* Just loop around doin our stuff until SIGKILL. */ | |||
| 606 | for (;;) { | |||
| 607 | while (TAILQ_FIRST(&nfs_bufq)((&nfs_bufq)->tqh_first) == NULL((void *)0) && error == 0) { | |||
| 608 | error = tsleep_nsec(&nfs_bufq, | |||
| 609 | PWAIT32 | PCATCH0x100, "nfsidl", INFSLP0xffffffffffffffffULL); | |||
| 610 | } | |||
| 611 | while ((bp = TAILQ_FIRST(&nfs_bufq)((&nfs_bufq)->tqh_first)) != NULL((void *)0)) { | |||
| 612 | /* Take one off the front of the list */ | |||
| 613 | TAILQ_REMOVE(&nfs_bufq, bp, b_freelist)do { if (((bp)->b_freelist.tqe_next) != ((void *)0)) (bp)-> b_freelist.tqe_next->b_freelist.tqe_prev = (bp)->b_freelist .tqe_prev; else (&nfs_bufq)->tqh_last = (bp)->b_freelist .tqe_prev; *(bp)->b_freelist.tqe_prev = (bp)->b_freelist .tqe_next; ((bp)->b_freelist.tqe_prev) = ((void *)-1); ((bp )->b_freelist.tqe_next) = ((void *)-1); } while (0); | |||
| 614 | nfs_bufqlen--; | |||
| 615 | wakeup_one(&nfs_bufqlen)wakeup_n((&nfs_bufqlen), 1); | |||
| 616 | if (bp->b_flags & B_READ0x00008000) | |||
| 617 | (void) nfs_doio(bp, NULL((void *)0)); | |||
| 618 | else do { | |||
| 619 | /* | |||
| 620 | * Look for a delayed write for the same vnode, so I can do | |||
| 621 | * it now. We must grab it before calling nfs_doio() to | |||
| 622 | * avoid any risk of the vnode getting vclean()'d while | |||
| 623 | * we are doing the write rpc. | |||
| 624 | */ | |||
| 625 | vp = bp->b_vp; | |||
| 626 | s = splbio()splraise(0x3); | |||
| 627 | LIST_FOREACH(nbp, &vp->v_dirtyblkhd, b_vnbufs)for((nbp) = ((&vp->v_dirtyblkhd)->lh_first); (nbp)!= ((void *)0); (nbp) = ((nbp)->b_vnbufs.le_next)) { | |||
| 628 | if ((nbp->b_flags & | |||
| 629 | (B_BUSY0x00000010|B_DELWRI0x00000080|B_NEEDCOMMIT0x00000002|B_NOCACHE0x00001000))!=B_DELWRI0x00000080) | |||
| 630 | continue; | |||
| 631 | nbp->b_flags |= B_ASYNC0x00000004; | |||
| 632 | bremfreebufcache_take(nbp); | |||
| 633 | buf_acquire(nbp); | |||
| 634 | break; | |||
| 635 | } | |||
| 636 | /* | |||
| 637 | * For the delayed write, do the first part of nfs_bwrite() | |||
| 638 | * up to, but not including nfs_strategy(). | |||
| 639 | */ | |||
| 640 | if (nbp) { | |||
| 641 | nbp->b_flags &= ~(B_READ0x00008000|B_DONE0x00000100|B_ERROR0x00000400); | |||
| 642 | buf_undirty(nbp); | |||
| 643 | nbp->b_vp->v_numoutput++; | |||
| 644 | } | |||
| 645 | splx(s)spllower(s); | |||
| 646 | ||||
| 647 | (void) nfs_doio(bp, NULL((void *)0)); | |||
| 648 | } while ((bp = nbp) != NULL((void *)0)); | |||
| 649 | } | |||
| 650 | if (error) { | |||
| 651 | nfs_asyncdaemon[myiod] = NULL((void *)0); | |||
| 652 | nfs_numasync--; | |||
| 653 | nfs_bufqmax -= bufcount; | |||
| 654 | kthread_exit(error); | |||
| 655 | } | |||
| 656 | } | |||
| 657 | } | |||
| 658 | ||||
| 659 | void | |||
| 660 | nfs_getset_niothreads(int set) | |||
| 661 | { | |||
| 662 | int i, have, start; | |||
| 663 | ||||
| 664 | for (have = 0, i = 0; i < NFS_MAXASYNCDAEMON20; i++) | |||
| 665 | if (nfs_asyncdaemon[i] != NULL((void *)0)) | |||
| 666 | have++; | |||
| 667 | ||||
| 668 | if (set) { | |||
| 669 | /* clamp to sane range */ | |||
| 670 | nfs_niothreads = max(0, min(nfs_niothreads, NFS_MAXASYNCDAEMON20)); | |||
| 671 | ||||
| 672 | start = nfs_niothreads - have; | |||
| 673 | ||||
| 674 | while (start > 0) { | |||
| 675 | kthread_create(nfssvc_iod, NULL((void *)0), NULL((void *)0), "nfsio"); | |||
| 676 | start--; | |||
| 677 | } | |||
| 678 | ||||
| 679 | for (i = 0; (start < 0) && (i < NFS_MAXASYNCDAEMON20); i++) | |||
| 680 | if (nfs_asyncdaemon[i] != NULL((void *)0)) { | |||
| 681 | psignal(nfs_asyncdaemon[i], SIGKILL9); | |||
| 682 | start++; | |||
| 683 | } | |||
| 684 | } else { | |||
| 685 | if (nfs_niothreads >= 0) | |||
| 686 | nfs_niothreads = have; | |||
| 687 | } | |||
| 688 | } | |||
| 689 | #endif /* NFSCLIENT */ | |||
| 690 | ||||
| 691 | #ifdef NFSSERVER1 | |||
| 692 | /* | |||
| 693 | * Find an nfssrv_sock for nfsd, sleeping if needed. | |||
| 694 | */ | |||
| 695 | int | |||
| 696 | nfsrv_getslp(struct nfsd *nfsd) | |||
| 697 | { | |||
| 698 | struct nfssvc_sock *slp; | |||
| 699 | int error; | |||
| 700 | ||||
| 701 | again: | |||
| 702 | while (nfsd->nfsd_slp
| |||
| 703 | (nfsd_head_flag & NFSD_CHECKSLP0x01) == 0) { | |||
| 704 | nfsd->nfsd_flag |= NFSD_WAITING0x01; | |||
| 705 | nfsd_waiting++; | |||
| 706 | error = tsleep_nsec(nfsd, PSOCK24 | PCATCH0x100, "nfsd", INFSLP0xffffffffffffffffULL); | |||
| 707 | nfsd_waiting--; | |||
| 708 | if (error) | |||
| 709 | return (error); | |||
| 710 | } | |||
| 711 | ||||
| 712 | if (nfsd->nfsd_slp
| |||
| 713 | (nfsd_head_flag & NFSD_CHECKSLP0x01) != 0) { | |||
| 714 | TAILQ_FOREACH(slp, &nfssvc_sockhead, ns_chain)for((slp) = ((&nfssvc_sockhead)->tqh_first); (slp) != ( (void *)0); (slp) = ((slp)->ns_chain.tqe_next)) { | |||
| 715 | if ((slp->ns_flag & (SLP_VALID0x01 | SLP_DOREC0x02)) == | |||
| 716 | (SLP_VALID0x01 | SLP_DOREC0x02)) { | |||
| 717 | slp->ns_flag &= ~SLP_DOREC0x02; | |||
| 718 | slp->ns_sref++; | |||
| 719 | nfsd->nfsd_slp = slp; | |||
| 720 | break; | |||
| 721 | } | |||
| 722 | } | |||
| 723 | if (slp
| |||
| 724 | nfsd_head_flag &= ~NFSD_CHECKSLP0x01; | |||
| 725 | } | |||
| 726 | ||||
| 727 | if (nfsd->nfsd_slp
| |||
| 728 | goto again; | |||
| 729 | ||||
| 730 | return (0); | |||
| 731 | } | |||
| 732 | #endif /* NFSSERVER */ |