uvm_swap.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,884 行 · 第 1/4 页

C
1,884
字号
		for (sdp = CIRCLEQ_FIRST(&spp->spi_swapdev);		     sdp != (void *)&spp->spi_swapdev;		     sdp = CIRCLEQ_NEXT(sdp, swd_next))			if (pgno >= sdp->swd_drumoffset &&			    pgno < (sdp->swd_drumoffset + sdp->swd_drumsize)) {				return sdp;			}	return NULL;}/* * sys_swapctl: main entry point for swapctl(2) system call * 	[with two helper functions: swap_on and swap_off] */intsys_swapctl(p, v, retval)	struct proc *p;	void *v;	register_t *retval;{	struct sys_swapctl_args /* {		syscallarg(int) cmd;		syscallarg(void *) arg;		syscallarg(int) misc;	} */ *uap = (struct sys_swapctl_args *)v;	struct vnode *vp;#ifndef OSKIT	struct nameidata nd;#endif	struct swappri *spp;	struct swapdev *sdp;	struct swapent *sep;#ifndef OSKIT	char	userpath[PATH_MAX + 1];	size_t	len;#endif	int	count, error, misc;	int	priority;	UVMHIST_FUNC("sys_swapctl"); UVMHIST_CALLED(pdhist);	misc = SCARG(uap, misc);	/*	 * ensure serialized syscall access by grabbing the swap_syscall_lock	 */	lockmgr(&swap_syscall_lock, LK_EXCLUSIVE, NULL);	/*	 * we handle the non-priv NSWAP and STATS request first.	 *	 * SWAP_NSWAP: return number of config'd swap devices 	 * [can also be obtained with uvmexp sysctl]	 */	if (SCARG(uap, cmd) == SWAP_NSWAP) {		UVMHIST_LOG(pdhist, "<- done SWAP_NSWAP=%d", uvmexp.nswapdev,		    0, 0, 0);		*retval = uvmexp.nswapdev;		error = 0;		goto out;	}	/*	 * SWAP_STATS: get stats on current # of configured swap devs	 *	 * note that the swap_priority list can't change as long 	 * as we are holding the swap_syscall_lock.  we don't want	 * to grab the uvm.swap_data_lock because we may fault&sleep during 	 * copyout() and we don't want to be holding that lock then!	 */	if (SCARG(uap, cmd) == SWAP_STATS#if defined(COMPAT_13)	    || SCARG(uap, cmd) == SWAP_OSTATS#endif	    ) {		sep = (struct swapent *)SCARG(uap, arg);		count = 0;		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 && misc-- > 0;			     sdp = CIRCLEQ_NEXT(sdp, swd_next)) {			  	/*				 * backwards compatibility for system call.				 * note that we use 'struct oswapent' as an				 * overlay into both 'struct swapdev' and				 * the userland 'struct swapent', as we				 * want to retain backwards compatibility				 * with NetBSD 1.3.				 */				sdp->swd_ose.ose_inuse = 				    btodb(sdp->swd_npginuse << PAGE_SHIFT);				error = copyout(&sdp->swd_ose, sep,						sizeof(struct oswapent));				/* now copy out the path if necessary */#if defined(COMPAT_13)				if (error == 0 && SCARG(uap, cmd) == SWAP_STATS)#else				if (error == 0)#endif					error = copyout(sdp->swd_path,					    &sep->se_path, sdp->swd_pathlen);				if (error)					goto out;				count++;#if defined(COMPAT_13)				if (SCARG(uap, cmd) == SWAP_OSTATS)					((struct oswapent *)sep)++;				else#endif					sep++;			}		}		UVMHIST_LOG(pdhist, "<- done SWAP_STATS", 0, 0, 0, 0);		*retval = count;		error = 0;		goto out;	} #ifndef OSKIT	/*	 * all other requests require superuser privs.   verify.	 */	if ((error = suser(p->p_ucred, &p->p_acflag)))		goto out;	if (SCARG(uap, cmd) == SWAP_GETDUMPDEV) {		dev_t	*devp = (dev_t *)SCARG(uap, arg);		error = copyout(&dumpdev, devp, sizeof(dumpdev));		goto out;	}#endif	/*	 * at this point we expect a path name in arg.   we will	 * use namei() to gain a vnode reference (vref), and lock	 * the vnode (VOP_LOCK).	 *	 * XXX: a NULL arg means use the root vnode pointer (e.g. for	 * miniroot)	 */#ifdef OSKIT	vp = (struct vnode*)SCARG(uap, arg); /* kill const */#else	if (SCARG(uap, arg) == NULL) {		vp = rootvp;		/* miniroot */		if (vget(vp, LK_EXCLUSIVE)) {			error = EBUSY;			goto out;		}		if (SCARG(uap, cmd) == SWAP_ON &&		    copystr("miniroot", userpath, sizeof userpath, &len))			panic("swapctl: miniroot copy failed");	} else {		int	space;		char	*where;		if (SCARG(uap, cmd) == SWAP_ON) {			if ((error = copyinstr(SCARG(uap, arg), userpath,			    sizeof userpath, &len)))				goto out;			space = UIO_SYSSPACE;			where = userpath;		} else {			space = UIO_USERSPACE;			where = (char *)SCARG(uap, arg);		}		NDINIT(&nd, LOOKUP, FOLLOW|LOCKLEAF, space, where, p);		if ((error = namei(&nd)))			goto out;		vp = nd.ni_vp;	}#endif /*OSKIT*/	/* note: "vp" is referenced and locked */	error = 0;		/* assume no error */	switch(SCARG(uap, cmd)) {#ifndef OSKIT	case SWAP_DUMPDEV:		if (vp->v_type != VBLK) {			error = ENOTBLK;			goto out;		}		dumpdev = vp->v_rdev;				break;#endif	case SWAP_CTL:		/*		 * get new priority, remove old entry (if any) and then		 * reinsert it in the correct place.  finally, prune out		 * any empty priority structures.		 */		priority = SCARG(uap, misc);		spp = malloc(sizeof *spp, M_VMSWAP, M_WAITOK);		simple_lock(&uvm.swap_data_lock);		if ((sdp = swaplist_find(vp, 1)) == NULL) {			error = ENOENT;		} else {			swaplist_insert(sdp, spp, priority);			swaplist_trim();		}		simple_unlock(&uvm.swap_data_lock);		if (error)			free(spp, M_VMSWAP);		break;	case SWAP_ON:		/*		 * check for duplicates.   if none found, then insert a		 * dummy entry on the list to prevent someone else from		 * trying to enable this device while we are working on		 * it.		 */		priority = SCARG(uap, misc);		simple_lock(&uvm.swap_data_lock);		if ((sdp = swaplist_find(vp, 0)) != NULL) {			error = EBUSY;			simple_unlock(&uvm.swap_data_lock);			break;		}		sdp = malloc(sizeof *sdp, M_VMSWAP, M_WAITOK);		spp = malloc(sizeof *spp, M_VMSWAP, M_WAITOK);		memset(sdp, 0, sizeof(*sdp));		sdp->swd_flags = SWF_FAKE;	/* placeholder only */		sdp->swd_vp = vp;		sdp->swd_dev = (vp->v_type == VBLK) ? vp->v_rdev : NODEV;		BUFQ_INIT(&sdp->swd_tab);#ifdef OSKIT		pthread_mutex_init(&sdp->swd_lock, NULL);#endif		/*		 * XXX Is NFS elaboration necessary?		 */		if (vp->v_type == VREG) {			sdp->swd_cred = crdup(p->p_ucred);		}		swaplist_insert(sdp, spp, priority);		simple_unlock(&uvm.swap_data_lock);#ifndef OSKIT		sdp->swd_pathlen = len;		sdp->swd_path = malloc(sdp->swd_pathlen, M_VMSWAP, M_WAITOK);		if (copystr(userpath, sdp->swd_path, sdp->swd_pathlen, 0) != 0)			panic("swapctl: copystr");#endif		/*		 * we've now got a FAKE placeholder in the swap list.		 * now attempt to enable swap on it.  if we fail, undo		 * what we've done and kill the fake entry we just inserted.		 * if swap_on is a success, it will clear the SWF_FAKE flag		 */		if ((error = swap_on(p, sdp)) != 0) {			simple_lock(&uvm.swap_data_lock);			(void) swaplist_find(vp, 1);  /* kill fake entry */			swaplist_trim();			simple_unlock(&uvm.swap_data_lock);			if (vp->v_type == VREG) {				crfree(sdp->swd_cred);			}#ifdef OSKIT			pthread_mutex_destroy(&sdp->swd_lock);#endif			free(sdp->swd_path, M_VMSWAP);			free(sdp, M_VMSWAP);			break;		}		break;	case SWAP_OFF:		simple_lock(&uvm.swap_data_lock);		if ((sdp = swaplist_find(vp, 0)) == NULL) {			simple_unlock(&uvm.swap_data_lock);			error = ENXIO;			break;		}		/*		 * If a device isn't in use or enabled, we		 * can't stop swapping from it (again).		 */		if ((sdp->swd_flags & (SWF_INUSE|SWF_ENABLE)) == 0) {			simple_unlock(&uvm.swap_data_lock);			error = EBUSY;			break;		}		/*		 * do the real work.		 */		if ((error = swap_off(p, sdp)) != 0)			goto out;		break;	default:		error = EINVAL;	}	/*	 * done!  release the ref gained by namei() and unlock.	 */	vput(vp);out:	lockmgr(&swap_syscall_lock, LK_RELEASE, NULL);	UVMHIST_LOG(pdhist, "<- done!  error=%d", error, 0, 0, 0);	return (error);}/* * swap_on: attempt to enable a swapdev for swapping.   note that the *	swapdev is already on the global list, but disabled (marked *	SWF_FAKE). * * => we avoid the start of the disk (to protect disk labels) * => we also avoid the miniroot, if we are swapping to root. * => caller should leave uvm.swap_data_lock unlocked, we may lock it *	if needed. */static intswap_on(p, sdp)	struct proc *p;	struct swapdev *sdp;{	static int count = 0;	/* static */	struct vnode *vp;	int error, npages, nblocks, size;	long addr;	struct vattr va;#ifdef NFS	extern int (**nfsv2_vnodeop_p) __P((void *));#endif /* NFS */	dev_t dev;	char *name;	UVMHIST_FUNC("swap_on"); UVMHIST_CALLED(pdhist);	/*	 * we want to enable swapping on sdp.   the swd_vp contains	 * the vnode we want (locked and ref'd), and the swd_dev	 * contains the dev_t of the file, if it a block device.	 */	vp = sdp->swd_vp;	dev = sdp->swd_dev;#ifndef OSKIT	/*	 * open the swap file (mostly useful for block device files to	 * let device driver know what is up).	 *	 * we skip the open/close for root on swap because the root	 * has already been opened when root was mounted (mountroot).	 */	if (vp != rootvp) {		if ((error = VOP_OPEN(vp, FREAD|FWRITE, p->p_ucred, p)))			return (error);	}#endif	/* XXX this only works for block devices */	UVMHIST_LOG(pdhist, "  dev=%d, major(dev)=%d", dev, major(dev), 0,0);	/*	 * we now need to determine the size of the swap area.   for	 * block specials we can call the d_psize function.	 * for normal files, we must stat [get attrs].	 *	 * we put the result in nblks.	 * for normal files, we also want the filesystem block size	 * (which we get with statfs).	 */	switch (vp->v_type) {	case VBLK:		if (bdevsw[major(dev)].d_psize == 0 ||		    (nblocks = (*bdevsw[major(dev)].d_psize)(dev)) == -1) {			error = ENXIO;			goto bad;		}		break;	case VREG:#ifdef OSKIT#undef VOP_GETATTR#undef VFS_STATFS#define VOP_GETATTR(vp, va, cred, p)	oskit_uvm_vop_getattr(vp, va)#define VFS_STATFS(mount, stat, p)	oskit_uvm_vfs_statfs(vp, stat)#endif		if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)))			goto bad;		nblocks = (int)btodb(va.va_size);		if ((error =		     VFS_STATFS(vp->v_mount, &vp->v_mount->mnt_stat, p)) != 0)			goto bad;		sdp->swd_bsize = vp->v_mount->mnt_stat.f_iosize;		/*		 * limit the max # of outstanding I/O requests we issue		 * at any one time.   take it easy on NFS servers.		 */#ifdef NFS		if (vp->v_op == nfsv2_vnodeop_p)			sdp->swd_maxactive = 2; /* XXX */		else#endif /* NFS */			sdp->swd_maxactive = 8; /* XXX */		break;	default:		error = ENXIO;		goto bad;	}	/*	 * save nblocks in a safe place and convert to pages.	 */	sdp->swd_ose.ose_nblks = nblocks;	npages = dbtob((u_int64_t)nblocks) >> PAGE_SHIFT;	/*	 * for block special files, we want to make sure that leave	 * the disklabel and bootblocks alone, so we arrange to skip	 * over them (arbitrarily choosing to skip PAGE_SIZE bytes).	 * note that because of this the "size" can be less than the	 * actual number of blocks on the device.	 */	if (vp->v_type == VBLK) {		/* we use pages 1 to (size - 1) [inclusive] */		size = npages - 1;		addr = 1;	} else {		/* we use pages 0 to (size - 1) [inclusive] */		size = npages;		addr = 0;	}	/*	 * make sure we have enough blocks for a reasonable sized swap	 * area.   we want at least one page.	 */	if (size < 1) {		UVMHIST_LOG(pdhist, "  size <= 1!!", 0, 0, 0, 0);		error = EINVAL;		goto bad;	}	UVMHIST_LOG(pdhist, "  dev=%x: size=%d addr=%ld\n", dev, size, addr, 0);	/*	 * now we need to allocate an extent to manage this swap device	 */	name = malloc(12, M_VMSWAP, M_WAITOK);	sprintf(name, "swap0x%04x", count++);	/* note that extent_create's 3rd arg is inclusive, thus "- 1" */	sdp->swd_ex = extent_create(name, 0, npages - 1, M_VMSWAP,

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?