uvm_swap.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,884 行 · 第 1/4 页
C
1,884 行
/* $NetBSD: uvm_swap.c,v 1.41 2000/11/27 08:40:05 chs Exp $ *//* * Copyright (c) 1995, 1996, 1997 Matthew R. Green * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: NetBSD: vm_swap.c,v 1.52 1997/12/02 13:47:37 pk Exp * from: Id: uvm_swap.c,v 1.1.2.42 1998/02/02 20:38:06 chuck Exp */#include "fs_nfs.h"#include "opt_uvmhist.h"#include "opt_compat_netbsd.h"#include "opt_ddb.h"#include <sys/param.h>#include <sys/systm.h>#include <sys/buf.h>#include <sys/conf.h>#include <sys/proc.h>#include <sys/namei.h>#include <sys/disklabel.h>#include <sys/errno.h>#include <sys/kernel.h>#include <sys/malloc.h>#include <sys/vnode.h>#include <sys/file.h>#include <sys/extent.h>#include <sys/mount.h>#include <sys/pool.h>#include <sys/syscallargs.h>#include <sys/swap.h>#include <uvm/uvm.h>#include <miscfs/specfs/specdev.h>#ifdef OSKIT#include <oskit/threads/pthread.h>#endif/* * uvm_swap.c: manage configuration and i/o to swap space. *//* * swap space is managed in the following way: * * each swap partition or file is described by a "swapdev" structure. * each "swapdev" structure contains a "swapent" structure which contains * information that is passed up to the user (via system calls). * * each swap partition is assigned a "priority" (int) which controls * swap parition usage. * * the system maintains a global data structure describing all swap * partitions/files. there is a sorted LIST of "swappri" structures * which describe "swapdev"'s at that priority. this LIST is headed * by the "swap_priority" global var. each "swappri" contains a * CIRCLEQ of "swapdev" structures at that priority. * * locking: * - swap_syscall_lock (sleep lock): this lock serializes the swapctl * system call and prevents the swap priority list from changing * while we are in the middle of a system call (e.g. SWAP_STATS). * - uvm.swap_data_lock (simple_lock): this lock protects all swap data * structures including the priority list, the swapdev structures, * and the swapmap extent. * * each swap device has the following info: * - swap device in use (could be disabled, preventing future use) * - swap enabled (allows new allocations on swap) * - map info in /dev/drum * - vnode pointer * for swap files only: * - block size * - max byte count in buffer * - buffer * - credentials to use when doing i/o to file * * userland controls and configures swap with the swapctl(2) system call. * the sys_swapctl performs the following operations: * [1] SWAP_NSWAP: returns the number of swap devices currently configured * [2] SWAP_STATS: given a pointer to an array of swapent structures * (passed in via "arg") of a size passed in via "misc" ... we load * the current swap config into the array. * [3] SWAP_ON: given a pathname in arg (could be device or file) and a * priority in "misc", start swapping on it. * [4] SWAP_OFF: as SWAP_ON, but stops swapping to a device * [5] SWAP_CTL: changes the priority of a swap device (new priority in * "misc") *//* * swapdev: describes a single swap partition/file * * note the following should be true: * swd_inuse <= swd_nblks [number of blocks in use is <= total blocks] * swd_nblks <= swd_mapsize [because mapsize includes miniroot+disklabel] */struct swapdev { struct oswapent swd_ose;#define swd_dev swd_ose.ose_dev /* device id */#define swd_flags swd_ose.ose_flags /* flags:inuse/enable/fake */#define swd_priority swd_ose.ose_priority /* our priority */ /* also: swd_ose.ose_nblks, swd_ose.ose_inuse */ char *swd_path; /* saved pathname of device */ int swd_pathlen; /* length of pathname */ int swd_npages; /* #pages we can use */ int swd_npginuse; /* #pages in use */ int swd_npgbad; /* #pages bad */ int swd_drumoffset; /* page0 offset in drum */ int swd_drumsize; /* #pages in drum */ struct extent *swd_ex; /* extent for this swapdev */ struct vnode *swd_vp; /* backing vnode */ CIRCLEQ_ENTRY(swapdev) swd_next; /* priority circleq */ int swd_bsize; /* blocksize (bytes) */ int swd_maxactive; /* max active i/o reqs */ struct buf_queue swd_tab; /* buffer list */ int swd_active; /* number of active buffers */ struct ucred *swd_cred; /* cred for file access */#ifdef OSKIT pthread_mutex_t swd_lock;#endif};/* * swap device priority entry; the list is kept sorted on `spi_priority'. */struct swappri { int spi_priority; /* priority */ CIRCLEQ_HEAD(spi_swapdev, swapdev) spi_swapdev; /* circleq of swapdevs at this priority */ LIST_ENTRY(swappri) spi_swappri; /* global list of pri's */};/* * The following two structures are used to keep track of data transfers * on swap devices associated with regular files. * NOTE: this code is more or less a copy of vnd.c; we use the same * structure names here to ease porting.. */struct vndxfer { struct buf *vx_bp; /* Pointer to parent buffer */ struct swapdev *vx_sdp; int vx_error; int vx_pending; /* # of pending aux buffers */ int vx_flags;#define VX_BUSY 1#define VX_DEAD 2};struct vndbuf { struct buf vb_buf; struct vndxfer *vb_xfer;};/* * We keep a of pool vndbuf's and vndxfer structures. */struct pool *vndxfer_pool;struct pool *vndbuf_pool;#define getvndxfer(vnx) do { \ int s = splbio(); \ vnx = pool_get(vndxfer_pool, PR_MALLOCOK|PR_WAITOK); \ splx(s); \} while (0)#define putvndxfer(vnx) { \ pool_put(vndxfer_pool, (void *)(vnx)); \}#define getvndbuf(vbp) do { \ int s = splbio(); \ vbp = pool_get(vndbuf_pool, PR_MALLOCOK|PR_WAITOK); \ splx(s); \} while (0)#define putvndbuf(vbp) { \ pool_put(vndbuf_pool, (void *)(vbp)); \}/* /dev/drum */bdev_decl(sw);cdev_decl(sw);/* * local variables */static struct extent *swapmap; /* controls the mapping of /dev/drum *//* list of all active swap devices [by priority] */LIST_HEAD(swap_priority, swappri);static struct swap_priority swap_priority;/* locks */lock_data_t swap_syscall_lock;/* * prototypes */static void swapdrum_add __P((struct swapdev *, int));static struct swapdev *swapdrum_getsdp __P((int));static struct swapdev *swaplist_find __P((struct vnode *, int));static void swaplist_insert __P((struct swapdev *, struct swappri *, int));static void swaplist_trim __P((void));static int swap_on __P((struct proc *, struct swapdev *));static int swap_off __P((struct proc *, struct swapdev *));#ifndef OSKITstatic void sw_reg_strategy __P((struct swapdev *, struct buf *, int));static void sw_reg_iodone __P((struct buf *));static void sw_reg_start __P((struct swapdev *));#endifstatic int uvm_swap_io __P((struct vm_page **, int, int, int));#ifdef OSKITstatic void oskit_sw_reg_strategy(struct swapdev *sdp, struct buf *bp, int bn);static int oskit_uvm_vop_getattr(struct vnode *, struct vattr *);static int oskit_uvm_vfs_statfs(struct vnode *, struct statfs *);#endif/* * uvm_swap_init: init the swap system data structures and locks * * => called at boot time from init_main.c after the filesystems * are brought up (which happens after uvm_init()) */voiduvm_swap_init(){ UVMHIST_FUNC("uvm_swap_init"); UVMHIST_CALLED(pdhist); /* * first, init the swap list, its counter, and its lock. * then get a handle on the vnode for /dev/drum by using * the its dev_t number ("swapdev", from MD conf.c). */ LIST_INIT(&swap_priority); uvmexp.nswapdev = 0; lockinit(&swap_syscall_lock, PVM, "swapsys", 0, 0); simple_lock_init(&uvm.swap_data_lock); if (bdevvp(swapdev, &swapdev_vp)) panic("uvm_swap_init: can't get vnode for swap device"); /* * create swap block resource map to map /dev/drum. the range * from 1 to INT_MAX allows 2 gigablocks of swap space. note * that block 0 is reserved (used to indicate an allocation * failure, or no allocation). */ swapmap = extent_create("swapmap", 1, INT_MAX, M_VMSWAP, 0, 0, EX_NOWAIT); if (swapmap == 0) panic("uvm_swap_init: extent_create failed"); /* * allocate pools for structures used for swapping to files. */ vndxfer_pool = pool_create(sizeof(struct vndxfer), 0, 0, 0, "swp vnx", 0, NULL, NULL, 0); if (vndxfer_pool == NULL) panic("swapinit: pool_create failed"); vndbuf_pool = pool_create(sizeof(struct vndbuf), 0, 0, 0, "swp vnd", 0, NULL, NULL, 0); if (vndbuf_pool == NULL) panic("swapinit: pool_create failed"); /* * done! */ UVMHIST_LOG(pdhist, "<- done", 0, 0, 0, 0);}/* * swaplist functions: functions that operate on the list of swap * devices on the system. *//* * swaplist_insert: insert swap device "sdp" into the global list * * => caller must hold both swap_syscall_lock and uvm.swap_data_lock * => caller must provide a newly malloc'd swappri structure (we will * FREE it if we don't need it... this it to prevent malloc blocking * here while adding swap) */static voidswaplist_insert(sdp, newspp, priority) struct swapdev *sdp; struct swappri *newspp; int priority;{ struct swappri *spp, *pspp; UVMHIST_FUNC("swaplist_insert"); UVMHIST_CALLED(pdhist); /* * find entry at or after which to insert the new device. */ for (pspp = NULL, spp = LIST_FIRST(&swap_priority); spp != NULL; spp = LIST_NEXT(spp, spi_swappri)) { if (priority <= spp->spi_priority) break; pspp = spp; } /* * new priority? */ if (spp == NULL || spp->spi_priority != priority) { spp = newspp; /* use newspp! */ UVMHIST_LOG(pdhist, "created new swappri = %d", priority, 0, 0, 0); spp->spi_priority = priority; CIRCLEQ_INIT(&spp->spi_swapdev); if (pspp) LIST_INSERT_AFTER(pspp, spp, spi_swappri); else LIST_INSERT_HEAD(&swap_priority, spp, spi_swappri); } else { /* we don't need a new priority structure, free it */ FREE(newspp, M_VMSWAP); } /* * priority found (or created). now insert on the priority's * circleq list and bump the total number of swapdevs. */ sdp->swd_priority = priority; CIRCLEQ_INSERT_TAIL(&spp->spi_swapdev, sdp, swd_next); uvmexp.nswapdev++;}/* * swaplist_find: find and optionally remove a swap device from the * global list. * * => caller must hold both swap_syscall_lock and uvm.swap_data_lock * => we return the swapdev we found (and removed) */static struct swapdev *swaplist_find(vp, remove) struct vnode *vp; boolean_t remove;{ struct swapdev *sdp; struct swappri *spp; /* * search the lists for the requested vp */ for (spp = LIST_FIRST(&swap_priority); spp != NULL; spp = LIST_NEXT(spp, spi_swappri)) { for (sdp = CIRCLEQ_FIRST(&spp->spi_swapdev); sdp != (void *)&spp->spi_swapdev; sdp = CIRCLEQ_NEXT(sdp, swd_next))#ifdef OSKIT if (sdp->swd_vp->v_blkio == vp->v_blkio && sdp->swd_vp->v_absio == vp->v_absio)#else if (sdp->swd_vp == vp)#endif { if (remove) { CIRCLEQ_REMOVE(&spp->spi_swapdev, sdp, swd_next); uvmexp.nswapdev--; } return(sdp); } } return (NULL);}/* * swaplist_trim: scan priority list for empty priority entries and kill * them. * * => caller must hold both swap_syscall_lock and uvm.swap_data_lock */static voidswaplist_trim(){ struct swappri *spp, *nextspp; for (spp = LIST_FIRST(&swap_priority); spp != NULL; spp = nextspp) { nextspp = LIST_NEXT(spp, spi_swappri); if (CIRCLEQ_FIRST(&spp->spi_swapdev) != (void *)&spp->spi_swapdev) continue; LIST_REMOVE(spp, spi_swappri); free(spp, M_VMSWAP); }}/* * swapdrum_add: add a "swapdev"'s blocks into /dev/drum's area. * * => caller must hold swap_syscall_lock * => uvm.swap_data_lock should be unlocked (we may sleep) */static voidswapdrum_add(sdp, npages) struct swapdev *sdp; int npages;{ u_long result; if (extent_alloc(swapmap, npages, EX_NOALIGN, EX_NOBOUNDARY, EX_WAITOK, &result)) panic("swapdrum_add"); sdp->swd_drumoffset = result; sdp->swd_drumsize = npages;}/* * swapdrum_getsdp: given a page offset in /dev/drum, convert it back * to the "swapdev" that maps that section of the drum. * * => each swapdev takes one big contig chunk of the drum * => caller must hold uvm.swap_data_lock */static struct swapdev *swapdrum_getsdp(pgno) int pgno;{ struct swapdev *sdp; struct swappri *spp; for (spp = LIST_FIRST(&swap_priority); spp != NULL; spp = LIST_NEXT(spp, spi_swappri))
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?