The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/vm/vm_swap.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 1982, 1986, 1989, 1993
    3  *      The Regents of the University of California.  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  *      @(#)vm_swap.c   8.5 (Berkeley) 2/17/94
   34  * $FreeBSD: src/sys/vm/vm_swap.c,v 1.40.2.2 1999/09/05 08:24:41 peter Exp $
   35  */
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/sysproto.h>
   40 #include <sys/buf.h>
   41 #include <sys/conf.h>
   42 #ifdef DEVFS
   43 #include <sys/devfsext.h>
   44 #endif
   45 #include <sys/proc.h>
   46 #include <sys/namei.h>
   47 #include <sys/dmap.h>           /* XXX */
   48 #include <sys/vnode.h>
   49 #include <sys/file.h>
   50 #include <sys/rlist.h>
   51 #include <sys/kernel.h>
   52 #include <vm/vm.h>
   53 #include <vm/vm_param.h>
   54 #include <vm/vm_extern.h>
   55 #include <vm/swap_pager.h>
   56 
   57 #include <miscfs/specfs/specdev.h>
   58 
   59 static void swstrategy __P((struct buf *));
   60 
   61 #define CDEV_MAJOR 4
   62 #define BDEV_MAJOR 26
   63 extern struct cdevsw sw_cdevsw ;
   64 
   65 static struct bdevsw sw_bdevsw = 
   66         { noopen,       noclose,        swstrategy,     noioc,          /*1*/
   67           nodump,       nopsize,        0,      "sw",   &sw_cdevsw,     -1 };
   68 
   69 static struct cdevsw sw_cdevsw = 
   70         { nullopen,     nullclose,      rawread,        rawwrite,       /*4*/
   71           noioc,        nostop,         noreset,        nodevtotty,/* swap */
   72           noselect,     nommap,         swstrategy,     "sw",
   73           &sw_bdevsw,   -1 };
   74 
   75 
   76 /*
   77  * Swapdev is a fake device implemented
   78  * in sw.c used only internally to get to swstrategy.
   79  * It cannot be provided to the users, because the
   80  * swstrategy routine munches the b_dev and b_blkno entries
   81  * before calling the appropriate driver.  This would horribly
   82  * confuse, e.g. the hashing routines. Instead, /dev/drum is
   83  * provided as a character (raw) device.
   84  */
   85 dev_t   swapdev = makedev(BDEV_MAJOR, 0);
   86 
   87 /*
   88  * Indirect driver for multi-controller paging.
   89  */
   90 
   91 #ifndef NSWAPDEV
   92 #define NSWAPDEV        4
   93 #endif
   94 static struct swdevt should_be_malloced[NSWAPDEV];
   95 static struct swdevt *swdevt = should_be_malloced;
   96 struct vnode *swapdev_vp;
   97 /* XXX swapinfo(8) needs this one I belive */
   98 int nswap;                      /* first block after the interleaved devs */
   99 static int nswdev = NSWAPDEV;
  100 int vm_swap_size;
  101 
  102 static void
  103 swstrategy(bp)
  104         register struct buf *bp;
  105 {
  106         int sz, off, seg, index;
  107         register struct swdevt *sp;
  108         struct vnode *vp;
  109 
  110         sz = howmany(bp->b_bcount, DEV_BSIZE);
  111         if (nswdev > 1) {
  112                 off = bp->b_blkno % dmmax;
  113                 if (off + sz > dmmax) {
  114                         bp->b_error = EINVAL;
  115                         bp->b_flags |= B_ERROR;
  116                         biodone(bp);
  117                         return;
  118                 }
  119                 seg = bp->b_blkno / dmmax;
  120                 index = seg % nswdev;
  121                 seg /= nswdev;
  122                 bp->b_blkno = seg * dmmax + off;
  123         } else
  124                 index = 0;
  125         sp = &swdevt[index];
  126         if (bp->b_blkno + sz > sp->sw_nblks) {
  127                 bp->b_error = EINVAL;
  128                 bp->b_flags |= B_ERROR;
  129                 biodone(bp);
  130                 return;
  131         }
  132         bp->b_dev = sp->sw_dev;
  133         if (sp->sw_vp == NULL) {
  134                 bp->b_error = ENODEV;
  135                 bp->b_flags |= B_ERROR;
  136                 biodone(bp);
  137                 return;
  138         }
  139         VHOLD(sp->sw_vp);
  140         if ((bp->b_flags & B_READ) == 0) {
  141                 vp = bp->b_vp;
  142                 if (vp) {
  143                         vp->v_numoutput--;
  144                         if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) {
  145                                 vp->v_flag &= ~VBWAIT;
  146                                 wakeup(&vp->v_numoutput);
  147                         }
  148                 }
  149                 sp->sw_vp->v_numoutput++;
  150         }
  151         if (bp->b_vp != NULL)
  152                 pbrelvp(bp);
  153         bp->b_vp = sp->sw_vp;
  154         VOP_STRATEGY(bp);
  155 }
  156 
  157 /*
  158  * System call swapon(name) enables swapping on device name,
  159  * which must be in the swdevsw.  Return EBUSY
  160  * if already swapping on this device.
  161  */
  162 #ifndef _SYS_SYSPROTO_H_
  163 struct swapon_args {
  164         char *name;
  165 };
  166 #endif
  167 
  168 /* ARGSUSED */
  169 int
  170 swapon(p, uap, retval)
  171         struct proc *p;
  172         struct swapon_args *uap;
  173         int *retval;
  174 {
  175         register struct vnode *vp;
  176         dev_t dev;
  177         struct nameidata nd;
  178         int error;
  179 
  180         error = suser(p->p_ucred, &p->p_acflag);
  181         if (error)
  182                 return (error);
  183 
  184         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->name, p);
  185         error = namei(&nd);
  186         if (error)
  187                 return (error);
  188 
  189         vp = nd.ni_vp;
  190 
  191         switch (vp->v_type) {
  192         case VBLK:
  193                 dev = (dev_t) vp->v_rdev;
  194                 if (major(dev) >= nblkdev) {
  195                         error = ENXIO;
  196                         break;
  197                 }
  198                 error = swaponvp(p, vp, dev, 0);
  199                 break;
  200         case VCHR:
  201                 /*
  202                  * For now, we disallow swapping to regular files.
  203                  * It requires logical->physcal block translation
  204                  * support in the swap pager before it will work.
  205                  */
  206                 error = ENOTBLK;
  207                 break;
  208 #if 0
  209                 error = VOP_GETATTR(vp, &attr, p->p_ucred, p);
  210                 if (!error)
  211                         error = swaponvp(p, vp, NODEV, attr.va_size / DEV_BSIZE);
  212                 break;
  213 #endif
  214         default:
  215                 error = EINVAL;
  216                 break;
  217         }
  218 
  219         if (error)
  220                 vrele(vp);
  221 
  222         return (error);
  223 }
  224 
  225 /*
  226  * Swfree(index) frees the index'th portion of the swap map.
  227  * Each of the nswdev devices provides 1/nswdev'th of the swap
  228  * space, which is laid out with blocks of dmmax pages circularly
  229  * among the devices.
  230  */
  231 int
  232 swaponvp(p, vp, dev, nblks)
  233         struct proc *p;
  234         struct vnode *vp;
  235         dev_t dev;
  236         u_long nblks;
  237 {
  238         int index;
  239         register struct swdevt *sp;
  240         register swblk_t vsbase;
  241         register long blk;
  242         swblk_t dvbase;
  243         int error;
  244 
  245         for (sp = swdevt, index = 0 ; index < nswdev; index++, sp++) {
  246                 if (sp->sw_vp == vp)
  247                         return EBUSY;
  248                 if (!sp->sw_vp)
  249                         goto found;
  250 
  251         }
  252         return EINVAL;
  253     found:
  254         if (dev != NODEV && (major(dev) >= nblkdev))
  255                 return (ENXIO);
  256 
  257         error = VOP_OPEN(vp, FREAD | FWRITE, p->p_ucred, p);
  258         if (error)
  259                 return (error);
  260 
  261         if (nblks == 0 && (bdevsw[major(dev)]->d_psize == 0 ||
  262             (nblks = (*bdevsw[major(dev)]->d_psize) (dev)) == -1)) {
  263                 (void) VOP_CLOSE(vp, FREAD | FWRITE, p->p_ucred, p);
  264                 return (ENXIO);
  265         }
  266         if (nblks == 0) {
  267                 (void) VOP_CLOSE(vp, FREAD | FWRITE, p->p_ucred, p);
  268                 return (ENXIO);
  269         }
  270         sp->sw_vp = vp;
  271         sp->sw_dev = dev;
  272         sp->sw_flags |= SW_FREED;
  273         sp->sw_nblks = nblks;
  274 
  275         if (nblks * nswdev > nswap)
  276                 nswap = (nblks+1) * nswdev;
  277 
  278         for (dvbase = dmmax; dvbase < nblks; dvbase += dmmax) {
  279                 blk = min(nblks - dvbase,dmmax);
  280                 vsbase = index * dmmax + dvbase * nswdev;
  281                 rlist_free(&swaplist, vsbase, vsbase + blk - 1);
  282                 vm_swap_size += blk;
  283         }
  284 
  285         if (!swapdev_vp) {
  286                 struct vnode *vp;
  287                 struct vnode *nvp;
  288 
  289                 error = getnewvnode(VT_NON, (struct mount *) 0,
  290                     spec_vnodeop_p, &nvp);
  291                 if (error)
  292                         panic("Cannot get vnode for swapdev");
  293                 vp = nvp;
  294                 vp->v_type = VBLK;
  295                 if ((nvp = checkalias(vp, swapdev,
  296                     (struct mount *) 0))) {
  297                         vput(vp);
  298                         vp = nvp;
  299                 }
  300                 swapdev_vp = vp;
  301         }
  302         return (0);
  303 }
  304 
  305 static sw_devsw_installed = 0;
  306 #ifdef DEVFS
  307 static void *drum_devfs_token;
  308 #endif
  309 
  310 static void     sw_drvinit(void *unused)
  311 {
  312         dev_t dev;
  313 
  314         if( ! sw_devsw_installed ) {
  315                 dev = makedev(CDEV_MAJOR,0);
  316                 cdevsw_add(&dev,&sw_cdevsw,NULL);
  317                 dev = makedev(BDEV_MAJOR,0);
  318                 bdevsw_add(&dev,&sw_bdevsw,NULL);
  319                 sw_devsw_installed = 1;
  320 #ifdef DEVFS
  321                 drum_devfs_token = devfs_add_devswf(&sw_cdevsw, 0, DV_CHR,
  322                                                     UID_ROOT, GID_KMEM, 0640,
  323                                                     "drum");
  324 #endif
  325         }
  326 }
  327 
  328 SYSINIT(swdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,sw_drvinit,NULL)
  329 

Cache object: ee3fed23ea62ad2050813fffe5c5a06e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.