1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  26 /*        All Rights Reserved   */
  27 
  28 /*
  29  * University Copyright- Copyright (c) 1982, 1986, 1988
  30  * The Regents of the University of California
  31  * All Rights Reserved
  32  *
  33  * University Acknowledgment- Portions of this document are derived from
  34  * software developed by the University of California, Berkeley, and its
  35  * contributors.
  36  */
  37 
  38 
  39 #include <sys/types.h>
  40 #include <sys/t_lock.h>
  41 #include <sys/param.h>
  42 #include <sys/buf.h>
  43 #include <sys/cmn_err.h>
  44 #include <sys/debug.h>
  45 #include <sys/errno.h>
  46 #include <sys/vfs.h>
  47 #include <sys/swap.h>
  48 #include <sys/vnode.h>
  49 #include <sys/cred.h>
  50 #include <sys/fs/snode.h>
  51 #include <sys/thread.h>
  52 
  53 #include <fs/fs_subr.h>
  54 
  55 /*
  56  * This is the loadable module wrapper.
  57  */
  58 #include <sys/modctl.h>
  59 
  60 static vfsdef_t vfw = {
  61         VFSDEF_VERSION,
  62         "specfs",
  63         specinit,
  64         VSW_ZMOUNT,
  65         NULL
  66 };
  67 
  68 extern struct mod_ops mod_fsops;
  69 
  70 /*
  71  * Module linkage information for the kernel.
  72  */
  73 static struct modlfs modlfs = {
  74         &mod_fsops, "filesystem for specfs", &vfw
  75 };
  76 
  77 static struct modlinkage modlinkage = {
  78         MODREV_1, (void *)&modlfs, NULL
  79 };
  80 
  81 int
  82 _init(void)
  83 {
  84         return (mod_install(&modlinkage));
  85 }
  86 
  87 int
  88 _info(struct modinfo *modinfop)
  89 {
  90         return (mod_info(&modlinkage, modinfop));
  91 }
  92 
  93 /*
  94  * N.B.
  95  * No _fini routine. This module cannot be unloaded once loaded.
  96  * The NO_UNLOAD_STUB in modstub.s must change if this module ever
  97  * is modified to become unloadable.
  98  */
  99 
 100 kmutex_t spec_syncbusy;         /* initialized in specinit() */
 101 
 102 /*
 103  * Run though all the snodes and force write-back
 104  * of all dirty pages on the block devices.
 105  */
 106 /*ARGSUSED*/
 107 int
 108 spec_sync(struct vfs *vfsp,
 109         short   flag,
 110         struct cred *cr)
 111 {
 112         struct snode *sync_list;
 113         register struct snode **spp, *sp, *spnext;
 114         register struct vnode *vp;
 115 
 116         if (mutex_tryenter(&spec_syncbusy) == 0)
 117                 return (0);
 118 
 119         if (flag & SYNC_ATTR) {
 120                 mutex_exit(&spec_syncbusy);
 121                 return (0);
 122         }
 123         mutex_enter(&stable_lock);
 124         sync_list = NULL;
 125         /*
 126          * Find all the snodes that are dirty and add them to the sync_list
 127          */
 128         for (spp = stable; spp < &stable[STABLESIZE]; spp++) {
 129                 for (sp = *spp; sp != NULL; sp = sp->s_next) {
 130                         vp = STOV(sp);
 131                         /*
 132                          * Don't bother sync'ing a vp if it's
 133                          * part of a virtual swap device.
 134                          */
 135                         if (IS_SWAPVP(vp))
 136                                 continue;
 137 
 138                         if (vp->v_type == VBLK && vn_has_cached_data(vp)) {
 139                                 /*
 140                                  * Prevent vp from going away before we
 141                                  * we get a chance to do a VOP_PUTPAGE
 142                                  * via sync_list processing
 143                                  */
 144                                 VN_HOLD(vp);
 145                                 sp->s_list = sync_list;
 146                                 sync_list = sp;
 147                         }
 148                 }
 149         }
 150         mutex_exit(&stable_lock);
 151         /*
 152          * Now write out all the snodes we marked asynchronously.
 153          */
 154         for (sp = sync_list; sp != NULL; sp = spnext) {
 155                 spnext = sp->s_list;
 156                 vp = STOV(sp);
 157                 (void) VOP_PUTPAGE(vp, (offset_t)0, (uint_t)0, B_ASYNC, cr,
 158                     NULL);
 159                 VN_RELE(vp);            /* Release our hold on vnode */
 160         }
 161         mutex_exit(&spec_syncbusy);
 162         return (0);
 163 }