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