xref: /original-bsd/usr.sbin/amd/amd/nfs_ops.c (revision 065e4d72)
1476d7312Sbostic /*-
2398a5aebSmckusick  * Copyright (c) 1990 Jan-Simon Pendry
3398a5aebSmckusick  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
44092c5ccSbostic  * Copyright (c) 1990, 1993
54092c5ccSbostic  *	The Regents of the University of California.  All rights reserved.
6398a5aebSmckusick  *
7398a5aebSmckusick  * This code is derived from software contributed to Berkeley by
8398a5aebSmckusick  * Jan-Simon Pendry at Imperial College, London.
9398a5aebSmckusick  *
10398a5aebSmckusick  * %sccs.include.redist.c%
11398a5aebSmckusick  *
1210042f30Spendry  * $Id: nfs_ops.c,v 5.2.2.2 1992/05/31 16:35:05 jsp Exp $
13398a5aebSmckusick  */
14398a5aebSmckusick 
15476d7312Sbostic #ifndef lint
16*065e4d72Spendry static char sccsid[] = "@(#)nfs_ops.c	8.2 (Berkeley) 05/10/95";
17476d7312Sbostic #endif /* not lint */
18476d7312Sbostic 
19398a5aebSmckusick #include "am.h"
2010042f30Spendry #include <sys/stat.h>
21398a5aebSmckusick 
22398a5aebSmckusick #ifdef HAS_NFS
23398a5aebSmckusick 
24398a5aebSmckusick #define NFS
25398a5aebSmckusick #define NFSCLIENT
26398a5aebSmckusick #ifdef NFS_3
27398a5aebSmckusick typedef nfs_fh fhandle_t;
28398a5aebSmckusick #endif /* NFS_3 */
29*065e4d72Spendry #include <sys/mount.h>
30398a5aebSmckusick #ifdef NFS_HDR
31398a5aebSmckusick #include NFS_HDR
32398a5aebSmckusick #endif /* NFS_HDR */
33398a5aebSmckusick #include "mount.h"
34398a5aebSmckusick 
35398a5aebSmckusick /*
36398a5aebSmckusick  * Network file system
37398a5aebSmckusick  */
38398a5aebSmckusick 
39398a5aebSmckusick /*
40398a5aebSmckusick  * Convert from nfsstat to UN*X error code
41398a5aebSmckusick  */
42398a5aebSmckusick #define unx_error(e)	((int)(e))
43398a5aebSmckusick 
44398a5aebSmckusick /*
45398a5aebSmckusick  * The NFS layer maintains a cache of file handles.
46398a5aebSmckusick  * This is *fundamental* to the implementation and
47398a5aebSmckusick  * also allows quick remounting when a filesystem
48398a5aebSmckusick  * is accessed soon after timing out.
49398a5aebSmckusick  *
50398a5aebSmckusick  * The NFS server layer knows to flush this cache
51398a5aebSmckusick  * when a server goes down so avoiding stale handles.
52398a5aebSmckusick  *
53398a5aebSmckusick  * Each cache entry keeps a hard reference to
54398a5aebSmckusick  * the corresponding server.  This ensures that
55398a5aebSmckusick  * the server keepalive information is maintained.
56398a5aebSmckusick  *
57398a5aebSmckusick  * The copy of the sockaddr_in here is taken so
58398a5aebSmckusick  * that the port can be twiddled to talk to mountd
59398a5aebSmckusick  * instead of portmap or the NFS server as used
60398a5aebSmckusick  * elsewhere.
61398a5aebSmckusick  * The port# is flushed if a server goes down.
62398a5aebSmckusick  * The IP address is never flushed - we assume
63398a5aebSmckusick  * that the address of a mounted machine never
64398a5aebSmckusick  * changes.  If it does, then you have other
65398a5aebSmckusick  * problems...
66398a5aebSmckusick  */
67398a5aebSmckusick typedef struct fh_cache fh_cache;
68398a5aebSmckusick struct fh_cache {
69398a5aebSmckusick 	qelem	fh_q;			/* List header */
70398a5aebSmckusick 	voidp	fh_wchan;		/* Wait channel */
71398a5aebSmckusick 	int	fh_error;		/* Valid data? */
72398a5aebSmckusick 	int	fh_id;			/* Unique id */
73398a5aebSmckusick 	int	fh_cid;			/* Callout id */
74398a5aebSmckusick 	struct fhstatus fh_handle;	/* Handle on filesystem */
75398a5aebSmckusick 	struct sockaddr_in fh_sin;	/* Address of mountd */
76398a5aebSmckusick 	fserver *fh_fs;			/* Server holding filesystem */
77398a5aebSmckusick 	char	*fh_path;		/* Filesystem on host */
78398a5aebSmckusick };
79398a5aebSmckusick 
80398a5aebSmckusick /*
81398a5aebSmckusick  * FH_TTL is the time a file handle will remain in the cache since
82398a5aebSmckusick  * last being used.  If the file handle becomes invalid, then it
83398a5aebSmckusick  * will be flushed anyway.
84398a5aebSmckusick  */
85398a5aebSmckusick #define	FH_TTL		(5 * 60)		/* five minutes */
86398a5aebSmckusick #define	FH_TTL_ERROR	(30)			/* 30 seconds */
87398a5aebSmckusick 
88398a5aebSmckusick static int fh_id = 0;
89398a5aebSmckusick #define	FHID_ALLOC()	(++fh_id)
90398a5aebSmckusick extern qelem fh_head;
91398a5aebSmckusick qelem fh_head = { &fh_head, &fh_head };
92398a5aebSmckusick 
93398a5aebSmckusick static int call_mountd P((fh_cache*, unsigned long, fwd_fun, voidp));
94398a5aebSmckusick 
95398a5aebSmckusick AUTH *nfs_auth;
96398a5aebSmckusick 
97398a5aebSmckusick static fh_cache *find_nfs_fhandle_cache P((voidp idv, int done));
find_nfs_fhandle_cache(idv,done)98398a5aebSmckusick static fh_cache *find_nfs_fhandle_cache(idv, done)
99398a5aebSmckusick voidp idv;
100398a5aebSmckusick int done;
101398a5aebSmckusick {
102398a5aebSmckusick 	fh_cache *fp, *fp2 = 0;
103398a5aebSmckusick 	int id = (int) idv;
104398a5aebSmckusick 
105398a5aebSmckusick 	ITER(fp, fh_cache, &fh_head) {
106398a5aebSmckusick 		if (fp->fh_id == id) {
107398a5aebSmckusick 			fp2 = fp;
108398a5aebSmckusick 			break;
109398a5aebSmckusick 		}
110398a5aebSmckusick 	}
111398a5aebSmckusick 
112398a5aebSmckusick #ifdef DEBUG
113398a5aebSmckusick 	if (fp2) {
114398a5aebSmckusick 		dlog("fh cache gives fp %#x, fs %s", fp2, fp2->fh_path);
115398a5aebSmckusick 	} else {
116398a5aebSmckusick 		dlog("fh cache search failed");
117398a5aebSmckusick 	}
118398a5aebSmckusick #endif /* DEBUG */
119398a5aebSmckusick 
120398a5aebSmckusick 	if (fp2 && !done) {
121398a5aebSmckusick 		fp2->fh_error = ETIMEDOUT;
122398a5aebSmckusick 		return 0;
123398a5aebSmckusick 	}
124398a5aebSmckusick 
125398a5aebSmckusick 	return fp2;
126398a5aebSmckusick }
127398a5aebSmckusick 
128398a5aebSmckusick /*
129398a5aebSmckusick  * Called when a filehandle appears
130398a5aebSmckusick  */
131398a5aebSmckusick static void got_nfs_fh P((voidp pkt, int len, struct sockaddr_in *sa,
132398a5aebSmckusick 				struct sockaddr_in *ia, voidp idv, int done));
got_nfs_fh(pkt,len,sa,ia,idv,done)133398a5aebSmckusick static void got_nfs_fh(pkt, len, sa, ia, idv, done)
134398a5aebSmckusick voidp pkt;
135398a5aebSmckusick int len;
136398a5aebSmckusick struct sockaddr_in *sa, *ia;
137398a5aebSmckusick voidp idv;
138398a5aebSmckusick int done;
139398a5aebSmckusick {
140398a5aebSmckusick 	fh_cache *fp = find_nfs_fhandle_cache(idv, done);
141398a5aebSmckusick 	if (fp) {
142398a5aebSmckusick 		fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &fp->fh_handle, xdr_fhstatus);
143398a5aebSmckusick 		if (!fp->fh_error) {
144398a5aebSmckusick #ifdef DEBUG
145398a5aebSmckusick 			dlog("got filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
146398a5aebSmckusick #endif /* DEBUG */
147398a5aebSmckusick 			/*
148398a5aebSmckusick 			 * Wakeup anything sleeping on this filehandle
149398a5aebSmckusick 			 */
150398a5aebSmckusick 			if (fp->fh_wchan) {
151398a5aebSmckusick #ifdef DEBUG
152398a5aebSmckusick 				dlog("Calling wakeup on %#x", fp->fh_wchan);
153398a5aebSmckusick #endif /* DEBUG */
154398a5aebSmckusick 				wakeup(fp->fh_wchan);
155398a5aebSmckusick 			}
156398a5aebSmckusick 		}
157398a5aebSmckusick 	}
158398a5aebSmckusick }
159398a5aebSmckusick 
160398a5aebSmckusick void flush_nfs_fhandle_cache P((fserver *fs));
flush_nfs_fhandle_cache(fs)161398a5aebSmckusick void flush_nfs_fhandle_cache(fs)
162398a5aebSmckusick fserver *fs;
163398a5aebSmckusick {
164398a5aebSmckusick 	fh_cache *fp;
165398a5aebSmckusick 	ITER(fp, fh_cache, &fh_head) {
1668a89c22cSpendry 		if (fp->fh_fs == fs || fs == 0) {
167398a5aebSmckusick 			fp->fh_sin.sin_port = (u_short) 0;
168398a5aebSmckusick 			fp->fh_error = -1;
169398a5aebSmckusick 		}
170398a5aebSmckusick 	}
171398a5aebSmckusick }
172398a5aebSmckusick 
173398a5aebSmckusick static void discard_fh P((fh_cache *fp));
discard_fh(fp)174398a5aebSmckusick static void discard_fh(fp)
175398a5aebSmckusick fh_cache *fp;
176398a5aebSmckusick {
177398a5aebSmckusick 	rem_que(&fp->fh_q);
178398a5aebSmckusick #ifdef DEBUG
179398a5aebSmckusick 	dlog("Discarding filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
180398a5aebSmckusick #endif /* DEBUG */
181398a5aebSmckusick 	free_srvr(fp->fh_fs);
182398a5aebSmckusick 	free((voidp) fp->fh_path);
183398a5aebSmckusick 	free((voidp) fp);
184398a5aebSmckusick }
185398a5aebSmckusick 
186398a5aebSmckusick /*
187398a5aebSmckusick  * Determine the file handle for a node
188398a5aebSmckusick  */
189398a5aebSmckusick static int prime_nfs_fhandle_cache P((char *path, fserver *fs, struct fhstatus *fhbuf, voidp wchan));
prime_nfs_fhandle_cache(path,fs,fhbuf,wchan)190398a5aebSmckusick static int prime_nfs_fhandle_cache(path, fs, fhbuf, wchan)
191398a5aebSmckusick char *path;
192398a5aebSmckusick fserver *fs;
193398a5aebSmckusick struct fhstatus *fhbuf;
194398a5aebSmckusick voidp wchan;
195398a5aebSmckusick {
196398a5aebSmckusick 	fh_cache *fp, *fp_save = 0;
197398a5aebSmckusick 	int error;
198398a5aebSmckusick 	int reuse_id = FALSE;
199398a5aebSmckusick 
200398a5aebSmckusick #ifdef DEBUG
201398a5aebSmckusick 	dlog("Searching cache for %s:%s", fs->fs_host, path);
202398a5aebSmckusick #endif /* DEBUG */
203398a5aebSmckusick 
204398a5aebSmckusick 	/*
205398a5aebSmckusick 	 * First search the cache
206398a5aebSmckusick 	 */
207398a5aebSmckusick 	ITER(fp, fh_cache, &fh_head) {
208398a5aebSmckusick 		if (fs == fp->fh_fs && strcmp(path, fp->fh_path) == 0) {
209398a5aebSmckusick 			switch (fp->fh_error) {
210398a5aebSmckusick 			case 0:
211398a5aebSmckusick 				error = fp->fh_error = unx_error(fp->fh_handle.fhs_status);
212398a5aebSmckusick 				if (error == 0) {
213398a5aebSmckusick 					if (fhbuf)
214398a5aebSmckusick 						bcopy((voidp) &fp->fh_handle, (voidp) fhbuf,
215398a5aebSmckusick 							sizeof(fp->fh_handle));
216398a5aebSmckusick 					if (fp->fh_cid)
217398a5aebSmckusick 						untimeout(fp->fh_cid);
218398a5aebSmckusick 					fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp);
219398a5aebSmckusick 				} else if (error == EACCES) {
220398a5aebSmckusick 					/*
221398a5aebSmckusick 					 * Now decode the file handle return code.
222398a5aebSmckusick 					 */
223398a5aebSmckusick 					plog(XLOG_INFO, "Filehandle denied for \"%s:%s\"",
224398a5aebSmckusick 						fs->fs_host, path);
225398a5aebSmckusick 				} else {
226398a5aebSmckusick 					errno = error;	/* XXX */
227398a5aebSmckusick 					plog(XLOG_INFO, "Filehandle error for \"%s:%s\": %m",
228398a5aebSmckusick 						fs->fs_host, path);
229398a5aebSmckusick 				}
230398a5aebSmckusick 
231398a5aebSmckusick 				/*
232398a5aebSmckusick 				 * The error was returned from the remote mount daemon.
233398a5aebSmckusick 				 * Policy: this error will be cached for now...
234398a5aebSmckusick 				 */
235398a5aebSmckusick 				return error;
236398a5aebSmckusick 
237398a5aebSmckusick 			case -1:
238398a5aebSmckusick 				/*
239398a5aebSmckusick 				 * Still thinking about it, but we can re-use.
240398a5aebSmckusick 				 */
241398a5aebSmckusick 				fp_save = fp;
242398a5aebSmckusick 				reuse_id = TRUE;
243398a5aebSmckusick 				break;
244398a5aebSmckusick 
245398a5aebSmckusick 			default:
246398a5aebSmckusick 				/*
247398a5aebSmckusick 				 * Return the error.
248398a5aebSmckusick 				 * Policy: make sure we recompute if required again
249398a5aebSmckusick 				 * in case this was caused by a network failure.
250398a5aebSmckusick 				 * This can thrash mountd's though...  If you find
251398a5aebSmckusick 				 * your mountd going slowly then:
252398a5aebSmckusick 				 * 1.  Add a fork() loop to main.
253398a5aebSmckusick 				 * 2.  Remove the call to innetgr() and don't use
254398a5aebSmckusick 				 *     netgroups, especially if you don't use YP.
255398a5aebSmckusick 				 */
256398a5aebSmckusick 				error = fp->fh_error;
257398a5aebSmckusick 				fp->fh_error = -1;
258398a5aebSmckusick 				return error;
259398a5aebSmckusick 			}
260398a5aebSmckusick 			break;
261398a5aebSmckusick 		}
262398a5aebSmckusick 	}
263398a5aebSmckusick 
264398a5aebSmckusick 	/*
265398a5aebSmckusick 	 * Not in cache
266398a5aebSmckusick 	 */
267398a5aebSmckusick 	if (fp_save) {
268398a5aebSmckusick 		fp = fp_save;
269398a5aebSmckusick 		/*
270398a5aebSmckusick 		 * Re-use existing slot
271398a5aebSmckusick 		 */
272398a5aebSmckusick 		untimeout(fp->fh_cid);
273398a5aebSmckusick 		free_srvr(fp->fh_fs);
274398a5aebSmckusick 		free(fp->fh_path);
275398a5aebSmckusick 	} else {
276398a5aebSmckusick 		fp = ALLOC(fh_cache);
277398a5aebSmckusick 		bzero((voidp) fp, sizeof(*fp));
278398a5aebSmckusick 		ins_que(&fp->fh_q, &fh_head);
279398a5aebSmckusick 	}
280398a5aebSmckusick 	if (!reuse_id)
281398a5aebSmckusick 		fp->fh_id = FHID_ALLOC();
282398a5aebSmckusick 	fp->fh_wchan = wchan;
283398a5aebSmckusick 	fp->fh_error = -1;
284398a5aebSmckusick 	fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp);
285398a5aebSmckusick 
286398a5aebSmckusick 	/*
287398a5aebSmckusick 	 * If the address has changed then don't try to re-use the
288398a5aebSmckusick 	 * port information
289398a5aebSmckusick 	 */
290398a5aebSmckusick 	if (fp->fh_sin.sin_addr.s_addr != fs->fs_ip->sin_addr.s_addr) {
291398a5aebSmckusick 		fp->fh_sin = *fs->fs_ip;
292398a5aebSmckusick 		fp->fh_sin.sin_port = 0;
293398a5aebSmckusick 	}
294398a5aebSmckusick 	fp->fh_fs = dup_srvr(fs);
295398a5aebSmckusick 	fp->fh_path = strdup(path);
296398a5aebSmckusick 
297398a5aebSmckusick 	error = call_mountd(fp, MOUNTPROC_MNT, got_nfs_fh, wchan);
298398a5aebSmckusick 	if (error) {
299398a5aebSmckusick 		/*
300398a5aebSmckusick 		 * Local error - cache for a short period
301398a5aebSmckusick 		 * just to prevent thrashing.
302398a5aebSmckusick 		 */
303398a5aebSmckusick 		untimeout(fp->fh_cid);
304398a5aebSmckusick 		fp->fh_cid = timeout(error < 0 ? 2 * ALLOWED_MOUNT_TIME : FH_TTL_ERROR,
305398a5aebSmckusick 						discard_fh, (voidp) fp);
306398a5aebSmckusick 		fp->fh_error = error;
307398a5aebSmckusick 	} else {
308398a5aebSmckusick 		error = fp->fh_error;
309398a5aebSmckusick 	}
310398a5aebSmckusick 	return error;
311398a5aebSmckusick }
312398a5aebSmckusick 
make_nfs_auth(void)313c626267eSpendry int make_nfs_auth P((void))
314c626267eSpendry {
315c626267eSpendry #ifdef HAS_NFS_QUALIFIED_NAMES
316c626267eSpendry 	/*
317c626267eSpendry 	 * From: Chris Metcalf <metcalf@masala.lcs.mit.edu>
318c626267eSpendry 	 * Use hostd, not just hostname.  Note that uids
319c626267eSpendry 	 * and gids and the gidlist are type *int* and not the
320c626267eSpendry 	 * system uid_t and gid_t types.
321c626267eSpendry 	 */
322c626267eSpendry 	static int group_wheel = 0;
323c626267eSpendry 	nfs_auth = authunix_create(hostd, 0, 0, 1, &group_wheel);
324c626267eSpendry #else
325c626267eSpendry 	nfs_auth = authunix_create_default();
326c626267eSpendry #endif
327c626267eSpendry 	if (!nfs_auth)
328c626267eSpendry 		return ENOBUFS;
329c626267eSpendry 	return 0;
330c626267eSpendry }
331c626267eSpendry 
332398a5aebSmckusick static int call_mountd P((fh_cache *fp, u_long proc, fwd_fun f, voidp wchan));
call_mountd(fp,proc,f,wchan)333398a5aebSmckusick static int call_mountd(fp, proc, f, wchan)
334398a5aebSmckusick fh_cache *fp;
335398a5aebSmckusick u_long proc;
336398a5aebSmckusick fwd_fun f;
337398a5aebSmckusick voidp wchan;
338398a5aebSmckusick {
339398a5aebSmckusick 	struct rpc_msg mnt_msg;
340398a5aebSmckusick 	int len;
341398a5aebSmckusick 	char iobuf[8192];
342398a5aebSmckusick 	int error;
343398a5aebSmckusick 
344398a5aebSmckusick 	if (!nfs_auth) {
345c626267eSpendry 		error = make_nfs_auth();
346c626267eSpendry 		if (error)
347c626267eSpendry 			return error;
348398a5aebSmckusick 	}
349398a5aebSmckusick 
350398a5aebSmckusick 	if (fp->fh_sin.sin_port == 0) {
351398a5aebSmckusick 		u_short port;
352398a5aebSmckusick 		error = nfs_srvr_port(fp->fh_fs, &port, wchan);
353398a5aebSmckusick 		if (error)
354398a5aebSmckusick 			return error;
355398a5aebSmckusick 		fp->fh_sin.sin_port = port;
356398a5aebSmckusick 	}
357398a5aebSmckusick 
358398a5aebSmckusick 	rpc_msg_init(&mnt_msg, MOUNTPROG, MOUNTVERS, (unsigned long) 0);
359398a5aebSmckusick 	len = make_rpc_packet(iobuf, sizeof(iobuf), proc,
360398a5aebSmckusick 			&mnt_msg, (voidp) &fp->fh_path, xdr_nfspath,  nfs_auth);
361398a5aebSmckusick 
362398a5aebSmckusick 	if (len > 0) {
363398a5aebSmckusick 		error = fwd_packet(MK_RPC_XID(RPC_XID_MOUNTD, fp->fh_id),
364398a5aebSmckusick 			(voidp) iobuf, len, &fp->fh_sin, &fp->fh_sin, (voidp) fp->fh_id, f);
365398a5aebSmckusick 	} else {
366398a5aebSmckusick 		error = -len;
367398a5aebSmckusick 	}
36810042f30Spendry /*
36910042f30Spendry  * It may be the case that we're sending to the wrong MOUNTD port.  This
37010042f30Spendry  * occurs if mountd is restarted on the server after the port has been
37110042f30Spendry  * looked up and stored in the filehandle cache somewhere.  The correct
37210042f30Spendry  * solution, if we're going to cache port numbers is to catch the ICMP
37310042f30Spendry  * port unreachable reply from the server and cause the portmap request
37410042f30Spendry  * to be redone.  The quick solution here is to invalidate the MOUNTD
37510042f30Spendry  * port.
37610042f30Spendry  */
37710042f30Spendry       fp->fh_sin.sin_port = 0;
37810042f30Spendry 
379398a5aebSmckusick 	return error;
380398a5aebSmckusick }
381398a5aebSmckusick 
382398a5aebSmckusick /*-------------------------------------------------------------------------*/
383398a5aebSmckusick 
384398a5aebSmckusick /*
385398a5aebSmckusick  * NFS needs the local filesystem, remote filesystem
386398a5aebSmckusick  * remote hostname.
387398a5aebSmckusick  * Local filesystem defaults to remote and vice-versa.
388398a5aebSmckusick  */
nfs_match(fo)3898a89c22cSpendry static char *nfs_match(fo)
390398a5aebSmckusick am_opts *fo;
391398a5aebSmckusick {
3928a89c22cSpendry 	char *xmtab;
393398a5aebSmckusick 	if (fo->opt_fs && !fo->opt_rfs)
394398a5aebSmckusick 		fo->opt_rfs = fo->opt_fs;
395398a5aebSmckusick 	if (!fo->opt_rfs) {
396398a5aebSmckusick 		plog(XLOG_USER, "nfs: no remote filesystem specified");
397398a5aebSmckusick 		return FALSE;
398398a5aebSmckusick 	}
399398a5aebSmckusick 	if (!fo->opt_rhost) {
400398a5aebSmckusick 		plog(XLOG_USER, "nfs: no remote host specified");
401398a5aebSmckusick 		return FALSE;
402398a5aebSmckusick 	}
403398a5aebSmckusick 	/*
404398a5aebSmckusick 	 * Determine magic cookie to put in mtab
405398a5aebSmckusick 	 */
4068a89c22cSpendry 	xmtab = (char *) xmalloc(strlen(fo->opt_rhost) + strlen(fo->opt_rfs) + 2);
4078a89c22cSpendry 	sprintf(xmtab, "%s:%s", fo->opt_rhost, fo->opt_rfs);
408398a5aebSmckusick #ifdef DEBUG
409398a5aebSmckusick 	dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"",
410398a5aebSmckusick 		fo->opt_rhost, fo->opt_rfs, fo->opt_fs);
411398a5aebSmckusick #endif /* DEBUG */
412398a5aebSmckusick 
4138a89c22cSpendry 	return xmtab;
414398a5aebSmckusick }
415398a5aebSmckusick 
416398a5aebSmckusick /*
417398a5aebSmckusick  * Initialise am structure for nfs
418398a5aebSmckusick  */
nfs_init(mf)419398a5aebSmckusick static int nfs_init(mf)
420398a5aebSmckusick mntfs *mf;
421398a5aebSmckusick {
4228a89c22cSpendry 	if (!mf->mf_private) {
423398a5aebSmckusick 		int error;
4248a89c22cSpendry 		struct fhstatus fhs;
4258a89c22cSpendry 
426398a5aebSmckusick 		char *colon = strchr(mf->mf_info, ':');
427398a5aebSmckusick 		if (colon == 0)
428398a5aebSmckusick 			return ENOENT;
429398a5aebSmckusick 
4308a89c22cSpendry 		error = prime_nfs_fhandle_cache(colon+1, mf->mf_server, &fhs, (voidp) mf);
4318a89c22cSpendry 		if (!error) {
4328a89c22cSpendry 			mf->mf_private = (voidp) ALLOC(fhstatus);
4338a89c22cSpendry 			mf->mf_prfree = (void (*)()) free;
4348a89c22cSpendry 			bcopy((voidp) &fhs, mf->mf_private, sizeof(fhs));
4358a89c22cSpendry 		}
436398a5aebSmckusick 		return error;
437398a5aebSmckusick 	}
438398a5aebSmckusick 
4398a89c22cSpendry 	return 0;
4408a89c22cSpendry }
4418a89c22cSpendry 
442cc0207dcSpendry int mount_nfs_fh P((struct fhstatus *fhp, char *dir, char *fs_name, char *opts, mntfs *mf));
mount_nfs_fh(fhp,dir,fs_name,opts,mf)4438a89c22cSpendry int mount_nfs_fh(fhp, dir, fs_name, opts, mf)
444398a5aebSmckusick struct fhstatus *fhp;
445398a5aebSmckusick char *dir;
446398a5aebSmckusick char *fs_name;
447398a5aebSmckusick char *opts;
448398a5aebSmckusick mntfs *mf;
449398a5aebSmckusick {
450398a5aebSmckusick 	struct nfs_args nfs_args;
451398a5aebSmckusick 	struct mntent mnt;
452398a5aebSmckusick 	int retry;
453398a5aebSmckusick 	char *colon;
4548a89c22cSpendry 	/*char *path;*/
455398a5aebSmckusick 	char host[MAXHOSTNAMELEN + MAXPATHLEN + 2];
456398a5aebSmckusick 	fserver *fs = mf->mf_server;
457398a5aebSmckusick 	int flags;
458cc0207dcSpendry 	char *xopts;
459cc0207dcSpendry 	int error;
460398a5aebSmckusick #ifdef notdef
461398a5aebSmckusick 	unsigned short port;
462398a5aebSmckusick #endif /* notdef */
463398a5aebSmckusick 
464398a5aebSmckusick 	MTYPE_TYPE type = MOUNT_TYPE_NFS;
465398a5aebSmckusick 
466398a5aebSmckusick 	bzero((voidp) &nfs_args, sizeof(nfs_args));	/* Paranoid */
467398a5aebSmckusick 
468398a5aebSmckusick 	/*
469398a5aebSmckusick 	 * Extract host name to give to kernel
470398a5aebSmckusick 	 */
471398a5aebSmckusick 	if (!(colon = strchr(fs_name, ':')))
472398a5aebSmckusick 		return ENOENT;
473398a5aebSmckusick #ifndef NFS_ARGS_NEEDS_PATH
474398a5aebSmckusick 	*colon = '\0';
475398a5aebSmckusick #endif
476398a5aebSmckusick 	strncpy(host, fs_name, sizeof(host));
477398a5aebSmckusick #ifndef NFS_ARGS_NEEDS_PATH
478398a5aebSmckusick 	*colon = ':';
479398a5aebSmckusick #endif /* NFS_ARGS_NEEDS_PATH */
4808a89c22cSpendry 	/*path = colon + 1;*/
481398a5aebSmckusick 
482cc0207dcSpendry 	if (mf->mf_remopts && *mf->mf_remopts && !islocalnet(fs->fs_ip->sin_addr.s_addr))
483cc0207dcSpendry 		xopts = strdup(mf->mf_remopts);
484cc0207dcSpendry 	else
485cc0207dcSpendry 		xopts = strdup(opts);
486cc0207dcSpendry 
487398a5aebSmckusick 	mnt.mnt_dir = dir;
488398a5aebSmckusick 	mnt.mnt_fsname = fs_name;
489398a5aebSmckusick 	mnt.mnt_type = MTAB_TYPE_NFS;
490cc0207dcSpendry 	mnt.mnt_opts = xopts;
491398a5aebSmckusick 	mnt.mnt_freq = 0;
492398a5aebSmckusick 	mnt.mnt_passno = 0;
493398a5aebSmckusick 
494398a5aebSmckusick 	retry = hasmntval(&mnt, "retry");
495398a5aebSmckusick 	if (retry <= 0)
496398a5aebSmckusick 		retry = 1;	/* XXX */
497398a5aebSmckusick 
498398a5aebSmckusick /*again:*/
499398a5aebSmckusick 
500398a5aebSmckusick 	/*
501398a5aebSmckusick 	 * set mount args
502398a5aebSmckusick 	 */
503*065e4d72Spendry #ifdef NFS_ARGSVERSION
504*065e4d72Spendry 	nfs_args.version = NFS_ARGSVERSION;
505*065e4d72Spendry #endif
506*065e4d72Spendry 
507398a5aebSmckusick 	NFS_FH_DREF(nfs_args.fh, (NFS_FH_TYPE) fhp->fhstatus_u.fhs_fhandle);
508398a5aebSmckusick 
509398a5aebSmckusick #ifdef ULTRIX_HACK
510398a5aebSmckusick 	nfs_args.optstr = mnt.mnt_opts;
511398a5aebSmckusick #endif /* ULTRIX_HACK */
512398a5aebSmckusick 
513398a5aebSmckusick 	nfs_args.hostname = host;
514398a5aebSmckusick 	nfs_args.flags |= NFSMNT_HOSTNAME;
515398a5aebSmckusick #ifdef HOSTNAMESZ
516398a5aebSmckusick 	/*
517398a5aebSmckusick 	 * Most kernels have a name length restriction.
518398a5aebSmckusick 	 */
519398a5aebSmckusick 	if (strlen(host) >= HOSTNAMESZ)
520398a5aebSmckusick 		strcpy(host + HOSTNAMESZ - 3, "..");
521398a5aebSmckusick #endif /* HOSTNAMESZ */
522398a5aebSmckusick 
523398a5aebSmckusick 	if (nfs_args.rsize = hasmntval(&mnt, "rsize"))
524398a5aebSmckusick 		nfs_args.flags |= NFSMNT_RSIZE;
525398a5aebSmckusick 
526398a5aebSmckusick 	if (nfs_args.wsize = hasmntval(&mnt, "wsize"))
527398a5aebSmckusick 		nfs_args.flags |= NFSMNT_WSIZE;
528398a5aebSmckusick 
529398a5aebSmckusick 	if (nfs_args.timeo = hasmntval(&mnt, "timeo"))
530398a5aebSmckusick 		nfs_args.flags |= NFSMNT_TIMEO;
531398a5aebSmckusick 
532398a5aebSmckusick 	if (nfs_args.retrans = hasmntval(&mnt, "retrans"))
533398a5aebSmckusick 		nfs_args.flags |= NFSMNT_RETRANS;
534398a5aebSmckusick 
535398a5aebSmckusick #ifdef NFSMNT_BIODS
536398a5aebSmckusick 	if (nfs_args.biods = hasmntval(&mnt, "biods"))
537398a5aebSmckusick 		nfs_args.flags |= NFSMNT_BIODS;
538398a5aebSmckusick 
539398a5aebSmckusick #endif /* NFSMNT_BIODS */
540398a5aebSmckusick 
5413f14a87dShibler #ifdef NFSMNT_MAXGRPS
5423f14a87dShibler 	if (nfs_args.maxgrouplist = hasmntval(&mnt, "maxgroups"))
5433f14a87dShibler 		nfs_args.flags |= NFSMNT_MAXGRPS;
5443f14a87dShibler #endif /* NFSMNT_MAXGRPS */
5453f14a87dShibler 
546398a5aebSmckusick #ifdef notdef
547398a5aebSmckusick /*
548398a5aebSmckusick  * This isn't supported by the ping algorithm yet.
549398a5aebSmckusick  * In any case, it is all done in nfs_init().
550398a5aebSmckusick  */
551398a5aebSmckusick  	if (port = hasmntval(&mnt, "port"))
552398a5aebSmckusick 		sin.sin_port = htons(port);
553398a5aebSmckusick 	else
554398a5aebSmckusick 		sin.sin_port = htons(NFS_PORT);	/* XXX should use portmapper */
555398a5aebSmckusick #endif /* notdef */
556398a5aebSmckusick 
557398a5aebSmckusick 	if (hasmntopt(&mnt, MNTOPT_SOFT) != NULL)
558398a5aebSmckusick 		nfs_args.flags |= NFSMNT_SOFT;
559398a5aebSmckusick 
5608a89c22cSpendry #ifdef NFSMNT_SPONGY
5618a89c22cSpendry 	if (hasmntopt(&mnt, "spongy") != NULL) {
5628a89c22cSpendry 		nfs_args.flags |= NFSMNT_SPONGY;
5638a89c22cSpendry 		if (nfs_args.flags & NFSMNT_SOFT) {
5648a89c22cSpendry 			plog(XLOG_USER, "Mount opts soft and spongy are incompatible - soft ignored");
5658a89c22cSpendry 			nfs_args.flags &= ~NFSMNT_SOFT;
5668a89c22cSpendry 		}
5678a89c22cSpendry 	}
5688a89c22cSpendry #endif /* MNTOPT_SPONGY */
5698a89c22cSpendry 
570398a5aebSmckusick #ifdef MNTOPT_INTR
571398a5aebSmckusick 	if (hasmntopt(&mnt, MNTOPT_INTR) != NULL)
572398a5aebSmckusick 		nfs_args.flags |= NFSMNT_INT;
573398a5aebSmckusick #endif /* MNTOPT_INTR */
574398a5aebSmckusick 
575398a5aebSmckusick #ifdef MNTOPT_NODEVS
576398a5aebSmckusick 	if (hasmntopt(&mnt, MNTOPT_NODEVS) != NULL)
577398a5aebSmckusick 		nfs_args.flags |= NFSMNT_NODEVS;
578398a5aebSmckusick #endif /* MNTOPT_NODEVS */
579398a5aebSmckusick 
5808a89c22cSpendry #ifdef MNTOPT_COMPRESS
5818a89c22cSpendry 	if (hasmntopt(&mnt, "compress") != NULL)
5828a89c22cSpendry 		nfs_args.flags |= NFSMNT_COMPRESS;
5838a89c22cSpendry #endif /* MNTOPT_COMPRESS */
5848a89c22cSpendry 
5858a89c22cSpendry #ifdef MNTOPT_NOCONN
5868a89c22cSpendry 	if (hasmntopt(&mnt, "noconn") != NULL)
5878a89c22cSpendry 		nfs_args.flags |= NFSMNT_NOCONN;
5888a89c22cSpendry #endif /* MNTOPT_NOCONN */
5898a89c22cSpendry 
590398a5aebSmckusick #ifdef NFSMNT_PGTHRESH
591398a5aebSmckusick 	if (nfs_args.pg_thresh = hasmntval(&mnt, "pgthresh"))
592398a5aebSmckusick 		nfs_args.flags |= NFSMNT_PGTHRESH;
593398a5aebSmckusick #endif /* NFSMNT_PGTHRESH */
594398a5aebSmckusick 
595398a5aebSmckusick 	NFS_SA_DREF(nfs_args, fs->fs_ip);
596398a5aebSmckusick 
597398a5aebSmckusick 	flags = compute_mount_flags(&mnt);
598398a5aebSmckusick 
5998a89c22cSpendry #ifdef NFSMNT_NOCTO
6008a89c22cSpendry 	if (hasmntopt(&mnt, "nocto") != NULL)
6018a89c22cSpendry 		nfs_args.flags |= NFSMNT_NOCTO;
6028a89c22cSpendry #endif /* NFSMNT_NOCTO */
6038a89c22cSpendry 
604398a5aebSmckusick #ifdef HAS_TCP_NFS
605398a5aebSmckusick 	if (hasmntopt(&mnt, "tcp") != NULL)
606398a5aebSmckusick 		nfs_args.sotype = SOCK_STREAM;
607398a5aebSmckusick #endif /* HAS_TCP_NFS */
608398a5aebSmckusick 
609398a5aebSmckusick 
610398a5aebSmckusick #ifdef ULTRIX_HACK
611398a5aebSmckusick 	/*
612398a5aebSmckusick 	 * Ultrix passes the flags argument as part of the
613398a5aebSmckusick 	 * mount data structure, rather than using the
614398a5aebSmckusick 	 * flags argument to the system call.  This is
615398a5aebSmckusick 	 * confusing...
616398a5aebSmckusick 	 */
617398a5aebSmckusick 	if (!(nfs_args.flags & NFSMNT_PGTHRESH)) {
618398a5aebSmckusick 		nfs_args.pg_thresh = 64; /* 64k - XXX */
619398a5aebSmckusick 		nfs_args.flags |= NFSMNT_PGTHRESH;
620398a5aebSmckusick 	}
621398a5aebSmckusick 	nfs_args.gfs_flags = flags;
622398a5aebSmckusick 	flags &= M_RDONLY;
623398a5aebSmckusick 	if (flags & M_RDONLY)
624398a5aebSmckusick 		nfs_args.flags |= NFSMNT_RONLY;
625398a5aebSmckusick #endif /* ULTRIX_HACK */
626398a5aebSmckusick 
627cc0207dcSpendry 	error = mount_fs(&mnt, flags, (caddr_t) &nfs_args, retry, type);
628cc0207dcSpendry 	free(xopts);
629cc0207dcSpendry 	return error;
630398a5aebSmckusick }
631398a5aebSmckusick 
mount_nfs(dir,fs_name,opts,mf)6328a89c22cSpendry static int mount_nfs(dir, fs_name, opts, mf)
633398a5aebSmckusick char *dir;
634398a5aebSmckusick char *fs_name;
635398a5aebSmckusick char *opts;
636398a5aebSmckusick mntfs *mf;
637398a5aebSmckusick {
6388a89c22cSpendry #ifdef notdef
639398a5aebSmckusick 	int error;
640398a5aebSmckusick 	struct fhstatus fhs;
641398a5aebSmckusick 	char *colon;
642398a5aebSmckusick 
643398a5aebSmckusick 	if (!(colon = strchr(fs_name, ':')))
644398a5aebSmckusick 		return ENOENT;
645398a5aebSmckusick 
646398a5aebSmckusick #ifdef DEBUG
647398a5aebSmckusick 	dlog("locating fhandle for %s", fs_name);
648398a5aebSmckusick #endif /* DEBUG */
649398a5aebSmckusick 	error = prime_nfs_fhandle_cache(colon+1, mf->mf_server, &fhs, (voidp) 0);
650398a5aebSmckusick 
651398a5aebSmckusick 	if (error)
652398a5aebSmckusick 		return error;
653398a5aebSmckusick 
654398a5aebSmckusick 	return mount_nfs_fh(&fhs, dir, fs_name, opts, mf);
6558a89c22cSpendry #endif
6568a89c22cSpendry 	if (!mf->mf_private) {
6578a89c22cSpendry 		plog(XLOG_ERROR, "Missing filehandle for %s", fs_name);
6588a89c22cSpendry 		return EINVAL;
659398a5aebSmckusick 	}
660398a5aebSmckusick 
6618a89c22cSpendry 	return mount_nfs_fh((struct fhstatus *) mf->mf_private, dir, fs_name, opts, mf);
6628a89c22cSpendry }
663398a5aebSmckusick 
nfs_fmount(mf)6648a89c22cSpendry static int nfs_fmount(mf)
6658a89c22cSpendry mntfs *mf;
6668a89c22cSpendry {
6678a89c22cSpendry 	int error;
6688a89c22cSpendry 
6698a89c22cSpendry 	error = mount_nfs(mf->mf_mount, mf->mf_info, mf->mf_mopts, mf);
670398a5aebSmckusick 
671398a5aebSmckusick #ifdef DEBUG
672398a5aebSmckusick 	if (error) {
673398a5aebSmckusick 		errno = error;
674398a5aebSmckusick 		dlog("mount_nfs: %m");
675398a5aebSmckusick 	}
676398a5aebSmckusick #endif /* DEBUG */
677398a5aebSmckusick 	return error;
678398a5aebSmckusick }
679398a5aebSmckusick 
nfs_fumount(mf)6808a89c22cSpendry static int nfs_fumount(mf)
6818a89c22cSpendry mntfs *mf;
682398a5aebSmckusick {
683398a5aebSmckusick 	int error = UMOUNT_FS(mf->mf_mount);
684398a5aebSmckusick 	if (error)
685398a5aebSmckusick 		return error;
686398a5aebSmckusick 
687398a5aebSmckusick 	return 0;
688398a5aebSmckusick }
689398a5aebSmckusick 
nfs_umounted(mp)690398a5aebSmckusick static void nfs_umounted(mp)
691398a5aebSmckusick am_node *mp;
692398a5aebSmckusick {
693398a5aebSmckusick #ifdef INFORM_MOUNTD
694398a5aebSmckusick 	/*
695398a5aebSmckusick 	 * Don't bother to inform remote mountd
696398a5aebSmckusick 	 * that we are finished.  Until a full
697398a5aebSmckusick 	 * track of filehandles is maintained
698398a5aebSmckusick 	 * the mountd unmount callback cannot
699398a5aebSmckusick 	 * be done correctly anyway...
700398a5aebSmckusick 	 */
701398a5aebSmckusick 
702398a5aebSmckusick 	mntfs *mf = mp->am_mnt;
703398a5aebSmckusick 	fserver *fs;
704398a5aebSmckusick 	char *colon, *path;
705398a5aebSmckusick 
706398a5aebSmckusick 	if (mf->mf_error || mf->mf_refc > 1)
707398a5aebSmckusick 		return;
708398a5aebSmckusick 
709398a5aebSmckusick 	fs = mf->mf_server;
710398a5aebSmckusick 
711398a5aebSmckusick 	/*
712398a5aebSmckusick 	 * Call the mount daemon on the server to
713398a5aebSmckusick 	 * announce that we are not using the fs any more.
714398a5aebSmckusick 	 *
715398a5aebSmckusick 	 * This is *wrong*.  The mountd should be called
716398a5aebSmckusick 	 * when the fhandle is flushed from the cache, and
717398a5aebSmckusick 	 * a reference held to the cached entry while the
718398a5aebSmckusick 	 * fs is mounted...
719398a5aebSmckusick 	 */
720398a5aebSmckusick 	colon = path = strchr(mf->mf_info, ':');
721398a5aebSmckusick 	if (fs && colon) {
722398a5aebSmckusick 		fh_cache f;
723398a5aebSmckusick #ifdef DEBUG
724398a5aebSmckusick 		dlog("calling mountd for %s", mf->mf_info);
725398a5aebSmckusick #endif /* DEBUG */
726398a5aebSmckusick 		*path++ = '\0';
727398a5aebSmckusick 		f.fh_path = path;
728398a5aebSmckusick 		f.fh_sin = *fs->fs_ip;
729398a5aebSmckusick 		f.fh_sin.sin_port = (u_short) 0;
730398a5aebSmckusick 		f.fh_fs = fs;
731398a5aebSmckusick 		f.fh_id = 0;
732398a5aebSmckusick 		f.fh_error = 0;
733398a5aebSmckusick 		(void) prime_nfs_fhandle_cache(colon+1, mf->mf_server, (struct fhstatus *) 0, (voidp) mf);
734398a5aebSmckusick 		(void) call_mountd(&f, MOUNTPROC_UMNT, (fwd_fun) 0, (voidp) 0);
735398a5aebSmckusick 		*colon = ':';
736398a5aebSmckusick 	}
737398a5aebSmckusick #endif /* INFORM_MOUNTD */
73810042f30Spendry 
73910042f30Spendry #ifdef KICK_KERNEL
74010042f30Spendry 	/* This should go into the mainline code, not in nfs_ops... */
74110042f30Spendry 
74210042f30Spendry 	/*
74310042f30Spendry 	 * Run lstat over the underlying directory in
74410042f30Spendry 	 * case this was a direct mount.  This will
74510042f30Spendry 	 * get the kernel back in sync with reality.
74610042f30Spendry 	 */
74710042f30Spendry 	if (mp->am_parent && mp->am_parent->am_path &&
74810042f30Spendry 	    STREQ(mp->am_parent->am_mnt->mf_ops->fs_type, "direct")) {
74910042f30Spendry 		struct stat stb;
75010042f30Spendry 		int pid;
75110042f30Spendry 		if ((pid = background()) == 0) {
75210042f30Spendry 			if (lstat(mp->am_parent->am_path, &stb) < 0) {
75310042f30Spendry 				plog(XLOG_ERROR, "lstat(%s) after unmount: %m", mp->am_parent->am_path);
75410042f30Spendry #ifdef DEBUG
75510042f30Spendry 			} else {
75610042f30Spendry 				dlog("hack lstat(%s): ok", mp->am_parent->am_path);
75710042f30Spendry #endif /* DEBUG */
75810042f30Spendry 			}
75910042f30Spendry 			_exit(0);
76010042f30Spendry 		}
76110042f30Spendry 	}
76210042f30Spendry #endif /* KICK_KERNEL */
763398a5aebSmckusick }
764398a5aebSmckusick 
765398a5aebSmckusick /*
766398a5aebSmckusick  * Network file system
767398a5aebSmckusick  */
768398a5aebSmckusick am_ops nfs_ops = {
769398a5aebSmckusick 	"nfs",
770398a5aebSmckusick 	nfs_match,
771398a5aebSmckusick 	nfs_init,
7728a89c22cSpendry 	auto_fmount,
7738a89c22cSpendry 	nfs_fmount,
7748a89c22cSpendry 	auto_fumount,
7758a89c22cSpendry 	nfs_fumount,
776398a5aebSmckusick 	efs_lookuppn,
777398a5aebSmckusick 	efs_readdir,
778398a5aebSmckusick 	0, /* nfs_readlink */
779398a5aebSmckusick 	0, /* nfs_mounted */
780398a5aebSmckusick 	nfs_umounted,
781398a5aebSmckusick 	find_nfs_srvr,
782398a5aebSmckusick 	FS_MKMNT|FS_BACKGROUND|FS_AMQINFO
783398a5aebSmckusick };
784398a5aebSmckusick 
785398a5aebSmckusick #endif /* HAS_NFS */
786