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 + -
显示快捷键?