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