1 /*-
2 * Copyright (c) 1990 Jan-Simon Pendry
3 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
4 * Copyright (c) 1990, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Jan-Simon Pendry at Imperial College, London.
9 *
10 * %sccs.include.redist.c%
11 *
12 * $Id: nfs_ops.c,v 5.2.2.2 1992/05/31 16:35:05 jsp Exp $
13 */
14
15 #ifndef lint
16 static char sccsid[] = "@(#)nfs_ops.c 8.2 (Berkeley) 05/10/95";
17 #endif /* not lint */
18
19 #include "am.h"
20 #include <sys/stat.h>
21
22 #ifdef HAS_NFS
23
24 #define NFS
25 #define NFSCLIENT
26 #ifdef NFS_3
27 typedef nfs_fh fhandle_t;
28 #endif /* NFS_3 */
29 #include <sys/mount.h>
30 #ifdef NFS_HDR
31 #include NFS_HDR
32 #endif /* NFS_HDR */
33 #include "mount.h"
34
35 /*
36 * Network file system
37 */
38
39 /*
40 * Convert from nfsstat to UN*X error code
41 */
42 #define unx_error(e) ((int)(e))
43
44 /*
45 * The NFS layer maintains a cache of file handles.
46 * This is *fundamental* to the implementation and
47 * also allows quick remounting when a filesystem
48 * is accessed soon after timing out.
49 *
50 * The NFS server layer knows to flush this cache
51 * when a server goes down so avoiding stale handles.
52 *
53 * Each cache entry keeps a hard reference to
54 * the corresponding server. This ensures that
55 * the server keepalive information is maintained.
56 *
57 * The copy of the sockaddr_in here is taken so
58 * that the port can be twiddled to talk to mountd
59 * instead of portmap or the NFS server as used
60 * elsewhere.
61 * The port# is flushed if a server goes down.
62 * The IP address is never flushed - we assume
63 * that the address of a mounted machine never
64 * changes. If it does, then you have other
65 * problems...
66 */
67 typedef struct fh_cache fh_cache;
68 struct fh_cache {
69 qelem fh_q; /* List header */
70 voidp fh_wchan; /* Wait channel */
71 int fh_error; /* Valid data? */
72 int fh_id; /* Unique id */
73 int fh_cid; /* Callout id */
74 struct fhstatus fh_handle; /* Handle on filesystem */
75 struct sockaddr_in fh_sin; /* Address of mountd */
76 fserver *fh_fs; /* Server holding filesystem */
77 char *fh_path; /* Filesystem on host */
78 };
79
80 /*
81 * FH_TTL is the time a file handle will remain in the cache since
82 * last being used. If the file handle becomes invalid, then it
83 * will be flushed anyway.
84 */
85 #define FH_TTL (5 * 60) /* five minutes */
86 #define FH_TTL_ERROR (30) /* 30 seconds */
87
88 static int fh_id = 0;
89 #define FHID_ALLOC() (++fh_id)
90 extern qelem fh_head;
91 qelem fh_head = { &fh_head, &fh_head };
92
93 static int call_mountd P((fh_cache*, unsigned long, fwd_fun, voidp));
94
95 AUTH *nfs_auth;
96
97 static fh_cache *find_nfs_fhandle_cache P((voidp idv, int done));
find_nfs_fhandle_cache(idv,done)98 static fh_cache *find_nfs_fhandle_cache(idv, done)
99 voidp idv;
100 int done;
101 {
102 fh_cache *fp, *fp2 = 0;
103 int id = (int) idv;
104
105 ITER(fp, fh_cache, &fh_head) {
106 if (fp->fh_id == id) {
107 fp2 = fp;
108 break;
109 }
110 }
111
112 #ifdef DEBUG
113 if (fp2) {
114 dlog("fh cache gives fp %#x, fs %s", fp2, fp2->fh_path);
115 } else {
116 dlog("fh cache search failed");
117 }
118 #endif /* DEBUG */
119
120 if (fp2 && !done) {
121 fp2->fh_error = ETIMEDOUT;
122 return 0;
123 }
124
125 return fp2;
126 }
127
128 /*
129 * Called when a filehandle appears
130 */
131 static void got_nfs_fh P((voidp pkt, int len, struct sockaddr_in *sa,
132 struct sockaddr_in *ia, voidp idv, int done));
got_nfs_fh(pkt,len,sa,ia,idv,done)133 static void got_nfs_fh(pkt, len, sa, ia, idv, done)
134 voidp pkt;
135 int len;
136 struct sockaddr_in *sa, *ia;
137 voidp idv;
138 int done;
139 {
140 fh_cache *fp = find_nfs_fhandle_cache(idv, done);
141 if (fp) {
142 fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &fp->fh_handle, xdr_fhstatus);
143 if (!fp->fh_error) {
144 #ifdef DEBUG
145 dlog("got filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
146 #endif /* DEBUG */
147 /*
148 * Wakeup anything sleeping on this filehandle
149 */
150 if (fp->fh_wchan) {
151 #ifdef DEBUG
152 dlog("Calling wakeup on %#x", fp->fh_wchan);
153 #endif /* DEBUG */
154 wakeup(fp->fh_wchan);
155 }
156 }
157 }
158 }
159
160 void flush_nfs_fhandle_cache P((fserver *fs));
flush_nfs_fhandle_cache(fs)161 void flush_nfs_fhandle_cache(fs)
162 fserver *fs;
163 {
164 fh_cache *fp;
165 ITER(fp, fh_cache, &fh_head) {
166 if (fp->fh_fs == fs || fs == 0) {
167 fp->fh_sin.sin_port = (u_short) 0;
168 fp->fh_error = -1;
169 }
170 }
171 }
172
173 static void discard_fh P((fh_cache *fp));
discard_fh(fp)174 static void discard_fh(fp)
175 fh_cache *fp;
176 {
177 rem_que(&fp->fh_q);
178 #ifdef DEBUG
179 dlog("Discarding filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
180 #endif /* DEBUG */
181 free_srvr(fp->fh_fs);
182 free((voidp) fp->fh_path);
183 free((voidp) fp);
184 }
185
186 /*
187 * Determine the file handle for a node
188 */
189 static int prime_nfs_fhandle_cache P((char *path, fserver *fs, struct fhstatus *fhbuf, voidp wchan));
prime_nfs_fhandle_cache(path,fs,fhbuf,wchan)190 static int prime_nfs_fhandle_cache(path, fs, fhbuf, wchan)
191 char *path;
192 fserver *fs;
193 struct fhstatus *fhbuf;
194 voidp wchan;
195 {
196 fh_cache *fp, *fp_save = 0;
197 int error;
198 int reuse_id = FALSE;
199
200 #ifdef DEBUG
201 dlog("Searching cache for %s:%s", fs->fs_host, path);
202 #endif /* DEBUG */
203
204 /*
205 * First search the cache
206 */
207 ITER(fp, fh_cache, &fh_head) {
208 if (fs == fp->fh_fs && strcmp(path, fp->fh_path) == 0) {
209 switch (fp->fh_error) {
210 case 0:
211 error = fp->fh_error = unx_error(fp->fh_handle.fhs_status);
212 if (error == 0) {
213 if (fhbuf)
214 bcopy((voidp) &fp->fh_handle, (voidp) fhbuf,
215 sizeof(fp->fh_handle));
216 if (fp->fh_cid)
217 untimeout(fp->fh_cid);
218 fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp);
219 } else if (error == EACCES) {
220 /*
221 * Now decode the file handle return code.
222 */
223 plog(XLOG_INFO, "Filehandle denied for \"%s:%s\"",
224 fs->fs_host, path);
225 } else {
226 errno = error; /* XXX */
227 plog(XLOG_INFO, "Filehandle error for \"%s:%s\": %m",
228 fs->fs_host, path);
229 }
230
231 /*
232 * The error was returned from the remote mount daemon.
233 * Policy: this error will be cached for now...
234 */
235 return error;
236
237 case -1:
238 /*
239 * Still thinking about it, but we can re-use.
240 */
241 fp_save = fp;
242 reuse_id = TRUE;
243 break;
244
245 default:
246 /*
247 * Return the error.
248 * Policy: make sure we recompute if required again
249 * in case this was caused by a network failure.
250 * This can thrash mountd's though... If you find
251 * your mountd going slowly then:
252 * 1. Add a fork() loop to main.
253 * 2. Remove the call to innetgr() and don't use
254 * netgroups, especially if you don't use YP.
255 */
256 error = fp->fh_error;
257 fp->fh_error = -1;
258 return error;
259 }
260 break;
261 }
262 }
263
264 /*
265 * Not in cache
266 */
267 if (fp_save) {
268 fp = fp_save;
269 /*
270 * Re-use existing slot
271 */
272 untimeout(fp->fh_cid);
273 free_srvr(fp->fh_fs);
274 free(fp->fh_path);
275 } else {
276 fp = ALLOC(fh_cache);
277 bzero((voidp) fp, sizeof(*fp));
278 ins_que(&fp->fh_q, &fh_head);
279 }
280 if (!reuse_id)
281 fp->fh_id = FHID_ALLOC();
282 fp->fh_wchan = wchan;
283 fp->fh_error = -1;
284 fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp);
285
286 /*
287 * If the address has changed then don't try to re-use the
288 * port information
289 */
290 if (fp->fh_sin.sin_addr.s_addr != fs->fs_ip->sin_addr.s_addr) {
291 fp->fh_sin = *fs->fs_ip;
292 fp->fh_sin.sin_port = 0;
293 }
294 fp->fh_fs = dup_srvr(fs);
295 fp->fh_path = strdup(path);
296
297 error = call_mountd(fp, MOUNTPROC_MNT, got_nfs_fh, wchan);
298 if (error) {
299 /*
300 * Local error - cache for a short period
301 * just to prevent thrashing.
302 */
303 untimeout(fp->fh_cid);
304 fp->fh_cid = timeout(error < 0 ? 2 * ALLOWED_MOUNT_TIME : FH_TTL_ERROR,
305 discard_fh, (voidp) fp);
306 fp->fh_error = error;
307 } else {
308 error = fp->fh_error;
309 }
310 return error;
311 }
312
make_nfs_auth(void)313 int make_nfs_auth P((void))
314 {
315 #ifdef HAS_NFS_QUALIFIED_NAMES
316 /*
317 * From: Chris Metcalf <metcalf@masala.lcs.mit.edu>
318 * Use hostd, not just hostname. Note that uids
319 * and gids and the gidlist are type *int* and not the
320 * system uid_t and gid_t types.
321 */
322 static int group_wheel = 0;
323 nfs_auth = authunix_create(hostd, 0, 0, 1, &group_wheel);
324 #else
325 nfs_auth = authunix_create_default();
326 #endif
327 if (!nfs_auth)
328 return ENOBUFS;
329 return 0;
330 }
331
332 static int call_mountd P((fh_cache *fp, u_long proc, fwd_fun f, voidp wchan));
call_mountd(fp,proc,f,wchan)333 static int call_mountd(fp, proc, f, wchan)
334 fh_cache *fp;
335 u_long proc;
336 fwd_fun f;
337 voidp wchan;
338 {
339 struct rpc_msg mnt_msg;
340 int len;
341 char iobuf[8192];
342 int error;
343
344 if (!nfs_auth) {
345 error = make_nfs_auth();
346 if (error)
347 return error;
348 }
349
350 if (fp->fh_sin.sin_port == 0) {
351 u_short port;
352 error = nfs_srvr_port(fp->fh_fs, &port, wchan);
353 if (error)
354 return error;
355 fp->fh_sin.sin_port = port;
356 }
357
358 rpc_msg_init(&mnt_msg, MOUNTPROG, MOUNTVERS, (unsigned long) 0);
359 len = make_rpc_packet(iobuf, sizeof(iobuf), proc,
360 &mnt_msg, (voidp) &fp->fh_path, xdr_nfspath, nfs_auth);
361
362 if (len > 0) {
363 error = fwd_packet(MK_RPC_XID(RPC_XID_MOUNTD, fp->fh_id),
364 (voidp) iobuf, len, &fp->fh_sin, &fp->fh_sin, (voidp) fp->fh_id, f);
365 } else {
366 error = -len;
367 }
368 /*
369 * It may be the case that we're sending to the wrong MOUNTD port. This
370 * occurs if mountd is restarted on the server after the port has been
371 * looked up and stored in the filehandle cache somewhere. The correct
372 * solution, if we're going to cache port numbers is to catch the ICMP
373 * port unreachable reply from the server and cause the portmap request
374 * to be redone. The quick solution here is to invalidate the MOUNTD
375 * port.
376 */
377 fp->fh_sin.sin_port = 0;
378
379 return error;
380 }
381
382 /*-------------------------------------------------------------------------*/
383
384 /*
385 * NFS needs the local filesystem, remote filesystem
386 * remote hostname.
387 * Local filesystem defaults to remote and vice-versa.
388 */
nfs_match(fo)389 static char *nfs_match(fo)
390 am_opts *fo;
391 {
392 char *xmtab;
393 if (fo->opt_fs && !fo->opt_rfs)
394 fo->opt_rfs = fo->opt_fs;
395 if (!fo->opt_rfs) {
396 plog(XLOG_USER, "nfs: no remote filesystem specified");
397 return FALSE;
398 }
399 if (!fo->opt_rhost) {
400 plog(XLOG_USER, "nfs: no remote host specified");
401 return FALSE;
402 }
403 /*
404 * Determine magic cookie to put in mtab
405 */
406 xmtab = (char *) xmalloc(strlen(fo->opt_rhost) + strlen(fo->opt_rfs) + 2);
407 sprintf(xmtab, "%s:%s", fo->opt_rhost, fo->opt_rfs);
408 #ifdef DEBUG
409 dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"",
410 fo->opt_rhost, fo->opt_rfs, fo->opt_fs);
411 #endif /* DEBUG */
412
413 return xmtab;
414 }
415
416 /*
417 * Initialise am structure for nfs
418 */
nfs_init(mf)419 static int nfs_init(mf)
420 mntfs *mf;
421 {
422 if (!mf->mf_private) {
423 int error;
424 struct fhstatus fhs;
425
426 char *colon = strchr(mf->mf_info, ':');
427 if (colon == 0)
428 return ENOENT;
429
430 error = prime_nfs_fhandle_cache(colon+1, mf->mf_server, &fhs, (voidp) mf);
431 if (!error) {
432 mf->mf_private = (voidp) ALLOC(fhstatus);
433 mf->mf_prfree = (void (*)()) free;
434 bcopy((voidp) &fhs, mf->mf_private, sizeof(fhs));
435 }
436 return error;
437 }
438
439 return 0;
440 }
441
442 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)443 int mount_nfs_fh(fhp, dir, fs_name, opts, mf)
444 struct fhstatus *fhp;
445 char *dir;
446 char *fs_name;
447 char *opts;
448 mntfs *mf;
449 {
450 struct nfs_args nfs_args;
451 struct mntent mnt;
452 int retry;
453 char *colon;
454 /*char *path;*/
455 char host[MAXHOSTNAMELEN + MAXPATHLEN + 2];
456 fserver *fs = mf->mf_server;
457 int flags;
458 char *xopts;
459 int error;
460 #ifdef notdef
461 unsigned short port;
462 #endif /* notdef */
463
464 MTYPE_TYPE type = MOUNT_TYPE_NFS;
465
466 bzero((voidp) &nfs_args, sizeof(nfs_args)); /* Paranoid */
467
468 /*
469 * Extract host name to give to kernel
470 */
471 if (!(colon = strchr(fs_name, ':')))
472 return ENOENT;
473 #ifndef NFS_ARGS_NEEDS_PATH
474 *colon = '\0';
475 #endif
476 strncpy(host, fs_name, sizeof(host));
477 #ifndef NFS_ARGS_NEEDS_PATH
478 *colon = ':';
479 #endif /* NFS_ARGS_NEEDS_PATH */
480 /*path = colon + 1;*/
481
482 if (mf->mf_remopts && *mf->mf_remopts && !islocalnet(fs->fs_ip->sin_addr.s_addr))
483 xopts = strdup(mf->mf_remopts);
484 else
485 xopts = strdup(opts);
486
487 mnt.mnt_dir = dir;
488 mnt.mnt_fsname = fs_name;
489 mnt.mnt_type = MTAB_TYPE_NFS;
490 mnt.mnt_opts = xopts;
491 mnt.mnt_freq = 0;
492 mnt.mnt_passno = 0;
493
494 retry = hasmntval(&mnt, "retry");
495 if (retry <= 0)
496 retry = 1; /* XXX */
497
498 /*again:*/
499
500 /*
501 * set mount args
502 */
503 #ifdef NFS_ARGSVERSION
504 nfs_args.version = NFS_ARGSVERSION;
505 #endif
506
507 NFS_FH_DREF(nfs_args.fh, (NFS_FH_TYPE) fhp->fhstatus_u.fhs_fhandle);
508
509 #ifdef ULTRIX_HACK
510 nfs_args.optstr = mnt.mnt_opts;
511 #endif /* ULTRIX_HACK */
512
513 nfs_args.hostname = host;
514 nfs_args.flags |= NFSMNT_HOSTNAME;
515 #ifdef HOSTNAMESZ
516 /*
517 * Most kernels have a name length restriction.
518 */
519 if (strlen(host) >= HOSTNAMESZ)
520 strcpy(host + HOSTNAMESZ - 3, "..");
521 #endif /* HOSTNAMESZ */
522
523 if (nfs_args.rsize = hasmntval(&mnt, "rsize"))
524 nfs_args.flags |= NFSMNT_RSIZE;
525
526 if (nfs_args.wsize = hasmntval(&mnt, "wsize"))
527 nfs_args.flags |= NFSMNT_WSIZE;
528
529 if (nfs_args.timeo = hasmntval(&mnt, "timeo"))
530 nfs_args.flags |= NFSMNT_TIMEO;
531
532 if (nfs_args.retrans = hasmntval(&mnt, "retrans"))
533 nfs_args.flags |= NFSMNT_RETRANS;
534
535 #ifdef NFSMNT_BIODS
536 if (nfs_args.biods = hasmntval(&mnt, "biods"))
537 nfs_args.flags |= NFSMNT_BIODS;
538
539 #endif /* NFSMNT_BIODS */
540
541 #ifdef NFSMNT_MAXGRPS
542 if (nfs_args.maxgrouplist = hasmntval(&mnt, "maxgroups"))
543 nfs_args.flags |= NFSMNT_MAXGRPS;
544 #endif /* NFSMNT_MAXGRPS */
545
546 #ifdef notdef
547 /*
548 * This isn't supported by the ping algorithm yet.
549 * In any case, it is all done in nfs_init().
550 */
551 if (port = hasmntval(&mnt, "port"))
552 sin.sin_port = htons(port);
553 else
554 sin.sin_port = htons(NFS_PORT); /* XXX should use portmapper */
555 #endif /* notdef */
556
557 if (hasmntopt(&mnt, MNTOPT_SOFT) != NULL)
558 nfs_args.flags |= NFSMNT_SOFT;
559
560 #ifdef NFSMNT_SPONGY
561 if (hasmntopt(&mnt, "spongy") != NULL) {
562 nfs_args.flags |= NFSMNT_SPONGY;
563 if (nfs_args.flags & NFSMNT_SOFT) {
564 plog(XLOG_USER, "Mount opts soft and spongy are incompatible - soft ignored");
565 nfs_args.flags &= ~NFSMNT_SOFT;
566 }
567 }
568 #endif /* MNTOPT_SPONGY */
569
570 #ifdef MNTOPT_INTR
571 if (hasmntopt(&mnt, MNTOPT_INTR) != NULL)
572 nfs_args.flags |= NFSMNT_INT;
573 #endif /* MNTOPT_INTR */
574
575 #ifdef MNTOPT_NODEVS
576 if (hasmntopt(&mnt, MNTOPT_NODEVS) != NULL)
577 nfs_args.flags |= NFSMNT_NODEVS;
578 #endif /* MNTOPT_NODEVS */
579
580 #ifdef MNTOPT_COMPRESS
581 if (hasmntopt(&mnt, "compress") != NULL)
582 nfs_args.flags |= NFSMNT_COMPRESS;
583 #endif /* MNTOPT_COMPRESS */
584
585 #ifdef MNTOPT_NOCONN
586 if (hasmntopt(&mnt, "noconn") != NULL)
587 nfs_args.flags |= NFSMNT_NOCONN;
588 #endif /* MNTOPT_NOCONN */
589
590 #ifdef NFSMNT_PGTHRESH
591 if (nfs_args.pg_thresh = hasmntval(&mnt, "pgthresh"))
592 nfs_args.flags |= NFSMNT_PGTHRESH;
593 #endif /* NFSMNT_PGTHRESH */
594
595 NFS_SA_DREF(nfs_args, fs->fs_ip);
596
597 flags = compute_mount_flags(&mnt);
598
599 #ifdef NFSMNT_NOCTO
600 if (hasmntopt(&mnt, "nocto") != NULL)
601 nfs_args.flags |= NFSMNT_NOCTO;
602 #endif /* NFSMNT_NOCTO */
603
604 #ifdef HAS_TCP_NFS
605 if (hasmntopt(&mnt, "tcp") != NULL)
606 nfs_args.sotype = SOCK_STREAM;
607 #endif /* HAS_TCP_NFS */
608
609
610 #ifdef ULTRIX_HACK
611 /*
612 * Ultrix passes the flags argument as part of the
613 * mount data structure, rather than using the
614 * flags argument to the system call. This is
615 * confusing...
616 */
617 if (!(nfs_args.flags & NFSMNT_PGTHRESH)) {
618 nfs_args.pg_thresh = 64; /* 64k - XXX */
619 nfs_args.flags |= NFSMNT_PGTHRESH;
620 }
621 nfs_args.gfs_flags = flags;
622 flags &= M_RDONLY;
623 if (flags & M_RDONLY)
624 nfs_args.flags |= NFSMNT_RONLY;
625 #endif /* ULTRIX_HACK */
626
627 error = mount_fs(&mnt, flags, (caddr_t) &nfs_args, retry, type);
628 free(xopts);
629 return error;
630 }
631
mount_nfs(dir,fs_name,opts,mf)632 static int mount_nfs(dir, fs_name, opts, mf)
633 char *dir;
634 char *fs_name;
635 char *opts;
636 mntfs *mf;
637 {
638 #ifdef notdef
639 int error;
640 struct fhstatus fhs;
641 char *colon;
642
643 if (!(colon = strchr(fs_name, ':')))
644 return ENOENT;
645
646 #ifdef DEBUG
647 dlog("locating fhandle for %s", fs_name);
648 #endif /* DEBUG */
649 error = prime_nfs_fhandle_cache(colon+1, mf->mf_server, &fhs, (voidp) 0);
650
651 if (error)
652 return error;
653
654 return mount_nfs_fh(&fhs, dir, fs_name, opts, mf);
655 #endif
656 if (!mf->mf_private) {
657 plog(XLOG_ERROR, "Missing filehandle for %s", fs_name);
658 return EINVAL;
659 }
660
661 return mount_nfs_fh((struct fhstatus *) mf->mf_private, dir, fs_name, opts, mf);
662 }
663
nfs_fmount(mf)664 static int nfs_fmount(mf)
665 mntfs *mf;
666 {
667 int error;
668
669 error = mount_nfs(mf->mf_mount, mf->mf_info, mf->mf_mopts, mf);
670
671 #ifdef DEBUG
672 if (error) {
673 errno = error;
674 dlog("mount_nfs: %m");
675 }
676 #endif /* DEBUG */
677 return error;
678 }
679
nfs_fumount(mf)680 static int nfs_fumount(mf)
681 mntfs *mf;
682 {
683 int error = UMOUNT_FS(mf->mf_mount);
684 if (error)
685 return error;
686
687 return 0;
688 }
689
nfs_umounted(mp)690 static void nfs_umounted(mp)
691 am_node *mp;
692 {
693 #ifdef INFORM_MOUNTD
694 /*
695 * Don't bother to inform remote mountd
696 * that we are finished. Until a full
697 * track of filehandles is maintained
698 * the mountd unmount callback cannot
699 * be done correctly anyway...
700 */
701
702 mntfs *mf = mp->am_mnt;
703 fserver *fs;
704 char *colon, *path;
705
706 if (mf->mf_error || mf->mf_refc > 1)
707 return;
708
709 fs = mf->mf_server;
710
711 /*
712 * Call the mount daemon on the server to
713 * announce that we are not using the fs any more.
714 *
715 * This is *wrong*. The mountd should be called
716 * when the fhandle is flushed from the cache, and
717 * a reference held to the cached entry while the
718 * fs is mounted...
719 */
720 colon = path = strchr(mf->mf_info, ':');
721 if (fs && colon) {
722 fh_cache f;
723 #ifdef DEBUG
724 dlog("calling mountd for %s", mf->mf_info);
725 #endif /* DEBUG */
726 *path++ = '\0';
727 f.fh_path = path;
728 f.fh_sin = *fs->fs_ip;
729 f.fh_sin.sin_port = (u_short) 0;
730 f.fh_fs = fs;
731 f.fh_id = 0;
732 f.fh_error = 0;
733 (void) prime_nfs_fhandle_cache(colon+1, mf->mf_server, (struct fhstatus *) 0, (voidp) mf);
734 (void) call_mountd(&f, MOUNTPROC_UMNT, (fwd_fun) 0, (voidp) 0);
735 *colon = ':';
736 }
737 #endif /* INFORM_MOUNTD */
738
739 #ifdef KICK_KERNEL
740 /* This should go into the mainline code, not in nfs_ops... */
741
742 /*
743 * Run lstat over the underlying directory in
744 * case this was a direct mount. This will
745 * get the kernel back in sync with reality.
746 */
747 if (mp->am_parent && mp->am_parent->am_path &&
748 STREQ(mp->am_parent->am_mnt->mf_ops->fs_type, "direct")) {
749 struct stat stb;
750 int pid;
751 if ((pid = background()) == 0) {
752 if (lstat(mp->am_parent->am_path, &stb) < 0) {
753 plog(XLOG_ERROR, "lstat(%s) after unmount: %m", mp->am_parent->am_path);
754 #ifdef DEBUG
755 } else {
756 dlog("hack lstat(%s): ok", mp->am_parent->am_path);
757 #endif /* DEBUG */
758 }
759 _exit(0);
760 }
761 }
762 #endif /* KICK_KERNEL */
763 }
764
765 /*
766 * Network file system
767 */
768 am_ops nfs_ops = {
769 "nfs",
770 nfs_match,
771 nfs_init,
772 auto_fmount,
773 nfs_fmount,
774 auto_fumount,
775 nfs_fumount,
776 efs_lookuppn,
777 efs_readdir,
778 0, /* nfs_readlink */
779 0, /* nfs_mounted */
780 nfs_umounted,
781 find_nfs_srvr,
782 FS_MKMNT|FS_BACKGROUND|FS_AMQINFO
783 };
784
785 #endif /* HAS_NFS */
786