1 |
|
|
/* |
2 |
|
|
* Copyright (c) 1990 Jan-Simon Pendry |
3 |
|
|
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine |
4 |
|
|
* Copyright (c) 1990, 1993 |
5 |
|
|
* The Regents of the University of California. All rights reserved. |
6 |
|
|
* |
7 |
|
|
* This code is derived from software contributed to Berkeley by |
8 |
|
|
* Jan-Simon Pendry at Imperial College, London. |
9 |
|
|
* |
10 |
|
|
* Redistribution and use in source and binary forms, with or without |
11 |
|
|
* modification, are permitted provided that the following conditions |
12 |
|
|
* are met: |
13 |
|
|
* 1. Redistributions of source code must retain the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer. |
15 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
16 |
|
|
* notice, this list of conditions and the following disclaimer in the |
17 |
|
|
* documentation and/or other materials provided with the distribution. |
18 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
19 |
|
|
* may be used to endorse or promote products derived from this software |
20 |
|
|
* without specific prior written permission. |
21 |
|
|
* |
22 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
23 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
24 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
26 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
27 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
28 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
29 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
30 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
31 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
32 |
|
|
* SUCH DAMAGE. |
33 |
|
|
* |
34 |
|
|
* from: @(#)srvr_nfs.c 8.1 (Berkeley) 6/6/93 |
35 |
|
|
* $Id: srvr_nfs.c,v 1.10 2014/10/26 03:28:41 guenther Exp $ |
36 |
|
|
*/ |
37 |
|
|
|
38 |
|
|
/* |
39 |
|
|
* NFS server modeling |
40 |
|
|
*/ |
41 |
|
|
|
42 |
|
|
#include "am.h" |
43 |
|
|
#include <netdb.h> |
44 |
|
|
#include <rpc/pmap_prot.h> |
45 |
|
|
#include "mount.h" |
46 |
|
|
|
47 |
|
|
extern qelem nfs_srvr_list; |
48 |
|
|
qelem nfs_srvr_list = { &nfs_srvr_list, &nfs_srvr_list }; |
49 |
|
|
|
50 |
|
|
typedef struct nfs_private { |
51 |
|
|
u_short np_mountd; /* Mount daemon port number */ |
52 |
|
|
char np_mountd_inval; /* Port *may* be invalid */ |
53 |
|
|
int np_ping; /* Number of failed ping attempts */ |
54 |
|
|
time_t np_ttl; /* Time when server is thought dead */ |
55 |
|
|
int np_xid; /* RPC transaction id for pings */ |
56 |
|
|
int np_error; /* Error during portmap request */ |
57 |
|
|
} nfs_private; |
58 |
|
|
|
59 |
|
|
static int np_xid; /* For NFS pings */ |
60 |
|
|
#define NPXID_ALLOC() (++np_xid) |
61 |
|
|
/*#define NPXID_ALLOC() ((++np_xid&0x0fffffff) == 0 ? npxid_gc() : np_xid)*/ |
62 |
|
|
|
63 |
|
|
/* |
64 |
|
|
* Number of pings allowed to fail before host is declared down |
65 |
|
|
* - three-fifths of the allowed mount time... |
66 |
|
|
#define MAX_ALLOWED_PINGS ((((ALLOWED_MOUNT_TIME + 5 * AM_PINGER - 1) * 3) / 5) / AM_PINGER) |
67 |
|
|
*/ |
68 |
|
|
#define MAX_ALLOWED_PINGS (3 + /* for luck ... */ 1) |
69 |
|
|
|
70 |
|
|
/* |
71 |
|
|
* How often to ping when starting a new server |
72 |
|
|
*/ |
73 |
|
|
#define FAST_NFS_PING 3 |
74 |
|
|
|
75 |
|
|
#if (FAST_NFS_PING * MAX_ALLOWED_PINGS) >= ALLOWED_MOUNT_TIME |
76 |
|
|
#error: sanity check failed |
77 |
|
|
/* |
78 |
|
|
you cannot do things this way... |
79 |
|
|
sufficient fast pings must be given the chance to fail |
80 |
|
|
within the allowed mount time |
81 |
|
|
*/ |
82 |
|
|
#endif /* (FAST_NFS_PING * MAX_ALLOWED_PINGS) >= ALLOWED_MOUNT_TIME */ |
83 |
|
|
|
84 |
|
|
static int ping_len; |
85 |
|
|
static char ping_buf[sizeof(struct rpc_msg) + 32]; |
86 |
|
|
|
87 |
|
|
/* |
88 |
|
|
* Flush any cached data |
89 |
|
|
*/ |
90 |
|
|
void |
91 |
|
|
flush_srvr_nfs_cache(void) |
92 |
|
|
{ |
93 |
|
|
fserver *fs = 0; |
94 |
|
|
|
95 |
|
|
ITER(fs, fserver, &nfs_srvr_list) { |
96 |
|
|
nfs_private *np = (nfs_private *) fs->fs_private; |
97 |
|
|
if (np) { |
98 |
|
|
np->np_mountd_inval = TRUE; |
99 |
|
|
np->np_error = -1; |
100 |
|
|
} |
101 |
|
|
} |
102 |
|
|
} |
103 |
|
|
|
104 |
|
|
/* |
105 |
|
|
* Startup the NFS ping |
106 |
|
|
*/ |
107 |
|
|
static void |
108 |
|
|
start_ping(void) |
109 |
|
|
{ |
110 |
|
|
XDR ping_xdr; |
111 |
|
|
struct rpc_msg ping_msg; |
112 |
|
|
|
113 |
|
|
rpc_msg_init(&ping_msg, NFS_PROGRAM, NFS_VERSION, NFSPROC_NULL); |
114 |
|
|
|
115 |
|
|
/* |
116 |
|
|
* Create an XDR endpoint |
117 |
|
|
*/ |
118 |
|
|
xdrmem_create(&ping_xdr, ping_buf, sizeof(ping_buf), XDR_ENCODE); |
119 |
|
|
|
120 |
|
|
/* |
121 |
|
|
* Create the NFS ping message |
122 |
|
|
*/ |
123 |
|
|
if (!xdr_callmsg(&ping_xdr, &ping_msg)) { |
124 |
|
|
plog(XLOG_ERROR, "Couldn't create ping RPC message"); |
125 |
|
|
going_down(3); |
126 |
|
|
} |
127 |
|
|
|
128 |
|
|
/* |
129 |
|
|
* Find out how long it is |
130 |
|
|
*/ |
131 |
|
|
ping_len = xdr_getpos(&ping_xdr); |
132 |
|
|
|
133 |
|
|
/* |
134 |
|
|
* Destroy the XDR endpoint - we don't need it anymore |
135 |
|
|
*/ |
136 |
|
|
xdr_destroy(&ping_xdr); |
137 |
|
|
} |
138 |
|
|
|
139 |
|
|
|
140 |
|
|
/* |
141 |
|
|
* Called when a portmap reply arrives |
142 |
|
|
*/ |
143 |
|
|
static void |
144 |
|
|
got_portmap(void *pkt, int len, struct sockaddr_in *sa, |
145 |
|
|
struct sockaddr_in *ia, void *idv, int done) |
146 |
|
|
{ |
147 |
|
|
fserver *fs2 = (fserver *) idv; |
148 |
|
|
fserver *fs = 0; |
149 |
|
|
|
150 |
|
|
/* |
151 |
|
|
* Find which fileserver we are talking about |
152 |
|
|
*/ |
153 |
|
|
ITER(fs, fserver, &nfs_srvr_list) |
154 |
|
|
if (fs == fs2) |
155 |
|
|
break; |
156 |
|
|
|
157 |
|
|
if (fs == fs2) { |
158 |
|
|
u_long port = 0; /* XXX - should be short but protocol is naff */ |
159 |
|
|
int error = done ? pickup_rpc_reply(pkt, len, &port, xdr_u_long) : -1; |
160 |
|
|
nfs_private *np = (nfs_private *) fs->fs_private; |
161 |
|
|
if (!error && port) { |
162 |
|
|
#ifdef DEBUG |
163 |
|
|
dlog("got port (%d) for mountd on %s", port, fs->fs_host); |
164 |
|
|
#endif /* DEBUG */ |
165 |
|
|
/* |
166 |
|
|
* Grab the port number. Portmap sends back |
167 |
|
|
* an unsigned long in native ordering, so it |
168 |
|
|
* needs converting to a unsigned short in |
169 |
|
|
* network ordering. |
170 |
|
|
*/ |
171 |
|
|
np->np_mountd = htons((u_short) port); |
172 |
|
|
np->np_mountd_inval = FALSE; |
173 |
|
|
np->np_error = 0; |
174 |
|
|
} else { |
175 |
|
|
#ifdef DEBUG |
176 |
|
|
dlog("Error fetching port for mountd on %s", fs->fs_host); |
177 |
|
|
#endif /* DEBUG */ |
178 |
|
|
/* |
179 |
|
|
* Almost certainly no mountd running on remote host |
180 |
|
|
*/ |
181 |
|
|
np->np_error = error ? error : ETIMEDOUT; |
182 |
|
|
} |
183 |
|
|
if (fs->fs_flags & FSF_WANT) |
184 |
|
|
wakeup_srvr(fs); |
185 |
|
|
} else if (done) { |
186 |
|
|
#ifdef DEBUG |
187 |
|
|
dlog("Got portmap for old port request"); |
188 |
|
|
#endif /* DEBUG */ |
189 |
|
|
} else { |
190 |
|
|
#ifdef DEBUG |
191 |
|
|
dlog("portmap request timed out"); |
192 |
|
|
#endif /* DEBUG */ |
193 |
|
|
} |
194 |
|
|
} |
195 |
|
|
|
196 |
|
|
/* |
197 |
|
|
* Obtain portmap information |
198 |
|
|
*/ |
199 |
|
|
static int |
200 |
|
|
call_portmap(fserver *fs, AUTH *auth, unsigned long prog, |
201 |
|
|
unsigned long vers, unsigned long prot) |
202 |
|
|
{ |
203 |
|
|
struct rpc_msg pmap_msg; |
204 |
|
|
int len; |
205 |
|
|
char iobuf[UDPMSGSIZE]; |
206 |
|
|
int error; |
207 |
|
|
struct pmap pmap; |
208 |
|
|
|
209 |
|
|
rpc_msg_init(&pmap_msg, PMAPPROG, PMAPVERS, (unsigned long) 0); |
210 |
|
|
pmap.pm_prog = prog; |
211 |
|
|
pmap.pm_vers = vers; |
212 |
|
|
pmap.pm_prot = prot; |
213 |
|
|
pmap.pm_port = 0; |
214 |
|
|
len = make_rpc_packet(iobuf, sizeof(iobuf), PMAPPROC_GETPORT, |
215 |
|
|
&pmap_msg, &pmap, xdr_pmap, auth); |
216 |
|
|
if (len > 0) { |
217 |
|
|
struct sockaddr_in sin; |
218 |
|
|
bzero(&sin, sizeof(sin)); |
219 |
|
|
sin = *fs->fs_ip; |
220 |
|
|
sin.sin_port = htons(PMAPPORT); |
221 |
|
|
error = fwd_packet(RPC_XID_PORTMAP, iobuf, len, |
222 |
|
|
&sin, &sin, fs, got_portmap); |
223 |
|
|
} else { |
224 |
|
|
error = -len; |
225 |
|
|
} |
226 |
|
|
return error; |
227 |
|
|
} |
228 |
|
|
|
229 |
|
|
static void nfs_keepalive(void *); |
230 |
|
|
|
231 |
|
|
static void |
232 |
|
|
recompute_portmap(fserver *fs) |
233 |
|
|
{ |
234 |
|
|
int error; |
235 |
|
|
|
236 |
|
|
if (nfs_auth) |
237 |
|
|
error = 0; |
238 |
|
|
else |
239 |
|
|
error = make_nfs_auth(); |
240 |
|
|
|
241 |
|
|
if (error) { |
242 |
|
|
nfs_private *np = (nfs_private *) fs->fs_private; |
243 |
|
|
np->np_error = error; |
244 |
|
|
} else { |
245 |
|
|
call_portmap(fs, nfs_auth, MOUNTPROG, |
246 |
|
|
MOUNTVERS, (unsigned long) IPPROTO_UDP); |
247 |
|
|
} |
248 |
|
|
} |
249 |
|
|
|
250 |
|
|
/* |
251 |
|
|
* This is called when we get a reply to an RPC ping. |
252 |
|
|
* The value of id was taken from the nfs_private |
253 |
|
|
* structure when the ping was transmitted. |
254 |
|
|
*/ |
255 |
|
|
static void |
256 |
|
|
nfs_pinged(void *pkt, int len, struct sockaddr_in *sp, |
257 |
|
|
struct sockaddr_in *tsp, void *idv, int done) |
258 |
|
|
{ |
259 |
|
|
/* XXX EVIL! XXX */ |
260 |
|
|
int xid = (int) ((long)idv); |
261 |
|
|
fserver *fs; |
262 |
|
|
#ifdef DEBUG |
263 |
|
|
int found_map = 0; |
264 |
|
|
#endif /* DEBUG */ |
265 |
|
|
|
266 |
|
|
if (!done) |
267 |
|
|
return; |
268 |
|
|
|
269 |
|
|
/* |
270 |
|
|
* For each node... |
271 |
|
|
*/ |
272 |
|
|
ITER(fs, fserver, &nfs_srvr_list) { |
273 |
|
|
nfs_private *np = (nfs_private *) fs->fs_private; |
274 |
|
|
if (np->np_xid == xid) { |
275 |
|
|
/* |
276 |
|
|
* Reset the ping counter. |
277 |
|
|
* Update the keepalive timer. |
278 |
|
|
* Log what happened. |
279 |
|
|
*/ |
280 |
|
|
if (fs->fs_flags & FSF_DOWN) { |
281 |
|
|
fs->fs_flags &= ~FSF_DOWN; |
282 |
|
|
if (fs->fs_flags & FSF_VALID) { |
283 |
|
|
srvrlog(fs, "is up"); |
284 |
|
|
} else { |
285 |
|
|
if (np->np_ping > 1) |
286 |
|
|
srvrlog(fs, "ok"); |
287 |
|
|
#ifdef DEBUG |
288 |
|
|
else |
289 |
|
|
srvrlog(fs, "starts up"); |
290 |
|
|
#endif |
291 |
|
|
fs->fs_flags |= FSF_VALID; |
292 |
|
|
} |
293 |
|
|
|
294 |
|
|
#ifdef notdef |
295 |
|
|
/* why ??? */ |
296 |
|
|
if (fs->fs_flags & FSF_WANT) |
297 |
|
|
wakeup_srvr(fs); |
298 |
|
|
#endif /* notdef */ |
299 |
|
|
map_flush_srvr(fs); |
300 |
|
|
} else { |
301 |
|
|
if (fs->fs_flags & FSF_VALID) { |
302 |
|
|
#ifdef DEBUG |
303 |
|
|
dlog("file server %s type nfs is still up", fs->fs_host); |
304 |
|
|
#endif /* DEBUG */ |
305 |
|
|
} else { |
306 |
|
|
if (np->np_ping > 1) |
307 |
|
|
srvrlog(fs, "ok"); |
308 |
|
|
fs->fs_flags |= FSF_VALID; |
309 |
|
|
} |
310 |
|
|
} |
311 |
|
|
|
312 |
|
|
/* |
313 |
|
|
* Adjust ping interval |
314 |
|
|
*/ |
315 |
|
|
untimeout(fs->fs_cid); |
316 |
|
|
fs->fs_cid = timeout(fs->fs_pinger, nfs_keepalive, fs); |
317 |
|
|
|
318 |
|
|
/* |
319 |
|
|
* Update ttl for this server |
320 |
|
|
*/ |
321 |
|
|
np->np_ttl = clocktime() + |
322 |
|
|
(MAX_ALLOWED_PINGS - 1) * FAST_NFS_PING + fs->fs_pinger - 1; |
323 |
|
|
|
324 |
|
|
/* |
325 |
|
|
* New RPC xid... |
326 |
|
|
*/ |
327 |
|
|
np->np_xid = NPXID_ALLOC(); |
328 |
|
|
|
329 |
|
|
/* |
330 |
|
|
* Failed pings is zero... |
331 |
|
|
*/ |
332 |
|
|
np->np_ping = 0; |
333 |
|
|
|
334 |
|
|
/* |
335 |
|
|
* Recompute portmap information if not known |
336 |
|
|
*/ |
337 |
|
|
if (np->np_mountd_inval) |
338 |
|
|
recompute_portmap(fs); |
339 |
|
|
|
340 |
|
|
#ifdef DEBUG |
341 |
|
|
found_map++; |
342 |
|
|
#endif /* DEBUG */ |
343 |
|
|
break; |
344 |
|
|
} |
345 |
|
|
} |
346 |
|
|
|
347 |
|
|
#ifdef DEBUG |
348 |
|
|
if (found_map == 0) |
349 |
|
|
dlog("Spurious ping packet"); |
350 |
|
|
#endif /* DEBUG */ |
351 |
|
|
} |
352 |
|
|
|
353 |
|
|
/* |
354 |
|
|
* Called when no ping-reply received |
355 |
|
|
*/ |
356 |
|
|
static void |
357 |
|
|
nfs_timed_out(void *arg) |
358 |
|
|
{ |
359 |
|
|
fserver *fs = arg; |
360 |
|
|
|
361 |
|
|
nfs_private *np = (nfs_private *) fs->fs_private; |
362 |
|
|
|
363 |
|
|
/* |
364 |
|
|
* Another ping has failed |
365 |
|
|
*/ |
366 |
|
|
np->np_ping++; |
367 |
|
|
|
368 |
|
|
/* |
369 |
|
|
* Not known to be up any longer |
370 |
|
|
*/ |
371 |
|
|
if (FSRV_ISUP(fs)) { |
372 |
|
|
fs->fs_flags &= ~FSF_VALID; |
373 |
|
|
if (np->np_ping > 1) |
374 |
|
|
srvrlog(fs, "not responding"); |
375 |
|
|
} |
376 |
|
|
|
377 |
|
|
/* |
378 |
|
|
* If ttl has expired then guess that it is dead |
379 |
|
|
*/ |
380 |
|
|
if (np->np_ttl < clocktime()) { |
381 |
|
|
int oflags = fs->fs_flags; |
382 |
|
|
if ((fs->fs_flags & FSF_DOWN) == 0) { |
383 |
|
|
/* |
384 |
|
|
* Server was up, but is now down. |
385 |
|
|
*/ |
386 |
|
|
srvrlog(fs, "is down"); |
387 |
|
|
fs->fs_flags |= FSF_DOWN|FSF_VALID; |
388 |
|
|
/* |
389 |
|
|
* Since the server is down, the portmap |
390 |
|
|
* information may now be wrong, so it |
391 |
|
|
* must be flushed from the local cache |
392 |
|
|
*/ |
393 |
|
|
flush_nfs_fhandle_cache(fs); |
394 |
|
|
np->np_error = -1; |
395 |
|
|
#ifdef notdef |
396 |
|
|
/* |
397 |
|
|
* Pretend just one ping has failed now |
398 |
|
|
*/ |
399 |
|
|
np->np_ping = 1; |
400 |
|
|
#endif |
401 |
|
|
} else { |
402 |
|
|
/* |
403 |
|
|
* Known to be down |
404 |
|
|
*/ |
405 |
|
|
#ifdef DEBUG |
406 |
|
|
if ((fs->fs_flags & FSF_VALID) == 0) |
407 |
|
|
srvrlog(fs, "starts down"); |
408 |
|
|
#endif |
409 |
|
|
fs->fs_flags |= FSF_VALID; |
410 |
|
|
} |
411 |
|
|
if (oflags != fs->fs_flags && (fs->fs_flags & FSF_WANT)) |
412 |
|
|
wakeup_srvr(fs); |
413 |
|
|
} else { |
414 |
|
|
#ifdef DEBUG |
415 |
|
|
if (np->np_ping > 1) |
416 |
|
|
dlog("%d pings to %s failed - at most %d allowed", np->np_ping, fs->fs_host, MAX_ALLOWED_PINGS); |
417 |
|
|
#endif /* DEBUG */ |
418 |
|
|
} |
419 |
|
|
|
420 |
|
|
/* |
421 |
|
|
* Run keepalive again |
422 |
|
|
*/ |
423 |
|
|
nfs_keepalive(fs); |
424 |
|
|
} |
425 |
|
|
|
426 |
|
|
/* |
427 |
|
|
* Keep track of whether a server is alive |
428 |
|
|
*/ |
429 |
|
|
static void |
430 |
|
|
nfs_keepalive(void *arg) |
431 |
|
|
{ |
432 |
|
|
fserver *fs = arg; |
433 |
|
|
|
434 |
|
|
int error; |
435 |
|
|
nfs_private *np = (nfs_private *) fs->fs_private; |
436 |
|
|
int fstimeo = -1; |
437 |
|
|
|
438 |
|
|
/* |
439 |
|
|
* Send an NFS ping to this node |
440 |
|
|
*/ |
441 |
|
|
|
442 |
|
|
if (ping_len == 0) |
443 |
|
|
start_ping(); |
444 |
|
|
|
445 |
|
|
/* |
446 |
|
|
* Queue the packet... |
447 |
|
|
*/ |
448 |
|
|
/* |
449 |
|
|
* XXX EVIL! We cast xid to a pointer, then back to an int when |
450 |
|
|
* XXX we get the reply. |
451 |
|
|
*/ |
452 |
|
|
error = fwd_packet(MK_RPC_XID(RPC_XID_NFSPING, np->np_xid), ping_buf, |
453 |
|
|
ping_len, fs->fs_ip, NULL, (void *)((long)np->np_xid), |
454 |
|
|
nfs_pinged); |
455 |
|
|
|
456 |
|
|
/* |
457 |
|
|
* See if a hard error occured |
458 |
|
|
*/ |
459 |
|
|
switch (error) { |
460 |
|
|
case ENETDOWN: |
461 |
|
|
case ENETUNREACH: |
462 |
|
|
case EHOSTDOWN: |
463 |
|
|
case EHOSTUNREACH: |
464 |
|
|
np->np_ping = MAX_ALLOWED_PINGS; /* immediately down */ |
465 |
|
|
np->np_ttl = (time_t) 0; |
466 |
|
|
/* |
467 |
|
|
* This causes an immediate call to nfs_timed_out |
468 |
|
|
* whenever the server was thought to be up. |
469 |
|
|
* See +++ below. |
470 |
|
|
*/ |
471 |
|
|
fstimeo = 0; |
472 |
|
|
break; |
473 |
|
|
|
474 |
|
|
case 0: |
475 |
|
|
#ifdef DEBUG |
476 |
|
|
dlog("Sent NFS ping to %s", fs->fs_host); |
477 |
|
|
#endif /* DEBUG */ |
478 |
|
|
break; |
479 |
|
|
} |
480 |
|
|
|
481 |
|
|
#ifdef DEBUG |
482 |
|
|
/*dlog("keepalive, ping = %d", np->np_ping);*/ |
483 |
|
|
#endif /* DEBUG */ |
484 |
|
|
|
485 |
|
|
/* |
486 |
|
|
* Back off the ping interval if we are not getting replies and |
487 |
|
|
* the remote system is know to be down. |
488 |
|
|
*/ |
489 |
|
|
switch (fs->fs_flags & (FSF_DOWN|FSF_VALID)) { |
490 |
|
|
case FSF_VALID: /* Up */ |
491 |
|
|
if (fstimeo < 0) /* +++ see above */ |
492 |
|
|
fstimeo = FAST_NFS_PING; |
493 |
|
|
break; |
494 |
|
|
|
495 |
|
|
case FSF_VALID|FSF_DOWN: /* Down */ |
496 |
|
|
fstimeo = fs->fs_pinger; |
497 |
|
|
break; |
498 |
|
|
|
499 |
|
|
default: /* Unknown */ |
500 |
|
|
fstimeo = FAST_NFS_PING; |
501 |
|
|
break; |
502 |
|
|
} |
503 |
|
|
|
504 |
|
|
#ifdef DEBUG |
505 |
|
|
dlog("NFS timeout in %d seconds", fstimeo); |
506 |
|
|
#endif /* DEBUG */ |
507 |
|
|
|
508 |
|
|
fs->fs_cid = timeout(fstimeo, nfs_timed_out, fs); |
509 |
|
|
} |
510 |
|
|
|
511 |
|
|
int |
512 |
|
|
nfs_srvr_port(fserver *fs, u_short *port, void *wchan) |
513 |
|
|
{ |
514 |
|
|
int error = -1; |
515 |
|
|
if ((fs->fs_flags & FSF_VALID) == FSF_VALID) { |
516 |
|
|
if ((fs->fs_flags & FSF_DOWN) == 0) { |
517 |
|
|
nfs_private *np = (nfs_private *) fs->fs_private; |
518 |
|
|
if (np->np_error == 0) { |
519 |
|
|
*port = np->np_mountd; |
520 |
|
|
error = 0; |
521 |
|
|
} else { |
522 |
|
|
error = np->np_error; |
523 |
|
|
} |
524 |
|
|
/* |
525 |
|
|
* Now go get the port mapping again in case it changed. |
526 |
|
|
* Note that it is used even if (np_mountd_inval) |
527 |
|
|
* is True. The flag is used simply as an |
528 |
|
|
* indication that the mountd may be invalid, not |
529 |
|
|
* that it is known to be invalid. |
530 |
|
|
*/ |
531 |
|
|
if (np->np_mountd_inval) |
532 |
|
|
recompute_portmap(fs); |
533 |
|
|
else |
534 |
|
|
np->np_mountd_inval = TRUE; |
535 |
|
|
} else { |
536 |
|
|
error = EWOULDBLOCK; |
537 |
|
|
} |
538 |
|
|
} |
539 |
|
|
if (error < 0 && wchan && !(fs->fs_flags & FSF_WANT)) { |
540 |
|
|
/* |
541 |
|
|
* If a wait channel is supplied, and no |
542 |
|
|
* error has yet occured, then arrange |
543 |
|
|
* that a wakeup is done on the wait channel, |
544 |
|
|
* whenever a wakeup is done on this fs node. |
545 |
|
|
* Wakeup's are done on the fs node whenever |
546 |
|
|
* it changes state - thus causing control to |
547 |
|
|
* come back here and new, better things to happen. |
548 |
|
|
*/ |
549 |
|
|
fs->fs_flags |= FSF_WANT; |
550 |
|
|
sched_task(wakeup_task, wchan, fs); |
551 |
|
|
} |
552 |
|
|
return error; |
553 |
|
|
} |
554 |
|
|
|
555 |
|
|
static void |
556 |
|
|
start_nfs_pings(fserver *fs, int pingval) |
557 |
|
|
{ |
558 |
|
|
if (!(fs->fs_flags & FSF_PINGING)) { |
559 |
|
|
fs->fs_flags |= FSF_PINGING; |
560 |
|
|
if (fs->fs_cid) |
561 |
|
|
untimeout(fs->fs_cid); |
562 |
|
|
if (pingval < 0) { |
563 |
|
|
srvrlog(fs, "wired up"); |
564 |
|
|
fs->fs_flags |= FSF_VALID; |
565 |
|
|
fs->fs_flags &= ~FSF_DOWN; |
566 |
|
|
} else { |
567 |
|
|
nfs_keepalive(fs); |
568 |
|
|
} |
569 |
|
|
} else { |
570 |
|
|
#ifdef DEBUG |
571 |
|
|
dlog("Already running pings to %s", fs->fs_host); |
572 |
|
|
#endif /* DEBUG */ |
573 |
|
|
} |
574 |
|
|
} |
575 |
|
|
|
576 |
|
|
/* |
577 |
|
|
* Find an nfs server for a host. |
578 |
|
|
*/ |
579 |
|
|
fserver * |
580 |
|
|
find_nfs_srvr(mntfs *mf) |
581 |
|
|
{ |
582 |
|
|
fserver *fs; |
583 |
|
|
struct hostent *hp = 0; |
584 |
|
|
char *host = mf->mf_fo->opt_rhost; |
585 |
|
|
struct sockaddr_in *ip; |
586 |
|
|
nfs_private *np; |
587 |
|
|
int pingval; |
588 |
|
|
|
589 |
|
|
/* |
590 |
|
|
* Get ping interval from mount options. |
591 |
|
|
* Current only used to decide whether pings |
592 |
|
|
* are required or not. < 0 = no pings. |
593 |
|
|
*/ |
594 |
|
|
{ struct mntent mnt; |
595 |
|
|
mnt.mnt_opts = mf->mf_mopts; |
596 |
|
|
pingval = hasmntval(&mnt, "ping"); |
597 |
|
|
/* |
598 |
|
|
* Over TCP mount, don't bother to do pings. |
599 |
|
|
* This is experimental - maybe you want to |
600 |
|
|
* do pings anyway... |
601 |
|
|
*/ |
602 |
|
|
if (pingval == 0 && hasmntopt(&mnt, "tcp")) |
603 |
|
|
pingval = -1; |
604 |
|
|
} |
605 |
|
|
|
606 |
|
|
|
607 |
|
|
/* |
608 |
|
|
* lookup host address and canonical name |
609 |
|
|
*/ |
610 |
|
|
hp = gethostbyname(host); |
611 |
|
|
|
612 |
|
|
/* |
613 |
|
|
* New code from Bob Harris <harris@basil-rathbone.mit.edu> |
614 |
|
|
* Use canonical name to keep track of file server |
615 |
|
|
* information. This way aliases do not generate |
616 |
|
|
* multiple NFS pingers. (Except when we're normalizing |
617 |
|
|
* hosts.) |
618 |
|
|
*/ |
619 |
|
|
if (hp && !normalize_hosts) host = hp->h_name; |
620 |
|
|
|
621 |
|
|
ITER(fs, fserver, &nfs_srvr_list) { |
622 |
|
|
if (STREQ(host, fs->fs_host)) { |
623 |
|
|
start_nfs_pings(fs, pingval); |
624 |
|
|
fs->fs_refc++; |
625 |
|
|
return fs; |
626 |
|
|
} |
627 |
|
|
} |
628 |
|
|
|
629 |
|
|
|
630 |
|
|
|
631 |
|
|
/* |
632 |
|
|
* Get here if we can't find an entry |
633 |
|
|
*/ |
634 |
|
|
if (hp) { |
635 |
|
|
switch (hp->h_addrtype) { |
636 |
|
|
case AF_INET: |
637 |
|
|
ip = ALLOC(sockaddr_in); |
638 |
|
|
bzero(ip, sizeof(*ip)); |
639 |
|
|
ip->sin_family = AF_INET; |
640 |
|
|
bcopy(hp->h_addr, &ip->sin_addr, sizeof(ip->sin_addr)); |
641 |
|
|
|
642 |
|
|
ip->sin_port = htons(NFS_PORT); |
643 |
|
|
break; |
644 |
|
|
|
645 |
|
|
default: |
646 |
|
|
ip = 0; |
647 |
|
|
break; |
648 |
|
|
} |
649 |
|
|
} else { |
650 |
|
|
plog(XLOG_USER, "Unknown host: %s", host); |
651 |
|
|
ip = 0; |
652 |
|
|
} |
653 |
|
|
|
654 |
|
|
/* |
655 |
|
|
* Allocate a new server |
656 |
|
|
*/ |
657 |
|
|
fs = ALLOC(fserver); |
658 |
|
|
fs->fs_refc = 1; |
659 |
|
|
fs->fs_host = strdup(hp ? hp->h_name : "unknown_hostname"); |
660 |
|
|
if (normalize_hosts) host_normalize(&fs->fs_host); |
661 |
|
|
fs->fs_ip = ip; |
662 |
|
|
fs->fs_cid = 0; |
663 |
|
|
if (ip) { |
664 |
|
|
fs->fs_flags = FSF_DOWN; /* Starts off down */ |
665 |
|
|
} else { |
666 |
|
|
fs->fs_flags = FSF_ERROR|FSF_VALID; |
667 |
|
|
mf->mf_flags |= MFF_ERROR; |
668 |
|
|
mf->mf_error = ENOENT; |
669 |
|
|
} |
670 |
|
|
fs->fs_type = "nfs"; |
671 |
|
|
fs->fs_pinger = AM_PINGER; |
672 |
|
|
np = ALLOC(nfs_private); |
673 |
|
|
bzero(np, sizeof(*np)); |
674 |
|
|
np->np_mountd_inval = TRUE; |
675 |
|
|
np->np_xid = NPXID_ALLOC(); |
676 |
|
|
np->np_error = -1; |
677 |
|
|
/* |
678 |
|
|
* Initially the server will be deemed dead after |
679 |
|
|
* MAX_ALLOWED_PINGS of the fast variety have failed. |
680 |
|
|
*/ |
681 |
|
|
np->np_ttl = clocktime() + MAX_ALLOWED_PINGS * FAST_NFS_PING - 1; |
682 |
|
|
fs->fs_private = np; |
683 |
|
|
fs->fs_prfree = free; |
684 |
|
|
|
685 |
|
|
if (!(fs->fs_flags & FSF_ERROR)) { |
686 |
|
|
/* |
687 |
|
|
* Start of keepalive timer |
688 |
|
|
*/ |
689 |
|
|
start_nfs_pings(fs, pingval); |
690 |
|
|
} |
691 |
|
|
|
692 |
|
|
/* |
693 |
|
|
* Add to list of servers |
694 |
|
|
*/ |
695 |
|
|
ins_que(&fs->fs_q, &nfs_srvr_list); |
696 |
|
|
|
697 |
|
|
return fs; |
698 |
|
|
} |