Home | History | Annotate | Line # | Download | only in amd
      1 /*	$NetBSD: mntfs.c,v 1.1.1.3 2015/01/17 16:34:15 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997-2014 Erez Zadok
      5  * Copyright (c) 1990 Jan-Simon Pendry
      6  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
      7  * Copyright (c) 1990 The Regents of the University of California.
      8  * All rights reserved.
      9  *
     10  * This code is derived from software contributed to Berkeley by
     11  * Jan-Simon Pendry at Imperial College, London.
     12  *
     13  * Redistribution and use in source and binary forms, with or without
     14  * modification, are permitted provided that the following conditions
     15  * are met:
     16  * 1. Redistributions of source code must retain the above copyright
     17  *    notice, this list of conditions and the following disclaimer.
     18  * 2. Redistributions in binary form must reproduce the above copyright
     19  *    notice, this list of conditions and the following disclaimer in the
     20  *    documentation and/or other materials provided with the distribution.
     21  * 3. Neither the name of the University nor the names of its contributors
     22  *    may be used to endorse or promote products derived from this software
     23  *    without specific prior written permission.
     24  *
     25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     35  * SUCH DAMAGE.
     36  *
     37  *
     38  * File: am-utils/amd/mntfs.c
     39  *
     40  */
     41 
     42 #ifdef HAVE_CONFIG_H
     43 # include <config.h>
     44 #endif /* HAVE_CONFIG_H */
     45 #include <am_defs.h>
     46 #include <amd.h>
     47 
     48 qelem mfhead = {&mfhead, &mfhead};
     49 
     50 int mntfs_allocated;
     51 
     52 
     53 am_loc *
     54 dup_loc(am_loc *loc)
     55 {
     56   loc->al_refc++;
     57   if (loc->al_mnt) {
     58     dup_mntfs(loc->al_mnt);
     59   }
     60   return loc;
     61 }
     62 
     63 mntfs *
     64 dup_mntfs(mntfs *mf)
     65 {
     66   if (mf->mf_refc == 0) {
     67     if (mf->mf_cid)
     68       untimeout(mf->mf_cid);
     69     mf->mf_cid = 0;
     70   }
     71   mf->mf_refc++;
     72 
     73   return mf;
     74 }
     75 
     76 
     77 static void
     78 init_mntfs(mntfs *mf, am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts)
     79 {
     80   mf->mf_ops = ops;
     81   mf->mf_fsflags = ops->nfs_fs_flags;
     82   mf->mf_fo = 0;
     83   if (mo)
     84     mf->mf_fo = copy_opts(mo);
     85 
     86   mf->mf_mount = xstrdup(mp);
     87   mf->mf_info = xstrdup(info);
     88   mf->mf_auto = xstrdup(auto_opts);
     89   mf->mf_mopts = xstrdup(mopts);
     90   mf->mf_remopts = xstrdup(remopts);
     91   mf->mf_loopdev = NULL;
     92   mf->mf_refc = 1;
     93   mf->mf_flags = 0;
     94   mf->mf_error = -1;
     95   mf->mf_cid = 0;
     96   mf->mf_private = NULL;
     97   mf->mf_prfree = NULL;
     98 
     99   if (ops->ffserver)
    100     mf->mf_server = (*ops->ffserver) (mf);
    101   else
    102     mf->mf_server = NULL;
    103 }
    104 
    105 
    106 static mntfs *
    107 alloc_mntfs(am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts)
    108 {
    109   mntfs *mf = ALLOC(struct mntfs);
    110 
    111   init_mntfs(mf, ops, mo, mp, info, auto_opts, mopts, remopts);
    112   ins_que(&mf->mf_q, &mfhead);
    113   mntfs_allocated++;
    114 
    115   return mf;
    116 }
    117 
    118 
    119 /* find a matching mntfs in our list */
    120 mntfs *
    121 locate_mntfs(am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts)
    122 {
    123   mntfs *mf;
    124 
    125   dlog("Locating mntfs reference to (%s,%s)", mp, info);
    126 
    127   ITER(mf, mntfs, &mfhead) {
    128     /*
    129      * For backwards compatibility purposes, we treat already-mounted
    130      * filesystems differently and only require a match of their mount point,
    131      * not of their server info. After all, there is little we can do if
    132      * the user asks us to mount two different things onto the same mount: one
    133      * will always cover the other one.
    134      */
    135     if (STREQ(mf->mf_mount, mp) &&
    136 	((mf->mf_flags & MFF_MOUNTED && !(mf->mf_fsflags & FS_DIRECT))
    137 	 || (STREQ(mf->mf_info, info) && mf->mf_ops == ops))) {
    138       /*
    139        * Handle cases where error ops are involved
    140        */
    141       if (ops == &amfs_error_ops) {
    142 	/*
    143 	 * If the existing ops are not amfs_error_ops
    144 	 * then continue...
    145 	 */
    146 	if (mf->mf_ops != &amfs_error_ops)
    147 	  continue;
    148 	return dup_mntfs(mf);
    149       }
    150 
    151       dlog("mf->mf_flags = %#x", mf->mf_flags);
    152 
    153       if ((mf->mf_flags & MFF_RESTART) && amd_state < Finishing) {
    154 	/*
    155 	 * Restart a previously mounted filesystem.
    156 	 */
    157 	dlog("Restarting filesystem %s", mf->mf_mount);
    158 
    159 	/*
    160 	 * If we are restarting an amd internal filesystem,
    161 	 * we need to initialize it a bit.
    162 	 *
    163 	 * We know it's internal because it is marked as toplvl.
    164 	 */
    165 	if (mf->mf_ops == &amfs_toplvl_ops) {
    166 	  mf->mf_ops = ops;
    167 	  mf->mf_info = strealloc(mf->mf_info, info);
    168 	  ops->mounted(mf);	/* XXX: not right, but will do for now */
    169 	}
    170 
    171 	return mf;
    172       }
    173 
    174       if (!(mf->mf_flags & (MFF_MOUNTED | MFF_MOUNTING | MFF_UNMOUNTING))) {
    175 	fserver *fs;
    176 	mf->mf_flags &= ~MFF_ERROR;
    177 	mf->mf_error = -1;
    178 	mf->mf_auto = strealloc(mf->mf_auto, auto_opts);
    179 	mf->mf_mopts = strealloc(mf->mf_mopts, mopts);
    180 	mf->mf_remopts = strealloc(mf->mf_remopts, remopts);
    181 	mf->mf_info = strealloc(mf->mf_info, info);
    182 
    183 	if (mf->mf_private && mf->mf_prfree) {
    184 	  mf->mf_prfree(mf->mf_private);
    185 	  mf->mf_private = NULL;
    186 	}
    187 
    188 	fs = ops->ffserver ? (*ops->ffserver) (mf) : (fserver *) NULL;
    189 	if (mf->mf_server)
    190 	  free_srvr(mf->mf_server);
    191 	mf->mf_server = fs;
    192       }
    193       return dup_mntfs(mf);
    194     } /* end of "if (STREQ(mf-> ..." */
    195   } /* end of ITER */
    196 
    197   return 0;
    198 }
    199 
    200 
    201 /* find a matching mntfs in our list, create a new one if none is found */
    202 mntfs *
    203 find_mntfs(am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts)
    204 {
    205   mntfs *mf = locate_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts);
    206   if (mf)
    207     return mf;
    208 
    209   return alloc_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts);
    210 }
    211 
    212 
    213 mntfs *
    214 new_mntfs(void)
    215 {
    216   return alloc_mntfs(&amfs_error_ops, (am_opts *) NULL, "//nil//", ".", "", "", "");
    217 }
    218 
    219 am_loc *
    220 new_loc(void)
    221 {
    222   am_loc *loc = CALLOC(struct am_loc);
    223   loc->al_fo = 0;
    224   loc->al_mnt = new_mntfs();
    225   loc->al_refc = 1;
    226   return loc;
    227 }
    228 
    229 
    230 static void
    231 uninit_mntfs(mntfs *mf)
    232 {
    233   if (mf->mf_fo) {
    234     free_opts(mf->mf_fo);
    235     XFREE(mf->mf_fo);
    236   }
    237   XFREE(mf->mf_auto);
    238   XFREE(mf->mf_mopts);
    239   XFREE(mf->mf_remopts);
    240   XFREE(mf->mf_info);
    241   if (mf->mf_private && mf->mf_prfree)
    242     (*mf->mf_prfree) (mf->mf_private);
    243 
    244   XFREE(mf->mf_mount);
    245 
    246   /*
    247    * Clean up the file server
    248    */
    249   if (mf->mf_server)
    250     free_srvr(mf->mf_server);
    251 
    252   /*
    253    * Don't do a callback on this mount
    254    */
    255   if (mf->mf_cid) {
    256     untimeout(mf->mf_cid);
    257     mf->mf_cid = 0;
    258   }
    259 }
    260 
    261 
    262 static void
    263 discard_mntfs(voidp v)
    264 {
    265   mntfs *mf = v;
    266 
    267   rem_que(&mf->mf_q);
    268 
    269   /*
    270    * Free memory
    271    */
    272   uninit_mntfs(mf);
    273   XFREE(mf);
    274 
    275   --mntfs_allocated;
    276 }
    277 
    278 static void
    279 discard_loc(voidp v)
    280 {
    281   am_loc *loc = v;
    282   if (loc->al_fo) {
    283     free_opts(loc->al_fo);
    284     XFREE(loc->al_fo);
    285   }
    286   XFREE(loc);
    287 }
    288 
    289 void
    290 flush_mntfs(void)
    291 {
    292   mntfs *mf;
    293 
    294   mf = AM_FIRST(mntfs, &mfhead);
    295   while (mf != HEAD(mntfs, &mfhead)) {
    296     mntfs *mf2 = mf;
    297     mf = NEXT(mntfs, mf);
    298     if (mf2->mf_refc == 0 && mf2->mf_cid)
    299       discard_mntfs(mf2);
    300   }
    301 }
    302 
    303 void
    304 free_loc(opaque_t arg)
    305 {
    306   am_loc *loc = (am_loc *) arg;
    307   dlog("free_loc %p", loc);
    308 
    309   if (loc->al_refc <= 0) {
    310     plog(XLOG_ERROR, "IGNORING free_loc for 0x%p", loc);
    311     return;
    312   }
    313 
    314   if (loc->al_mnt)
    315     free_mntfs(loc->al_mnt);
    316   if (--loc->al_refc == 0) {
    317     discard_loc(loc);
    318   }
    319 }
    320 
    321 void
    322 free_mntfs(opaque_t arg)
    323 {
    324   mntfs *mf = (mntfs *) arg;
    325 
    326   dlog("free_mntfs <%s> type %s mf_refc %d flags %x",
    327        mf->mf_mount, mf->mf_ops->fs_type, mf->mf_refc, mf->mf_flags);
    328 
    329   /*
    330    * We shouldn't ever be called to free something that has
    331    * a non-positive refcount.  Something is badly wrong if
    332    * we have been!  Ignore the request for now...
    333    */
    334   if (mf->mf_refc <= 0) {
    335     plog(XLOG_ERROR, "IGNORING free_mntfs for <%s>: refc %d, flags %x (bug?)",
    336          mf->mf_mount, mf->mf_refc, mf->mf_flags);
    337     return;
    338   }
    339 
    340   /* don't discard last reference of a restarted/kept mntfs */
    341   if (mf->mf_refc == 1 && mf->mf_flags & MFF_RSTKEEP) {
    342     plog(XLOG_ERROR, "IGNORING free_mntfs for <%s>: refc %d, flags %x (restarted)",
    343          mf->mf_mount, mf->mf_refc, mf->mf_flags);
    344     return;
    345   }
    346 
    347   if (--mf->mf_refc == 0) {
    348     if (mf->mf_flags & MFF_MOUNTED) {
    349       int quoted;
    350       mf->mf_flags &= ~MFF_MOUNTED;
    351 
    352       /*
    353        * Record for posterity
    354        */
    355       quoted = strchr(mf->mf_info, ' ') != 0;	/* cheap */
    356       plog(XLOG_INFO, "%s%s%s %sed fstype %s from %s",
    357 	   quoted ? "\"" : "",
    358 	   mf->mf_info,
    359 	   quoted ? "\"" : "",
    360 	   mf->mf_error ? "discard" : "unmount",
    361 	   mf->mf_ops->fs_type, mf->mf_mount);
    362     }
    363 
    364     if (mf->mf_fsflags & FS_DISCARD) {
    365       dlog("Immediately discarding mntfs for %s", mf->mf_mount);
    366       discard_mntfs(mf);
    367 
    368     } else {
    369 
    370       if (mf->mf_flags & MFF_RESTART) {
    371 	dlog("Discarding remount hook for %s", mf->mf_mount);
    372       } else {
    373 	dlog("Discarding last mntfs reference to %s fstype %s",
    374 	     mf->mf_mount, mf->mf_ops->fs_type);
    375       }
    376       if (mf->mf_flags & (MFF_MOUNTED | MFF_MOUNTING | MFF_UNMOUNTING))
    377 	dlog("mntfs reference for %s still active", mf->mf_mount);
    378       mf->mf_cid = timeout(ALLOWED_MOUNT_TIME, discard_mntfs, (voidp) mf);
    379     }
    380   }
    381 }
    382 
    383 
    384 mntfs *
    385 realloc_mntfs(mntfs *mf, am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts)
    386 {
    387   mntfs *mf2;
    388 
    389   if (mf->mf_refc == 1 &&
    390       mf->mf_flags & MFF_RESTART &&
    391       STREQ(mf->mf_mount, mp)) {
    392     /*
    393      * If we are inheriting then just return
    394      * the same node...
    395      */
    396     return mf;
    397   }
    398 
    399   /*
    400    * Re-use the existing mntfs if it is mounted.
    401    * This traps a race in nfsx.
    402    */
    403   if (mf->mf_ops != &amfs_error_ops &&
    404       (mf->mf_flags & MFF_MOUNTED) &&
    405       !FSRV_ISDOWN(mf->mf_server)) {
    406     return mf;
    407   }
    408 
    409   mf2 = find_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts);
    410   free_mntfs(mf);
    411   return mf2;
    412 }
    413