ops_nfs.c revision 51292
138494Sobrien/* 251292Sobrien * Copyright (c) 1997-1999 Erez Zadok 338494Sobrien * Copyright (c) 1990 Jan-Simon Pendry 438494Sobrien * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 538494Sobrien * Copyright (c) 1990 The Regents of the University of California. 638494Sobrien * All rights reserved. 738494Sobrien * 838494Sobrien * This code is derived from software contributed to Berkeley by 938494Sobrien * Jan-Simon Pendry at Imperial College, London. 1038494Sobrien * 1138494Sobrien * Redistribution and use in source and binary forms, with or without 1238494Sobrien * modification, are permitted provided that the following conditions 1338494Sobrien * are met: 1438494Sobrien * 1. Redistributions of source code must retain the above copyright 1538494Sobrien * notice, this list of conditions and the following disclaimer. 1638494Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1738494Sobrien * notice, this list of conditions and the following disclaimer in the 1838494Sobrien * documentation and/or other materials provided with the distribution. 1938494Sobrien * 3. All advertising materials mentioning features or use of this software 2042629Sobrien * must display the following acknowledgment: 2138494Sobrien * This product includes software developed by the University of 2238494Sobrien * California, Berkeley and its contributors. 2338494Sobrien * 4. Neither the name of the University nor the names of its contributors 2438494Sobrien * may be used to endorse or promote products derived from this software 2538494Sobrien * without specific prior written permission. 2638494Sobrien * 2738494Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2838494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2938494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3038494Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3138494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3238494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3338494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3438494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3538494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3638494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3738494Sobrien * SUCH DAMAGE. 3838494Sobrien * 3938494Sobrien * %W% (Berkeley) %G% 4038494Sobrien * 4151292Sobrien * $Id: ops_nfs.c,v 1.5 1999/03/13 17:03:28 ezk Exp $ 4238494Sobrien * 4338494Sobrien */ 4438494Sobrien 4538494Sobrien/* 4638494Sobrien * Network file system 4738494Sobrien */ 4838494Sobrien 4938494Sobrien#ifdef HAVE_CONFIG_H 5038494Sobrien# include <config.h> 5138494Sobrien#endif /* HAVE_CONFIG_H */ 5238494Sobrien#include <am_defs.h> 5338494Sobrien#include <amd.h> 5438494Sobrien 5538494Sobrien/* 5638494Sobrien * Convert from nfsstat to UN*X error code 5738494Sobrien */ 5838494Sobrien#define unx_error(e) ((int)(e)) 5938494Sobrien 6038494Sobrien/* 6138494Sobrien * FH_TTL is the time a file handle will remain in the cache since 6238494Sobrien * last being used. If the file handle becomes invalid, then it 6338494Sobrien * will be flushed anyway. 6438494Sobrien */ 6538494Sobrien#define FH_TTL (5 * 60) /* five minutes */ 6638494Sobrien#define FH_TTL_ERROR (30) /* 30 seconds */ 6738494Sobrien#define FHID_ALLOC(struct) (++fh_id) 6838494Sobrien 6938494Sobrien/* 7038494Sobrien * The NFS layer maintains a cache of file handles. 7138494Sobrien * This is *fundamental* to the implementation and 7238494Sobrien * also allows quick remounting when a filesystem 7338494Sobrien * is accessed soon after timing out. 7438494Sobrien * 7538494Sobrien * The NFS server layer knows to flush this cache 7638494Sobrien * when a server goes down so avoiding stale handles. 7738494Sobrien * 7838494Sobrien * Each cache entry keeps a hard reference to 7938494Sobrien * the corresponding server. This ensures that 8038494Sobrien * the server keepalive information is maintained. 8138494Sobrien * 8238494Sobrien * The copy of the sockaddr_in here is taken so 8338494Sobrien * that the port can be twiddled to talk to mountd 8438494Sobrien * instead of portmap or the NFS server as used 8538494Sobrien * elsewhere. 8638494Sobrien * The port# is flushed if a server goes down. 8738494Sobrien * The IP address is never flushed - we assume 8838494Sobrien * that the address of a mounted machine never 8938494Sobrien * changes. If it does, then you have other 9038494Sobrien * problems... 9138494Sobrien */ 9238494Sobrientypedef struct fh_cache fh_cache; 9338494Sobrienstruct fh_cache { 9438494Sobrien qelem fh_q; /* List header */ 9538494Sobrien voidp fh_wchan; /* Wait channel */ 9638494Sobrien int fh_error; /* Valid data? */ 9738494Sobrien int fh_id; /* Unique id */ 9838494Sobrien int fh_cid; /* Callout id */ 9938494Sobrien u_long fh_nfs_version; /* highest NFS version on host */ 10038494Sobrien am_nfs_handle_t fh_nfs_handle; /* Handle on filesystem */ 10138494Sobrien struct sockaddr_in fh_sin; /* Address of mountd */ 10238494Sobrien fserver *fh_fs; /* Server holding filesystem */ 10338494Sobrien char *fh_path; /* Filesystem on host */ 10438494Sobrien}; 10538494Sobrien 10638494Sobrien/* forward definitions */ 10738494Sobrienstatic int call_mountd(fh_cache *fp, u_long proc, fwd_fun f, voidp wchan); 10838494Sobrienstatic int fh_id = 0; 10938494Sobrien 11038494Sobrien/* globals */ 11138494SobrienAUTH *nfs_auth; 11238494Sobrienqelem fh_head = {&fh_head, &fh_head}; 11338494Sobrien 11438494Sobrien/* 11538494Sobrien * Network file system operations 11638494Sobrien */ 11738494Sobrienam_ops nfs_ops = 11838494Sobrien{ 11938494Sobrien "nfs", 12038494Sobrien nfs_match, 12138494Sobrien nfs_init, 12238494Sobrien amfs_auto_fmount, 12338494Sobrien nfs_fmount, 12438494Sobrien amfs_auto_fumount, 12538494Sobrien nfs_fumount, 12638494Sobrien amfs_error_lookuppn, 12738494Sobrien amfs_error_readdir, 12838494Sobrien 0, /* nfs_readlink */ 12938494Sobrien 0, /* nfs_mounted */ 13038494Sobrien nfs_umounted, 13138494Sobrien find_nfs_srvr, 13238494Sobrien FS_MKMNT | FS_BACKGROUND | FS_AMQINFO 13338494Sobrien}; 13438494Sobrien 13538494Sobrien 13638494Sobrienstatic fh_cache * 13738494Sobrienfind_nfs_fhandle_cache(voidp idv, int done) 13838494Sobrien{ 13938494Sobrien fh_cache *fp, *fp2 = 0; 14038494Sobrien int id = (long) idv; /* for 64-bit archs */ 14138494Sobrien 14238494Sobrien ITER(fp, fh_cache, &fh_head) { 14338494Sobrien if (fp->fh_id == id) { 14438494Sobrien fp2 = fp; 14538494Sobrien break; 14638494Sobrien } 14738494Sobrien } 14838494Sobrien 14938494Sobrien#ifdef DEBUG 15038494Sobrien if (fp2) { 15151292Sobrien dlog("fh cache gives fp %#lx, fs %s", (unsigned long) fp2, fp2->fh_path); 15238494Sobrien } else { 15338494Sobrien dlog("fh cache search failed"); 15438494Sobrien } 15538494Sobrien#endif /* DEBUG */ 15638494Sobrien 15738494Sobrien if (fp2 && !done) { 15838494Sobrien fp2->fh_error = ETIMEDOUT; 15938494Sobrien return 0; 16038494Sobrien } 16138494Sobrien 16238494Sobrien return fp2; 16338494Sobrien} 16438494Sobrien 16538494Sobrien 16638494Sobrien/* 16738494Sobrien * Called when a filehandle appears 16838494Sobrien */ 16938494Sobrienstatic void 17038494Sobriengot_nfs_fh(voidp pkt, int len, struct sockaddr_in * sa, struct sockaddr_in * ia, voidp idv, int done) 17138494Sobrien{ 17238494Sobrien fh_cache *fp; 17338494Sobrien 17438494Sobrien fp = find_nfs_fhandle_cache(idv, done); 17538494Sobrien if (!fp) 17638494Sobrien return; 17738494Sobrien 17838494Sobrien /* 17938494Sobrien * retrieve the correct RPC reply for the file handle, based on the 18038494Sobrien * NFS protocol version. 18138494Sobrien */ 18238494Sobrien#ifdef HAVE_FS_NFS3 18338494Sobrien if (fp->fh_nfs_version == NFS_VERSION3) 18438494Sobrien fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &fp->fh_nfs_handle.v3, 18538494Sobrien (XDRPROC_T_TYPE) xdr_mountres3); 18638494Sobrien else 18738494Sobrien#endif /* HAVE_FS_NFS3 */ 18838494Sobrien fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &fp->fh_nfs_handle.v2, 18938494Sobrien (XDRPROC_T_TYPE) xdr_fhstatus); 19038494Sobrien 19138494Sobrien if (!fp->fh_error) { 19238494Sobrien#ifdef DEBUG 19338494Sobrien dlog("got filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path); 19438494Sobrien#endif /* DEBUG */ 19538494Sobrien 19638494Sobrien /* 19738494Sobrien * Wakeup anything sleeping on this filehandle 19838494Sobrien */ 19938494Sobrien if (fp->fh_wchan) { 20038494Sobrien#ifdef DEBUG 20151292Sobrien dlog("Calling wakeup on %#lx", (unsigned long) fp->fh_wchan); 20238494Sobrien#endif /* DEBUG */ 20338494Sobrien wakeup(fp->fh_wchan); 20438494Sobrien } 20538494Sobrien } 20638494Sobrien} 20738494Sobrien 20838494Sobrien 20938494Sobrienvoid 21038494Sobrienflush_nfs_fhandle_cache(fserver *fs) 21138494Sobrien{ 21238494Sobrien fh_cache *fp; 21338494Sobrien 21438494Sobrien ITER(fp, fh_cache, &fh_head) { 21538494Sobrien if (fp->fh_fs == fs || fs == 0) { 21638494Sobrien fp->fh_sin.sin_port = (u_short) 0; 21738494Sobrien fp->fh_error = -1; 21838494Sobrien } 21938494Sobrien } 22038494Sobrien} 22138494Sobrien 22238494Sobrien 22338494Sobrienstatic void 22438494Sobriendiscard_fh(voidp v) 22538494Sobrien{ 22638494Sobrien fh_cache *fp = v; 22738494Sobrien 22838494Sobrien rem_que(&fp->fh_q); 22938494Sobrien if (fp->fh_fs) { 23038494Sobrien#ifdef DEBUG 23138494Sobrien dlog("Discarding filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path); 23238494Sobrien#endif /* DEBUG */ 23338494Sobrien free_srvr(fp->fh_fs); 23438494Sobrien } 23538494Sobrien if (fp->fh_path) 23638494Sobrien XFREE(fp->fh_path); 23738494Sobrien XFREE(fp); 23838494Sobrien} 23938494Sobrien 24038494Sobrien 24138494Sobrien/* 24238494Sobrien * Determine the file handle for a node 24338494Sobrien */ 24438494Sobrienstatic int 24538494Sobrienprime_nfs_fhandle_cache(char *path, fserver *fs, am_nfs_handle_t *fhbuf, voidp wchan) 24638494Sobrien{ 24738494Sobrien fh_cache *fp, *fp_save = 0; 24838494Sobrien int error; 24938494Sobrien int reuse_id = FALSE; 25038494Sobrien 25138494Sobrien#ifdef DEBUG 25238494Sobrien dlog("Searching cache for %s:%s", fs->fs_host, path); 25338494Sobrien#endif /* DEBUG */ 25438494Sobrien 25538494Sobrien /* 25638494Sobrien * First search the cache 25738494Sobrien */ 25838494Sobrien ITER(fp, fh_cache, &fh_head) { 25938494Sobrien if (fs == fp->fh_fs && STREQ(path, fp->fh_path)) { 26038494Sobrien switch (fp->fh_error) { 26138494Sobrien case 0: 26251292Sobrien plog(XLOG_INFO, "prime_nfs_fhandle_cache: NFS version %d", (int) fp->fh_nfs_version); 26338494Sobrien#ifdef HAVE_FS_NFS3 26438494Sobrien if (fp->fh_nfs_version == NFS_VERSION3) 26538494Sobrien error = fp->fh_error = unx_error(fp->fh_nfs_handle.v3.fhs_status); 26638494Sobrien else 26738494Sobrien#endif /* HAVE_FS_NFS3 */ 26838494Sobrien error = fp->fh_error = unx_error(fp->fh_nfs_handle.v2.fhs_status); 26938494Sobrien if (error == 0) { 27038494Sobrien if (fhbuf) { 27138494Sobrien#ifdef HAVE_FS_NFS3 27238494Sobrien if (fp->fh_nfs_version == NFS_VERSION3) 27338494Sobrien memmove((voidp) &(fhbuf->v3), (voidp) &(fp->fh_nfs_handle.v3), 27438494Sobrien sizeof(fp->fh_nfs_handle.v3)); 27538494Sobrien else 27638494Sobrien#endif /* HAVE_FS_NFS3 */ 27738494Sobrien memmove((voidp) &(fhbuf->v2), (voidp) &(fp->fh_nfs_handle.v2), 27838494Sobrien sizeof(fp->fh_nfs_handle.v2)); 27938494Sobrien } 28038494Sobrien if (fp->fh_cid) 28138494Sobrien untimeout(fp->fh_cid); 28238494Sobrien fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp); 28338494Sobrien } else if (error == EACCES) { 28438494Sobrien /* 28538494Sobrien * Now decode the file handle return code. 28638494Sobrien */ 28738494Sobrien plog(XLOG_INFO, "Filehandle denied for \"%s:%s\"", 28838494Sobrien fs->fs_host, path); 28938494Sobrien } else { 29038494Sobrien errno = error; /* XXX */ 29138494Sobrien plog(XLOG_INFO, "Filehandle error for \"%s:%s\": %m", 29238494Sobrien fs->fs_host, path); 29338494Sobrien } 29438494Sobrien 29538494Sobrien /* 29638494Sobrien * The error was returned from the remote mount daemon. 29738494Sobrien * Policy: this error will be cached for now... 29838494Sobrien */ 29938494Sobrien return error; 30038494Sobrien 30138494Sobrien case -1: 30238494Sobrien /* 30338494Sobrien * Still thinking about it, but we can re-use. 30438494Sobrien */ 30538494Sobrien fp_save = fp; 30638494Sobrien reuse_id = TRUE; 30738494Sobrien break; 30838494Sobrien 30938494Sobrien default: 31038494Sobrien /* 31138494Sobrien * Return the error. 31238494Sobrien * Policy: make sure we recompute if required again 31338494Sobrien * in case this was caused by a network failure. 31438494Sobrien * This can thrash mountd's though... If you find 31538494Sobrien * your mountd going slowly then: 31638494Sobrien * 1. Add a fork() loop to main. 31738494Sobrien * 2. Remove the call to innetgr() and don't use 31838494Sobrien * netgroups, especially if you don't use YP. 31938494Sobrien */ 32038494Sobrien error = fp->fh_error; 32138494Sobrien fp->fh_error = -1; 32238494Sobrien return error; 32338494Sobrien } 32438494Sobrien break; 32538494Sobrien } 32638494Sobrien } 32738494Sobrien 32838494Sobrien /* 32938494Sobrien * Not in cache 33038494Sobrien */ 33138494Sobrien if (fp_save) { 33238494Sobrien fp = fp_save; 33338494Sobrien /* 33438494Sobrien * Re-use existing slot 33538494Sobrien */ 33638494Sobrien untimeout(fp->fh_cid); 33738494Sobrien free_srvr(fp->fh_fs); 33838494Sobrien XFREE(fp->fh_path); 33938494Sobrien } else { 34038494Sobrien fp = ALLOC(struct fh_cache); 34138494Sobrien memset((voidp) fp, 0, sizeof(struct fh_cache)); 34238494Sobrien ins_que(&fp->fh_q, &fh_head); 34338494Sobrien } 34438494Sobrien if (!reuse_id) 34538494Sobrien fp->fh_id = FHID_ALLOC(struct ); 34638494Sobrien fp->fh_wchan = wchan; 34738494Sobrien fp->fh_error = -1; 34838494Sobrien fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp); 34938494Sobrien 35038494Sobrien /* 35138494Sobrien * if fs->fs_ip is null, remote server is probably down. 35238494Sobrien */ 35338494Sobrien if (!fs->fs_ip) { 35438494Sobrien /* Mark the fileserver down and invalid again */ 35538494Sobrien fs->fs_flags &= ~FSF_VALID; 35638494Sobrien fs->fs_flags |= FSF_DOWN; 35738494Sobrien error = AM_ERRNO_HOST_DOWN; 35838494Sobrien return error; 35938494Sobrien } 36038494Sobrien 36138494Sobrien /* 36238494Sobrien * If the address has changed then don't try to re-use the 36338494Sobrien * port information 36438494Sobrien */ 36538494Sobrien if (fp->fh_sin.sin_addr.s_addr != fs->fs_ip->sin_addr.s_addr) { 36638494Sobrien fp->fh_sin = *fs->fs_ip; 36738494Sobrien fp->fh_sin.sin_port = 0; 36838494Sobrien fp->fh_nfs_version = fs->fs_version; 36938494Sobrien } 37038494Sobrien fp->fh_fs = dup_srvr(fs); 37138494Sobrien fp->fh_path = strdup(path); 37238494Sobrien 37338494Sobrien error = call_mountd(fp, MOUNTPROC_MNT, got_nfs_fh, wchan); 37438494Sobrien if (error) { 37538494Sobrien /* 37638494Sobrien * Local error - cache for a short period 37738494Sobrien * just to prevent thrashing. 37838494Sobrien */ 37938494Sobrien untimeout(fp->fh_cid); 38038494Sobrien fp->fh_cid = timeout(error < 0 ? 2 * ALLOWED_MOUNT_TIME : FH_TTL_ERROR, 38138494Sobrien discard_fh, (voidp) fp); 38238494Sobrien fp->fh_error = error; 38338494Sobrien } else { 38438494Sobrien error = fp->fh_error; 38538494Sobrien } 38638494Sobrien 38738494Sobrien return error; 38838494Sobrien} 38938494Sobrien 39038494Sobrien 39138494Sobrienint 39238494Sobrienmake_nfs_auth(void) 39338494Sobrien{ 39438494Sobrien AUTH_CREATE_GIDLIST_TYPE group_wheel = 0; 39538494Sobrien 39638494Sobrien /* Some NFS mounts (particularly cross-domain) require FQDNs to succeed */ 39738494Sobrien 39838494Sobrien#ifdef HAVE_TRANSPORT_TYPE_TLI 39938494Sobrien if (gopt.flags & CFM_FULLY_QUALIFIED_HOSTS) { 40038494Sobrien plog(XLOG_INFO, "Using NFS auth for fqhn \"%s\"", hostd); 40138494Sobrien nfs_auth = authsys_create(hostd, 0, 0, 1, &group_wheel); 40238494Sobrien } else { 40338494Sobrien nfs_auth = authsys_create_default(); 40438494Sobrien } 40538494Sobrien#else /* not HAVE_TRANSPORT_TYPE_TLI */ 40638494Sobrien if (gopt.flags & CFM_FULLY_QUALIFIED_HOSTS) { 40738494Sobrien plog(XLOG_INFO, "Using NFS auth for fqhn \"%s\"", hostd); 40838494Sobrien nfs_auth = authunix_create(hostd, 0, 0, 1, &group_wheel); 40938494Sobrien } else { 41038494Sobrien nfs_auth = authunix_create_default(); 41138494Sobrien } 41238494Sobrien#endif /* not HAVE_TRANSPORT_TYPE_TLI */ 41338494Sobrien 41438494Sobrien if (!nfs_auth) 41538494Sobrien return ENOBUFS; 41638494Sobrien 41738494Sobrien return 0; 41838494Sobrien} 41938494Sobrien 42038494Sobrien 42138494Sobrienstatic int 42238494Sobriencall_mountd(fh_cache *fp, u_long proc, fwd_fun f, voidp wchan) 42338494Sobrien{ 42438494Sobrien struct rpc_msg mnt_msg; 42538494Sobrien int len; 42638494Sobrien char iobuf[8192]; 42738494Sobrien int error; 42838494Sobrien u_long mnt_version; 42938494Sobrien 43038494Sobrien if (!nfs_auth) { 43138494Sobrien error = make_nfs_auth(); 43238494Sobrien if (error) 43338494Sobrien return error; 43438494Sobrien } 43538494Sobrien 43638494Sobrien if (fp->fh_sin.sin_port == 0) { 43738494Sobrien u_short port; 43838494Sobrien error = nfs_srvr_port(fp->fh_fs, &port, wchan); 43938494Sobrien if (error) 44038494Sobrien return error; 44138494Sobrien fp->fh_sin.sin_port = port; 44238494Sobrien } 44338494Sobrien 44438494Sobrien /* find the right version of the mount protocol */ 44538494Sobrien#ifdef HAVE_FS_NFS3 44638494Sobrien if (fp->fh_nfs_version == NFS_VERSION3) 44738494Sobrien mnt_version = MOUNTVERS3; 44838494Sobrien else 44938494Sobrien#endif /* HAVE_FS_NFS3 */ 45038494Sobrien mnt_version = MOUNTVERS; 45138494Sobrien plog(XLOG_INFO, "call_mountd: NFS version %d, mount version %d", 45251292Sobrien (int) fp->fh_nfs_version, (int) mnt_version); 45338494Sobrien 45438494Sobrien rpc_msg_init(&mnt_msg, MOUNTPROG, mnt_version, MOUNTPROC_NULL); 45538494Sobrien len = make_rpc_packet(iobuf, 45638494Sobrien sizeof(iobuf), 45738494Sobrien proc, 45838494Sobrien &mnt_msg, 45938494Sobrien (voidp) &fp->fh_path, 46038494Sobrien (XDRPROC_T_TYPE) xdr_nfspath, 46138494Sobrien nfs_auth); 46238494Sobrien 46338494Sobrien if (len > 0) { 46438494Sobrien error = fwd_packet(MK_RPC_XID(RPC_XID_MOUNTD, fp->fh_id), 46538494Sobrien (voidp) iobuf, 46638494Sobrien len, 46738494Sobrien &fp->fh_sin, 46838494Sobrien &fp->fh_sin, 46938494Sobrien (voidp) ((long) fp->fh_id), /* for 64-bit archs */ 47038494Sobrien f); 47138494Sobrien } else { 47238494Sobrien error = -len; 47338494Sobrien } 47438494Sobrien 47538494Sobrien/* 47638494Sobrien * It may be the case that we're sending to the wrong MOUNTD port. This 47738494Sobrien * occurs if mountd is restarted on the server after the port has been 47838494Sobrien * looked up and stored in the filehandle cache somewhere. The correct 47938494Sobrien * solution, if we're going to cache port numbers is to catch the ICMP 48038494Sobrien * port unreachable reply from the server and cause the portmap request 48138494Sobrien * to be redone. The quick solution here is to invalidate the MOUNTD 48238494Sobrien * port. 48338494Sobrien */ 48438494Sobrien fp->fh_sin.sin_port = 0; 48538494Sobrien 48638494Sobrien return error; 48738494Sobrien} 48838494Sobrien 48938494Sobrien 49038494Sobrien/* 49138494Sobrien * NFS needs the local filesystem, remote filesystem 49238494Sobrien * remote hostname. 49338494Sobrien * Local filesystem defaults to remote and vice-versa. 49438494Sobrien */ 49538494Sobrienchar * 49638494Sobriennfs_match(am_opts *fo) 49738494Sobrien{ 49838494Sobrien char *xmtab; 49938494Sobrien 50038494Sobrien if (fo->opt_fs && !fo->opt_rfs) 50138494Sobrien fo->opt_rfs = fo->opt_fs; 50238494Sobrien if (!fo->opt_rfs) { 50338494Sobrien plog(XLOG_USER, "nfs: no remote filesystem specified"); 50438494Sobrien return NULL; 50538494Sobrien } 50638494Sobrien if (!fo->opt_rhost) { 50738494Sobrien plog(XLOG_USER, "nfs: no remote host specified"); 50838494Sobrien return NULL; 50938494Sobrien } 51038494Sobrien 51138494Sobrien /* 51238494Sobrien * Determine magic cookie to put in mtab 51338494Sobrien */ 51438494Sobrien xmtab = (char *) xmalloc(strlen(fo->opt_rhost) + strlen(fo->opt_rfs) + 2); 51538494Sobrien sprintf(xmtab, "%s:%s", fo->opt_rhost, fo->opt_rfs); 51638494Sobrien#ifdef DEBUG 51738494Sobrien dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"", 51838494Sobrien fo->opt_rhost, fo->opt_rfs, fo->opt_fs); 51938494Sobrien#endif /* DEBUG */ 52038494Sobrien 52138494Sobrien return xmtab; 52238494Sobrien} 52338494Sobrien 52438494Sobrien 52538494Sobrien/* 52638494Sobrien * Initialize am structure for nfs 52738494Sobrien */ 52838494Sobrienint 52938494Sobriennfs_init(mntfs *mf) 53038494Sobrien{ 53138494Sobrien int error; 53238494Sobrien am_nfs_handle_t fhs; 53338494Sobrien char *colon; 53438494Sobrien 53538494Sobrien if (mf->mf_private) 53638494Sobrien return 0; 53738494Sobrien 53838494Sobrien colon = strchr(mf->mf_info, ':'); 53938494Sobrien if (colon == 0) 54038494Sobrien return ENOENT; 54138494Sobrien 54238494Sobrien error = prime_nfs_fhandle_cache(colon + 1, mf->mf_server, &fhs, (voidp) mf); 54338494Sobrien if (!error) { 54438494Sobrien mf->mf_private = (voidp) ALLOC(am_nfs_handle_t); 54538494Sobrien mf->mf_prfree = (void (*)(voidp)) free; 54638494Sobrien memmove(mf->mf_private, (voidp) &fhs, sizeof(fhs)); 54738494Sobrien } 54838494Sobrien return error; 54938494Sobrien} 55038494Sobrien 55138494Sobrien 55238494Sobrienint 55338494Sobrienmount_nfs_fh(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *mf) 55438494Sobrien{ 55538494Sobrien MTYPE_TYPE type; 55638494Sobrien char *colon; 55738494Sobrien char *xopts; 55838494Sobrien char host[MAXHOSTNAMELEN + MAXPATHLEN + 2]; 55938494Sobrien fserver *fs = mf->mf_server; 56038494Sobrien u_long nfs_version = fs->fs_version; 56138494Sobrien char *nfs_proto = fs->fs_proto; /* "tcp" or "udp" */ 56238494Sobrien int error; 56338494Sobrien int genflags; 56438494Sobrien int retry; 56538494Sobrien mntent_t mnt; 56638494Sobrien nfs_args_t nfs_args; 56738494Sobrien 56838494Sobrien /* 56938494Sobrien * Extract HOST name to give to kernel. 57038494Sobrien * Some systems like osf1/aix3/bsd44 variants may need old code 57138494Sobrien * for NFS_ARGS_NEEDS_PATH. 57238494Sobrien */ 57338494Sobrien if (!(colon = strchr(fs_name, ':'))) 57438494Sobrien return ENOENT; 57538494Sobrien#ifdef MOUNT_TABLE_ON_FILE 57638494Sobrien *colon = '\0'; 57738494Sobrien#endif /* MOUNT_TABLE_ON_FILE */ 57838494Sobrien strncpy(host, fs_name, sizeof(host)); 57938494Sobrien#ifdef MOUNT_TABLE_ON_FILE 58038494Sobrien *colon = ':'; 58138494Sobrien#endif /* MOUNT_TABLE_ON_FILE */ 58238494Sobrien#ifdef MAXHOSTNAMELEN 58338494Sobrien /* most kernels have a name length restriction */ 58438494Sobrien if (strlen(host) >= MAXHOSTNAMELEN) 58538494Sobrien strcpy(host + MAXHOSTNAMELEN - 3, ".."); 58638494Sobrien#endif /* MAXHOSTNAMELEN */ 58738494Sobrien 58851292Sobrien if (mf->mf_remopts && *mf->mf_remopts && 58951292Sobrien !islocalnet(fs->fs_ip->sin_addr.s_addr)) { 59051292Sobrien plog(XLOG_INFO, "Using remopts=\"%s\"", mf->mf_remopts); 59138494Sobrien xopts = strdup(mf->mf_remopts); 59251292Sobrien } else { 59338494Sobrien xopts = strdup(opts); 59451292Sobrien } 59538494Sobrien 59638494Sobrien memset((voidp) &mnt, 0, sizeof(mnt)); 59738494Sobrien mnt.mnt_dir = dir; 59838494Sobrien mnt.mnt_fsname = fs_name; 59938494Sobrien mnt.mnt_opts = xopts; 60038494Sobrien 60138494Sobrien /* 60238494Sobrien * Set mount types accordingly 60338494Sobrien */ 60438494Sobrien#ifndef HAVE_FS_NFS3 60538494Sobrien type = MOUNT_TYPE_NFS; 60638494Sobrien mnt.mnt_type = MNTTAB_TYPE_NFS; 60738494Sobrien#else /* HAVE_FS_NFS3 */ 60838494Sobrien if (nfs_version == NFS_VERSION3) { 60938494Sobrien type = MOUNT_TYPE_NFS3; 61038494Sobrien /* 61138494Sobrien * Systems that include the mount table "vers" option generally do not 61238494Sobrien * set the mnttab entry to "nfs3", but to "nfs" and then they set 61338494Sobrien * "vers=3". Setting it to "nfs3" works, but it may break some things 61438494Sobrien * like "df -t nfs" and the "quota" program (esp. on Solaris and Irix). 61538494Sobrien * So on those systems, set it to "nfs". 61638494Sobrien * Note: MNTTAB_OPT_VERS is always set for NFS3 (see am_compat.h). 61738494Sobrien */ 61838494Sobrien# if defined(MNTTAB_OPT_VERS) && defined(MOUNT_TABLE_ON_FILE) 61938494Sobrien mnt.mnt_type = MNTTAB_TYPE_NFS; 62038494Sobrien# else /* defined(MNTTAB_OPT_VERS) && defined(MOUNT_TABLE_ON_FILE) */ 62138494Sobrien mnt.mnt_type = MNTTAB_TYPE_NFS3; 62238494Sobrien# endif /* defined(MNTTAB_OPT_VERS) && defined(MOUNT_TABLE_ON_FILE) */ 62338494Sobrien } else { 62438494Sobrien type = MOUNT_TYPE_NFS; 62538494Sobrien mnt.mnt_type = MNTTAB_TYPE_NFS; 62638494Sobrien } 62738494Sobrien#endif /* HAVE_FS_NFS3 */ 62851292Sobrien plog(XLOG_INFO, "mount_nfs_fh: NFS version %d", (int) nfs_version); 62938494Sobrien#if defined(HAVE_FS_NFS3) || defined(HAVE_TRANSPORT_TYPE_TLI) 63038494Sobrien plog(XLOG_INFO, "mount_nfs_fh: using NFS transport %s", nfs_proto); 63138494Sobrien#endif /* defined(HAVE_FS_NFS3) || defined(HAVE_TRANSPORT_TYPE_TLI) */ 63238494Sobrien 63338494Sobrien retry = hasmntval(&mnt, MNTTAB_OPT_RETRY); 63438494Sobrien if (retry <= 0) 63538494Sobrien retry = 1; /* XXX */ 63638494Sobrien 63738494Sobrien genflags = compute_mount_flags(&mnt); 63838494Sobrien 63938494Sobrien /* setup the many fields and flags within nfs_args */ 64038494Sobrien#ifdef HAVE_TRANSPORT_TYPE_TLI 64138494Sobrien compute_nfs_args(&nfs_args, 64238494Sobrien &mnt, 64338494Sobrien genflags, 64438494Sobrien NULL, /* struct netconfig *nfsncp */ 64538494Sobrien fs->fs_ip, 64638494Sobrien nfs_version, 64738494Sobrien nfs_proto, 64838494Sobrien fhp, 64938494Sobrien host, 65038494Sobrien fs_name); 65138494Sobrien#else /* not HAVE_TRANSPORT_TYPE_TLI */ 65238494Sobrien compute_nfs_args(&nfs_args, 65338494Sobrien &mnt, 65438494Sobrien genflags, 65538494Sobrien fs->fs_ip, 65638494Sobrien nfs_version, 65738494Sobrien nfs_proto, 65838494Sobrien fhp, 65938494Sobrien host, 66038494Sobrien fs_name); 66138494Sobrien#endif /* not HAVE_TRANSPORT_TYPE_TLI */ 66238494Sobrien 66338494Sobrien /* finally call the mounting function */ 66438494Sobrien#ifdef DEBUG 66551292Sobrien amuDebug(D_TRACE) { 66638494Sobrien print_nfs_args(&nfs_args, nfs_version); 66751292Sobrien plog(XLOG_DEBUG, "Generic mount flags 0x%x", genflags); 66851292Sobrien } 66938494Sobrien#endif /* DEBUG */ 67038494Sobrien error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 67138494Sobrien nfs_version, nfs_proto, mnttab_file_name); 67238494Sobrien XFREE(xopts); 67338494Sobrien 67438494Sobrien#ifdef HAVE_TRANSPORT_TYPE_TLI 67538494Sobrien free_knetconfig(nfs_args.knconf); 67638494Sobrien if (nfs_args.addr) 67738494Sobrien XFREE(nfs_args.addr); /* allocated in compute_nfs_args() */ 67838494Sobrien#endif /* HAVE_TRANSPORT_TYPE_TLI */ 67938494Sobrien 68038494Sobrien return error; 68138494Sobrien} 68238494Sobrien 68338494Sobrien 68438494Sobrienstatic int 68538494Sobrienmount_nfs(char *dir, char *fs_name, char *opts, mntfs *mf) 68638494Sobrien{ 68738494Sobrien if (!mf->mf_private) { 68838494Sobrien plog(XLOG_ERROR, "Missing filehandle for %s", fs_name); 68938494Sobrien return EINVAL; 69038494Sobrien } 69138494Sobrien 69238494Sobrien return mount_nfs_fh((am_nfs_handle_t *) mf->mf_private, dir, fs_name, opts, mf); 69338494Sobrien} 69438494Sobrien 69538494Sobrien 69638494Sobrienint 69738494Sobriennfs_fmount(mntfs *mf) 69838494Sobrien{ 69938494Sobrien int error = 0; 70038494Sobrien 70138494Sobrien error = mount_nfs(mf->mf_mount, mf->mf_info, mf->mf_mopts, mf); 70238494Sobrien 70338494Sobrien#ifdef DEBUG 70438494Sobrien if (error) { 70538494Sobrien errno = error; 70638494Sobrien dlog("mount_nfs: %m"); 70738494Sobrien } 70838494Sobrien#endif /* DEBUG */ 70938494Sobrien 71038494Sobrien return error; 71138494Sobrien} 71238494Sobrien 71338494Sobrien 71438494Sobrienint 71538494Sobriennfs_fumount(mntfs *mf) 71638494Sobrien{ 71738494Sobrien int error = UMOUNT_FS(mf->mf_mount, mnttab_file_name); 71838494Sobrien 71938494Sobrien /* 72038494Sobrien * Here is some code to unmount 'restarted' file systems. 72138494Sobrien * The restarted file systems are marked as 'nfs', not 72238494Sobrien * 'host', so we only have the map information for the 72338494Sobrien * the top-level mount. The unmount will fail (EBUSY) 72438494Sobrien * if there are anything else from the NFS server mounted 72538494Sobrien * below the mount-point. This code checks to see if there 72638494Sobrien * is anything mounted with the same prefix as the 72738494Sobrien * file system to be unmounted ("/a/b/c" when unmounting "/a/b"). 72838494Sobrien * If there is, and it is a 'restarted' file system, we unmount 72938494Sobrien * it. 73038494Sobrien * Added by Mike Mitchell, mcm@unx.sas.com, 09/08/93 73138494Sobrien */ 73238494Sobrien if (error == EBUSY) { 73338494Sobrien mntfs *new_mf; 73438494Sobrien int len = strlen(mf->mf_mount); 73538494Sobrien int didsome = 0; 73638494Sobrien 73738494Sobrien ITER(new_mf, mntfs, &mfhead) { 73838494Sobrien if (new_mf->mf_ops != mf->mf_ops || 73938494Sobrien new_mf->mf_refc > 1 || 74038494Sobrien mf == new_mf || 74138494Sobrien ((new_mf->mf_flags & (MFF_MOUNTED | MFF_UNMOUNTING | MFF_RESTART)) == (MFF_MOUNTED | MFF_RESTART))) 74238494Sobrien continue; 74338494Sobrien 74438494Sobrien if (NSTREQ(mf->mf_mount, new_mf->mf_mount, len) && 74538494Sobrien new_mf->mf_mount[len] == '/') { 74638494Sobrien UMOUNT_FS(new_mf->mf_mount, mnttab_file_name); 74738494Sobrien didsome = 1; 74838494Sobrien } 74938494Sobrien } 75038494Sobrien if (didsome) 75138494Sobrien error = UMOUNT_FS(mf->mf_mount, mnttab_file_name); 75238494Sobrien } 75338494Sobrien if (error) 75438494Sobrien return error; 75538494Sobrien 75638494Sobrien return 0; 75738494Sobrien} 75838494Sobrien 75938494Sobrien 76038494Sobrienvoid 76138494Sobriennfs_umounted(am_node *mp) 76238494Sobrien{ 76338494Sobrien /* 76438494Sobrien * Don't bother to inform remote mountd that we are finished. Until a 76538494Sobrien * full track of filehandles is maintained the mountd unmount callback 76638494Sobrien * cannot be done correctly anyway... 76738494Sobrien */ 76838494Sobrien mntfs *mf = mp->am_mnt; 76938494Sobrien fserver *fs; 77038494Sobrien char *colon, *path; 77138494Sobrien 77238494Sobrien if (mf->mf_error || mf->mf_refc > 1) 77338494Sobrien return; 77438494Sobrien 77538494Sobrien fs = mf->mf_server; 77638494Sobrien 77738494Sobrien /* 77838494Sobrien * Call the mount daemon on the server to announce that we are not using 77938494Sobrien * the fs any more. 78038494Sobrien * 78138494Sobrien * This is *wrong*. The mountd should be called when the fhandle is 78238494Sobrien * flushed from the cache, and a reference held to the cached entry while 78338494Sobrien * the fs is mounted... 78438494Sobrien */ 78538494Sobrien colon = path = strchr(mf->mf_info, ':'); 78638494Sobrien if (fs && colon) { 78738494Sobrien fh_cache f; 78838494Sobrien 78938494Sobrien#ifdef DEBUG 79038494Sobrien dlog("calling mountd for %s", mf->mf_info); 79138494Sobrien#endif /* DEBUG */ 79238494Sobrien *path++ = '\0'; 79338494Sobrien f.fh_path = path; 79438494Sobrien f.fh_sin = *fs->fs_ip; 79538494Sobrien f.fh_sin.sin_port = (u_short) 0; 79638494Sobrien f.fh_nfs_version = fs->fs_version; 79738494Sobrien f.fh_fs = fs; 79838494Sobrien f.fh_id = 0; 79938494Sobrien f.fh_error = 0; 80038494Sobrien prime_nfs_fhandle_cache(colon + 1, mf->mf_server, (am_nfs_handle_t *) 0, (voidp) mf); 80138494Sobrien call_mountd(&f, MOUNTPROC_UMNT, (fwd_fun) 0, (voidp) 0); 80238494Sobrien *colon = ':'; 80338494Sobrien } 80438494Sobrien} 805