1 | #include <machine/rtems-bsd-kernel-space.h> |
---|
2 | |
---|
3 | /*- |
---|
4 | * SPDX-License-Identifier: BSD-3-Clause |
---|
5 | * |
---|
6 | * Copyright (c) 1989, 1991, 1993, 1995 |
---|
7 | * The Regents of the University of California. All rights reserved. |
---|
8 | * |
---|
9 | * This code is derived from software contributed to Berkeley by |
---|
10 | * Rick Macklem at The University of Guelph. |
---|
11 | * |
---|
12 | * Redistribution and use in source and binary forms, with or without |
---|
13 | * modification, are permitted provided that the following conditions |
---|
14 | * are met: |
---|
15 | * 1. Redistributions of source code must retain the above copyright |
---|
16 | * notice, this list of conditions and the following disclaimer. |
---|
17 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
18 | * notice, this list of conditions and the following disclaimer in the |
---|
19 | * documentation and/or other materials provided with the distribution. |
---|
20 | * 3. Neither the name of the University nor the names of its contributors |
---|
21 | * may be used to endorse or promote products derived from this software |
---|
22 | * without specific prior written permission. |
---|
23 | * |
---|
24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
---|
25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
---|
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
34 | * SUCH DAMAGE. |
---|
35 | * |
---|
36 | */ |
---|
37 | |
---|
38 | #include <sys/cdefs.h> |
---|
39 | __FBSDID("$FreeBSD$"); |
---|
40 | |
---|
41 | /* |
---|
42 | * Socket operations for use by nfs |
---|
43 | */ |
---|
44 | |
---|
45 | #include <rtems/bsd/local/opt_kgssapi.h> |
---|
46 | #include <rtems/bsd/local/opt_nfs.h> |
---|
47 | |
---|
48 | #include <sys/param.h> |
---|
49 | #include <sys/systm.h> |
---|
50 | #include <sys/kernel.h> |
---|
51 | #include <sys/limits.h> |
---|
52 | #include <sys/lock.h> |
---|
53 | #include <sys/malloc.h> |
---|
54 | #include <sys/mbuf.h> |
---|
55 | #include <sys/mount.h> |
---|
56 | #include <sys/mutex.h> |
---|
57 | #include <sys/proc.h> |
---|
58 | #include <sys/signalvar.h> |
---|
59 | #include <sys/syscallsubr.h> |
---|
60 | #include <sys/sysctl.h> |
---|
61 | #include <sys/syslog.h> |
---|
62 | #include <sys/vnode.h> |
---|
63 | |
---|
64 | #include <rpc/rpc.h> |
---|
65 | #include <rpc/krpc.h> |
---|
66 | |
---|
67 | #ifndef __rtems__ |
---|
68 | #include <kgssapi/krb5/kcrypto.h> |
---|
69 | #endif /* __rtems__ */ |
---|
70 | |
---|
71 | #include <fs/nfs/nfsport.h> |
---|
72 | |
---|
73 | #ifdef KDTRACE_HOOKS |
---|
74 | #include <sys/dtrace_bsd.h> |
---|
75 | |
---|
76 | dtrace_nfsclient_nfs23_start_probe_func_t |
---|
77 | dtrace_nfscl_nfs234_start_probe; |
---|
78 | |
---|
79 | dtrace_nfsclient_nfs23_done_probe_func_t |
---|
80 | dtrace_nfscl_nfs234_done_probe; |
---|
81 | |
---|
82 | /* |
---|
83 | * Registered probes by RPC type. |
---|
84 | */ |
---|
85 | uint32_t nfscl_nfs2_start_probes[NFSV41_NPROCS + 1]; |
---|
86 | uint32_t nfscl_nfs2_done_probes[NFSV41_NPROCS + 1]; |
---|
87 | |
---|
88 | uint32_t nfscl_nfs3_start_probes[NFSV41_NPROCS + 1]; |
---|
89 | uint32_t nfscl_nfs3_done_probes[NFSV41_NPROCS + 1]; |
---|
90 | |
---|
91 | uint32_t nfscl_nfs4_start_probes[NFSV41_NPROCS + 1]; |
---|
92 | uint32_t nfscl_nfs4_done_probes[NFSV41_NPROCS + 1]; |
---|
93 | #endif |
---|
94 | |
---|
95 | NFSSTATESPINLOCK; |
---|
96 | NFSREQSPINLOCK; |
---|
97 | NFSDLOCKMUTEX; |
---|
98 | NFSCLSTATEMUTEX; |
---|
99 | extern struct nfsstatsv1 nfsstatsv1; |
---|
100 | extern struct nfsreqhead nfsd_reqq; |
---|
101 | extern int nfscl_ticks; |
---|
102 | extern void (*ncl_call_invalcaches)(struct vnode *); |
---|
103 | extern int nfs_numnfscbd; |
---|
104 | extern int nfscl_debuglevel; |
---|
105 | extern int nfsrv_lease; |
---|
106 | |
---|
107 | SVCPOOL *nfscbd_pool; |
---|
108 | static int nfsrv_gsscallbackson = 0; |
---|
109 | static int nfs_bufpackets = 4; |
---|
110 | static int nfs_reconnects; |
---|
111 | static int nfs3_jukebox_delay = 10; |
---|
112 | static int nfs_skip_wcc_data_onerr = 1; |
---|
113 | static int nfs_dsretries = 2; |
---|
114 | |
---|
115 | SYSCTL_DECL(_vfs_nfs); |
---|
116 | |
---|
117 | SYSCTL_INT(_vfs_nfs, OID_AUTO, bufpackets, CTLFLAG_RW, &nfs_bufpackets, 0, |
---|
118 | "Buffer reservation size 2 < x < 64"); |
---|
119 | SYSCTL_INT(_vfs_nfs, OID_AUTO, reconnects, CTLFLAG_RD, &nfs_reconnects, 0, |
---|
120 | "Number of times the nfs client has had to reconnect"); |
---|
121 | SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs3_jukebox_delay, CTLFLAG_RW, &nfs3_jukebox_delay, 0, |
---|
122 | "Number of seconds to delay a retry after receiving EJUKEBOX"); |
---|
123 | SYSCTL_INT(_vfs_nfs, OID_AUTO, skip_wcc_data_onerr, CTLFLAG_RW, &nfs_skip_wcc_data_onerr, 0, |
---|
124 | "Disable weak cache consistency checking when server returns an error"); |
---|
125 | SYSCTL_INT(_vfs_nfs, OID_AUTO, dsretries, CTLFLAG_RW, &nfs_dsretries, 0, |
---|
126 | "Number of retries for a DS RPC before failure"); |
---|
127 | |
---|
128 | static void nfs_down(struct nfsmount *, struct thread *, const char *, |
---|
129 | int, int); |
---|
130 | static void nfs_up(struct nfsmount *, struct thread *, const char *, |
---|
131 | int, int); |
---|
132 | static int nfs_msg(struct thread *, const char *, const char *, int); |
---|
133 | |
---|
134 | struct nfs_cached_auth { |
---|
135 | int ca_refs; /* refcount, including 1 from the cache */ |
---|
136 | uid_t ca_uid; /* uid that corresponds to this auth */ |
---|
137 | AUTH *ca_auth; /* RPC auth handle */ |
---|
138 | }; |
---|
139 | |
---|
140 | static int nfsv2_procid[NFS_V3NPROCS] = { |
---|
141 | NFSV2PROC_NULL, |
---|
142 | NFSV2PROC_GETATTR, |
---|
143 | NFSV2PROC_SETATTR, |
---|
144 | NFSV2PROC_LOOKUP, |
---|
145 | NFSV2PROC_NOOP, |
---|
146 | NFSV2PROC_READLINK, |
---|
147 | NFSV2PROC_READ, |
---|
148 | NFSV2PROC_WRITE, |
---|
149 | NFSV2PROC_CREATE, |
---|
150 | NFSV2PROC_MKDIR, |
---|
151 | NFSV2PROC_SYMLINK, |
---|
152 | NFSV2PROC_CREATE, |
---|
153 | NFSV2PROC_REMOVE, |
---|
154 | NFSV2PROC_RMDIR, |
---|
155 | NFSV2PROC_RENAME, |
---|
156 | NFSV2PROC_LINK, |
---|
157 | NFSV2PROC_READDIR, |
---|
158 | NFSV2PROC_NOOP, |
---|
159 | NFSV2PROC_STATFS, |
---|
160 | NFSV2PROC_NOOP, |
---|
161 | NFSV2PROC_NOOP, |
---|
162 | NFSV2PROC_NOOP, |
---|
163 | }; |
---|
164 | |
---|
165 | /* |
---|
166 | * Initialize sockets and congestion for a new NFS connection. |
---|
167 | * We do not free the sockaddr if error. |
---|
168 | * Which arguments are set to NULL indicate what kind of call it is. |
---|
169 | * cred == NULL --> a call to connect to a pNFS DS |
---|
170 | * nmp == NULL --> indicates an upcall to userland or a NFSv4.0 callback |
---|
171 | */ |
---|
172 | int |
---|
173 | newnfs_connect(struct nfsmount *nmp, struct nfssockreq *nrp, |
---|
174 | struct ucred *cred, NFSPROC_T *p, int callback_retry_mult) |
---|
175 | { |
---|
176 | int rcvreserve, sndreserve; |
---|
177 | int pktscale, pktscalesav; |
---|
178 | struct sockaddr *saddr; |
---|
179 | struct ucred *origcred; |
---|
180 | CLIENT *client; |
---|
181 | struct netconfig *nconf; |
---|
182 | struct socket *so; |
---|
183 | int one = 1, retries, error = 0; |
---|
184 | struct thread *td = curthread; |
---|
185 | SVCXPRT *xprt; |
---|
186 | struct timeval timo; |
---|
187 | |
---|
188 | /* |
---|
189 | * We need to establish the socket using the credentials of |
---|
190 | * the mountpoint. Some parts of this process (such as |
---|
191 | * sobind() and soconnect()) will use the curent thread's |
---|
192 | * credential instead of the socket credential. To work |
---|
193 | * around this, temporarily change the current thread's |
---|
194 | * credential to that of the mountpoint. |
---|
195 | * |
---|
196 | * XXX: It would be better to explicitly pass the correct |
---|
197 | * credential to sobind() and soconnect(). |
---|
198 | */ |
---|
199 | origcred = td->td_ucred; |
---|
200 | |
---|
201 | /* |
---|
202 | * Use the credential in nr_cred, if not NULL. |
---|
203 | */ |
---|
204 | if (nrp->nr_cred != NULL) |
---|
205 | td->td_ucred = nrp->nr_cred; |
---|
206 | else |
---|
207 | td->td_ucred = cred; |
---|
208 | saddr = nrp->nr_nam; |
---|
209 | |
---|
210 | if (saddr->sa_family == AF_INET) |
---|
211 | if (nrp->nr_sotype == SOCK_DGRAM) |
---|
212 | nconf = getnetconfigent("udp"); |
---|
213 | else |
---|
214 | nconf = getnetconfigent("tcp"); |
---|
215 | else if (saddr->sa_family == AF_LOCAL) |
---|
216 | nconf = getnetconfigent("local"); |
---|
217 | else |
---|
218 | if (nrp->nr_sotype == SOCK_DGRAM) |
---|
219 | nconf = getnetconfigent("udp6"); |
---|
220 | else |
---|
221 | nconf = getnetconfigent("tcp6"); |
---|
222 | |
---|
223 | pktscale = nfs_bufpackets; |
---|
224 | if (pktscale < 2) |
---|
225 | pktscale = 2; |
---|
226 | if (pktscale > 64) |
---|
227 | pktscale = 64; |
---|
228 | pktscalesav = pktscale; |
---|
229 | /* |
---|
230 | * soreserve() can fail if sb_max is too small, so shrink pktscale |
---|
231 | * and try again if there is an error. |
---|
232 | * Print a log message suggesting increasing sb_max. |
---|
233 | * Creating a socket and doing this is necessary since, if the |
---|
234 | * reservation sizes are too large and will make soreserve() fail, |
---|
235 | * the connection will work until a large send is attempted and |
---|
236 | * then it will loop in the krpc code. |
---|
237 | */ |
---|
238 | so = NULL; |
---|
239 | saddr = NFSSOCKADDR(nrp->nr_nam, struct sockaddr *); |
---|
240 | error = socreate(saddr->sa_family, &so, nrp->nr_sotype, |
---|
241 | nrp->nr_soproto, td->td_ucred, td); |
---|
242 | if (error) { |
---|
243 | td->td_ucred = origcred; |
---|
244 | goto out; |
---|
245 | } |
---|
246 | do { |
---|
247 | if (error != 0 && pktscale > 2) { |
---|
248 | if (nmp != NULL && nrp->nr_sotype == SOCK_STREAM && |
---|
249 | pktscale == pktscalesav) |
---|
250 | printf("Consider increasing kern.ipc.maxsockbuf\n"); |
---|
251 | pktscale--; |
---|
252 | } |
---|
253 | if (nrp->nr_sotype == SOCK_DGRAM) { |
---|
254 | if (nmp != NULL) { |
---|
255 | sndreserve = (NFS_MAXDGRAMDATA + NFS_MAXPKTHDR) * |
---|
256 | pktscale; |
---|
257 | rcvreserve = (NFS_MAXDGRAMDATA + NFS_MAXPKTHDR) * |
---|
258 | pktscale; |
---|
259 | } else { |
---|
260 | sndreserve = rcvreserve = 1024 * pktscale; |
---|
261 | } |
---|
262 | } else { |
---|
263 | if (nrp->nr_sotype != SOCK_STREAM) |
---|
264 | panic("nfscon sotype"); |
---|
265 | if (nmp != NULL) { |
---|
266 | sndreserve = (NFS_MAXBSIZE + NFS_MAXXDR + |
---|
267 | sizeof (u_int32_t)) * pktscale; |
---|
268 | rcvreserve = (NFS_MAXBSIZE + NFS_MAXXDR + |
---|
269 | sizeof (u_int32_t)) * pktscale; |
---|
270 | } else { |
---|
271 | sndreserve = rcvreserve = 1024 * pktscale; |
---|
272 | } |
---|
273 | } |
---|
274 | error = soreserve(so, sndreserve, rcvreserve); |
---|
275 | if (error != 0 && nmp != NULL && nrp->nr_sotype == SOCK_STREAM && |
---|
276 | pktscale <= 2) |
---|
277 | printf("Must increase kern.ipc.maxsockbuf or reduce" |
---|
278 | " rsize, wsize\n"); |
---|
279 | } while (error != 0 && pktscale > 2); |
---|
280 | soclose(so); |
---|
281 | if (error) { |
---|
282 | td->td_ucred = origcred; |
---|
283 | goto out; |
---|
284 | } |
---|
285 | |
---|
286 | client = clnt_reconnect_create(nconf, saddr, nrp->nr_prog, |
---|
287 | nrp->nr_vers, sndreserve, rcvreserve); |
---|
288 | CLNT_CONTROL(client, CLSET_WAITCHAN, "nfsreq"); |
---|
289 | if (nmp != NULL) { |
---|
290 | if ((nmp->nm_flag & NFSMNT_INT)) |
---|
291 | CLNT_CONTROL(client, CLSET_INTERRUPTIBLE, &one); |
---|
292 | if ((nmp->nm_flag & NFSMNT_RESVPORT)) |
---|
293 | CLNT_CONTROL(client, CLSET_PRIVPORT, &one); |
---|
294 | if (NFSHASSOFT(nmp)) { |
---|
295 | if (nmp->nm_sotype == SOCK_DGRAM) |
---|
296 | /* |
---|
297 | * For UDP, the large timeout for a reconnect |
---|
298 | * will be set to "nm_retry * nm_timeo / 2", so |
---|
299 | * we only want to do 2 reconnect timeout |
---|
300 | * retries. |
---|
301 | */ |
---|
302 | retries = 2; |
---|
303 | else |
---|
304 | retries = nmp->nm_retry; |
---|
305 | } else |
---|
306 | retries = INT_MAX; |
---|
307 | if (NFSHASNFSV4N(nmp)) { |
---|
308 | if (cred != NULL) { |
---|
309 | if (NFSHASSOFT(nmp)) { |
---|
310 | /* |
---|
311 | * This should be a DS mount. |
---|
312 | * Use CLSET_TIMEOUT to set the timeout |
---|
313 | * for connections to DSs instead of |
---|
314 | * specifying a timeout on each RPC. |
---|
315 | * This is done so that SO_SNDTIMEO |
---|
316 | * is set on the TCP socket as well |
---|
317 | * as specifying a time limit when |
---|
318 | * waiting for an RPC reply. Useful |
---|
319 | * if the send queue for the TCP |
---|
320 | * connection has become constipated, |
---|
321 | * due to a failed DS. |
---|
322 | * The choice of lease_duration / 4 is |
---|
323 | * fairly arbitrary, but seems to work |
---|
324 | * ok, with a lower bound of 10sec. |
---|
325 | */ |
---|
326 | timo.tv_sec = nfsrv_lease / 4; |
---|
327 | if (timo.tv_sec < 10) |
---|
328 | timo.tv_sec = 10; |
---|
329 | timo.tv_usec = 0; |
---|
330 | CLNT_CONTROL(client, CLSET_TIMEOUT, |
---|
331 | &timo); |
---|
332 | } |
---|
333 | /* |
---|
334 | * Make sure the nfscbd_pool doesn't get |
---|
335 | * destroyed while doing this. |
---|
336 | */ |
---|
337 | NFSD_LOCK(); |
---|
338 | if (nfs_numnfscbd > 0) { |
---|
339 | nfs_numnfscbd++; |
---|
340 | NFSD_UNLOCK(); |
---|
341 | xprt = svc_vc_create_backchannel( |
---|
342 | nfscbd_pool); |
---|
343 | CLNT_CONTROL(client, CLSET_BACKCHANNEL, |
---|
344 | xprt); |
---|
345 | NFSD_LOCK(); |
---|
346 | nfs_numnfscbd--; |
---|
347 | if (nfs_numnfscbd == 0) |
---|
348 | wakeup(&nfs_numnfscbd); |
---|
349 | } |
---|
350 | NFSD_UNLOCK(); |
---|
351 | } else { |
---|
352 | /* |
---|
353 | * cred == NULL for a DS connect. |
---|
354 | * For connects to a DS, set a retry limit |
---|
355 | * so that failed DSs will be detected. |
---|
356 | * This is ok for NFSv4.1, since a DS does |
---|
357 | * not maintain open/lock state and is the |
---|
358 | * only case where using a "soft" mount is |
---|
359 | * recommended for NFSv4. |
---|
360 | * For mounts from the MDS to DS, this is done |
---|
361 | * via mount options, but that is not the case |
---|
362 | * here. The retry limit here can be adjusted |
---|
363 | * via the sysctl vfs.nfs.dsretries. |
---|
364 | * See the comment above w.r.t. timeout. |
---|
365 | */ |
---|
366 | timo.tv_sec = nfsrv_lease / 4; |
---|
367 | if (timo.tv_sec < 10) |
---|
368 | timo.tv_sec = 10; |
---|
369 | timo.tv_usec = 0; |
---|
370 | CLNT_CONTROL(client, CLSET_TIMEOUT, &timo); |
---|
371 | retries = nfs_dsretries; |
---|
372 | } |
---|
373 | } |
---|
374 | } else { |
---|
375 | /* |
---|
376 | * Three cases: |
---|
377 | * - Null RPC callback to client |
---|
378 | * - Non-Null RPC callback to client, wait a little longer |
---|
379 | * - upcalls to nfsuserd and gssd (clp == NULL) |
---|
380 | */ |
---|
381 | if (callback_retry_mult == 0) { |
---|
382 | retries = NFSV4_UPCALLRETRY; |
---|
383 | CLNT_CONTROL(client, CLSET_PRIVPORT, &one); |
---|
384 | } else { |
---|
385 | retries = NFSV4_CALLBACKRETRY * callback_retry_mult; |
---|
386 | } |
---|
387 | } |
---|
388 | CLNT_CONTROL(client, CLSET_RETRIES, &retries); |
---|
389 | |
---|
390 | if (nmp != NULL) { |
---|
391 | /* |
---|
392 | * For UDP, there are 2 timeouts: |
---|
393 | * - CLSET_RETRY_TIMEOUT sets the initial timeout for the timer |
---|
394 | * that does a retransmit of an RPC request using the same |
---|
395 | * socket and xid. This is what you normally want to do, |
---|
396 | * since NFS servers depend on "same xid" for their |
---|
397 | * Duplicate Request Cache. |
---|
398 | * - timeout specified in CLNT_CALL_MBUF(), which specifies when |
---|
399 | * retransmits on the same socket should fail and a fresh |
---|
400 | * socket created. Each of these timeouts counts as one |
---|
401 | * CLSET_RETRIES as set above. |
---|
402 | * Set the initial retransmit timeout for UDP. This timeout |
---|
403 | * doesn't exist for TCP and the following call just fails, |
---|
404 | * which is ok. |
---|
405 | */ |
---|
406 | timo.tv_sec = nmp->nm_timeo / NFS_HZ; |
---|
407 | timo.tv_usec = (nmp->nm_timeo % NFS_HZ) * 1000000 / NFS_HZ; |
---|
408 | CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, &timo); |
---|
409 | } |
---|
410 | |
---|
411 | mtx_lock(&nrp->nr_mtx); |
---|
412 | if (nrp->nr_client != NULL) { |
---|
413 | mtx_unlock(&nrp->nr_mtx); |
---|
414 | /* |
---|
415 | * Someone else already connected. |
---|
416 | */ |
---|
417 | CLNT_RELEASE(client); |
---|
418 | } else { |
---|
419 | nrp->nr_client = client; |
---|
420 | /* |
---|
421 | * Protocols that do not require connections may be optionally |
---|
422 | * left unconnected for servers that reply from a port other |
---|
423 | * than NFS_PORT. |
---|
424 | */ |
---|
425 | if (nmp == NULL || (nmp->nm_flag & NFSMNT_NOCONN) == 0) { |
---|
426 | mtx_unlock(&nrp->nr_mtx); |
---|
427 | CLNT_CONTROL(client, CLSET_CONNECT, &one); |
---|
428 | } else |
---|
429 | mtx_unlock(&nrp->nr_mtx); |
---|
430 | } |
---|
431 | |
---|
432 | |
---|
433 | /* Restore current thread's credentials. */ |
---|
434 | td->td_ucred = origcred; |
---|
435 | |
---|
436 | out: |
---|
437 | NFSEXITCODE(error); |
---|
438 | return (error); |
---|
439 | } |
---|
440 | |
---|
441 | /* |
---|
442 | * NFS disconnect. Clean up and unlink. |
---|
443 | */ |
---|
444 | void |
---|
445 | newnfs_disconnect(struct nfssockreq *nrp) |
---|
446 | { |
---|
447 | CLIENT *client; |
---|
448 | |
---|
449 | mtx_lock(&nrp->nr_mtx); |
---|
450 | if (nrp->nr_client != NULL) { |
---|
451 | client = nrp->nr_client; |
---|
452 | nrp->nr_client = NULL; |
---|
453 | mtx_unlock(&nrp->nr_mtx); |
---|
454 | rpc_gss_secpurge_call(client); |
---|
455 | CLNT_CLOSE(client); |
---|
456 | CLNT_RELEASE(client); |
---|
457 | } else { |
---|
458 | mtx_unlock(&nrp->nr_mtx); |
---|
459 | } |
---|
460 | } |
---|
461 | |
---|
462 | static AUTH * |
---|
463 | nfs_getauth(struct nfssockreq *nrp, int secflavour, char *clnt_principal, |
---|
464 | char *srv_principal, gss_OID mech_oid, struct ucred *cred) |
---|
465 | { |
---|
466 | rpc_gss_service_t svc; |
---|
467 | AUTH *auth; |
---|
468 | |
---|
469 | switch (secflavour) { |
---|
470 | case RPCSEC_GSS_KRB5: |
---|
471 | case RPCSEC_GSS_KRB5I: |
---|
472 | case RPCSEC_GSS_KRB5P: |
---|
473 | if (!mech_oid) { |
---|
474 | if (!rpc_gss_mech_to_oid_call("kerberosv5", &mech_oid)) |
---|
475 | return (NULL); |
---|
476 | } |
---|
477 | if (secflavour == RPCSEC_GSS_KRB5) |
---|
478 | svc = rpc_gss_svc_none; |
---|
479 | else if (secflavour == RPCSEC_GSS_KRB5I) |
---|
480 | svc = rpc_gss_svc_integrity; |
---|
481 | else |
---|
482 | svc = rpc_gss_svc_privacy; |
---|
483 | |
---|
484 | if (clnt_principal == NULL) |
---|
485 | auth = rpc_gss_secfind_call(nrp->nr_client, cred, |
---|
486 | srv_principal, mech_oid, svc); |
---|
487 | else { |
---|
488 | auth = rpc_gss_seccreate_call(nrp->nr_client, cred, |
---|
489 | clnt_principal, srv_principal, "kerberosv5", |
---|
490 | svc, NULL, NULL, NULL); |
---|
491 | return (auth); |
---|
492 | } |
---|
493 | if (auth != NULL) |
---|
494 | return (auth); |
---|
495 | /* fallthrough */ |
---|
496 | case AUTH_SYS: |
---|
497 | default: |
---|
498 | return (authunix_create(cred)); |
---|
499 | |
---|
500 | } |
---|
501 | } |
---|
502 | |
---|
503 | /* |
---|
504 | * Callback from the RPC code to generate up/down notifications. |
---|
505 | */ |
---|
506 | |
---|
507 | struct nfs_feedback_arg { |
---|
508 | struct nfsmount *nf_mount; |
---|
509 | int nf_lastmsg; /* last tprintf */ |
---|
510 | int nf_tprintfmsg; |
---|
511 | struct thread *nf_td; |
---|
512 | }; |
---|
513 | |
---|
514 | static void |
---|
515 | nfs_feedback(int type, int proc, void *arg) |
---|
516 | { |
---|
517 | struct nfs_feedback_arg *nf = (struct nfs_feedback_arg *) arg; |
---|
518 | struct nfsmount *nmp = nf->nf_mount; |
---|
519 | time_t now; |
---|
520 | |
---|
521 | switch (type) { |
---|
522 | case FEEDBACK_REXMIT2: |
---|
523 | case FEEDBACK_RECONNECT: |
---|
524 | now = NFSD_MONOSEC; |
---|
525 | if (nf->nf_lastmsg + nmp->nm_tprintf_delay < now) { |
---|
526 | nfs_down(nmp, nf->nf_td, |
---|
527 | "not responding", 0, NFSSTA_TIMEO); |
---|
528 | nf->nf_tprintfmsg = TRUE; |
---|
529 | nf->nf_lastmsg = now; |
---|
530 | } |
---|
531 | break; |
---|
532 | |
---|
533 | case FEEDBACK_OK: |
---|
534 | nfs_up(nf->nf_mount, nf->nf_td, |
---|
535 | "is alive again", NFSSTA_TIMEO, nf->nf_tprintfmsg); |
---|
536 | break; |
---|
537 | } |
---|
538 | } |
---|
539 | |
---|
540 | /* |
---|
541 | * newnfs_request - goes something like this |
---|
542 | * - does the rpc by calling the krpc layer |
---|
543 | * - break down rpc header and return with nfs reply |
---|
544 | * nb: always frees up nd_mreq mbuf list |
---|
545 | */ |
---|
546 | int |
---|
547 | newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp, |
---|
548 | struct nfsclient *clp, struct nfssockreq *nrp, vnode_t vp, |
---|
549 | struct thread *td, struct ucred *cred, u_int32_t prog, u_int32_t vers, |
---|
550 | u_char *retsum, int toplevel, u_int64_t *xidp, struct nfsclsession *dssep) |
---|
551 | { |
---|
552 | uint32_t retseq, retval, slotseq, *tl; |
---|
553 | time_t waituntil; |
---|
554 | int i = 0, j = 0, opcnt, set_sigset = 0, slot; |
---|
555 | int error = 0, usegssname = 0, secflavour = AUTH_SYS; |
---|
556 | int freeslot, maxslot, reterr, slotpos, timeo; |
---|
557 | u_int16_t procnum; |
---|
558 | u_int trylater_delay = 1; |
---|
559 | struct nfs_feedback_arg nf; |
---|
560 | struct timeval timo; |
---|
561 | AUTH *auth; |
---|
562 | struct rpc_callextra ext; |
---|
563 | enum clnt_stat stat; |
---|
564 | struct nfsreq *rep = NULL; |
---|
565 | char *srv_principal = NULL, *clnt_principal = NULL; |
---|
566 | sigset_t oldset; |
---|
567 | struct ucred *authcred; |
---|
568 | struct nfsclsession *sep; |
---|
569 | uint8_t sessionid[NFSX_V4SESSIONID]; |
---|
570 | |
---|
571 | sep = dssep; |
---|
572 | if (xidp != NULL) |
---|
573 | *xidp = 0; |
---|
574 | /* Reject requests while attempting a forced unmount. */ |
---|
575 | if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) { |
---|
576 | m_freem(nd->nd_mreq); |
---|
577 | return (ESTALE); |
---|
578 | } |
---|
579 | |
---|
580 | /* |
---|
581 | * Set authcred, which is used to acquire RPC credentials to |
---|
582 | * the cred argument, by default. The crhold() should not be |
---|
583 | * necessary, but will ensure that some future code change |
---|
584 | * doesn't result in the credential being free'd prematurely. |
---|
585 | */ |
---|
586 | authcred = crhold(cred); |
---|
587 | |
---|
588 | /* For client side interruptible mounts, mask off the signals. */ |
---|
589 | if (nmp != NULL && td != NULL && NFSHASINT(nmp)) { |
---|
590 | newnfs_set_sigmask(td, &oldset); |
---|
591 | set_sigset = 1; |
---|
592 | } |
---|
593 | |
---|
594 | /* |
---|
595 | * XXX if not already connected call nfs_connect now. Longer |
---|
596 | * term, change nfs_mount to call nfs_connect unconditionally |
---|
597 | * and let clnt_reconnect_create handle reconnects. |
---|
598 | */ |
---|
599 | if (nrp->nr_client == NULL) |
---|
600 | newnfs_connect(nmp, nrp, cred, td, 0); |
---|
601 | |
---|
602 | /* |
---|
603 | * For a client side mount, nmp is != NULL and clp == NULL. For |
---|
604 | * server calls (callbacks or upcalls), nmp == NULL. |
---|
605 | */ |
---|
606 | if (clp != NULL) { |
---|
607 | NFSLOCKSTATE(); |
---|
608 | if ((clp->lc_flags & LCL_GSS) && nfsrv_gsscallbackson) { |
---|
609 | secflavour = RPCSEC_GSS_KRB5; |
---|
610 | if (nd->nd_procnum != NFSPROC_NULL) { |
---|
611 | if (clp->lc_flags & LCL_GSSINTEGRITY) |
---|
612 | secflavour = RPCSEC_GSS_KRB5I; |
---|
613 | else if (clp->lc_flags & LCL_GSSPRIVACY) |
---|
614 | secflavour = RPCSEC_GSS_KRB5P; |
---|
615 | } |
---|
616 | } |
---|
617 | NFSUNLOCKSTATE(); |
---|
618 | } else if (nmp != NULL && NFSHASKERB(nmp) && |
---|
619 | nd->nd_procnum != NFSPROC_NULL) { |
---|
620 | if (NFSHASALLGSSNAME(nmp) && nmp->nm_krbnamelen > 0) |
---|
621 | nd->nd_flag |= ND_USEGSSNAME; |
---|
622 | if ((nd->nd_flag & ND_USEGSSNAME) != 0) { |
---|
623 | /* |
---|
624 | * If there is a client side host based credential, |
---|
625 | * use that, otherwise use the system uid, if set. |
---|
626 | * The system uid is in the nmp->nm_sockreq.nr_cred |
---|
627 | * credentials. |
---|
628 | */ |
---|
629 | if (nmp->nm_krbnamelen > 0) { |
---|
630 | usegssname = 1; |
---|
631 | clnt_principal = nmp->nm_krbname; |
---|
632 | } else if (nmp->nm_uid != (uid_t)-1) { |
---|
633 | KASSERT(nmp->nm_sockreq.nr_cred != NULL, |
---|
634 | ("newnfs_request: NULL nr_cred")); |
---|
635 | crfree(authcred); |
---|
636 | authcred = crhold(nmp->nm_sockreq.nr_cred); |
---|
637 | } |
---|
638 | } else if (nmp->nm_krbnamelen == 0 && |
---|
639 | nmp->nm_uid != (uid_t)-1 && cred->cr_uid == (uid_t)0) { |
---|
640 | /* |
---|
641 | * If there is no host based principal name and |
---|
642 | * the system uid is set and this is root, use the |
---|
643 | * system uid, since root won't have user |
---|
644 | * credentials in a credentials cache file. |
---|
645 | * The system uid is in the nmp->nm_sockreq.nr_cred |
---|
646 | * credentials. |
---|
647 | */ |
---|
648 | KASSERT(nmp->nm_sockreq.nr_cred != NULL, |
---|
649 | ("newnfs_request: NULL nr_cred")); |
---|
650 | crfree(authcred); |
---|
651 | authcred = crhold(nmp->nm_sockreq.nr_cred); |
---|
652 | } |
---|
653 | if (NFSHASINTEGRITY(nmp)) |
---|
654 | secflavour = RPCSEC_GSS_KRB5I; |
---|
655 | else if (NFSHASPRIVACY(nmp)) |
---|
656 | secflavour = RPCSEC_GSS_KRB5P; |
---|
657 | else |
---|
658 | secflavour = RPCSEC_GSS_KRB5; |
---|
659 | srv_principal = NFSMNT_SRVKRBNAME(nmp); |
---|
660 | } else if (nmp != NULL && !NFSHASKERB(nmp) && |
---|
661 | nd->nd_procnum != NFSPROC_NULL && |
---|
662 | (nd->nd_flag & ND_USEGSSNAME) != 0) { |
---|
663 | /* |
---|
664 | * Use the uid that did the mount when the RPC is doing |
---|
665 | * NFSv4 system operations, as indicated by the |
---|
666 | * ND_USEGSSNAME flag, for the AUTH_SYS case. |
---|
667 | * The credentials in nm_sockreq.nr_cred were used for the |
---|
668 | * mount. |
---|
669 | */ |
---|
670 | KASSERT(nmp->nm_sockreq.nr_cred != NULL, |
---|
671 | ("newnfs_request: NULL nr_cred")); |
---|
672 | crfree(authcred); |
---|
673 | authcred = crhold(nmp->nm_sockreq.nr_cred); |
---|
674 | } |
---|
675 | |
---|
676 | if (nmp != NULL) { |
---|
677 | bzero(&nf, sizeof(struct nfs_feedback_arg)); |
---|
678 | nf.nf_mount = nmp; |
---|
679 | nf.nf_td = td; |
---|
680 | nf.nf_lastmsg = NFSD_MONOSEC - |
---|
681 | ((nmp->nm_tprintf_delay)-(nmp->nm_tprintf_initial_delay)); |
---|
682 | } |
---|
683 | |
---|
684 | if (nd->nd_procnum == NFSPROC_NULL) |
---|
685 | auth = authnone_create(); |
---|
686 | else if (usegssname) { |
---|
687 | /* |
---|
688 | * For this case, the authenticator is held in the |
---|
689 | * nfssockreq structure, so don't release the reference count |
---|
690 | * held on it. --> Don't AUTH_DESTROY() it in this function. |
---|
691 | */ |
---|
692 | if (nrp->nr_auth == NULL) |
---|
693 | nrp->nr_auth = nfs_getauth(nrp, secflavour, |
---|
694 | clnt_principal, srv_principal, NULL, authcred); |
---|
695 | else |
---|
696 | rpc_gss_refresh_auth_call(nrp->nr_auth); |
---|
697 | auth = nrp->nr_auth; |
---|
698 | } else |
---|
699 | auth = nfs_getauth(nrp, secflavour, NULL, |
---|
700 | srv_principal, NULL, authcred); |
---|
701 | crfree(authcred); |
---|
702 | if (auth == NULL) { |
---|
703 | m_freem(nd->nd_mreq); |
---|
704 | if (set_sigset) |
---|
705 | newnfs_restore_sigmask(td, &oldset); |
---|
706 | return (EACCES); |
---|
707 | } |
---|
708 | bzero(&ext, sizeof(ext)); |
---|
709 | ext.rc_auth = auth; |
---|
710 | if (nmp != NULL) { |
---|
711 | ext.rc_feedback = nfs_feedback; |
---|
712 | ext.rc_feedback_arg = &nf; |
---|
713 | } |
---|
714 | |
---|
715 | procnum = nd->nd_procnum; |
---|
716 | if ((nd->nd_flag & ND_NFSV4) && |
---|
717 | nd->nd_procnum != NFSPROC_NULL && |
---|
718 | nd->nd_procnum != NFSV4PROC_CBCOMPOUND) |
---|
719 | procnum = NFSV4PROC_COMPOUND; |
---|
720 | |
---|
721 | if (nmp != NULL) { |
---|
722 | NFSINCRGLOBAL(nfsstatsv1.rpcrequests); |
---|
723 | |
---|
724 | /* Map the procnum to the old NFSv2 one, as required. */ |
---|
725 | if ((nd->nd_flag & ND_NFSV2) != 0) { |
---|
726 | if (nd->nd_procnum < NFS_V3NPROCS) |
---|
727 | procnum = nfsv2_procid[nd->nd_procnum]; |
---|
728 | else |
---|
729 | procnum = NFSV2PROC_NOOP; |
---|
730 | } |
---|
731 | |
---|
732 | /* |
---|
733 | * Now only used for the R_DONTRECOVER case, but until that is |
---|
734 | * supported within the krpc code, I need to keep a queue of |
---|
735 | * outstanding RPCs for nfsv4 client requests. |
---|
736 | */ |
---|
737 | if ((nd->nd_flag & ND_NFSV4) && procnum == NFSV4PROC_COMPOUND) |
---|
738 | rep = malloc(sizeof(struct nfsreq), |
---|
739 | M_NFSDREQ, M_WAITOK); |
---|
740 | #ifdef KDTRACE_HOOKS |
---|
741 | if (dtrace_nfscl_nfs234_start_probe != NULL) { |
---|
742 | uint32_t probe_id; |
---|
743 | int probe_procnum; |
---|
744 | |
---|
745 | if (nd->nd_flag & ND_NFSV4) { |
---|
746 | probe_id = |
---|
747 | nfscl_nfs4_start_probes[nd->nd_procnum]; |
---|
748 | probe_procnum = nd->nd_procnum; |
---|
749 | } else if (nd->nd_flag & ND_NFSV3) { |
---|
750 | probe_id = nfscl_nfs3_start_probes[procnum]; |
---|
751 | probe_procnum = procnum; |
---|
752 | } else { |
---|
753 | probe_id = |
---|
754 | nfscl_nfs2_start_probes[nd->nd_procnum]; |
---|
755 | probe_procnum = procnum; |
---|
756 | } |
---|
757 | if (probe_id != 0) |
---|
758 | (dtrace_nfscl_nfs234_start_probe) |
---|
759 | (probe_id, vp, nd->nd_mreq, cred, |
---|
760 | probe_procnum); |
---|
761 | } |
---|
762 | #endif |
---|
763 | } |
---|
764 | freeslot = -1; /* Set to slot that needs to be free'd */ |
---|
765 | tryagain: |
---|
766 | slot = -1; /* Slot that needs a sequence# increment. */ |
---|
767 | /* |
---|
768 | * This timeout specifies when a new socket should be created, |
---|
769 | * along with new xid values. For UDP, this should be done |
---|
770 | * infrequently, since retransmits of RPC requests should normally |
---|
771 | * use the same xid. |
---|
772 | */ |
---|
773 | if (nmp == NULL) { |
---|
774 | timo.tv_usec = 0; |
---|
775 | if (clp == NULL) |
---|
776 | timo.tv_sec = NFSV4_UPCALLTIMEO; |
---|
777 | else |
---|
778 | timo.tv_sec = NFSV4_CALLBACKTIMEO; |
---|
779 | } else { |
---|
780 | if (nrp->nr_sotype != SOCK_DGRAM) { |
---|
781 | timo.tv_usec = 0; |
---|
782 | if ((nmp->nm_flag & NFSMNT_NFSV4)) |
---|
783 | timo.tv_sec = INT_MAX; |
---|
784 | else |
---|
785 | timo.tv_sec = NFS_TCPTIMEO; |
---|
786 | } else { |
---|
787 | if (NFSHASSOFT(nmp)) { |
---|
788 | /* |
---|
789 | * CLSET_RETRIES is set to 2, so this should be |
---|
790 | * half of the total timeout required. |
---|
791 | */ |
---|
792 | timeo = nmp->nm_retry * nmp->nm_timeo / 2; |
---|
793 | if (timeo < 1) |
---|
794 | timeo = 1; |
---|
795 | timo.tv_sec = timeo / NFS_HZ; |
---|
796 | timo.tv_usec = (timeo % NFS_HZ) * 1000000 / |
---|
797 | NFS_HZ; |
---|
798 | } else { |
---|
799 | /* For UDP hard mounts, use a large value. */ |
---|
800 | timo.tv_sec = NFS_MAXTIMEO / NFS_HZ; |
---|
801 | timo.tv_usec = 0; |
---|
802 | } |
---|
803 | } |
---|
804 | |
---|
805 | if (rep != NULL) { |
---|
806 | rep->r_flags = 0; |
---|
807 | rep->r_nmp = nmp; |
---|
808 | /* |
---|
809 | * Chain request into list of outstanding requests. |
---|
810 | */ |
---|
811 | NFSLOCKREQ(); |
---|
812 | TAILQ_INSERT_TAIL(&nfsd_reqq, rep, r_chain); |
---|
813 | NFSUNLOCKREQ(); |
---|
814 | } |
---|
815 | } |
---|
816 | |
---|
817 | nd->nd_mrep = NULL; |
---|
818 | if (clp != NULL && sep != NULL) |
---|
819 | stat = clnt_bck_call(nrp->nr_client, &ext, procnum, |
---|
820 | nd->nd_mreq, &nd->nd_mrep, timo, sep->nfsess_xprt); |
---|
821 | else |
---|
822 | stat = CLNT_CALL_MBUF(nrp->nr_client, &ext, procnum, |
---|
823 | nd->nd_mreq, &nd->nd_mrep, timo); |
---|
824 | NFSCL_DEBUG(2, "clnt call=%d\n", stat); |
---|
825 | |
---|
826 | if (rep != NULL) { |
---|
827 | /* |
---|
828 | * RPC done, unlink the request. |
---|
829 | */ |
---|
830 | NFSLOCKREQ(); |
---|
831 | TAILQ_REMOVE(&nfsd_reqq, rep, r_chain); |
---|
832 | NFSUNLOCKREQ(); |
---|
833 | } |
---|
834 | |
---|
835 | /* |
---|
836 | * If there was a successful reply and a tprintf msg. |
---|
837 | * tprintf a response. |
---|
838 | */ |
---|
839 | if (stat == RPC_SUCCESS) { |
---|
840 | error = 0; |
---|
841 | } else if (stat == RPC_TIMEDOUT) { |
---|
842 | NFSINCRGLOBAL(nfsstatsv1.rpctimeouts); |
---|
843 | error = ETIMEDOUT; |
---|
844 | } else if (stat == RPC_VERSMISMATCH) { |
---|
845 | NFSINCRGLOBAL(nfsstatsv1.rpcinvalid); |
---|
846 | error = EOPNOTSUPP; |
---|
847 | } else if (stat == RPC_PROGVERSMISMATCH) { |
---|
848 | NFSINCRGLOBAL(nfsstatsv1.rpcinvalid); |
---|
849 | error = EPROTONOSUPPORT; |
---|
850 | } else if (stat == RPC_INTR) { |
---|
851 | error = EINTR; |
---|
852 | } else if (stat == RPC_CANTSEND || stat == RPC_CANTRECV || |
---|
853 | stat == RPC_SYSTEMERROR) { |
---|
854 | /* Check for a session slot that needs to be free'd. */ |
---|
855 | if ((nd->nd_flag & (ND_NFSV41 | ND_HASSLOTID)) == |
---|
856 | (ND_NFSV41 | ND_HASSLOTID) && nmp != NULL && |
---|
857 | nd->nd_procnum != NFSPROC_NULL) { |
---|
858 | /* |
---|
859 | * This should only occur when either the MDS or |
---|
860 | * a client has an RPC against a DS fail. |
---|
861 | * This happens because these cases use "soft" |
---|
862 | * connections that can time out and fail. |
---|
863 | * The slot used for this RPC is now in a |
---|
864 | * non-deterministic state, but if the slot isn't |
---|
865 | * free'd, threads can get stuck waiting for a slot. |
---|
866 | */ |
---|
867 | if (sep == NULL) |
---|
868 | sep = nfsmnt_mdssession(nmp); |
---|
869 | /* |
---|
870 | * Bump the sequence# out of range, so that reuse of |
---|
871 | * this slot will result in an NFSERR_SEQMISORDERED |
---|
872 | * error and not a bogus cached RPC reply. |
---|
873 | */ |
---|
874 | mtx_lock(&sep->nfsess_mtx); |
---|
875 | sep->nfsess_slotseq[nd->nd_slotid] += 10; |
---|
876 | mtx_unlock(&sep->nfsess_mtx); |
---|
877 | /* And free the slot. */ |
---|
878 | nfsv4_freeslot(sep, nd->nd_slotid); |
---|
879 | } |
---|
880 | NFSINCRGLOBAL(nfsstatsv1.rpcinvalid); |
---|
881 | error = ENXIO; |
---|
882 | } else { |
---|
883 | NFSINCRGLOBAL(nfsstatsv1.rpcinvalid); |
---|
884 | error = EACCES; |
---|
885 | } |
---|
886 | if (error) { |
---|
887 | m_freem(nd->nd_mreq); |
---|
888 | if (usegssname == 0) |
---|
889 | AUTH_DESTROY(auth); |
---|
890 | if (rep != NULL) |
---|
891 | free(rep, M_NFSDREQ); |
---|
892 | if (set_sigset) |
---|
893 | newnfs_restore_sigmask(td, &oldset); |
---|
894 | return (error); |
---|
895 | } |
---|
896 | |
---|
897 | KASSERT(nd->nd_mrep != NULL, ("mrep shouldn't be NULL if no error\n")); |
---|
898 | |
---|
899 | /* |
---|
900 | * Search for any mbufs that are not a multiple of 4 bytes long |
---|
901 | * or with m_data not longword aligned. |
---|
902 | * These could cause pointer alignment problems, so copy them to |
---|
903 | * well aligned mbufs. |
---|
904 | */ |
---|
905 | newnfs_realign(&nd->nd_mrep, M_WAITOK); |
---|
906 | nd->nd_md = nd->nd_mrep; |
---|
907 | nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t); |
---|
908 | nd->nd_repstat = 0; |
---|
909 | if (nd->nd_procnum != NFSPROC_NULL && |
---|
910 | nd->nd_procnum != NFSV4PROC_CBNULL) { |
---|
911 | /* If sep == NULL, set it to the default in nmp. */ |
---|
912 | if (sep == NULL && nmp != NULL) |
---|
913 | sep = nfsmnt_mdssession(nmp); |
---|
914 | /* |
---|
915 | * and now the actual NFS xdr. |
---|
916 | */ |
---|
917 | NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); |
---|
918 | nd->nd_repstat = fxdr_unsigned(u_int32_t, *tl); |
---|
919 | if (nd->nd_repstat >= 10000) |
---|
920 | NFSCL_DEBUG(1, "proc=%d reps=%d\n", (int)nd->nd_procnum, |
---|
921 | (int)nd->nd_repstat); |
---|
922 | |
---|
923 | /* |
---|
924 | * Get rid of the tag, return count and SEQUENCE result for |
---|
925 | * NFSv4. |
---|
926 | */ |
---|
927 | if ((nd->nd_flag & ND_NFSV4) != 0 && nd->nd_repstat != |
---|
928 | NFSERR_MINORVERMISMATCH) { |
---|
929 | NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); |
---|
930 | i = fxdr_unsigned(int, *tl); |
---|
931 | error = nfsm_advance(nd, NFSM_RNDUP(i), -1); |
---|
932 | if (error) |
---|
933 | goto nfsmout; |
---|
934 | NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); |
---|
935 | opcnt = fxdr_unsigned(int, *tl++); |
---|
936 | i = fxdr_unsigned(int, *tl++); |
---|
937 | j = fxdr_unsigned(int, *tl); |
---|
938 | if (j >= 10000) |
---|
939 | NFSCL_DEBUG(1, "fop=%d fst=%d\n", i, j); |
---|
940 | /* |
---|
941 | * If the first op is Sequence, free up the slot. |
---|
942 | */ |
---|
943 | if ((nmp != NULL && i == NFSV4OP_SEQUENCE && j != 0) || |
---|
944 | (clp != NULL && i == NFSV4OP_CBSEQUENCE && j != 0)) |
---|
945 | NFSCL_DEBUG(1, "failed seq=%d\n", j); |
---|
946 | if (((nmp != NULL && i == NFSV4OP_SEQUENCE && j == 0) || |
---|
947 | (clp != NULL && i == NFSV4OP_CBSEQUENCE && |
---|
948 | j == 0)) && sep != NULL) { |
---|
949 | if (i == NFSV4OP_SEQUENCE) |
---|
950 | NFSM_DISSECT(tl, uint32_t *, |
---|
951 | NFSX_V4SESSIONID + |
---|
952 | 5 * NFSX_UNSIGNED); |
---|
953 | else |
---|
954 | NFSM_DISSECT(tl, uint32_t *, |
---|
955 | NFSX_V4SESSIONID + |
---|
956 | 4 * NFSX_UNSIGNED); |
---|
957 | mtx_lock(&sep->nfsess_mtx); |
---|
958 | if (bcmp(tl, sep->nfsess_sessionid, |
---|
959 | NFSX_V4SESSIONID) == 0) { |
---|
960 | tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; |
---|
961 | retseq = fxdr_unsigned(uint32_t, *tl++); |
---|
962 | slot = fxdr_unsigned(int, *tl++); |
---|
963 | freeslot = slot; |
---|
964 | if (retseq != sep->nfsess_slotseq[slot]) |
---|
965 | printf("retseq diff 0x%x\n", |
---|
966 | retseq); |
---|
967 | retval = fxdr_unsigned(uint32_t, *++tl); |
---|
968 | if ((retval + 1) < sep->nfsess_foreslots |
---|
969 | ) |
---|
970 | sep->nfsess_foreslots = (retval |
---|
971 | + 1); |
---|
972 | else if ((retval + 1) > |
---|
973 | sep->nfsess_foreslots) |
---|
974 | sep->nfsess_foreslots = (retval |
---|
975 | < 64) ? (retval + 1) : 64; |
---|
976 | } |
---|
977 | mtx_unlock(&sep->nfsess_mtx); |
---|
978 | |
---|
979 | /* Grab the op and status for the next one. */ |
---|
980 | if (opcnt > 1) { |
---|
981 | NFSM_DISSECT(tl, uint32_t *, |
---|
982 | 2 * NFSX_UNSIGNED); |
---|
983 | i = fxdr_unsigned(int, *tl++); |
---|
984 | j = fxdr_unsigned(int, *tl); |
---|
985 | } |
---|
986 | } |
---|
987 | } |
---|
988 | if (nd->nd_repstat != 0) { |
---|
989 | if (nd->nd_repstat == NFSERR_BADSESSION && |
---|
990 | nmp != NULL && dssep == NULL && |
---|
991 | (nd->nd_flag & ND_NFSV41) != 0) { |
---|
992 | /* |
---|
993 | * If this is a client side MDS RPC, mark |
---|
994 | * the MDS session defunct and initiate |
---|
995 | * recovery, as required. |
---|
996 | * The nfsess_defunct field is protected by |
---|
997 | * the NFSLOCKMNT()/nm_mtx lock and not the |
---|
998 | * nfsess_mtx lock to simplify its handling, |
---|
999 | * for the MDS session. This lock is also |
---|
1000 | * sufficient for nfsess_sessionid, since it |
---|
1001 | * never changes in the structure. |
---|
1002 | */ |
---|
1003 | NFSCL_DEBUG(1, "Got badsession\n"); |
---|
1004 | NFSLOCKCLSTATE(); |
---|
1005 | NFSLOCKMNT(nmp); |
---|
1006 | sep = NFSMNT_MDSSESSION(nmp); |
---|
1007 | if (bcmp(sep->nfsess_sessionid, nd->nd_sequence, |
---|
1008 | NFSX_V4SESSIONID) == 0) { |
---|
1009 | /* Initiate recovery. */ |
---|
1010 | sep->nfsess_defunct = 1; |
---|
1011 | NFSCL_DEBUG(1, "Marked defunct\n"); |
---|
1012 | if (nmp->nm_clp != NULL) { |
---|
1013 | nmp->nm_clp->nfsc_flags |= |
---|
1014 | NFSCLFLAGS_RECOVER; |
---|
1015 | wakeup(nmp->nm_clp); |
---|
1016 | } |
---|
1017 | } |
---|
1018 | NFSUNLOCKCLSTATE(); |
---|
1019 | /* |
---|
1020 | * Sleep for up to 1sec waiting for a new |
---|
1021 | * session. |
---|
1022 | */ |
---|
1023 | mtx_sleep(&nmp->nm_sess, &nmp->nm_mtx, PZERO, |
---|
1024 | "nfsbadsess", hz); |
---|
1025 | /* |
---|
1026 | * Get the session again, in case a new one |
---|
1027 | * has been created during the sleep. |
---|
1028 | */ |
---|
1029 | sep = NFSMNT_MDSSESSION(nmp); |
---|
1030 | NFSUNLOCKMNT(nmp); |
---|
1031 | if ((nd->nd_flag & ND_LOOPBADSESS) != 0) { |
---|
1032 | reterr = nfsv4_sequencelookup(nmp, sep, |
---|
1033 | &slotpos, &maxslot, &slotseq, |
---|
1034 | sessionid); |
---|
1035 | if (reterr == 0) { |
---|
1036 | /* Fill in new session info. */ |
---|
1037 | NFSCL_DEBUG(1, |
---|
1038 | "Filling in new sequence\n"); |
---|
1039 | tl = nd->nd_sequence; |
---|
1040 | bcopy(sessionid, tl, |
---|
1041 | NFSX_V4SESSIONID); |
---|
1042 | tl += NFSX_V4SESSIONID / |
---|
1043 | NFSX_UNSIGNED; |
---|
1044 | *tl++ = txdr_unsigned(slotseq); |
---|
1045 | *tl++ = txdr_unsigned(slotpos); |
---|
1046 | *tl = txdr_unsigned(maxslot); |
---|
1047 | } |
---|
1048 | if (reterr == NFSERR_BADSESSION || |
---|
1049 | reterr == 0) { |
---|
1050 | NFSCL_DEBUG(1, |
---|
1051 | "Badsession looping\n"); |
---|
1052 | m_freem(nd->nd_mrep); |
---|
1053 | nd->nd_mrep = NULL; |
---|
1054 | goto tryagain; |
---|
1055 | } |
---|
1056 | nd->nd_repstat = reterr; |
---|
1057 | NFSCL_DEBUG(1, "Got err=%d\n", reterr); |
---|
1058 | } |
---|
1059 | } |
---|
1060 | /* |
---|
1061 | * When clp != NULL, it is a callback and all |
---|
1062 | * callback operations can be retried for NFSERR_DELAY. |
---|
1063 | */ |
---|
1064 | if (((nd->nd_repstat == NFSERR_DELAY || |
---|
1065 | nd->nd_repstat == NFSERR_GRACE) && |
---|
1066 | (nd->nd_flag & ND_NFSV4) && (clp != NULL || |
---|
1067 | (nd->nd_procnum != NFSPROC_DELEGRETURN && |
---|
1068 | nd->nd_procnum != NFSPROC_SETATTR && |
---|
1069 | nd->nd_procnum != NFSPROC_READ && |
---|
1070 | nd->nd_procnum != NFSPROC_READDS && |
---|
1071 | nd->nd_procnum != NFSPROC_WRITE && |
---|
1072 | nd->nd_procnum != NFSPROC_WRITEDS && |
---|
1073 | nd->nd_procnum != NFSPROC_OPEN && |
---|
1074 | nd->nd_procnum != NFSPROC_CREATE && |
---|
1075 | nd->nd_procnum != NFSPROC_OPENCONFIRM && |
---|
1076 | nd->nd_procnum != NFSPROC_OPENDOWNGRADE && |
---|
1077 | nd->nd_procnum != NFSPROC_CLOSE && |
---|
1078 | nd->nd_procnum != NFSPROC_LOCK && |
---|
1079 | nd->nd_procnum != NFSPROC_LOCKU))) || |
---|
1080 | (nd->nd_repstat == NFSERR_DELAY && |
---|
1081 | (nd->nd_flag & ND_NFSV4) == 0) || |
---|
1082 | nd->nd_repstat == NFSERR_RESOURCE) { |
---|
1083 | if (trylater_delay > NFS_TRYLATERDEL) |
---|
1084 | trylater_delay = NFS_TRYLATERDEL; |
---|
1085 | waituntil = NFSD_MONOSEC + trylater_delay; |
---|
1086 | while (NFSD_MONOSEC < waituntil) |
---|
1087 | (void) nfs_catnap(PZERO, 0, "nfstry"); |
---|
1088 | trylater_delay *= 2; |
---|
1089 | if (slot != -1) { |
---|
1090 | mtx_lock(&sep->nfsess_mtx); |
---|
1091 | sep->nfsess_slotseq[slot]++; |
---|
1092 | *nd->nd_slotseq = txdr_unsigned( |
---|
1093 | sep->nfsess_slotseq[slot]); |
---|
1094 | mtx_unlock(&sep->nfsess_mtx); |
---|
1095 | } |
---|
1096 | m_freem(nd->nd_mrep); |
---|
1097 | nd->nd_mrep = NULL; |
---|
1098 | goto tryagain; |
---|
1099 | } |
---|
1100 | |
---|
1101 | /* |
---|
1102 | * If the File Handle was stale, invalidate the |
---|
1103 | * lookup cache, just in case. |
---|
1104 | * (vp != NULL implies a client side call) |
---|
1105 | */ |
---|
1106 | if (nd->nd_repstat == ESTALE && vp != NULL) { |
---|
1107 | cache_purge(vp); |
---|
1108 | if (ncl_call_invalcaches != NULL) |
---|
1109 | (*ncl_call_invalcaches)(vp); |
---|
1110 | } |
---|
1111 | } |
---|
1112 | if ((nd->nd_flag & ND_NFSV4) != 0) { |
---|
1113 | /* Free the slot, as required. */ |
---|
1114 | if (freeslot != -1) |
---|
1115 | nfsv4_freeslot(sep, freeslot); |
---|
1116 | /* |
---|
1117 | * If this op is Putfh, throw its results away. |
---|
1118 | */ |
---|
1119 | if (j >= 10000) |
---|
1120 | NFSCL_DEBUG(1, "nop=%d nst=%d\n", i, j); |
---|
1121 | if (nmp != NULL && i == NFSV4OP_PUTFH && j == 0) { |
---|
1122 | NFSM_DISSECT(tl,u_int32_t *,2 * NFSX_UNSIGNED); |
---|
1123 | i = fxdr_unsigned(int, *tl++); |
---|
1124 | j = fxdr_unsigned(int, *tl); |
---|
1125 | if (j >= 10000) |
---|
1126 | NFSCL_DEBUG(1, "n2op=%d n2st=%d\n", i, |
---|
1127 | j); |
---|
1128 | /* |
---|
1129 | * All Compounds that do an Op that must |
---|
1130 | * be in sequence consist of NFSV4OP_PUTFH |
---|
1131 | * followed by one of these. As such, we |
---|
1132 | * can determine if the seqid# should be |
---|
1133 | * incremented, here. |
---|
1134 | */ |
---|
1135 | if ((i == NFSV4OP_OPEN || |
---|
1136 | i == NFSV4OP_OPENCONFIRM || |
---|
1137 | i == NFSV4OP_OPENDOWNGRADE || |
---|
1138 | i == NFSV4OP_CLOSE || |
---|
1139 | i == NFSV4OP_LOCK || |
---|
1140 | i == NFSV4OP_LOCKU) && |
---|
1141 | (j == 0 || |
---|
1142 | (j != NFSERR_STALECLIENTID && |
---|
1143 | j != NFSERR_STALESTATEID && |
---|
1144 | j != NFSERR_BADSTATEID && |
---|
1145 | j != NFSERR_BADSEQID && |
---|
1146 | j != NFSERR_BADXDR && |
---|
1147 | j != NFSERR_RESOURCE && |
---|
1148 | j != NFSERR_NOFILEHANDLE))) |
---|
1149 | nd->nd_flag |= ND_INCRSEQID; |
---|
1150 | } |
---|
1151 | /* |
---|
1152 | * If this op's status is non-zero, mark |
---|
1153 | * that there is no more data to process. |
---|
1154 | * The exception is Setattr, which always has xdr |
---|
1155 | * when it has failed. |
---|
1156 | */ |
---|
1157 | if (j != 0 && i != NFSV4OP_SETATTR) |
---|
1158 | nd->nd_flag |= ND_NOMOREDATA; |
---|
1159 | |
---|
1160 | /* |
---|
1161 | * If R_DONTRECOVER is set, replace the stale error |
---|
1162 | * reply, so that recovery isn't initiated. |
---|
1163 | */ |
---|
1164 | if ((nd->nd_repstat == NFSERR_STALECLIENTID || |
---|
1165 | nd->nd_repstat == NFSERR_BADSESSION || |
---|
1166 | nd->nd_repstat == NFSERR_STALESTATEID) && |
---|
1167 | rep != NULL && (rep->r_flags & R_DONTRECOVER)) |
---|
1168 | nd->nd_repstat = NFSERR_STALEDONTRECOVER; |
---|
1169 | } |
---|
1170 | } |
---|
1171 | |
---|
1172 | #ifdef KDTRACE_HOOKS |
---|
1173 | if (nmp != NULL && dtrace_nfscl_nfs234_done_probe != NULL) { |
---|
1174 | uint32_t probe_id; |
---|
1175 | int probe_procnum; |
---|
1176 | |
---|
1177 | if (nd->nd_flag & ND_NFSV4) { |
---|
1178 | probe_id = nfscl_nfs4_done_probes[nd->nd_procnum]; |
---|
1179 | probe_procnum = nd->nd_procnum; |
---|
1180 | } else if (nd->nd_flag & ND_NFSV3) { |
---|
1181 | probe_id = nfscl_nfs3_done_probes[procnum]; |
---|
1182 | probe_procnum = procnum; |
---|
1183 | } else { |
---|
1184 | probe_id = nfscl_nfs2_done_probes[nd->nd_procnum]; |
---|
1185 | probe_procnum = procnum; |
---|
1186 | } |
---|
1187 | if (probe_id != 0) |
---|
1188 | (dtrace_nfscl_nfs234_done_probe)(probe_id, vp, |
---|
1189 | nd->nd_mreq, cred, probe_procnum, 0); |
---|
1190 | } |
---|
1191 | #endif |
---|
1192 | |
---|
1193 | m_freem(nd->nd_mreq); |
---|
1194 | if (usegssname == 0) |
---|
1195 | AUTH_DESTROY(auth); |
---|
1196 | if (rep != NULL) |
---|
1197 | free(rep, M_NFSDREQ); |
---|
1198 | if (set_sigset) |
---|
1199 | newnfs_restore_sigmask(td, &oldset); |
---|
1200 | return (0); |
---|
1201 | nfsmout: |
---|
1202 | mbuf_freem(nd->nd_mrep); |
---|
1203 | mbuf_freem(nd->nd_mreq); |
---|
1204 | if (usegssname == 0) |
---|
1205 | AUTH_DESTROY(auth); |
---|
1206 | if (rep != NULL) |
---|
1207 | free(rep, M_NFSDREQ); |
---|
1208 | if (set_sigset) |
---|
1209 | newnfs_restore_sigmask(td, &oldset); |
---|
1210 | return (error); |
---|
1211 | } |
---|
1212 | |
---|
1213 | /* |
---|
1214 | * Mark all of an nfs mount's outstanding requests with R_SOFTTERM and |
---|
1215 | * wait for all requests to complete. This is used by forced unmounts |
---|
1216 | * to terminate any outstanding RPCs. |
---|
1217 | */ |
---|
1218 | int |
---|
1219 | newnfs_nmcancelreqs(struct nfsmount *nmp) |
---|
1220 | { |
---|
1221 | struct nfsclds *dsp; |
---|
1222 | struct __rpc_client *cl; |
---|
1223 | |
---|
1224 | if (nmp->nm_sockreq.nr_client != NULL) |
---|
1225 | CLNT_CLOSE(nmp->nm_sockreq.nr_client); |
---|
1226 | lookformore: |
---|
1227 | NFSLOCKMNT(nmp); |
---|
1228 | TAILQ_FOREACH(dsp, &nmp->nm_sess, nfsclds_list) { |
---|
1229 | NFSLOCKDS(dsp); |
---|
1230 | if (dsp != TAILQ_FIRST(&nmp->nm_sess) && |
---|
1231 | (dsp->nfsclds_flags & NFSCLDS_CLOSED) == 0 && |
---|
1232 | dsp->nfsclds_sockp != NULL && |
---|
1233 | dsp->nfsclds_sockp->nr_client != NULL) { |
---|
1234 | dsp->nfsclds_flags |= NFSCLDS_CLOSED; |
---|
1235 | cl = dsp->nfsclds_sockp->nr_client; |
---|
1236 | NFSUNLOCKDS(dsp); |
---|
1237 | NFSUNLOCKMNT(nmp); |
---|
1238 | CLNT_CLOSE(cl); |
---|
1239 | goto lookformore; |
---|
1240 | } |
---|
1241 | NFSUNLOCKDS(dsp); |
---|
1242 | } |
---|
1243 | NFSUNLOCKMNT(nmp); |
---|
1244 | return (0); |
---|
1245 | } |
---|
1246 | |
---|
1247 | /* |
---|
1248 | * Any signal that can interrupt an NFS operation in an intr mount |
---|
1249 | * should be added to this set. SIGSTOP and SIGKILL cannot be masked. |
---|
1250 | */ |
---|
1251 | int newnfs_sig_set[] = { |
---|
1252 | SIGINT, |
---|
1253 | SIGTERM, |
---|
1254 | SIGHUP, |
---|
1255 | SIGKILL, |
---|
1256 | SIGQUIT |
---|
1257 | }; |
---|
1258 | |
---|
1259 | /* |
---|
1260 | * Check to see if one of the signals in our subset is pending on |
---|
1261 | * the process (in an intr mount). |
---|
1262 | */ |
---|
1263 | static int |
---|
1264 | nfs_sig_pending(sigset_t set) |
---|
1265 | { |
---|
1266 | int i; |
---|
1267 | |
---|
1268 | for (i = 0 ; i < nitems(newnfs_sig_set); i++) |
---|
1269 | if (SIGISMEMBER(set, newnfs_sig_set[i])) |
---|
1270 | return (1); |
---|
1271 | return (0); |
---|
1272 | } |
---|
1273 | |
---|
1274 | /* |
---|
1275 | * The set/restore sigmask functions are used to (temporarily) overwrite |
---|
1276 | * the thread td_sigmask during an RPC call (for example). These are also |
---|
1277 | * used in other places in the NFS client that might tsleep(). |
---|
1278 | */ |
---|
1279 | void |
---|
1280 | newnfs_set_sigmask(struct thread *td, sigset_t *oldset) |
---|
1281 | { |
---|
1282 | #ifndef __rtems__ |
---|
1283 | sigset_t newset; |
---|
1284 | int i; |
---|
1285 | struct proc *p; |
---|
1286 | |
---|
1287 | SIGFILLSET(newset); |
---|
1288 | if (td == NULL) |
---|
1289 | td = curthread; /* XXX */ |
---|
1290 | p = td->td_proc; |
---|
1291 | /* Remove the NFS set of signals from newset */ |
---|
1292 | PROC_LOCK(p); |
---|
1293 | mtx_lock(&p->p_sigacts->ps_mtx); |
---|
1294 | for (i = 0 ; i < nitems(newnfs_sig_set); i++) { |
---|
1295 | /* |
---|
1296 | * But make sure we leave the ones already masked |
---|
1297 | * by the process, ie. remove the signal from the |
---|
1298 | * temporary signalmask only if it wasn't already |
---|
1299 | * in p_sigmask. |
---|
1300 | */ |
---|
1301 | if (!SIGISMEMBER(td->td_sigmask, newnfs_sig_set[i]) && |
---|
1302 | !SIGISMEMBER(p->p_sigacts->ps_sigignore, newnfs_sig_set[i])) |
---|
1303 | SIGDELSET(newset, newnfs_sig_set[i]); |
---|
1304 | } |
---|
1305 | mtx_unlock(&p->p_sigacts->ps_mtx); |
---|
1306 | kern_sigprocmask(td, SIG_SETMASK, &newset, oldset, |
---|
1307 | SIGPROCMASK_PROC_LOCKED); |
---|
1308 | PROC_UNLOCK(p); |
---|
1309 | #endif /* __rtems__ */ |
---|
1310 | } |
---|
1311 | |
---|
1312 | void |
---|
1313 | newnfs_restore_sigmask(struct thread *td, sigset_t *set) |
---|
1314 | { |
---|
1315 | #ifndef __rtems__ |
---|
1316 | if (td == NULL) |
---|
1317 | td = curthread; /* XXX */ |
---|
1318 | kern_sigprocmask(td, SIG_SETMASK, set, NULL, 0); |
---|
1319 | #endif /* __rtems__ */ |
---|
1320 | } |
---|
1321 | |
---|
1322 | /* |
---|
1323 | * NFS wrapper to msleep(), that shoves a new p_sigmask and restores the |
---|
1324 | * old one after msleep() returns. |
---|
1325 | */ |
---|
1326 | int |
---|
1327 | newnfs_msleep(struct thread *td, void *ident, struct mtx *mtx, int priority, char *wmesg, int timo) |
---|
1328 | { |
---|
1329 | sigset_t oldset; |
---|
1330 | int error; |
---|
1331 | |
---|
1332 | if ((priority & PCATCH) == 0) |
---|
1333 | return msleep(ident, mtx, priority, wmesg, timo); |
---|
1334 | if (td == NULL) |
---|
1335 | td = curthread; /* XXX */ |
---|
1336 | newnfs_set_sigmask(td, &oldset); |
---|
1337 | error = msleep(ident, mtx, priority, wmesg, timo); |
---|
1338 | newnfs_restore_sigmask(td, &oldset); |
---|
1339 | return (error); |
---|
1340 | } |
---|
1341 | |
---|
1342 | /* |
---|
1343 | * Test for a termination condition pending on the process. |
---|
1344 | * This is used for NFSMNT_INT mounts. |
---|
1345 | */ |
---|
1346 | int |
---|
1347 | newnfs_sigintr(struct nfsmount *nmp, struct thread *td) |
---|
1348 | { |
---|
1349 | #ifndef __rtems__ |
---|
1350 | struct proc *p; |
---|
1351 | sigset_t tmpset; |
---|
1352 | |
---|
1353 | /* Terminate all requests while attempting a forced unmount. */ |
---|
1354 | if (NFSCL_FORCEDISM(nmp->nm_mountp)) |
---|
1355 | return (EIO); |
---|
1356 | if (!(nmp->nm_flag & NFSMNT_INT)) |
---|
1357 | return (0); |
---|
1358 | if (td == NULL) |
---|
1359 | return (0); |
---|
1360 | p = td->td_proc; |
---|
1361 | PROC_LOCK(p); |
---|
1362 | tmpset = p->p_siglist; |
---|
1363 | SIGSETOR(tmpset, td->td_siglist); |
---|
1364 | SIGSETNAND(tmpset, td->td_sigmask); |
---|
1365 | mtx_lock(&p->p_sigacts->ps_mtx); |
---|
1366 | SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore); |
---|
1367 | mtx_unlock(&p->p_sigacts->ps_mtx); |
---|
1368 | if ((SIGNOTEMPTY(p->p_siglist) || SIGNOTEMPTY(td->td_siglist)) |
---|
1369 | && nfs_sig_pending(tmpset)) { |
---|
1370 | PROC_UNLOCK(p); |
---|
1371 | return (EINTR); |
---|
1372 | } |
---|
1373 | PROC_UNLOCK(p); |
---|
1374 | #endif /* __rtems__ */ |
---|
1375 | return (0); |
---|
1376 | } |
---|
1377 | |
---|
1378 | static int |
---|
1379 | nfs_msg(struct thread *td, const char *server, const char *msg, int error) |
---|
1380 | { |
---|
1381 | struct proc *p; |
---|
1382 | |
---|
1383 | p = td ? td->td_proc : NULL; |
---|
1384 | if (error) { |
---|
1385 | tprintf(p, LOG_INFO, "nfs server %s: %s, error %d\n", |
---|
1386 | server, msg, error); |
---|
1387 | } else { |
---|
1388 | tprintf(p, LOG_INFO, "nfs server %s: %s\n", server, msg); |
---|
1389 | } |
---|
1390 | return (0); |
---|
1391 | } |
---|
1392 | |
---|
1393 | static void |
---|
1394 | nfs_down(struct nfsmount *nmp, struct thread *td, const char *msg, |
---|
1395 | int error, int flags) |
---|
1396 | { |
---|
1397 | if (nmp == NULL) |
---|
1398 | return; |
---|
1399 | mtx_lock(&nmp->nm_mtx); |
---|
1400 | if ((flags & NFSSTA_TIMEO) && !(nmp->nm_state & NFSSTA_TIMEO)) { |
---|
1401 | nmp->nm_state |= NFSSTA_TIMEO; |
---|
1402 | mtx_unlock(&nmp->nm_mtx); |
---|
1403 | vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, |
---|
1404 | VQ_NOTRESP, 0); |
---|
1405 | } else |
---|
1406 | mtx_unlock(&nmp->nm_mtx); |
---|
1407 | mtx_lock(&nmp->nm_mtx); |
---|
1408 | if ((flags & NFSSTA_LOCKTIMEO) && !(nmp->nm_state & NFSSTA_LOCKTIMEO)) { |
---|
1409 | nmp->nm_state |= NFSSTA_LOCKTIMEO; |
---|
1410 | mtx_unlock(&nmp->nm_mtx); |
---|
1411 | vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, |
---|
1412 | VQ_NOTRESPLOCK, 0); |
---|
1413 | } else |
---|
1414 | mtx_unlock(&nmp->nm_mtx); |
---|
1415 | nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, error); |
---|
1416 | } |
---|
1417 | |
---|
1418 | static void |
---|
1419 | nfs_up(struct nfsmount *nmp, struct thread *td, const char *msg, |
---|
1420 | int flags, int tprintfmsg) |
---|
1421 | { |
---|
1422 | if (nmp == NULL) |
---|
1423 | return; |
---|
1424 | if (tprintfmsg) { |
---|
1425 | nfs_msg(td, nmp->nm_mountp->mnt_stat.f_mntfromname, msg, 0); |
---|
1426 | } |
---|
1427 | |
---|
1428 | mtx_lock(&nmp->nm_mtx); |
---|
1429 | if ((flags & NFSSTA_TIMEO) && (nmp->nm_state & NFSSTA_TIMEO)) { |
---|
1430 | nmp->nm_state &= ~NFSSTA_TIMEO; |
---|
1431 | mtx_unlock(&nmp->nm_mtx); |
---|
1432 | vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, |
---|
1433 | VQ_NOTRESP, 1); |
---|
1434 | } else |
---|
1435 | mtx_unlock(&nmp->nm_mtx); |
---|
1436 | |
---|
1437 | mtx_lock(&nmp->nm_mtx); |
---|
1438 | if ((flags & NFSSTA_LOCKTIMEO) && (nmp->nm_state & NFSSTA_LOCKTIMEO)) { |
---|
1439 | nmp->nm_state &= ~NFSSTA_LOCKTIMEO; |
---|
1440 | mtx_unlock(&nmp->nm_mtx); |
---|
1441 | vfs_event_signal(&nmp->nm_mountp->mnt_stat.f_fsid, |
---|
1442 | VQ_NOTRESPLOCK, 1); |
---|
1443 | } else |
---|
1444 | mtx_unlock(&nmp->nm_mtx); |
---|
1445 | } |
---|
1446 | |
---|