138494Sobrien/* 2174294Sobrien * Copyright (c) 1997-2006 Erez Zadok 338494Sobrien * Copyright (c) 1990 Jan-Simon Pendry 438494Sobrien * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 538494Sobrien * Copyright (c) 1990 The Regents of the University of California. 638494Sobrien * All rights reserved. 738494Sobrien * 838494Sobrien * This code is derived from software contributed to Berkeley by 938494Sobrien * Jan-Simon Pendry at Imperial College, London. 1038494Sobrien * 1138494Sobrien * Redistribution and use in source and binary forms, with or without 1238494Sobrien * modification, are permitted provided that the following conditions 1338494Sobrien * are met: 1438494Sobrien * 1. Redistributions of source code must retain the above copyright 1538494Sobrien * notice, this list of conditions and the following disclaimer. 1638494Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1738494Sobrien * notice, this list of conditions and the following disclaimer in the 1838494Sobrien * documentation and/or other materials provided with the distribution. 1938494Sobrien * 3. All advertising materials mentioning features or use of this software 2042629Sobrien * must display the following acknowledgment: 2138494Sobrien * This product includes software developed by the University of 2238494Sobrien * California, Berkeley and its contributors. 2338494Sobrien * 4. Neither the name of the University nor the names of its contributors 2438494Sobrien * may be used to endorse or promote products derived from this software 2538494Sobrien * without specific prior written permission. 2638494Sobrien * 2738494Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2838494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2938494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3038494Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3138494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3238494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3338494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3438494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3538494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3638494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3738494Sobrien * SUCH DAMAGE. 3838494Sobrien * 3938494Sobrien * 40174294Sobrien * File: am-utils/amd/mntfs.c 4138494Sobrien * 4238494Sobrien */ 4338494Sobrien 4438494Sobrien#ifdef HAVE_CONFIG_H 4538494Sobrien# include <config.h> 4638494Sobrien#endif /* HAVE_CONFIG_H */ 4738494Sobrien#include <am_defs.h> 4838494Sobrien#include <amd.h> 4938494Sobrien 5038494Sobrienqelem mfhead = {&mfhead, &mfhead}; 5138494Sobrien 5238494Sobrienint mntfs_allocated; 5338494Sobrien 5438494Sobrien 5538494Sobrienmntfs * 5638494Sobriendup_mntfs(mntfs *mf) 5738494Sobrien{ 5838494Sobrien if (mf->mf_refc == 0) { 5938494Sobrien if (mf->mf_cid) 6038494Sobrien untimeout(mf->mf_cid); 6138494Sobrien mf->mf_cid = 0; 6238494Sobrien } 6338494Sobrien mf->mf_refc++; 6438494Sobrien 6538494Sobrien return mf; 6638494Sobrien} 6738494Sobrien 6838494Sobrien 6938494Sobrienstatic void 7038494Sobrieninit_mntfs(mntfs *mf, am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts) 7138494Sobrien{ 7238494Sobrien mf->mf_ops = ops; 73174294Sobrien mf->mf_fsflags = ops->nfs_fs_flags; 7438494Sobrien mf->mf_fo = mo; 7538494Sobrien mf->mf_mount = strdup(mp); 7638494Sobrien mf->mf_info = strdup(info); 7738494Sobrien mf->mf_auto = strdup(auto_opts); 7838494Sobrien mf->mf_mopts = strdup(mopts); 7938494Sobrien mf->mf_remopts = strdup(remopts); 80174294Sobrien mf->mf_loopdev = NULL; 8138494Sobrien mf->mf_refc = 1; 8238494Sobrien mf->mf_flags = 0; 8338494Sobrien mf->mf_error = -1; 8438494Sobrien mf->mf_cid = 0; 8538494Sobrien mf->mf_private = 0; 8638494Sobrien mf->mf_prfree = 0; 8738494Sobrien 8838494Sobrien if (ops->ffserver) 8938494Sobrien mf->mf_server = (*ops->ffserver) (mf); 9038494Sobrien else 9138494Sobrien mf->mf_server = 0; 9238494Sobrien} 9338494Sobrien 9438494Sobrien 9538494Sobrienstatic mntfs * 9638494Sobrienalloc_mntfs(am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts) 9738494Sobrien{ 9838494Sobrien mntfs *mf = ALLOC(struct mntfs); 9938494Sobrien 10038494Sobrien init_mntfs(mf, ops, mo, mp, info, auto_opts, mopts, remopts); 10138494Sobrien ins_que(&mf->mf_q, &mfhead); 10238494Sobrien mntfs_allocated++; 10338494Sobrien 10438494Sobrien return mf; 10538494Sobrien} 10638494Sobrien 10738494Sobrien 108174294Sobrien/* find a matching mntfs in our list */ 10938494Sobrienmntfs * 110174294Sobrienlocate_mntfs(am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts) 11138494Sobrien{ 11238494Sobrien mntfs *mf; 11338494Sobrien 114174294Sobrien dlog("Locating mntfs reference to (%s,%s)", mp, info); 11538494Sobrien 11638494Sobrien ITER(mf, mntfs, &mfhead) { 117174294Sobrien /* 118174294Sobrien * For backwards compatibility purposes, we treat already-mounted 119174294Sobrien * filesystems differently and only require a match of their mount point, 120174294Sobrien * not of their server info. After all, there is little we can do if 121174294Sobrien * the user asks us to mount two different things onto the same mount: one 122174294Sobrien * will always cover the other one. 123174294Sobrien */ 124174294Sobrien if (STREQ(mf->mf_mount, mp) && 125174294Sobrien ((mf->mf_flags & MFF_MOUNTED && !(mf->mf_fsflags & FS_DIRECT)) 126174294Sobrien || (STREQ(mf->mf_info, info) && mf->mf_ops == ops))) { 12738494Sobrien /* 12838494Sobrien * Handle cases where error ops are involved 12938494Sobrien */ 13038494Sobrien if (ops == &amfs_error_ops) { 13138494Sobrien /* 13238494Sobrien * If the existing ops are not amfs_error_ops 13338494Sobrien * then continue... 13438494Sobrien */ 13538494Sobrien if (mf->mf_ops != &amfs_error_ops) 13638494Sobrien continue; 137174294Sobrien return dup_mntfs(mf); 13838494Sobrien } 13938494Sobrien 140174294Sobrien dlog("mf->mf_flags = %#x", mf->mf_flags); 141174294Sobrien mf->mf_fo = mo; 142174294Sobrien if ((mf->mf_flags & MFF_RESTART) && amd_state < Finishing) { 14338494Sobrien /* 14438494Sobrien * Restart a previously mounted filesystem. 14538494Sobrien */ 14638494Sobrien dlog("Restarting filesystem %s", mf->mf_mount); 14738494Sobrien 14838494Sobrien /* 149174294Sobrien * If we are restarting an amd internal filesystem, 150174294Sobrien * we need to initialize it a bit. 151174294Sobrien * 152174294Sobrien * We know it's internal because it is marked as toplvl. 15338494Sobrien */ 154174294Sobrien if (mf->mf_ops == &amfs_toplvl_ops) { 155174294Sobrien mf->mf_ops = ops; 156174294Sobrien mf->mf_info = strealloc(mf->mf_info, info); 157174294Sobrien ops->mounted(mf); /* XXX: not right, but will do for now */ 158174294Sobrien } 159174294Sobrien 160174294Sobrien return mf; 16138494Sobrien } 16238494Sobrien 16338494Sobrien if (!(mf->mf_flags & (MFF_MOUNTED | MFF_MOUNTING | MFF_UNMOUNTING))) { 16438494Sobrien fserver *fs; 16538494Sobrien mf->mf_flags &= ~MFF_ERROR; 16638494Sobrien mf->mf_error = -1; 16738494Sobrien mf->mf_auto = strealloc(mf->mf_auto, auto_opts); 16838494Sobrien mf->mf_mopts = strealloc(mf->mf_mopts, mopts); 16938494Sobrien mf->mf_remopts = strealloc(mf->mf_remopts, remopts); 17038494Sobrien mf->mf_info = strealloc(mf->mf_info, info); 17138494Sobrien 17238494Sobrien if (mf->mf_private && mf->mf_prfree) { 173174294Sobrien mf->mf_prfree(mf->mf_private); 17438494Sobrien mf->mf_private = 0; 17538494Sobrien } 17638494Sobrien 17738494Sobrien fs = ops->ffserver ? (*ops->ffserver) (mf) : (fserver *) NULL; 17838494Sobrien if (mf->mf_server) 17938494Sobrien free_srvr(mf->mf_server); 18038494Sobrien mf->mf_server = fs; 18138494Sobrien } 18238494Sobrien return dup_mntfs(mf); 18382794Sobrien } /* end of "if (STREQ(mf-> ..." */ 18482794Sobrien } /* end of ITER */ 18538494Sobrien 186174294Sobrien return 0; 187174294Sobrien} 188174294Sobrien 189174294Sobrien 190174294Sobrien/* find a matching mntfs in our list, create a new one if none is found */ 191174294Sobrienmntfs * 192174294Sobrienfind_mntfs(am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts) 193174294Sobrien{ 194174294Sobrien mntfs *mf = locate_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts); 195174294Sobrien if (mf) 196174294Sobrien return mf; 197174294Sobrien 19838494Sobrien return alloc_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts); 19938494Sobrien} 20038494Sobrien 20138494Sobrien 20238494Sobrienmntfs * 20338494Sobriennew_mntfs(void) 20438494Sobrien{ 20538494Sobrien return alloc_mntfs(&amfs_error_ops, (am_opts *) 0, "//nil//", ".", "", "", ""); 20638494Sobrien} 20738494Sobrien 20838494Sobrien 20938494Sobrienstatic void 210174294Sobrienuninit_mntfs(mntfs *mf) 21138494Sobrien{ 21238494Sobrien if (mf->mf_auto) 21338494Sobrien XFREE(mf->mf_auto); 21438494Sobrien if (mf->mf_mopts) 21538494Sobrien XFREE(mf->mf_mopts); 21638494Sobrien if (mf->mf_remopts) 21738494Sobrien XFREE(mf->mf_remopts); 21838494Sobrien if (mf->mf_info) 21938494Sobrien XFREE(mf->mf_info); 22038494Sobrien if (mf->mf_private && mf->mf_prfree) 22138494Sobrien (*mf->mf_prfree) (mf->mf_private); 22238494Sobrien 22338494Sobrien if (mf->mf_mount) 22438494Sobrien XFREE(mf->mf_mount); 22538494Sobrien 22638494Sobrien /* 22738494Sobrien * Clean up the file server 22838494Sobrien */ 22938494Sobrien if (mf->mf_server) 23038494Sobrien free_srvr(mf->mf_server); 23138494Sobrien 23238494Sobrien /* 23338494Sobrien * Don't do a callback on this mount 23438494Sobrien */ 23538494Sobrien if (mf->mf_cid) { 23638494Sobrien untimeout(mf->mf_cid); 23738494Sobrien mf->mf_cid = 0; 23838494Sobrien } 23938494Sobrien} 24038494Sobrien 24138494Sobrien 24238494Sobrienstatic void 24338494Sobriendiscard_mntfs(voidp v) 24438494Sobrien{ 24538494Sobrien mntfs *mf = v; 24638494Sobrien 24738494Sobrien rem_que(&mf->mf_q); 24838494Sobrien 24938494Sobrien /* 25038494Sobrien * Free memory 25138494Sobrien */ 252174294Sobrien uninit_mntfs(mf); 25338494Sobrien XFREE(mf); 25438494Sobrien 25538494Sobrien --mntfs_allocated; 25638494Sobrien} 25738494Sobrien 25838494Sobrien 25938494Sobrienvoid 26038494Sobrienflush_mntfs(void) 26138494Sobrien{ 26238494Sobrien mntfs *mf; 26338494Sobrien 26438494Sobrien mf = AM_FIRST(mntfs, &mfhead); 26538494Sobrien while (mf != HEAD(mntfs, &mfhead)) { 26638494Sobrien mntfs *mf2 = mf; 26738494Sobrien mf = NEXT(mntfs, mf); 26838494Sobrien if (mf2->mf_refc == 0 && mf2->mf_cid) 26938494Sobrien discard_mntfs(mf2); 27038494Sobrien } 27138494Sobrien} 27238494Sobrien 27338494Sobrien 27438494Sobrienvoid 275174294Sobrienfree_mntfs(opaque_t arg) 27638494Sobrien{ 277174294Sobrien mntfs *mf = (mntfs *) arg; 27838494Sobrien 279174294Sobrien dlog("free_mntfs <%s> type %s mf_refc %d flags %x", 280174294Sobrien mf->mf_mount, mf->mf_ops->fs_type, mf->mf_refc, mf->mf_flags); 281174294Sobrien 282119679Smbr /* 283119679Smbr * We shouldn't ever be called to free something that has 284119679Smbr * a non-positive refcount. Something is badly wrong if 285119679Smbr * we have been! Ignore the request for now... 286119679Smbr */ 287174294Sobrien if (mf->mf_refc <= 0) { 288174294Sobrien plog(XLOG_ERROR, "IGNORING free_mntfs for <%s>: refc %d, flags %x (bug?)", 289119679Smbr mf->mf_mount, mf->mf_refc, mf->mf_flags); 290119679Smbr return; 291119679Smbr } 292119679Smbr 293174294Sobrien /* don't discard last reference of a restarted/kept mntfs */ 294174294Sobrien if (mf->mf_refc == 1 && mf->mf_flags & MFF_RSTKEEP) { 295174294Sobrien plog(XLOG_ERROR, "IGNORING free_mntfs for <%s>: refc %d, flags %x (restarted)", 296174294Sobrien mf->mf_mount, mf->mf_refc, mf->mf_flags); 297174294Sobrien return; 298174294Sobrien } 299174294Sobrien 30038494Sobrien if (--mf->mf_refc == 0) { 30138494Sobrien if (mf->mf_flags & MFF_MOUNTED) { 30238494Sobrien int quoted; 30338494Sobrien mf->mf_flags &= ~MFF_MOUNTED; 30438494Sobrien 30538494Sobrien /* 30638494Sobrien * Record for posterity 30738494Sobrien */ 30838494Sobrien quoted = strchr(mf->mf_info, ' ') != 0; /* cheap */ 30938494Sobrien plog(XLOG_INFO, "%s%s%s %sed fstype %s from %s", 31038494Sobrien quoted ? "\"" : "", 31138494Sobrien mf->mf_info, 31238494Sobrien quoted ? "\"" : "", 31338494Sobrien mf->mf_error ? "discard" : "unmount", 31438494Sobrien mf->mf_ops->fs_type, mf->mf_mount); 31538494Sobrien } 31638494Sobrien 317174294Sobrien if (mf->mf_fsflags & FS_DISCARD) { 31838494Sobrien dlog("Immediately discarding mntfs for %s", mf->mf_mount); 31938494Sobrien discard_mntfs(mf); 32038494Sobrien 32138494Sobrien } else { 32238494Sobrien 32338494Sobrien if (mf->mf_flags & MFF_RESTART) { 32438494Sobrien dlog("Discarding remount hook for %s", mf->mf_mount); 32538494Sobrien } else { 32638494Sobrien dlog("Discarding last mntfs reference to %s fstype %s", 32738494Sobrien mf->mf_mount, mf->mf_ops->fs_type); 32838494Sobrien } 32938494Sobrien if (mf->mf_flags & (MFF_MOUNTED | MFF_MOUNTING | MFF_UNMOUNTING)) 33038494Sobrien dlog("mntfs reference for %s still active", mf->mf_mount); 33138494Sobrien mf->mf_cid = timeout(ALLOWED_MOUNT_TIME, discard_mntfs, (voidp) mf); 33238494Sobrien } 33338494Sobrien } 33438494Sobrien} 33538494Sobrien 33638494Sobrien 33738494Sobrienmntfs * 33838494Sobrienrealloc_mntfs(mntfs *mf, am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts) 33938494Sobrien{ 34038494Sobrien mntfs *mf2; 34138494Sobrien 34282794Sobrien if (mf->mf_refc == 1 && 343174294Sobrien mf->mf_flags & MFF_RESTART && 34482794Sobrien STREQ(mf->mf_mount, mp)) { 34538494Sobrien /* 34638494Sobrien * If we are inheriting then just return 34738494Sobrien * the same node... 34838494Sobrien */ 34938494Sobrien return mf; 35038494Sobrien } 35138494Sobrien 35238494Sobrien /* 35338494Sobrien * Re-use the existing mntfs if it is mounted. 35438494Sobrien * This traps a race in nfsx. 35538494Sobrien */ 35638494Sobrien if (mf->mf_ops != &amfs_error_ops && 35738494Sobrien (mf->mf_flags & MFF_MOUNTED) && 35838494Sobrien !FSRV_ISDOWN(mf->mf_server)) { 35938494Sobrien mf->mf_fo = mo; 36038494Sobrien return mf; 36138494Sobrien } 36238494Sobrien 36338494Sobrien mf2 = find_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts); 36438494Sobrien free_mntfs(mf); 36538494Sobrien return mf2; 36638494Sobrien} 367