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