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