MFC r1.27:
[dragonfly.git] / contrib / amd / amd / ops_nfs.c
blob01cdcee787f4b6e4478e21c1133624c2f88970a4
1 /*
2 * Copyright (c) 1997-1999 Erez Zadok
3 * Copyright (c) 1990 Jan-Simon Pendry
4 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1990 The Regents of the University of California.
6 * All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgment:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
39 * %W% (Berkeley) %G%
41 * $Id: ops_nfs.c,v 1.5 1999/03/13 17:03:28 ezk Exp $
46 * Network file system
49 #ifdef HAVE_CONFIG_H
50 # include <config.h>
51 #endif /* HAVE_CONFIG_H */
52 #include <am_defs.h>
53 #include <amd.h>
56 * Convert from nfsstat to UN*X error code
58 #define unx_error(e) ((int)(e))
61 * FH_TTL is the time a file handle will remain in the cache since
62 * last being used. If the file handle becomes invalid, then it
63 * will be flushed anyway.
65 #define FH_TTL (5 * 60) /* five minutes */
66 #define FH_TTL_ERROR (30) /* 30 seconds */
67 #define FHID_ALLOC(struct) (++fh_id)
70 * The NFS layer maintains a cache of file handles.
71 * This is *fundamental* to the implementation and
72 * also allows quick remounting when a filesystem
73 * is accessed soon after timing out.
75 * The NFS server layer knows to flush this cache
76 * when a server goes down so avoiding stale handles.
78 * Each cache entry keeps a hard reference to
79 * the corresponding server. This ensures that
80 * the server keepalive information is maintained.
82 * The copy of the sockaddr_in here is taken so
83 * that the port can be twiddled to talk to mountd
84 * instead of portmap or the NFS server as used
85 * elsewhere.
86 * The port# is flushed if a server goes down.
87 * The IP address is never flushed - we assume
88 * that the address of a mounted machine never
89 * changes. If it does, then you have other
90 * problems...
92 typedef struct fh_cache fh_cache;
93 struct fh_cache {
94 qelem fh_q; /* List header */
95 voidp fh_wchan; /* Wait channel */
96 int fh_error; /* Valid data? */
97 int fh_id; /* Unique id */
98 int fh_cid; /* Callout id */
99 u_long fh_nfs_version; /* highest NFS version on host */
100 am_nfs_handle_t fh_nfs_handle; /* Handle on filesystem */
101 struct sockaddr_in fh_sin; /* Address of mountd */
102 fserver *fh_fs; /* Server holding filesystem */
103 char *fh_path; /* Filesystem on host */
106 /* forward definitions */
107 static int call_mountd(fh_cache *fp, u_long proc, fwd_fun f, voidp wchan);
108 static int fh_id = 0;
110 /* globals */
111 AUTH *nfs_auth;
112 qelem fh_head = {&fh_head, &fh_head};
115 * Network file system operations
117 am_ops nfs_ops =
119 "nfs",
120 nfs_match,
121 nfs_init,
122 amfs_auto_fmount,
123 nfs_fmount,
124 amfs_auto_fumount,
125 nfs_fumount,
126 amfs_error_lookuppn,
127 amfs_error_readdir,
128 0, /* nfs_readlink */
129 0, /* nfs_mounted */
130 nfs_umounted,
131 find_nfs_srvr,
132 FS_MKMNT | FS_BACKGROUND | FS_AMQINFO
136 static fh_cache *
137 find_nfs_fhandle_cache(voidp idv, int done)
139 fh_cache *fp, *fp2 = 0;
140 int id = (long) idv; /* for 64-bit archs */
142 ITER(fp, fh_cache, &fh_head) {
143 if (fp->fh_id == id) {
144 fp2 = fp;
145 break;
149 #ifdef DEBUG
150 if (fp2) {
151 dlog("fh cache gives fp %#lx, fs %s", (unsigned long) fp2, fp2->fh_path);
152 } else {
153 dlog("fh cache search failed");
155 #endif /* DEBUG */
157 if (fp2 && !done) {
158 fp2->fh_error = ETIMEDOUT;
159 return 0;
162 return fp2;
167 * Called when a filehandle appears
169 static void
170 got_nfs_fh(voidp pkt, int len, struct sockaddr_in * sa, struct sockaddr_in * ia, voidp idv, int done)
172 fh_cache *fp;
174 fp = find_nfs_fhandle_cache(idv, done);
175 if (!fp)
176 return;
179 * retrieve the correct RPC reply for the file handle, based on the
180 * NFS protocol version.
182 #ifdef HAVE_FS_NFS3
183 if (fp->fh_nfs_version == NFS_VERSION3)
184 fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &fp->fh_nfs_handle.v3,
185 (XDRPROC_T_TYPE) xdr_mountres3);
186 else
187 #endif /* HAVE_FS_NFS3 */
188 fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &fp->fh_nfs_handle.v2,
189 (XDRPROC_T_TYPE) xdr_fhstatus);
191 if (!fp->fh_error) {
192 #ifdef DEBUG
193 dlog("got filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
194 #endif /* DEBUG */
197 * Wakeup anything sleeping on this filehandle
199 if (fp->fh_wchan) {
200 #ifdef DEBUG
201 dlog("Calling wakeup on %#lx", (unsigned long) fp->fh_wchan);
202 #endif /* DEBUG */
203 wakeup(fp->fh_wchan);
209 void
210 flush_nfs_fhandle_cache(fserver *fs)
212 fh_cache *fp;
214 ITER(fp, fh_cache, &fh_head) {
215 if (fp->fh_fs == fs || fs == 0) {
216 fp->fh_sin.sin_port = (u_short) 0;
217 fp->fh_error = -1;
223 static void
224 discard_fh(voidp v)
226 fh_cache *fp = v;
228 rem_que(&fp->fh_q);
229 if (fp->fh_fs) {
230 #ifdef DEBUG
231 dlog("Discarding filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
232 #endif /* DEBUG */
233 free_srvr(fp->fh_fs);
235 if (fp->fh_path)
236 XFREE(fp->fh_path);
237 XFREE(fp);
242 * Determine the file handle for a node
244 static int
245 prime_nfs_fhandle_cache(char *path, fserver *fs, am_nfs_handle_t *fhbuf, voidp wchan)
247 fh_cache *fp, *fp_save = 0;
248 int error;
249 int reuse_id = FALSE;
251 #ifdef DEBUG
252 dlog("Searching cache for %s:%s", fs->fs_host, path);
253 #endif /* DEBUG */
256 * First search the cache
258 ITER(fp, fh_cache, &fh_head) {
259 if (fs == fp->fh_fs && STREQ(path, fp->fh_path)) {
260 switch (fp->fh_error) {
261 case 0:
262 plog(XLOG_INFO, "prime_nfs_fhandle_cache: NFS version %d", (int) fp->fh_nfs_version);
263 #ifdef HAVE_FS_NFS3
264 if (fp->fh_nfs_version == NFS_VERSION3)
265 error = fp->fh_error = unx_error(fp->fh_nfs_handle.v3.fhs_status);
266 else
267 #endif /* HAVE_FS_NFS3 */
268 error = fp->fh_error = unx_error(fp->fh_nfs_handle.v2.fhs_status);
269 if (error == 0) {
270 if (fhbuf) {
271 #ifdef HAVE_FS_NFS3
272 if (fp->fh_nfs_version == NFS_VERSION3)
273 memmove((voidp) &(fhbuf->v3), (voidp) &(fp->fh_nfs_handle.v3),
274 sizeof(fp->fh_nfs_handle.v3));
275 else
276 #endif /* HAVE_FS_NFS3 */
277 memmove((voidp) &(fhbuf->v2), (voidp) &(fp->fh_nfs_handle.v2),
278 sizeof(fp->fh_nfs_handle.v2));
280 if (fp->fh_cid)
281 untimeout(fp->fh_cid);
282 fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp);
283 } else if (error == EACCES) {
285 * Now decode the file handle return code.
287 plog(XLOG_INFO, "Filehandle denied for \"%s:%s\"",
288 fs->fs_host, path);
289 } else {
290 errno = error; /* XXX */
291 plog(XLOG_INFO, "Filehandle error for \"%s:%s\": %m",
292 fs->fs_host, path);
296 * The error was returned from the remote mount daemon.
297 * Policy: this error will be cached for now...
299 return error;
301 case -1:
303 * Still thinking about it, but we can re-use.
305 fp_save = fp;
306 reuse_id = TRUE;
307 break;
309 default:
311 * Return the error.
312 * Policy: make sure we recompute if required again
313 * in case this was caused by a network failure.
314 * This can thrash mountd's though... If you find
315 * your mountd going slowly then:
316 * 1. Add a fork() loop to main.
317 * 2. Remove the call to innetgr() and don't use
318 * netgroups, especially if you don't use YP.
320 error = fp->fh_error;
321 fp->fh_error = -1;
322 return error;
324 break;
329 * Not in cache
331 if (fp_save) {
332 fp = fp_save;
334 * Re-use existing slot
336 untimeout(fp->fh_cid);
337 free_srvr(fp->fh_fs);
338 XFREE(fp->fh_path);
339 } else {
340 fp = ALLOC(struct fh_cache);
341 memset((voidp) fp, 0, sizeof(struct fh_cache));
342 ins_que(&fp->fh_q, &fh_head);
344 if (!reuse_id)
345 fp->fh_id = FHID_ALLOC(struct );
346 fp->fh_wchan = wchan;
347 fp->fh_error = -1;
348 fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp);
351 * if fs->fs_ip is null, remote server is probably down.
353 if (!fs->fs_ip) {
354 /* Mark the fileserver down and invalid again */
355 fs->fs_flags &= ~FSF_VALID;
356 fs->fs_flags |= FSF_DOWN;
357 error = AM_ERRNO_HOST_DOWN;
358 return error;
362 * If the address has changed then don't try to re-use the
363 * port information
365 if (fp->fh_sin.sin_addr.s_addr != fs->fs_ip->sin_addr.s_addr) {
366 fp->fh_sin = *fs->fs_ip;
367 fp->fh_sin.sin_port = 0;
368 fp->fh_nfs_version = fs->fs_version;
370 fp->fh_fs = dup_srvr(fs);
371 fp->fh_path = strdup(path);
373 error = call_mountd(fp, MOUNTPROC_MNT, got_nfs_fh, wchan);
374 if (error) {
376 * Local error - cache for a short period
377 * just to prevent thrashing.
379 untimeout(fp->fh_cid);
380 fp->fh_cid = timeout(error < 0 ? 2 * ALLOWED_MOUNT_TIME : FH_TTL_ERROR,
381 discard_fh, (voidp) fp);
382 fp->fh_error = error;
383 } else {
384 error = fp->fh_error;
387 return error;
392 make_nfs_auth(void)
394 AUTH_CREATE_GIDLIST_TYPE group_wheel = 0;
396 /* Some NFS mounts (particularly cross-domain) require FQDNs to succeed */
398 #ifdef HAVE_TRANSPORT_TYPE_TLI
399 if (gopt.flags & CFM_FULLY_QUALIFIED_HOSTS) {
400 plog(XLOG_INFO, "Using NFS auth for fqhn \"%s\"", hostd);
401 nfs_auth = authsys_create(hostd, 0, 0, 1, &group_wheel);
402 } else {
403 nfs_auth = authsys_create_default();
405 #else /* not HAVE_TRANSPORT_TYPE_TLI */
406 if (gopt.flags & CFM_FULLY_QUALIFIED_HOSTS) {
407 plog(XLOG_INFO, "Using NFS auth for fqhn \"%s\"", hostd);
408 nfs_auth = authunix_create(hostd, 0, 0, 1, &group_wheel);
409 } else {
410 nfs_auth = authunix_create_default();
412 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
414 if (!nfs_auth)
415 return ENOBUFS;
417 return 0;
421 static int
422 call_mountd(fh_cache *fp, u_long proc, fwd_fun f, voidp wchan)
424 struct rpc_msg mnt_msg;
425 int len;
426 char iobuf[8192];
427 int error;
428 u_long mnt_version;
430 if (!nfs_auth) {
431 error = make_nfs_auth();
432 if (error)
433 return error;
436 if (fp->fh_sin.sin_port == 0) {
437 u_short port;
438 error = nfs_srvr_port(fp->fh_fs, &port, wchan);
439 if (error)
440 return error;
441 fp->fh_sin.sin_port = port;
444 /* find the right version of the mount protocol */
445 #ifdef HAVE_FS_NFS3
446 if (fp->fh_nfs_version == NFS_VERSION3)
447 mnt_version = MOUNTVERS3;
448 else
449 #endif /* HAVE_FS_NFS3 */
450 mnt_version = MOUNTVERS;
451 plog(XLOG_INFO, "call_mountd: NFS version %d, mount version %d",
452 (int) fp->fh_nfs_version, (int) mnt_version);
454 rpc_msg_init(&mnt_msg, MOUNTPROG, mnt_version, MOUNTPROC_NULL);
455 len = make_rpc_packet(iobuf,
456 sizeof(iobuf),
457 proc,
458 &mnt_msg,
459 (voidp) &fp->fh_path,
460 (XDRPROC_T_TYPE) xdr_nfspath,
461 nfs_auth);
463 if (len > 0) {
464 error = fwd_packet(MK_RPC_XID(RPC_XID_MOUNTD, fp->fh_id),
465 (voidp) iobuf,
466 len,
467 &fp->fh_sin,
468 &fp->fh_sin,
469 (voidp) ((long) fp->fh_id), /* for 64-bit archs */
471 } else {
472 error = -len;
476 * It may be the case that we're sending to the wrong MOUNTD port. This
477 * occurs if mountd is restarted on the server after the port has been
478 * looked up and stored in the filehandle cache somewhere. The correct
479 * solution, if we're going to cache port numbers is to catch the ICMP
480 * port unreachable reply from the server and cause the portmap request
481 * to be redone. The quick solution here is to invalidate the MOUNTD
482 * port.
484 fp->fh_sin.sin_port = 0;
486 return error;
491 * NFS needs the local filesystem, remote filesystem
492 * remote hostname.
493 * Local filesystem defaults to remote and vice-versa.
495 char *
496 nfs_match(am_opts *fo)
498 char *xmtab;
500 if (fo->opt_fs && !fo->opt_rfs)
501 fo->opt_rfs = fo->opt_fs;
502 if (!fo->opt_rfs) {
503 plog(XLOG_USER, "nfs: no remote filesystem specified");
504 return NULL;
506 if (!fo->opt_rhost) {
507 plog(XLOG_USER, "nfs: no remote host specified");
508 return NULL;
512 * Determine magic cookie to put in mtab
514 xmtab = (char *) xmalloc(strlen(fo->opt_rhost) + strlen(fo->opt_rfs) + 2);
515 sprintf(xmtab, "%s:%s", fo->opt_rhost, fo->opt_rfs);
516 #ifdef DEBUG
517 dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"",
518 fo->opt_rhost, fo->opt_rfs, fo->opt_fs);
519 #endif /* DEBUG */
521 return xmtab;
526 * Initialize am structure for nfs
529 nfs_init(mntfs *mf)
531 int error;
532 am_nfs_handle_t fhs;
533 char *colon;
535 if (mf->mf_private)
536 return 0;
538 colon = strchr(mf->mf_info, ':');
539 if (colon == 0)
540 return ENOENT;
542 error = prime_nfs_fhandle_cache(colon + 1, mf->mf_server, &fhs, (voidp) mf);
543 if (!error) {
544 mf->mf_private = (voidp) ALLOC(am_nfs_handle_t);
545 mf->mf_prfree = (void (*)(voidp)) free;
546 memmove(mf->mf_private, (voidp) &fhs, sizeof(fhs));
548 return error;
553 mount_nfs_fh(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *mf)
555 MTYPE_TYPE type;
556 char *colon;
557 char *xopts;
558 char host[MAXHOSTNAMELEN + MAXPATHLEN + 2];
559 fserver *fs = mf->mf_server;
560 u_long nfs_version = fs->fs_version;
561 char *nfs_proto = fs->fs_proto; /* "tcp" or "udp" */
562 int error;
563 int genflags;
564 int retry;
565 mntent_t mnt;
566 nfs_args_t nfs_args;
569 * Extract HOST name to give to kernel.
570 * Some systems like osf1/aix3/bsd44 variants may need old code
571 * for NFS_ARGS_NEEDS_PATH.
573 if (!(colon = strchr(fs_name, ':')))
574 return ENOENT;
575 #ifdef MOUNT_TABLE_ON_FILE
576 *colon = '\0';
577 #endif /* MOUNT_TABLE_ON_FILE */
578 strncpy(host, fs_name, sizeof(host));
579 #ifdef MOUNT_TABLE_ON_FILE
580 *colon = ':';
581 #endif /* MOUNT_TABLE_ON_FILE */
582 #ifdef MAXHOSTNAMELEN
583 /* most kernels have a name length restriction */
584 if (strlen(host) >= MAXHOSTNAMELEN)
585 strcpy(host + MAXHOSTNAMELEN - 3, "..");
586 #endif /* MAXHOSTNAMELEN */
588 if (mf->mf_remopts && *mf->mf_remopts &&
589 !islocalnet(fs->fs_ip->sin_addr.s_addr)) {
590 plog(XLOG_INFO, "Using remopts=\"%s\"", mf->mf_remopts);
591 xopts = strdup(mf->mf_remopts);
592 } else {
593 xopts = strdup(opts);
596 memset((voidp) &mnt, 0, sizeof(mnt));
597 mnt.mnt_dir = dir;
598 mnt.mnt_fsname = fs_name;
599 mnt.mnt_opts = xopts;
602 * Set mount types accordingly
604 #ifndef HAVE_FS_NFS3
605 type = MOUNT_TYPE_NFS;
606 mnt.mnt_type = MNTTAB_TYPE_NFS;
607 #else /* HAVE_FS_NFS3 */
608 if (nfs_version == NFS_VERSION3) {
609 type = MOUNT_TYPE_NFS3;
611 * Systems that include the mount table "vers" option generally do not
612 * set the mnttab entry to "nfs3", but to "nfs" and then they set
613 * "vers=3". Setting it to "nfs3" works, but it may break some things
614 * like "df -t nfs" and the "quota" program (esp. on Solaris and Irix).
615 * So on those systems, set it to "nfs".
616 * Note: MNTTAB_OPT_VERS is always set for NFS3 (see am_compat.h).
618 # if defined(MNTTAB_OPT_VERS) && defined(MOUNT_TABLE_ON_FILE)
619 mnt.mnt_type = MNTTAB_TYPE_NFS;
620 # else /* defined(MNTTAB_OPT_VERS) && defined(MOUNT_TABLE_ON_FILE) */
621 mnt.mnt_type = MNTTAB_TYPE_NFS3;
622 # endif /* defined(MNTTAB_OPT_VERS) && defined(MOUNT_TABLE_ON_FILE) */
623 } else {
624 type = MOUNT_TYPE_NFS;
625 mnt.mnt_type = MNTTAB_TYPE_NFS;
627 #endif /* HAVE_FS_NFS3 */
628 plog(XLOG_INFO, "mount_nfs_fh: NFS version %d", (int) nfs_version);
629 #if defined(HAVE_FS_NFS3) || defined(HAVE_TRANSPORT_TYPE_TLI)
630 plog(XLOG_INFO, "mount_nfs_fh: using NFS transport %s", nfs_proto);
631 #endif /* defined(HAVE_FS_NFS3) || defined(HAVE_TRANSPORT_TYPE_TLI) */
633 retry = hasmntval(&mnt, MNTTAB_OPT_RETRY);
634 if (retry <= 0)
635 retry = 1; /* XXX */
637 genflags = compute_mount_flags(&mnt);
639 /* setup the many fields and flags within nfs_args */
640 #ifdef HAVE_TRANSPORT_TYPE_TLI
641 compute_nfs_args(&nfs_args,
642 &mnt,
643 genflags,
644 NULL, /* struct netconfig *nfsncp */
645 fs->fs_ip,
646 nfs_version,
647 nfs_proto,
648 fhp,
649 host,
650 fs_name);
651 #else /* not HAVE_TRANSPORT_TYPE_TLI */
652 compute_nfs_args(&nfs_args,
653 &mnt,
654 genflags,
655 fs->fs_ip,
656 nfs_version,
657 nfs_proto,
658 fhp,
659 host,
660 fs_name);
661 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
663 /* finally call the mounting function */
664 #ifdef DEBUG
665 amuDebug(D_TRACE) {
666 print_nfs_args(&nfs_args, nfs_version);
667 plog(XLOG_DEBUG, "Generic mount flags 0x%x", genflags);
669 #endif /* DEBUG */
670 error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type,
671 nfs_version, nfs_proto, mnttab_file_name);
672 XFREE(xopts);
674 #ifdef HAVE_TRANSPORT_TYPE_TLI
675 free_knetconfig(nfs_args.knconf);
676 if (nfs_args.addr)
677 XFREE(nfs_args.addr); /* allocated in compute_nfs_args() */
678 #endif /* HAVE_TRANSPORT_TYPE_TLI */
680 return error;
684 static int
685 mount_nfs(char *dir, char *fs_name, char *opts, mntfs *mf)
687 if (!mf->mf_private) {
688 plog(XLOG_ERROR, "Missing filehandle for %s", fs_name);
689 return EINVAL;
692 return mount_nfs_fh((am_nfs_handle_t *) mf->mf_private, dir, fs_name, opts, mf);
697 nfs_fmount(mntfs *mf)
699 int error = 0;
701 error = mount_nfs(mf->mf_mount, mf->mf_info, mf->mf_mopts, mf);
703 #ifdef DEBUG
704 if (error) {
705 errno = error;
706 dlog("mount_nfs: %m");
708 #endif /* DEBUG */
710 return error;
715 nfs_fumount(mntfs *mf)
717 int error = UMOUNT_FS(mf->mf_mount, mnttab_file_name);
720 * Here is some code to unmount 'restarted' file systems.
721 * The restarted file systems are marked as 'nfs', not
722 * 'host', so we only have the map information for the
723 * the top-level mount. The unmount will fail (EBUSY)
724 * if there are anything else from the NFS server mounted
725 * below the mount-point. This code checks to see if there
726 * is anything mounted with the same prefix as the
727 * file system to be unmounted ("/a/b/c" when unmounting "/a/b").
728 * If there is, and it is a 'restarted' file system, we unmount
729 * it.
730 * Added by Mike Mitchell, mcm@unx.sas.com, 09/08/93
732 if (error == EBUSY) {
733 mntfs *new_mf;
734 int len = strlen(mf->mf_mount);
735 int didsome = 0;
737 ITER(new_mf, mntfs, &mfhead) {
738 if (new_mf->mf_ops != mf->mf_ops ||
739 new_mf->mf_refc > 1 ||
740 mf == new_mf ||
741 ((new_mf->mf_flags & (MFF_MOUNTED | MFF_UNMOUNTING | MFF_RESTART)) == (MFF_MOUNTED | MFF_RESTART)))
742 continue;
744 if (NSTREQ(mf->mf_mount, new_mf->mf_mount, len) &&
745 new_mf->mf_mount[len] == '/') {
746 UMOUNT_FS(new_mf->mf_mount, mnttab_file_name);
747 didsome = 1;
750 if (didsome)
751 error = UMOUNT_FS(mf->mf_mount, mnttab_file_name);
753 if (error)
754 return error;
756 return 0;
760 void
761 nfs_umounted(am_node *mp)
764 * Don't bother to inform remote mountd that we are finished. Until a
765 * full track of filehandles is maintained the mountd unmount callback
766 * cannot be done correctly anyway...
768 mntfs *mf = mp->am_mnt;
769 fserver *fs;
770 char *colon, *path;
772 if (mf->mf_error || mf->mf_refc > 1)
773 return;
775 fs = mf->mf_server;
778 * Call the mount daemon on the server to announce that we are not using
779 * the fs any more.
781 * This is *wrong*. The mountd should be called when the fhandle is
782 * flushed from the cache, and a reference held to the cached entry while
783 * the fs is mounted...
785 colon = path = strchr(mf->mf_info, ':');
786 if (fs && colon) {
787 fh_cache f;
789 #ifdef DEBUG
790 dlog("calling mountd for %s", mf->mf_info);
791 #endif /* DEBUG */
792 *path++ = '\0';
793 f.fh_path = path;
794 f.fh_sin = *fs->fs_ip;
795 f.fh_sin.sin_port = (u_short) 0;
796 f.fh_nfs_version = fs->fs_version;
797 f.fh_fs = fs;
798 f.fh_id = 0;
799 f.fh_error = 0;
800 prime_nfs_fhandle_cache(colon + 1, mf->mf_server, (am_nfs_handle_t *) 0, (voidp) mf);
801 call_mountd(&f, MOUNTPROC_UMNT, (fwd_fun) 0, (voidp) 0);
802 *colon = ':';