1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $Id: vfs.c,v 1.1 94/10/19 17:09:24 bill Exp Locker: bill $ 34 * 35 * Virtual filesystem interface routines and implementation. 36 */ 37 38 #include "sys/param.h" 39 #include "sys/mount.h" 40 #include "sys/time.h" 41 #include "sys/file.h" 42 #include "sys/errno.h" 43 #include "sys/kinfo.h" 44 45 #include "proc.h" 46 #include "uio.h" 47 #include "specdev.h" 48 #include "buf.h" 49 #include "malloc.h" 50 #include "modconfig.h" 51 52 #include "vnode.h" 53 #include "namei.h" 54 55 #include "prototypes.h" 56 57 /*static*/ void insmntque(struct vnode *vp, struct mount *mp); 58 59 /* 60 * Remove a mount point from the list of mounted filesystems. 61 * Unmount of the root is illegal. 62 */ 63 void 64 vfs_remove(struct mount *mp) 65 { 66 67 if (mp == rootfs) 68 panic("vfs_remove: unmounting root"); 69 mp->mnt_prev->mnt_next = mp->mnt_next; 70 mp->mnt_next->mnt_prev = mp->mnt_prev; 71 mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 72 vfs_unlock(mp); 73 } 74 75 /* 76 * Lock a filesystem. 77 * Used to prevent access to it while mounting and unmounting. 78 */ 79 int 80 vfs_lock(struct mount *mp) 81 { 82 83 while(mp->mnt_flag & MNT_MLOCK) { 84 mp->mnt_flag |= MNT_MWAIT; 85 tsleep((caddr_t)mp, PVFS, "vfslock", 0); 86 } 87 mp->mnt_flag |= MNT_MLOCK; 88 return (0); 89 } 90 91 /* 92 * Unlock a locked filesystem. 93 * Panic if filesystem is not locked. 94 */ 95 void 96 vfs_unlock(struct mount *mp) 97 { 98 99 if ((mp->mnt_flag & MNT_MLOCK) == 0) 100 panic("vfs_unlock: not locked"); 101 mp->mnt_flag &= ~MNT_MLOCK; 102 if (mp->mnt_flag & MNT_MWAIT) { 103 mp->mnt_flag &= ~MNT_MWAIT; 104 wakeup((caddr_t)mp); 105 } 106 } 107 108 /* 109 * Mark a mount point as busy. 110 * Used to synchronize access and to delay unmounting. 111 */ 112 int 113 vfs_busy(struct mount *mp) 114 { 115 116 while(mp->mnt_flag & MNT_MPBUSY) { 117 mp->mnt_flag |= MNT_MPWANT; 118 tsleep((caddr_t)&mp->mnt_flag, PVFS, "vfsbusy", 0); 119 } 120 if (mp->mnt_flag & MNT_UNMOUNT) 121 return (1); 122 mp->mnt_flag |= MNT_MPBUSY; 123 return (0); 124 } 125 126 /* 127 * Free a busy filesystem. 128 * Panic if filesystem is not busy. 129 */ 130 void 131 vfs_unbusy(struct mount *mp) 132 { 133 134 if ((mp->mnt_flag & MNT_MPBUSY) == 0) 135 panic("vfs_unbusy: not busy"); 136 mp->mnt_flag &= ~MNT_MPBUSY; 137 if (mp->mnt_flag & MNT_MPWANT) { 138 mp->mnt_flag &= ~MNT_MPWANT; 139 wakeup((caddr_t)&mp->mnt_flag); 140 } 141 } 142 143 /* 144 * Lookup a mount point by filesystem identifier. 145 */ 146 struct mount * 147 getvfs(fsid_t *fsid) 148 { 149 struct mount *mp; 150 151 mp = rootfs; 152 do { 153 if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && 154 mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { 155 return (mp); 156 } 157 mp = mp->mnt_next; 158 } while (mp != rootfs); 159 return ((struct mount *)0); 160 } 161 162 /* add a filesystem type to the system. */ 163 void 164 addvfs(struct vfsops *vfsp) { 165 struct vfsops *ovfsp = vfs; 166 167 vfsp->vfs_next = ovfsp; 168 vfs = vfsp; 169 } 170 171 /* find a filesystem type in the system. */ 172 struct vfsops * 173 findvfs(int type) { 174 struct vfsops *vfsp; 175 176 /* search list */ 177 for(vfsp = vfs; vfsp ; vfsp = vfsp->vfs_next) 178 if (vfsp->vfs_type == type) 179 return (vfsp); 180 return (0); 181 } 182 183 /* compose a partially implemented filesystem with parts from another */ 184 void 185 incorporatefs(struct vfsops *srcfs, struct vfsops *dstfs) { 186 187 if (dstfs->vfs_mount == 0) 188 dstfs->vfs_mount = srcfs->vfs_mount; 189 if (dstfs->vfs_start == 0) 190 dstfs->vfs_start = srcfs->vfs_start; 191 if (dstfs->vfs_unmount == 0) 192 dstfs->vfs_unmount = srcfs->vfs_unmount; 193 if (dstfs->vfs_root == 0) 194 dstfs->vfs_root = srcfs->vfs_root; 195 if (dstfs->vfs_quotactl == 0) 196 dstfs->vfs_quotactl = srcfs->vfs_quotactl; 197 if (dstfs->vfs_statfs == 0) 198 dstfs->vfs_statfs = srcfs->vfs_statfs; 199 if (dstfs->vfs_sync == 0) 200 dstfs->vfs_sync = srcfs->vfs_sync; 201 if (dstfs->vfs_fhtovp == 0) 202 dstfs->vfs_fhtovp = srcfs->vfs_fhtovp; 203 if (dstfs->vfs_vptofh == 0) 204 dstfs->vfs_vptofh = srcfs->vfs_vptofh; 205 if (dstfs->vfs_init == 0) 206 dstfs->vfs_init = srcfs->vfs_init; 207 if (dstfs->vfs_mountroot == 0) 208 dstfs->vfs_mountroot = srcfs->vfs_mountroot; 209 } 210 211 /* 212 * Initialize the vnode structures and initialize each file system type. 213 */ 214 void 215 vfsinit(void) 216 { 217 struct vfsops *vfsp; 218 219 /* initialize the name cache */ 220 nchinit(); 221 222 /* initalize the vnode layer */ 223 vattr_null(&va_null); 224 225 /* initialize each filesystem */ 226 for (vfsp = vfs; vfsp ; vfsp = vfsp->vfs_next) 227 (*vfsp->vfs_init)(); 228 } 229 230 /* 231 * Move a vnode from one mount queue to another. 232 */ 233 /*static*/ void 234 insmntque(struct vnode *vp, struct mount *mp) 235 { 236 struct vnode *vq; 237 238 /* 239 * Delete from old mount point vnode list, if on one. 240 */ 241 if (vp->v_mountb) { 242 if (vq = vp->v_mountf) 243 vq->v_mountb = vp->v_mountb; 244 *vp->v_mountb = vq; 245 } 246 /* 247 * Insert into list of vnodes for the new mount point, if available. 248 */ 249 vp->v_mount = mp; 250 if (mp == NULL) { 251 vp->v_mountf = NULL; 252 vp->v_mountb = NULL; 253 return; 254 } 255 if (vq = mp->mnt_mounth) 256 vq->v_mountb = &vp->v_mountf; 257 vp->v_mountf = vq; 258 vp->v_mountb = &mp->mnt_mounth; 259 mp->mnt_mounth = vp; 260 } 261 262 /* 263 * Make sure all write-behind blocks associated 264 * with mount point are flushed out (from sync). 265 */ 266 void 267 mntflushbuf(struct mount *mountp, int flags) 268 { 269 struct vnode *vp; 270 271 if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 272 panic("mntflushbuf: not busy"); 273 loop: 274 for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 275 if (VOP_ISLOCKED(vp)) 276 continue; 277 if (vget(vp)) 278 goto loop; 279 vflushbuf(vp, flags, 0); 280 vput(vp); 281 if (vp->v_mount != mountp) 282 goto loop; 283 } 284 } 285 286 /* 287 * Invalidate in core blocks belonging to closed or unmounted filesystem 288 * 289 * Go through the list of vnodes associated with the file system; 290 * for each vnode invalidate any buffers that it holds. Normally 291 * this routine is preceeded by a bflush call, so that on a quiescent 292 * filesystem there will be no dirty buffers when we are done. Binval 293 * returns the count of dirty buffers when it is finished. 294 */ 295 int 296 mntinvalbuf(struct mount *mountp) 297 { 298 register struct vnode *vp; 299 int dirty = 0; 300 301 if ((mountp->mnt_flag & MNT_MPBUSY) == 0) 302 panic("mntinvalbuf: not busy"); 303 loop: 304 for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) { 305 if (vget(vp)) 306 goto loop; 307 dirty += vinvalbuf(vp, 1); 308 vput(vp); 309 if (vp->v_mount != mountp) 310 goto loop; 311 } 312 return (dirty); 313 } 314 315 /* 316 * Remove any vnodes in the vnode table belonging to mount point mp. 317 * 318 * If MNT_NOFORCE is specified, there should not be any active ones, 319 * return error if any are found (nb: this is a user error, not a 320 * system error). If MNT_FORCE is specified, detach any active vnodes 321 * that are found. 322 */ 323 #ifdef DEBUG 324 int busyprt = 0; /* patch to print out busy vnodes */ 325 #endif 326 327 int 328 vflush(struct mount *mp, struct vnode *skipvp, int flags) 329 { 330 register struct vnode *vp, *nvp; 331 int busy = 0; 332 333 if ((mp->mnt_flag & MNT_MPBUSY) == 0) 334 panic("vflush: not busy"); 335 loop: 336 for (vp = mp->mnt_mounth; vp; vp = nvp) { 337 if (vp->v_mount != mp) 338 goto loop; 339 nvp = vp->v_mountf; 340 /* 341 * Skip over a selected vnode. 342 */ 343 if (vp == skipvp) 344 continue; 345 /* 346 * Skip over a vnodes marked VSYSTEM. 347 */ 348 if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) 349 continue; 350 /* 351 * With v_usecount == 0, all we need to do is clear 352 * out the vnode data structures and we are done. 353 */ 354 if (vp->v_usecount == 0) { 355 vgone(vp); 356 continue; 357 } 358 /* 359 * For block or character devices, revert to an 360 * anonymous device. For all other files, just kill them. 361 */ 362 if (flags & FORCECLOSE) { 363 if (vp->v_type != VBLK && vp->v_type != VCHR) { 364 vgone(vp); 365 } else { 366 spec_anonymous(vp); 367 /*vclean(vp, 0); 368 vp->v_op = &spec_vnodeops; 369 insmntque(vp, (struct mount *)0);*/ 370 } 371 continue; 372 } 373 #ifdef DEBUG 374 if (busyprt) 375 vprint("vflush: busy vnode", vp); 376 #endif 377 busy++; 378 } 379 if (busy) 380 return (EBUSY); 381 return (0); 382 } 383