LCOV - code coverage report
Current view: top level - kern - vfs_sync.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 116 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 8 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*       $OpenBSD: vfs_sync.c,v 1.60 2018/08/13 15:26:17 visa Exp $  */
       2             : 
       3             : /*
       4             :  *  Portions of this code are:
       5             :  *
       6             :  * Copyright (c) 1989, 1993
       7             :  *      The Regents of the University of California.  All rights reserved.
       8             :  * (c) UNIX System Laboratories, Inc.
       9             :  * All or some portions of this file are derived from material licensed
      10             :  * to the University of California by American Telephone and Telegraph
      11             :  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
      12             :  * the permission of UNIX System Laboratories, Inc.
      13             :  *
      14             :  * Redistribution and use in source and binary forms, with or without
      15             :  * modification, are permitted provided that the following conditions
      16             :  * are met:
      17             :  * 1. Redistributions of source code must retain the above copyright
      18             :  *    notice, this list of conditions and the following disclaimer.
      19             :  * 2. Redistributions in binary form must reproduce the above copyright
      20             :  *    notice, this list of conditions and the following disclaimer in the
      21             :  *    documentation and/or other materials provided with the distribution.
      22             :  * 3. Neither the name of the University nor the names of its contributors
      23             :  *    may be used to endorse or promote products derived from this software
      24             :  *    without specific prior written permission.
      25             :  *
      26             :  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      27             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      28             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      29             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      30             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      31             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      32             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      33             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      34             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      35             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      36             :  * SUCH DAMAGE.
      37             :  */
      38             : 
      39             : /*
      40             :  * Syncer daemon
      41             :  */
      42             : 
      43             : #include <sys/queue.h>
      44             : #include <sys/param.h>
      45             : #include <sys/systm.h>
      46             : #include <sys/proc.h>
      47             : #include <sys/mount.h>
      48             : #include <sys/vnode.h>
      49             : #include <sys/lock.h>
      50             : #include <sys/malloc.h>
      51             : 
      52             : #include <sys/kernel.h>
      53             : #include <sys/sched.h>
      54             : 
      55             : #ifdef FFS_SOFTUPDATES
      56             : int   softdep_process_worklist(struct mount *);
      57             : #endif
      58             : 
      59             : /*
      60             :  * The workitem queue.
      61             :  */
      62             : #define SYNCER_MAXDELAY 32              /* maximum sync delay time */
      63             : #define SYNCER_DEFAULT 30               /* default sync delay time */
      64             : int syncer_maxdelay = SYNCER_MAXDELAY;  /* maximum delay time */
      65             : int syncdelay = SYNCER_DEFAULT;         /* time to delay syncing vnodes */
      66             : 
      67             : int rushjob = 0;                        /* number of slots to run ASAP */
      68             : int stat_rush_requests = 0;             /* number of rush requests */
      69             : 
      70             : int syncer_delayno = 0;
      71             : long syncer_mask;
      72             : LIST_HEAD(synclist, vnode);
      73             : static struct synclist *syncer_workitem_pending;
      74             : 
      75             : struct proc *syncerproc;
      76             : 
      77             : /*
      78             :  * The workitem queue.
      79             :  *
      80             :  * It is useful to delay writes of file data and filesystem metadata
      81             :  * for tens of seconds so that quickly created and deleted files need
      82             :  * not waste disk bandwidth being created and removed. To realize this,
      83             :  * we append vnodes to a "workitem" queue. When running with a soft
      84             :  * updates implementation, most pending metadata dependencies should
      85             :  * not wait for more than a few seconds. Thus, mounted block devices
      86             :  * are delayed only about half the time that file data is delayed.
      87             :  * Similarly, directory updates are more critical, so are only delayed
      88             :  * about a third the time that file data is delayed. Thus, there are
      89             :  * SYNCER_MAXDELAY queues that are processed round-robin at a rate of
      90             :  * one each second (driven off the filesystem syncer process). The
      91             :  * syncer_delayno variable indicates the next queue that is to be processed.
      92             :  * Items that need to be processed soon are placed in this queue:
      93             :  *
      94             :  *      syncer_workitem_pending[syncer_delayno]
      95             :  *
      96             :  * A delay of fifteen seconds is done by placing the request fifteen
      97             :  * entries later in the queue:
      98             :  *
      99             :  *      syncer_workitem_pending[(syncer_delayno + 15) & syncer_mask]
     100             :  *
     101             :  */
     102             : 
     103             : void
     104           0 : vn_initialize_syncerd(void)
     105             : {
     106           0 :         syncer_workitem_pending = hashinit(syncer_maxdelay, M_VNODE, M_WAITOK,
     107             :             &syncer_mask);
     108           0 :         syncer_maxdelay = syncer_mask + 1;
     109           0 : }
     110             : 
     111             : /*
     112             :  * Add an item to the syncer work queue.
     113             :  */
     114             : void
     115           0 : vn_syncer_add_to_worklist(struct vnode *vp, int delay)
     116             : {
     117             :         int s, slot;
     118             : 
     119           0 :         if (delay > syncer_maxdelay - 2)
     120           0 :                 delay = syncer_maxdelay - 2;
     121           0 :         slot = (syncer_delayno + delay) & syncer_mask;
     122             : 
     123           0 :         s = splbio();
     124           0 :         if (vp->v_bioflag & VBIOONSYNCLIST)
     125           0 :                 LIST_REMOVE(vp, v_synclist);
     126             : 
     127           0 :         vp->v_bioflag |= VBIOONSYNCLIST;
     128           0 :         LIST_INSERT_HEAD(&syncer_workitem_pending[slot], vp, v_synclist);
     129           0 :         splx(s);
     130           0 : }
     131             : 
     132             : /*
     133             :  * System filesystem synchronizer daemon.
     134             :  */
     135             : void
     136           0 : syncer_thread(void *arg)
     137             : {
     138           0 :         struct proc *p = curproc;
     139             :         struct synclist *slp;
     140             :         struct vnode *vp;
     141             :         time_t starttime;
     142             :         int s;
     143             : 
     144           0 :         for (;;) {
     145           0 :                 starttime = time_second;
     146             : 
     147             :                 /*
     148             :                  * Push files whose dirty time has expired.
     149             :                  */
     150           0 :                 s = splbio();
     151           0 :                 slp = &syncer_workitem_pending[syncer_delayno];
     152             : 
     153           0 :                 syncer_delayno += 1;
     154           0 :                 if (syncer_delayno == syncer_maxdelay)
     155             :                         syncer_delayno = 0;
     156             : 
     157           0 :                 while ((vp = LIST_FIRST(slp)) != NULL) {
     158           0 :                         if (vget(vp, LK_EXCLUSIVE | LK_NOWAIT)) {
     159             :                                 /*
     160             :                                  * If we fail to get the lock, we move this
     161             :                                  * vnode one second ahead in time.
     162             :                                  * XXX - no good, but the best we can do.
     163             :                                  */
     164           0 :                                 vn_syncer_add_to_worklist(vp, 1);
     165           0 :                                 continue;
     166             :                         }
     167           0 :                         splx(s);
     168           0 :                         (void) VOP_FSYNC(vp, p->p_ucred, MNT_LAZY, p);
     169           0 :                         vput(vp);
     170           0 :                         s = splbio();
     171           0 :                         if (LIST_FIRST(slp) == vp) {
     172             :                                 /*
     173             :                                  * Note: disk vps can remain on the
     174             :                                  * worklist too with no dirty blocks, but
     175             :                                  * since sync_fsync() moves it to a different
     176             :                                  * slot we are safe.
     177             :                                  */
     178             : #ifdef DIAGNOSTIC
     179           0 :                                 if (LIST_FIRST(&vp->v_dirtyblkhd) == NULL &&
     180           0 :                                     vp->v_type != VBLK) {
     181           0 :                                         vprint("fsync failed", vp);
     182           0 :                                         if (vp->v_mount != NULL)
     183           0 :                                                 printf("mounted on: %s\n",
     184           0 :                                                     vp->v_mount->mnt_stat.f_mntonname);
     185           0 :                                         panic("%s: fsync failed", __func__);
     186             :                                 }
     187             : #endif /* DIAGNOSTIC */
     188             :                                 /*
     189             :                                  * Put us back on the worklist.  The worklist
     190             :                                  * routine will remove us from our current
     191             :                                  * position and then add us back in at a later
     192             :                                  * position.
     193             :                                  */
     194           0 :                                 vn_syncer_add_to_worklist(vp, syncdelay);
     195           0 :                         }
     196             : 
     197           0 :                         sched_pause(yield);
     198             :                 }
     199             : 
     200           0 :                 splx(s);
     201             : 
     202             : #ifdef FFS_SOFTUPDATES
     203             :                 /*
     204             :                  * Do soft update processing.
     205             :                  */
     206           0 :                 softdep_process_worklist(NULL);
     207             : #endif
     208             : 
     209             :                 /*
     210             :                  * The variable rushjob allows the kernel to speed up the
     211             :                  * processing of the filesystem syncer process. A rushjob
     212             :                  * value of N tells the filesystem syncer to process the next
     213             :                  * N seconds worth of work on its queue ASAP. Currently rushjob
     214             :                  * is used by the soft update code to speed up the filesystem
     215             :                  * syncer process when the incore state is getting so far
     216             :                  * ahead of the disk that the kernel memory pool is being
     217             :                  * threatened with exhaustion.
     218             :                  */
     219           0 :                 if (rushjob > 0) {
     220           0 :                         rushjob -= 1;
     221           0 :                         continue;
     222             :                 }
     223             :                 /*
     224             :                  * If it has taken us less than a second to process the
     225             :                  * current work, then wait. Otherwise start right over
     226             :                  * again. We can still lose time if any single round
     227             :                  * takes more than two seconds, but it does not really
     228             :                  * matter as we are just trying to generally pace the
     229             :                  * filesystem activity.
     230             :                  */
     231           0 :                 if (time_second == starttime)
     232           0 :                         tsleep(&lbolt, PPAUSE, "syncer", 0);
     233             :         }
     234             : }
     235             : 
     236             : /*
     237             :  * Request the syncer daemon to speed up its work.
     238             :  * We never push it to speed up more than half of its
     239             :  * normal turn time, otherwise it could take over the cpu.
     240             :  */
     241             : int
     242           0 : speedup_syncer(void)
     243             : {
     244             :         int s;
     245             : 
     246           0 :         SCHED_LOCK(s);
     247           0 :         if (syncerproc && syncerproc->p_wchan == &lbolt)
     248           0 :                 setrunnable(syncerproc);
     249           0 :         SCHED_UNLOCK(s);
     250           0 :         if (rushjob < syncdelay / 2) {
     251           0 :                 rushjob += 1;
     252           0 :                 stat_rush_requests += 1;
     253           0 :                 return 1;
     254             :         }
     255           0 :         return 0;
     256           0 : }
     257             : 
     258             : /* Routine to create and manage a filesystem syncer vnode. */
     259             : int   sync_fsync(void *);
     260             : int   sync_inactive(void *);
     261             : int   sync_print(void *);
     262             : 
     263             : struct vops sync_vops = {
     264             :         .vop_close      = nullop,
     265             :         .vop_fsync      = sync_fsync,
     266             :         .vop_inactive   = sync_inactive,
     267             :         .vop_reclaim    = nullop,
     268             :         .vop_lock       = vop_generic_lock,
     269             :         .vop_unlock     = vop_generic_unlock,
     270             :         .vop_islocked   = vop_generic_islocked,
     271             :         .vop_print      = sync_print
     272             : };
     273             : 
     274             : /*
     275             :  * Create a new filesystem syncer vnode for the specified mount point.
     276             :  */
     277             : int
     278           0 : vfs_allocate_syncvnode(struct mount *mp)
     279             : {
     280           0 :         struct vnode *vp;
     281             :         static long start, incr, next;
     282             :         int error;
     283             : 
     284             :         /* Allocate a new vnode */
     285           0 :         if ((error = getnewvnode(VT_VFS, mp, &sync_vops, &vp)) != 0) {
     286           0 :                 mp->mnt_syncer = NULL;
     287           0 :                 return (error);
     288             :         }
     289           0 :         vp->v_writecount = 1;
     290           0 :         vp->v_type = VNON;
     291             :         /*
     292             :          * Place the vnode onto the syncer worklist. We attempt to
     293             :          * scatter them about on the list so that they will go off
     294             :          * at evenly distributed times even if all the filesystems
     295             :          * are mounted at once.
     296             :          */
     297           0 :         next += incr;
     298           0 :         if (next == 0 || next > syncer_maxdelay) {
     299           0 :                 start /= 2;
     300           0 :                 incr /= 2;
     301           0 :                 if (start == 0) {
     302           0 :                         start = syncer_maxdelay / 2;
     303           0 :                         incr = syncer_maxdelay;
     304           0 :                 }
     305           0 :                 next = start;
     306           0 :         }
     307           0 :         vn_syncer_add_to_worklist(vp, next);
     308           0 :         mp->mnt_syncer = vp;
     309           0 :         return (0);
     310           0 : }
     311             : 
     312             : /*
     313             :  * Do a lazy sync of the filesystem.
     314             :  */
     315             : int
     316           0 : sync_fsync(void *v)
     317             : {
     318           0 :         struct vop_fsync_args *ap = v;
     319           0 :         struct vnode *syncvp = ap->a_vp;
     320           0 :         struct mount *mp = syncvp->v_mount;
     321             :         int asyncflag;
     322             : 
     323             :         /*
     324             :          * We only need to do something if this is a lazy evaluation.
     325             :          */
     326           0 :         if (ap->a_waitfor != MNT_LAZY)
     327           0 :                 return (0);
     328             : 
     329             :         /*
     330             :          * Move ourselves to the back of the sync list.
     331             :          */
     332           0 :         vn_syncer_add_to_worklist(syncvp, syncdelay);
     333             : 
     334             :         /*
     335             :          * Walk the list of vnodes pushing all that are dirty and
     336             :          * not already on the sync list.
     337             :          */
     338           0 :         if (vfs_busy(mp, VB_READ|VB_NOWAIT) == 0) {
     339           0 :                 asyncflag = mp->mnt_flag & MNT_ASYNC;
     340           0 :                 mp->mnt_flag &= ~MNT_ASYNC;
     341           0 :                 VFS_SYNC(mp, MNT_LAZY, 0, ap->a_cred, ap->a_p);
     342           0 :                 if (asyncflag)
     343           0 :                         mp->mnt_flag |= MNT_ASYNC;
     344           0 :                 vfs_unbusy(mp);
     345           0 :         }
     346             : 
     347           0 :         return (0);
     348           0 : }
     349             : 
     350             : /*
     351             :  * The syncer vnode is no longer needed and is being decommissioned.
     352             :  */
     353             : int
     354           0 : sync_inactive(void *v)
     355             : {
     356           0 :         struct vop_inactive_args *ap = v;
     357             : 
     358           0 :         struct vnode *vp = ap->a_vp;
     359             :         int s;
     360             : 
     361           0 :         if (vp->v_usecount == 0) {
     362           0 :                 VOP_UNLOCK(vp);
     363           0 :                 return (0);
     364             :         }
     365             : 
     366           0 :         vp->v_mount->mnt_syncer = NULL;
     367             : 
     368           0 :         s = splbio();
     369             : 
     370           0 :         LIST_REMOVE(vp, v_synclist);
     371           0 :         vp->v_bioflag &= ~VBIOONSYNCLIST;
     372             : 
     373           0 :         splx(s);
     374             : 
     375           0 :         vp->v_writecount = 0;
     376           0 :         vput(vp);
     377             : 
     378           0 :         return (0);
     379           0 : }
     380             : 
     381             : /*
     382             :  * Print out a syncer vnode.
     383             :  */
     384             : int
     385           0 : sync_print(void *v)
     386             : {
     387           0 :         printf("syncer vnode\n");
     388             : 
     389           0 :         return (0);
     390             : }

Generated by: LCOV version 1.13