File: | nfs/nfs_syscalls.c |
Warning: | line 379, column 27 Access to field 'nd_procnum' results in a dereference of a null pointer (loaded from variable 'nd') |
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 || !ISSET(slp->ns_flag, SLP_VALID)((slp->ns_flag) & (0x01))) { | |||
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 == NULL((void *)0) && | |||
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 == NULL((void *)0) && | |||
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 == NULL((void *)0)) | |||
724 | nfsd_head_flag &= ~NFSD_CHECKSLP0x01; | |||
725 | } | |||
726 | ||||
727 | if (nfsd->nfsd_slp == NULL((void *)0)) | |||
728 | goto again; | |||
729 | ||||
730 | return (0); | |||
731 | } | |||
732 | #endif /* NFSSERVER */ |