1 1.1 christos /* $NetBSD: srvr_nfs.c,v 1.1.1.3 2015/01/17 16:34:15 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.1.1.3 christos * Copyright (c) 1997-2014 Erez Zadok 5 1.1 christos * Copyright (c) 1990 Jan-Simon Pendry 6 1.1 christos * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 7 1.1 christos * Copyright (c) 1990 The Regents of the University of California. 8 1.1 christos * All rights reserved. 9 1.1 christos * 10 1.1 christos * This code is derived from software contributed to Berkeley by 11 1.1 christos * Jan-Simon Pendry at Imperial College, London. 12 1.1 christos * 13 1.1 christos * Redistribution and use in source and binary forms, with or without 14 1.1 christos * modification, are permitted provided that the following conditions 15 1.1 christos * are met: 16 1.1 christos * 1. Redistributions of source code must retain the above copyright 17 1.1 christos * notice, this list of conditions and the following disclaimer. 18 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright 19 1.1 christos * notice, this list of conditions and the following disclaimer in the 20 1.1 christos * documentation and/or other materials provided with the distribution. 21 1.1.1.3 christos * 3. Neither the name of the University nor the names of its contributors 22 1.1 christos * may be used to endorse or promote products derived from this software 23 1.1 christos * without specific prior written permission. 24 1.1 christos * 25 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 1.1 christos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 1.1 christos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 1.1 christos * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 1.1 christos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 1.1 christos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 1.1 christos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 1.1 christos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 1.1 christos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 1.1 christos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 1.1 christos * SUCH DAMAGE. 36 1.1 christos * 37 1.1 christos * 38 1.1 christos * File: am-utils/amd/srvr_nfs.c 39 1.1 christos * 40 1.1 christos */ 41 1.1 christos 42 1.1 christos /* 43 1.1 christos * NFS server modeling 44 1.1 christos */ 45 1.1 christos 46 1.1 christos #ifdef HAVE_CONFIG_H 47 1.1 christos # include <config.h> 48 1.1 christos #endif /* HAVE_CONFIG_H */ 49 1.1 christos #include <am_defs.h> 50 1.1 christos #include <amd.h> 51 1.1 christos 52 1.1 christos /* 53 1.1 christos * Number of pings allowed to fail before host is declared down 54 1.1 christos * - three-fifths of the allowed mount time... 55 1.1 christos */ 56 1.1 christos #define MAX_ALLOWED_PINGS (3 + /* for luck ... */ 1) 57 1.1 christos 58 1.1 christos /* 59 1.1 christos * How often to ping when starting a new server 60 1.1 christos */ 61 1.1 christos #define FAST_NFS_PING 3 62 1.1 christos 63 1.1 christos #if (FAST_NFS_PING * MAX_ALLOWED_PINGS) >= ALLOWED_MOUNT_TIME 64 1.1 christos # error: sanity check failed in srvr_nfs.c 65 1.1 christos /* 66 1.1 christos * you cannot do things this way... 67 1.1 christos * sufficient fast pings must be given the chance to fail 68 1.1 christos * within the allowed mount time 69 1.1 christos */ 70 1.1 christos #endif /* (FAST_NFS_PING * MAX_ALLOWED_PINGS) >= ALLOWED_MOUNT_TIME */ 71 1.1 christos 72 1.1 christos /* structures and typedefs */ 73 1.1 christos typedef struct nfs_private { 74 1.1 christos u_short np_mountd; /* Mount daemon port number */ 75 1.1 christos char np_mountd_inval; /* Port *may* be invalid */ 76 1.1.1.3 christos /* 'Y' invalid, 'N' valid, 'P' permanent */ 77 1.1 christos int np_ping; /* Number of failed ping attempts */ 78 1.1 christos time_t np_ttl; /* Time when server is thought dead */ 79 1.1 christos int np_xid; /* RPC transaction id for pings */ 80 1.1 christos int np_error; /* Error during portmap request */ 81 1.1 christos } nfs_private; 82 1.1 christos 83 1.1 christos /* globals */ 84 1.1 christos qelem nfs_srvr_list = {&nfs_srvr_list, &nfs_srvr_list}; 85 1.1 christos 86 1.1 christos /* statics */ 87 1.1 christos static int global_xid; /* For NFS pings */ 88 1.1 christos #define XID_ALLOC() (++global_xid) 89 1.1 christos 90 1.1.1.3 christos #if defined(HAVE_FS_NFS4) 91 1.1.1.3 christos # define NUM_NFS_VERS 3 92 1.1.1.3 christos #elif defined(HAVE_FS_NFS3) 93 1.1 christos # define NUM_NFS_VERS 2 94 1.1 christos #else /* not HAVE_FS_NFS3 */ 95 1.1 christos # define NUM_NFS_VERS 1 96 1.1 christos #endif /* not HAVE_FS_NFS3 */ 97 1.1 christos static int ping_len[NUM_NFS_VERS]; 98 1.1 christos static char ping_buf[NUM_NFS_VERS][sizeof(struct rpc_msg) + 32]; 99 1.1 christos 100 1.1 christos #if defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3) 101 1.1 christos /* 102 1.1 christos * Protocols we know about, in order of preference. 103 1.1 christos * 104 1.1 christos * Note that Solaris 8 and newer NetBSD systems are switching to UDP first, 105 1.1 christos * so this order may have to be adjusted for Amd in the future once more 106 1.1 christos * vendors make that change. -Erez 11/24/2000 107 1.1 christos * 108 1.1 christos * Or we might simply make this is a platform-specific order. -Ion 09/13/2003 109 1.1 christos */ 110 1.1 christos static char *protocols[] = { "tcp", "udp", NULL }; 111 1.1 christos #endif /* defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3) */ 112 1.1 christos 113 1.1 christos /* forward definitions */ 114 1.1 christos static void nfs_keepalive(voidp); 115 1.1 christos 116 1.1 christos 117 1.1 christos /* 118 1.1 christos * Flush cached data for an fserver (or for all, if fs==NULL) 119 1.1 christos */ 120 1.1 christos void 121 1.1 christos flush_srvr_nfs_cache(fserver *fs) 122 1.1 christos { 123 1.1 christos fserver *fs2 = NULL; 124 1.1 christos 125 1.1 christos ITER(fs2, fserver, &nfs_srvr_list) { 126 1.1 christos if (fs == NULL || fs == fs2) { 127 1.1 christos nfs_private *np = (nfs_private *) fs2->fs_private; 128 1.1.1.3 christos if (np && np->np_mountd_inval != 'P') { 129 1.1.1.3 christos np->np_mountd_inval = 'Y'; 130 1.1 christos np->np_error = -1; 131 1.1 christos } 132 1.1 christos } 133 1.1 christos } 134 1.1 christos } 135 1.1 christos 136 1.1 christos 137 1.1 christos /* 138 1.1 christos * Startup the NFS ping for a particular version. 139 1.1 christos */ 140 1.1 christos static void 141 1.1 christos create_ping_payload(u_long nfs_version) 142 1.1 christos { 143 1.1 christos XDR ping_xdr; 144 1.1 christos struct rpc_msg ping_msg; 145 1.1 christos 146 1.1 christos /* 147 1.1 christos * Non nfs mounts like /afs/glue.umd.edu have ended up here. 148 1.1 christos */ 149 1.1 christos if (nfs_version == 0) { 150 1.1 christos nfs_version = NFS_VERSION; 151 1.1.1.3 christos plog(XLOG_WARNING, "%s: nfs_version = 0, changed to 2", __func__); 152 1.1 christos } else 153 1.1.1.3 christos plog(XLOG_INFO, "%s: nfs_version: %d", __func__, (int) nfs_version); 154 1.1 christos 155 1.1 christos rpc_msg_init(&ping_msg, NFS_PROGRAM, nfs_version, NFSPROC_NULL); 156 1.1 christos 157 1.1 christos /* 158 1.1 christos * Create an XDR endpoint 159 1.1 christos */ 160 1.1 christos xdrmem_create(&ping_xdr, ping_buf[nfs_version - NFS_VERSION], sizeof(ping_buf[0]), XDR_ENCODE); 161 1.1 christos 162 1.1 christos /* 163 1.1 christos * Create the NFS ping message 164 1.1 christos */ 165 1.1 christos if (!xdr_callmsg(&ping_xdr, &ping_msg)) { 166 1.1 christos plog(XLOG_ERROR, "Couldn't create ping RPC message"); 167 1.1 christos going_down(3); 168 1.1.1.3 christos return; 169 1.1 christos } 170 1.1 christos /* 171 1.1 christos * Find out how long it is 172 1.1 christos */ 173 1.1 christos ping_len[nfs_version - NFS_VERSION] = xdr_getpos(&ping_xdr); 174 1.1 christos 175 1.1 christos /* 176 1.1 christos * Destroy the XDR endpoint - we don't need it anymore 177 1.1 christos */ 178 1.1 christos xdr_destroy(&ping_xdr); 179 1.1 christos } 180 1.1 christos 181 1.1 christos 182 1.1 christos /* 183 1.1 christos * Called when a portmap reply arrives 184 1.1 christos */ 185 1.1 christos static void 186 1.1 christos got_portmap(voidp pkt, int len, struct sockaddr_in *sa, struct sockaddr_in *ia, voidp idv, int done) 187 1.1 christos { 188 1.1 christos fserver *fs2 = (fserver *) idv; 189 1.1 christos fserver *fs = NULL; 190 1.1 christos 191 1.1 christos /* 192 1.1 christos * Find which fileserver we are talking about 193 1.1 christos */ 194 1.1 christos ITER(fs, fserver, &nfs_srvr_list) 195 1.1 christos if (fs == fs2) 196 1.1 christos break; 197 1.1 christos 198 1.1 christos if (fs == fs2) { 199 1.1 christos u_long port = 0; /* XXX - should be short but protocol is naff */ 200 1.1 christos int error = done ? pickup_rpc_reply(pkt, len, (voidp) &port, (XDRPROC_T_TYPE) xdr_u_long) : -1; 201 1.1 christos nfs_private *np = (nfs_private *) fs->fs_private; 202 1.1 christos 203 1.1 christos if (!error && port) { 204 1.1 christos dlog("got port (%d) for mountd on %s", (int) port, fs->fs_host); 205 1.1 christos /* 206 1.1 christos * Grab the port number. Portmap sends back 207 1.1 christos * an u_long in native ordering, so it 208 1.1 christos * needs converting to a u_short in 209 1.1 christos * network ordering. 210 1.1 christos */ 211 1.1 christos np->np_mountd = htons((u_short) port); 212 1.1.1.3 christos np->np_mountd_inval = 'N'; 213 1.1 christos np->np_error = 0; 214 1.1 christos } else { 215 1.1 christos dlog("Error fetching port for mountd on %s", fs->fs_host); 216 1.1 christos dlog("\t error=%d, port=%d", error, (int) port); 217 1.1 christos /* 218 1.1 christos * Almost certainly no mountd running on remote host 219 1.1 christos */ 220 1.1 christos np->np_error = error ? error : ETIMEDOUT; 221 1.1 christos } 222 1.1 christos 223 1.1 christos if (fs->fs_flags & FSF_WANT) 224 1.1 christos wakeup_srvr(fs); 225 1.1 christos } else if (done) { 226 1.1 christos dlog("Got portmap for old port request"); 227 1.1 christos } else { 228 1.1 christos dlog("portmap request timed out"); 229 1.1 christos } 230 1.1 christos } 231 1.1 christos 232 1.1 christos 233 1.1 christos /* 234 1.1 christos * Obtain portmap information 235 1.1 christos */ 236 1.1 christos static int 237 1.1 christos call_portmap(fserver *fs, AUTH *auth, u_long prog, u_long vers, u_long prot) 238 1.1 christos { 239 1.1 christos struct rpc_msg pmap_msg; 240 1.1 christos int len; 241 1.1 christos char iobuf[UDPMSGSIZE]; 242 1.1 christos int error; 243 1.1 christos struct pmap pmap; 244 1.1 christos 245 1.1 christos rpc_msg_init(&pmap_msg, PMAPPROG, PMAPVERS, PMAPPROC_NULL); 246 1.1 christos pmap.pm_prog = prog; 247 1.1 christos pmap.pm_vers = vers; 248 1.1 christos pmap.pm_prot = prot; 249 1.1 christos pmap.pm_port = 0; 250 1.1 christos len = make_rpc_packet(iobuf, 251 1.1 christos sizeof(iobuf), 252 1.1 christos PMAPPROC_GETPORT, 253 1.1 christos &pmap_msg, 254 1.1 christos (voidp) &pmap, 255 1.1 christos (XDRPROC_T_TYPE) xdr_pmap, 256 1.1 christos auth); 257 1.1 christos if (len > 0) { 258 1.1 christos struct sockaddr_in sin; 259 1.1 christos memset((voidp) &sin, 0, sizeof(sin)); 260 1.1 christos sin = *fs->fs_ip; 261 1.1 christos sin.sin_port = htons(PMAPPORT); 262 1.1 christos error = fwd_packet(RPC_XID_PORTMAP, iobuf, len, 263 1.1 christos &sin, &sin, (voidp) fs, got_portmap); 264 1.1 christos } else { 265 1.1 christos error = -len; 266 1.1 christos } 267 1.1 christos 268 1.1 christos return error; 269 1.1 christos } 270 1.1 christos 271 1.1 christos 272 1.1 christos static void 273 1.1 christos recompute_portmap(fserver *fs) 274 1.1 christos { 275 1.1 christos int error; 276 1.1 christos u_long mnt_version; 277 1.1 christos 278 1.1 christos /* 279 1.1 christos * No portmap calls for pure WebNFS servers. 280 1.1 christos */ 281 1.1 christos if (fs->fs_flags & FSF_WEBNFS) 282 1.1 christos return; 283 1.1 christos 284 1.1 christos if (nfs_auth) 285 1.1 christos error = 0; 286 1.1 christos else 287 1.1 christos error = make_nfs_auth(); 288 1.1 christos 289 1.1 christos if (error) { 290 1.1 christos nfs_private *np = (nfs_private *) fs->fs_private; 291 1.1 christos np->np_error = error; 292 1.1 christos return; 293 1.1 christos } 294 1.1 christos 295 1.1 christos if (fs->fs_version == 0) 296 1.1.1.3 christos plog(XLOG_WARNING, "%s: nfs_version = 0 fixed", __func__); 297 1.1 christos 298 1.1.1.3 christos plog(XLOG_INFO, "%s: NFS version %d on %s", __func__, 299 1.1 christos (int) fs->fs_version, fs->fs_host); 300 1.1 christos #ifdef HAVE_FS_NFS3 301 1.1 christos if (fs->fs_version == NFS_VERSION3) 302 1.1 christos mnt_version = AM_MOUNTVERS3; 303 1.1 christos else 304 1.1 christos #endif /* HAVE_FS_NFS3 */ 305 1.1 christos mnt_version = MOUNTVERS; 306 1.1 christos 307 1.1 christos plog(XLOG_INFO, "Using MOUNT version: %d", (int) mnt_version); 308 1.1 christos call_portmap(fs, nfs_auth, MOUNTPROG, mnt_version, (u_long) IPPROTO_UDP); 309 1.1 christos } 310 1.1 christos 311 1.1 christos 312 1.1 christos int 313 1.1 christos get_mountd_port(fserver *fs, u_short *port, wchan_t wchan) 314 1.1 christos { 315 1.1 christos int error = -1; 316 1.1.1.3 christos 317 1.1 christos if (FSRV_ISDOWN(fs)) 318 1.1 christos return EWOULDBLOCK; 319 1.1 christos 320 1.1 christos if (FSRV_ISUP(fs)) { 321 1.1 christos nfs_private *np = (nfs_private *) fs->fs_private; 322 1.1 christos if (np->np_error == 0) { 323 1.1 christos *port = np->np_mountd; 324 1.1 christos error = 0; 325 1.1 christos } else { 326 1.1 christos error = np->np_error; 327 1.1 christos } 328 1.1 christos /* 329 1.1 christos * Now go get the port mapping again in case it changed. 330 1.1 christos * Note that it is used even if (np_mountd_inval) 331 1.1 christos * is True. The flag is used simply as an 332 1.1 christos * indication that the mountd may be invalid, not 333 1.1 christos * that it is known to be invalid. 334 1.1 christos */ 335 1.1.1.3 christos switch (np->np_mountd_inval) { 336 1.1.1.3 christos case 'Y': 337 1.1 christos recompute_portmap(fs); 338 1.1.1.3 christos break; 339 1.1.1.3 christos case 'N': 340 1.1.1.3 christos np->np_mountd_inval = 'Y'; 341 1.1.1.3 christos break; 342 1.1.1.3 christos case 'P': 343 1.1.1.3 christos break; 344 1.1.1.3 christos default: 345 1.1.1.3 christos abort(); 346 1.1.1.3 christos } 347 1.1 christos } 348 1.1 christos if (error < 0 && wchan && !(fs->fs_flags & FSF_WANT)) { 349 1.1 christos /* 350 1.1 christos * If a wait channel is supplied, and no 351 1.1 christos * error has yet occurred, then arrange 352 1.1 christos * that a wakeup is done on the wait channel, 353 1.1 christos * whenever a wakeup is done on this fs node. 354 1.1 christos * Wakeup's are done on the fs node whenever 355 1.1 christos * it changes state - thus causing control to 356 1.1 christos * come back here and new, better things to happen. 357 1.1 christos */ 358 1.1 christos fs->fs_flags |= FSF_WANT; 359 1.1 christos sched_task(wakeup_task, wchan, (wchan_t) fs); 360 1.1 christos } 361 1.1 christos return error; 362 1.1 christos } 363 1.1 christos 364 1.1 christos 365 1.1 christos /* 366 1.1 christos * This is called when we get a reply to an RPC ping. 367 1.1 christos * The value of id was taken from the nfs_private 368 1.1 christos * structure when the ping was transmitted. 369 1.1 christos */ 370 1.1 christos static void 371 1.1 christos nfs_keepalive_callback(voidp pkt, int len, struct sockaddr_in *sp, struct sockaddr_in *tsp, voidp idv, int done) 372 1.1 christos { 373 1.1 christos int xid = (long) idv; /* cast needed for 64-bit archs */ 374 1.1 christos fserver *fs; 375 1.1 christos int found_map = 0; 376 1.1 christos 377 1.1 christos if (!done) 378 1.1 christos return; 379 1.1 christos 380 1.1 christos /* 381 1.1 christos * For each node... 382 1.1 christos */ 383 1.1 christos ITER(fs, fserver, &nfs_srvr_list) { 384 1.1 christos nfs_private *np = (nfs_private *) fs->fs_private; 385 1.1 christos if (np->np_xid == xid && (fs->fs_flags & FSF_PINGING)) { 386 1.1 christos /* 387 1.1 christos * Reset the ping counter. 388 1.1 christos * Update the keepalive timer. 389 1.1 christos * Log what happened. 390 1.1 christos */ 391 1.1 christos if (fs->fs_flags & FSF_DOWN) { 392 1.1 christos fs->fs_flags &= ~FSF_DOWN; 393 1.1 christos if (fs->fs_flags & FSF_VALID) { 394 1.1 christos srvrlog(fs, "is up"); 395 1.1 christos } else { 396 1.1 christos if (np->np_ping > 1) 397 1.1 christos srvrlog(fs, "ok"); 398 1.1 christos else 399 1.1 christos srvrlog(fs, "starts up"); 400 1.1 christos fs->fs_flags |= FSF_VALID; 401 1.1 christos } 402 1.1 christos 403 1.1 christos map_flush_srvr(fs); 404 1.1 christos } else { 405 1.1 christos if (fs->fs_flags & FSF_VALID) { 406 1.1 christos dlog("file server %s type nfs is still up", fs->fs_host); 407 1.1 christos } else { 408 1.1 christos if (np->np_ping > 1) 409 1.1 christos srvrlog(fs, "ok"); 410 1.1 christos fs->fs_flags |= FSF_VALID; 411 1.1 christos } 412 1.1 christos } 413 1.1 christos 414 1.1 christos /* 415 1.1 christos * Adjust ping interval 416 1.1 christos */ 417 1.1 christos untimeout(fs->fs_cid); 418 1.1 christos fs->fs_cid = timeout(fs->fs_pinger, nfs_keepalive, (voidp) fs); 419 1.1 christos 420 1.1 christos /* 421 1.1 christos * Update ttl for this server 422 1.1 christos */ 423 1.1 christos np->np_ttl = clocktime(NULL) + 424 1.1 christos (MAX_ALLOWED_PINGS - 1) * FAST_NFS_PING + fs->fs_pinger - 1; 425 1.1 christos 426 1.1 christos /* 427 1.1 christos * New RPC xid... 428 1.1 christos */ 429 1.1 christos np->np_xid = XID_ALLOC(); 430 1.1 christos 431 1.1 christos /* 432 1.1 christos * Failed pings is zero... 433 1.1 christos */ 434 1.1 christos np->np_ping = 0; 435 1.1 christos 436 1.1 christos /* 437 1.1 christos * Recompute portmap information if not known 438 1.1 christos */ 439 1.1.1.3 christos if (np->np_mountd_inval == 'Y') 440 1.1 christos recompute_portmap(fs); 441 1.1 christos 442 1.1 christos found_map++; 443 1.1 christos break; 444 1.1 christos } 445 1.1 christos } 446 1.1 christos 447 1.1 christos if (found_map == 0) 448 1.1 christos dlog("Spurious ping packet"); 449 1.1 christos } 450 1.1 christos 451 1.1 christos 452 1.1 christos static void 453 1.1 christos check_fs_addr_change(fserver *fs) 454 1.1 christos { 455 1.1 christos struct hostent *hp = NULL; 456 1.1 christos struct in_addr ia; 457 1.1 christos char *old_ipaddr, *new_ipaddr; 458 1.1 christos 459 1.1 christos hp = gethostbyname(fs->fs_host); 460 1.1 christos if (!hp || 461 1.1 christos hp->h_addrtype != AF_INET || 462 1.1 christos !STREQ((char *) hp->h_name, fs->fs_host) || 463 1.1 christos memcmp((voidp) &fs->fs_ip->sin_addr, 464 1.1 christos (voidp) hp->h_addr, 465 1.1 christos sizeof(fs->fs_ip->sin_addr)) == 0) 466 1.1 christos return; 467 1.1 christos /* if got here: downed server changed IP address */ 468 1.1.1.3 christos old_ipaddr = xstrdup(inet_ntoa(fs->fs_ip->sin_addr)); 469 1.1 christos memmove((voidp) &ia, (voidp) hp->h_addr, sizeof(struct in_addr)); 470 1.1 christos new_ipaddr = inet_ntoa(ia); /* ntoa uses static buf */ 471 1.1 christos plog(XLOG_WARNING, "EZK: down fileserver %s changed ip: %s -> %s", 472 1.1 christos fs->fs_host, old_ipaddr, new_ipaddr); 473 1.1 christos XFREE(old_ipaddr); 474 1.1 christos /* copy new IP addr */ 475 1.1 christos memmove((voidp) &fs->fs_ip->sin_addr, 476 1.1 christos (voidp) hp->h_addr, 477 1.1 christos sizeof(fs->fs_ip->sin_addr)); 478 1.1 christos /* XXX: do we need to un/set these flags? */ 479 1.1 christos fs->fs_flags &= ~FSF_DOWN; 480 1.1 christos fs->fs_flags |= FSF_VALID | FSF_WANT; 481 1.1 christos map_flush_srvr(fs); /* XXX: a race with flush_srvr_nfs_cache? */ 482 1.1 christos flush_srvr_nfs_cache(fs); 483 1.1 christos fs->fs_flags |= FSF_FORCE_UNMOUNT; 484 1.1 christos 485 1.1 christos #if 0 486 1.1 christos flush_nfs_fhandle_cache(fs); /* done in caller: nfs_keepalive_timeout */ 487 1.1 christos /* XXX: need to purge nfs_private so that somehow it will get re-initialized? */ 488 1.1 christos #endif /* 0 */ 489 1.1 christos } 490 1.1 christos 491 1.1 christos 492 1.1 christos /* 493 1.1 christos * Called when no ping-reply received 494 1.1 christos */ 495 1.1 christos static void 496 1.1 christos nfs_keepalive_timeout(voidp v) 497 1.1 christos { 498 1.1 christos fserver *fs = v; 499 1.1 christos nfs_private *np = (nfs_private *) fs->fs_private; 500 1.1 christos 501 1.1 christos /* 502 1.1 christos * Another ping has failed 503 1.1 christos */ 504 1.1 christos np->np_ping++; 505 1.1 christos if (np->np_ping > 1) 506 1.1 christos srvrlog(fs, "not responding"); 507 1.1 christos 508 1.1 christos /* 509 1.1 christos * Not known to be up any longer 510 1.1 christos */ 511 1.1 christos if (FSRV_ISUP(fs)) 512 1.1 christos fs->fs_flags &= ~FSF_VALID; 513 1.1 christos 514 1.1 christos /* 515 1.1 christos * If ttl has expired then guess that it is dead 516 1.1 christos */ 517 1.1 christos if (np->np_ttl < clocktime(NULL)) { 518 1.1 christos int oflags = fs->fs_flags; 519 1.1 christos dlog("ttl has expired"); 520 1.1 christos if ((fs->fs_flags & FSF_DOWN) == 0) { 521 1.1 christos /* 522 1.1 christos * Server was up, but is now down. 523 1.1 christos */ 524 1.1 christos srvrlog(fs, "is down"); 525 1.1 christos fs->fs_flags |= FSF_DOWN | FSF_VALID; 526 1.1 christos /* 527 1.1 christos * Since the server is down, the portmap 528 1.1 christos * information may now be wrong, so it 529 1.1 christos * must be flushed from the local cache 530 1.1 christos */ 531 1.1 christos flush_nfs_fhandle_cache(fs); 532 1.1 christos np->np_error = -1; 533 1.1 christos check_fs_addr_change(fs); /* check if IP addr of fserver changed */ 534 1.1 christos } else { 535 1.1 christos /* 536 1.1 christos * Known to be down 537 1.1 christos */ 538 1.1 christos if ((fs->fs_flags & FSF_VALID) == 0) 539 1.1 christos srvrlog(fs, "starts down"); 540 1.1 christos fs->fs_flags |= FSF_VALID; 541 1.1 christos } 542 1.1 christos if (oflags != fs->fs_flags && (fs->fs_flags & FSF_WANT)) 543 1.1 christos wakeup_srvr(fs); 544 1.1 christos /* 545 1.1 christos * Reset failed ping count 546 1.1 christos */ 547 1.1 christos np->np_ping = 0; 548 1.1 christos } else { 549 1.1 christos if (np->np_ping > 1) 550 1.1 christos dlog("%d pings to %s failed - at most %d allowed", np->np_ping, fs->fs_host, MAX_ALLOWED_PINGS); 551 1.1 christos } 552 1.1 christos 553 1.1 christos /* 554 1.1 christos * New RPC xid, so any late responses to the previous ping 555 1.1 christos * get ignored... 556 1.1 christos */ 557 1.1 christos np->np_xid = XID_ALLOC(); 558 1.1 christos 559 1.1 christos /* 560 1.1 christos * Run keepalive again 561 1.1 christos */ 562 1.1 christos nfs_keepalive(fs); 563 1.1 christos } 564 1.1 christos 565 1.1 christos 566 1.1 christos /* 567 1.1 christos * Keep track of whether a server is alive 568 1.1 christos */ 569 1.1 christos static void 570 1.1 christos nfs_keepalive(voidp v) 571 1.1 christos { 572 1.1 christos fserver *fs = v; 573 1.1 christos int error; 574 1.1 christos nfs_private *np = (nfs_private *) fs->fs_private; 575 1.1 christos int fstimeo = -1; 576 1.1.1.3 christos int fs_version = nfs_valid_version(gopt.nfs_vers_ping) && 577 1.1.1.3 christos gopt.nfs_vers_ping < fs->fs_version ? gopt.nfs_vers_ping : fs->fs_version; 578 1.1 christos 579 1.1 christos /* 580 1.1 christos * Send an NFS ping to this node 581 1.1 christos */ 582 1.1 christos 583 1.1.1.3 christos if (ping_len[fs_version - NFS_VERSION] == 0) 584 1.1.1.3 christos create_ping_payload(fs_version); 585 1.1 christos 586 1.1 christos /* 587 1.1 christos * Queue the packet... 588 1.1 christos */ 589 1.1 christos error = fwd_packet(MK_RPC_XID(RPC_XID_NFSPING, np->np_xid), 590 1.1.1.3 christos ping_buf[fs_version - NFS_VERSION], 591 1.1.1.3 christos ping_len[fs_version - NFS_VERSION], 592 1.1 christos fs->fs_ip, 593 1.1 christos (struct sockaddr_in *) NULL, 594 1.1 christos (voidp) ((long) np->np_xid), /* cast needed for 64-bit archs */ 595 1.1 christos nfs_keepalive_callback); 596 1.1 christos 597 1.1 christos /* 598 1.1 christos * See if a hard error occurred 599 1.1 christos */ 600 1.1 christos switch (error) { 601 1.1 christos case ENETDOWN: 602 1.1 christos case ENETUNREACH: 603 1.1 christos case EHOSTDOWN: 604 1.1 christos case EHOSTUNREACH: 605 1.1 christos np->np_ping = MAX_ALLOWED_PINGS; /* immediately down */ 606 1.1 christos np->np_ttl = (time_t) 0; 607 1.1 christos /* 608 1.1 christos * This causes an immediate call to nfs_keepalive_timeout 609 1.1 christos * whenever the server was thought to be up. 610 1.1 christos * See +++ below. 611 1.1 christos */ 612 1.1 christos fstimeo = 0; 613 1.1 christos break; 614 1.1 christos 615 1.1 christos case 0: 616 1.1 christos dlog("Sent NFS ping to %s", fs->fs_host); 617 1.1 christos break; 618 1.1 christos } 619 1.1 christos 620 1.1 christos /* 621 1.1 christos * Back off the ping interval if we are not getting replies and 622 1.1 christos * the remote system is known to be down. 623 1.1 christos */ 624 1.1 christos switch (fs->fs_flags & (FSF_DOWN | FSF_VALID)) { 625 1.1 christos case FSF_VALID: /* Up */ 626 1.1 christos if (fstimeo < 0) /* +++ see above */ 627 1.1 christos fstimeo = FAST_NFS_PING; 628 1.1 christos break; 629 1.1 christos 630 1.1 christos case FSF_VALID | FSF_DOWN: /* Down */ 631 1.1 christos fstimeo = fs->fs_pinger; 632 1.1 christos break; 633 1.1 christos 634 1.1 christos default: /* Unknown */ 635 1.1 christos fstimeo = FAST_NFS_PING; 636 1.1 christos break; 637 1.1 christos } 638 1.1 christos 639 1.1 christos dlog("NFS timeout in %d seconds", fstimeo); 640 1.1 christos 641 1.1 christos fs->fs_cid = timeout(fstimeo, nfs_keepalive_timeout, (voidp) fs); 642 1.1 christos } 643 1.1 christos 644 1.1 christos 645 1.1 christos static void 646 1.1 christos start_nfs_pings(fserver *fs, int pingval) 647 1.1 christos { 648 1.1 christos if (pingval == 0) /* could be because ping mnt option not found */ 649 1.1 christos pingval = AM_PINGER; 650 1.1 christos /* if pings haven't been initalized, then init them for first time */ 651 1.1 christos if (fs->fs_flags & FSF_PING_UNINIT) { 652 1.1 christos fs->fs_flags &= ~FSF_PING_UNINIT; 653 1.1 christos plog(XLOG_INFO, "initializing %s's pinger to %d sec", fs->fs_host, pingval); 654 1.1 christos goto do_pings; 655 1.1 christos } 656 1.1 christos 657 1.1 christos if ((fs->fs_flags & FSF_PINGING) && fs->fs_pinger == pingval) { 658 1.1 christos dlog("already running pings to %s", fs->fs_host); 659 1.1 christos return; 660 1.1 christos } 661 1.1 christos 662 1.1 christos /* if got here, then we need to update the ping value */ 663 1.1 christos plog(XLOG_INFO, "changing %s's ping value from %d%s to %d%s", 664 1.1 christos fs->fs_host, 665 1.1 christos fs->fs_pinger, (fs->fs_pinger < 0 ? " (off)" : ""), 666 1.1 christos pingval, (pingval < 0 ? " (off)" : "")); 667 1.1 christos do_pings: 668 1.1 christos fs->fs_pinger = pingval; 669 1.1 christos 670 1.1 christos if (fs->fs_cid) 671 1.1 christos untimeout(fs->fs_cid); 672 1.1 christos if (pingval < 0) { 673 1.1 christos srvrlog(fs, "wired up (pings disabled)"); 674 1.1 christos fs->fs_flags |= FSF_VALID; 675 1.1 christos fs->fs_flags &= ~FSF_DOWN; 676 1.1 christos } else { 677 1.1 christos fs->fs_flags |= FSF_PINGING; 678 1.1 christos nfs_keepalive(fs); 679 1.1 christos } 680 1.1 christos } 681 1.1 christos 682 1.1 christos 683 1.1 christos /* 684 1.1 christos * Find an nfs server for a host. 685 1.1 christos */ 686 1.1 christos fserver * 687 1.1 christos find_nfs_srvr(mntfs *mf) 688 1.1 christos { 689 1.1.1.3 christos char *host; 690 1.1 christos fserver *fs; 691 1.1 christos int pingval; 692 1.1 christos mntent_t mnt; 693 1.1 christos nfs_private *np; 694 1.1 christos struct hostent *hp = NULL; 695 1.1 christos struct sockaddr_in *ip = NULL; 696 1.1 christos u_long nfs_version = 0; /* default is no version specified */ 697 1.1 christos u_long best_nfs_version = 0; 698 1.1 christos char *nfs_proto = NULL; /* no IP protocol either */ 699 1.1 christos int nfs_port = 0; 700 1.1 christos int nfs_port_opt = 0; 701 1.1 christos int fserver_is_down = 0; 702 1.1 christos 703 1.1.1.3 christos if (mf->mf_fo == NULL) { 704 1.1.1.3 christos plog(XLOG_ERROR, "%s: NULL mf_fo", __func__); 705 1.1.1.3 christos return NULL; 706 1.1.1.3 christos } 707 1.1.1.3 christos host = mf->mf_fo->opt_rhost; 708 1.1 christos /* 709 1.1 christos * Get ping interval from mount options. 710 1.1 christos * Current only used to decide whether pings 711 1.1 christos * are required or not. < 0 = no pings. 712 1.1 christos */ 713 1.1 christos mnt.mnt_opts = mf->mf_mopts; 714 1.1 christos pingval = hasmntval(&mnt, "ping"); 715 1.1 christos 716 1.1 christos if (mf->mf_flags & MFF_NFS_SCALEDOWN) { 717 1.1 christos /* 718 1.1 christos * the server granted us a filehandle, but we were unable to mount it. 719 1.1 christos * therefore, scale down to NFSv2/UDP and try again. 720 1.1 christos */ 721 1.1 christos nfs_version = NFS_VERSION; 722 1.1 christos nfs_proto = "udp"; 723 1.1.1.3 christos plog(XLOG_WARNING, "%s: NFS mount failed, trying again with NFSv2/UDP", 724 1.1.1.3 christos __func__); 725 1.1 christos mf->mf_flags &= ~MFF_NFS_SCALEDOWN; 726 1.1 christos } else { 727 1.1 christos /* 728 1.1 christos * Get the NFS version from the mount options. This is used 729 1.1 christos * to decide the highest NFS version to try. 730 1.1 christos */ 731 1.1 christos #ifdef MNTTAB_OPT_VERS 732 1.1 christos nfs_version = hasmntval(&mnt, MNTTAB_OPT_VERS); 733 1.1 christos #endif /* MNTTAB_OPT_VERS */ 734 1.1 christos 735 1.1 christos #ifdef MNTTAB_OPT_PROTO 736 1.1 christos { 737 1.1 christos char *proto_opt = hasmnteq(&mnt, MNTTAB_OPT_PROTO); 738 1.1 christos if (proto_opt) { 739 1.1 christos char **p; 740 1.1 christos for (p = protocols; *p; p++) 741 1.1 christos if (NSTREQ(proto_opt, *p, strlen(*p))) { 742 1.1 christos nfs_proto = *p; 743 1.1 christos break; 744 1.1 christos } 745 1.1 christos if (*p == NULL) 746 1.1 christos plog(XLOG_WARNING, "ignoring unknown protocol option for %s:%s", 747 1.1 christos host, mf->mf_fo->opt_rfs); 748 1.1 christos } 749 1.1 christos } 750 1.1 christos #endif /* MNTTAB_OPT_PROTO */ 751 1.1 christos 752 1.1 christos #ifdef HAVE_NFS_NFSV2_H 753 1.1 christos /* allow overriding if nfsv2 option is specified in mount options */ 754 1.1 christos if (amu_hasmntopt(&mnt, "nfsv2")) { 755 1.1 christos nfs_version = NFS_VERSION;/* nullify any ``vers=X'' statements */ 756 1.1 christos nfs_proto = "udp"; /* nullify any ``proto=tcp'' statements */ 757 1.1 christos plog(XLOG_WARNING, "found compatibility option \"nfsv2\": set options vers=2,proto=udp for host %s", host); 758 1.1 christos } 759 1.1 christos #endif /* HAVE_NFS_NFSV2_H */ 760 1.1 christos 761 1.1 christos /* check if we've globally overridden the NFS version/protocol */ 762 1.1 christos if (gopt.nfs_vers) { 763 1.1 christos nfs_version = gopt.nfs_vers; 764 1.1.1.3 christos plog(XLOG_INFO, "%s: force NFS version to %d", __func__, 765 1.1 christos (int) nfs_version); 766 1.1 christos } 767 1.1 christos if (gopt.nfs_proto) { 768 1.1 christos nfs_proto = gopt.nfs_proto; 769 1.1.1.3 christos plog(XLOG_INFO, "%s: force NFS protocol transport to %s", __func__, 770 1.1.1.3 christos nfs_proto); 771 1.1 christos } 772 1.1 christos } 773 1.1 christos 774 1.1 christos /* 775 1.1 christos * lookup host address and canonical name 776 1.1 christos */ 777 1.1 christos hp = gethostbyname(host); 778 1.1 christos 779 1.1 christos /* 780 1.1 christos * New code from Bob Harris <harris (at) basil-rathbone.mit.edu> 781 1.1 christos * Use canonical name to keep track of file server 782 1.1 christos * information. This way aliases do not generate 783 1.1 christos * multiple NFS pingers. (Except when we're normalizing 784 1.1 christos * hosts.) 785 1.1 christos */ 786 1.1 christos if (hp && !(gopt.flags & CFM_NORMALIZE_HOSTNAMES)) 787 1.1 christos host = (char *) hp->h_name; 788 1.1 christos 789 1.1 christos if (hp) { 790 1.1 christos switch (hp->h_addrtype) { 791 1.1 christos case AF_INET: 792 1.1.1.3 christos ip = CALLOC(struct sockaddr_in); 793 1.1 christos memset((voidp) ip, 0, sizeof(*ip)); 794 1.1 christos /* as per POSIX, sin_len need not be set (used internally by kernel) */ 795 1.1 christos ip->sin_family = AF_INET; 796 1.1 christos memmove((voidp) &ip->sin_addr, (voidp) hp->h_addr, sizeof(ip->sin_addr)); 797 1.1 christos break; 798 1.1 christos 799 1.1 christos default: 800 1.1 christos plog(XLOG_USER, "No IP address for host %s", host); 801 1.1 christos goto no_dns; 802 1.1 christos } 803 1.1 christos } else { 804 1.1 christos plog(XLOG_USER, "Unknown host: %s", host); 805 1.1 christos goto no_dns; 806 1.1 christos } 807 1.1 christos 808 1.1 christos /* 809 1.1 christos * This may not be the best way to do things, but it really doesn't make 810 1.1 christos * sense to query a file server which is marked as 'down' for any 811 1.1 christos * version/proto combination. 812 1.1 christos */ 813 1.1 christos ITER(fs, fserver, &nfs_srvr_list) { 814 1.1 christos if (FSRV_ISDOWN(fs) && 815 1.1 christos STREQ(host, fs->fs_host)) { 816 1.1 christos plog(XLOG_WARNING, "fileserver %s is already hung - not running NFS proto/version discovery", host); 817 1.1 christos fs->fs_refc++; 818 1.1.1.3 christos XFREE(ip); 819 1.1 christos return fs; 820 1.1 christos } 821 1.1 christos } 822 1.1 christos 823 1.1 christos /* 824 1.1 christos * Get the NFS Version, and verify server is up. 825 1.1 christos * If the client only supports NFSv2, hardcode it but still try to 826 1.1 christos * contact the remote portmapper to see if the service is running. 827 1.1 christos */ 828 1.1 christos #ifndef HAVE_FS_NFS3 829 1.1 christos nfs_version = NFS_VERSION; 830 1.1 christos nfs_proto = "udp"; 831 1.1 christos plog(XLOG_INFO, "The client supports only NFS(2,udp)"); 832 1.1 christos #endif /* not HAVE_FS_NFS3 */ 833 1.1 christos 834 1.1 christos 835 1.1 christos if (amu_hasmntopt(&mnt, MNTTAB_OPT_PUBLIC)) { 836 1.1 christos /* 837 1.1 christos * Use WebNFS to obtain file handles. 838 1.1 christos */ 839 1.1 christos mf->mf_flags |= MFF_WEBNFS; 840 1.1 christos plog(XLOG_INFO, "%s option used, NOT contacting the portmapper on %s", 841 1.1 christos MNTTAB_OPT_PUBLIC, host); 842 1.1 christos /* 843 1.1.1.3 christos * Prefer NFSv4/tcp if the client supports it (cf. RFC 2054, 7). 844 1.1 christos */ 845 1.1 christos if (!nfs_version) { 846 1.1.1.3 christos #if defined(HAVE_FS_NFS4) 847 1.1.1.3 christos nfs_version = NFS_VERSION4; 848 1.1.1.3 christos #elif defined(HAVE_FS_NFS3) 849 1.1 christos nfs_version = NFS_VERSION3; 850 1.1 christos #else /* not HAVE_FS_NFS3 */ 851 1.1 christos nfs_version = NFS_VERSION; 852 1.1 christos #endif /* not HAVE_FS_NFS3 */ 853 1.1 christos plog(XLOG_INFO, "No NFS version specified, will use NFSv%d", 854 1.1 christos (int) nfs_version); 855 1.1 christos } 856 1.1 christos if (!nfs_proto) { 857 1.1.1.3 christos #if defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3) || defined(HAVE_FS_NFS4) 858 1.1 christos nfs_proto = "tcp"; 859 1.1.1.3 christos #else /* not defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3) || defined(HAVE_FS_NFS4) */ 860 1.1 christos nfs_proto = "udp"; 861 1.1.1.3 christos #endif /* not defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3) || defined(HAVE_FS_NFS4) */ 862 1.1 christos plog(XLOG_INFO, "No NFS protocol transport specified, will use %s", 863 1.1 christos nfs_proto); 864 1.1 christos } 865 1.1 christos } else { 866 1.1 christos /* 867 1.1 christos * Find the best combination of NFS version and protocol. 868 1.1 christos * When given a choice, use the highest available version, 869 1.1 christos * and use TCP over UDP if available. 870 1.1 christos */ 871 1.1 christos if (check_pmap_up(host, ip)) { 872 1.1 christos if (nfs_proto) { 873 1.1.1.3 christos best_nfs_version = get_nfs_version(host, ip, nfs_version, nfs_proto, 874 1.1.1.3 christos gopt.nfs_vers); 875 1.1 christos nfs_port = ip->sin_port; 876 1.1 christos } 877 1.1 christos #ifdef MNTTAB_OPT_PROTO 878 1.1 christos else { 879 1.1 christos u_int proto_nfs_version; 880 1.1 christos char **p; 881 1.1 christos 882 1.1 christos for (p = protocols; *p; p++) { 883 1.1.1.3 christos proto_nfs_version = get_nfs_version(host, ip, nfs_version, *p, 884 1.1.1.3 christos gopt.nfs_vers); 885 1.1 christos if (proto_nfs_version > best_nfs_version) { 886 1.1 christos best_nfs_version = proto_nfs_version; 887 1.1 christos nfs_proto = *p; 888 1.1 christos nfs_port = ip->sin_port; 889 1.1 christos } 890 1.1 christos } 891 1.1 christos } 892 1.1 christos #endif /* MNTTAB_OPT_PROTO */ 893 1.1 christos } else { 894 1.1 christos plog(XLOG_INFO, "portmapper service not running on %s", host); 895 1.1 christos } 896 1.1 christos 897 1.1 christos /* use the portmapper results only nfs_version is not set yet */ 898 1.1 christos if (!best_nfs_version) { 899 1.1 christos /* 900 1.1 christos * If the NFS server is down or does not support the portmapper call 901 1.1 christos * (such as certain Novell NFS servers) we mark it as version 2 and we 902 1.1 christos * let the nfs code deal with the case when it is down. If/when the 903 1.1 christos * server comes back up and it can support NFSv3 and/or TCP, it will 904 1.1 christos * use those. 905 1.1 christos */ 906 1.1 christos if (nfs_version == 0) { 907 1.1 christos nfs_version = NFS_VERSION; 908 1.1 christos nfs_proto = "udp"; 909 1.1 christos } 910 1.1 christos plog(XLOG_INFO, "NFS service not running on %s", host); 911 1.1 christos fserver_is_down = 1; 912 1.1 christos } else { 913 1.1 christos if (nfs_version == 0) 914 1.1 christos nfs_version = best_nfs_version; 915 1.1 christos plog(XLOG_INFO, "Using NFS version %d, protocol %s on host %s", 916 1.1 christos (int) nfs_version, nfs_proto, host); 917 1.1 christos } 918 1.1 christos } 919 1.1 christos 920 1.1 christos /* 921 1.1 christos * Determine the NFS port. 922 1.1 christos * 923 1.1 christos * A valid "port" mount option overrides anything else. 924 1.1 christos * If the port has been determined from the portmapper, use that. 925 1.1 christos * Default to NFS_PORT otherwise (cf. RFC 2054, 3). 926 1.1 christos */ 927 1.1 christos nfs_port_opt = hasmntval(&mnt, MNTTAB_OPT_PORT); 928 1.1 christos if (nfs_port_opt > 0) 929 1.1 christos nfs_port = htons(nfs_port_opt); 930 1.1 christos if (!nfs_port) 931 1.1 christos nfs_port = htons(NFS_PORT); 932 1.1 christos 933 1.1.1.3 christos dlog("%s: using port %d for nfs on %s", __func__, 934 1.1.1.3 christos (int) ntohs(nfs_port), host); 935 1.1 christos ip->sin_port = nfs_port; 936 1.1 christos 937 1.1 christos no_dns: 938 1.1 christos /* 939 1.1 christos * Try to find an existing fs server structure for this host. 940 1.1 christos * Note that differing versions or protocols have their own structures. 941 1.1 christos * XXX: Need to fix the ping mechanism to actually use the NFS protocol 942 1.1 christos * chosen here (right now it always uses datagram sockets). 943 1.1 christos */ 944 1.1 christos ITER(fs, fserver, &nfs_srvr_list) { 945 1.1 christos if (STREQ(host, fs->fs_host) && 946 1.1 christos nfs_version == fs->fs_version && 947 1.1 christos STREQ(nfs_proto, fs->fs_proto)) { 948 1.1 christos /* 949 1.1 christos * fill in the IP address -- this is only needed 950 1.1 christos * if there is a chance an IP address will change 951 1.1 christos * between mounts. 952 1.1 christos * Mike Mitchell, mcm (at) unx.sas.com, 09/08/93 953 1.1 christos */ 954 1.1 christos if (hp && fs->fs_ip && 955 1.1 christos memcmp((voidp) &fs->fs_ip->sin_addr, 956 1.1 christos (voidp) hp->h_addr, 957 1.1 christos sizeof(fs->fs_ip->sin_addr)) != 0) { 958 1.1 christos struct in_addr ia; 959 1.1 christos char *old_ipaddr, *new_ipaddr; 960 1.1.1.3 christos old_ipaddr = xstrdup(inet_ntoa(fs->fs_ip->sin_addr)); 961 1.1 christos memmove((voidp) &ia, (voidp) hp->h_addr, sizeof(struct in_addr)); 962 1.1 christos new_ipaddr = inet_ntoa(ia); /* ntoa uses static buf */ 963 1.1 christos plog(XLOG_WARNING, "fileserver %s changed ip: %s -> %s", 964 1.1 christos fs->fs_host, old_ipaddr, new_ipaddr); 965 1.1 christos XFREE(old_ipaddr); 966 1.1 christos flush_nfs_fhandle_cache(fs); 967 1.1 christos memmove((voidp) &fs->fs_ip->sin_addr, (voidp) hp->h_addr, sizeof(fs->fs_ip->sin_addr)); 968 1.1 christos } 969 1.1 christos 970 1.1 christos /* 971 1.1 christos * If the new file systems doesn't use WebNFS, the nfs pings may 972 1.1 christos * try to contact the portmapper. 973 1.1 christos */ 974 1.1 christos if (!(mf->mf_flags & MFF_WEBNFS)) 975 1.1 christos fs->fs_flags &= ~FSF_WEBNFS; 976 1.1 christos 977 1.1 christos /* check if pingval needs to be updated/set/reset */ 978 1.1 christos start_nfs_pings(fs, pingval); 979 1.1 christos 980 1.1 christos /* 981 1.1 christos * Following if statement from Mike Mitchell <mcm (at) unx.sas.com> 982 1.1 christos * Initialize the ping data if we aren't pinging now. The np_ttl and 983 1.1 christos * np_ping fields are especially important. 984 1.1 christos */ 985 1.1 christos if (!(fs->fs_flags & FSF_PINGING)) { 986 1.1 christos np = (nfs_private *) fs->fs_private; 987 1.1.1.3 christos if (np->np_mountd_inval != 'P') { 988 1.1.1.3 christos np->np_mountd_inval = TRUE; 989 1.1.1.3 christos np->np_xid = XID_ALLOC(); 990 1.1.1.3 christos np->np_error = -1; 991 1.1.1.3 christos np->np_ping = 0; 992 1.1.1.3 christos /* 993 1.1.1.3 christos * Initially the server will be deemed dead 994 1.1.1.3 christos * after MAX_ALLOWED_PINGS of the fast variety 995 1.1.1.3 christos * have failed. 996 1.1.1.3 christos */ 997 1.1.1.3 christos np->np_ttl = MAX_ALLOWED_PINGS * FAST_NFS_PING + clocktime(NULL) - 1; 998 1.1.1.3 christos start_nfs_pings(fs, pingval); 999 1.1.1.3 christos if (fserver_is_down) 1000 1.1.1.3 christos fs->fs_flags |= FSF_VALID | FSF_DOWN; 1001 1.1.1.3 christos } else { 1002 1.1.1.3 christos fs->fs_flags = FSF_VALID; 1003 1.1.1.3 christos } 1004 1.1.1.3 christos 1005 1.1 christos } 1006 1.1 christos 1007 1.1 christos fs->fs_refc++; 1008 1.1.1.3 christos XFREE(ip); 1009 1.1 christos return fs; 1010 1.1 christos } 1011 1.1 christos } 1012 1.1 christos 1013 1.1 christos /* 1014 1.1 christos * Get here if we can't find an entry 1015 1.1 christos */ 1016 1.1 christos 1017 1.1 christos /* 1018 1.1 christos * Allocate a new server 1019 1.1 christos */ 1020 1.1 christos fs = ALLOC(struct fserver); 1021 1.1 christos fs->fs_refc = 1; 1022 1.1.1.3 christos fs->fs_host = xstrdup(hp ? hp->h_name : "unknown_hostname"); 1023 1.1 christos if (gopt.flags & CFM_NORMALIZE_HOSTNAMES) 1024 1.1 christos host_normalize(&fs->fs_host); 1025 1.1 christos fs->fs_ip = ip; 1026 1.1 christos fs->fs_cid = 0; 1027 1.1 christos if (ip) { 1028 1.1 christos fs->fs_flags = FSF_DOWN; /* Starts off down */ 1029 1.1 christos } else { 1030 1.1 christos fs->fs_flags = FSF_ERROR | FSF_VALID; 1031 1.1 christos mf->mf_flags |= MFF_ERROR; 1032 1.1 christos mf->mf_error = ENOENT; 1033 1.1 christos } 1034 1.1 christos if (mf->mf_flags & MFF_WEBNFS) 1035 1.1 christos fs->fs_flags |= FSF_WEBNFS; 1036 1.1 christos fs->fs_version = nfs_version; 1037 1.1 christos fs->fs_proto = nfs_proto; 1038 1.1 christos fs->fs_type = MNTTAB_TYPE_NFS; 1039 1.1 christos fs->fs_pinger = AM_PINGER; 1040 1.1 christos fs->fs_flags |= FSF_PING_UNINIT; /* pinger hasn't been initialized */ 1041 1.1 christos np = ALLOC(struct nfs_private); 1042 1.1 christos memset((voidp) np, 0, sizeof(*np)); 1043 1.1.1.3 christos np->np_mountd = htons(hasmntval(&mnt, "mountport")); 1044 1.1.1.3 christos if (np->np_mountd == 0) { 1045 1.1.1.3 christos np->np_mountd_inval = 'Y'; 1046 1.1.1.3 christos np->np_xid = XID_ALLOC(); 1047 1.1.1.3 christos np->np_error = -1; 1048 1.1.1.3 christos } else { 1049 1.1.1.3 christos plog(XLOG_INFO, "%s: using mountport: %d", __func__, 1050 1.1.1.3 christos (int) ntohs(np->np_mountd)); 1051 1.1.1.3 christos np->np_mountd_inval = 'P'; 1052 1.1.1.3 christos np->np_xid = 0; 1053 1.1.1.3 christos np->np_error = 0; 1054 1.1.1.3 christos } 1055 1.1 christos 1056 1.1 christos /* 1057 1.1 christos * Initially the server will be deemed dead after 1058 1.1 christos * MAX_ALLOWED_PINGS of the fast variety have failed. 1059 1.1 christos */ 1060 1.1 christos np->np_ttl = clocktime(NULL) + MAX_ALLOWED_PINGS * FAST_NFS_PING - 1; 1061 1.1 christos fs->fs_private = (voidp) np; 1062 1.1 christos fs->fs_prfree = (void (*)(voidp)) free; 1063 1.1 christos 1064 1.1 christos if (!FSRV_ERROR(fs)) { 1065 1.1 christos /* start of keepalive timer, first updating pingval */ 1066 1.1 christos start_nfs_pings(fs, pingval); 1067 1.1 christos if (fserver_is_down) 1068 1.1 christos fs->fs_flags |= FSF_VALID | FSF_DOWN; 1069 1.1 christos } 1070 1.1 christos 1071 1.1 christos /* 1072 1.1 christos * Add to list of servers 1073 1.1 christos */ 1074 1.1 christos ins_que(&fs->fs_q, &nfs_srvr_list); 1075 1.1 christos 1076 1.1 christos return fs; 1077 1.1 christos } 1078