diff options
Diffstat (limited to 'amd/map.c')
-rw-r--r-- | amd/map.c | 294 |
1 files changed, 160 insertions, 134 deletions
diff --git a/amd/map.c b/amd/map.c index 8696dfd6984d..fce8273e4ef6 100644 --- a/amd/map.c +++ b/amd/map.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2006 Erez Zadok + * Copyright (c) 1997-2014 Erez Zadok * Copyright (c) 1990 Jan-Simon Pendry * Copyright (c) 1990 Imperial College of Science, Technology & Medicine * Copyright (c) 1990 The Regents of the University of California. @@ -16,11 +16,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgment: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -69,7 +65,7 @@ static u_int am_gen = 2; /* Initial generation number */ static int timeout_mp_id; /* Id from last call to timeout */ static am_node *root_node; /* The root of the mount tree */ -static am_node **exported_ap = (am_node **) 0; +static am_node **exported_ap = (am_node **) NULL; static int exported_ap_size = 0; static int first_free_map = 0; /* First available free slot */ static int last_used_map = -1; /* Last unavailable used slot */ @@ -190,7 +186,7 @@ am_node * get_ap_child(am_node *mp, char *fname) { am_node *new_mp; - mntfs *mf = mp->am_mnt; + mntfs *mf = mp->am_al->al_mnt; /* * Allocate a new map @@ -280,7 +276,7 @@ exported_ap_free(am_node *mp) /* * Zero the slot pointer to avoid double free's */ - exported_ap[mp->am_mapno] = 0; + exported_ap[mp->am_mapno] = NULL; /* * Update the free and last_used indices @@ -325,7 +321,7 @@ insert_am(am_node *mp, am_node *p_mp) mp->am_osib->am_ysib = mp; p_mp->am_child = mp; #ifdef HAVE_FS_AUTOFS - if (p_mp->am_mnt->mf_flags & MFF_IS_AUTOFS) + if (p_mp->am_al->al_mnt->mf_flags & MFF_IS_AUTOFS) mp->am_flags |= AMF_AUTOFS; #endif /* HAVE_FS_AUTOFS */ } @@ -408,13 +404,14 @@ init_map(am_node *mp, char *dir) * mp->am_mapno is initialized by exported_ap_alloc * other fields don't need to be set to zero. */ - mp->am_mnt = new_mntfs(); - mp->am_mfarray = 0; - mp->am_name = strdup(dir); - mp->am_path = strdup(dir); + + mp->am_al = new_loc(); + mp->am_alarray = NULL; + mp->am_name = xstrdup(dir); + mp->am_path = xstrdup(dir); mp->am_gen = new_gen(); #ifdef HAVE_FS_AUTOFS - mp->am_autofs_fh = 0; + mp->am_autofs_fh = NULL; #endif /* HAVE_FS_AUTOFS */ mp->am_timeo = gopt.am_timeo; @@ -430,6 +427,30 @@ init_map(am_node *mp, char *dir) mp->am_stats.s_mtime = mp->am_fattr.na_atime.nt_seconds; mp->am_dev = -1; mp->am_rdev = -1; + mp->am_fd[0] = -1; + mp->am_fd[1] = -1; +} + + +void +notify_child(am_node *mp, au_etype au_etype, int au_errno, int au_signal) +{ + amq_sync_umnt rv; + int err; + + if (mp->am_fd[1] >= 0) { /* we have a child process */ + rv.au_etype = au_etype; + rv.au_signal = au_signal; + rv.au_errno = au_errno; + + err = write(mp->am_fd[1], &rv, sizeof(rv)); + /* XXX: do something else on err? */ + if (err < sizeof(rv)) + plog(XLOG_INFO, "notify_child: write returned %d instead of %d.", + err, (int) sizeof(rv)); + close(mp->am_fd[1]); + mp->am_fd[1] = -1; + } } @@ -442,25 +463,24 @@ free_map(am_node *mp) { remove_am(mp); - if (mp->am_link) - XFREE(mp->am_link); - if (mp->am_name) - XFREE(mp->am_name); - if (mp->am_path) - XFREE(mp->am_path); - if (mp->am_pref) - XFREE(mp->am_pref); - if (mp->am_transp) - XFREE(mp->am_transp); - - if (mp->am_mnt) - free_mntfs(mp->am_mnt); - - if (mp->am_mfarray) { - mntfs **temp_mf; - for (temp_mf = mp->am_mfarray; *temp_mf; temp_mf++) - free_mntfs(*temp_mf); - XFREE(mp->am_mfarray); + if (mp->am_fd[1] != -1) + plog(XLOG_FATAL, "free_map: called prior to notifying the child for %s.", + mp->am_path); + + XFREE(mp->am_link); + XFREE(mp->am_name); + XFREE(mp->am_path); + XFREE(mp->am_pref); + XFREE(mp->am_transp); + + if (mp->am_al) + free_loc(mp->am_al); + + if (mp->am_alarray) { + am_loc **temp_al; + for (temp_al = mp->am_alarray; *temp_al; temp_al++) + free_loc(*temp_al); + XFREE(mp->am_alarray); } #ifdef HAVE_FS_AUTOFS @@ -480,8 +500,8 @@ find_ap_recursive(char *dir, am_node *mp) if (STREQ(mp->am_path, dir)) return mp; - if ((mp->am_mnt->mf_flags & MFF_MOUNTED) && - STREQ(mp->am_mnt->mf_mount, dir)) + if ((mp->am_al->al_mnt->mf_flags & MFF_MOUNTED) && + STREQ(mp->am_al->al_mnt->mf_mount, dir)) return mp; mp2 = find_ap_recursive(dir, mp->am_osib); @@ -518,37 +538,20 @@ find_ap(char *dir) /* - * Find the mount node corresponding - * to the mntfs structure. - */ -am_node * -find_mf(mntfs *mf) -{ - int i; - - for (i = last_used_map; i >= 0; --i) { - am_node *mp = exported_ap[i]; - if (mp && mp->am_mnt == mf) - return mp; - } - - return 0; -} - - -/* * Get the filehandle for a particular named directory. * This is used during the bootstrap to tell the kernel * the filehandles of the initial automount points. */ -am_nfs_fh * -get_root_nfs_fh(char *dir) +am_nfs_handle_t * +get_root_nfs_fh(char *dir, am_nfs_handle_t *nfh) { - static am_nfs_fh nfh; am_node *mp = get_root_ap(dir); if (mp) { - mp_to_fh(mp, &nfh); - return &nfh; + if (nfs_dispatcher == nfs_program_2) + mp_to_fh(mp, &nfh->v2); + else + mp_to_fh3(mp, &nfh->v3); + return nfh; } /* @@ -584,7 +587,8 @@ map_flush_srvr(fserver *fs) for (i = last_used_map; i >= 0; --i) { am_node *mp = exported_ap[i]; - if (mp && mp->am_mnt && mp->am_mnt->mf_server == fs) { + + if (mp && mp->am_al->al_mnt && mp->am_al->al_mnt->mf_server == fs) { plog(XLOG_INFO, "Flushed %s; dependent on %s", mp->am_path, fs->fs_host); mp->am_ttl = clocktime(NULL); done = 1; @@ -608,7 +612,7 @@ mount_auto_node(char *dir, opaque_t arg) am_node *mp = (am_node *) arg; am_node *new_mp; - new_mp = mp->am_mnt->mf_ops->lookup_child(mp, dir, &error, VLOOK_CREATE); + new_mp = mp->am_al->al_mnt->mf_ops->lookup_child(mp, dir, &error, VLOOK_CREATE); if (new_mp && error < 0) { /* * We can't allow the fileid of the root node to change. @@ -616,7 +620,7 @@ mount_auto_node(char *dir, opaque_t arg) */ new_mp->am_gen = new_mp->am_fattr.na_fileid = 1; - new_mp = mp->am_mnt->mf_ops->mount_child(new_mp, &error); + (void) mp->am_al->al_mnt->mf_ops->mount_child(new_mp, &error); } if (error > 0) { @@ -647,7 +651,7 @@ mount_exported(void) void make_root_node(void) { - mntfs *root_mnt; + mntfs *root_mf; char *rootmap = ROOT_MAP; root_node = exported_ap_alloc(); @@ -659,24 +663,24 @@ make_root_node(void) /* * Allocate a new mounted filesystem */ - root_mnt = find_mntfs(&amfs_root_ops, (am_opts *) 0, "", rootmap, "", "", ""); + root_mf = find_mntfs(&amfs_root_ops, (am_opts *) NULL, "", rootmap, "", "", ""); /* * Replace the initial null reference */ - free_mntfs(root_node->am_mnt); - root_node->am_mnt = root_mnt; + free_mntfs(root_node->am_al->al_mnt); + root_node->am_al->al_mnt = root_mf; /* * Initialize the root */ - if (root_mnt->mf_ops->fs_init) - (*root_mnt->mf_ops->fs_init) (root_mnt); + if (root_mf->mf_ops->fs_init) + (*root_mf->mf_ops->fs_init) (root_mf); /* * Mount the root */ - root_mnt->mf_error = root_mnt->mf_ops->mount_fs(root_node, root_mnt); + root_mf->mf_error = root_mf->mf_ops->mount_fs(root_node, root_mf); } @@ -687,68 +691,81 @@ make_root_node(void) void umount_exported(void) { - int i; + int i, work_done; - for (i = last_used_map; i >= 0; --i) { - am_node *mp = exported_ap[i]; - mntfs *mf; + do { + work_done = 0; - if (!mp) - continue; + for (i = last_used_map; i >= 0; --i) { + am_node *mp = exported_ap[i]; + mntfs *mf; - mf = mp->am_mnt; - if (mf->mf_flags & MFF_UNMOUNTING) { - /* - * If this node is being unmounted then just ignore it. However, - * this could prevent amd from finishing if the unmount gets blocked - * since the am_node will never be free'd. am_unmounted needs - * telling about this possibility. - XXX - */ - continue; - } + if (!mp) + continue; - if (!(mf->mf_fsflags & FS_DIRECTORY)) /* - * When shutting down this had better - * look like a directory, otherwise it - * can't be unmounted! + * Wait for children to be removed first */ - mk_fattr(&mp->am_fattr, NFDIR); + if (mp->am_child) + continue; - if ((--immediate_abort < 0 && - !(mp->am_flags & AMF_ROOT) && mp->am_parent) || - (mf->mf_flags & MFF_RESTART)) { + mf = mp->am_al->al_mnt; + if (mf->mf_flags & MFF_UNMOUNTING) { + /* + * If this node is being unmounted then just ignore it. However, + * this could prevent amd from finishing if the unmount gets blocked + * since the am_node will never be free'd. am_unmounted needs + * telling about this possibility. - XXX + */ + continue; + } + + if (!(mf->mf_fsflags & FS_DIRECTORY)) + /* + * When shutting down this had better + * look like a directory, otherwise it + * can't be unmounted! + */ + mk_fattr(&mp->am_fattr, NFDIR); + + if ((--immediate_abort < 0 && + !(mp->am_flags & AMF_ROOT) && mp->am_parent) || + (mf->mf_flags & MFF_RESTART)) { + + work_done++; - /* - * Just throw this node away without bothering to unmount it. If - * the server is not known to be up then don't discard the mounted - * on directory or Amd might hang... - */ - if (mf->mf_server && - (mf->mf_server->fs_flags & (FSF_DOWN | FSF_VALID)) != FSF_VALID) - mf->mf_flags &= ~MFF_MKMNT; - if (gopt.flags & CFM_UNMOUNT_ON_EXIT || mp->am_flags & AMF_AUTOFS) { - plog(XLOG_INFO, "on-exit attempt to unmount %s", mf->mf_mount); /* - * use unmount_mp, not unmount_node, so that unmounts be - * backgrounded as needed. + * Just throw this node away without bothering to unmount it. If + * the server is not known to be up then don't discard the mounted + * on directory or Amd might hang... */ - unmount_mp((opaque_t) mp); + if (mf->mf_server && + (mf->mf_server->fs_flags & (FSF_DOWN | FSF_VALID)) != FSF_VALID) + mf->mf_flags &= ~MFF_MKMNT; + if (gopt.flags & CFM_UNMOUNT_ON_EXIT || mp->am_flags & AMF_AUTOFS) { + plog(XLOG_INFO, "on-exit attempt to unmount %s", mf->mf_mount); + /* + * use unmount_mp, not unmount_node, so that unmounts be + * backgrounded as needed. + */ + unmount_mp((opaque_t) mp); + } else { + am_unmounted(mp); + } + if (!(mf->mf_flags && (MFF_UNMOUNTING|MFF_MOUNTED))) + exported_ap[i] = NULL; } else { - am_unmounted(mp); + /* + * Any other node gets forcibly timed out. + */ + mp->am_flags &= ~AMF_NOTIMEOUT; + mp->am_al->al_mnt->mf_flags &= ~MFF_RSTKEEP; + mp->am_ttl = 0; + mp->am_timeo = 1; + mp->am_timeo_w = 0; } - exported_ap[i] = 0; - } else { - /* - * Any other node gets forcibly timed out. - */ - mp->am_flags &= ~AMF_NOTIMEOUT; - mp->am_mnt->mf_flags &= ~MFF_RSTKEEP; - mp->am_ttl = 0; - mp->am_timeo = 1; - mp->am_timeo_w = 0; } - } + } while (work_done); } @@ -762,7 +779,7 @@ int mount_node(opaque_t arg) { am_node *mp = (am_node *) arg; - mntfs *mf = mp->am_mnt; + mntfs *mf = mp->am_al->al_mnt; int error = 0; #ifdef HAVE_FS_AUTOFS @@ -784,7 +801,7 @@ static int unmount_node(opaque_t arg) { am_node *mp = (am_node *) arg; - mntfs *mf = mp->am_mnt; + mntfs *mf = mp->am_al->al_mnt; int error = 0; if (mf->mf_flags & MFF_ERROR) { @@ -805,7 +822,7 @@ unmount_node(opaque_t arg) } /* do this again, it might have changed */ - mf = mp->am_mnt; + mf = mp->am_al->al_mnt; if (error) { errno = error; /* XXX */ dlog("%s: unmount: %m", mf->mf_mount); @@ -819,7 +836,7 @@ static void free_map_if_success(int rc, int term, opaque_t arg) { am_node *mp = (am_node *) arg; - mntfs *mf = mp->am_mnt; + mntfs *mf = mp->am_al->al_mnt; wchan_t wchan = get_mntfs_wchan(mf); /* @@ -836,6 +853,7 @@ free_map_if_success(int rc, int term, opaque_t arg) reschedule_timeout_mp(); } if (term) { + notify_child(mp, AMQ_UMNT_SIGNAL, 0, term); plog(XLOG_ERROR, "unmount for %s got signal %d", mp->am_path, term); #if defined(DEBUG) && defined(SIGTRAP) /* @@ -852,18 +870,24 @@ free_map_if_success(int rc, int term, opaque_t arg) #endif /* HAVE_FS_AUTOFS */ amd_stats.d_uerr++; } else if (rc) { + notify_child(mp, AMQ_UMNT_FAILED, rc, 0); if (mf->mf_ops == &amfs_program_ops || rc == EBUSY) plog(XLOG_STATS, "\"%s\" on %s still active", mp->am_path, mf->mf_mount); else plog(XLOG_ERROR, "%s: unmount: %s", mp->am_path, strerror(rc)); #ifdef HAVE_FS_AUTOFS - if (mf->mf_flags & MFF_IS_AUTOFS) - autofs_get_mp(mp); - if (mp->am_flags & AMF_AUTOFS) - autofs_umount_failed(mp); + if (rc != ENOENT) { + if (mf->mf_flags & MFF_IS_AUTOFS) + autofs_get_mp(mp); + if (mp->am_flags & AMF_AUTOFS) + autofs_umount_failed(mp); + } #endif /* HAVE_FS_AUTOFS */ amd_stats.d_uerr++; } else { + /* + * am_unmounted() will call notify_child() appropriately. + */ am_unmounted(mp); } @@ -878,11 +902,11 @@ int unmount_mp(am_node *mp) { int was_backgrounded = 0; - mntfs *mf = mp->am_mnt; + mntfs *mf = mp->am_al->al_mnt; #ifdef notdef plog(XLOG_INFO, "\"%s\" on %s timed out (flags 0x%x)", - mp->am_path, mp->am_mnt->mf_mount, (int) mf->mf_flags); + mp->am_path, mf->mf_mount, (int) mf->mf_flags); #endif /* notdef */ #ifndef MNT2_NFS_OPT_SYMTTL @@ -914,10 +938,11 @@ unmount_mp(am_node *mp) plog(XLOG_STATS, "file server %s is down - timeout of \"%s\" ignored", mf->mf_server->fs_host, mp->am_path); mf->mf_flags |= MFF_LOGDOWN; } + notify_child(mp, AMQ_UMNT_SERVER, 0, 0); return 0; } - dlog("\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount); + dlog("\"%s\" on %s timed out", mp->am_path, mf->mf_mount); mf->mf_flags |= MFF_UNMOUNTING; #ifdef HAVE_FS_AUTOFS @@ -926,7 +951,8 @@ unmount_mp(am_node *mp) #endif /* HAVE_FS_AUTOFS */ if ((mf->mf_fsflags & FS_UBACKGROUND) && - (mf->mf_flags & MFF_MOUNTED)) { + (mf->mf_flags & MFF_MOUNTED) && + !(mf->mf_flags & MFF_ON_AUTOFS)) { dlog("Trying unmount in background"); run_task(unmount_node, (opaque_t) mp, free_map_if_success, (opaque_t) mp); @@ -964,7 +990,7 @@ timeout_mp(opaque_t v) /* argument not used?! */ /* * Pick up mounted filesystem */ - mf = mp->am_mnt; + mf = mp->am_al->al_mnt; if (!mf) continue; @@ -1056,7 +1082,7 @@ timeout_mp(opaque_t v) /* argument not used?! */ t = now + 1; dlog("Next mount timeout in %lds", (long) (t - now)); - timeout_mp_id = timeout(t - now, timeout_mp, 0); + timeout_mp_id = timeout(t - now, timeout_mp, NULL); } @@ -1068,5 +1094,5 @@ reschedule_timeout_mp(void) { if (timeout_mp_id) untimeout(timeout_mp_id); - timeout_mp_id = timeout(0, timeout_mp, 0); + timeout_mp_id = timeout(0, timeout_mp, NULL); } |